@selesai/code 0.13.15 → 0.13.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +2 -14
  3. package/dist/bun/cli.d.ts +3 -1
  4. package/dist/bun/cli.js +3 -9
  5. package/dist/bun/{register-bedrock.js → runtime-setup.js} +5 -0
  6. package/dist/bun/sandbox-env-setup.d.ts +1 -0
  7. package/dist/bun/sandbox-env-setup.js +3 -0
  8. package/dist/cli/auth-command.d.ts +23 -0
  9. package/dist/cli/auth-command.js +102 -0
  10. package/dist/cli/config-selector.js +2 -1
  11. package/dist/cli/setup.d.ts +1 -0
  12. package/dist/cli/setup.js +11 -0
  13. package/dist/cli.js +2 -14
  14. package/dist/config.d.ts +3 -2
  15. package/dist/config.js +9 -4
  16. package/dist/core/agent-session-runtime.js +15 -7
  17. package/dist/core/agent-session.d.ts +2 -6
  18. package/dist/core/agent-session.js +15 -4
  19. package/dist/core/compaction/branch-summarization.d.ts +1 -1
  20. package/dist/core/compaction/branch-summarization.js +2 -1
  21. package/dist/core/extensions/loader.js +3 -0
  22. package/dist/core/extensions/types.d.ts +16 -2
  23. package/dist/core/http-dispatcher.js +2 -0
  24. package/dist/core/keybindings.d.ts +5 -0
  25. package/dist/core/keybindings.js +4 -0
  26. package/dist/core/messages.d.ts +1 -1
  27. package/dist/core/model-config.d.ts +15 -0
  28. package/dist/core/model-config.js +3 -0
  29. package/dist/core/model-runtime.d.ts +1 -0
  30. package/dist/core/model-runtime.js +5 -2
  31. package/dist/core/provider-composer.js +8 -2
  32. package/dist/core/session-export.d.ts +3 -0
  33. package/dist/core/session-export.js +31 -0
  34. package/dist/core/session-manager.d.ts +3 -2
  35. package/dist/core/session-manager.js +40 -13
  36. package/dist/core/skills.d.ts +1 -1
  37. package/dist/core/skills.js +4 -2
  38. package/dist/core/system-prompt.js +10 -10
  39. package/dist/core/tools/bash.js +3 -117
  40. package/dist/core/tools/edit.d.ts +1 -12
  41. package/dist/core/tools/edit.js +5 -163
  42. package/dist/core/tools/find.js +4 -55
  43. package/dist/core/tools/grep.js +4 -60
  44. package/dist/core/tools/ls.js +4 -49
  45. package/dist/core/tools/read.d.ts +4 -0
  46. package/dist/core/tools/read.js +10 -122
  47. package/dist/core/tools/renderers/bash.d.ts +11 -0
  48. package/dist/core/tools/renderers/bash.js +129 -0
  49. package/dist/core/tools/renderers/edit.d.ts +22 -0
  50. package/dist/core/tools/renderers/edit.js +166 -0
  51. package/dist/core/tools/renderers/find.d.ts +9 -0
  52. package/dist/core/tools/renderers/find.js +63 -0
  53. package/dist/core/tools/renderers/grep.d.ts +9 -0
  54. package/dist/core/tools/renderers/grep.js +68 -0
  55. package/dist/core/tools/renderers/index.d.ts +27 -0
  56. package/dist/core/tools/renderers/index.js +46 -0
  57. package/dist/core/tools/renderers/ls.d.ts +9 -0
  58. package/dist/core/tools/renderers/ls.js +57 -0
  59. package/dist/core/tools/renderers/read.d.ts +10 -0
  60. package/dist/core/tools/renderers/read.js +128 -0
  61. package/dist/core/tools/renderers/write.d.ts +9 -0
  62. package/dist/core/tools/renderers/write.js +152 -0
  63. package/dist/core/tools/write.js +5 -146
  64. package/dist/extensions/capability-gateway/index.ts +12 -1
  65. package/dist/extensions/capability-gateway/integration.test.ts +23 -0
  66. package/dist/extensions/pi-hermes-memory/CHANGELOG.md +18 -0
  67. package/dist/extensions/pi-hermes-memory/README.md +16 -12
  68. package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +1 -1
  69. package/dist/extensions/pi-hermes-memory/package-lock.json +587 -62
  70. package/dist/extensions/pi-hermes-memory/package.json +4 -4
  71. package/dist/extensions/pi-hermes-memory/src/config.ts +32 -0
  72. package/dist/extensions/pi-hermes-memory/src/constants.ts +12 -2
  73. package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +109 -51
  74. package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +9 -3
  75. package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +257 -98
  76. package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +9 -2
  77. package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +5 -0
  78. package/dist/extensions/pi-hermes-memory/src/index.ts +22 -2
  79. package/dist/extensions/pi-hermes-memory/src/paths.ts +1 -1
  80. package/dist/extensions/pi-hermes-memory/src/store/db.ts +6 -0
  81. package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +58 -1
  82. package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +60 -8
  83. package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +169 -7
  84. package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +7 -21
  85. package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +134 -15
  86. package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +4 -2
  87. package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +24 -9
  88. package/dist/extensions/pi-hermes-memory/src/types.ts +11 -0
  89. package/dist/extensions/pi-hermes-memory/tests/config.test.ts +42 -0
  90. package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +159 -3
  91. package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +452 -0
  92. package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +39 -0
  93. package/dist/extensions/pi-hermes-memory/tests/integration/corruption-recovery-integration.test.ts +91 -0
  94. package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +29 -0
  95. package/dist/extensions/pi-hermes-memory/tests/store/fts-query.test.ts +116 -0
  96. package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +163 -0
  97. package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +233 -0
  98. package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +12 -0
  99. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +175 -0
  100. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +2 -2
  101. package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +22 -0
  102. package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +37 -1
  103. package/dist/extensions/pi-intercom/CHANGELOG.md +13 -0
  104. package/dist/extensions/pi-intercom/README.md +16 -2
  105. package/dist/extensions/pi-intercom/broker/spawn.test.ts +19 -2
  106. package/dist/extensions/pi-intercom/broker/spawn.ts +4 -4
  107. package/dist/extensions/pi-intercom/index.ts +1 -1
  108. package/dist/extensions/pi-intercom/intercom.integration.test.ts +121 -2
  109. package/dist/extensions/pi-intercom/package.json +1 -1
  110. package/dist/extensions/pi-intercom/project-agent.test.ts +1 -1
  111. package/dist/extensions/pi-intercom/project-agent.ts +1 -6
  112. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +7 -6
  113. package/dist/extensions/pi-rewind-hook/index.test.ts +7 -0
  114. package/dist/extensions/pi-subagents/.github/workflows/test.yml +36 -4
  115. package/dist/extensions/pi-subagents/CHANGELOG.md +120 -0
  116. package/dist/extensions/pi-subagents/README.md +3 -3
  117. package/dist/extensions/pi-subagents/agents/researcher.md +23 -13
  118. package/dist/extensions/pi-subagents/agents/reviewer.md +1 -1
  119. package/dist/extensions/pi-subagents/agents/scout.md +1 -1
  120. package/dist/extensions/pi-subagents/docs/agents.md +32 -16
  121. package/dist/extensions/pi-subagents/docs/configuration.md +41 -15
  122. package/dist/extensions/pi-subagents/docs/extension-api.md +109 -6
  123. package/dist/extensions/pi-subagents/docs/missions.md +2 -0
  124. package/dist/extensions/pi-subagents/docs/models.md +58 -1
  125. package/dist/extensions/pi-subagents/docs/observability.md +50 -12
  126. package/dist/extensions/pi-subagents/docs/tool-reference.md +17 -10
  127. package/dist/extensions/pi-subagents/docs/watchdog.md +1 -1
  128. package/dist/extensions/pi-subagents/docs/workflows.md +26 -9
  129. package/dist/extensions/pi-subagents/package-lock.json +747 -177
  130. package/dist/extensions/pi-subagents/package.json +6 -4
  131. package/dist/extensions/pi-subagents/runner-server-preload.mjs +13 -0
  132. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +2 -1
  133. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
  134. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +21 -4
  135. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -1
  136. package/dist/extensions/pi-subagents/skills/pi-subagents/references/multi-lane-orchestration.md +2 -0
  137. package/dist/extensions/pi-subagents/src/agents/advertised-agent-prompt.ts +63 -0
  138. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +61 -16
  139. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
  140. package/dist/extensions/pi-subagents/src/agents/agents.ts +8 -0
  141. package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +0 -1
  142. package/dist/extensions/pi-subagents/src/api/{pi-args.ts → child-tool-plan.ts} +1 -1
  143. package/dist/extensions/pi-subagents/src/api/preflight.ts +7 -4
  144. package/dist/extensions/pi-subagents/src/api/shared-types.ts +2 -2
  145. package/dist/extensions/pi-subagents/src/api/workflow-resources.ts +6 -0
  146. package/dist/extensions/pi-subagents/src/extension/config.ts +4 -2
  147. package/dist/extensions/pi-subagents/src/extension/doctor.ts +2 -10
  148. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +9 -11
  149. package/dist/extensions/pi-subagents/src/extension/index.ts +99 -10
  150. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +13 -0
  151. package/dist/extensions/pi-subagents/src/extension/rpc.ts +7 -23
  152. package/dist/extensions/pi-subagents/src/extension/schemas.ts +11 -8
  153. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +25 -7
  154. package/dist/extensions/pi-subagents/src/integrations/pi-web-session-liveness.ts +73 -0
  155. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +228 -136
  156. package/dist/extensions/pi-subagents/src/intercom/supervisor-ui.ts +244 -0
  157. package/dist/extensions/pi-subagents/src/missions/workflow-state.ts +37 -16
  158. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +18 -18
  159. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +51 -25
  160. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +46 -3
  161. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -3
  162. package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +9 -0
  163. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +10 -12
  164. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -15
  165. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +40 -29
  166. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +8 -0
  167. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +79 -247
  168. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +88 -12
  169. package/dist/extensions/pi-subagents/src/runs/background/owned-process-tree.ts +6 -6
  170. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +24 -24
  171. package/dist/extensions/pi-subagents/src/runs/background/retained-nested-route-tracker.ts +96 -0
  172. package/dist/extensions/pi-subagents/src/runs/background/run-child-session.ts +642 -0
  173. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +75 -6
  174. package/dist/extensions/pi-subagents/src/runs/background/runner-aliases.ts +163 -0
  175. package/dist/extensions/pi-subagents/src/runs/background/runner-child-launch.ts +86 -0
  176. package/dist/extensions/pi-subagents/src/runs/background/runner-child-sessions.ts +31 -0
  177. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +18 -4
  178. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -1
  179. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +597 -1092
  180. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +3 -0
  181. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +4 -0
  182. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +20 -17
  183. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +296 -394
  184. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +4 -0
  185. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +3 -1
  186. package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +9 -5
  187. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +630 -283
  188. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +8 -5
  189. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-foreground-steering.ts +78 -98
  190. package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +3 -3
  191. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +16 -3
  192. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +1 -1
  193. package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +47 -47
  194. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +1 -2
  195. package/dist/extensions/pi-subagents/src/runs/shared/child-hooks.ts +174 -0
  196. package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +14 -3
  197. package/dist/extensions/pi-subagents/src/runs/shared/child-launch.ts +319 -0
  198. package/dist/extensions/pi-subagents/src/runs/shared/child-lifecycle.ts +25 -0
  199. package/dist/extensions/pi-subagents/src/runs/shared/child-runtime-config.ts +126 -0
  200. package/dist/extensions/pi-subagents/src/runs/shared/child-session.ts +373 -0
  201. package/dist/extensions/pi-subagents/src/runs/shared/child-tool-plan.ts +530 -0
  202. package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +2 -2
  203. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +2 -1
  204. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +16 -0
  205. package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +11 -11
  206. package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +30 -20
  207. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +5 -4
  208. package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +84 -15
  209. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +88 -12
  210. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +37 -53
  211. package/dist/extensions/pi-subagents/src/runs/shared/nested-path.ts +1 -1
  212. package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +18 -7
  213. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +57 -12
  214. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +3 -4
  215. package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +0 -11
  216. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +4 -1
  217. package/dist/extensions/pi-subagents/src/runs/shared/readonly-drain-observation.ts +42 -0
  218. package/dist/extensions/pi-subagents/src/runs/shared/readonly-model-continuation.ts +69 -0
  219. package/dist/extensions/pi-subagents/src/runs/shared/readonly-session-evidence.ts +307 -0
  220. package/dist/extensions/pi-subagents/src/runs/shared/run-fanout-budget.ts +8 -21
  221. package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +3 -30
  222. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +17 -4
  223. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +2 -0
  224. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +99 -386
  225. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +18 -62
  226. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +0 -14
  227. package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +31 -9
  228. package/dist/extensions/pi-subagents/src/runs/shared/worktree-setup-command.ts +190 -0
  229. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +506 -226
  230. package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +1 -1
  231. package/dist/extensions/pi-subagents/src/shared/jsonl-writer.ts +11 -0
  232. package/dist/extensions/pi-subagents/src/shared/model-response-aliases.ts +13 -0
  233. package/dist/extensions/pi-subagents/src/shared/thinking-ceiling.ts +0 -6
  234. package/dist/extensions/pi-subagents/src/shared/types.ts +145 -89
  235. package/dist/extensions/pi-subagents/src/shared/utils.ts +13 -6
  236. package/dist/extensions/pi-subagents/src/shared/watch-strategy.ts +2 -0
  237. package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +18 -13
  238. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +0 -6
  239. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +1 -1
  240. package/dist/extensions/pi-subagents/src/tui/fleet.ts +11 -6
  241. package/dist/extensions/pi-subagents/src/tui/render.ts +277 -46
  242. package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +0 -1
  243. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +12 -12
  244. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +3 -3
  245. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +116 -15
  246. package/dist/extensions/pi-subagents/src/workflows/workflow-checklist.ts +15 -18
  247. package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +57 -8
  248. package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +19 -19
  249. package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +3 -3
  250. package/dist/extensions/pi-subagents/src/workflows/workflow-resources.ts +97 -22
  251. package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +3 -0
  252. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +336 -21
  253. package/dist/extensions/pi-subagents/test/integration/async-execution.part-1.test.ts +1181 -0
  254. package/dist/extensions/pi-subagents/test/integration/async-execution.part-2.test.ts +2240 -0
  255. package/dist/extensions/pi-subagents/test/integration/async-execution.part-3.test.ts +2268 -0
  256. package/dist/extensions/pi-subagents/test/integration/async-execution.part-4.test.ts +1512 -0
  257. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +231 -16
  258. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +4 -18
  259. package/dist/extensions/pi-subagents/test/integration/foreign-workflow-steering.test.ts +95 -0
  260. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +9 -15
  261. package/dist/extensions/pi-subagents/test/integration/in-process-child.test.ts +374 -0
  262. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +20 -10
  263. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +18 -6
  264. package/dist/extensions/pi-subagents/test/integration/recovered-assistant-error.test.ts +151 -0
  265. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +42 -1
  266. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +150 -25
  267. package/dist/extensions/pi-subagents/test/integration/result-publication.test.ts +354 -0
  268. package/dist/extensions/pi-subagents/test/integration/shared-cwd-terminal-evidence.test.ts +117 -0
  269. package/dist/extensions/pi-subagents/test/integration/single-execution.part-1.test.ts +3678 -0
  270. package/dist/extensions/pi-subagents/test/integration/{single-execution.test.ts → single-execution.part-2.test.ts} +500 -4207
  271. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +1 -2
  272. package/dist/extensions/pi-subagents/test/integration/workflow-result-publication.test.ts +127 -0
  273. package/dist/extensions/pi-subagents/test/integration/workflow-steer-inbox.test.ts +365 -0
  274. package/dist/extensions/pi-subagents/test/smoke/pi085-child.ts +31 -0
  275. package/dist/extensions/pi-subagents/test/smoke/pi085-clean-install.mjs +74 -0
  276. package/dist/extensions/pi-subagents/test/smoke/pi085-extension.ts +16 -0
  277. package/dist/extensions/pi-subagents/test/support/async-execution-fixture.ts +699 -0
  278. package/dist/extensions/pi-subagents/test/support/fake-child-session.ts +418 -0
  279. package/dist/extensions/pi-subagents/test/support/foreign-workflow-steer-host.mjs +13 -0
  280. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +30 -76
  281. package/dist/extensions/pi-subagents/test/support/notify-diagnostics-fixture.ts +84 -0
  282. package/dist/extensions/pi-subagents/test/support/result-publication-capacity-preload.mjs +70 -0
  283. package/dist/extensions/pi-subagents/test/support/runner-child-session-factory.ts +17 -0
  284. package/dist/extensions/pi-subagents/test/support/single-execution-fixture.ts +390 -0
  285. package/dist/extensions/pi-subagents/test/unit/acceptance-compaction.test.ts +120 -0
  286. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +24 -3
  287. package/dist/extensions/pi-subagents/test/unit/advertised-agent-prompt.test.ts +87 -0
  288. package/dist/extensions/pi-subagents/test/unit/advertised-agent-refresh.test.ts +163 -0
  289. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +70 -31
  290. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +78 -3
  291. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +2 -8
  292. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +1 -1
  293. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +73 -66
  294. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +51 -1
  295. package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +49 -1
  296. package/dist/extensions/pi-subagents/test/unit/async-spawn-preload.test.ts +103 -0
  297. package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +3 -3
  298. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +9 -8
  299. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +10 -7
  300. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +48 -6
  301. package/dist/extensions/pi-subagents/test/unit/child-runtime-config.test.ts +90 -0
  302. package/dist/extensions/pi-subagents/test/unit/{pi-args-permission-system.test.ts → child-tool-plan-permission-system.test.ts} +48 -86
  303. package/dist/extensions/pi-subagents/test/unit/child-tool-plan.test.ts +33 -0
  304. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +18 -18
  305. package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +9 -9
  306. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +8 -7
  307. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +225 -65
  308. package/dist/extensions/pi-subagents/test/unit/extension-bindings.test.ts +17 -22
  309. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +11 -1
  310. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +47 -3
  311. package/dist/extensions/pi-subagents/test/unit/foreign-workflow-steering.test.ts +74 -0
  312. package/dist/extensions/pi-subagents/test/unit/fork-cache-key.test.ts +23 -29
  313. package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +96 -4
  314. package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +4 -4
  315. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +116 -55
  316. package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +58 -1
  317. package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +104 -3
  318. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +10 -1
  319. package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +31 -1
  320. package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +102 -51
  321. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +196 -6
  322. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +181 -38
  323. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +62 -70
  324. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +58 -53
  325. package/dist/extensions/pi-subagents/test/unit/notify-diagnostics.test.ts +42 -0
  326. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +84 -0
  327. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +13 -5
  328. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +21 -5
  329. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +5 -4
  330. package/dist/extensions/pi-subagents/test/unit/permissions.test.ts +2 -6
  331. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +28 -2
  332. package/dist/extensions/pi-subagents/test/unit/pi-web-session-liveness.test.ts +209 -0
  333. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +38 -1
  334. package/dist/extensions/pi-subagents/test/unit/prompt-audit-optional-peers.test.ts +43 -0
  335. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +24 -2
  336. package/dist/extensions/pi-subagents/test/unit/readonly-drain-observation.test.ts +174 -0
  337. package/dist/extensions/pi-subagents/test/unit/readonly-model-continuation.test.ts +94 -0
  338. package/dist/extensions/pi-subagents/test/unit/readonly-session-evidence.test.ts +1329 -0
  339. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +29 -80
  340. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +11 -8
  341. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +2 -2
  342. package/dist/extensions/pi-subagents/test/unit/retained-nested-route-tracker.test.ts +175 -0
  343. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +38 -12
  344. package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +2 -5
  345. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +89 -1
  346. package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +2 -16
  347. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +27 -3
  348. package/dist/extensions/pi-subagents/test/unit/scheduled-supervisor-demand.test.ts +215 -0
  349. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +15 -11
  350. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +237 -1
  351. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -5
  352. package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +2 -2
  353. package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +14 -1
  354. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +130 -739
  355. package/dist/extensions/pi-subagents/test/unit/supervisor-ask-registration.test.ts +682 -0
  356. package/dist/extensions/pi-subagents/test/unit/supervisor-ui.test.ts +137 -0
  357. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +1 -11
  358. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +23 -3
  359. package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +8 -1
  360. package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +19 -1
  361. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +72 -4
  362. package/dist/extensions/pi-subagents/test/unit/workflow-checklist.test.ts +17 -3
  363. package/dist/extensions/pi-subagents/test/unit/workflow-child-summary.test.ts +34 -0
  364. package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +12 -2
  365. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +46 -6
  366. package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +3 -3
  367. package/dist/extensions/pi-subagents/test/unit/workflow-resources.test.ts +133 -1
  368. package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +53 -2
  369. package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +222 -14
  370. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +526 -85
  371. package/dist/extensions/pi-web-agent/src/backends/config.ts +1 -0
  372. package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +5 -3
  373. package/dist/extensions/pi-web-agent/src/search/tokenin.ts +7 -3
  374. package/dist/extensions/pi-web-agent/src/types.ts +1 -1
  375. package/dist/extensions/pi-zentui/README.md +17 -0
  376. package/dist/extensions/pi-zentui/assets/screenshots/footer-status-hyperlink.png +0 -0
  377. package/dist/extensions/pi-zentui/docs/configuration.md +71 -2
  378. package/dist/extensions/pi-zentui/extensions/zentui/config.ts +11 -0
  379. package/dist/extensions/pi-zentui/extensions/zentui/editor-transfer.ts +14 -0
  380. package/dist/extensions/pi-zentui/extensions/zentui/extension-status.ts +29 -13
  381. package/dist/extensions/pi-zentui/extensions/zentui/footer-layout.ts +5 -4
  382. package/dist/extensions/pi-zentui/extensions/zentui/footer-text.ts +11 -0
  383. package/dist/extensions/pi-zentui/extensions/zentui/footer.ts +11 -10
  384. package/dist/extensions/pi-zentui/extensions/zentui/index.ts +77 -3
  385. package/dist/extensions/pi-zentui/extensions/zentui/presets.ts +77 -0
  386. package/dist/extensions/pi-zentui/extensions/zentui/settings-command.ts +103 -2
  387. package/dist/extensions/pi-zentui/extensions/zentui/working-line-extension-segments.ts +115 -0
  388. package/dist/extensions/pi-zentui/extensions/zentui/working-line.ts +87 -5
  389. package/dist/extensions/pi-zentui/package-lock.json +277 -517
  390. package/dist/extensions/pi-zentui/package.json +7 -4
  391. package/dist/extensions/pi-zentui/test/config-presets.test.ts +238 -0
  392. package/dist/extensions/pi-zentui/test/editor-transfer.test.ts +24 -1
  393. package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +570 -2
  394. package/dist/extensions/pi-zentui/test/extension-status.test.ts +90 -0
  395. package/dist/extensions/pi-zentui/test/footer-hyperlink.test.ts +243 -0
  396. package/dist/extensions/pi-zentui/test/package-contents.mjs +1 -0
  397. package/dist/extensions/pi-zentui/test/presets.test.ts +121 -0
  398. package/dist/extensions/pi-zentui/test/settings-command.test.ts +205 -1
  399. package/dist/extensions/pi-zentui/test/working-line-extension-segments.test.ts +139 -0
  400. package/dist/extensions/pi-zentui/test/working-line-lifecycle.integration.test.ts +237 -3
  401. package/dist/extensions/pi-zentui/test/working-line.test.ts +94 -2
  402. package/dist/index.d.ts +1 -1
  403. package/dist/main.js +4 -1
  404. package/dist/modes/interactive/chat-viewport.d.ts +19 -0
  405. package/dist/modes/interactive/chat-viewport.js +27 -0
  406. package/dist/modes/interactive/components/assistant-message.d.ts +6 -2
  407. package/dist/modes/interactive/components/assistant-message.js +30 -13
  408. package/dist/modes/interactive/components/custom-editor.d.ts +10 -1
  409. package/dist/modes/interactive/components/custom-editor.js +39 -1
  410. package/dist/modes/interactive/components/first-time-setup.js +1 -1
  411. package/dist/modes/interactive/components/index.d.ts +1 -1
  412. package/dist/modes/interactive/components/markdown-transform.d.ts +2 -0
  413. package/dist/modes/interactive/components/markdown-transform.js +18 -0
  414. package/dist/modes/interactive/components/model-selector.js +19 -17
  415. package/dist/modes/interactive/components/scoped-models-selector.js +21 -23
  416. package/dist/modes/interactive/components/settings-selector.d.ts +7 -1
  417. package/dist/modes/interactive/components/settings-selector.js +128 -20
  418. package/dist/modes/interactive/components/settings-submenu.d.ts +71 -0
  419. package/dist/modes/interactive/components/settings-submenu.js +164 -0
  420. package/dist/modes/interactive/components/status-indicator.d.ts +3 -1
  421. package/dist/modes/interactive/components/status-indicator.js +10 -3
  422. package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
  423. package/dist/modes/interactive/components/thinking-selector.js +75 -18
  424. package/dist/modes/interactive/components/tool-execution.d.ts +21 -4
  425. package/dist/modes/interactive/components/tool-execution.js +35 -33
  426. package/dist/modes/interactive/components/trust-selector.js +2 -2
  427. package/dist/modes/interactive/interactive-mode.d.ts +13 -15
  428. package/dist/modes/interactive/interactive-mode.js +144 -80
  429. package/dist/modes/interactive/session-share.d.ts +15 -0
  430. package/dist/modes/interactive/session-share.js +183 -0
  431. package/dist/modes/interactive/theme/dark.json +2 -1
  432. package/dist/modes/interactive/theme/light.json +2 -1
  433. package/dist/modes/interactive/theme/theme-controller.d.ts +1 -0
  434. package/dist/modes/interactive/theme/theme-controller.js +5 -0
  435. package/dist/modes/interactive/theme/theme-json.d.ts +83 -0
  436. package/dist/modes/interactive/theme/theme-json.js +129 -0
  437. package/dist/modes/interactive/theme/theme-schema.json +9 -1
  438. package/dist/modes/interactive/theme/theme.d.ts +14 -5
  439. package/dist/modes/interactive/theme/theme.js +18 -119
  440. package/dist/modes/interactive/tui-renderer.d.ts +20 -0
  441. package/dist/modes/interactive/tui-renderer.js +65 -0
  442. package/dist/utils/exif-orientation.js +2 -3
  443. package/dist/utils/management-http.d.ts +24 -0
  444. package/dist/utils/management-http.js +53 -0
  445. package/dist/utils/text.d.ts +7 -0
  446. package/dist/utils/text.js +8 -0
  447. package/dist/utils/tools-manager.d.ts +1 -0
  448. package/dist/utils/tools-manager.js +43 -21
  449. package/docs/docs.json +0 -4
  450. package/package.json +4 -4
  451. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +0 -415
  452. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +0 -1059
  453. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +0 -116
  454. package/dist/extensions/pi-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
  455. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +0 -224
  456. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +0 -6986
  457. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +0 -447
  458. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +0 -185
  459. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +0 -311
  460. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +0 -84
  461. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +0 -202
  462. package/dist/extensions/pi-subagents/test/unit/close-grace-timer.test.ts +0 -101
  463. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +0 -2347
  464. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +0 -104
  465. package/dist/extensions/pi-subagents/test/unit/windows-hide-spawn.test.ts +0 -49
  466. package/dist/skills/imagegen-frontend-mobile/SKILL.md +0 -1465
  467. package/dist/skills/imagegen-frontend-web/SKILL.md +0 -987
  468. package/dist/skills/implanger/SKILL.md +0 -70
  469. package/dist/skills/output/SKILL.md +0 -49
  470. package/dist/skills/planger/SKILL.md +0 -167
  471. package/dist/skills/workflow/SKILL.md +0 -95
  472. package/docs/workflows.md +0 -18
  473. /package/dist/bun/{register-bedrock.d.ts → runtime-setup.d.ts} +0 -0
