@selesai/code 0.5.28 → 0.5.29

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 (307) hide show
  1. package/dist/cli/args.d.ts.map +1 -1
  2. package/dist/cli/args.js +9 -1
  3. package/dist/cli/args.js.map +1 -1
  4. package/dist/cli/config-selector.d.ts.map +1 -1
  5. package/dist/cli/config-selector.js +1 -1
  6. package/dist/cli/config-selector.js.map +1 -1
  7. package/dist/cli/credential-print.d.ts +23 -0
  8. package/dist/cli/credential-print.d.ts.map +1 -0
  9. package/dist/cli/credential-print.js +117 -0
  10. package/dist/cli/credential-print.js.map +1 -0
  11. package/dist/cli/startup-ui.d.ts.map +1 -1
  12. package/dist/cli/startup-ui.js +1 -1
  13. package/dist/cli/startup-ui.js.map +1 -1
  14. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  15. package/dist/core/agent-session-runtime.js +3 -0
  16. package/dist/core/agent-session-runtime.js.map +1 -1
  17. package/dist/core/agent-session.d.ts +12 -1
  18. package/dist/core/agent-session.d.ts.map +1 -1
  19. package/dist/core/agent-session.js +20 -14
  20. package/dist/core/agent-session.js.map +1 -1
  21. package/dist/core/compaction/compaction.d.ts.map +1 -1
  22. package/dist/core/compaction/compaction.js +11 -3
  23. package/dist/core/compaction/compaction.js.map +1 -1
  24. package/dist/core/extensions/runner.d.ts +1 -0
  25. package/dist/core/extensions/runner.d.ts.map +1 -1
  26. package/dist/core/extensions/runner.js +11 -0
  27. package/dist/core/extensions/runner.js.map +1 -1
  28. package/dist/core/extensions/types.d.ts +14 -1
  29. package/dist/core/extensions/types.d.ts.map +1 -1
  30. package/dist/core/extensions/types.js.map +1 -1
  31. package/dist/core/footer-data-provider.d.ts +10 -0
  32. package/dist/core/footer-data-provider.d.ts.map +1 -1
  33. package/dist/core/footer-data-provider.js +1 -1
  34. package/dist/core/footer-data-provider.js.map +1 -1
  35. package/dist/core/llama/provider.d.ts.map +1 -1
  36. package/dist/core/llama/provider.js +8 -3
  37. package/dist/core/llama/provider.js.map +1 -1
  38. package/dist/core/model-config.d.ts +30 -0
  39. package/dist/core/model-config.d.ts.map +1 -1
  40. package/dist/core/model-config.js +6 -0
  41. package/dist/core/model-config.js.map +1 -1
  42. package/dist/core/model-registry.d.ts.map +1 -1
  43. package/dist/core/model-registry.js +2 -2
  44. package/dist/core/model-registry.js.map +1 -1
  45. package/dist/core/model-resolver.d.ts +1 -0
  46. package/dist/core/model-resolver.d.ts.map +1 -1
  47. package/dist/core/model-resolver.js +20 -3
  48. package/dist/core/model-resolver.js.map +1 -1
  49. package/dist/core/model-runtime.d.ts +2 -0
  50. package/dist/core/model-runtime.d.ts.map +1 -1
  51. package/dist/core/model-runtime.js +5 -4
  52. package/dist/core/model-runtime.js.map +1 -1
  53. package/dist/core/package-manager.d.ts.map +1 -1
  54. package/dist/core/package-manager.js +13 -6
  55. package/dist/core/package-manager.js.map +1 -1
  56. package/dist/core/remote-catalog-provider.d.ts +1 -1
  57. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  58. package/dist/core/remote-catalog-provider.js +24 -11
  59. package/dist/core/remote-catalog-provider.js.map +1 -1
  60. package/dist/core/resource-loader.d.ts +15 -0
  61. package/dist/core/resource-loader.d.ts.map +1 -1
  62. package/dist/core/resource-loader.js +66 -9
  63. package/dist/core/resource-loader.js.map +1 -1
  64. package/dist/core/settings-manager.d.ts +1 -1
  65. package/dist/core/settings-manager.d.ts.map +1 -1
  66. package/dist/core/settings-manager.js.map +1 -1
  67. package/dist/core/system-prompt.d.ts.map +1 -1
  68. package/dist/core/system-prompt.js +1 -1
  69. package/dist/core/system-prompt.js.map +1 -1
  70. package/dist/core/tools/bash.d.ts +2 -0
  71. package/dist/core/tools/bash.d.ts.map +1 -1
  72. package/dist/core/tools/bash.js +34 -5
  73. package/dist/core/tools/bash.js.map +1 -1
  74. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  75. package/dist/core/tools/tool-definition-wrapper.js +3 -1
  76. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  77. package/dist/extensions/pi-intercom/CHANGELOG.md +249 -0
  78. package/dist/extensions/pi-intercom/README.md +102 -39
  79. package/dist/extensions/pi-intercom/broker/broker.ts +1233 -36
  80. package/dist/extensions/pi-intercom/broker/client.test.ts +83 -0
  81. package/dist/extensions/pi-intercom/broker/client.ts +315 -12
  82. package/dist/extensions/pi-intercom/broker/extension-state.ts +186 -0
  83. package/dist/extensions/pi-intercom/broker/extension.test.ts +387 -0
  84. package/dist/extensions/pi-intercom/broker/framing.test.ts +114 -0
  85. package/dist/extensions/pi-intercom/broker/framing.ts +82 -24
  86. package/dist/extensions/pi-intercom/broker/paths.test.ts +153 -0
  87. package/dist/extensions/pi-intercom/broker/paths.ts +117 -8
  88. package/dist/extensions/pi-intercom/broker/runtime-claim.test.ts +34 -0
  89. package/dist/extensions/pi-intercom/broker/runtime-claim.ts +21 -0
  90. package/dist/extensions/pi-intercom/broker/spawn.test.ts +160 -23
  91. package/dist/extensions/pi-intercom/broker/spawn.ts +113 -27
  92. package/dist/extensions/pi-intercom/config.test.ts +93 -0
  93. package/dist/extensions/pi-intercom/config.ts +55 -6
  94. package/dist/extensions/pi-intercom/cwd.test.ts +40 -0
  95. package/dist/extensions/pi-intercom/cwd.ts +31 -0
  96. package/dist/extensions/pi-intercom/extension-api.ts +44 -0
  97. package/dist/extensions/pi-intercom/format-context.test.ts +31 -0
  98. package/dist/extensions/pi-intercom/format-context.ts +32 -0
  99. package/dist/extensions/pi-intercom/index.ts +742 -145
  100. package/dist/extensions/pi-intercom/intercom.integration.test.ts +2646 -0
  101. package/dist/extensions/pi-intercom/package.json +15 -5
  102. package/dist/extensions/pi-intercom/reply-tracker.test.ts +134 -0
  103. package/dist/extensions/pi-intercom/reply-tracker.ts +31 -13
  104. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +13 -11
  105. package/dist/extensions/pi-intercom/test/inline-message.test.ts +184 -0
  106. package/dist/extensions/pi-intercom/test/overlay-width.test.ts +66 -0
  107. package/dist/extensions/pi-intercom/types.ts +94 -4
  108. package/dist/extensions/pi-intercom/ui/compose.ts +8 -4
  109. package/dist/extensions/pi-intercom/ui/inline-message.ts +61 -25
  110. package/dist/extensions/pi-intercom/ui/session-list.ts +7 -3
  111. package/dist/extensions/pi-subagents/CHANGELOG.md +85 -0
  112. package/dist/extensions/pi-subagents/LICENSE +21 -0
  113. package/dist/extensions/pi-subagents/README.md +146 -52
  114. package/dist/extensions/pi-subagents/agents/architect.md +1 -0
  115. package/dist/extensions/pi-subagents/agents/builder.md +1 -0
  116. package/dist/extensions/pi-subagents/package-lock.json +2 -2
  117. package/dist/extensions/pi-subagents/package.json +3 -3
  118. package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
  119. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +21 -989
  120. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +256 -0
  121. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +430 -0
  122. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +144 -0
  123. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +282 -0
  124. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +71 -30
  125. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +4 -0
  126. package/dist/extensions/pi-subagents/src/agents/agents.ts +118 -9
  127. package/dist/extensions/pi-subagents/src/agents/skills.ts +14 -12
  128. package/dist/extensions/pi-subagents/src/api/delegation.ts +3 -0
  129. package/dist/extensions/pi-subagents/src/api/preflight.ts +16 -12
  130. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +17 -1
  131. package/dist/extensions/pi-subagents/src/extension/index.ts +17 -7
  132. package/dist/extensions/pi-subagents/src/extension/rpc.ts +248 -6
  133. package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -6
  134. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +8 -7
  135. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +9 -4
  136. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +33 -4
  137. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +63 -16
  138. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +24 -13
  139. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +7 -5
  140. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -2
  141. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +48 -5
  142. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +68 -1
  143. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +29 -4
  144. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +29 -6
  145. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +29 -3
  146. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +372 -28
  147. package/dist/extensions/pi-subagents/src/runs/foreground/async-stop-action.ts +65 -0
  148. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +3 -3
  149. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +143 -43
  150. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +527 -247
  151. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +42 -0
  152. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +426 -123
  153. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +15 -7
  154. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +51 -19
  155. package/dist/extensions/pi-subagents/src/runs/shared/chain-outputs.ts +3 -1
  156. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
  157. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +44 -11
  158. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +8 -0
  159. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +97 -20
  160. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +43 -12
  161. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +52 -4
  162. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +19 -0
  163. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +45 -9
  164. package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +71 -0
  165. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +31 -1
  166. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +101 -0
  167. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +1 -1
  168. package/dist/extensions/pi-subagents/src/runs/shared/usage-budget.ts +65 -0
  169. package/dist/extensions/pi-subagents/src/runs/shared/workflow-graph.ts +26 -1
  170. package/dist/extensions/pi-subagents/src/shared/settings.ts +17 -1
  171. package/dist/extensions/pi-subagents/src/shared/types.ts +155 -10
  172. package/dist/extensions/pi-subagents/src/shared/utils.ts +73 -4
  173. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +5 -0
  174. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +46 -4
  175. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +5 -3
  176. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +87 -24
  177. package/dist/extensions/pi-subagents/src/tui/fleet.ts +182 -9
  178. package/dist/extensions/pi-subagents/src/tui/render.ts +27 -28
  179. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +14 -7
  180. package/dist/extensions/pi-subagents/src/watchdog/review.ts +5 -4
  181. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +170 -17
  182. package/dist/extensions/pi-subagents/src/watchdog/scope.ts +62 -0
  183. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +41 -1
  184. package/dist/extensions/pi-subagents/src/watchdog/types.ts +10 -0
  185. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
  186. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +348 -7
  187. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +84 -0
  188. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +4 -2
  189. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +51 -2
  190. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +26 -1
  191. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +48 -0
  192. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +3 -3
  193. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +213 -13
  194. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +34 -0
  195. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +44 -0
  196. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +118 -12
  197. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +850 -7
  198. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +112 -23
  199. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +17 -5
  200. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +2 -0
  201. package/dist/extensions/pi-subagents/test/support/register-loader.mjs +3 -3
  202. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +3 -1
  203. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +128 -0
  204. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +47 -2
  205. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +60 -0
  206. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +8 -0
  207. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +102 -0
  208. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +1 -1
  209. package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +6 -0
  210. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +1 -1
  211. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +48 -48
  212. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +23 -0
  213. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +27 -0
  214. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +4 -2
  215. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +1 -0
  216. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +176 -8
  217. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +164 -5
  218. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +41 -1
  219. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +11 -11
  220. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +18 -2
  221. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -1
  222. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +30 -2
  223. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +10 -2
  224. package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +22 -0
  225. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +103 -0
  226. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +18 -0
  227. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +46 -0
  228. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +13 -1
  229. package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +29 -4
  230. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +223 -4
  231. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +30 -0
  232. package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +52 -0
  233. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +34 -2
  234. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  235. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +1 -1
  236. package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +78 -0
  237. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +41 -0
  238. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +77 -0
  239. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +3 -0
  240. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +1 -1
  241. package/dist/extensions/pi-subagents/test/unit/total-cost.test.ts +1 -0
  242. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +210 -1
  243. package/dist/extensions/pi-subagents/test/unit/watchdog-scope.test.ts +33 -0
  244. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +32 -0
  245. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +1 -1
  246. package/dist/main.d.ts.map +1 -1
  247. package/dist/main.js +43 -0
  248. package/dist/main.js.map +1 -1
  249. package/dist/modes/interactive/components/custom-message.d.ts +3 -1
  250. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  251. package/dist/modes/interactive/components/custom-message.js +10 -2
  252. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  253. package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
  254. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  255. package/dist/modes/interactive/components/extension-editor.js +16 -46
  256. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  257. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  258. package/dist/modes/interactive/components/model-selector.js +4 -1
  259. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  260. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  261. package/dist/modes/interactive/components/scoped-models-selector.js +22 -13
  262. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  263. package/dist/modes/interactive/external-editor.d.ts +12 -0
  264. package/dist/modes/interactive/external-editor.d.ts.map +1 -0
  265. package/dist/modes/interactive/external-editor.js +37 -0
  266. package/dist/modes/interactive/external-editor.js.map +1 -0
  267. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  268. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  269. package/dist/modes/interactive/interactive-mode.js +72 -64
  270. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  271. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  272. package/dist/modes/rpc/rpc-mode.js +14 -0
  273. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  274. package/dist/utils/clipboard.d.ts.map +1 -1
  275. package/dist/utils/clipboard.js +19 -8
  276. package/dist/utils/clipboard.js.map +1 -1
  277. package/dist/utils/version-check.d.ts.map +1 -1
  278. package/dist/utils/version-check.js +1 -1
  279. package/dist/utils/version-check.js.map +1 -1
  280. package/docs/compaction.md +1 -1
  281. package/docs/custom-provider.md +14 -5
  282. package/docs/environment-variables.md +86 -0
  283. package/docs/extensions.md +15 -5
  284. package/docs/index.md +1 -0
  285. package/docs/models.md +9 -2
  286. package/docs/providers.md +21 -2
  287. package/docs/rpc.md +23 -6
  288. package/docs/session-format.md +2 -0
  289. package/docs/settings.md +1 -1
  290. package/docs/usage.md +0 -13
  291. package/examples/extensions/custom-compaction.ts +5 -2
  292. package/examples/extensions/custom-provider-anthropic/index.ts +9 -3
  293. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  294. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  295. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  296. package/examples/extensions/gondolin/package-lock.json +2 -2
  297. package/examples/extensions/gondolin/package.json +1 -1
  298. package/examples/extensions/handoff.ts +11 -3
  299. package/examples/extensions/message-renderer.ts +3 -3
  300. package/examples/extensions/sandbox/package-lock.json +2 -2
  301. package/examples/extensions/sandbox/package.json +1 -1
  302. package/examples/extensions/summarize.ts +5 -2
  303. package/examples/extensions/with-deps/package-lock.json +2 -2
  304. package/examples/extensions/with-deps/package.json +1 -1
  305. package/examples/sdk/12-full-control.ts +3 -1
  306. package/package.json +15 -6
  307. package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
