@agimon-ai/doompi-team 0.0.1-alpha.2 → 0.0.1-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/extensions/orchestratorPrompt.cjs +3 -4
- package/dist/extensions/orchestratorPrompt.cjs.map +1 -1
- package/dist/extensions/orchestratorPrompt.mjs +3 -4
- package/dist/extensions/orchestratorPrompt.mjs.map +1 -1
- package/dist/extensions/subagentPromptRuntime.cjs.map +1 -1
- package/dist/extensions/subagentPromptRuntime.mjs.map +1 -1
- package/dist/extensions/subagentTool.cjs +5 -6
- package/dist/extensions/subagentTool.cjs.map +1 -1
- package/dist/extensions/subagentTool.mjs +5 -6
- package/dist/extensions/subagentTool.mjs.map +1 -1
- package/dist/extensions/toolDescription.cjs +1 -1
- package/dist/extensions/toolDescription.cjs.map +1 -1
- package/dist/extensions/toolDescription.mjs +1 -1
- package/dist/extensions/toolDescription.mjs.map +1 -1
- package/dist/runs/background/cliRunnerEntry.cjs.map +1 -1
- package/dist/runs/background/cliRunnerEntry.mjs.map +1 -1
- package/dist/runs/background/subagentWait.cjs.map +1 -1
- package/dist/runs/background/subagentWait.mjs.map +1 -1
- package/package.json +7 -7
|
@@ -10,10 +10,9 @@ genuinely long, or genuinely better done in a fresh context.
|
|
|
10
10
|
|
|
11
11
|
**Launches return immediately.** \`{action:"run", requests:[...]}\` returns run
|
|
12
12
|
handles after startup, not completion. After launching, choose whether to keep
|
|
13
|
-
doing useful work that does not duplicate the delegated scope, or end your turn
|
|
14
|
-
|
|
15
|
-
automatically.
|
|
16
|
-
cannot end without a completion or attention result.
|
|
13
|
+
doing useful work that does not duplicate the delegated scope, or end your turn.
|
|
14
|
+
Do not sleep or poll status in a loop. Completion messages wake you
|
|
15
|
+
automatically.
|
|
17
16
|
|
|
18
17
|
**Results arrive as messages, not return values.** A finished run shows up as a
|
|
19
18
|
completion message carrying its run id, its summary, and the handling it needs.
|
|
@@ -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
|
|
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"}
|
|
@@ -10,10 +10,9 @@ genuinely long, or genuinely better done in a fresh context.
|
|
|
10
10
|
|
|
11
11
|
**Launches return immediately.** \`{action:"run", requests:[...]}\` returns run
|
|
12
12
|
handles after startup, not completion. After launching, choose whether to keep
|
|
13
|
-
doing useful work that does not duplicate the delegated scope, or end your turn
|
|
14
|
-
|
|
15
|
-
automatically.
|
|
16
|
-
cannot end without a completion or attention result.
|
|
13
|
+
doing useful work that does not duplicate the delegated scope, or end your turn.
|
|
14
|
+
Do not sleep or poll status in a loop. Completion messages wake you
|
|
15
|
+
automatically.
|
|
17
16
|
|
|
18
17
|
**Results arrive as messages, not return values.** A finished run shows up as a
|
|
19
18
|
completion message carrying its run id, its summary, and the handling it needs.
|
|
@@ -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
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagentPromptRuntime.cjs","names":["createPromptRuntimeContainer","SUBAGENT_RUN_ID_ENV","DOOM_TEAM_TYPES","nativeTeamMemberEnvironment","getMessageUsageTokens","REQUIRED_CHILD_TOOLS_ENV","MCP_DIRECT_CHILD_TOOLS_ENV","CHILD_TOOL_DIAGNOSTIC_PATH_ENV","writeChildToolDiagnostic","SUBAGENT_CHILD_AGENT_ENV","SUBAGENT_FANOUT_CHILD_ENV","SUBAGENT_STEER_ACK_DIR_ENV","SUBAGENT_CHILD_INDEX_ENV","steerAckPathFromDir","toolBudgetSoftNudge","shouldBlockToolForBudget","toolBudgetBlockedMessage","SUBAGENT_STEER_INBOX_ENV","SUBAGENT_STEER_CAPABILITY_ENV","claimSteerRequestsFromDir","fs","resolveWatchPath","decodeToolBudgetEnv","TOOL_BUDGET_ENV","TOOL_BUDGET_ZERO_AUTH_ENV","STRUCTURED_OUTPUT_CAPTURE_ENV","STRUCTURED_OUTPUT_SCHEMA_ENV","createStructuredOutputToolParameters","StructuredOutputValidator","path","SUBAGENT_INTERCOM_SESSION_NAME_ENV","INHERIT_PROJECT_CONTEXT_ENV","INHERIT_SKILLS_ENV"],"sources":["../../src/extensions/subagentPromptRuntime.ts"],"sourcesContent":["/**\n * The extension loaded INSIDE every spawned child: prompt rewriting,\n * mid-run steering delivery, the tool-call budget, native supervisor/team\n * messaging, and the `structured_output` tool.\n *\n * WHY THIS RUNS IN A DIFFERENT WORLD THAN EVERYTHING ELSE PORTED SO FAR:\n * Every other module in this package runs in the parent or the runner\n * process. This one is loaded BY the child's own Pi process\n * (`piArgs.ts`'s `resolveRuntimeExtensionPath` resolves it onto the\n * child's `--extension` args). The child's stdout IS its captured\n * transcript - a stray console write here does not go to a developer's\n * terminal, it becomes part of the child's output. Nothing in this file\n * writes to the console, ever; a failure that would have been\n * logged elsewhere is swallowed with a comment when there is no safe channel\n * to report it.\n *\n * FIX (claim-by-rename for the per-child steer inbox):\n * The predecessor's `registerSteeringInbox` called\n * `consumeSteerRequestsFromDir`, which deletes every queued request before\n * attempting delivery, then manually re-queued whatever it had not yet\n * attempted (`requests.slice(index + 1)`) if `sendUserMessage` threw\n * partway through a batch - but the request that was actually attempted\n * when the throw happened was already gone, lost the same way FIX 1 in\n * `control-channel.ts` was written to close for the runner-side steer\n * queue. This module's `flush()` uses `claimSteerRequestsFromDir` (already\n * exported from `control-channel.ts`, directory-agnostic) instead: each\n * request is claimed individually, and a failed `sendUserMessage` call\n * calls `release()` on that one claim so it is retried on the next flush,\n * while every OTHER claim in the same batch is still committed or released\n * independently. That is also a behavioural improvement over the\n * predecessor's `break`-on-first-failure, which abandoned the rest of a\n * batch rather than giving each message its own outcome - the same\n * per-item independence `ControlChannelWatcher.check()` already applies on\n * the runner side.\n *\n * Child runtimes keep the native team transport for lifecycle and result\n * delivery, but model-visible coordination tools are filtered by the selected\n * layer policy. They never register the root orchestration tool or a separate\n * wait alias.\n *\n * AVOID:\n * - Writing to the console. See the header above\n * - Reintroducing the predecessor's \"delete the whole batch, dispatch,\n * re-queue what failed\" shape for the steer inbox. See the FIX above\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Container } from 'inversify';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nimport { createPromptRuntimeContainer, DOOM_TEAM_TYPES } from '../container/index.ts';\nimport {\n CHILD_TOOL_DIAGNOSTIC_PATH_ENV,\n INHERIT_PROJECT_CONTEXT_ENV,\n INHERIT_SKILLS_ENV,\n MCP_DIRECT_CHILD_TOOLS_ENV,\n REQUIRED_CHILD_TOOLS_ENV,\n STRUCTURED_OUTPUT_CAPTURE_ENV,\n STRUCTURED_OUTPUT_SCHEMA_ENV,\n SUBAGENT_CHILD_AGENT_ENV,\n SUBAGENT_CHILD_INDEX_ENV,\n SUBAGENT_FANOUT_CHILD_ENV,\n SUBAGENT_INTERCOM_SESSION_NAME_ENV,\n SUBAGENT_RUN_ID_ENV,\n SUBAGENT_STEER_ACK_DIR_ENV,\n SUBAGENT_STEER_CAPABILITY_ENV,\n SUBAGENT_STEER_INBOX_ENV,\n TOOL_BUDGET_ENV,\n TOOL_BUDGET_ZERO_AUTH_ENV,\n} from '../env.ts';\nimport {\n type INativeTeamChannelService,\n NATIVE_TEAM_TOOL_NAME,\n nativeTeamMemberEnvironment,\n type TeamMemberContext,\n} from '../intercom/nativeTeamChannel.ts';\nimport { resolveWatchPath } from '../shared/configDir.ts';\nimport { getMessageUsageTokens, type ChildTranscriptMessage } from '../shared/childTranscript.ts';\nimport { adoptSessionScopeFromEnv } from '../shared/paths.ts';\nimport type { JsonSchemaObject } from '../types.ts';\nimport {\n claimSteerRequestsFromDir,\n steerAckPathFromDir,\n writeSteerAckAt,\n writeSteerCapabilityAt,\n type SteerRequest,\n} from '../intercom/supervisorControlChannel.ts';\nimport type { IPollScheduler } from '../shared/pollScheduler.ts';\nimport type { IRunnerBootstrap } from '../runs/background/runnerBootstrap.ts';\nimport type { IRunnerExecution } from '../runs/background/runnerExecution.ts';\nimport type { IRunnerReporting } from '../runs/background/runnerReporting.ts';\nimport { createStructuredOutputToolParameters, StructuredOutputValidator } from '../runs/shared/structuredOutput.ts';\nimport { writeChildToolDiagnostic, type ChildToolDiagnostic } from '../runs/shared/toolAvailability.ts';\nimport {\n decodeToolBudgetEnv,\n shouldBlockToolForBudget,\n toolBudgetBlockedMessage,\n toolBudgetSoftNudge,\n} from '../runs/shared/toolBudget.ts';\nimport type { ResolvedToolBudget } from '../runs/shared/toolBudget.ts';\n\nconst STEER_FLUSH_POLL_INTERVAL_MS = 250;\n\n/**\n * Failures this runtime absorbed rather than propagated.\n *\n * WHY RECORD RATHER THAN LOG:\n * This module runs inside the spawned child, where stdout IS the child's\n * captured transcript. Writing a diagnostic there would corrupt the very\n * output the run exists to produce, so nothing here may reach stdio. But a\n * discarded error is indistinguishable from one that never happened, and a\n * watcher that fails on every event looks exactly like a quiet inbox. These\n * counters are the compromise: cheap, bounded, and queryable by a caller that\n * wants to know whether the child's steering path was actually healthy.\n *\n * WHY THIS IS CALLER-OWNED, NOT MODULE STATE:\n * A module-level singleton here would be exactly the bug this package's \"no\n * module-level mutable state\" rule exists to prevent - see\n * `nativeTeamChannel.ts`'s header: \"a second session in the same process\n * cannot inherit the first one's [state]\". `registerSubagentPromptRuntime`\n * runs once per real child process, so a singleton would rarely matter in\n * production, but every test in this file registers multiple independent\n * runtimes in one process, and a shared singleton would leak counts between\n * them silently. `createPromptRuntimeDiagnostics()` hands each registration\n * its own object instead; the caller keeps the reference to read later, and\n * a fresh registration is what \"reset\" means - there is no shared state left\n * to reset.\n *\n * AVOID:\n * - Adding a `console.*` here, on any path, for any reason\n * - Treating a non-zero count as fatal; every one of these is a degraded-mode\n * path with a working fallback, which is why it was absorbed in the first place\n * - Reintroducing a module-level instance of this. See the header above\n */\nexport interface PromptRuntimeDiagnostics {\n /** Advisory tool-budget nudges that could not be delivered to the child. */\n steerNudgeFailures: number;\n /** Errors emitted by the steer-inbox watcher. The interval poll covers these. */\n watchErrors: number;\n /** Failures closing the watcher during shutdown. */\n watchCloseFailures: number;\n /** The most recent absorbed failure, whichever kind it was. */\n lastError?: unknown;\n}\n\n/** A fresh, zeroed diagnostics object for one registration. See the interface doc for why this is not a singleton. */\nexport function createPromptRuntimeDiagnostics(): PromptRuntimeDiagnostics {\n return { steerNudgeFailures: 0, watchErrors: 0, watchCloseFailures: 0 };\n}\n\nconst STRUCTURED_OUTPUT_INSTRUCTIONS = [\n 'This subagent step has a strict structured output contract.',\n 'Your final action must be to call the `structured_output` tool with JSON matching the provided schema.',\n 'Do not rely on prose-only completion; if you do not call `structured_output`, the parent will fail this step.',\n].join('\\n');\n\nexport const CHILD_CONTEXT_FIRST_INSTRUCTIONS = [\n 'When the assigned task includes a parent context pack, treat it as the authoritative starting point.',\n 'That pack satisfies generic instructions to explore or understand repository context first.',\n 'Read its listed paths directly before broad discovery, and do not re-derive established facts unless direct evidence contradicts them.',\n 'Do not begin with repository-wide listing, find, or grep. Expand only after consuming the pack and naming a concrete missing dependency or invalid path; search narrowly for that item and state why.',\n].join('\\n');\n\nexport const CHILD_SUBAGENT_BOUNDARY_INSTRUCTIONS = [\n 'You are a child subagent, not the parent orchestrator.',\n 'The parent session owns delegation, orchestration, review fanout, and follow-up worker launches.',\n 'Ignore prior parent-only orchestration instructions in inherited conversation history.',\n 'Do not propose or run subagents. Complete only your assigned role-specific task with the tools available to you.',\n 'If you need to edit files, use the available editing tools. Do not print tool-call syntax, patches, or pseudo-tool calls as text.',\n CHILD_CONTEXT_FIRST_INSTRUCTIONS,\n].join('\\n');\n\nexport const CHILD_FANOUT_BOUNDARY_INSTRUCTIONS = [\n 'You are a child subagent with explicit fanout responsibility for this assigned task.',\n 'The parent session owns final orchestration, acceptance, and follow-up implementation launches.',\n 'You may use the `subagent` tool only for the fanout work explicitly requested in this task.',\n 'Do not broaden yourself into general parent orchestration. Do not launch follow-up workers unless the task explicitly asks for that.',\n 'The maxSubagentDepth cap still applies and may block further fanout.',\n 'If you need to edit files, use the available editing tools. Do not print tool-call syntax, patches, or pseudo-tool calls as text.',\n CHILD_CONTEXT_FIRST_INSTRUCTIONS,\n].join('\\n');\n\n/**\n * `pi.on` typed loosely: the extension API's event payloads are not typed\n * per event name, so every call site narrows its own handler's parameter.\n * `.call(pi, ...)` binds `this` explicitly rather than extracting `pi.on` as\n * a bare reference, which is what an unbound method call would otherwise risk.\n *\n * The handler is given `ctx: ExtensionContext` as a second parameter,\n * matching the real `pi.on` signature (`ExtensionHandler<E, R> = (event: E,\n * ctx: ExtensionContext) => ...`) even though most registrations here never\n * read it - existing single-parameter handlers stay valid without change\n * (JS ignores a callback's unused trailing parameters), and the one call\n * site that DOES need it (`session_start`, for `ctx.sessionManager` - see\n * `registerDeliverableGuardCheck`'s doc) no longer has to reach past this\n * wrapper to get it.\n */\nfunction onEvent<E = unknown>(\n pi: ExtensionAPI,\n event: string,\n handler: (event: E, ctx: ExtensionContext) => unknown,\n): void {\n (pi.on as unknown as (event: string, handler: (event: E, ctx: ExtensionContext) => unknown) => void).call(\n pi,\n event,\n handler,\n );\n}\n\n/** A text block from an assistant message's content array. Narrowed structurally, not imported from `@earendil-works/pi-ai`, matching this file's habit of ad-hoc event-payload types (see `onEvent`'s own doc). */\ninterface AssistantTextBlock {\n type: 'text';\n text: string;\n}\n\n/** The subset of `AgentEndEvent`/message shape this file actually reads. */\ninterface DeliverableCheckMessage {\n role?: string;\n content?: unknown;\n}\n\nfunction isAssistantTextBlock(block: unknown): block is AssistantTextBlock {\n return (\n typeof block === 'object' &&\n block !== null &&\n (block as { type?: unknown }).type === 'text' &&\n typeof (block as { text?: unknown }).text === 'string'\n );\n}\n\n/**\n * The last non-empty assistant text found in `messages`, or `''`.\n *\n * `DeliverableGuardInput.summary` is checked for the `'summary'`-kind\n * expectation, and nothing in this package tracks a run's summary text\n * per-turn - `RunnerReporting` only computes one at the terminal\n * `mutateTerminalStatus` callback, which has not happened yet when a\n * mid-run deliverable check needs to run. The assistant's own most recent\n * text output is the best available proxy for \"what would this run's\n * summary be if it stopped now\" without a dedicated tracking mechanism this\n * package does not have yet. Best-effort by construction: an unparseable or\n * missing message reads as an empty summary, which is the SAFE failure\n * direction for this guard (nudging once more than strictly necessary,\n * never fewer times than necessary).\n */\nexport function extractAssistantSummaryText(messages: readonly DeliverableCheckMessage[]): string {\n for (let index = messages.length - 1; index >= 0; index -= 1) {\n const message = messages[index];\n if (message?.role !== 'assistant' || !Array.isArray(message.content)) continue;\n const text = message.content\n .filter(isAssistantTextBlock)\n .map((block) => block.text)\n .join('\\n')\n .trim();\n if (text) return text;\n }\n return '';\n}\n\n/**\n * Wires `DeliverableGuard`'s write side into this process. See the module\n * doc's overall framing: everything else in the missing-deliverable chain\n * (detection, the single nudge, escalation, the fold into `status.json`,\n * `AsyncJobTracker`'s read and folded wait action already exist;\n * nothing called it. This is that call.\n *\n * WHY THIS RESOLVES ITS OWN CONTAINER, HERE:\n * `RunnerBootstrap`/`RunnerExecution`/`DeliverableGuard` are DI-bound\n * services (`container/modules/runs.ts`), and this file is the one place\n * `container/index.ts` documents as the in-child composition root\n * (`createPromptRuntimeContainer()`) - filed under `src/extensions/**`, the\n * boundary reserved for composition roots (see `vibe-lint.config.yaml`'s\n * `extensions` boundary), not under `src/runs/**` where it used to live. It\n * was moved here specifically so it could stop being the one exception\n * carved into the `runs` boundary's allowlist for `src/container/index.ts` -\n * a domain that can build its own container can bypass every composition\n * decision above it, and that hole is now closed rather than merely\n * documented. `container` is an optional parameter, defaulting to the real\n * container, purely so a test can supply one pre-loaded with fakes via\n * `container.rebind(...)` instead of standing up the real filesystem-backed\n * services.\n *\n * WHY `session_start` BOOTSTRAPS, AND WHY IT ONLY EVER RUNS ONCE:\n * `RunnerBootstrap.bootstrap()` is genuinely the FIRST real caller this\n * package has ever had for it - it opens `status.json`, wires\n * `TerminalPersistenceService`'s finalize callback, and writes the startup\n * handshake `SpawnHandshake.waitForHandshake()` on the parent side blocks\n * on. `RunnerExecution.start()` then begins watching the control inbox.\n * `ControlChannelWatcher` depends on `PollScheduler`\n * (`control-channel.ts:809`), which nothing in this package's runner\n * services ever calls `.start()` on by itself (see `pollScheduler.ts`'s own\n * AVOID note: \"a registered-but-unstarted PollScheduler never ticks\") - so\n * this starts it explicitly, once, alongside bootstrap. The `resolved` guard\n * makes a stray second `session_start` (nothing in this file's other\n * registrations assumes it fires only once) a no-op rather than a second\n * bootstrap of the same run.\n *\n * WHY `execution.start()` IS GIVEN AN `onSteer` HANDLER:\n * `DeliverableGuard.deliverNudge()` drops a nudge into this run's OWN\n * steer-requests queue via `requestAsyncSteer` (see that method's doc) and\n * calls it delivered once the write succeeds. But the write alone does not\n * reach the child: `ControlChannelWatcher`, wired up by `execution.start()`,\n * claims and commits (deletes) every request it finds in that queue whether\n * or not a handler is registered for it - found by testing this file\n * against the REAL `ControlChannelWatcher` rather than a fake with no side\n * effects, which is exactly the failure mode this task kept turning up\n * elsewhere (`createRunsModule()` never loaded into any root;\n * `PollScheduler.start()` never called). `onSteer` is the missing delivery\n * half: it reuses `formatSteerMessage`/`sendUserMessage`, the same\n * mechanism `registerSteeringInbox` already uses for its own, separate\n * steer queue, so a nudge actually lands in the child's conversation instead\n * of being silently claimed and discarded.\n *\n * WHY `agent_end`, NOT `turn_end`:\n * `agent_end`'s own event (`AgentEndEvent.messages`) carries the full\n * message history for this agent loop, which `extractAssistantSummaryText`\n * reads from - `turn_end` only carries the one message that ended that turn,\n * not the memory of what preceded it, and `DeliverableGuard`'s own doc\n * frames this check as \"end-of-turn or idle\", not \"every turn.\"\n *\n * `unansweredAsks` AND `memberId`:\n * Both come from this run's own bound `TeamMemberContext`, which\n * `RunnerBootstrap.bootstrap()` already holds (from registering as a team\n * member) and now returns on its result. `memberId` is `teamContext.memberId`\n * directly. `unansweredAsks` calls `pendingAsksAddressedTo(teamContext,\n * teamContext.memberId, now)` - see `deliverable-guard.ts`'s own AVOID\n * section for why `DeliverableGuard` cannot call that itself, and that\n * function's own doc for why it deliberately returns id/sender/time only,\n * never the question's text (this maps its result into a factual, non-\n * fabricated placeholder message rather than guessing at content it was\n * never given). A standalone run with no team root forwarded has no\n * `teamContext` at all, in which case both are simply omitted - narrower\n * than the real behaviour, never wider, matching every other gap in this\n * file when there is genuinely nothing to report rather than something\n * unknown to guess at.\n *\n * `session_start` ALSO RECORDS THIS RUN'S OWN SESSION FILE:\n * `ctx.sessionManager.getSessionFile()` is the only place in this process\n * that ever answers \"what is my own transcript path\" - see\n * `runnerReporting.ts`'s header for why the value has to come from here\n * (the child) rather than be derived by the parent. `RunnerReporting`\n * validates and retains it while `RunnerBootstrap` writes it before the\n * ready handshake. `getSessionFile()` can return `undefined` (no persisted\n * transcript for this run); that case is simply not recorded, the same\n * \"omit rather than guess\" shape as `unansweredAsks`/`teamContext` above.\n */\nexport function registerRunnerLifecycle(pi: ExtensionAPI, container: Container = createPromptRuntimeContainer()): void {\n const runId = process.env[SUBAGENT_RUN_ID_ENV]?.trim();\n if (!runId) return;\n\n const pollScheduler = container.get<IPollScheduler>(DOOM_TEAM_TYPES.PollScheduler);\n const bootstrap = container.get<IRunnerBootstrap>(DOOM_TEAM_TYPES.RunnerBootstrap);\n const execution = container.get<IRunnerExecution>(DOOM_TEAM_TYPES.RunnerExecution);\n const reporting = container.get<IRunnerReporting>(DOOM_TEAM_TYPES.RunnerReporting);\n\n let resolved: { teamContext: TeamMemberContext | undefined } | undefined;\n let cumulativeTokens: number | undefined;\n let toolCount = 0;\n const countedMessages = new WeakSet<object>();\n\n onEvent(pi, 'session_start', (_event, ctx) => {\n if (resolved) return;\n pollScheduler.start();\n const sessionFile = ctx.sessionManager.getSessionFile();\n const recordedSessionFile = sessionFile ? reporting.recordSessionFile(sessionFile) : undefined;\n const bootstrapped = bootstrap.bootstrap(runId, recordedSessionFile);\n if (bootstrapped.teamContext) Object.assign(process.env, nativeTeamMemberEnvironment(bootstrapped.teamContext));\n // `onSteer` is the delivery half of `DeliverableGuard.deliverNudge`'s\n // write side (see `RunnerExecutionHandlers.onSteer`'s own doc, which\n // cross-references it): `deliverNudge` drops a request into this run's\n // OWN steer-requests queue via `requestAsyncSteer`, and\n // `ControlChannelWatcher` (wired up by `execution.start()` below) claims\n // it and calls this handler. Without it, `execution.start()` still\n // claims and commits the nudge - `deliverNudge` reports\n // `nudgeDelivered: true`, `status.json` still shows `needs_attention` -\n // but the request is silently discarded before it ever reaches the\n // child's own conversation. `formatSteerMessage`/`sendUserMessage` are\n // the exact same delivery this file already uses for\n // `registerSteeringInbox`'s separate queue.\n execution.start(runId, {\n onSteer: (request) => {\n const sendUserMessage = (\n pi as { sendUserMessage?: (content: string, options: { deliverAs: 'steer' }) => unknown }\n ).sendUserMessage;\n if (!sendUserMessage) {\n acknowledgeRunnerSteer(request, 'failed', 'Child Pi session does not support sendUserMessage steering.');\n return;\n }\n try {\n sendUserMessage(formatSteerMessage(request), { deliverAs: 'steer' });\n acknowledgeRunnerSteer(request, 'delivered', 'Pi accepted the correlated steering input.');\n } catch (error) {\n acknowledgeRunnerSteer(request, 'failed', error instanceof Error ? error.message : String(error));\n throw error;\n }\n },\n });\n resolved = { teamContext: bootstrapped.teamContext };\n execution.setActivity('working');\n });\n\n onEvent(pi, 'agent_start', () => {\n if (resolved) execution.setActivity('working');\n });\n onEvent<{ message?: ChildTranscriptMessage }>(pi, 'message_end', (event) => {\n if (!resolved || !event.message || typeof event.message !== 'object') return;\n if (countedMessages.has(event.message)) return;\n countedMessages.add(event.message);\n const messageTokens = getMessageUsageTokens(event.message);\n if (messageTokens === undefined) return;\n cumulativeTokens = (cumulativeTokens ?? 0) + messageTokens;\n execution.setProgress({ tokens: cumulativeTokens });\n });\n onEvent<{ toolName?: string; tool?: { name?: string }; args?: { action?: string } }>(\n pi,\n 'tool_execution_start',\n (event) => {\n if (!resolved) return;\n const toolName = event.toolName ?? event.tool?.name;\n toolCount += 1;\n execution.setProgress({\n toolCount,\n ...(typeof toolName === 'string' && toolName.length > 0 ? { currentTool: toolName } : {}),\n });\n execution.setActivity(\n toolName === NATIVE_TEAM_TOOL_NAME && event.args?.action === 'ask' ? 'waiting_for_reply' : 'tool',\n );\n },\n );\n onEvent(pi, 'tool_execution_end', () => {\n if (resolved) execution.setActivity('working');\n });\n onEvent<{ messages: DeliverableCheckMessage[] }>(pi, 'agent_end', (event) => {\n if (!resolved) return; // session_start has not bootstrapped yet; nothing to report against.\n execution.setActivity('finalizing');\n const summary = extractAssistantSummaryText(event.messages);\n execution.complete(true, summary);\n });\n}\n\nconst PARENT_ONLY_CUSTOM_MESSAGE_TYPES = new Set([\n 'subagent-orchestration-instructions',\n 'subagent-slash-result',\n 'subagent-slash-text-result',\n 'subagent-notify',\n 'subagent_control_notice',\n 'subagent-control',\n 'subagent-control-notice',\n]);\nconst SUBAGENT_ORCHESTRATION_SKILL_NAME_PATTERN = /<name>\\s*pi-subagents\\s*<\\/name>/;\nconst PROJECT_CONTEXT_HEADER = '\\n\\n# Project Context\\n\\nProject-specific instructions and guidelines:\\n\\n';\nconst SKILLS_HEADER = '\\n\\nThe following skills provide specialized instructions for specific tasks.';\nconst DATE_HEADER = '\\nCurrent date:';\n\nfunction readBooleanEnv(name: string): boolean | undefined {\n const value = process.env[name];\n if (value === undefined) return undefined;\n return value !== '0';\n}\n\nfunction readRequiredChildTools(): string[] | undefined {\n const encoded = process.env[REQUIRED_CHILD_TOOLS_ENV]?.trim();\n if (!encoded) return undefined;\n const required = JSON.parse(encoded) as unknown;\n if (!Array.isArray(required) || required.some((name) => typeof name !== 'string' || !name)) {\n throw new Error(`Invalid ${REQUIRED_CHILD_TOOLS_ENV} payload.`);\n }\n return required;\n}\n\nfunction readMcpDirectChildTools(): string[] | undefined {\n const encoded = process.env[MCP_DIRECT_CHILD_TOOLS_ENV]?.trim();\n if (!encoded) return undefined;\n try {\n const tools = JSON.parse(encoded) as unknown;\n if (!Array.isArray(tools) || tools.some((name) => typeof name !== 'string' || !name)) return undefined;\n return tools;\n } catch {\n return undefined;\n }\n}\n\nfunction refreshChildToolDiagnostic(pi: ExtensionAPI): ChildToolDiagnostic | undefined {\n const filePath = process.env[CHILD_TOOL_DIAGNOSTIC_PATH_ENV]?.trim();\n const required = readRequiredChildTools();\n if (!filePath || !required) return undefined;\n const available = pi.getAllTools().map((tool) => tool.name);\n return writeChildToolDiagnostic(\n filePath,\n required,\n available,\n process.env[SUBAGENT_CHILD_AGENT_ENV]?.trim(),\n readMcpDirectChildTools(),\n );\n}\n\nfunction findSectionEnd(prompt: string, startIndex: number, nextHeaders: string[]): number {\n let endIndex = prompt.length;\n for (const header of nextHeaders) {\n const index = prompt.indexOf(header, startIndex);\n if (index !== -1 && index < endIndex) {\n endIndex = index;\n }\n }\n return endIndex;\n}\n\nexport function stripProjectContext(prompt: string): string {\n const startIndex = prompt.indexOf(PROJECT_CONTEXT_HEADER);\n if (startIndex === -1) return prompt;\n const endIndex = findSectionEnd(prompt, startIndex + PROJECT_CONTEXT_HEADER.length, [SKILLS_HEADER, DATE_HEADER]);\n return `${prompt.slice(0, startIndex)}${prompt.slice(endIndex)}`;\n}\n\nexport function stripInheritedSkills(prompt: string): string {\n const startIndex = prompt.indexOf(SKILLS_HEADER);\n if (startIndex === -1) return prompt;\n const endIndex = findSectionEnd(prompt, startIndex + SKILLS_HEADER.length, [DATE_HEADER]);\n return `${prompt.slice(0, startIndex)}${prompt.slice(endIndex)}`;\n}\n\nexport function stripSubagentOrchestrationSkill(prompt: string): string {\n return prompt\n .replace(/\\n{0,2}<skill\\s+name=[\"']pi-subagents[\"'][^>]*>[\\s\\S]*?<\\/skill>\\n{0,2}/g, '\\n\\n')\n .replace(/[ \\t]*<skill>\\s*[\\s\\S]*?<\\/skill>\\s*/g, (block) =>\n SUBAGENT_ORCHESTRATION_SKILL_NAME_PATTERN.test(block) ? '' : block,\n );\n}\n\nfunction stripChildBoundaryInstructions(prompt: string): string {\n let rewritten = prompt;\n for (const injectedInstructions of [\n CHILD_SUBAGENT_BOUNDARY_INSTRUCTIONS,\n CHILD_FANOUT_BOUNDARY_INSTRUCTIONS,\n STRUCTURED_OUTPUT_INSTRUCTIONS,\n ]) {\n rewritten = rewritten.split(injectedInstructions).join('');\n }\n return rewritten.replace(/^(?:[ \\t]*\\r?\\n)+/, '');\n}\n\nexport function rewriteSubagentPrompt(\n prompt: string,\n options: { inheritProjectContext: boolean; inheritSkills: boolean; fanoutChild?: boolean },\n): string {\n let rewritten = prompt;\n if (!options.inheritProjectContext) {\n rewritten = stripProjectContext(rewritten);\n }\n if (!options.inheritSkills) {\n rewritten = stripInheritedSkills(rewritten);\n }\n rewritten = stripSubagentOrchestrationSkill(rewritten);\n rewritten = stripChildBoundaryInstructions(rewritten);\n const boundary = options.fanoutChild ? CHILD_FANOUT_BOUNDARY_INSTRUCTIONS : CHILD_SUBAGENT_BOUNDARY_INSTRUCTIONS;\n const structured = process.env[STRUCTURED_OUTPUT_CAPTURE_ENV] ? `\\n\\n${STRUCTURED_OUTPUT_INSTRUCTIONS}` : '';\n return `${boundary}${structured}\\n\\n${rewritten}`;\n}\n\nfunction isParentOnlySubagentMessage(message: unknown): boolean {\n const m = message as { role?: string; customType?: string };\n if (m?.role !== 'custom' || typeof m.customType !== 'string') return false;\n return PARENT_ONLY_CUSTOM_MESSAGE_TYPES.has(m.customType);\n}\n\nfunction isSubagentToolResultMessage(message: unknown): boolean {\n const m = message as { role?: string; toolName?: string };\n return m?.role === 'toolResult' && m.toolName === 'subagent';\n}\n\nfunction isSubagentToolCallBlock(block: unknown): boolean {\n const b = block as { type?: string; name?: string };\n return b?.type === 'toolCall' && b.name === 'subagent';\n}\n\nfunction stripAssistantSubagentToolCallBlocks(message: unknown): unknown {\n const m = message as { role?: string; content?: unknown };\n if (m?.role !== 'assistant' || !Array.isArray(m.content)) return message;\n const filteredContent = m.content.filter((block) => !isSubagentToolCallBlock(block));\n if (filteredContent.length === m.content.length) return message;\n if (filteredContent.length === 0) return undefined;\n return { ...m, content: filteredContent };\n}\n\nexport function stripParentOnlySubagentMessages(messages: unknown[]): unknown[] {\n const preserveCurrentFanoutToolHistory = process.env[SUBAGENT_FANOUT_CHILD_ENV] === '1';\n let changed = false;\n const filtered: unknown[] = [];\n for (const message of messages) {\n if (\n isParentOnlySubagentMessage(message) ||\n (!preserveCurrentFanoutToolHistory && isSubagentToolResultMessage(message))\n ) {\n changed = true;\n continue;\n }\n const stripped = preserveCurrentFanoutToolHistory ? message : stripAssistantSubagentToolCallBlocks(message);\n if (stripped === undefined) {\n changed = true;\n continue;\n }\n if (stripped !== message) changed = true;\n filtered.push(stripped);\n }\n return changed ? filtered : messages;\n}\n\nexport function formatSteerMessage(request: SteerRequest): string {\n return [\n 'Mid-run steering from the parent orchestrator:',\n '',\n request.message,\n '',\n 'Incorporate this guidance at the next safe point. Do not restart the task unless the guidance explicitly asks you to.',\n ].join('\\n');\n}\n\nfunction acknowledgeRunnerSteer(request: SteerRequest, state: 'delivered' | 'failed', message: string): void {\n const ackDir = process.env[SUBAGENT_STEER_ACK_DIR_ENV]?.trim();\n const childIndex = Number(process.env[SUBAGENT_CHILD_INDEX_ENV]);\n if (!ackDir || !Number.isInteger(childIndex) || childIndex < 0) return;\n writeSteerAckAt(steerAckPathFromDir(ackDir, request.id), {\n requestId: request.id,\n index: childIndex,\n ts: Date.now(),\n state,\n message,\n });\n}\n\nfunction registerToolBudget(\n pi: ExtensionAPI,\n budget: ResolvedToolBudget | undefined,\n diagnostics: PromptRuntimeDiagnostics,\n): void {\n if (!budget) return;\n let toolCount = 0;\n let softNudged = false;\n const sendUserMessage = (pi as { sendUserMessage?: (content: string, options: { deliverAs: 'steer' }) => unknown })\n .sendUserMessage;\n onEvent<{ toolName?: string }>(pi, 'tool_call', (event) => {\n const toolName = typeof event.toolName === 'string' ? event.toolName : 'tool';\n toolCount++;\n if (budget.soft !== undefined && toolCount >= budget.soft && !softNudged) {\n softNudged = true;\n try {\n sendUserMessage?.(toolBudgetSoftNudge(budget, toolCount), { deliverAs: 'steer' });\n } catch (error) {\n // Advisory nudge only; the child's own output is what matters. Recorded\n // rather than discarded so a host that never accepts steering is\n // discoverable instead of silently dropping every nudge.\n diagnostics.steerNudgeFailures += 1;\n diagnostics.lastError = error;\n }\n }\n if (!shouldBlockToolForBudget(budget, toolName, toolCount)) return undefined;\n return { block: true, reason: toolBudgetBlockedMessage(budget, toolName, toolCount) };\n });\n}\n\n/**\n * Deliver mid-run steer requests queued for THIS child (by fan-out index)\n * into its own session via `sendUserMessage`. See the module doc's FIX for\n * why this claims each request individually rather than batch-deleting.\n */\nexport function registerSteeringInbox(\n pi: ExtensionAPI,\n deps: {\n watch?: typeof fs.watch;\n nativeRealpath?: (filePath: string) => string;\n diagnostics?: PromptRuntimeDiagnostics;\n } = {},\n): void {\n const diagnostics = deps.diagnostics ?? createPromptRuntimeDiagnostics();\n const steerInbox = process.env[SUBAGENT_STEER_INBOX_ENV]?.trim();\n if (!steerInbox) return;\n const capabilityPath = process.env[SUBAGENT_STEER_CAPABILITY_ENV]?.trim();\n const ackDir = process.env[SUBAGENT_STEER_ACK_DIR_ENV]?.trim();\n const sendUserMessage = (pi as { sendUserMessage?: (content: string, options: { deliverAs: 'steer' }) => unknown })\n .sendUserMessage;\n const childIndex = Number(process.env[SUBAGENT_CHILD_INDEX_ENV]);\n const pending = new Map<string, string[]>();\n let disposed = false;\n let flushing = false;\n let started = false;\n const canSteer = typeof sendUserMessage === 'function';\n let watcher: fs.FSWatcher | undefined;\n let interval: NodeJS.Timeout | undefined;\n\n const acknowledge = (request: SteerRequest, state: 'delivered' | 'failed', message: string): void => {\n if (!ackDir || !Number.isInteger(childIndex) || childIndex < 0) return;\n writeSteerAckAt(steerAckPathFromDir(ackDir, request.id), {\n requestId: request.id,\n index: childIndex,\n ts: Date.now(),\n state,\n message,\n });\n };\n const publishCapability = (): void => {\n if (!capabilityPath || !Number.isInteger(childIndex) || childIndex < 0) return;\n writeSteerCapabilityAt(capabilityPath, {\n index: childIndex,\n pid: process.pid,\n readyAt: Date.now(),\n supported: canSteer,\n });\n };\n\n const flush = (): void => {\n if (disposed || flushing) return;\n flushing = true;\n try {\n for (const claim of claimSteerRequestsFromDir(steerInbox)) {\n if (!canSteer || typeof sendUserMessage !== 'function') {\n acknowledge(claim.request, 'failed', 'Child Pi session does not support sendUserMessage steering.');\n claim.commit();\n continue;\n }\n const formatted = formatSteerMessage(claim.request);\n const ids = pending.get(formatted) ?? [];\n ids.push(claim.request.id);\n pending.set(formatted, ids);\n try {\n sendUserMessage(formatted, { deliverAs: 'steer' });\n claim.commit();\n } catch (error) {\n ids.pop();\n if (ids.length === 0) pending.delete(formatted);\n // Recoverable: this claim goes back to the queue for the next\n // flush to retry, instead of being lost. See the module doc's FIX.\n claim.release();\n acknowledge(claim.request, 'failed', error instanceof Error ? error.message : String(error));\n }\n }\n } finally {\n flushing = false;\n }\n };\n const onInput = (event: unknown): undefined => {\n if (disposed || !event || typeof event !== 'object') return undefined;\n const input = event as { source?: unknown; streamingBehavior?: unknown; text?: unknown; content?: unknown };\n if (input.source !== 'extension' || input.streamingBehavior !== 'steer') return undefined;\n const text =\n typeof input.text === 'string' ? input.text : typeof input.content === 'string' ? input.content : undefined;\n if (!text) return undefined;\n const ids = pending.get(text);\n const requestId = ids?.shift();\n if (!requestId) return undefined;\n if (ids?.length === 0) pending.delete(text);\n acknowledge(\n { type: 'steer', id: requestId, ts: Date.now(), message: text },\n 'delivered',\n 'Pi accepted the correlated steering input.',\n );\n return undefined;\n };\n const start = (): void => {\n if (started || disposed) return;\n try {\n fs.mkdirSync(steerInbox, { recursive: true });\n publishCapability();\n } catch {\n // No channel to report a startup failure on from inside the child;\n // the parent observes a missing capability file and treats it as\n // \"steering unsupported for this child\" on its own.\n return;\n }\n started = true;\n try {\n watcher = (deps.watch ?? fs.watch)(resolveWatchPath(steerInbox, deps.nativeRealpath), () => flush());\n watcher.on('error', (error) => {\n // fs.watch emits on transient FS errors and the interval poll below\n // keeps delivery live regardless, so this is not fatal. Recorded so a\n // watch that fails on every event is distinguishable from a quiet inbox.\n diagnostics.watchErrors += 1;\n diagnostics.lastError = error;\n });\n } catch {\n watcher = undefined;\n }\n interval = setInterval(flush, STEER_FLUSH_POLL_INTERVAL_MS);\n interval.unref?.();\n };\n const activate = (): undefined => {\n start();\n flush();\n return undefined;\n };\n\n // Register input before the watcher so an accepted extension input cannot race request dispatch.\n onEvent(pi, 'input', onInput);\n onEvent(pi, 'session_start', () => start());\n for (const eventName of [\n 'message_start',\n 'message_update',\n 'message_end',\n 'tool_execution_start',\n 'tool_execution_end',\n 'turn_end',\n ] as const) {\n onEvent(pi, eventName, activate);\n }\n onEvent(pi, 'session_shutdown', () => {\n disposed = true;\n try {\n watcher?.close();\n } catch (error) {\n // Best effort; the process is shutting down regardless. Still recorded,\n // because a close that always fails is a leaked descriptor per run.\n diagnostics.watchCloseFailures += 1;\n diagnostics.lastError = error;\n }\n if (interval) clearInterval(interval);\n });\n}\n\n/**\n * `diagnostics` is optional and defaults to a fresh object: the `.cts` entry\n * point calls this with a single argument (`pi`), matching the host contract\n * `resolveRuntimeExtensionPath` resolves onto every child's `--extension`\n * args, so that call keeps working unchanged. A caller that wants to observe\n * what this runtime absorbed - see `PromptRuntimeDiagnostics` - passes its\n * own object and keeps the reference; this function only ever mutates it, it\n * never owns or resets it.\n */\nexport function registerSubagentPromptRuntime(\n pi: ExtensionAPI,\n diagnostics: PromptRuntimeDiagnostics = createPromptRuntimeDiagnostics(),\n): void {\n // First, before any scoped path is touched. Pi loads extensions through jiti\n // with `moduleCache: false`, so this extension gets its OWN instance of\n // `shared/paths.ts` - the scope the surrounding runner process adopted is not\n // visible here, and has to be read from the environment again.\n adoptSessionScopeFromEnv();\n registerSteeringInbox(pi, { diagnostics });\n registerToolBudget(\n pi,\n decodeToolBudgetEnv(process.env[TOOL_BUDGET_ENV], { allowZero: process.env[TOOL_BUDGET_ZERO_AUTH_ENV] === '1' }),\n diagnostics,\n );\n // One container for this whole registration, not one built inside each\n // resolver's own default parameter: this process has exactly one\n // composition root (see container/index.ts and this function's own doc),\n // and a second independent createPromptRuntimeContainer() call anywhere\n // else in this function would silently mean two sets of \"singletons\" in\n // one process, defeating the point of a shared container.\n const container = createPromptRuntimeContainer();\n registerRunnerLifecycle(pi, container);\n\n const teamChannels = container.get<INativeTeamChannelService>(DOOM_TEAM_TYPES.NativeTeamChannelService);\n\n onEvent(pi, 'session_start', () => {\n const teamRuntime = teamChannels.createRuntime(pi);\n teamRuntime.bindChildFromEnvironment();\n });\n onEvent(pi, 'agent_start', () => {\n refreshChildToolDiagnostic(pi);\n });\n // `agent_end` intentionally does not drain outstanding work here. See the\n // module doc's \"WHAT IS DELIBERATELY NOT WIRED YET\" for why.\n\n const structuredOutputPath = process.env[STRUCTURED_OUTPUT_CAPTURE_ENV];\n const structuredSchemaPath = process.env[STRUCTURED_OUTPUT_SCHEMA_ENV];\n if (structuredOutputPath && structuredSchemaPath) {\n const schema = JSON.parse(fs.readFileSync(structuredSchemaPath, 'utf-8')) as JsonSchemaObject;\n const parameters = createStructuredOutputToolParameters(schema);\n const validator = new StructuredOutputValidator();\n const registerTool = (\n pi.registerTool as unknown as (tool: {\n name: string;\n label: string;\n description: string;\n parameters: unknown;\n execute: (_id: string, params: { value: unknown }) => Promise<unknown>;\n }) => void\n ).bind(pi);\n registerTool({\n name: 'structured_output',\n label: 'Structured Output',\n description: 'Submit the required final structured output for this subagent step. This terminates the step.',\n parameters: parameters as never,\n async execute(_id: string, params: { value: unknown }) {\n const validation = await validator.validateValue(schema, params.value);\n if (validation.status === 'invalid') {\n throw new Error(`Structured output validation failed: ${validation.message}`);\n }\n fs.mkdirSync(path.dirname(structuredOutputPath), { recursive: true });\n fs.writeFileSync(structuredOutputPath, JSON.stringify(params.value), { mode: 0o600 });\n return {\n content: [{ type: 'text', text: 'Structured output captured.' }],\n details: { path: structuredOutputPath },\n terminate: true,\n };\n },\n });\n }\n\n onEvent<{ messages: unknown[] }>(pi, 'context', (event) => {\n const messages = stripParentOnlySubagentMessages(event.messages);\n if (messages === event.messages) return undefined;\n return { messages };\n });\n\n onEvent<{ systemPrompt: string }>(pi, 'before_agent_start', async (event) => {\n const intercomSessionName = process.env[SUBAGENT_INTERCOM_SESSION_NAME_ENV]?.trim();\n if (intercomSessionName && typeof pi.setSessionName === 'function') {\n pi.setSessionName(intercomSessionName);\n }\n\n const inheritProjectContext = readBooleanEnv(INHERIT_PROJECT_CONTEXT_ENV);\n const inheritSkills = readBooleanEnv(INHERIT_SKILLS_ENV);\n const fanoutChild = readBooleanEnv(SUBAGENT_FANOUT_CHILD_ENV);\n let rewritten = event.systemPrompt;\n if (inheritProjectContext !== undefined || inheritSkills !== undefined || fanoutChild !== undefined) {\n rewritten = rewriteSubagentPrompt(event.systemPrompt, {\n inheritProjectContext: inheritProjectContext ?? true,\n inheritSkills: inheritSkills ?? true,\n fanoutChild: fanoutChild === true,\n });\n }\n if (rewritten === event.systemPrompt) return;\n return { systemPrompt: rewritten };\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"subagentPromptRuntime.cjs","names":["createPromptRuntimeContainer","SUBAGENT_RUN_ID_ENV","DOOM_TEAM_TYPES","nativeTeamMemberEnvironment","getMessageUsageTokens","REQUIRED_CHILD_TOOLS_ENV","MCP_DIRECT_CHILD_TOOLS_ENV","CHILD_TOOL_DIAGNOSTIC_PATH_ENV","writeChildToolDiagnostic","SUBAGENT_CHILD_AGENT_ENV","SUBAGENT_FANOUT_CHILD_ENV","SUBAGENT_STEER_ACK_DIR_ENV","SUBAGENT_CHILD_INDEX_ENV","steerAckPathFromDir","toolBudgetSoftNudge","shouldBlockToolForBudget","toolBudgetBlockedMessage","SUBAGENT_STEER_INBOX_ENV","SUBAGENT_STEER_CAPABILITY_ENV","claimSteerRequestsFromDir","fs","resolveWatchPath","decodeToolBudgetEnv","TOOL_BUDGET_ENV","TOOL_BUDGET_ZERO_AUTH_ENV","STRUCTURED_OUTPUT_CAPTURE_ENV","STRUCTURED_OUTPUT_SCHEMA_ENV","createStructuredOutputToolParameters","StructuredOutputValidator","path","SUBAGENT_INTERCOM_SESSION_NAME_ENV","INHERIT_PROJECT_CONTEXT_ENV","INHERIT_SKILLS_ENV"],"sources":["../../src/extensions/subagentPromptRuntime.ts"],"sourcesContent":["/**\n * The extension loaded INSIDE every spawned child: prompt rewriting,\n * mid-run steering delivery, the tool-call budget, native supervisor/team\n * messaging, and the `structured_output` tool.\n *\n * WHY THIS RUNS IN A DIFFERENT WORLD THAN EVERYTHING ELSE PORTED SO FAR:\n * Every other module in this package runs in the parent or the runner\n * process. This one is loaded BY the child's own Pi process\n * (`piArgs.ts`'s `resolveRuntimeExtensionPath` resolves it onto the\n * child's `--extension` args). The child's stdout IS its captured\n * transcript - a stray console write here does not go to a developer's\n * terminal, it becomes part of the child's output. Nothing in this file\n * writes to the console, ever; a failure that would have been\n * logged elsewhere is swallowed with a comment when there is no safe channel\n * to report it.\n *\n * FIX (claim-by-rename for the per-child steer inbox):\n * The predecessor's `registerSteeringInbox` called\n * `consumeSteerRequestsFromDir`, which deletes every queued request before\n * attempting delivery, then manually re-queued whatever it had not yet\n * attempted (`requests.slice(index + 1)`) if `sendUserMessage` threw\n * partway through a batch - but the request that was actually attempted\n * when the throw happened was already gone, lost the same way FIX 1 in\n * `control-channel.ts` was written to close for the runner-side steer\n * queue. This module's `flush()` uses `claimSteerRequestsFromDir` (already\n * exported from `control-channel.ts`, directory-agnostic) instead: each\n * request is claimed individually, and a failed `sendUserMessage` call\n * calls `release()` on that one claim so it is retried on the next flush,\n * while every OTHER claim in the same batch is still committed or released\n * independently. That is also a behavioural improvement over the\n * predecessor's `break`-on-first-failure, which abandoned the rest of a\n * batch rather than giving each message its own outcome - the same\n * per-item independence `ControlChannelWatcher.check()` already applies on\n * the runner side.\n *\n * Child runtimes keep the native team transport for lifecycle and result\n * delivery, but model-visible coordination tools are filtered by the selected\n * layer policy. They never register the root orchestration tool or a separate\n * wait alias.\n *\n * AVOID:\n * - Writing to the console. See the header above\n * - Reintroducing the predecessor's \"delete the whole batch, dispatch,\n * re-queue what failed\" shape for the steer inbox. See the FIX above\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Container } from 'inversify';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nimport { createPromptRuntimeContainer, DOOM_TEAM_TYPES } from '../container/index.ts';\nimport {\n CHILD_TOOL_DIAGNOSTIC_PATH_ENV,\n INHERIT_PROJECT_CONTEXT_ENV,\n INHERIT_SKILLS_ENV,\n MCP_DIRECT_CHILD_TOOLS_ENV,\n REQUIRED_CHILD_TOOLS_ENV,\n STRUCTURED_OUTPUT_CAPTURE_ENV,\n STRUCTURED_OUTPUT_SCHEMA_ENV,\n SUBAGENT_CHILD_AGENT_ENV,\n SUBAGENT_CHILD_INDEX_ENV,\n SUBAGENT_FANOUT_CHILD_ENV,\n SUBAGENT_INTERCOM_SESSION_NAME_ENV,\n SUBAGENT_RUN_ID_ENV,\n SUBAGENT_STEER_ACK_DIR_ENV,\n SUBAGENT_STEER_CAPABILITY_ENV,\n SUBAGENT_STEER_INBOX_ENV,\n TOOL_BUDGET_ENV,\n TOOL_BUDGET_ZERO_AUTH_ENV,\n} from '../env.ts';\nimport {\n type INativeTeamChannelService,\n NATIVE_TEAM_TOOL_NAME,\n nativeTeamMemberEnvironment,\n type TeamMemberContext,\n} from '../intercom/nativeTeamChannel.ts';\nimport { resolveWatchPath } from '../shared/configDir.ts';\nimport { getMessageUsageTokens, type ChildTranscriptMessage } from '../shared/childTranscript.ts';\nimport { adoptSessionScopeFromEnv } from '../shared/paths.ts';\nimport type { JsonSchemaObject } from '../types.ts';\nimport {\n claimSteerRequestsFromDir,\n steerAckPathFromDir,\n writeSteerAckAt,\n writeSteerCapabilityAt,\n type SteerRequest,\n} from '../intercom/supervisorControlChannel.ts';\nimport type { IPollScheduler } from '../shared/pollScheduler.ts';\nimport type { IRunnerBootstrap } from '../runs/background/runnerBootstrap.ts';\nimport type { IRunnerExecution } from '../runs/background/runnerExecution.ts';\nimport type { IRunnerReporting } from '../runs/background/runnerReporting.ts';\nimport { createStructuredOutputToolParameters, StructuredOutputValidator } from '../runs/shared/structuredOutput.ts';\nimport { writeChildToolDiagnostic, type ChildToolDiagnostic } from '../runs/shared/toolAvailability.ts';\nimport {\n decodeToolBudgetEnv,\n shouldBlockToolForBudget,\n toolBudgetBlockedMessage,\n toolBudgetSoftNudge,\n} from '../runs/shared/toolBudget.ts';\nimport type { ResolvedToolBudget } from '../runs/shared/toolBudget.ts';\n\nconst STEER_FLUSH_POLL_INTERVAL_MS = 250;\n\n/**\n * Failures this runtime absorbed rather than propagated.\n *\n * WHY RECORD RATHER THAN LOG:\n * This module runs inside the spawned child, where stdout IS the child's\n * captured transcript. Writing a diagnostic there would corrupt the very\n * output the run exists to produce, so nothing here may reach stdio. But a\n * discarded error is indistinguishable from one that never happened, and a\n * watcher that fails on every event looks exactly like a quiet inbox. These\n * counters are the compromise: cheap, bounded, and queryable by a caller that\n * wants to know whether the child's steering path was actually healthy.\n *\n * WHY THIS IS CALLER-OWNED, NOT MODULE STATE:\n * A module-level singleton here would be exactly the bug this package's \"no\n * module-level mutable state\" rule exists to prevent - see\n * `nativeTeamChannel.ts`'s header: \"a second session in the same process\n * cannot inherit the first one's [state]\". `registerSubagentPromptRuntime`\n * runs once per real child process, so a singleton would rarely matter in\n * production, but every test in this file registers multiple independent\n * runtimes in one process, and a shared singleton would leak counts between\n * them silently. `createPromptRuntimeDiagnostics()` hands each registration\n * its own object instead; the caller keeps the reference to read later, and\n * a fresh registration is what \"reset\" means - there is no shared state left\n * to reset.\n *\n * AVOID:\n * - Adding a `console.*` here, on any path, for any reason\n * - Treating a non-zero count as fatal; every one of these is a degraded-mode\n * path with a working fallback, which is why it was absorbed in the first place\n * - Reintroducing a module-level instance of this. See the header above\n */\nexport interface PromptRuntimeDiagnostics {\n /** Advisory tool-budget nudges that could not be delivered to the child. */\n steerNudgeFailures: number;\n /** Errors emitted by the steer-inbox watcher. The interval poll covers these. */\n watchErrors: number;\n /** Failures closing the watcher during shutdown. */\n watchCloseFailures: number;\n /** The most recent absorbed failure, whichever kind it was. */\n lastError?: unknown;\n}\n\n/** A fresh, zeroed diagnostics object for one registration. See the interface doc for why this is not a singleton. */\nexport function createPromptRuntimeDiagnostics(): PromptRuntimeDiagnostics {\n return { steerNudgeFailures: 0, watchErrors: 0, watchCloseFailures: 0 };\n}\n\nconst STRUCTURED_OUTPUT_INSTRUCTIONS = [\n 'This subagent step has a strict structured output contract.',\n 'Your final action must be to call the `structured_output` tool with JSON matching the provided schema.',\n 'Do not rely on prose-only completion; if you do not call `structured_output`, the parent will fail this step.',\n].join('\\n');\n\nexport const CHILD_CONTEXT_FIRST_INSTRUCTIONS = [\n 'When the assigned task includes a parent context pack, treat it as the authoritative starting point.',\n 'That pack satisfies generic instructions to explore or understand repository context first.',\n 'Read its listed paths directly before broad discovery, and do not re-derive established facts unless direct evidence contradicts them.',\n 'Do not begin with repository-wide listing, find, or grep. Expand only after consuming the pack and naming a concrete missing dependency or invalid path; search narrowly for that item and state why.',\n].join('\\n');\n\nexport const CHILD_SUBAGENT_BOUNDARY_INSTRUCTIONS = [\n 'You are a child subagent, not the parent orchestrator.',\n 'The parent session owns delegation, orchestration, review fanout, and follow-up worker launches.',\n 'Ignore prior parent-only orchestration instructions in inherited conversation history.',\n 'Do not propose or run subagents. Complete only your assigned role-specific task with the tools available to you.',\n 'If you need to edit files, use the available editing tools. Do not print tool-call syntax, patches, or pseudo-tool calls as text.',\n CHILD_CONTEXT_FIRST_INSTRUCTIONS,\n].join('\\n');\n\nexport const CHILD_FANOUT_BOUNDARY_INSTRUCTIONS = [\n 'You are a child subagent with explicit fanout responsibility for this assigned task.',\n 'The parent session owns final orchestration, acceptance, and follow-up implementation launches.',\n 'You may use the `subagent` tool only for the fanout work explicitly requested in this task.',\n 'Do not broaden yourself into general parent orchestration. Do not launch follow-up workers unless the task explicitly asks for that.',\n 'The maxSubagentDepth cap still applies and may block further fanout.',\n 'If you need to edit files, use the available editing tools. Do not print tool-call syntax, patches, or pseudo-tool calls as text.',\n CHILD_CONTEXT_FIRST_INSTRUCTIONS,\n].join('\\n');\n\n/**\n * `pi.on` typed loosely: the extension API's event payloads are not typed\n * per event name, so every call site narrows its own handler's parameter.\n * `.call(pi, ...)` binds `this` explicitly rather than extracting `pi.on` as\n * a bare reference, which is what an unbound method call would otherwise risk.\n *\n * The handler is given `ctx: ExtensionContext` as a second parameter,\n * matching the real `pi.on` signature (`ExtensionHandler<E, R> = (event: E,\n * ctx: ExtensionContext) => ...`) even though most registrations here never\n * read it - existing single-parameter handlers stay valid without change\n * (JS ignores a callback's unused trailing parameters), and the one call\n * site that DOES need it (`session_start`, for `ctx.sessionManager` - see\n * `registerDeliverableGuardCheck`'s doc) no longer has to reach past this\n * wrapper to get it.\n */\nfunction onEvent<E = unknown>(\n pi: ExtensionAPI,\n event: string,\n handler: (event: E, ctx: ExtensionContext) => unknown,\n): void {\n (pi.on as unknown as (event: string, handler: (event: E, ctx: ExtensionContext) => unknown) => void).call(\n pi,\n event,\n handler,\n );\n}\n\n/** A text block from an assistant message's content array. Narrowed structurally, not imported from `@earendil-works/pi-ai`, matching this file's habit of ad-hoc event-payload types (see `onEvent`'s own doc). */\ninterface AssistantTextBlock {\n type: 'text';\n text: string;\n}\n\n/** The subset of `AgentEndEvent`/message shape this file actually reads. */\ninterface DeliverableCheckMessage {\n role?: string;\n content?: unknown;\n}\n\nfunction isAssistantTextBlock(block: unknown): block is AssistantTextBlock {\n return (\n typeof block === 'object' &&\n block !== null &&\n (block as { type?: unknown }).type === 'text' &&\n typeof (block as { text?: unknown }).text === 'string'\n );\n}\n\n/**\n * The last non-empty assistant text found in `messages`, or `''`.\n *\n * `DeliverableGuardInput.summary` is checked for the `'summary'`-kind\n * expectation, and nothing in this package tracks a run's summary text\n * per-turn - `RunnerReporting` only computes one at the terminal\n * `mutateTerminalStatus` callback, which has not happened yet when a\n * mid-run deliverable check needs to run. The assistant's own most recent\n * text output is the best available proxy for \"what would this run's\n * summary be if it stopped now\" without a dedicated tracking mechanism this\n * package does not have yet. Best-effort by construction: an unparseable or\n * missing message reads as an empty summary, which is the SAFE failure\n * direction for this guard (nudging once more than strictly necessary,\n * never fewer times than necessary).\n */\nexport function extractAssistantSummaryText(messages: readonly DeliverableCheckMessage[]): string {\n for (let index = messages.length - 1; index >= 0; index -= 1) {\n const message = messages[index];\n if (message?.role !== 'assistant' || !Array.isArray(message.content)) continue;\n const text = message.content\n .filter(isAssistantTextBlock)\n .map((block) => block.text)\n .join('\\n')\n .trim();\n if (text) return text;\n }\n return '';\n}\n\n/**\n * Wires `DeliverableGuard`'s write side into this process. See the module\n * doc's overall framing: everything else in the missing-deliverable chain\n * (detection, the single nudge, escalation, the fold into `status.json`,\n * `AsyncJobTracker`'s read, and internal completion monitoring) already exist;\n * nothing called them. This is that call.\n *\n * WHY THIS RESOLVES ITS OWN CONTAINER, HERE:\n * `RunnerBootstrap`/`RunnerExecution`/`DeliverableGuard` are DI-bound\n * services (`container/modules/runs.ts`), and this file is the one place\n * `container/index.ts` documents as the in-child composition root\n * (`createPromptRuntimeContainer()`) - filed under `src/extensions/**`, the\n * boundary reserved for composition roots (see `vibe-lint.config.yaml`'s\n * `extensions` boundary), not under `src/runs/**` where it used to live. It\n * was moved here specifically so it could stop being the one exception\n * carved into the `runs` boundary's allowlist for `src/container/index.ts` -\n * a domain that can build its own container can bypass every composition\n * decision above it, and that hole is now closed rather than merely\n * documented. `container` is an optional parameter, defaulting to the real\n * container, purely so a test can supply one pre-loaded with fakes via\n * `container.rebind(...)` instead of standing up the real filesystem-backed\n * services.\n *\n * WHY `session_start` BOOTSTRAPS, AND WHY IT ONLY EVER RUNS ONCE:\n * `RunnerBootstrap.bootstrap()` is genuinely the FIRST real caller this\n * package has ever had for it - it opens `status.json`, wires\n * `TerminalPersistenceService`'s finalize callback, and writes the startup\n * handshake `SpawnHandshake.waitForHandshake()` on the parent side blocks\n * on. `RunnerExecution.start()` then begins watching the control inbox.\n * `ControlChannelWatcher` depends on `PollScheduler`\n * (`control-channel.ts:809`), which nothing in this package's runner\n * services ever calls `.start()` on by itself (see `pollScheduler.ts`'s own\n * AVOID note: \"a registered-but-unstarted PollScheduler never ticks\") - so\n * this starts it explicitly, once, alongside bootstrap. The `resolved` guard\n * makes a stray second `session_start` (nothing in this file's other\n * registrations assumes it fires only once) a no-op rather than a second\n * bootstrap of the same run.\n *\n * WHY `execution.start()` IS GIVEN AN `onSteer` HANDLER:\n * `DeliverableGuard.deliverNudge()` drops a nudge into this run's OWN\n * steer-requests queue via `requestAsyncSteer` (see that method's doc) and\n * calls it delivered once the write succeeds. But the write alone does not\n * reach the child: `ControlChannelWatcher`, wired up by `execution.start()`,\n * claims and commits (deletes) every request it finds in that queue whether\n * or not a handler is registered for it - found by testing this file\n * against the REAL `ControlChannelWatcher` rather than a fake with no side\n * effects, which is exactly the failure mode this task kept turning up\n * elsewhere (`createRunsModule()` never loaded into any root;\n * `PollScheduler.start()` never called). `onSteer` is the missing delivery\n * half: it reuses `formatSteerMessage`/`sendUserMessage`, the same\n * mechanism `registerSteeringInbox` already uses for its own, separate\n * steer queue, so a nudge actually lands in the child's conversation instead\n * of being silently claimed and discarded.\n *\n * WHY `agent_end`, NOT `turn_end`:\n * `agent_end`'s own event (`AgentEndEvent.messages`) carries the full\n * message history for this agent loop, which `extractAssistantSummaryText`\n * reads from - `turn_end` only carries the one message that ended that turn,\n * not the memory of what preceded it, and `DeliverableGuard`'s own doc\n * frames this check as \"end-of-turn or idle\", not \"every turn.\"\n *\n * `unansweredAsks` AND `memberId`:\n * Both come from this run's own bound `TeamMemberContext`, which\n * `RunnerBootstrap.bootstrap()` already holds (from registering as a team\n * member) and now returns on its result. `memberId` is `teamContext.memberId`\n * directly. `unansweredAsks` calls `pendingAsksAddressedTo(teamContext,\n * teamContext.memberId, now)` - see `deliverable-guard.ts`'s own AVOID\n * section for why `DeliverableGuard` cannot call that itself, and that\n * function's own doc for why it deliberately returns id/sender/time only,\n * never the question's text (this maps its result into a factual, non-\n * fabricated placeholder message rather than guessing at content it was\n * never given). A standalone run with no team root forwarded has no\n * `teamContext` at all, in which case both are simply omitted - narrower\n * than the real behaviour, never wider, matching every other gap in this\n * file when there is genuinely nothing to report rather than something\n * unknown to guess at.\n *\n * `session_start` ALSO RECORDS THIS RUN'S OWN SESSION FILE:\n * `ctx.sessionManager.getSessionFile()` is the only place in this process\n * that ever answers \"what is my own transcript path\" - see\n * `runnerReporting.ts`'s header for why the value has to come from here\n * (the child) rather than be derived by the parent. `RunnerReporting`\n * validates and retains it while `RunnerBootstrap` writes it before the\n * ready handshake. `getSessionFile()` can return `undefined` (no persisted\n * transcript for this run); that case is simply not recorded, the same\n * \"omit rather than guess\" shape as `unansweredAsks`/`teamContext` above.\n */\nexport function registerRunnerLifecycle(pi: ExtensionAPI, container: Container = createPromptRuntimeContainer()): void {\n const runId = process.env[SUBAGENT_RUN_ID_ENV]?.trim();\n if (!runId) return;\n\n const pollScheduler = container.get<IPollScheduler>(DOOM_TEAM_TYPES.PollScheduler);\n const bootstrap = container.get<IRunnerBootstrap>(DOOM_TEAM_TYPES.RunnerBootstrap);\n const execution = container.get<IRunnerExecution>(DOOM_TEAM_TYPES.RunnerExecution);\n const reporting = container.get<IRunnerReporting>(DOOM_TEAM_TYPES.RunnerReporting);\n\n let resolved: { teamContext: TeamMemberContext | undefined } | undefined;\n let cumulativeTokens: number | undefined;\n let toolCount = 0;\n const countedMessages = new WeakSet<object>();\n\n onEvent(pi, 'session_start', (_event, ctx) => {\n if (resolved) return;\n pollScheduler.start();\n const sessionFile = ctx.sessionManager.getSessionFile();\n const recordedSessionFile = sessionFile ? reporting.recordSessionFile(sessionFile) : undefined;\n const bootstrapped = bootstrap.bootstrap(runId, recordedSessionFile);\n if (bootstrapped.teamContext) Object.assign(process.env, nativeTeamMemberEnvironment(bootstrapped.teamContext));\n // `onSteer` is the delivery half of `DeliverableGuard.deliverNudge`'s\n // write side (see `RunnerExecutionHandlers.onSteer`'s own doc, which\n // cross-references it): `deliverNudge` drops a request into this run's\n // OWN steer-requests queue via `requestAsyncSteer`, and\n // `ControlChannelWatcher` (wired up by `execution.start()` below) claims\n // it and calls this handler. Without it, `execution.start()` still\n // claims and commits the nudge - `deliverNudge` reports\n // `nudgeDelivered: true`, `status.json` still shows `needs_attention` -\n // but the request is silently discarded before it ever reaches the\n // child's own conversation. `formatSteerMessage`/`sendUserMessage` are\n // the exact same delivery this file already uses for\n // `registerSteeringInbox`'s separate queue.\n execution.start(runId, {\n onSteer: (request) => {\n const sendUserMessage = (\n pi as { sendUserMessage?: (content: string, options: { deliverAs: 'steer' }) => unknown }\n ).sendUserMessage;\n if (!sendUserMessage) {\n acknowledgeRunnerSteer(request, 'failed', 'Child Pi session does not support sendUserMessage steering.');\n return;\n }\n try {\n sendUserMessage(formatSteerMessage(request), { deliverAs: 'steer' });\n acknowledgeRunnerSteer(request, 'delivered', 'Pi accepted the correlated steering input.');\n } catch (error) {\n acknowledgeRunnerSteer(request, 'failed', error instanceof Error ? error.message : String(error));\n throw error;\n }\n },\n });\n resolved = { teamContext: bootstrapped.teamContext };\n execution.setActivity('working');\n });\n\n onEvent(pi, 'agent_start', () => {\n if (resolved) execution.setActivity('working');\n });\n onEvent<{ message?: ChildTranscriptMessage }>(pi, 'message_end', (event) => {\n if (!resolved || !event.message || typeof event.message !== 'object') return;\n if (countedMessages.has(event.message)) return;\n countedMessages.add(event.message);\n const messageTokens = getMessageUsageTokens(event.message);\n if (messageTokens === undefined) return;\n cumulativeTokens = (cumulativeTokens ?? 0) + messageTokens;\n execution.setProgress({ tokens: cumulativeTokens });\n });\n onEvent<{ toolName?: string; tool?: { name?: string }; args?: { action?: string } }>(\n pi,\n 'tool_execution_start',\n (event) => {\n if (!resolved) return;\n const toolName = event.toolName ?? event.tool?.name;\n toolCount += 1;\n execution.setProgress({\n toolCount,\n ...(typeof toolName === 'string' && toolName.length > 0 ? { currentTool: toolName } : {}),\n });\n execution.setActivity(\n toolName === NATIVE_TEAM_TOOL_NAME && event.args?.action === 'ask' ? 'waiting_for_reply' : 'tool',\n );\n },\n );\n onEvent(pi, 'tool_execution_end', () => {\n if (resolved) execution.setActivity('working');\n });\n onEvent<{ messages: DeliverableCheckMessage[] }>(pi, 'agent_end', (event) => {\n if (!resolved) return; // session_start has not bootstrapped yet; nothing to report against.\n execution.setActivity('finalizing');\n const summary = extractAssistantSummaryText(event.messages);\n execution.complete(true, summary);\n });\n}\n\nconst PARENT_ONLY_CUSTOM_MESSAGE_TYPES = new Set([\n 'subagent-orchestration-instructions',\n 'subagent-slash-result',\n 'subagent-slash-text-result',\n 'subagent-notify',\n 'subagent_control_notice',\n 'subagent-control',\n 'subagent-control-notice',\n]);\nconst SUBAGENT_ORCHESTRATION_SKILL_NAME_PATTERN = /<name>\\s*pi-subagents\\s*<\\/name>/;\nconst PROJECT_CONTEXT_HEADER = '\\n\\n# Project Context\\n\\nProject-specific instructions and guidelines:\\n\\n';\nconst SKILLS_HEADER = '\\n\\nThe following skills provide specialized instructions for specific tasks.';\nconst DATE_HEADER = '\\nCurrent date:';\n\nfunction readBooleanEnv(name: string): boolean | undefined {\n const value = process.env[name];\n if (value === undefined) return undefined;\n return value !== '0';\n}\n\nfunction readRequiredChildTools(): string[] | undefined {\n const encoded = process.env[REQUIRED_CHILD_TOOLS_ENV]?.trim();\n if (!encoded) return undefined;\n const required = JSON.parse(encoded) as unknown;\n if (!Array.isArray(required) || required.some((name) => typeof name !== 'string' || !name)) {\n throw new Error(`Invalid ${REQUIRED_CHILD_TOOLS_ENV} payload.`);\n }\n return required;\n}\n\nfunction readMcpDirectChildTools(): string[] | undefined {\n const encoded = process.env[MCP_DIRECT_CHILD_TOOLS_ENV]?.trim();\n if (!encoded) return undefined;\n try {\n const tools = JSON.parse(encoded) as unknown;\n if (!Array.isArray(tools) || tools.some((name) => typeof name !== 'string' || !name)) return undefined;\n return tools;\n } catch {\n return undefined;\n }\n}\n\nfunction refreshChildToolDiagnostic(pi: ExtensionAPI): ChildToolDiagnostic | undefined {\n const filePath = process.env[CHILD_TOOL_DIAGNOSTIC_PATH_ENV]?.trim();\n const required = readRequiredChildTools();\n if (!filePath || !required) return undefined;\n const available = pi.getAllTools().map((tool) => tool.name);\n return writeChildToolDiagnostic(\n filePath,\n required,\n available,\n process.env[SUBAGENT_CHILD_AGENT_ENV]?.trim(),\n readMcpDirectChildTools(),\n );\n}\n\nfunction findSectionEnd(prompt: string, startIndex: number, nextHeaders: string[]): number {\n let endIndex = prompt.length;\n for (const header of nextHeaders) {\n const index = prompt.indexOf(header, startIndex);\n if (index !== -1 && index < endIndex) {\n endIndex = index;\n }\n }\n return endIndex;\n}\n\nexport function stripProjectContext(prompt: string): string {\n const startIndex = prompt.indexOf(PROJECT_CONTEXT_HEADER);\n if (startIndex === -1) return prompt;\n const endIndex = findSectionEnd(prompt, startIndex + PROJECT_CONTEXT_HEADER.length, [SKILLS_HEADER, DATE_HEADER]);\n return `${prompt.slice(0, startIndex)}${prompt.slice(endIndex)}`;\n}\n\nexport function stripInheritedSkills(prompt: string): string {\n const startIndex = prompt.indexOf(SKILLS_HEADER);\n if (startIndex === -1) return prompt;\n const endIndex = findSectionEnd(prompt, startIndex + SKILLS_HEADER.length, [DATE_HEADER]);\n return `${prompt.slice(0, startIndex)}${prompt.slice(endIndex)}`;\n}\n\nexport function stripSubagentOrchestrationSkill(prompt: string): string {\n return prompt\n .replace(/\\n{0,2}<skill\\s+name=[\"']pi-subagents[\"'][^>]*>[\\s\\S]*?<\\/skill>\\n{0,2}/g, '\\n\\n')\n .replace(/[ \\t]*<skill>\\s*[\\s\\S]*?<\\/skill>\\s*/g, (block) =>\n SUBAGENT_ORCHESTRATION_SKILL_NAME_PATTERN.test(block) ? '' : block,\n );\n}\n\nfunction stripChildBoundaryInstructions(prompt: string): string {\n let rewritten = prompt;\n for (const injectedInstructions of [\n CHILD_SUBAGENT_BOUNDARY_INSTRUCTIONS,\n CHILD_FANOUT_BOUNDARY_INSTRUCTIONS,\n STRUCTURED_OUTPUT_INSTRUCTIONS,\n ]) {\n rewritten = rewritten.split(injectedInstructions).join('');\n }\n return rewritten.replace(/^(?:[ \\t]*\\r?\\n)+/, '');\n}\n\nexport function rewriteSubagentPrompt(\n prompt: string,\n options: { inheritProjectContext: boolean; inheritSkills: boolean; fanoutChild?: boolean },\n): string {\n let rewritten = prompt;\n if (!options.inheritProjectContext) {\n rewritten = stripProjectContext(rewritten);\n }\n if (!options.inheritSkills) {\n rewritten = stripInheritedSkills(rewritten);\n }\n rewritten = stripSubagentOrchestrationSkill(rewritten);\n rewritten = stripChildBoundaryInstructions(rewritten);\n const boundary = options.fanoutChild ? CHILD_FANOUT_BOUNDARY_INSTRUCTIONS : CHILD_SUBAGENT_BOUNDARY_INSTRUCTIONS;\n const structured = process.env[STRUCTURED_OUTPUT_CAPTURE_ENV] ? `\\n\\n${STRUCTURED_OUTPUT_INSTRUCTIONS}` : '';\n return `${boundary}${structured}\\n\\n${rewritten}`;\n}\n\nfunction isParentOnlySubagentMessage(message: unknown): boolean {\n const m = message as { role?: string; customType?: string };\n if (m?.role !== 'custom' || typeof m.customType !== 'string') return false;\n return PARENT_ONLY_CUSTOM_MESSAGE_TYPES.has(m.customType);\n}\n\nfunction isSubagentToolResultMessage(message: unknown): boolean {\n const m = message as { role?: string; toolName?: string };\n return m?.role === 'toolResult' && m.toolName === 'subagent';\n}\n\nfunction isSubagentToolCallBlock(block: unknown): boolean {\n const b = block as { type?: string; name?: string };\n return b?.type === 'toolCall' && b.name === 'subagent';\n}\n\nfunction stripAssistantSubagentToolCallBlocks(message: unknown): unknown {\n const m = message as { role?: string; content?: unknown };\n if (m?.role !== 'assistant' || !Array.isArray(m.content)) return message;\n const filteredContent = m.content.filter((block) => !isSubagentToolCallBlock(block));\n if (filteredContent.length === m.content.length) return message;\n if (filteredContent.length === 0) return undefined;\n return { ...m, content: filteredContent };\n}\n\nexport function stripParentOnlySubagentMessages(messages: unknown[]): unknown[] {\n const preserveCurrentFanoutToolHistory = process.env[SUBAGENT_FANOUT_CHILD_ENV] === '1';\n let changed = false;\n const filtered: unknown[] = [];\n for (const message of messages) {\n if (\n isParentOnlySubagentMessage(message) ||\n (!preserveCurrentFanoutToolHistory && isSubagentToolResultMessage(message))\n ) {\n changed = true;\n continue;\n }\n const stripped = preserveCurrentFanoutToolHistory ? message : stripAssistantSubagentToolCallBlocks(message);\n if (stripped === undefined) {\n changed = true;\n continue;\n }\n if (stripped !== message) changed = true;\n filtered.push(stripped);\n }\n return changed ? filtered : messages;\n}\n\nexport function formatSteerMessage(request: SteerRequest): string {\n return [\n 'Mid-run steering from the parent orchestrator:',\n '',\n request.message,\n '',\n 'Incorporate this guidance at the next safe point. Do not restart the task unless the guidance explicitly asks you to.',\n ].join('\\n');\n}\n\nfunction acknowledgeRunnerSteer(request: SteerRequest, state: 'delivered' | 'failed', message: string): void {\n const ackDir = process.env[SUBAGENT_STEER_ACK_DIR_ENV]?.trim();\n const childIndex = Number(process.env[SUBAGENT_CHILD_INDEX_ENV]);\n if (!ackDir || !Number.isInteger(childIndex) || childIndex < 0) return;\n writeSteerAckAt(steerAckPathFromDir(ackDir, request.id), {\n requestId: request.id,\n index: childIndex,\n ts: Date.now(),\n state,\n message,\n });\n}\n\nfunction registerToolBudget(\n pi: ExtensionAPI,\n budget: ResolvedToolBudget | undefined,\n diagnostics: PromptRuntimeDiagnostics,\n): void {\n if (!budget) return;\n let toolCount = 0;\n let softNudged = false;\n const sendUserMessage = (pi as { sendUserMessage?: (content: string, options: { deliverAs: 'steer' }) => unknown })\n .sendUserMessage;\n onEvent<{ toolName?: string }>(pi, 'tool_call', (event) => {\n const toolName = typeof event.toolName === 'string' ? event.toolName : 'tool';\n toolCount++;\n if (budget.soft !== undefined && toolCount >= budget.soft && !softNudged) {\n softNudged = true;\n try {\n sendUserMessage?.(toolBudgetSoftNudge(budget, toolCount), { deliverAs: 'steer' });\n } catch (error) {\n // Advisory nudge only; the child's own output is what matters. Recorded\n // rather than discarded so a host that never accepts steering is\n // discoverable instead of silently dropping every nudge.\n diagnostics.steerNudgeFailures += 1;\n diagnostics.lastError = error;\n }\n }\n if (!shouldBlockToolForBudget(budget, toolName, toolCount)) return undefined;\n return { block: true, reason: toolBudgetBlockedMessage(budget, toolName, toolCount) };\n });\n}\n\n/**\n * Deliver mid-run steer requests queued for THIS child (by fan-out index)\n * into its own session via `sendUserMessage`. See the module doc's FIX for\n * why this claims each request individually rather than batch-deleting.\n */\nexport function registerSteeringInbox(\n pi: ExtensionAPI,\n deps: {\n watch?: typeof fs.watch;\n nativeRealpath?: (filePath: string) => string;\n diagnostics?: PromptRuntimeDiagnostics;\n } = {},\n): void {\n const diagnostics = deps.diagnostics ?? createPromptRuntimeDiagnostics();\n const steerInbox = process.env[SUBAGENT_STEER_INBOX_ENV]?.trim();\n if (!steerInbox) return;\n const capabilityPath = process.env[SUBAGENT_STEER_CAPABILITY_ENV]?.trim();\n const ackDir = process.env[SUBAGENT_STEER_ACK_DIR_ENV]?.trim();\n const sendUserMessage = (pi as { sendUserMessage?: (content: string, options: { deliverAs: 'steer' }) => unknown })\n .sendUserMessage;\n const childIndex = Number(process.env[SUBAGENT_CHILD_INDEX_ENV]);\n const pending = new Map<string, string[]>();\n let disposed = false;\n let flushing = false;\n let started = false;\n const canSteer = typeof sendUserMessage === 'function';\n let watcher: fs.FSWatcher | undefined;\n let interval: NodeJS.Timeout | undefined;\n\n const acknowledge = (request: SteerRequest, state: 'delivered' | 'failed', message: string): void => {\n if (!ackDir || !Number.isInteger(childIndex) || childIndex < 0) return;\n writeSteerAckAt(steerAckPathFromDir(ackDir, request.id), {\n requestId: request.id,\n index: childIndex,\n ts: Date.now(),\n state,\n message,\n });\n };\n const publishCapability = (): void => {\n if (!capabilityPath || !Number.isInteger(childIndex) || childIndex < 0) return;\n writeSteerCapabilityAt(capabilityPath, {\n index: childIndex,\n pid: process.pid,\n readyAt: Date.now(),\n supported: canSteer,\n });\n };\n\n const flush = (): void => {\n if (disposed || flushing) return;\n flushing = true;\n try {\n for (const claim of claimSteerRequestsFromDir(steerInbox)) {\n if (!canSteer || typeof sendUserMessage !== 'function') {\n acknowledge(claim.request, 'failed', 'Child Pi session does not support sendUserMessage steering.');\n claim.commit();\n continue;\n }\n const formatted = formatSteerMessage(claim.request);\n const ids = pending.get(formatted) ?? [];\n ids.push(claim.request.id);\n pending.set(formatted, ids);\n try {\n sendUserMessage(formatted, { deliverAs: 'steer' });\n claim.commit();\n } catch (error) {\n ids.pop();\n if (ids.length === 0) pending.delete(formatted);\n // Recoverable: this claim goes back to the queue for the next\n // flush to retry, instead of being lost. See the module doc's FIX.\n claim.release();\n acknowledge(claim.request, 'failed', error instanceof Error ? error.message : String(error));\n }\n }\n } finally {\n flushing = false;\n }\n };\n const onInput = (event: unknown): undefined => {\n if (disposed || !event || typeof event !== 'object') return undefined;\n const input = event as { source?: unknown; streamingBehavior?: unknown; text?: unknown; content?: unknown };\n if (input.source !== 'extension' || input.streamingBehavior !== 'steer') return undefined;\n const text =\n typeof input.text === 'string' ? input.text : typeof input.content === 'string' ? input.content : undefined;\n if (!text) return undefined;\n const ids = pending.get(text);\n const requestId = ids?.shift();\n if (!requestId) return undefined;\n if (ids?.length === 0) pending.delete(text);\n acknowledge(\n { type: 'steer', id: requestId, ts: Date.now(), message: text },\n 'delivered',\n 'Pi accepted the correlated steering input.',\n );\n return undefined;\n };\n const start = (): void => {\n if (started || disposed) return;\n try {\n fs.mkdirSync(steerInbox, { recursive: true });\n publishCapability();\n } catch {\n // No channel to report a startup failure on from inside the child;\n // the parent observes a missing capability file and treats it as\n // \"steering unsupported for this child\" on its own.\n return;\n }\n started = true;\n try {\n watcher = (deps.watch ?? fs.watch)(resolveWatchPath(steerInbox, deps.nativeRealpath), () => flush());\n watcher.on('error', (error) => {\n // fs.watch emits on transient FS errors and the interval poll below\n // keeps delivery live regardless, so this is not fatal. Recorded so a\n // watch that fails on every event is distinguishable from a quiet inbox.\n diagnostics.watchErrors += 1;\n diagnostics.lastError = error;\n });\n } catch {\n watcher = undefined;\n }\n interval = setInterval(flush, STEER_FLUSH_POLL_INTERVAL_MS);\n interval.unref?.();\n };\n const activate = (): undefined => {\n start();\n flush();\n return undefined;\n };\n\n // Register input before the watcher so an accepted extension input cannot race request dispatch.\n onEvent(pi, 'input', onInput);\n onEvent(pi, 'session_start', () => start());\n for (const eventName of [\n 'message_start',\n 'message_update',\n 'message_end',\n 'tool_execution_start',\n 'tool_execution_end',\n 'turn_end',\n ] as const) {\n onEvent(pi, eventName, activate);\n }\n onEvent(pi, 'session_shutdown', () => {\n disposed = true;\n try {\n watcher?.close();\n } catch (error) {\n // Best effort; the process is shutting down regardless. Still recorded,\n // because a close that always fails is a leaked descriptor per run.\n diagnostics.watchCloseFailures += 1;\n diagnostics.lastError = error;\n }\n if (interval) clearInterval(interval);\n });\n}\n\n/**\n * `diagnostics` is optional and defaults to a fresh object: the `.cts` entry\n * point calls this with a single argument (`pi`), matching the host contract\n * `resolveRuntimeExtensionPath` resolves onto every child's `--extension`\n * args, so that call keeps working unchanged. A caller that wants to observe\n * what this runtime absorbed - see `PromptRuntimeDiagnostics` - passes its\n * own object and keeps the reference; this function only ever mutates it, it\n * never owns or resets it.\n */\nexport function registerSubagentPromptRuntime(\n pi: ExtensionAPI,\n diagnostics: PromptRuntimeDiagnostics = createPromptRuntimeDiagnostics(),\n): void {\n // First, before any scoped path is touched. Pi loads extensions through jiti\n // with `moduleCache: false`, so this extension gets its OWN instance of\n // `shared/paths.ts` - the scope the surrounding runner process adopted is not\n // visible here, and has to be read from the environment again.\n adoptSessionScopeFromEnv();\n registerSteeringInbox(pi, { diagnostics });\n registerToolBudget(\n pi,\n decodeToolBudgetEnv(process.env[TOOL_BUDGET_ENV], { allowZero: process.env[TOOL_BUDGET_ZERO_AUTH_ENV] === '1' }),\n diagnostics,\n );\n // One container for this whole registration, not one built inside each\n // resolver's own default parameter: this process has exactly one\n // composition root (see container/index.ts and this function's own doc),\n // and a second independent createPromptRuntimeContainer() call anywhere\n // else in this function would silently mean two sets of \"singletons\" in\n // one process, defeating the point of a shared container.\n const container = createPromptRuntimeContainer();\n registerRunnerLifecycle(pi, container);\n\n const teamChannels = container.get<INativeTeamChannelService>(DOOM_TEAM_TYPES.NativeTeamChannelService);\n\n onEvent(pi, 'session_start', () => {\n const teamRuntime = teamChannels.createRuntime(pi);\n teamRuntime.bindChildFromEnvironment();\n });\n onEvent(pi, 'agent_start', () => {\n refreshChildToolDiagnostic(pi);\n });\n // `agent_end` intentionally does not drain outstanding work here. See the\n // module doc's \"WHAT IS DELIBERATELY NOT WIRED YET\" for why.\n\n const structuredOutputPath = process.env[STRUCTURED_OUTPUT_CAPTURE_ENV];\n const structuredSchemaPath = process.env[STRUCTURED_OUTPUT_SCHEMA_ENV];\n if (structuredOutputPath && structuredSchemaPath) {\n const schema = JSON.parse(fs.readFileSync(structuredSchemaPath, 'utf-8')) as JsonSchemaObject;\n const parameters = createStructuredOutputToolParameters(schema);\n const validator = new StructuredOutputValidator();\n const registerTool = (\n pi.registerTool as unknown as (tool: {\n name: string;\n label: string;\n description: string;\n parameters: unknown;\n execute: (_id: string, params: { value: unknown }) => Promise<unknown>;\n }) => void\n ).bind(pi);\n registerTool({\n name: 'structured_output',\n label: 'Structured Output',\n description: 'Submit the required final structured output for this subagent step. This terminates the step.',\n parameters: parameters as never,\n async execute(_id: string, params: { value: unknown }) {\n const validation = await validator.validateValue(schema, params.value);\n if (validation.status === 'invalid') {\n throw new Error(`Structured output validation failed: ${validation.message}`);\n }\n fs.mkdirSync(path.dirname(structuredOutputPath), { recursive: true });\n fs.writeFileSync(structuredOutputPath, JSON.stringify(params.value), { mode: 0o600 });\n return {\n content: [{ type: 'text', text: 'Structured output captured.' }],\n details: { path: structuredOutputPath },\n terminate: true,\n };\n },\n });\n }\n\n onEvent<{ messages: unknown[] }>(pi, 'context', (event) => {\n const messages = stripParentOnlySubagentMessages(event.messages);\n if (messages === event.messages) return undefined;\n return { messages };\n });\n\n onEvent<{ systemPrompt: string }>(pi, 'before_agent_start', async (event) => {\n const intercomSessionName = process.env[SUBAGENT_INTERCOM_SESSION_NAME_ENV]?.trim();\n if (intercomSessionName && typeof pi.setSessionName === 'function') {\n pi.setSessionName(intercomSessionName);\n }\n\n const inheritProjectContext = readBooleanEnv(INHERIT_PROJECT_CONTEXT_ENV);\n const inheritSkills = readBooleanEnv(INHERIT_SKILLS_ENV);\n const fanoutChild = readBooleanEnv(SUBAGENT_FANOUT_CHILD_ENV);\n let rewritten = event.systemPrompt;\n if (inheritProjectContext !== undefined || inheritSkills !== undefined || fanoutChild !== undefined) {\n rewritten = rewriteSubagentPrompt(event.systemPrompt, {\n inheritProjectContext: inheritProjectContext ?? true,\n inheritSkills: inheritSkills ?? true,\n fanoutChild: fanoutChild === true,\n });\n }\n if (rewritten === event.systemPrompt) return;\n return { systemPrompt: rewritten };\n });\n}\n"],"mappings":"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"}
|