@@ -3,41 +3,28 @@ import * as fs from "node:fs";
3
3
  import * as path from "node:path";
4
4
  import type { BeforeProviderRequestEvent, ExtensionAPI, ExtensionContext } from "@selesai/code";
5
5
  import { registerNativeSupervisorClient } from "../../intercom/native-supervisor-channel.ts";
6
- import { shouldUseNativeFsWatch } from "../../shared/watch-strategy.ts";
7
- import { decodePermissionRules, permissionDecision, PERMISSION_AUDIT_PATH_ENV, PERMISSION_POLICY_ENV } from "./permissions.ts";
8
- import { consumeSteerRequestsFromDir, MAX_STEER_QUEUE_SIZE, steerAckPathFromDir, writeSteerAckAt, writeSteerCapabilityAt, writeSteerRequestToDir, type SteerDeliveryStatus, type SteerRequest } from "../background/control-channel.ts";
9
- import { SUBAGENT_CHILD_AGENT_ENV, SUBAGENT_CHILD_INDEX_ENV, SUBAGENT_FANOUT_CHILD_ENV, SUBAGENT_FORK_CACHE_KEY_ENV, SUBAGENT_INHERIT_GLOBAL_CONTEXT_ENV, SUBAGENT_STEER_ACK_DIR_ENV, SUBAGENT_STEER_CAPABILITY_ENV, SUBAGENT_STEER_INBOX_ENV } from "./pi-args.ts";
10
- import { RUNTIME_EXTENSION_ACK_EVENT, RUNTIME_EXTENSION_ACK_PATH_ENV, isRuntimeAcknowledgedExtensionId, writeRuntimeAcknowledgedExtensions } from "./runtime-acknowledged-extensions.ts";
11
- import { createStructuredOutputToolParameters, MISSING_STRUCTURED_ACCEPTANCE_REPORT_ERROR, STRUCTURED_OUTPUT_ACCEPTANCE_CAPTURE_ENV, STRUCTURED_OUTPUT_ACCEPTANCE_REQUIRED_ENV, STRUCTURED_OUTPUT_CAPTURE_ENV, STRUCTURED_OUTPUT_SCHEMA_ENV, validateStructuredOutputValue } from "./structured-output.ts";
6
+ import { permissionDecision } from "./permissions.ts";
7
+ import type { SteerRequest } from "../background/control-channel.ts";
8
+ import { RUNTIME_EXTENSION_ACK_EVENT, isRuntimeAcknowledgedExtensionId } from "./runtime-acknowledged-extensions.ts";
9
+ import { createStructuredOutputToolParameters, MISSING_STRUCTURED_ACCEPTANCE_REPORT_ERROR, validateStructuredOutputValue } from "./structured-output.ts";
12
10
  import { validateAcceptanceReport } from "./acceptance.ts";