@@ -0,0 +1,65 @@
1
+ import * as path from "node:path";
2
+ import type { AgentToolResult } from "@earendil-works/pi-agent-core";
3
+ import type { Details, SubagentState } from "../../shared/types.ts";
4
+ import { deliverStopRequest } from "../background/control-channel.ts";
5
+ import { reconcileAsyncRun } from "../background/stale-run-reconciler.ts";
6
+
7
+ function getAsyncStopTarget(
8
+ state: SubagentState,
9
+ runId: string | undefined,
10
+ location?: { asyncDir: string | null; resolvedId?: string },
11
+ ): { asyncId: string; asyncDir: string } | undefined {
12
+ if (location?.asyncDir) {
13
+ return {
14
+ asyncId: location.resolvedId ?? runId ?? path.basename(location.asyncDir),
15
+ asyncDir: location.asyncDir,
16
+ };
17
+ }
18
+ if (!runId) return undefined;
19
+ const direct = state.asyncJobs.get(runId);
20
+ return direct ? { asyncId: direct.asyncId, asyncDir: direct.asyncDir } : undefined;
21
+ }
22
+
23
+ export function stopAsyncRun(
24
+ state: SubagentState,
25
+ runId: string | undefined,
26
+ kill?: (pid: number, signal?: NodeJS.Signals | 0) => boolean,
27
+ location?: { asyncDir: string | null; resolvedId?: string },
28
+ ): AgentToolResult<Details> | null {
29
+ const target = getAsyncStopTarget(state, runId, location);
30
+ if (!target) return null;
31
+ const status = reconcileAsyncRun(target.asyncDir, { kill }).status;
32
+ if (state.currentSessionId && status?.sessionId !== state.currentSessionId) {
33
+ return {
34
+ content: [{ type: "text", text: `Async run '${target.asyncId}' was not found in the active session.` }],
35
+ isError: true,
36
+ details: { mode: "management", results: [] },
37
+ };
38
+ }
39
+ if (!status || (status.state !== "running" && status.state !== "queued")) {
40
+ return {
41
+ content: [{ type: "text", text: `No running or queued async run was found for '${runId ?? "current"}'.` }],
42
+ isError: true,
43
+ details: { mode: "management", results: [] },
44
+ };
45
+ }
46
+ try {
47
+ deliverStopRequest({ asyncDir: target.asyncDir, pid: typeof status.pid === "number" ? status.pid : undefined, kill, source: "stop-action" });
48
+ const tracked = state.asyncJobs.get(target.asyncId);
49
+ if (tracked) {
50
+ tracked.activityState = undefined;
51
+ tracked.updatedAt = Date.now();
52
+ }
53
+ return {
54
+ content: [{ type: "text", text: `Stop requested for async run ${target.asyncId}.` }],
55
+ details: { mode: "management", results: [] },
56
+ };
57
+ } catch (error) {
58
+ const message = error instanceof Error ? error.message : String(error);
59
+ return {
60
+ content: [{ type: "text", text: `Failed to stop async run ${target.asyncId}: ${message}` }],
61
+ isError: true,
62
+ details: { mode: "management", results: [] },
63
+ };
64
+ }
65
+ }
@@ -451,13 +451,13 @@ export class ChainClarifyComponent implements Component {
451
451
  return;
452
452
  }
