@selesai/code 0.5.20 → 0.5.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/dist/extensions/handoff-new.test.ts +8 -9
  2. package/dist/extensions/handoff-new.ts +6 -8
  3. package/dist/extensions/pi-subagents/CHANGELOG.md +1367 -0
  4. package/dist/extensions/pi-subagents/README.md +602 -220
  5. package/dist/extensions/pi-subagents/banner.png +0 -0
  6. package/dist/extensions/pi-subagents/index.ts +1 -0
  7. package/dist/extensions/pi-subagents/install.mjs +3 -3
  8. package/dist/extensions/pi-subagents/package-lock.json +3405 -0
  9. package/dist/extensions/pi-subagents/package.json +26 -14
  10. package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
  11. package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
  12. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
  13. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
  14. package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
  15. package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
  16. package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
  17. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
  18. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
  19. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
  20. package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
  21. package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
  22. package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
  23. package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
  24. package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
  25. package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
  26. package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
  27. package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
  28. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
  29. package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
  30. package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
  31. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
  32. package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
  33. package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
  34. package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
  35. package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
  36. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
  37. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
  38. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
  39. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
  40. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
  41. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
  42. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
  43. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
  44. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
  45. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
  46. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
  47. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
  48. package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
  49. package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
  50. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
  51. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
  52. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
  53. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
  54. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
  55. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
  56. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
  57. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
  58. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
  59. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
  60. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
  61. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
  62. package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
  63. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
  64. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
  65. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
  66. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
  67. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
  68. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
  69. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
  70. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
  71. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
  72. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
  73. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
  74. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
  75. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
  76. package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
  77. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
  78. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
  79. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
  80. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
  81. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
  82. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
  83. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
  84. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
  85. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
  86. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
  87. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
  88. package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
  89. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
  90. package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
  91. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
  92. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
  93. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
  94. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
  95. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
  96. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
  97. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
  98. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
  99. package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
  100. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
  101. package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
  102. package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
  103. package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
  104. package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
  105. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
  106. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
  107. package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
  108. package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
  109. package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
  110. package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
  111. package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
  112. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
  113. package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
  114. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
  115. package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
  116. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
  117. package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
  118. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
  119. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
  120. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
  121. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
  122. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
  123. package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
  124. package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
  125. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
  126. package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
  127. package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
  128. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
  129. package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
  130. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
  131. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
  132. package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
  133. package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
  134. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
  135. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
  136. package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
  137. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
  138. package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
  139. package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
  140. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
  141. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
  142. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
  143. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
  144. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
  145. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
  146. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
  147. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
  148. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
  149. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
  150. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
  151. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
  152. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
  153. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
  154. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
  155. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
  156. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
  157. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
  158. package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
  159. package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
  160. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
  161. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
  162. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
  163. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
  164. package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
  165. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
  166. package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
  167. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
  168. package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
  169. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
  170. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
  171. package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
  172. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
  173. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
  174. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
  175. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
  176. package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
  177. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
  178. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
  179. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
  180. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
  181. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
  182. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
  183. package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
  184. package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
  185. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
  186. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
  187. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
  188. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
  189. package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
  190. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
  191. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
  192. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
  193. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
  194. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
  195. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
  196. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
  197. package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
  198. package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
  199. package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
  200. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
  201. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
  202. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
  203. package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
  204. package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
  205. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
  206. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
  207. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
  208. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
  209. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
  210. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
  211. package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
  212. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
  213. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
  214. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
  215. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
  216. package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
  217. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
  218. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
  219. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
  220. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
  221. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
  222. package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
  223. package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
  224. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
  225. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
  226. package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
  227. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
  228. package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
  229. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
  230. package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
  231. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
  232. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
  233. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
  234. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
  235. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
  236. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
  237. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
  238. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
  239. package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
  240. package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
  241. package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
  242. package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
  243. package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
  244. package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
  245. package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
  246. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
  247. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
  248. package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
  249. package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
  250. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
  251. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
  252. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
  253. package/dist/extensions/question/batch.ts +39 -0
  254. package/dist/extensions/question/dialog-adapter.ts +23 -1
  255. package/dist/extensions/question/index.ts +237 -7
  256. package/dist/extensions/question/schemas.ts +28 -15
  257. package/dist/extensions/question/tests/batch.test.ts +26 -0
  258. package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
  259. package/dist/extensions/question/tui-adapter.ts +2 -3
  260. package/dist/extensions/question/types.ts +37 -0
  261. package/dist/extensions/question/ui-protocol.ts +3 -3
  262. package/dist/skills/batch-grill-me/SKILL.md +3 -1
  263. package/package.json +1 -1
