@selesai/code 0.5.19 → 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 (265) 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-intercom/broker/spawn.test.ts +31 -0
  4. package/dist/extensions/pi-intercom/broker/spawn.ts +5 -3
  5. package/dist/extensions/pi-subagents/CHANGELOG.md +1367 -0
  6. package/dist/extensions/pi-subagents/README.md +602 -220
  7. package/dist/extensions/pi-subagents/banner.png +0 -0
  8. package/dist/extensions/pi-subagents/index.ts +1 -0
  9. package/dist/extensions/pi-subagents/install.mjs +3 -3
  10. package/dist/extensions/pi-subagents/package-lock.json +3405 -0
  11. package/dist/extensions/pi-subagents/package.json +26 -14
  12. package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
  13. package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
  14. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
  15. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
  16. package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
  17. package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
  18. package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
  19. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
  20. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
  21. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
  22. package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
  23. package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
  24. package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
  25. package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
  26. package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
  27. package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
  28. package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
  29. package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
  30. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
  31. package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
  32. package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
  33. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
  34. package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
  35. package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
  36. package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
  37. package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
  38. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
  39. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
  40. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
  41. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
  42. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
  43. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
  44. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
  45. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
  46. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
  47. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
  48. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
  49. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
  50. package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
  51. package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
  52. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
  53. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
  54. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
  55. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
  56. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
  57. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
  58. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
  59. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
  60. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
  61. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
  62. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
  63. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
  64. package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
  65. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
  66. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
  67. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
  68. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
  69. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
  70. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
  71. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
  72. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
  73. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
  74. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
  75. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
  76. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
  77. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
  78. package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
  79. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
  80. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
  81. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
  82. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
  83. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
  84. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
  85. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
  86. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
  87. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
  88. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
  89. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
  90. package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
  91. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
  92. package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
  93. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
  94. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
  95. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
  96. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
  97. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
  98. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
  99. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
  100. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
  101. package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
  102. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
  103. package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
  104. package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
  105. package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
  106. package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
  107. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
  108. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
  109. package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
  110. package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
  111. package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
  112. package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
  113. package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
  114. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
  115. package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
  116. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
  117. package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
  118. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
  119. package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
  120. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
  121. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
  122. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
  123. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
  124. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
  125. package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
  126. package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
  127. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
  128. package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
  129. package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
  130. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
  131. package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
  132. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
  133. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
  134. package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
  135. package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
  136. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
  137. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
  138. package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
  139. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
  140. package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
  141. package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
  142. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
  143. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
  144. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
  145. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
  146. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
  147. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
  148. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
  149. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
  150. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
  151. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
  152. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
  153. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
  154. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
  155. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
  156. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
  157. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
  158. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
  159. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
  160. package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
  161. package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
  162. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
  163. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
  164. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
  165. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
  166. package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
  167. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
  168. package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
  169. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
  170. package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
  171. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
  172. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
  173. package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
  174. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
  175. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
  176. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
  177. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
  178. package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
  179. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
  180. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
  181. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
  182. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
  183. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
  184. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
  185. package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
  186. package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
  187. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
  188. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
  189. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
  190. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
  191. package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
  192. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
  193. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
  194. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
  195. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
  196. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
  197. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
  198. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
  199. package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
  200. package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
  201. package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
  202. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
  203. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
  204. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
  205. package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
  206. package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
  207. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
  208. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
  209. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
  210. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
  211. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
  212. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
  213. package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
  214. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
  215. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
  216. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
  217. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
  218. package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
  219. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
  220. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
  221. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
  222. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
  223. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
  224. package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
  225. package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
  226. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
  227. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
  228. package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
  229. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
  230. package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
  231. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
  232. package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
  233. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
  234. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
  235. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
  236. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
  237. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
  238. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
  239. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
  240. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
  241. package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
  242. package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
  243. package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
  244. package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
  245. package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
  246. package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
  247. package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
  248. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
  249. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
  250. package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
  251. package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
  252. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
  253. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
  254. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
  255. package/dist/extensions/question/batch.ts +39 -0
  256. package/dist/extensions/question/dialog-adapter.ts +23 -1
  257. package/dist/extensions/question/index.ts +237 -7
  258. package/dist/extensions/question/schemas.ts +28 -15
  259. package/dist/extensions/question/tests/batch.test.ts +26 -0
  260. package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
  261. package/dist/extensions/question/tui-adapter.ts +2 -3
  262. package/dist/extensions/question/types.ts +37 -0
  263. package/dist/extensions/question/ui-protocol.ts +3 -3
  264. package/dist/skills/batch-grill-me/SKILL.md +3 -1
  265. package/package.json +2 -1