453
453
 
454
- if (matchesKey(data, "up")) {
454
+ if (matchesKey(data, "up") || matchesKey(data, "k")) {
455
455
  this.selectedStep = Math.max(0, this.selectedStep - 1);
456
456
  this.tui.requestRender();
457
457
  return;
458
458
  }
459
459
 
460
- if (matchesKey(data, "down")) {
460
+ if (matchesKey(data, "down") || matchesKey(data, "j")) {
461
461
  const maxStep = Math.max(0, this.agentConfigs.length - 1);
462
462
  this.selectedStep = Math.min(maxStep, this.selectedStep + 1);
463
463
  this.tui.requestRender();
@@ -1123,7 +1123,7 @@ export class ChainClarifyComponent implements Component {
1123
1123
  private getFooterText(): string {
1124
1124
  return this.mode === 'single'
1125
1125
  ? " [Enter] Run • [Esc] Cancel "
1126
- : " [Enter] Run • [Esc] Cancel • [↑↓] Navigate ";
1126
+ : " [Enter] Run • [Esc] Cancel • [↑↓/jk] Navigate ";
1127
1127
  }
1128
1128
 
1129
1129
  private appendNotice(lines: string[]): void {
@@ -8,7 +8,7 @@ import type { AgentToolResult } from "@earendil-works/pi-agent-core";
8
8
  import type { ExtensionContext } from "@selesai/code";
9
9
  import type { AgentConfig } from "../../agents/agents.ts";
10
10
  import { ChainClarifyComponent, type ChainClarifyResult, type BehaviorOverride } from "./chain-clarify.ts";
11
- import { toModelInfo, type ModelInfo } from "../../shared/model-info.ts";
11
+ import { resolveEffectiveThinking, toModelInfo, type ModelInfo } from "../../shared/model-info.ts";
12
12
  import {
13
13
  resolveChainTemplates,
14
14
  createChainDir,
@@ -20,6 +20,7 @@ import {
20
20
  createParallelDirs,
21
21
  suppressProgressForReadOnlyTask,
22
22
  aggregateParallelOutputs,
23
+ isCheckpointStep,
23
24
  isDynamicParallelStep,
24
25
  isParallelStep,
25
26
  type StepOverrides,
@@ -33,7 +34,13 @@ import {
33
34
  import { discoverAvailableSkills, normalizeSkillInput } from "../../agents/skills.ts";
34
35
  import { INTERCOM_BRIDGE_MARKER } from "../../intercom/intercom-bridge.ts";
35
36
  import { runSync } from "./execution.ts";
36
- import { beginForegroundChild, finishForegroundChild, updateForegroundChild } from "./foreground-control.ts";
37
+ import {
38
+ beginForegroundChild,
39
+ finishForegroundChild,
40
+ retainForegroundSchedulingOwner,
41
+ settleForegroundSchedulingOwner,
42
+ updateForegroundChild,
43
+ } from "./foreground-control.ts";
37
44
  import { buildChainSummary } from "../../shared/formatters.ts";
38
45
  import { compactForegroundDetails, getSingleResultOutput, mapConcurrent, resolveChildCwd, sumResultsCost, sumResultsUsage } from "../../shared/utils.ts";
39
46
  import { DEFAULT_GLOBAL_CONCURRENCY_LIMIT, Semaphore } from "../shared/parallel-utils.ts";
@@ -64,6 +71,8 @@ import {
64
71
  type ResolvedToolBudget,
65
72
  type SingleResult,
66
73
  type ToolBudgetConfig,
74
+ type ChainCheckpointState,
75
+ type UsageBudgetConfig,
67
76
  MAX_CONCURRENCY,
68
77
  resolveChildMaxSubagentDepth,
69
78
  } from "../../shared/types.ts";
@@ -78,6 +87,7 @@ import { acceptanceFailureMessage, aggregateAcceptanceReport, evaluateAcceptance
78
87
  import { isAgentContractV1 } from "../shared/agent-contract.ts";
79
88
  import type { ChainOutputMap } from "../../shared/types.ts";
80
89
  import { validateToolBudgetConfig } from "../shared/tool-budget.ts";
90
+ import { usageBudgetExceededMessage, usageBudgetState } from "../shared/usage-budget.ts";
81
91
  import type { ContextMode } from "../shared/context-mode.ts";
82
92
  import type { ResolvedSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
83
93
 
@@ -97,6 +107,8 @@ interface ChainExecutionDetailsInput {
97
107
  dynamicChildren?: Record<number, Array<{ agent: string; label?: string; flatIndex: number; itemKey: string; outputName?: string; structured?: boolean; error?: string }>>;
98
108
  dynamicGroupStatuses?: Record<number, { status: "pending" | "running" | "completed" | "failed" | "paused" | "stopped" | "detached"; error?: string; acceptance?: SingleResult["acceptance"] }>;
99
109
  parallelHandoff?: Details["parallelHandoff"];
110
+ checkpoint?: ChainCheckpointState;
111
+ usageBudget?: UsageBudgetConfig;
100
112
  }
101
113
 
102
114
  interface ParallelChainRunInput {
@@ -145,7 +157,10 @@ interface ParallelChainRunInput {
145
157
  timeoutMs?: number;
146
158
  deadlineAt?: number;
147
159
  turnBudget?: ResolvedTurnBudget;
160
+ usageBudget?: UsageBudgetConfig;
148
161
  onDetachedExit?: (index: number, result: SingleResult) => void;
162
+ /** Called after an attached child releases its foreground ownership. */
163
+ onForegroundChildSettled?: () => void;
149
164
  toolBudget?: ResolvedToolBudget;
150
165
  configToolBudget?: ToolBudgetConfig;
151
166
  globalSemaphore?: Semaphore;
@@ -165,6 +180,8 @@ function buildChainExecutionDetails(input: ChainExecutionDetailsInput): Details
165
180
  outputs: input.outputs,
166
181
  totalChildUsage: sumResultsUsage(input.results),
167
182
  totalCost: sumResultsCost(input.results),
183
+ usageBudget: usageBudgetState(input.usageBudget, sumResultsCost(input.results)),
184
+ ...(input.checkpoint ? { checkpoint: input.checkpoint } : {}),
168
185
  ...(input.parallelHandoff ? { parallelHandoff: input.parallelHandoff } : {}),
169
186
  workflowGraph: buildWorkflowGraphSnapshot({
170
187
  runId: input.runId,
@@ -277,12 +294,29 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
277
294
  input.sessionFileForTask?.(task.agent, input.globalTaskIndex + taskIndex, effectiveModels[taskIndex]);
278
295
  }
279
296
 
297
+ const completedResults: SingleResult[] = [];
298
+ if (input.foregroundControl) retainForegroundSchedulingOwner(input.foregroundControl);
280
299
  const parallelResults = await mapConcurrent(
281
300
  input.step.parallel,
282
301
  concurrency,
283
302
  async (task, taskIndex) => {
303
+ const childIndex = input.globalTaskIndex + taskIndex;
304
+ const budgetState = usageBudgetState(input.usageBudget, sumResultsCost(input.results.concat(completedResults)));
305
+ if (budgetState?.exhausted) {
306
+ return {
307
+ index: childIndex,
308
+ agent: task.agent,
309
+ task: input.parallelTemplates[taskIndex] ?? "(skipped)",
310
+ exitCode: 1,
311
+ messages: [],
312
+ usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 },
313
+ error: usageBudgetExceededMessage(budgetState),
314
+ skipped: true,
315
+ } as SingleResult;
316
+ }
284
317
  if (aborted && failFast) {
285
318
  return {
319
+ index: childIndex,
286
320
  agent: task.agent,
287
321
  task: "(skipped)",
288
322
  exitCode: -1,
@@ -324,12 +358,14 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
324
358
  : undefined;
325
359
  taskStr = injectSingleOutputInstruction(taskStr, outputPath, taskAgentConfig);
326
360
  const interruptController = new AbortController();
327
- const childIndex = input.globalTaskIndex + taskIndex;
328
361
  if (input.foregroundControl) {
362
+ const thinking = resolveEffectiveThinking(effectiveModel, input.thinkingOverrideForTask?.(task.agent, childIndex, effectiveModel));
329
363
  beginForegroundChild(input.foregroundControl, {
330
364
  index: childIndex,
331
365
  agent: task.agent,
332
366
  description: cleanTask.trim(),
367
+ ...(effectiveModel ? { model: effectiveModel } : {}),
368
+ ...(thinking ? { thinking } : {}),
333
369
  interrupt: () => {
334
370
  if (interruptController.signal.aborted) return false;
335
371
  interruptController.abort();
@@ -342,7 +378,9 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
342
378
  ? createStructuredOutputRuntime(task.outputSchema, path.join(input.chainDir, "structured-output"))
343
379
  : undefined;
344
380
  const agentContract = task.agentContract ?? input.step.agentContract ?? input.agentContract;
345
- const result = await runSync(input.ctx.cwd, input.agents, task.agent, taskStr, {
381
+ let result!: SingleResult;
382
+ try {
383
+ result = await runSync(input.ctx.cwd, input.agents, task.agent, taskStr, {
346
384
  parentSessionId: input.ctx.sessionManager.getSessionId() ?? undefined,
347
385
  capabilityCeiling: input.capabilityCeiling,
348
386
  context: input.contextForAgent?.(task.agent),
@@ -380,9 +418,13 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
380
418
  timeoutMs: input.timeoutMs,
381
419
  deadlineAt: input.deadlineAt,
382
420
  turnBudget: input.turnBudget,
383
- onDetachedExit: input.onDetachedExit
384
- ? (result) => input.onDetachedExit?.(childIndex, result)
385
- : undefined,
421
+ onDetachedExit: (result) => {
422
+ try {
423
+ if (input.foregroundControl) finishForegroundChild(input.foregroundControl, childIndex);
424
+ } finally {
425
+ input.onDetachedExit?.(childIndex, result);
426
+ }
427
+ },
386
428
  toolBudget: toolBudget.toolBudget,
387
429
  onUpdate: input.onUpdate
388
430
  ? (progressUpdate) => {
@@ -416,16 +458,28 @@ async function runParallelChainTasks(input: ParallelChainRunInput): Promise<Sing
416
458
  });
417
459
  }
418
460
  : undefined,
419
- });
420
- if (input.foregroundControl) finishForegroundChild(input.foregroundControl, childIndex);
461
+ });
462
+ } finally {
463
+ // Rejected attached attempts still release their parallel child control;
464
+ // detached receipts transfer ownership to onDetachedExit.
465
+ if (!result?.detached) {
466
+ if (input.foregroundControl) finishForegroundChild(input.foregroundControl, childIndex);
467
+ input.onForegroundChildSettled?.();
468
+ }
469
+ }
421
470
 
422
471
  if (result.exitCode !== 0 && failFast) {
423
472
  aborted = true;
424
473
  }
425
474
  recordRun(task.agent, cleanTask, result.exitCode, result.progressSummary?.durationMs ?? 0);
475
+ completedResults.push(result);
426
476
  return result;
427
477
  },
428
478
  input.globalSemaphore,
479
+ () => {
480
+ if (input.foregroundControl) settleForegroundSchedulingOwner(input.foregroundControl);
481
+ input.onForegroundChildSettled?.();
482
+ },
429
483
  );
430
484
 
431
485
  return parallelResults;
@@ -470,7 +524,10 @@ interface ChainExecutionParams {
470
524
  deadlineAt?: number;
471
525
  turnBudget?: ResolvedTurnBudget;
472
526
  onDetachedExit?: (index: number, result: SingleResult) => void;
527
+ /** Ownership callback used when parallel siblings outlive executeChain rejection. */
528
+ onForegroundChildSettled?: () => void;
473
529
  toolBudget?: ResolvedToolBudget;
530
+ usageBudget?: UsageBudgetConfig;
474
531
  configToolBudget?: ToolBudgetConfig;
475
532
  /** Global cap on simultaneously-running tasks within this chain. Defaults to DEFAULT_GLOBAL_CONCURRENCY_LIMIT. */
476
533
  globalConcurrencyLimit?: number;
@@ -531,7 +588,9 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
531
588
  let parallelHandoff: Details["parallelHandoff"];
532
589
 
533
590
  const chainAgents: string[] = chainSteps.map((step) =>
534
- isParallelStep(step)
591
+ isCheckpointStep(step)
592
+ ? `checkpoint:${step.checkpoint}`
593
+ : isParallelStep(step)
535
594
  ? `[${step.parallel.map((t) => t.agent).join("+")}]`
536
595
  : isDynamicParallelStep(step)
537
596
  ? `expand:${step.parallel.agent}`
@@ -539,7 +598,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
539
598
  );
540
599
  const totalSteps = chainSteps.length;
541
600
 
542
- const makeDetailsInput = (overrides: Pick<Partial<ChainExecutionDetailsInput>, "currentStepIndex" | "currentFlatIndex"> = {}): ChainExecutionDetailsInput => ({
601
+ const makeDetailsInput = (overrides: Pick<Partial<ChainExecutionDetailsInput>, "currentStepIndex" | "currentFlatIndex" | "checkpoint"> = {}): ChainExecutionDetailsInput => ({
543
602
  results,
544
603
  ...(includeProgress !== undefined ? { includeProgress } : {}),
545
604
  allProgress,
@@ -553,16 +612,25 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
553
612
  dynamicChildren,
554
613
  dynamicGroupStatuses,
555
614
  ...(parallelHandoff ? { parallelHandoff } : {}),
615
+ usageBudget: params.usageBudget,
556
616
  ...overrides,
557
617
  });
558
618
 
619
+ const usageBudgetError = (stepIndex: number, flatIndex: number): ChainExecutionResult | undefined => {
620
+ const state = usageBudgetState(params.usageBudget, sumResultsCost(results));
621
+ if (!state?.exhausted) return undefined;
622
+ return buildChainExecutionErrorResult(usageBudgetExceededMessage(state), makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: flatIndex }));
623
+ };
624
+
559
625
  const firstStep = chainSteps[0]!;
560
626
  const originalTask = params.task
561
- ?? (isParallelStep(firstStep)
562
- ? firstStep.parallel[0]!.task!
563
- : isDynamicParallelStep(firstStep)
564
- ? firstStep.parallel.task!
565
- : (firstStep as SequentialStep).task!);
627
+ ?? (isCheckpointStep(firstStep)
628
+ ? undefined
629
+ : isParallelStep(firstStep)
630
+ ? firstStep.parallel[0]!.task!
631
+ : isDynamicParallelStep(firstStep)
632
+ ? firstStep.parallel.task!
633
+ : (firstStep as SequentialStep).task!);
566
634
  try {
567
635
  validateChainOutputBindings(chainSteps, { maxItems: params.dynamicFanoutMaxItems });
568
636
  } catch (error) {
@@ -577,7 +645,7 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
577
645
  }
578
646
 
579
647
  const chainDir = createChainDir(runId, chainDirBase);
580
- const hasParallelSteps = chainSteps.some((step) => isParallelStep(step) || isDynamicParallelStep(step));
648
+ const hasParallelSteps = chainSteps.some((step) => isParallelStep(step) || isDynamicParallelStep(step) || isCheckpointStep(step));
581
649
  let templates: ResolvedTemplates = resolveChainTemplates(chainSteps);
582
650
  const shouldClarify = clarify === true && ctx.hasUI && !hasParallelSteps;
583
651
  let tuiBehaviorOverrides: (BehaviorOverride | undefined)[] | undefined;
@@ -677,9 +745,21 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
677
745
  let progressCreated = false;
678
746
 
679
747
  for (let stepIndex = 0; stepIndex < chainSteps.length; stepIndex++) {
748
+ const budgetError = usageBudgetError(stepIndex, globalTaskIndex);
749
+ if (budgetError) return budgetError;
680
750
  const step = chainSteps[stepIndex]!;
681
751
  const stepTemplates = templates[stepIndex]!;
682
752
 
753
+ if (isCheckpointStep(step)) {
754
+ const checkpoint = { name: step.checkpoint, ...(step.message ? { message: step.message } : {}), status: "pending" as const, stepIndex };
755
+ return {
756
+ content: [{ type: "text", text: `Chain paused at checkpoint '${step.checkpoint}'. Approve with subagent({ action: "approve-checkpoint", id: "${runId}" }) or reject with subagent({ action: "reject-checkpoint", id: "${runId}" }).${step.message ? `
757
+
758
+ ${step.message}` : ""}` }],
759
+ details: buildChainExecutionDetails(makeDetailsInput({ currentStepIndex: stepIndex, currentFlatIndex: globalTaskIndex, checkpoint })),
760
+ };
761
+ }
762
+
683
763
  if (isParallelStep(step)) {
684
764
  const parallelTemplates = stepTemplates as string[];
685
765
  const parallelCwd = resolveChildCwd(cwd ?? ctx.cwd, step.cwd);
@@ -768,7 +848,9 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
768
848
  timeoutMs: params.timeoutMs,
769
849
  deadlineAt,
770
850
  turnBudget: params.turnBudget,
851
+ usageBudget: params.usageBudget,
771
852
  onDetachedExit,
853
+ onForegroundChildSettled: params.onForegroundChildSettled,
772
854
  toolBudget: params.toolBudget,
773
855
  configToolBudget: params.configToolBudget,
774
856
  globalSemaphore,
@@ -1024,7 +1106,9 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
1024
1106
  timeoutMs: params.timeoutMs,
1025
1107
  deadlineAt,
1026
1108
  turnBudget: params.turnBudget,
1109
+ usageBudget: params.usageBudget,
1027
1110
  onDetachedExit,
1111
+ onForegroundChildSettled: params.onForegroundChildSettled,
1028
1112
  toolBudget: params.toolBudget,
1029
1113
  configToolBudget: params.configToolBudget,
1030
1114
  globalSemaphore,
@@ -1217,10 +1301,13 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
1217
1301
  const childIndex = globalTaskIndex;
1218
1302
  const interruptController = new AbortController();
1219
1303
  if (foregroundControl) {
1304
+ const thinking = resolveEffectiveThinking(effectiveModel, params.thinkingOverrideForTask?.(seqStep.agent, childIndex, effectiveModel));
1220
1305
  beginForegroundChild(foregroundControl, {
1221
1306
  index: childIndex,
1222
1307
  agent: seqStep.agent,
1223
1308
  description: cleanTask.trim(),
1309
+ ...(effectiveModel ? { model: effectiveModel } : {}),
1310
+ ...(thinking ? { thinking } : {}),
1224
1311
  interrupt: () => {
1225
1312
  if (interruptController.signal.aborted) return false;
1226
1313
  interruptController.abort();
@@ -1229,28 +1316,30 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
1229
1316
  });
1230
1317
  }
1231
1318
 
1232
- const structuredRuntime = seqStep.outputSchema
1233
- ? createStructuredOutputRuntime(seqStep.outputSchema, path.join(chainDir, "structured-output"))
1234
- : undefined;
1235
1319
  const agentContract = seqStep.agentContract ?? params.agentContract;
1236
- const toolBudget = resolveChainToolBudget({ stepBudget: seqStep.toolBudget, runBudget: params.toolBudget, agentBudget: agentConfig?.toolBudget, configBudget: params.configToolBudget });
1237
- if (toolBudget.error) return buildChainExecutionErrorResult(toolBudget.error, {
1238
- results,
1239
- includeProgress,
1240
- allProgress,
1241
- allArtifactPaths,
1242
- artifactsDir: params.artifactsDir,
1243
- chainAgents,
1244
- chainSteps,
1245
- totalSteps,
1246
- currentStepIndex: stepIndex,
1247
- runId: params.runId,
1248
- outputs,
1249
- currentFlatIndex: globalTaskIndex,
1250
- dynamicChildren,
1251
- dynamicGroupStatuses,
1252
- });
1253
- const r = await runSync(ctx.cwd, agents, seqStep.agent, stepTask, {
1320
+ let r!: SingleResult;
1321
+ try {
1322
+ const structuredRuntime = seqStep.outputSchema
1323
+ ? createStructuredOutputRuntime(seqStep.outputSchema, path.join(chainDir, "structured-output"))
1324
+ : undefined;
1325
+ const toolBudget = resolveChainToolBudget({ stepBudget: seqStep.toolBudget, runBudget: params.toolBudget, agentBudget: agentConfig?.toolBudget, configBudget: params.configToolBudget });
1326
+ if (toolBudget.error) return buildChainExecutionErrorResult(toolBudget.error, {
1327
+ results,
1328
+ includeProgress,
1329
+ allProgress,
1330
+ allArtifactPaths,
1331
+ artifactsDir: params.artifactsDir,
1332
+ chainAgents,
1333
+ chainSteps,
1334
+ totalSteps,
1335
+ currentStepIndex: stepIndex,
1336
+ runId: params.runId,
1337
+ outputs,
1338
+ currentFlatIndex: globalTaskIndex,
1339
+ dynamicChildren,
1340
+ dynamicGroupStatuses,
1341
+ });
1342
+ r = await runSync(ctx.cwd, agents, seqStep.agent, stepTask, {
1254
1343
  parentSessionId: ctx.sessionManager.getSessionId() ?? undefined,
1255
1344
  capabilityCeiling: params.capabilityCeiling,
1256
1345
  context: params.contextForAgent?.(seqStep.agent),
@@ -1288,9 +1377,13 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
1288
1377
  timeoutMs: params.timeoutMs,
1289
1378
  deadlineAt,
1290
1379
  turnBudget: params.turnBudget,
1291
- onDetachedExit: onDetachedExit
1292
- ? (result) => onDetachedExit(childIndex, result)
1293
- : undefined,
1380
+ onDetachedExit: (result) => {
1381
+ try {
1382
+ if (foregroundControl) finishForegroundChild(foregroundControl, childIndex);
1383
+ } finally {
1384
+ onDetachedExit?.(childIndex, result);
1385
+ }
1386
+ },
1294
1387
  toolBudget: toolBudget.toolBudget,
1295
1388
  onUpdate: onUpdate
1296
1389
  ? (p) => {
@@ -1324,8 +1417,15 @@ export async function executeChain(params: ChainExecutionParams): Promise<ChainE
1324
1417
  });
1325
1418
  }
1326
1419
  : undefined,
1327
- });
1328
- if (foregroundControl) finishForegroundChild(foregroundControl, childIndex);
1420
+ });
1421
+ } finally {
1422
+ // Rejected attempts and early validation returns release the child here.
1423
+ // A detached receipt transfers cleanup ownership to onDetachedExit.
1424
+ if (!r?.detached) {
1425
+ if (foregroundControl) finishForegroundChild(foregroundControl, childIndex);
1426
+ params.onForegroundChildSettled?.();
1427
+ }
1428
+ }
1329
1429
  recordRun(seqStep.agent, cleanTask, r.exitCode, r.progressSummary?.durationMs ?? 0);
1330
1430
 
1331
1431
  globalTaskIndex++;