@@ -69,14 +69,16 @@ interface MetadataCache {
69
69
  servers: Record<string, ServerCacheEntry>;
70
70
  }
71
71
 
72
- export function resolveMcpDirectToolNames(mcpDirectTools: string[] | undefined, cwd = process.cwd()): string[] {
72
+ export interface ResolvedMcpDirectToolSelection { name: string; selector: string }
73
+
74
+ export function resolveMcpDirectToolSelections(mcpDirectTools: string[] | undefined, cwd = process.cwd()): ResolvedMcpDirectToolSelection[] {
73
75
  if (!mcpDirectTools?.length) return [];
74
76
 
75
77
  try {
76
78
  const config = loadMcpConfig(cwd);
77
79
  const cache = loadMetadataCache();
78
80
  if (!cache) return [];
79
- return resolveDirectToolNames(config, cache, getToolPrefix(config.settings?.toolPrefix), mcpDirectTools);
81
+ return resolveDirectToolSelections(config, cache, getToolPrefix(config.settings?.toolPrefix), mcpDirectTools);
80
82
  } catch {
81
83
  return [];
82
84
  }
@@ -195,8 +197,8 @@ function extractServers(config: unknown, kind: ImportKind): Record<string, Serve
195
197
  return servers && typeof servers === "object" && !Array.isArray(servers) ? servers as Record<string, ServerEntry> : {};
196
198
  }
197
199
 
198
- function resolveDirectToolNames(config: McpConfig, cache: MetadataCache, prefix: ToolPrefix, envOverride: string[]): string[] {
199
- const names: string[] = [];
200
+ function resolveDirectToolSelections(config: McpConfig, cache: MetadataCache, prefix: ToolPrefix, envOverride: string[]): ResolvedMcpDirectToolSelection[] {
201
+ const names: ResolvedMcpDirectToolSelection[] = [];
200
202
  const seenNames = new Set<string>();
201
203
  const { servers: selectedServers, tools: selectedTools } = parseSelections(envOverride);
202
204
 
@@ -216,7 +218,7 @@ function resolveDirectToolNames(config: McpConfig, cache: MetadataCache, prefix:
216
218
  const prefixedName = formatToolName(tool.name, serverName, prefix);
217
219
  if (BUILTIN_TOOL_NAMES.has(prefixedName) || seenNames.has(prefixedName)) continue;
218
220
  seenNames.add(prefixedName);
219
- names.push(prefixedName);
221
+ names.push({ name: prefixedName, selector: `${serverName}/${tool.name}` });
220
222
  }
221
223
 
222
224
  if (definition.exposeResources === false) continue;
@@ -228,13 +230,17 @@ function resolveDirectToolNames(config: McpConfig, cache: MetadataCache, prefix:
228
230
  const prefixedName = formatToolName(baseName, serverName, prefix);
229
231
  if (BUILTIN_TOOL_NAMES.has(prefixedName) || seenNames.has(prefixedName)) continue;
230
232
  seenNames.add(prefixedName);
231
- names.push(prefixedName);
233
+ names.push({ name: prefixedName, selector: `${serverName}/${baseName}` });
232
234
  }
233
235
  }
234
236
 
235
237
  return names;
236
238
  }
237
239
 
240
+ export function resolveMcpDirectToolNames(mcpDirectTools: string[] | undefined, cwd = process.cwd()): string[] {
241
+ return resolveMcpDirectToolSelections(mcpDirectTools, cwd).map((selection) => selection.name);
242
+ }
243
+
238
244
  function parseSelections(selections: string[]): { servers: Set<string>; tools: Map<string, Set<string>> } {
239
245
  const servers = new Set<string>();
240
246
  const tools = new Map<string, Set<string>>();
@@ -211,6 +211,31 @@ export function resolveSubagentModelOverride(
211
211
  return resolved;
212
212
  }
213
213
 
214
+ export function resolveEffectiveSubagentModel(
215
+ explicitModel: string | boolean | undefined,
216
+ agentModel: string | boolean | undefined,
217
+ parentModel: ParentModel | undefined,
218
+ availableModels: AvailableModelInfo[] | undefined,
219
+ preferredProvider?: string,
220
+ options?: Omit<ResolveSubagentModelOverrideOptions, "source">,
221
+ ): string | undefined {
222
+ const resolved = resolveSubagentModelOverride(
223
+ explicitModel ?? agentModel,
224
+ parentModel,
225
+ availableModels,
226
+ preferredProvider,
227
+ { ...options, source: explicitModel !== undefined ? "explicit" : "inherited" },
228
+ );
229
+ if (resolved || explicitModel === undefined) return resolved;
230
+ return resolveSubagentModelOverride(
231
+ agentModel,
232
+ parentModel,
233
+ availableModels,
234
+ preferredProvider,
235
+ { ...options, source: "inherited" },
236
+ );
237
+ }
238
+
214
239
  export interface BuildModelCandidatesOptions {
215
240
  /** Fallback models are inherited agent config and warn, rather than error, when out of scope. */
216
241
  scope?: ModelScopeConfig;
@@ -267,6 +292,7 @@ const RETRYABLE_MODEL_FAILURE_PATTERNS = [
267
292
  /fetch failed/i,
268
293
  /network error/i,
269
294
  /socket hang up/i,
295
+ /stream ended without finish_reason/i,
270
296
  /upstream/i,
271
297
  /timed? out/i,
272
298
  /timeout/i,
@@ -279,8 +305,18 @@ const RETRYABLE_MODEL_FAILURE_PATTERNS = [
279
305
  /model.*(?:load|fail|error)/i,
280
306
  ];
281
307
 
308
+ /**
309
+ * Failures reported as `<tool> failed (exit N): ...` or `<tool> failed with
310
+ * exit code N` come from a tool call inside the child's task, not from the
311
+ * provider/model, however network-flavored their details read. Retrying a
312
+ * different model cannot fix them and would rerun the whole task. Tool names
313
+ * include namespaced forms like `mcp.server/write`.
314
+ */
315
+ const TOOL_FAILURE_PREFIX = /^[\w.:@/-]+ failed (?:(?:\(exit \d+\):)|(?:with exit code \d+))(?:\s|$)/i;
316
+
282
317
  export function isRetryableModelFailure(error: string | undefined): boolean {
283
318
  if (!error) return false;
319
+ if (TOOL_FAILURE_PREFIX.test(error.trim())) return false;
284
320
  return RETRYABLE_MODEL_FAILURE_PATTERNS.some((pattern) => pattern.test(error));
285
321
  }
286
322
 
@@ -27,6 +27,7 @@ import {
27
27
  SUBAGENT_PARENT_RUN_ID_ENV,
28
28
  } from "./pi-args.ts";
29
29
  import { writeAtomicJson } from "../../shared/atomic-json.ts";
30
+ import { sanitizeProcessTerminal } from "../background/process-terminal.ts";
30
31
 
31
32
  export const NESTED_EVENTS_DIR = path.join(TEMP_ROOT_DIR, "nested-subagent-events");
32
33
  const ROUTE_FILE = "route.json";
@@ -202,7 +203,7 @@ function sanitizeTurnBudget(value: unknown): TurnBudgetState | undefined {
202
203
  const maxTurns = clampNumber(raw.maxTurns);
203
204
  const graceTurns = clampNumber(raw.graceTurns);
204
205
  const turnCount = clampNumber(raw.turnCount);
205
- const outcome = raw.outcome === "within-budget" || raw.outcome === "wrap-up-requested" || raw.outcome === "exceeded" ? raw.outcome : undefined;
206
+ const outcome = raw.outcome === "within-budget" || raw.outcome === "wrap-up-requested" || raw.outcome === "termination-deferred" || raw.outcome === "exceeded" ? raw.outcome : undefined;
206
207
  if (maxTurns === undefined || graceTurns === undefined || turnCount === undefined || !outcome) return undefined;
207
208
  return {
208
209
  maxTurns,
@@ -210,12 +211,13 @@ function sanitizeTurnBudget(value: unknown): TurnBudgetState | undefined {
210
211
  turnCount,
211
212
  outcome,
212
213
  ...(clampNumber(raw.wrapUpRequestedAtTurn) !== undefined ? { wrapUpRequestedAtTurn: clampNumber(raw.wrapUpRequestedAtTurn) } : {}),
214
+ ...(clampNumber(raw.terminationDeferredAtTurn) !== undefined ? { terminationDeferredAtTurn: clampNumber(raw.terminationDeferredAtTurn) } : {}),
213
215
  ...(clampNumber(raw.exceededAtTurn) !== undefined ? { exceededAtTurn: clampNumber(raw.exceededAtTurn) } : {}),
214
216
  };
215
217
  }
216
218
 
217
219
  function sanitizeState(value: unknown, fallback: NestedRunState): NestedRunState {
218
- return value === "queued" || value === "running" || value === "complete" || value === "failed" || value === "paused"
220
+ return value === "queued" || value === "running" || value === "complete" || value === "failed" || value === "paused" || value === "stopped"
219
221
  ? value
220
222
  : fallback;
221
223
  }
@@ -225,7 +227,7 @@ function sanitizeStep(input: unknown, depth: number): NestedStepSummary | undefi
225
227
  const raw = input as Record<string, unknown>;
226
228
  const agent = stringValue(raw.agent, 128);
227
229
  if (!agent) return undefined;
228
- const status = raw.status === "pending" || raw.status === "running" || raw.status === "complete" || raw.status === "completed" || raw.status === "failed" || raw.status === "paused"
230
+ const status = raw.status === "pending" || raw.status === "running" || raw.status === "complete" || raw.status === "completed" || raw.status === "failed" || raw.status === "paused" || raw.status === "stopped"
229
231
  ? raw.status
230
232
  : "pending";
231
233
  return {
@@ -243,6 +245,7 @@ function sanitizeStep(input: unknown, depth: number): NestedStepSummary | undefi
243
245
  ...(clampNumber(raw.endedAt) !== undefined ? { endedAt: clampNumber(raw.endedAt) } : {}),
244
246
  ...(stringValue(raw.error, 1024) ? { error: stringValue(raw.error, 1024) } : {}),
245
247
  ...(raw.timedOut === true ? { timedOut: true } : {}),
248
+ ...(raw.stopped === true ? { stopped: true } : {}),
246
249
  ...(sanitizeTurnBudget(raw.turnBudget) ? { turnBudget: sanitizeTurnBudget(raw.turnBudget) } : {}),
247
250
  ...(raw.turnBudgetExceeded === true ? { turnBudgetExceeded: true } : {}),
248
251
  ...(raw.wrapUpRequested === true ? { wrapUpRequested: true } : {}),
@@ -298,6 +301,7 @@ export function sanitizeSummary(input: unknown, depth = 0): NestedRunSummary | u
298
301
  ...(clampNumber(raw.timeoutMs) !== undefined ? { timeoutMs: clampNumber(raw.timeoutMs) } : {}),
299
302
  ...(clampNumber(raw.deadlineAt) !== undefined ? { deadlineAt: clampNumber(raw.deadlineAt) } : {}),
300
303
  ...(raw.timedOut === true ? { timedOut: true } : {}),
304
+ ...(raw.stopped === true ? { stopped: true } : {}),
301
305
  ...(sanitizeTurnBudget(raw.turnBudget) ? { turnBudget: sanitizeTurnBudget(raw.turnBudget) } : {}),
302
306
  ...(raw.turnBudgetExceeded === true ? { turnBudgetExceeded: true } : {}),
303
307
  ...(raw.wrapUpRequested === true ? { wrapUpRequested: true } : {}),
@@ -353,7 +357,7 @@ export function parseNestedEventRecords(content: string, route: NestedRoute): Ne
353
357
  }
354
358
 
355
359
  function terminal(state: NestedRunState): boolean {
356
- return state === "complete" || state === "failed" || state === "paused";
360
+ return state === "complete" || state === "failed" || state === "paused" || state === "stopped";
357
361
  }
358
362
 
359
363
  function mergeSummary(existing: NestedRunSummary | undefined, event: NestedEventRecord): NestedRunSummary {
@@ -609,7 +613,9 @@ export function projectNestedEvents(route: NestedRoute): NestedRegistry {
609
613
  } catch {
610
614
  continue;
611
615
  }
612
- for (const event of parseNestedEventRecords(content, route)) {
616
+ const records = parseNestedEventRecords(content, route);
617
+ if (records.length === 0) continue;
618
+ for (const event of records) {
613
619
  registry = applyNestedEvent(registry, event);
614
620
  changed = true;
615
621
  }
@@ -617,11 +623,34 @@ export function projectNestedEvents(route: NestedRoute): NestedRegistry {
617
623
  changed = true;
618
624
  }
619
625
  if (changed) {
620
- registry = { ...registry, processedEvents: [...seen].slice(-1000) };
626
+ const processedEvents = [...seen];
627
+ const retainedEvents = processedEvents.slice(-1000);
628
+ const evictedEvents = processedEvents.slice(0, -1000);
629
+ registry = { ...registry, processedEvents: retainedEvents };
621
630
  // Parent projection is the only writer to this sidecar registry. Child and
622
631
  // runner processes only create immutable event files, so parent status.json
623
632
  // remains owned by the existing runner writer and is never rewritten here.
624
633
  writeAtomicJson(registryPath(route), registry);
634
+
635
+ // The registry retains only a bounded filename cursor. Remove the old
636
+ // immutable status records after the cursor is durable; otherwise an evicted
637
+ // filename is rediscovered on the next projection and replayed forever.
638
+ for (const entry of evictedEvents) {
639
+ const eventPath = path.join(route.eventSink, entry);
640
+ if (!containedPath(route.eventSink, eventPath)) continue;
641
+ try {
642
+ const stat = fs.statSync(eventPath);
643
+ if (!stat.isFile() || stat.size > MAX_EVENT_BYTES) continue;
644
+ const content = fs.readFileSync(eventPath, "utf-8");
645
+ const hasStatusRecord = parseNestedEventRecords(content, route).length > 0;
646
+ const hasControlResult = content
647
+ .split("\n")
648
+ .some((line) => line.trim() && parseControlResult(line.trim(), route));
649
+ if (hasStatusRecord && !hasControlResult) fs.unlinkSync(eventPath);
650
+ } catch {
651
+ // A cleanup failure must not make a successfully projected status fail.
652
+ }
653
+ }
625
654
  }
626
655
  return registry;
627
656
  }
@@ -845,6 +874,9 @@ export function nestedSummaryFromAsyncStatus(status: AsyncStatus, asyncDir: stri
845
874
  ...(status.pid ? { pid: status.pid } : {}),
846
875
  ...(status.sessionId ? { sessionId: status.sessionId } : {}),
847
876
  mode: status.mode ?? fallback.mode,
877
+ ...(status.processTerminal ? { processTerminal: sanitizeProcessTerminal(status.processTerminal, { runId: status.runId || fallback.id, runnerProcessInstanceId: status.processTerminal.runnerProcessInstanceId }, `${asyncDir}/status.json`) } : {}),
878
+ ...(status.capabilityCeiling ? { capabilityCeiling: status.capabilityCeiling } : {}),
879
+ ...(status.capabilityAudit ? { capabilityAudit: status.capabilityAudit } : {}),
848
880
  state: status.state,
849
881
  ...(status.currentStep !== undefined ? { currentStep: status.currentStep } : {}),
850
882
  ...(status.chainStepCount !== undefined ? { chainStepCount: status.chainStepCount } : {}),
@@ -859,6 +891,7 @@ export function nestedSummaryFromAsyncStatus(status: AsyncStatus, asyncDir: stri
859
891
  ...(status.timeoutMs !== undefined ? { timeoutMs: status.timeoutMs } : {}),
860
892
  ...(status.deadlineAt !== undefined ? { deadlineAt: status.deadlineAt } : {}),
861
893
  ...(status.timedOut !== undefined ? { timedOut: status.timedOut } : {}),
894
+ ...(status.stopped !== undefined ? { stopped: status.stopped } : {}),
862
895
  ...(status.turnBudget ? { turnBudget: status.turnBudget } : {}),
863
896
  ...(status.turnBudgetExceeded !== undefined ? { turnBudgetExceeded: status.turnBudgetExceeded } : {}),
864
897
  ...(status.wrapUpRequested !== undefined ? { wrapUpRequested: status.wrapUpRequested } : {}),
@@ -867,7 +900,7 @@ export function nestedSummaryFromAsyncStatus(status: AsyncStatus, asyncDir: stri
867
900
  ...(status.endedAt !== undefined ? { endedAt: status.endedAt } : {}),
868
901
  lastUpdate: status.lastUpdate ?? fallback.ts,
869
902
  ...(status.sessionFile ? { sessionFile: status.sessionFile } : {}),
870
- ...(status.steps?.length ? { steps: status.steps.map((step) => ({
903
+ ...(status.steps?.length ? { steps: status.steps.map((step, index) => ({
871
904
  agent: step.agent,
872
905
  status: step.status,
873
906
  ...(step.sessionFile ? { sessionFile: step.sessionFile } : {}),
@@ -882,9 +915,13 @@ export function nestedSummaryFromAsyncStatus(status: AsyncStatus, asyncDir: stri
882
915
  ...(step.endedAt !== undefined ? { endedAt: step.endedAt } : {}),
883
916
  ...(step.error ? { error: step.error } : {}),
884
917
  ...(step.timedOut !== undefined ? { timedOut: step.timedOut } : {}),
918
+ ...(step.stopped !== undefined ? { stopped: step.stopped } : {}),
885
919
  ...(step.turnBudget ? { turnBudget: step.turnBudget } : {}),
886
920
  ...(step.turnBudgetExceeded !== undefined ? { turnBudgetExceeded: step.turnBudgetExceeded } : {}),
887
921
  ...(step.wrapUpRequested !== undefined ? { wrapUpRequested: step.wrapUpRequested } : {}),
922
+ ...(step.processTerminal ? { processTerminal: sanitizeProcessTerminal(step.processTerminal, { runId: status.runId || fallback.id, runnerProcessInstanceId: step.processTerminal.runnerProcessInstanceId }, `${asyncDir}/status.json step ${index}`) } : {}),
923
+ ...(step.capabilityCeiling ? { capabilityCeiling: step.capabilityCeiling } : {}),
924
+ ...(step.capabilityAudit ? { capabilityAudit: step.capabilityAudit } : {}),
888
925
  })).slice(0, MAX_STEPS) } : {}),
889
926
  };
890
927
  }
@@ -8,11 +8,12 @@ export interface NestedRunCounts {
8
8
  paused: number;
9
9
  complete: number;
10
10
  failed: number;
11
+ stopped: number;
11
12
  queued: number;
12
13
  }
13
14
 
14
15
  export function countNestedRuns(children: NestedRunSummary[] | undefined): NestedRunCounts {
15
- const counts: NestedRunCounts = { total: 0, running: 0, paused: 0, complete: 0, failed: 0, queued: 0 };
16
+ const counts: NestedRunCounts = { total: 0, running: 0, paused: 0, complete: 0, failed: 0, stopped: 0, queued: 0 };
16
17
  for (const child of children ?? []) {
17
18
  counts.total++;
18
19
  counts[child.state]++;
@@ -22,6 +23,7 @@ export function countNestedRuns(children: NestedRunSummary[] | undefined): Neste
22
23
  counts.paused += nested.paused;
23
24
  counts.complete += nested.complete;
24
25
  counts.failed += nested.failed;
26
+ counts.stopped += nested.stopped;
25
27
  counts.queued += nested.queued;
26
28
  }
27
29
  return counts;
@@ -34,6 +36,7 @@ export function formatNestedAggregate(children: NestedRunSummary[] | undefined):
34
36
  counts.running > 0 ? `${counts.running} running` : "",
35
37
  counts.paused > 0 ? `${counts.paused} paused` : "",
36
38
  counts.failed > 0 ? `${counts.failed} failed` : "",
39
+ counts.stopped > 0 ? `${counts.stopped} stopped` : "",
37
40
  counts.complete > 0 ? `${counts.complete} complete` : "",
38
41
  counts.queued > 0 ? `${counts.queued} queued` : "",
39
42
  ].filter(Boolean);
@@ -0,0 +1,154 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { writeAtomicJson } from "../../shared/atomic-json.ts";
4
+ import type {
5
+ ParallelHandoffGroup,
6
+ ParallelHandoffManifest,
7
+ ParallelHandoffReference,
8
+ SubagentResultStatus,
9
+ } from "../../shared/types.ts";
10
+ import type {
11
+ WorktreeCleanupReport,
12
+ WorktreeDiff,
13
+ WorktreeSetup,
14
+ } from "./worktree.ts";
15
+
16
+ export interface ParallelHandoffResult {
17
+ agent: string;
18
+ status: SubagentResultStatus;
19
+ summary: string;
20
+ outputPath?: string;
21
+ structuredOutput?: unknown;
22
+ structuredOutputPath?: string;
23
+ sessionPath?: string;
24
+ }
25
+
26
+ function readManifest(manifestPath: string): ParallelHandoffManifest | undefined {
27
+ if (!fs.existsSync(manifestPath)) return undefined;
28
+ const parsed = JSON.parse(fs.readFileSync(manifestPath, "utf-8")) as ParallelHandoffManifest;
29
+ if (parsed.version !== 1 || !Array.isArray(parsed.groups)) {
30
+ throw new Error(`Invalid parallel handoff manifest: ${manifestPath}`);
31
+ }
32
+ return parsed;
33
+ }
34
+
35
+ function referenceFor(manifestPath: string, manifest: ParallelHandoffManifest): ParallelHandoffReference {
36
+ const children = manifest.groups.flatMap((group) => group.children);
37
+ return {
38
+ version: 1,
39
+ path: manifestPath,
40
+ groupCount: manifest.groups.length,
41
+ childCount: children.length,
42
+ changedPatches: children.filter((child) => child.patch.changed).length,
43
+ cleanupState: manifest.groups.every((group) => group.cleanup.state === "complete") ? "complete" : "partial",
44
+ };
45
+ }
46
+
47
+ function safeHandoffAgentName(agent: string): string {
48
+ return agent.replace(/[^\w.-]/g, "_");
49
+ }
50
+
51
+ function missingDiff(input: { manifestPath: string; stepIndex: number; taskIndex: number; agent: string; branch?: string }): WorktreeDiff {
52
+ const patchPath = path.join(path.dirname(input.manifestPath), `missing-diff-step-${input.stepIndex}-task-${input.taskIndex}-${safeHandoffAgentName(input.agent)}.patch`);
53
+ try {
54
+ fs.mkdirSync(path.dirname(patchPath), { recursive: true });
55
+ fs.writeFileSync(patchPath, "", "utf-8");
56
+ } catch {
57
+ // Handoff records the artifact failure below; patch creation remains best-effort.
58
+ }
59
+ return {
60
+ index: input.taskIndex,
61
+ agent: input.agent,
62
+ branch: input.branch ?? "",
63
+ diffStat: "",
64
+ filesChanged: 0,
65
+ insertions: 0,
66
+ deletions: 0,
67
+ patchPath,
68
+ error: "diff artifact unavailable; no patch was captured",
69
+ };
70
+ }
71
+
72
+ export function writeParallelHandoffGroup(input: {
73
+ manifestPath: string;
74
+ runId: string;
75
+ mode: "parallel" | "chain";
76
+ source: "foreground" | "async";
77
+ cwd: string;
78
+ stepIndex: number;
79
+ flatStartIndex: number;
80
+ setup: WorktreeSetup;
81
+ diffs: WorktreeDiff[];
82
+ cleanup: WorktreeCleanupReport;
83
+ results: ParallelHandoffResult[];
84
+ now?: number;
85
+ }): ParallelHandoffReference {
86
+ const now = input.now ?? Date.now();
87
+ const existing = readManifest(input.manifestPath);
88
+ if (existing && (existing.runId !== input.runId || existing.mode !== input.mode || existing.source !== input.source)) {
89
+ throw new Error(`Parallel handoff manifest belongs to a different run: ${input.manifestPath}`);
90
+ }
91
+ const group: ParallelHandoffGroup = {
92
+ stepIndex: input.stepIndex,
93
+ baseCommit: input.setup.baseCommit,
94
+ repoRoot: input.setup.cwd,
95
+ children: input.results.map((result, taskIndex) => {
96
+ const diff = input.diffs[taskIndex] ?? missingDiff({
97
+ manifestPath: input.manifestPath,
98
+ stepIndex: input.stepIndex,
99
+ taskIndex,
100
+ agent: result.agent,
101
+ branch: input.setup.worktrees[taskIndex]?.branch,
102
+ });
103
+ return {
104
+ index: input.flatStartIndex + taskIndex,
105
+ taskIndex,
106
+ agent: result.agent,
107
+ status: result.status,
108
+ summary: result.summary,
109
+ ...(result.outputPath ? { outputPath: result.outputPath } : {}),
110
+ ...(result.structuredOutput !== undefined ? { structuredOutput: result.structuredOutput } : {}),
111
+ ...(result.structuredOutputPath ? { structuredOutputPath: result.structuredOutputPath } : {}),
112
+ ...(result.sessionPath ? { sessionPath: result.sessionPath } : {}),
113
+ patch: {
114
+ path: diff.patchPath,
115
+ branch: diff.branch,
116
+ changed: diff.filesChanged > 0 || diff.insertions > 0 || diff.deletions > 0 || diff.diffStat.trim().length > 0,
117
+ diffStat: diff.diffStat,
118
+ filesChanged: diff.filesChanged,
119
+ insertions: diff.insertions,
120
+ deletions: diff.deletions,
121
+ ...(diff.error ? { error: diff.error } : {}),
122
+ },
123
+ };
124
+ }),
125
+ cleanup: input.cleanup,
126
+ };
127
+ const groups = existing?.groups.filter((candidate) => candidate.stepIndex !== input.stepIndex) ?? [];
128
+ groups.push(group);
129
+ groups.sort((left, right) => left.stepIndex - right.stepIndex);
130
+ const manifest: ParallelHandoffManifest = {
131
+ version: 1,
132
+ runId: input.runId,
133
+ mode: input.mode,
134
+ source: input.source,
135
+ cwd: input.cwd,
136
+ createdAt: existing?.createdAt ?? now,
137
+ updatedAt: now,
138
+ groups,
139
+ };
140
+ writeAtomicJson(input.manifestPath, manifest);
141
+ return referenceFor(input.manifestPath, manifest);
142
+ }
143
+
144
+ export function parallelHandoffPath(baseDir: string, runId?: string): string {
145
+ return runId ? path.join(baseDir, "handoffs", `${runId}.json`) : path.join(baseDir, "handoff.json");
146
+ }
147
+
148
+ export function formatParallelHandoffReference(reference: ParallelHandoffReference): string {
149
+ return `Parallel handoff: ${reference.path} (${reference.childCount} children, ${reference.changedPatches} changed patches, cleanup ${reference.cleanupState})`;
150
+ }
151
+
152
+ export function formatParallelHandoffError(error: unknown): string {
153
+ return `Parallel handoff unavailable: ${error instanceof Error ? error.message : String(error)}`;
154
+ }
@@ -3,6 +3,8 @@ export interface RunnerSubagentStep {
3
3
  parentSessionId?: string;
4
4
  agent: string;
5
5
  task: string;
6
+ /** Resolved launch context for this child. */
7
+ context?: "fresh" | "fork";
6
8
  importAsyncRoot?: {
7
9
  runId: string;
8
10
  asyncDir: string;
@@ -28,17 +30,29 @@ export interface RunnerSubagentStep {
28
30
  inheritSkills: boolean;
29
31
  skills?: string[];
30
32
  outputPath?: string;
33
+ /** Defer the authoritative output instruction until a dynamic fanout item is materialized. */
34
+ namespaceOutputPath?: boolean;
31
35
  outputMode?: "inline" | "file-only";
32
36
  sessionFile?: string;
33
37
  maxSubagentDepth?: number;
38
+ waitToolEnabled?: boolean;
34
39
  structuredOutput?: {
35
40
  schema: import("../../shared/types.ts").JsonSchemaObject;
36
41
  schemaPath: string;
37
42
  outputPath: string;
38
43
  };
39
44
  structuredOutputSchema?: import("../../shared/types.ts").JsonSchemaObject;
45
+ agentContract?: import("../../shared/types.ts").AgentContract;
46
+ definitionDigest?: string;
47
+ launchBindingTask?: string;
48
+ launchContractDigest?: string;
40
49
  effectiveAcceptance?: import("../../shared/types.ts").ResolvedAcceptanceConfig;
50
+ acceptanceInput?: import("../../shared/types.ts").AcceptanceInput;
51
+ acceptanceRole?: import("../../shared/types.ts").AcceptanceRole;
52
+ gateOn?: import("../../shared/types.ts").ChainGateLayer;
41
53
  toolBudget?: import("../../shared/types.ts").ResolvedToolBudget;
54
+ capabilityCeiling?: import("./capability-ceiling.ts").ResolvedSubagentCapabilityCeiling;
55
+ capabilityAudit?: import("./capability-ceiling.ts").SubagentCapabilityAudit;
42
56
  }
43
57
 
44
58
  export interface ParallelStepGroup {
@@ -59,6 +73,10 @@ export interface DynamicRunnerGroup {
59
73
  sessionFiles?: (string | undefined)[];
60
74
  thinkingOverrides?: (string | undefined)[];
61
75
  effectiveAcceptance?: import("../../shared/types.ts").ResolvedAcceptanceConfig;
76
+ acceptanceInput?: import("../../shared/types.ts").AcceptanceInput;
77
+ acceptanceRole?: import("../../shared/types.ts").AcceptanceRole;
78
+ agentContract?: import("../../shared/types.ts").AgentContract;
79
+ gateOn?: import("../../shared/types.ts").ChainGateLayer;
62
80
  }
63
81
 
64
82
  export type RunnerStep = RunnerSubagentStep | ParallelStepGroup | DynamicRunnerGroup;