13
- import {
14
- CHILD_TOOL_DIAGNOSTIC_PATH_ENV,
15
- formatChildToolDiagnostic,
16
- MCP_DIRECT_CHILD_TOOLS_ENV,
17
- REQUIRED_CHILD_TOOLS_ENV,
18
- writeChildToolDiagnostic,
19
- type ChildToolDiagnostic,
20
- } from "./tool-availability.ts";
21
- import { TOOL_BUDGET_ENV, TOOL_BUDGET_ZERO_AUTH_ENV, decodeToolBudgetEnv, shouldBlockToolForBudget, toolBudgetBlockedMessage, toolBudgetSoftNudge } from "./tool-budget.ts";
22
- import type { JsonSchemaObject, ResolvedToolBudget, SubagentState } from "../../shared/types.ts";
11
+ import { formatChildToolDiagnostic } from "./tool-availability.ts";
12
+ import { shouldBlockToolForBudget, toolBudgetBlockedMessage, toolBudgetSoftNudge } from "./tool-budget.ts";
13
+ import type { ResolvedToolBudget, SubagentState } from "../../shared/types.ts";
23
14
  import { resolveCurrentSessionId } from "../../shared/session-identity.ts";
24
- import { getAgentDir, resolveWatchPath } from "../../shared/utils.ts";
15
+ import { getAgentDir } from "../../shared/utils.ts";
25
16
  import { registerChildWatchdog } from "../../watchdog/register-child.ts";