@@ -12,7 +12,7 @@ import {
12
12
  SUBAGENT_RUN_ID_ENV,
13
13
  SUBAGENT_SUPERVISOR_CHANNEL_DIR_ENV,
14
14
  } from "../runs/shared/pi-args.ts";
15
- import { POLL_INTERVAL_MS, TEMP_ROOT_DIR, type SubagentState } from "../shared/types.ts";
15
+ import { INTERCOM_DETACH_REQUEST_EVENT, POLL_INTERVAL_MS, TEMP_ROOT_DIR, type IntercomEventBus, type SubagentState } from "../shared/types.ts";
16
16
  import { writeAtomicJson } from "../shared/atomic-json.ts";
17
17
 
18
18
  const SUPERVISOR_CHANNEL_ROOT = path.join(TEMP_ROOT_DIR, "supervisor-channels");
@@ -22,6 +22,8 @@ export const NATIVE_SUPERVISOR_TOOL_NAME = "subagent_supervisor";
22
22
  const MAX_MESSAGE_BYTES = 64 * 1024;
23
23
  const DEFAULT_ASK_TIMEOUT_MS = 10 * 60 * 1000;
24
24
  const CHANNEL_POLL_MS = Math.min(POLL_INTERVAL_MS, 500);
25
+ const STALE_EMPTY_CHANNEL_AGE_MS = 60 * 1000;
26
+ const STALE_EMPTY_CHANNEL_CLEANUP_INTERVAL_MS = 60 * 1000;
25
27
 
26
28
  type SupervisorReason = "need_decision" | "interview_request" | "progress_update";
27
29
 
@@ -29,6 +31,7 @@ interface SupervisorRequest {
29
31
  type: "subagent.supervisor.request";
30
32
  id: string;
31
33
  createdAt: number;
34
+ expiresAt?: number;
32
35
  reason: SupervisorReason;
33
36
  message: string;
34
37
  expectsReply: boolean;
@@ -203,9 +206,8 @@ function delay(ms: number, signal?: AbortSignal): Promise<void> {
203
206
  });
204
207
  }
205
208
 