26
- import { CHILD_WATCHDOG_CONFIG_ENV, decodeChildWatchdogConfig } from "../../watchdog/child-status.ts";
17
+ import type { ChildWatchdogConfig } from "../../watchdog/child-status.ts";
27
18
  import { requestWatchdogPermission, type WatchdogPermissionRequest, type WatchdogPermissionResult } from "../../watchdog/permission-arbiter.ts";
28
19
  import { SUBAGENT_WATCHDOG_WARNING_TYPE } from "../../watchdog/types.ts";
29
- import { resolveWaitToolConfig } from "../background/wait-config.ts";
30
20
  import { registerWaitTool } from "../background/wait-tool.ts";
31
21
  import { drainOutstandingWork } from "../background/auto-drain.ts";
32
-
33
- const SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV = "SELESAI_SUBAGENT_INHERIT_PROJECT_CONTEXT";
34
- const SUBAGENT_INHERIT_SKILLS_ENV = "SELESAI_SUBAGENT_INHERIT_SKILLS";
35
- export const SUBAGENT_INTERCOM_SESSION_NAME_ENV = "SELESAI_SUBAGENT_INTERCOM_SESSION_NAME";
36
- /** Human-readable child display name (agent + task excerpt) set by the parent
37
- * at launch; applied via pi.setSessionName when no intercom target exists. */
38
- export const SUBAGENT_SESSION_NAME_ENV = "SELESAI_SUBAGENT_SESSION_NAME";
39
- const STEERING_LEGACY_SETTLE_FALLBACK_MS = 1000;
40
- const STEERING_SAFETY_POLL_INTERVAL_MS = 5000;
22
+ import {
23
+ childSupervisorMetadata,
24
+ evaluateChildToolDiagnostic,
25
+ type ChildPermissions,
26
+ type ChildRuntimeConfig,
27
+ } from "./child-runtime-config.ts";
41
28
 
42
29
  const STRUCTURED_OUTPUT_INSTRUCTIONS = [
43
30
  "This subagent step has a strict structured output contract.",
@@ -77,45 +64,8 @@ const PROJECT_CONTEXT_LEGACY_HEADER = "\n\n# Project Context\n\nProject-specific
77
64
  const SKILLS_HEADER = "\n\nThe following skills provide specialized instructions for specific tasks.";
78
65
  const DATE_HEADER = "\nCurrent date:";
79
66
 
80
- function readBooleanEnv(name: string): boolean | undefined {
81
- const value = process.env[name];
82
- if (value === undefined) return undefined;
83
- return value !== "0";
84
- }
85
-
86
- function readRequiredChildTools(): string[] | undefined {
87
- const encoded = process.env[REQUIRED_CHILD_TOOLS_ENV]?.trim();
88
- if (!encoded) return undefined;
89
- const required = JSON.parse(encoded) as unknown;
90
- if (!Array.isArray(required) || required.some((name) => typeof name !== "string" || !name)) {
91
- throw new Error(`Invalid ${REQUIRED_CHILD_TOOLS_ENV} payload.`);
92
- }
93
- return required;
94
- }
95
-
96
- function readMcpDirectChildTools(): string[] | undefined {
97
- const encoded = process.env[MCP_DIRECT_CHILD_TOOLS_ENV]?.trim();
98
- if (!encoded) return undefined;
99
- try {
100
- const tools = JSON.parse(encoded) as unknown;
101
- if (!Array.isArray(tools) || tools.some((name) => typeof name !== "string" || !name)) return undefined;
102
- return tools;
103
- } catch {
104
- return undefined;
105
- }
106
- }
107
-
108
- function refreshChildToolDiagnostic(pi: ExtensionAPI): ChildToolDiagnostic | undefined {
109
- const filePath = process.env[CHILD_TOOL_DIAGNOSTIC_PATH_ENV]?.trim();
110
- const required = readRequiredChildTools();
111
- if (!filePath || !required) return undefined;
112
- const available = pi.getAllTools().map((tool) => tool.name);
113
- return writeChildToolDiagnostic(filePath, required, available, process.env[SUBAGENT_CHILD_AGENT_ENV]?.trim(), readMcpDirectChildTools());
114
- }
115
-
116
- function registerRuntimeExtensionAcknowledgements(pi: ExtensionAPI): void {
117
- const outputPath = process.env[RUNTIME_EXTENSION_ACK_PATH_ENV]?.trim();
118
- if (!outputPath) return;
67
+ function registerRuntimeExtensionAcknowledgements(pi: ExtensionAPI, sink: ((ids: string[]) => void) | undefined): void {
68
+ if (!sink) return;
119
69
  const ids: string[] = [];
120
70
  let finalized = false;
121
71
  const acknowledge = (payload: unknown): undefined => {
@@ -127,7 +77,7 @@ function registerRuntimeExtensionAcknowledgements(pi: ExtensionAPI): void {
127
77
  const finalize = (): undefined => {
128
78
  if (finalized) return undefined;
129
79
  finalized = true;
130
- writeRuntimeAcknowledgedExtensions(outputPath, ids);
80
+ sink(ids);
131
81
  return undefined;
132
82
  };
133
83
  try {
@@ -252,7 +202,7 @@ function stripChildBoundaryInstructions(prompt: string): string {
252
202
 
253
203
  export function rewriteSubagentPrompt(
254
204
  prompt: string,
255
- options: { inheritProjectContext: boolean; inheritGlobalContext: boolean; inheritSkills: boolean; fanoutChild?: boolean },
205
+ options: { inheritProjectContext: boolean; inheritGlobalContext: boolean; inheritSkills: boolean; fanoutChild?: boolean; structuredOutput?: boolean },
256
206
  ): string {
257
207
  let rewritten = prompt;
258
208
  if (!options.inheritProjectContext) {
@@ -267,7 +217,7 @@ export function rewriteSubagentPrompt(
267
217
  rewritten = stripSubagentOrchestrationSkill(rewritten);
268
218
  rewritten = stripChildBoundaryInstructions(rewritten);
269
219
  const boundary = options.fanoutChild ? CHILD_FANOUT_BOUNDARY_INSTRUCTIONS : CHILD_SUBAGENT_BOUNDARY_INSTRUCTIONS;
270
- const structured = process.env[STRUCTURED_OUTPUT_CAPTURE_ENV] ? `\n\n${STRUCTURED_OUTPUT_INSTRUCTIONS}` : "";
220
+ const structured = options.structuredOutput ? `\n\n${STRUCTURED_OUTPUT_INSTRUCTIONS}` : "";
271
221
  return `${boundary}${structured}\n\n${rewritten}`;
272
222
  }
273
223
 
@@ -304,14 +254,14 @@ const PROMPT_CACHE_KEY_APIS = new Set([
304
254
  "openai-responses",
305
255
  ]);
306
256
 
307
- export function rewriteForkCacheProviderRequest(event: BeforeProviderRequestEvent, ctx?: Pick<ExtensionContext, "model">): unknown {
308
- const forkCacheKey = process.env[SUBAGENT_FORK_CACHE_KEY_ENV]?.trim();
309
- if (!forkCacheKey || !PROMPT_CACHE_KEY_APIS.has(ctx?.model?.api ?? "")) return undefined;
257
+ export function rewriteForkCacheProviderRequest(event: BeforeProviderRequestEvent, ctx: Pick<ExtensionContext, "model"> | undefined, forkCacheKey: string | undefined): unknown {
258
+ const key = forkCacheKey?.trim();
259
+ if (!key || !PROMPT_CACHE_KEY_APIS.has(ctx?.model?.api ?? "")) return undefined;
310
260
  if (!event || typeof event !== "object") return undefined;
311
261
  const payload = event.payload;
312
262
  if (!payload || typeof payload !== "object" || Array.isArray(payload)) return undefined;
313
263
  if (typeof (payload as { prompt_cache_key?: unknown }).prompt_cache_key !== "string") return undefined;
314
- return { ...payload, prompt_cache_key: forkCacheKey };
264
+ return { ...payload, prompt_cache_key: key };
315
265
  }
316
266
 
317
267
  function portableToolId(id: string): string {
@@ -349,8 +299,8 @@ function stripAssistantSubagentToolCallBlocks(message: unknown): unknown | undef
349
299
  return { ...m, content: filteredContent };
350
300
  }
351
301
 
352
- export function stripParentOnlySubagentMessages(messages: unknown[], options: { sanitizeToolIds?: boolean } = {}): unknown[] {
353
- const preserveCurrentFanoutToolHistory = process.env[SUBAGENT_FANOUT_CHILD_ENV] === "1";
302
+ export function stripParentOnlySubagentMessages(messages: unknown[], options: { sanitizeToolIds?: boolean; preserveFanoutToolHistory?: boolean } = {}): unknown[] {
303
+ const preserveCurrentFanoutToolHistory = options.preserveFanoutToolHistory === true;
354
304
  const sanitizeToolIds = options.sanitizeToolIds ?? true;
355
305
  let changed = false;
356
306
  const filtered: unknown[] = [];
@@ -383,23 +333,20 @@ export function formatSteerMessage(request: SteerRequest): string {
383
333
 
384
334
  export function registerPermissionGate(
385
335
  pi: ExtensionAPI,
336
+ permissions: ChildPermissions | undefined,
337
+ childWatchdog: ChildWatchdogConfig | undefined,
386
338
  requestPermission: (request: WatchdogPermissionRequest) => Promise<WatchdogPermissionResult> = requestWatchdogPermission,
387
339
  ): void {
388
- const rules = decodePermissionRules(process.env[PERMISSION_POLICY_ENV]);
389
- if (!rules) return;
340
+ const rules = permissions?.rules;
341
+ if (!rules || Object.keys(rules).length === 0) return;
342
+ const rawWatchdogConfig = childWatchdog ? JSON.stringify(childWatchdog) : undefined;
343
+ const timeoutMs = childWatchdog?.agentEndTimeoutMs ?? 30_000;
390
344
  const onRuntimeEvent = pi.on as unknown as (event: string, handler: (event: { toolName?: string; input?: unknown }, ctx: ExtensionContext) => unknown) => void;
391
345
  onRuntimeEvent("tool_call", async (event, ctx) => {
392
346
  const toolName = typeof event.toolName === "string" ? event.toolName : "tool";
393
347
  const decision = permissionDecision(rules, toolName);
394
348
  if (decision === "allow") return undefined;
395
349
  if (decision === "deny") return { block: true, reason: `Blocked by pi-subagents permission rule: '${toolName}' is denied.` };
396
- const rawWatchdogConfig = process.env[CHILD_WATCHDOG_CONFIG_ENV];
397
- let timeoutMs = 30_000;
398
- try {
399
- timeoutMs = decodeChildWatchdogConfig(rawWatchdogConfig)?.agentEndTimeoutMs ?? timeoutMs;
400
- } catch {
401
- // The arbiter reports invalid configuration with the concrete decode error.
402
- }
403
350
  if (ctx.signal?.aborted) return { block: true, reason: "Blocked by pi-subagents permission rule: Watchdog permission decision was cancelled." };
404
351
  let timeout: ReturnType<typeof setTimeout> | undefined;
405
352
  let abort: (() => void) | undefined;
@@ -411,7 +358,7 @@ export function registerPermissionGate(
411
358
  toolName,
412
359
  args: event.input ?? {},
413
360
  rawWatchdogConfig,
414
- auditPath: process.env[PERMISSION_AUDIT_PATH_ENV],
361
+ auditPath: permissions.auditPath,
415
362
  ...(ctx.signal ? { signal: ctx.signal } : {}),
416
363
  }),
417
364
  new Promise<WatchdogPermissionResult>((resolve) => {
@@ -455,245 +402,56 @@ function registerToolBudget(pi: ExtensionAPI, budget: ResolvedToolBudget | undef
455
402
  });
456
403
  }
457
404
 
458
- export function registerSteeringInbox(
459
- pi: ExtensionAPI,
460
- deps: {
461
- watch?: typeof fs.watch;
462
- nativeRealpath?: (filePath: string) => string;
463
- legacySettleFallbackMs?: number;
464
- safetyPollIntervalMs?: number;
465
- platform?: NodeJS.Platform;
466
- timers?: Pick<typeof globalThis, "setInterval" | "clearInterval">;
467
- } = {},
468
- ): void {
469
- const steerInbox = process.env[SUBAGENT_STEER_INBOX_ENV]?.trim();
470
- if (!steerInbox) return;
471
- const capabilityPath = process.env[SUBAGENT_STEER_CAPABILITY_ENV]?.trim();
472
- const ackDir = process.env[SUBAGENT_STEER_ACK_DIR_ENV]?.trim();
473
- const sendUserMessage = (pi as { sendUserMessage?: (content: string, options?: { deliverAs: "steer" | "followUp" }) => unknown }).sendUserMessage;
474
- const childIndex = Number(process.env[SUBAGENT_CHILD_INDEX_ENV]);
475
- const pending = new Map<string, Array<{ request: SteerRequest; deliveryStatus: SteerDeliveryStatus }>>();
476
- const queued: Array<{ request: SteerRequest; ready: boolean }> = [];
477
- let disposed = false;
478
- let agentRunning = false;
479
- let inTurn = false;
480
- let awaitingSettlement = false;
481
- let flushing = false;
482
- let started = false;
483
- let canSteer = typeof sendUserMessage === "function";
484
- let watcher: fs.FSWatcher | undefined;
485
- let interval: NodeJS.Timeout | undefined;
486
- let safetyInterval: NodeJS.Timeout | undefined;
487
- let settleFallback: NodeJS.Timeout | undefined;
488
- const legacySettleFallbackMs = deps.legacySettleFallbackMs ?? STEERING_LEGACY_SETTLE_FALLBACK_MS;
489
- const acknowledge = (request: SteerRequest, state: "delivered" | "queued" | "failed", message: string, deliveryStatus?: SteerDeliveryStatus): void => {
490
- if (!ackDir || !Number.isInteger(childIndex) || childIndex < 0) return;
491
- writeSteerAckAt(steerAckPathFromDir(ackDir, request.id), {
492
- requestId: request.id,
493
- index: childIndex,
494
- ts: Date.now(),
495
- state,
496
- ...(deliveryStatus ? { deliveryStatus } : {}),
497
- message,
498
- });
499
- };
500
- const publishCapability = (): void => {
501
- if (!capabilityPath || !Number.isInteger(childIndex) || childIndex < 0) return;
502
- writeSteerCapabilityAt(capabilityPath, { index: childIndex, pid: process.pid, readyAt: Date.now(), supported: canSteer });
503
- };
504
- const flush = (): void => {
505
- if (disposed || flushing) return;
506
- flushing = true;
507
- try {
508
- const requests = consumeSteerRequestsFromDir(steerInbox);
509
- for (let index = 0; index < requests.length; index++) {
510
- const request = requests[index]!;
511
- if (!canSteer || typeof sendUserMessage !== "function") {
512
- acknowledge(request, "failed", "Child Pi session does not support sendUserMessage steering.");
513
- continue;
514
- }
515
- const requestedMode = request.mode ?? "steer";
516
- const autoCanUseIdle = requestedMode === "auto" && !agentRunning && !awaitingSettlement;
517
- const delivery = requestedMode === "follow_up" || (requestedMode === "auto" && (inTurn || awaitingSettlement)) ? "followUp" as const : "steer" as const;
518
- const pendingFollowUps = [...pending.values()].reduce((count, entries) => count + entries.filter((entry) => entry.deliveryStatus === "queued").length, 0);
519
- if (delivery === "followUp" && queued.length + pendingFollowUps >= MAX_STEER_QUEUE_SIZE) {
520
- acknowledge(request, "failed", `Follow-up queue is full (${MAX_STEER_QUEUE_SIZE} messages).`);
521
- continue;
522
- }
523
- const formatted = formatSteerMessage(request);
524
- const entries = pending.get(formatted) ?? [];
525
- entries.push({ request, deliveryStatus: delivery === "followUp" ? "queued" : "delivered" });
526
- pending.set(formatted, entries);
527
- try {
528
- sendUserMessage(formatted, autoCanUseIdle ? undefined : { deliverAs: delivery });
529
- } catch (error) {
530
- entries.pop();
531
- if (entries.length === 0) pending.delete(formatted);
532
- acknowledge(request, "failed", error instanceof Error ? error.message : String(error));
533
- for (const retry of requests.slice(index + 1)) writeSteerRequestToDir(steerInbox, retry);
534
- break;
535
- }
405
+ function registerStructuredOutputTool(pi: ExtensionAPI, structured: NonNullable<ChildRuntimeConfig["structuredOutput"]>): void {
406
+ const required = structured.acceptanceReport === "required";
407
+ const parameters = createStructuredOutputToolParameters(structured.schema, { acceptanceReport: structured.acceptanceReport });
408
+ const registerTool = pi.registerTool as unknown as (tool: {
409
+ name: string;
410
+ label: string;
411
+ description: string;
412
+ parameters: unknown;
413
+ execute: (_id: string, params: { value: unknown; acceptanceReport?: unknown }) => Promise<unknown>;
414
+ }) => void;
415
+ registerTool({
416
+ name: "structured_output",
417
+ label: "Structured Output",
418
+ description: "Submit the required final structured output for this subagent step. This terminates the step.",
419
+ parameters,
420
+ async execute(_id: string, params: { value: unknown; acceptanceReport?: unknown }) {
421
+ const validation = await validateStructuredOutputValue(structured.schema, params.value);
422
+ if (validation.status === "invalid") {
423
+ throw new Error(`Structured output validation failed: ${validation.message}`);
536
424
  }
537
- } finally {
538
- flushing = false;
539
- }
540
- };
541
- const onInput = (event: unknown): undefined => {
542
- if (disposed || !event || typeof event !== "object") return undefined;
543
- const input = event as { source?: unknown; streamingBehavior?: unknown; text?: unknown; content?: unknown };
544
- if (input.source !== "extension") return undefined;
545
- const text = typeof input.text === "string" ? input.text : typeof input.content === "string" ? input.content : undefined;
546
- if (!text) return undefined;
547
- const entries = pending.get(text);
548
- const entry = entries?.shift();
549
- if (!entry) return undefined;
550
- if (entries?.length === 0) pending.delete(text);
551
- if (entry.deliveryStatus === "queued") {
552
- queued.push({ request: entry.request, ready: !inTurn });
553
- acknowledge(entry.request, "queued", "Pi queued the correlated follow-up input.", "queued");
554
- } else {
555
- acknowledge(entry.request, "delivered", "Pi accepted the correlated steering input.", "delivered");
556
- }
557
- return undefined;
558
- };
559
- const start = (): void => {
560
- if (started || disposed) return;
561
- try {
562
- fs.mkdirSync(steerInbox, { recursive: true });
563
- publishCapability();
564
- } catch {
565
- return;
566
- }
567
- started = true;
568
- const startPolling = (): void => {
569
- if (interval || disposed) return;
570
- interval = (deps.timers?.setInterval ?? setInterval)(flush, 250) as NodeJS.Timeout;
571
- interval.unref?.();
572
- };
573
- const startSafetyPolling = (): void => {
574
- if (safetyInterval || disposed) return;
575
- safetyInterval = (deps.timers?.setInterval ?? setInterval)(flush, deps.safetyPollIntervalMs ?? STEERING_SAFETY_POLL_INTERVAL_MS) as NodeJS.Timeout;
576
- safetyInterval.unref?.();
577
- };
578
- if (!shouldUseNativeFsWatch("child-steering-inbox", deps.platform)) {
579
- startPolling();
580
- } else {
581
- try {
582
- watcher = (deps.watch ?? fs.watch)(resolveWatchPath(steerInbox, deps.nativeRealpath), () => flush());
583
- watcher.on("error", startPolling);
584
- startSafetyPolling();
585
- } catch {
586
- watcher = undefined;
587
- startPolling();
425
+ if (required && params.acceptanceReport === undefined) {
426
+ throw new Error(MISSING_STRUCTURED_ACCEPTANCE_REPORT_ERROR);
588
427
  }
589
- }
590
- };
591
- const activate = (): undefined => {
592
- start();
593
- flush();
594
- return undefined;
595
- };
596
- const clearSettleFallback = (): void => {
597
- if (!settleFallback) return;
598
- clearTimeout(settleFallback);
599
- settleFallback = undefined;
600
- };
601
- const markSettled = (): undefined => {
602
- clearSettleFallback();
603
- agentRunning = false;
604
- inTurn = false;
605
- awaitingSettlement = false;
606
- return activate();
607
- };
608
- const armLegacySettleFallback = (): void => {
609
- clearSettleFallback();
610
- settleFallback = setTimeout(() => {
611
- settleFallback = undefined;
612
- if (disposed || !awaitingSettlement) return;
613
- agentRunning = false;
614
- inTurn = false;
615
- awaitingSettlement = false;
616
- activate();
617
- }, legacySettleFallbackMs);
618
- settleFallback.unref?.();
619
- };
620
-
621
- const onRuntimeEvent = pi.on as unknown as (event: string, handler: (event: unknown, ctx?: unknown) => unknown) => void;
622
- // Register input before the watcher so an accepted extension input cannot race request dispatch.
623
- onRuntimeEvent("input", onInput);
624
- onRuntimeEvent("session_start", () => start());
625
- onRuntimeEvent("agent_start", () => {
626
- clearSettleFallback();
627
- agentRunning = true;
628
- awaitingSettlement = false;
629
- return activate();
630
- });
631
- onRuntimeEvent("agent_end", (event) => {
632
- inTurn = false;
633
- if ((event as { willRetry?: unknown } | undefined)?.willRetry === true) {
634
- clearSettleFallback();
635
- agentRunning = true;
636
- awaitingSettlement = true;
637
- return activate();
638
- }
639
- agentRunning = true;
640
- awaitingSettlement = true;
641
- armLegacySettleFallback();
642
- return activate();
643
- });
644
- onRuntimeEvent("agent_settled", markSettled);
645
- onRuntimeEvent("session_compact", () => {
646
- const unresolved = [...pending.values()].flat();
647
- pending.clear();
648
- for (const entry of unresolved) {
649
- try {
650
- writeSteerRequestToDir(steerInbox, { ...entry.request, mode: "follow_up" });
651
- } catch (error) {
652
- acknowledge(entry.request, "failed", `Could not retry steering after compaction: ${error instanceof Error ? error.message : String(error)}`);
428
+ if (required && params.acceptanceReport !== undefined) {
429
+ const acceptanceValidation = validateAcceptanceReport(params.acceptanceReport, "acceptanceReport");
430
+ if (!acceptanceValidation.report) {
431
+ throw new Error(`Invalid structured output acceptance report: ${acceptanceValidation.errors.join("; ")}`);
432
+ }
653
433
  }
654
- }
655
- return activate();
656
- });
657
- onRuntimeEvent("turn_start", () => {
658
- clearSettleFallback();
659
- agentRunning = true;
660
- awaitingSettlement = false;
661
- inTurn = true;
662
- const next = queued.findIndex((entry) => entry.ready);
663
- if (next >= 0) {
664
- const [entry] = queued.splice(next, 1);
665
- if (entry) acknowledge(entry.request, "delivered", "Pi delivered the queued follow-up at a turn boundary.", "delivered");
666
- }
667
- return activate();
668
- });
669
- onRuntimeEvent("turn_end", () => {
670
- inTurn = false;
671
- for (const entry of queued) entry.ready = true;
672
- return activate();
673
- });
674
- for (const eventName of ["message_start", "message_update", "message_end", "tool_execution_start", "tool_execution_end"] as const) {
675
- onRuntimeEvent(eventName, activate);
676
- }
677
- onRuntimeEvent("session_shutdown", () => {
678
- for (const entry of queued) acknowledge(entry.request, "failed", "Run ended before queued follow-up delivery.", "queued");
679
- for (const entries of pending.values()) {
680
- for (const entry of entries) acknowledge(entry.request, "failed", "Run ended before Pi confirmed steering input delivery.");
681
- }
682
- disposed = true;
683
- clearSettleFallback();
684
- try { watcher?.close(); } catch {}
685
- if (interval) (deps.timers?.clearInterval ?? clearInterval)(interval);
686
- if (safetyInterval) (deps.timers?.clearInterval ?? clearInterval)(safetyInterval);
434
+ structured.capture(params.value, structured.acceptanceReport ? params.acceptanceReport : undefined);
435
+ return {
436
+ content: [{ type: "text", text: "Structured output captured." }],
437
+ details: {},
438
+ terminate: true,
439
+ };
440
+ },
687
441
  });
688
442
  }
689
443
 
690
- export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
691
- registerRuntimeExtensionAcknowledgements(pi);
692
- registerSteeringInbox(pi);
693
- registerPermissionGate(pi);
694
- registerToolBudget(pi, decodeToolBudgetEnv(process.env[TOOL_BUDGET_ENV], { allowZero: process.env[TOOL_BUDGET_ZERO_AUTH_ENV] === "1" }));
695
- registerChildWatchdog(pi);
696
- const waitToolConfig = resolveWaitToolConfig();
444
+ /** Register every child-side hook the prompt runtime owns for one child session. */
445
+ export default function registerSubagentPromptRuntime(pi: ExtensionAPI, config?: ChildRuntimeConfig, drainObservation?: import("./readonly-drain-observation.ts").ReadonlyDrainObservation): void {
446
+ // A path-based load has no ChildRuntimeConfig. This can happen if an
447
+ // ambient-extension discovery path finds the runtime module in addition to
448
+ // the configured inline factory. It must be inert rather than crashing the
449
+ // child before startup; the inline factory remains the real registration path.
450
+ if (!config) return;
451
+ registerRuntimeExtensionAcknowledgements(pi, config.runtimeAcknowledgements);
452
+ registerPermissionGate(pi, config.permissions, config.childWatchdog);
453
+ registerToolBudget(pi, config.toolBudget);
454
+ registerChildWatchdog(pi, config.childWatchdog, config.watchdogStatus);
697
455
  const waitState = {
698
456
  baseCwd: "",
699
457
  currentSessionId: null,
@@ -708,12 +466,13 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
708
466
  watcherRestartTimer: null,
709
467
  resultFileCoalescer: { schedule: () => false, clear: () => {} },
710
468
  } as unknown as SubagentState;
711
- if (typeof pi.registerTool === "function") registerWaitTool(pi, waitState, waitToolConfig.enabled, undefined, waitToolConfig.defaultTimeoutMs);
469
+ if (typeof pi.registerTool === "function") registerWaitTool(pi, waitState, config.waitTool.enabled, undefined, config.waitTool.defaultTimeoutMs);
470
+ const supervisorMetadata = childSupervisorMetadata(config);
712
471
  let nativeSupervisorClientRegistered = false;
713
472
  const registerNativeSupervisorClientOnce = (): void => {
714
473
  if (nativeSupervisorClientRegistered) return;
715
474
  nativeSupervisorClientRegistered = true;
716
- registerNativeSupervisorClient(pi);
475
+ registerNativeSupervisorClient(pi, supervisorMetadata);
717
476
  };
718
477
  const onRuntimeEvent = pi.on as unknown as (event: string, handler: (event: unknown, ctx?: ExtensionContext) => unknown) => void;
719
478
  onRuntimeEvent("session_start", (_event: unknown, ctx?: ExtensionContext) => {
@@ -722,72 +481,29 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
722
481
  registerNativeSupervisorClientOnce();
723
482
  });
724
483
  onRuntimeEvent("agent_start", () => {
725
- const diagnostic = refreshChildToolDiagnostic(pi);
484
+ if (!config.requiredTools) return;
485
+ const diagnostic = evaluateChildToolDiagnostic(config, pi.getAllTools().map((tool) => tool.name));
486
+ config.toolDiagnostic?.(diagnostic);
726
487
  if (diagnostic) throw new Error(formatChildToolDiagnostic(diagnostic));
727
488
  });
728
489
  onRuntimeEvent("agent_end", async (_event: unknown, ctx: unknown) => {
729
- if ((ctx as { hasUI?: boolean } | undefined)?.hasUI === true) return;
730
- await drainOutstandingWork({ state: waitState, events: pi.events });
490
+ if ((ctx as { hasUI?: boolean } | undefined)?.hasUI === true) { drainObservation?.deny(); return; }
491
+ if (drainObservation) {
492
+ try {
493
+ if ((ctx as ExtensionContext)?.sessionManager?.getSessionFile() !== waitState.currentSessionId) drainObservation.deny();
494
+ } catch { drainObservation.deny(); }
495
+ }
496
+ await drainOutstandingWork({ state: waitState, events: pi.events }, drainObservation);
731
497
  });
732
- const structuredOutputPath = process.env[STRUCTURED_OUTPUT_CAPTURE_ENV];
733
- const structuredAcceptanceReportPath = process.env[STRUCTURED_OUTPUT_ACCEPTANCE_CAPTURE_ENV];
734
- const structuredAcceptanceReportRequired = process.env[STRUCTURED_OUTPUT_ACCEPTANCE_REQUIRED_ENV] === "1";
735
- const structuredSchemaPath = process.env[STRUCTURED_OUTPUT_SCHEMA_ENV];
736
- if (structuredOutputPath && structuredSchemaPath) {
737
- const schema = JSON.parse(fs.readFileSync(structuredSchemaPath, "utf-8")) as JsonSchemaObject;
738
- const acceptanceReportMode = structuredAcceptanceReportPath
739
- ? structuredAcceptanceReportRequired ? "required" as const : "optional" as const
740
- : undefined;
741
- const parameters = createStructuredOutputToolParameters(schema, { acceptanceReport: acceptanceReportMode });
742
- const registerTool = pi.registerTool as unknown as (tool: {
743
- name: string;
744
- label: string;
745
- description: string;
746
- parameters: unknown;
747
- execute: (_id: string, params: { value: unknown; acceptanceReport?: unknown }) => Promise<unknown>;
748
- }) => void;
749
- registerTool({
750
- name: "structured_output",
751
- label: "Structured Output",
752
- description: "Submit the required final structured output for this subagent step. This terminates the step.",
753
- parameters,
754
- async execute(_id: string, params: { value: unknown; acceptanceReport?: unknown }) {
755
- const validation = await validateStructuredOutputValue(schema, params.value);
756
- if (validation.status === "invalid") {
757
- throw new Error(`Structured output validation failed: ${validation.message}`);
758
- }
759
- if (structuredAcceptanceReportRequired && params.acceptanceReport === undefined) {
760
- throw new Error(MISSING_STRUCTURED_ACCEPTANCE_REPORT_ERROR);
761
- }
762
- if (structuredAcceptanceReportRequired && params.acceptanceReport !== undefined) {
763
- const acceptanceValidation = validateAcceptanceReport(params.acceptanceReport, "acceptanceReport");
764
- if (!acceptanceValidation.report) {
765
- throw new Error(`Invalid structured output acceptance report: ${acceptanceValidation.errors.join("; ")}`);
766
- }
767
- }
768
- fs.mkdirSync(path.dirname(structuredOutputPath), { recursive: true });
769
- if (structuredAcceptanceReportPath && params.acceptanceReport !== undefined) {
770
- fs.mkdirSync(path.dirname(structuredAcceptanceReportPath), { recursive: true });
771
- fs.writeFileSync(structuredAcceptanceReportPath, JSON.stringify(params.acceptanceReport), { mode: 0o600 });
772
- } else if (structuredAcceptanceReportPath && fs.existsSync(structuredAcceptanceReportPath)) {
773
- fs.unlinkSync(structuredAcceptanceReportPath);
774
- }
775
- fs.writeFileSync(structuredOutputPath, JSON.stringify(params.value), { mode: 0o600 });
776
- return {
777
- content: [{ type: "text", text: "Structured output captured." }],
778
- details: { path: structuredOutputPath },
779
- terminate: true,
780
- };
781
- },
782
- });
783
- }
498
+ if (config.structuredOutput) registerStructuredOutputTool(pi, config.structuredOutput);
784
499
 
785
- onRuntimeEvent("before_provider_request", (event: unknown, ctx?: ExtensionContext) => rewriteForkCacheProviderRequest(event as BeforeProviderRequestEvent, ctx));
500
+ onRuntimeEvent("before_provider_request", (event: unknown, ctx?: ExtensionContext) => rewriteForkCacheProviderRequest(event as BeforeProviderRequestEvent, ctx, config.forkCacheKey));
786
501
 
787
502
  onRuntimeEvent("context", (event: unknown, ctx?: ExtensionContext) => {
788
503
  if (!event || typeof event !== "object" || !("messages" in event) || !Array.isArray(event.messages)) return undefined;
789
504
  const messages = stripParentOnlySubagentMessages(event.messages, {
790
505
  sanitizeToolIds: !COMPOSITE_TOOL_ID_APIS.has(ctx?.model?.api ?? ""),
506
+ preserveFanoutToolHistory: config.fanoutChild,
791
507
  });
792
508
  if (messages === event.messages) return undefined;
793
509
  return { messages };
@@ -799,24 +515,21 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
799
515
  // The intercom target is a routing address and always wins; the display
800
516
  // name (agent + task excerpt, computed by the parent at launch) only
801
517
  // applies when the bridge is not addressing this child.
802
- const intercomSessionName = process.env[SUBAGENT_INTERCOM_SESSION_NAME_ENV]?.trim();
803
- const displaySessionName = process.env[SUBAGENT_SESSION_NAME_ENV]?.trim();
804
- const childSessionName = intercomSessionName || displaySessionName;
518
+ const childSessionName = config.intercomSessionName || config.sessionName;
805
519
  if (childSessionName && typeof pi.setSessionName === "function") {
806
520
  pi.setSessionName(childSessionName);
807
521
  }
808
522
 
809
- const inheritProjectContext = readBooleanEnv(SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV);
810
- const inheritGlobalContext = readBooleanEnv(SUBAGENT_INHERIT_GLOBAL_CONTEXT_ENV);
811
- const inheritSkills = readBooleanEnv(SUBAGENT_INHERIT_SKILLS_ENV);
812
- const fanoutChild = readBooleanEnv(SUBAGENT_FANOUT_CHILD_ENV);
523
+ const { inheritProjectContext, inheritGlobalContext, inheritSkills } = config;
524
+ const fanoutChild = config.fanoutChild;
813
525
  let rewritten = event.systemPrompt;
814
- if (inheritProjectContext !== undefined || inheritGlobalContext !== undefined || inheritSkills !== undefined || fanoutChild !== undefined) {
526
+ if (inheritProjectContext !== undefined || inheritGlobalContext !== undefined || inheritSkills !== undefined || fanoutChild) {
815
527
  rewritten = rewriteSubagentPrompt(event.systemPrompt, {
816
528
  inheritProjectContext: inheritProjectContext ?? true,
817
529
  inheritGlobalContext: inheritGlobalContext ?? true,
818
530
  inheritSkills: inheritSkills ?? true,
819
- fanoutChild: fanoutChild === true,
531
+ fanoutChild,
532
+ structuredOutput: Boolean(config.structuredOutput),
820
533
  });
821
534
  }
822
535
  if (rewritten === event.systemPrompt) return;