206
- async function waitForReply(channelDir: string, requestId: string, signal?: AbortSignal): Promise<SupervisorReply> {
209
+ async function waitForReply(channelDir: string, requestId: string, deadline: number, signal?: AbortSignal): Promise<SupervisorReply> {
207
210
  const file = replyPath(channelDir, requestId);
208
- const deadline = Date.now() + askTimeoutMs();
209
211
  while (Date.now() <= deadline) {
210
212
  if (signal?.aborted) throw new Error("Supervisor request cancelled.");
211
213
  if (fs.existsSync(file)) {
@@ -228,11 +230,15 @@ async function sendSupervisorRequest(params: ContactSupervisorParams, signal?: A
228
230
  ensureSupervisorChannelDir(metadata.channelDir);
229
231
  const requestId = randomUUID();
230
232
  const expectsReply = params.reason !== "progress_update";
233
+ const createdAt = Date.now();
234
+ const replyDeadline = createdAt + askTimeoutMs();
235
+ const expiresAt = expectsReply ? replyDeadline : undefined;
231
236
  const message = formatChildMessage({ ...metadata, reason: params.reason, message: params.message, interview: params.interview });
232
237
  const request: SupervisorRequest = {
233
238
  type: "subagent.supervisor.request",
234
239
  id: requestId,
235
- createdAt: Date.now(),
240
+ createdAt,
241
+ ...(expiresAt !== undefined ? { expiresAt } : {}),
236
242
  reason: params.reason,
237
243
  message,
238
244
  expectsReply,
@@ -255,17 +261,22 @@ async function sendSupervisorRequest(params: ContactSupervisorParams, signal?: A
255
261
  };
256
262
  }
257
263
 
258
- const reply = await waitForReply(metadata.channelDir, requestId, signal);
259
- const details: Record<string, unknown> = { requestId, reason: params.reason };
260
- if (params.reason === "interview_request") {
261
- const structured = parseStructuredReply(reply.message);
262
- if (structured.error) details.structuredReplyParseError = structured.error;
263
- else details.structuredReply = structured.value;
264
+ try {
265
+ const reply = await waitForReply(metadata.channelDir, requestId, replyDeadline, signal);
266
+ const details: Record<string, unknown> = { requestId, reason: params.reason };
267
+ if (params.reason === "interview_request") {
268
+ const structured = parseStructuredReply(reply.message);
269
+ if (structured.error) details.structuredReplyParseError = structured.error;
270
+ else details.structuredReply = structured.value;
271
+ }
272
+ return {
273
+ content: [{ type: "text", text: `**Reply from supervisor:**\n${reply.message}` }],
274
+ details,
275
+ };
276
+ } catch (error) {
277
+ removeRequestFile(requestPath(metadata.channelDir, requestId));
278
+ throw error;
264
279
  }
265
- return {
266
- content: [{ type: "text", text: `**Reply from supervisor:**\n${reply.message}` }],
267
- details,
268
- };
269
280
  }
270
281
 
271
282
  function hasTool(pi: ExtensionAPI, name: string): boolean {
@@ -350,6 +361,77 @@ function listRequestFiles(): Array<{ channelDir: string; file: string }> {
350
361
  return files;
351
362
  }
352
363
 
364
+ function readDirectoryEntries(dir: string): fs.Dirent[] | undefined {
365
+ try {
366
+ return fs.readdirSync(dir, { withFileTypes: true });
367
+ } catch (error) {
368
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return [];
369
+ return undefined;
370
+ }
371
+ }
372
+
373
+ function directoryMtimeMs(dir: string): number {
374
+ try {
375
+ return fs.statSync(dir).mtimeMs;
376
+ } catch {
377
+ return 0;
378
+ }
379
+ }
380
+
381
+ function removeEmptyDirectory(dir: string): boolean {
382
+ try {
383
+ fs.rmdirSync(dir);
384
+ return true;
385
+ } catch (error) {
386
+ const code = (error as NodeJS.ErrnoException).code;
387
+ if (code === "ENOENT") return true;
388
+ if (code === "ENOTEMPTY" || code === "EEXIST" || code === "EPERM" || code === "EBUSY") return false;
389
+ throw error;
390
+ }
391
+ }
392
+
393
+ function removeStaleEmptySupervisorChannel(channelDir: string, nowMs: number): boolean {
394
+ const requestsDir = path.join(channelDir, REQUESTS_DIR);
395
+ const repliesDir = path.join(channelDir, REPLIES_DIR);
396
+ const newestKnownMtimeMs = Math.max(
397
+ directoryMtimeMs(channelDir),
398
+ directoryMtimeMs(requestsDir),
399
+ directoryMtimeMs(repliesDir),
400
+ );
401
+ if (nowMs - newestKnownMtimeMs < STALE_EMPTY_CHANNEL_AGE_MS) return false;
402
+
403
+ const requestEntries = readDirectoryEntries(requestsDir);
404
+ if (!requestEntries || requestEntries.length > 0) return false;
405
+ const replyEntries = readDirectoryEntries(repliesDir);
406
+ if (!replyEntries || replyEntries.length > 0) return false;
407
+
408
+ if (!removeEmptyDirectory(requestsDir)) return false;
409
+ if (!removeEmptyDirectory(repliesDir)) return false;
410
+ if (!removeEmptyDirectory(channelDir)) return false;
411
+ return true;
412
+ }
413
+
414
+ function cleanupStaleEmptySupervisorChannels(nowMs = Date.now()): number {
415
+ let channelEntries: fs.Dirent[];
416
+ try {
417
+ channelEntries = fs.readdirSync(SUPERVISOR_CHANNEL_ROOT, { withFileTypes: true });
418
+ } catch (error) {
419
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return 0;
420
+ throw error;
421
+ }
422
+
423
+ let removed = 0;
424
+ for (const entry of channelEntries) {
425
+ if (!entry.isDirectory()) continue;
426
+ try {
427
+ if (removeStaleEmptySupervisorChannel(path.join(SUPERVISOR_CHANNEL_ROOT, entry.name), nowMs)) removed++;
428
+ } catch {
429
+ // Cleanup is opportunistic; active writers can race with us and will be picked up by a later pass.
430
+ }
431
+ }
432
+ return removed;
433
+ }
434
+
353
435
  function currentContextSessionId(state: Pick<SubagentState, "currentSessionId">, ctx: ExtensionContext): string | undefined {
354
436
  try {
355
437
  const sessionId = ctx.sessionManager.getSessionId();
@@ -365,6 +447,94 @@ function requestMatchesContext(request: SupervisorRequest, state: Pick<SubagentS
365
447
  return Boolean(currentSessionId && request.orchestratorSessionId === currentSessionId);
366
448
  }
367
449
 
450
+ function rememberedForegroundChild(request: SupervisorRequest, state: SubagentState) {
451
+ const run = state.foregroundRuns?.get(request.runId);
452
+ const child = run?.children.find((candidate) => candidate.index === request.childIndex && candidate.agent === request.agent)
453
+ ?? run?.children[request.childIndex];
454
+ return run && child ? { run, child } : undefined;
455
+ }
456
+
457
+ function markForegroundSupervisorAttention(request: SupervisorRequest, state: SubagentState): void {
458
+ const remembered = rememberedForegroundChild(request, state);
459
+ if (!remembered || remembered.child.status !== "detached") return;
460
+ const updatedAt = Date.now();
461
+ remembered.run.updatedAt = updatedAt;
462
+ remembered.child.activityState = "needs_attention";
463
+ remembered.child.lastActivityAt = request.createdAt;
464
+ remembered.child.currentTool = "contact_supervisor";
465
+ remembered.child.currentToolStartedAt = request.createdAt;
466
+ remembered.child.updatedAt = updatedAt;
467
+ }
468
+
469
+ function clearForegroundSupervisorAttention(request: SupervisorRequest, pending: Map<string, PendingSupervisorRequest>, state: SubagentState): void {
470
+ if ([...pending.values()].some((candidate) =>
471
+ candidate.expectsReply
472
+ && candidate.runId === request.runId
473
+ && candidate.agent === request.agent
474
+ && candidate.childIndex === request.childIndex
475
+ )) return;
476
+ const remembered = rememberedForegroundChild(request, state);
477
+ if (!remembered || remembered.child.status !== "detached" || remembered.child.currentTool !== "contact_supervisor") return;
478
+ const updatedAt = Date.now();
479
+ remembered.run.updatedAt = updatedAt;
480
+ remembered.child.activityState = undefined;
481
+ remembered.child.lastActivityAt = updatedAt;
482
+ remembered.child.currentTool = undefined;
483
+ remembered.child.currentToolStartedAt = undefined;
484
+ remembered.child.updatedAt = updatedAt;
485
+ }
486
+
487
+ function removeRequestFile(file: string): void {
488
+ try {
489
+ fs.rmSync(file, { force: true });
490
+ } catch {
491
+ // Request cleanup is best-effort; reply files and timeout errors remain authoritative.
492
+ }
493
+ }
494
+
495
+ type SupervisorRequestLifecycle = "pending" | "resolved" | "expired" | "inactive" | "missing" | "wrong-session";
496
+
497
+ function requestExpiresAt(request: SupervisorRequest, now: number): number {
498
+ const expiresAt = (request as { expiresAt?: unknown }).expiresAt;
499
+ if (typeof expiresAt === "number" && Number.isFinite(expiresAt)) return expiresAt;
500
+ return Number.isFinite(request.createdAt) ? request.createdAt + askTimeoutMs() : now;
501
+ }
502
+
503
+ function requestRunInactive(request: SupervisorRequest, state: SubagentState): boolean {
504
+ if (state.foregroundControls.has(request.runId)) return false;
505
+ const foreground = rememberedForegroundChild(request, state);
506
+ if (foreground) return foreground.child.status !== "detached";
507
+
508
+ const asyncJob = state.asyncJobs.get(request.runId);
509
+ if (!asyncJob) return false;
510
+ if (asyncJob.status === "complete" || asyncJob.status === "failed" || asyncJob.status === "paused") return true;
511
+ const stepStatus = asyncJob.steps?.[request.childIndex]?.status;
512
+ return stepStatus === "complete" || stepStatus === "completed" || stepStatus === "failed" || stepStatus === "paused";
513
+ }
514
+
515
+ function requestLifecycle(request: PendingSupervisorRequest, state: SubagentState, ctx: ExtensionContext | undefined, now: number): SupervisorRequestLifecycle {
516
+ if (ctx && !requestMatchesContext(request, state, ctx)) return "wrong-session";
517
+ if (!fs.existsSync(request.requestFile)) return "missing";
518
+ if (request.expectsReply && fs.existsSync(replyPath(request.channelDir, request.id))) return "resolved";
519
+ if (request.expectsReply && now > requestExpiresAt(request, now)) return "expired";
520
+ if (request.expectsReply && requestRunInactive(request, state)) return "inactive";
521
+ return "pending";
522
+ }
523
+
524
+ function cleanupRequestLifecycle(request: PendingSupervisorRequest, lifecycle: SupervisorRequestLifecycle): void {
525
+ if (lifecycle === "resolved" || lifecycle === "expired" || lifecycle === "inactive") removeRequestFile(request.requestFile);
526
+ }
527
+
528
+ function refreshPendingRequests(pending: Map<string, PendingSupervisorRequest>, state: SubagentState, ctx: ExtensionContext | undefined): void {
529
+ const now = Date.now();
530
+ for (const request of pending.values()) {
531
+ const lifecycle = requestLifecycle(request, state, ctx, now);
532
+ if (lifecycle === "pending") continue;
533
+ pending.delete(request.id);
534
+ cleanupRequestLifecycle(request, lifecycle);
535
+ }
536
+ }
537
+
368
538
  function formatPendingLine(request: PendingSupervisorRequest): string {
369
539
  const replyHint = request.expectsReply ? ` Reply: ${NATIVE_SUPERVISOR_TOOL_NAME}({ action: "reply", replyTo: "${request.id}", message: "..." })` : "";
370
540
  return `- ${request.id}: ${request.agent} [${request.runId}#${request.childIndex}] ${request.reason}.${replyHint}`;
@@ -387,11 +557,7 @@ function writeReply(request: PendingSupervisorRequest, message: string): void {
387
557
  message: message.trim(),
388
558
  };
389
559
  writeAtomicJson(replyPath(request.channelDir, request.id), reply);
390
- try {
391
- fs.rmSync(request.requestFile, { force: true });
392
- } catch {
393
- // Best effort: the reply file is authoritative for the child.
394
- }
560
+ removeRequestFile(request.requestFile);
395
561
  }
396
562
 
397
563
  function resolvePendingRequest(pending: Map<string, PendingSupervisorRequest>, params: IntercomParams): PendingSupervisorRequest {
@@ -427,7 +593,7 @@ function publicPendingRequests(pending: Map<string, PendingSupervisorRequest>):
427
593
  }));
428
594
  }
429
595
 
430
- function buildParentIntercomTool(pending: Map<string, PendingSupervisorRequest>, name = "intercom"): ToolDefinition<typeof IntercomParamsSchema, Record<string, unknown>> {
596
+ function buildParentIntercomTool(pending: Map<string, PendingSupervisorRequest>, state: SubagentState, name = "intercom"): ToolDefinition<typeof IntercomParamsSchema, Record<string, unknown>> {
431
597
  return {
432
598
  name,
433
599
  label: name === "intercom" ? "Intercom" : "Subagent Supervisor",
@@ -436,6 +602,7 @@ function buildParentIntercomTool(pending: Map<string, PendingSupervisorRequest>,
436
602
  : "Native pi-subagents supervisor channel. Use reply/pending/status to answer child subagent requests without overriding pi-intercom.",
437
603
  parameters: IntercomParamsSchema,
438
604
  async execute(_id, params) {
605
+ refreshPendingRequests(pending, state, state.lastUiContext ?? undefined);
439
606
  const input = params as IntercomParams;
440
607
  if (input.action === "status") {
441
608
  return { content: [{ type: "text", text: `Native supervisor channel active. Pending replies: ${pending.size}.` }], details: { active: true, pending: pending.size, root: SUPERVISOR_CHANNEL_ROOT } };
@@ -448,6 +615,7 @@ function buildParentIntercomTool(pending: Map<string, PendingSupervisorRequest>,
448
615
  const request = resolvePendingRequest(pending, input);
449
616
  writeReply(request, input.message ?? "");
450
617
  pending.delete(request.id);
618
+ clearForegroundSupervisorAttention(request, pending, state);
451
619
  return { content: [{ type: "text", text: `Replied to supervisor request ${request.id}.` }], details: { replyTo: request.id, runId: request.runId, agent: request.agent } };
452
620
  }
453
621
  if (input.action === "send" || input.action === "ask") {
@@ -462,27 +630,47 @@ export function createNativeSupervisorChannel(pi: ExtensionAPI, state: SubagentS
462
630
  const pending = new Map<string, PendingSupervisorRequest>();
463
631
  const seenFiles = new Set<string>();
464
632
  let poller: ReturnType<typeof setInterval> | undefined;
633
+ let lastStaleCleanupAt = 0;
465
634
 
466
635
  const registerParentTools = (): void => {
467
- if (!hasTool(pi, NATIVE_SUPERVISOR_TOOL_NAME)) pi.registerTool(buildParentIntercomTool(pending, NATIVE_SUPERVISOR_TOOL_NAME));
468
- if (!hasTool(pi, "intercom")) pi.registerTool(buildParentIntercomTool(pending));
636
+ if (!hasTool(pi, NATIVE_SUPERVISOR_TOOL_NAME)) pi.registerTool(buildParentIntercomTool(pending, state, NATIVE_SUPERVISOR_TOOL_NAME));
637
+ if (!hasTool(pi, "intercom")) pi.registerTool(buildParentIntercomTool(pending, state));
638
+ };
639
+
640
+ const cleanupStaleChannelsIfDue = (): void => {
641
+ const nowMs = Date.now();
642
+ if (nowMs - lastStaleCleanupAt < STALE_EMPTY_CHANNEL_CLEANUP_INTERVAL_MS) return;
643
+ lastStaleCleanupAt = nowMs;
644
+ try {
645
+ cleanupStaleEmptySupervisorChannels(nowMs);
646
+ } catch {
647
+ // Supervisor delivery must not fail because best-effort temp cleanup failed.
648
+ }
469
649
  };
470
650
 
471
651
  const poll = (): void => {
652
+ cleanupStaleChannelsIfDue();
472
653
  const ctx = state.lastUiContext;
473
654
  if (!ctx) return;
655
+ refreshPendingRequests(pending, state, ctx);
656
+ const now = Date.now();
474
657
  for (const { channelDir, file } of listRequestFiles()) {
475
658
  if (seenFiles.has(file)) continue;
476
659
  const request = parseRequestFile(file, channelDir);
477
660
  if (!request || !requestMatchesContext(request, state, ctx)) continue;
661
+ const lifecycle = requestLifecycle(request, state, undefined, now);
662
+ if (lifecycle !== "pending") {
663
+ seenFiles.add(file);
664
+ cleanupRequestLifecycle(request, lifecycle);
665
+ continue;
666
+ }
478
667
  seenFiles.add(file);
479
- if (request.expectsReply) pending.set(request.id, request);
668
+ if (request.expectsReply) {
669
+ pending.set(request.id, request);
670
+ markForegroundSupervisorAttention(request, state);
671
+ }
480
672
  else {
481
- try {
482
- fs.rmSync(request.requestFile, { force: true });
483
- } catch {
484
- // Non-blocking progress updates are already delivered to this session.
485
- }
673
+ removeRequestFile(request.requestFile);
486
674
  }
487
675
  pi.sendMessage({
488
676
  customType: "subagent_supervisor_request",
@@ -496,7 +684,15 @@ export function createNativeSupervisorChannel(pi: ExtensionAPI, state: SubagentS
496
684
  agent: request.agent,
497
685
  childIndex: request.childIndex,
498
686
  },
499
- });
687
+ }, { triggerTurn: true });
688
+ if (request.expectsReply) {
689
+ (pi as { events?: IntercomEventBus }).events?.emit(INTERCOM_DETACH_REQUEST_EVENT, {
690
+ requestId: request.id,
691
+ runId: request.runId,
692
+ agent: request.agent,
693
+ childIndex: request.childIndex,
694
+ });
695
+ }
500
696
  }
501
697
  };
502
698
 
@@ -5,6 +5,7 @@ import {
5
5
  type IntercomEventBus,
6
6
  type NestedRunSummary,
7
7
  type PublicNestedRunSummary,
8
+ type ParallelHandoffReference,
8
9
  type SingleResult,
9
10
  type SubagentResultIntercomChild,
10
11
  type SubagentResultIntercomPayload,
@@ -22,6 +23,7 @@ export function resolveSubagentResultStatus(input: {
22
23
  detached?: boolean;
23
24
  }): SubagentResultStatus {
24
25
  if (input.detached) return "detached";
26
+ if (input.state === "stopped") return "stopped";
25
27
  if (input.interrupted || input.state === "paused") return "paused";
26
28
  if (typeof input.success === "boolean") return input.success ? "completed" : "failed";
27
29
  if (input.state === "complete") return "completed";
@@ -35,6 +37,7 @@ function countStatuses(children: SubagentResultIntercomChild[]): Record<Subagent
35
37
  completed: 0,
36
38
  failed: 0,
37
39
  paused: 0,
40
+ stopped: 0,
38
41
  detached: 0,
39
42
  };
40
43
  for (const child of children) {
@@ -47,6 +50,7 @@ function formatStatusCounts(counts: Record<SubagentResultStatus, number>): strin
47
50
  const parts = [
48
51
  counts.completed ? `${counts.completed} completed` : undefined,
49
52
  counts.failed ? `${counts.failed} failed` : undefined,
53
+ counts.stopped ? `${counts.stopped} stopped` : undefined,
50
54
  counts.paused ? `${counts.paused} paused` : undefined,
51
55
  counts.detached ? `${counts.detached} detached` : undefined,
52
56
  ].filter((part): part is string => Boolean(part));
@@ -56,6 +60,7 @@ function formatStatusCounts(counts: Record<SubagentResultStatus, number>): strin
56
60
  function resolveGroupedStatus(children: SubagentResultIntercomChild[]): SubagentResultStatus {
57
61
  const counts = countStatuses(children);
58
62
  if (counts.failed > 0) return "failed";
63
+ if (counts.stopped > 0) return "stopped";
59
64
  if (counts.paused > 0) return "paused";
60
65
  if (counts.completed > 0) return "completed";
61
66
  if (counts.detached > 0) return "detached";
@@ -175,6 +180,7 @@ interface GroupedResultIntercomMessageInput {
175
180
  asyncId?: string;
176
181
  asyncDir?: string;
177
182
  chainSteps?: number;
183
+ parallelHandoff?: ParallelHandoffReference;
178
184
  }
179
185
 
180
186
  function asyncResumeGuidance(input: {
@@ -203,6 +209,7 @@ function formatSubagentResultIntercomMessage(input: {
203
209
  asyncId?: string;
204
210
  asyncDir?: string;
205
211
  chainSteps?: number;
212
+ parallelHandoff?: ParallelHandoffReference;
206
213
  }): string {
207
214
  const counts = countStatuses(input.children);
208
215
  const lines: string[] = [
@@ -218,6 +225,7 @@ function formatSubagentResultIntercomMessage(input: {
218
225
  }
219
226
  if (input.asyncId) lines.push(`Async id: ${input.asyncId}`);
220
227
  if (input.asyncDir) lines.push(`Async dir: ${input.asyncDir}`);
228
+ if (input.parallelHandoff) lines.push(`Parallel handoff: ${input.parallelHandoff.path}`);
221
229
  const resumeGuidance = asyncResumeGuidance(input);
222
230
  if (resumeGuidance) lines.push(resumeGuidance);
223
231
  if (input.children.some((child) => child.intercomTarget)) {
@@ -262,6 +270,7 @@ export function buildSubagentResultIntercomPayload(input: GroupedResultIntercomM
262
270
  ...(input.asyncId ? { asyncId: input.asyncId } : {}),
263
271
  ...(input.asyncDir ? { asyncDir: input.asyncDir } : {}),
264
272
  ...(typeof input.chainSteps === "number" ? { chainSteps: input.chainSteps } : {}),
273
+ ...(input.parallelHandoff ? { parallelHandoff: input.parallelHandoff } : {}),
265
274
  ...(firstChild?.agent ? { agent: firstChild.agent } : {}),
266
275
  ...(firstChild?.index !== undefined ? { index: firstChild.index } : {}),
267
276
  ...(firstChild?.artifactPath ? { artifactPath: firstChild.artifactPath } : {}),
@@ -348,6 +357,8 @@ export function formatSubagentResultReceipt(input: {
348
357
  `Children: ${formatStatusCounts(counts)}`,
349
358
  ];
350
359
 
360
+ if (input.payload.parallelHandoff) lines.push(`Parallel handoff: ${input.payload.parallelHandoff.path}`);
361
+
351
362
  const artifacts = input.payload.children.filter((child) => typeof child.artifactPath === "string");
352
363
  if (artifacts.length > 0) {
353
364
  lines.push("Artifacts:");
@@ -242,9 +242,9 @@ function qualityTierToRoleTier(quality: QualityTier, cost: CostTier): Recommende
242
242
  }
243
243
 
244
244
  function agentsForRoleTier(roleTier: RecommendedRoleTier): BuiltinAgentName[] {
245
- if (roleTier === "cheap") return ["scout", "delegate"];
246
- if (roleTier === "medium") return ["planner", "context-builder", "researcher"];
247
- return ["worker", "reviewer", "oracle"];
245
+ if (roleTier === "cheap") return ["explorer", "recapper"];
246
+ if (roleTier === "medium") return ["architect", "researcher"];
247
+ return ["builder", "commentator"];
248
248
  }
249
249
 
250
250
  function classifyModel(input: ModelClassificationInput, context: ClassificationContext): {
@@ -386,14 +386,12 @@ function buildProfileFile(kind: ProfileKind, models: { cheap: string; medium: st
386
386
  return {
387
387
  subagents: {
388
388
  agentOverrides: {
389
- scout: { model: models.cheap },
390
- delegate: { model: models.cheap },
391
- planner: { model: models.medium },
392
- "context-builder": { model: models.medium },
389
+ explorer: { model: models.cheap },
390
+ recapper: { model: models.cheap },
391
+ architect: { model: models.medium },
393
392
  researcher: { model: models.medium },
394
- worker: { model: models.strong },
395
- reviewer: { model: models.strong },
396
- oracle: { model: models.strong },
393
+ builder: { model: models.strong },
394
+ commentator: { model: models.strong },
397
395
  },
398
396
  },
399
397
  };