@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
@@ -18,6 +18,8 @@ import {
18
18
  type AsyncStatus,
19
19
  type ChainOutputMap,
20
20
  type CostSummary,
21
+ type LaunchResolvedChildExtensionsV1,
22
+ type RuntimeAcknowledgedChildExtensionsV1,
21
23
  type ModelAttempt,
22
24
  type NestedRouteInfo,
23
25
  type NestedRunSummary,
@@ -25,6 +27,8 @@ import {
25
27
  type ResolvedTurnBudget,
26
28
  type ResolvedToolBudget,
27
29
  type SubagentRunMode,
30
+ type SubagentOutputState,
31
+ type UsageBudgetConfig,
28
32
  type ToolBudgetState,
29
33
  type TurnBudgetState,
30
34
  type Usage,
@@ -35,6 +39,7 @@ import {
35
39
  DEFAULT_MAX_OUTPUT,
36
40
  type MaxOutputConfig,
37
41
  SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
42
+ POLL_INTERVAL_MS,
38
43
  truncateOutput,
39
44
  getSubagentDepthEnv,
40
45
  } from "../../shared/types.ts";
@@ -49,6 +54,7 @@ import {
49
54
  import {
50
55
  type RunnerSubagentStep as SubagentStep,
51
56
  type RunnerStep,
57
+ isCheckpointRunnerStep,
52
58
  isDynamicRunnerGroup,
53
59
  isParallelGroup,
54
60
  flattenSteps,
@@ -58,13 +64,22 @@ import {
58
64
  DEFAULT_GLOBAL_CONCURRENCY_LIMIT,
59
65
  Semaphore,
60
66
  } from "../shared/parallel-utils.ts";
61
- import { applyThinkingSuffix, buildPiArgs, cleanupTempDir, resolvePiLaunchToolPlan } from "../shared/pi-args.ts";
67
+ import { applyThinkingSuffix, buildPiArgs, cleanupTempDir, projectLaunchResolvedChildExtensions, resolvePiLaunchToolPlan } from "../shared/pi-args.ts";
68
+ import { readRuntimeAcknowledgedExtensions } from "../shared/runtime-acknowledged-extensions.ts";
62
69
  import { outputEntryFromAsyncResult, resolveOutputReferences } from "../shared/chain-outputs.ts";
63
70
  import { createStructuredOutputRuntime, readStructuredOutput } from "../shared/structured-output.ts";
71
+ import { formatProcessSignalError, isUnexplainedProcessSignal } from "../shared/process-signal.ts";
64
72
  import { readChildToolDiagnosticError } from "../shared/tool-availability.ts";
65
73
  import { collectDynamicResults, DynamicFanoutError, materializeDynamicParallelStep, validateDynamicCollection } from "../shared/dynamic-fanout.ts";
66
74
  import { nestedSummaryFromAsyncStatus, projectNestedEvents, resolveNestedAsyncDir, writeNestedEvent } from "../shared/nested-events.ts";
67
75
  import { formatModelAttemptNote, isRetryableModelFailure } from "../shared/model-fallback.ts";
76
+ import {
77
+ SUBAGENT_STARTUP_RETRY_DELAYS_MS,
78
+ formatSubagentStartupRetryExhaustedError,
79
+ formatSubagentStartupRetryNote,
80
+ isRetryableSubagentStartupFailure,
81
+ waitForSubagentStartupRetry,
82
+ } from "../shared/subagent-startup-retry.ts";
68
83
  import { markProcessTerminalCandidateLeaseRelease, writeProcessTerminalCandidate, type ProcessTerminalCandidate } from "./process-terminal.ts";
69
84
  import { createSteeringStatus, recordSteeringRequest, steeringStatus, terminalSteeringNoticeState, updateSteeringTarget } from "./steering.ts";
70
85
  import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
@@ -99,9 +114,10 @@ import { resolveSubagentIntercomTarget } from "../../intercom/intercom-bridge.ts
99
114
  import { acceptanceFailureMessage, aggregateAcceptanceReport, buildSkippedAcceptanceLedger, evaluateAcceptance, formatAcceptancePrompt, resolveEffectiveAcceptance, stripAcceptanceReport } from "../shared/acceptance.ts";
100
115
  import { attachContractProjections, isAgentContractV1 } from "../shared/agent-contract.ts";
101
116
  import { waitForImportedAsyncRoot } from "./chain-root-attachment.ts";
102
- import { appendRunnerStepsToStatus, consumeChainAppendRequests, countPendingChainAppendRequests } from "./chain-append.ts";
117
+ import { appendRunnerStepsToStatus, consumeChainAppendRequests, countPendingChainAppendRequests, statusStepDescription } from "./chain-append.ts";
103
118
  import { appendTurnBudgetSystemPrompt, formatTurnBudgetOutput, initialTurnBudgetState, turnBudgetDecision, turnBudgetDeferredNote, turnBudgetDeferredState, turnBudgetExceededMessage, turnBudgetSoftNote, turnBudgetState } from "../shared/turn-budget.ts";
104
119
  import { initialToolBudgetState, toolBudgetState } from "../shared/tool-budget.ts";
120
+ import { usageBudgetExceededMessage, usageBudgetState } from "../shared/usage-budget.ts";
105
121
  import { formatParallelHandoffError, formatParallelHandoffReference, parallelHandoffPath, writeParallelHandoffGroup } from "../shared/parallel-handoff.ts";
106
122
  import { resolveWatchdogConfig } from "../../watchdog/settings.ts";
107
123
  import { createBoundedByteTail, createBoundedLineReader, formatProtocolOutputLimit, MAX_CHILD_STDERR_BYTES, projectChildLifecycle, type ChildLifecycleAction, type ProtocolOutputLimit } from "../shared/child-protocol.ts";
@@ -149,12 +165,15 @@ interface SubagentRunConfig {
149
165
  deadlineAt?: number;
150
166
  turnBudget?: ResolvedTurnBudget;
151
167
  toolBudget?: ResolvedToolBudget;
168
+ usageBudget?: UsageBudgetConfig;
152
169
  revivalLease?: SessionLeaseRequest;
153
170
  revivalLeaseToken?: string;
154
171
  /** Global cap on simultaneously-running subagent tasks within this run. */
155
172
  globalConcurrencyLimit?: number;
156
173
  capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
157
174
  launchContractDigest?: string;
175
+ launchResolvedExtensions?: LaunchResolvedChildExtensionsV1;
176
+ runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;
158
177
  runnerProcessInstanceId?: string;
159
178
  }
160
179
 
@@ -163,7 +182,10 @@ interface StepResult {
163
182
  context?: "fresh" | "fork";
164
183
  capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
165
184
  capabilityAudit?: import("../shared/capability-ceiling.ts").SubagentCapabilityAudit;
185
+ launchResolvedExtensions?: LaunchResolvedChildExtensionsV1;
186
+ runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;
166
187
  output: string;
188
+ outputState?: SubagentOutputState;
167
189
  error?: string;
168
190
  protocolError?: ProtocolOutputLimit;
169
191
  success: boolean;
@@ -172,6 +194,7 @@ interface StepResult {
172
194
  interrupted?: boolean;
173
195
  timedOut?: boolean;
174
196
  stopped?: boolean;
197
+ processSignal?: string | null;
175
198
  turnBudget?: TurnBudgetState;
176
199
  turnBudgetExceeded?: boolean;
177
200
  wrapUpRequested?: boolean;
@@ -395,10 +418,13 @@ interface RunPiStreamingResult {
395
418
  exitCode: number | null;
396
419
  messages: Message[];
397
420
  usage: Usage;
421
+ toolCount: number;
422
+ durationMs: number;
398
423
  model?: string;
399
424
  error?: string;
400
425
  protocolError?: ProtocolOutputLimit;
401
426
  finalOutput: string;
427
+ outputState: SubagentOutputState;
402
428
  interrupted?: boolean;
403
429
  timedOut?: boolean;
404
430
  stopped?: boolean;
@@ -409,6 +435,7 @@ interface RunPiStreamingResult {
409
435
  toolBudgetBlocked?: boolean;
410
436
  observedMutationAttempt?: boolean;
411
437
  watchdog?: ChildWatchdogStateSnapshot;
438
+ runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;
412
439
  processInstanceId: string;
413
440
  processCloseObservedAt?: number;
414
441
  processSignal?: string | null;
@@ -434,6 +461,7 @@ function runPiStreaming(
434
461
  onWriterProcess?: (writer: { state: "none" | "spawning" } | { state: "running"; pid: number }) => void,
435
462
  ): Promise<RunPiStreamingResult> {
436
463
  return new Promise((resolve) => {
464
+ const startedAt = Date.now();
437
465
  const processInstanceId = randomUUID();
438
466
  onWriterProcess?.({ state: "spawning" });
439
467
  const outputStream = fs.createWriteStream(outputFile, { flags: "w" });
@@ -471,6 +499,7 @@ function runPiStreaming(
471
499
  let turnBudgetMessage: string | undefined;
472
500
  let turnBudget: TurnBudgetState | undefined;
473
501
  let observedMutationAttempt = false;
502
+ let toolCount = 0;
474
503
  const childWatchdogConfig = decodeChildWatchdogConfig(env?.[CHILD_WATCHDOG_CONFIG_ENV]);
475
504
  let childWatchdogState: ChildWatchdogStateSnapshot | undefined;
476
505
  let applyChildLifecycle = (_action: ChildLifecycleAction): void => {};
@@ -557,6 +586,7 @@ function runPiStreaming(
557
586
  onChildEvent?.(event);
558
587
 
559
588
  if (event.type === "tool_execution_start" && event.toolName) {
589
+ toolCount += 1;
560
590
  observedMutationAttempt = observedMutationAttempt || isMutatingTool(event.toolName, event.args);
561
591
  const toolArgs = extractToolArgsPreview(event.args ?? {});
562
592
  writeOutputLine(toolArgs ? `${event.toolName}: ${toolArgs}` : event.toolName);
@@ -790,16 +820,27 @@ function runPiStreaming(
790
820
  const stderr = stderrTail.text();
791
821
  const finalOutput = getFinalOutput(messages) || rawStdoutTail.text().trim();
792
822
  const finalError = error ?? assistantError;
793
- const forcedDrainAfterFinalSuccess = forcedTerminationSignal && (cleanTerminalAssistantStopReceived || agentSettledReceived) && !finalError;
823
+ const forcedDrainAfterFinalSuccess = Boolean(forcedTerminationSignal || signal) && (cleanTerminalAssistantStopReceived || agentSettledReceived) && !finalError;
824
+ const signalError = isUnexplainedProcessSignal({
825
+ processSignal: signal,
826
+ interrupted,
827
+ timedOut,
828
+ stopped,
829
+ turnBudgetExceeded,
830
+ forcedDrainAfterFinalSuccess,
831
+ }) ? formatProcessSignalError(signal!) : undefined;
794
832
  resolve({
795
833
  stderr,
796
834
  exitCode: timedOut || stopped ? 1 : turnBudgetExceeded ? 1 : interrupted || forcedDrainAfterFinalSuccess ? 0 : forcedTerminationSignal || signal ? (exitCode ?? 1) : exitCode,
797
835
  messages,
798
836
  usage,
837
+ toolCount,
838
+ durationMs: Date.now() - startedAt,
799
839
  model,
800
- error: stopped ? (stopMessage ?? "Subagent stopped by user.") : timedOut ? (timeoutMessage ?? "Subagent timed out.") : turnBudgetExceeded ? turnBudgetMessage : interrupted || forcedDrainAfterFinalSuccess ? undefined : finalError,
840
+ error: stopped ? (stopMessage ?? "Subagent stopped by user.") : timedOut ? (timeoutMessage ?? "Subagent timed out.") : turnBudgetExceeded ? turnBudgetMessage : interrupted || forcedDrainAfterFinalSuccess ? undefined : finalError ?? signalError,
801
841
  protocolError,
802
842
  finalOutput: (timedOut || stopped) && !finalOutput.trim() ? (stopped ? stopMessage ?? "Subagent stopped by user." : timeoutMessage ?? "Subagent timed out.") : finalOutput,
843
+ outputState: finalOutput.trim() ? "present" : "absent",
803
844
  interrupted,
804
845
  timedOut,
805
846
  stopped,
@@ -833,7 +874,7 @@ function runPiStreaming(
833
874
  const stderr = stderrTail.text();
834
875
  const finalOutput = getFinalOutput(messages) || rawStdoutTail.text().trim();
835
876
  const spawnErrorMessage = spawnError instanceof Error ? spawnError.message : String(spawnError);
836
- resolve({ stderr, exitCode: 1, messages, usage, model, error: stopped ? (stopMessage ?? "Subagent stopped by user.") : timedOut ? (timeoutMessage ?? "Subagent timed out.") : turnBudgetExceeded ? turnBudgetMessage : error ?? assistantError ?? spawnErrorMessage, protocolError, finalOutput: (timedOut || stopped) && !finalOutput.trim() ? (stopped ? stopMessage ?? "Subagent stopped by user." : timeoutMessage ?? "Subagent timed out.") : finalOutput, timedOut, stopped, turnBudget, turnBudgetExceeded, wrapUpRequested: turnBudget?.outcome === "wrap-up-requested" || turnBudget?.outcome === "termination-deferred" || turnBudgetExceeded || undefined, observedMutationAttempt, watchdog: childWatchdogState, processInstanceId });
877
+ resolve({ stderr, exitCode: 1, messages, usage, toolCount, durationMs: Date.now() - startedAt, model, error: stopped ? (stopMessage ?? "Subagent stopped by user.") : timedOut ? (timeoutMessage ?? "Subagent timed out.") : turnBudgetExceeded ? turnBudgetMessage : error ?? assistantError ?? spawnErrorMessage, protocolError, finalOutput: (timedOut || stopped) && !finalOutput.trim() ? (stopped ? stopMessage ?? "Subagent stopped by user." : timeoutMessage ?? "Subagent timed out.") : finalOutput, outputState: finalOutput.trim() ? "present" : "absent", timedOut, stopped, turnBudget, turnBudgetExceeded, wrapUpRequested: turnBudget?.outcome === "wrap-up-requested" || turnBudget?.outcome === "termination-deferred" || turnBudgetExceeded || undefined, observedMutationAttempt, watchdog: childWatchdogState, processInstanceId });
837
878
  });
838
879
  });
839
880
  }
@@ -992,6 +1033,8 @@ async function runSingleStep(
992
1033
  context?: "fresh" | "fork";
993
1034
  agentContract?: import("../../shared/types.ts").AgentContract;
994
1035
  launchContractDigest?: string;
1036
+ launchResolvedExtensions?: LaunchResolvedChildExtensionsV1;
1037
+ runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;
995
1038
  output: string;
996
1039
  exitCode: number | null;
997
1040
  error?: string;
@@ -1132,6 +1175,7 @@ async function runSingleStep(
1132
1175
  : [undefined];
1133
1176
  const attemptedModels: string[] = [];
1134
1177
  let capabilityAudit: import("../shared/capability-ceiling.ts").SubagentCapabilityAudit | undefined;
1178
+ let launchResolvedExtensions = step.launchResolvedExtensions;
1135
1179
  const modelAttempts: ModelAttempt[] = [];
1136
1180
  const writerProcesses: Array<{ processInstanceId: string; kind: "pi-writer"; attempt: number; closeObservedAt: number; exitCode: number | null; signal: string | null }> = [];
1137
1181
  let writerAttemptCount = 0;
@@ -1145,9 +1189,11 @@ async function runSingleStep(
1145
1189
  let toolBudgetBlocked = false;
1146
1190
  let actualLaunchContractDigest = step.launchContractDigest;
1147
1191
 
1148
- for (let index = 0; index < candidates.length; index++) {
1149
- if (ctx.timeoutSignal?.aborted || ctx.skipAcceptance?.()) break;
1150
- const candidate = candidates[index];
1192
+ let modelIndex = 0;
1193
+ let startupAttemptIndex = 0;
1194
+ modelAttemptsLoop: while (modelIndex < candidates.length) {
1195
+ if (ctx.timeoutSignal?.aborted || ctx.stopSignal?.aborted || ctx.skipAcceptance?.()) break;
1196
+ const candidate = candidates[modelIndex];
1151
1197
  ctx.onAttemptStart?.({ model: candidate, thinking: resolveEffectiveThinking(candidate, step.thinking) });
1152
1198
  const outputSnapshot = captureSingleOutputSnapshot(step.outputPath);
1153
1199
  if (effectiveStructuredOutput) {
@@ -1166,7 +1212,7 @@ async function runSingleStep(
1166
1212
  childIndex: ctx.flatIndex,
1167
1213
  })
1168
1214
  : undefined;
1169
- const { args, env, tempDir, toolDiagnosticPath, capabilityAudit: attemptCapabilityAudit } = buildPiArgs({
1215
+ const { args, env, tempDir, toolDiagnosticPath, runtimeAcknowledgedExtensionsPath, capabilityAudit: attemptCapabilityAudit } = buildPiArgs({
1170
1216
  parentSessionId: step.parentSessionId,
1171
1217
  baseArgs: ["--offline", "--mode", "json", "-p"],
1172
1218
  task,
@@ -1215,6 +1261,7 @@ async function runSingleStep(
1215
1261
  capabilityCeiling: step.capabilityCeiling ?? ctx.capabilityCeiling,
1216
1262
  inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
1217
1263
  });
1264
+ launchResolvedExtensions = projectLaunchResolvedChildExtensions(toolPlan);
1218
1265
  actualLaunchContractDigest = launchBindingDigest({
1219
1266
  definitionDigest: step.definitionDigest,
1220
1267
  task: step.launchBindingTask ?? task,
@@ -1259,7 +1306,7 @@ async function runSingleStep(
1259
1306
  writerProcesses.push({
1260
1307
  processInstanceId: run.processInstanceId,
1261
1308
  kind: "pi-writer",
1262
- attempt: index,
1309
+ attempt: writerAttemptCount - 1,
1263
1310
  closeObservedAt: run.processCloseObservedAt,
1264
1311
  exitCode: run.exitCode,
1265
1312
  signal: run.processSignal ?? null,
@@ -1287,6 +1334,7 @@ async function runSingleStep(
1287
1334
  const toolAvailabilityError = run.exitCode === 0 && !run.error
1288
1335
  ? readChildToolDiagnosticError(toolDiagnosticPath)
1289
1336
  : undefined;
1337
+ const runtimeAcknowledgedExtensions = readRuntimeAcknowledgedExtensions(runtimeAcknowledgedExtensionsPath);
1290
1338
  cleanupTempDir(tempDir);
1291
1339
 
1292
1340
  const hiddenError = run.exitCode === 0 && !run.error && !toolAvailabilityError ? detectSubagentError(run.messages) : null;
@@ -1341,6 +1389,13 @@ async function runSingleStep(
1341
1389
  : run.error && run.exitCode === 0
1342
1390
  ? 1
1343
1391
  : run.exitCode;
1392
+ const signalError = run.exitCode !== 0 && isUnexplainedProcessSignal({
1393
+ processSignal: run.processSignal,
1394
+ interrupted: run.interrupted,
1395
+ timedOut: run.timedOut,
1396
+ stopped: run.stopped,
1397
+ turnBudgetExceeded: run.turnBudgetExceeded,
1398
+ }) ? formatProcessSignalError(run.processSignal!) : undefined;
1344
1399
  const error = toolAvailabilityError
1345
1400
  ?? completionGuardError
1346
1401
  ?? structuredError
@@ -1349,7 +1404,7 @@ async function runSingleStep(
1349
1404
  ? hiddenError.details
1350
1405
  ? `${hiddenError.errorType} failed (exit ${effectiveExitCode}): ${hiddenError.details}`
1351
1406
  : `${hiddenError.errorType} failed with exit code ${effectiveExitCode}`
1352
- : run.error || (run.exitCode !== 0 && run.stderr.trim() ? run.stderr.trim() : undefined));
1407
+ : run.error || signalError || (run.exitCode !== 0 && run.stderr.trim() ? run.stderr.trim() : undefined));
1353
1408
  const attempt: ModelAttempt = {
1354
1409
  model: candidate ?? run.model ?? step.model ?? "default",
1355
1410
  success: effectiveExitCode === 0 && !error,
@@ -1358,7 +1413,7 @@ async function runSingleStep(
1358
1413
  usage: run.usage,
1359
1414
  };
1360
1415
  modelAttempts.push(attempt);
1361
- if (candidate) attemptedModels.push(candidate);
1416
+ if (candidate && startupAttemptIndex === 0) attemptedModels.push(candidate);
1362
1417
  completionGuardTriggeredFinal = completionGuardTriggered;
1363
1418
  finalOutputSnapshot = outputSnapshot;
1364
1419
  if (step.toolBudget) {
@@ -1367,12 +1422,56 @@ async function runSingleStep(
1367
1422
  toolBudgetBlocked = Boolean(blockedMessage);
1368
1423
  toolBudget = toolBudgetState(step.toolBudget, toolMessages.length, blockedMessage ? (blockedMessage as { toolName?: string }).toolName : undefined);
1369
1424
  }
1370
- finalResult = { ...run, exitCode: effectiveExitCode, model: candidate ?? run.model, error, structuredOutput, ...(step.agentContract ? { agentContract: step.agentContract } : {}), ...(fileMutationEffect ? { effects: { fileMutation: fileMutationEffect } } : {}) } as RunPiStreamingResult & { structuredOutput?: unknown; agentContract?: import("../../shared/types.ts").AgentContract; effects?: import("../../shared/types.ts").EffectsProjection };
1371
- if (run.turnBudgetExceeded) break;
1372
- if (run.stopped || run.timedOut || ctx.timeoutSignal?.aborted || ctx.stopSignal?.aborted || ctx.skipAcceptance?.()) break;
1373
- if (attempt.success || completionGuardTriggered) break;
1374
- if (!isRetryableModelFailure(error) || index === candidates.length - 1) break;
1375
- attemptNotes.push(formatModelAttemptNote(attempt, candidates[index + 1]));
1425
+ finalResult = { ...run, exitCode: effectiveExitCode, model: candidate ?? run.model, error, structuredOutput, runtimeAcknowledgedExtensions, ...(step.agentContract ? { agentContract: step.agentContract } : {}), ...(fileMutationEffect ? { effects: { fileMutation: fileMutationEffect } } : {}) } as RunPiStreamingResult & { structuredOutput?: unknown; agentContract?: import("../../shared/types.ts").AgentContract; effects?: import("../../shared/types.ts").EffectsProjection };
1426
+ if (run.turnBudgetExceeded) break modelAttemptsLoop;
1427
+ if (run.stopped || run.timedOut || ctx.timeoutSignal?.aborted || ctx.stopSignal?.aborted || ctx.skipAcceptance?.()) break modelAttemptsLoop;
1428
+ if (attempt.success || completionGuardTriggered) break modelAttemptsLoop;
1429
+
1430
+ const startupFailure = isRetryableSubagentStartupFailure({
1431
+ exitCode: effectiveExitCode,
1432
+ error,
1433
+ finalOutput: run.finalOutput,
1434
+ messageCount: run.messages.length,
1435
+ toolCount: run.toolCount,
1436
+ usage: run.usage,
1437
+ durationMs: run.durationMs,
1438
+ protocolError: run.protocolError,
1439
+ processSignal: run.processSignal,
1440
+ observedMutationAttempt: run.observedMutationAttempt,
1441
+ interrupted: run.interrupted,
1442
+ timedOut: run.timedOut,
1443
+ stopped: run.stopped,
1444
+ turnBudgetExceeded: run.turnBudgetExceeded,
1445
+ });
1446
+ const retryDelayMs = SUBAGENT_STARTUP_RETRY_DELAYS_MS[startupAttemptIndex];
1447
+ if (startupFailure && retryDelayMs !== undefined) {
1448
+ const retryNote = formatSubagentStartupRetryNote({
1449
+ model: attempt.model,
1450
+ attempt: startupAttemptIndex + 1,
1451
+ maxAttempts: SUBAGENT_STARTUP_RETRY_DELAYS_MS.length + 1,
1452
+ delayMs: retryDelayMs,
1453
+ });
1454
+ const shouldRetry = await waitForSubagentStartupRetry(retryDelayMs, [ctx.timeoutSignal, ctx.stopSignal]);
1455
+ if (!shouldRetry || ctx.skipAcceptance?.()) break modelAttemptsLoop;
1456
+ attempt.error = retryNote;
1457
+ attemptNotes.push(retryNote);
1458
+ startupAttemptIndex += 1;
1459
+ continue;
1460
+ }
1461
+ if (startupFailure) {
1462
+ const startupError = formatSubagentStartupRetryExhaustedError({
1463
+ model: attempt.model,
1464
+ attempts: startupAttemptIndex + 1,
1465
+ });
1466
+ attempt.error = startupError;
1467
+ finalResult.error = startupError;
1468
+ finalResult.finalOutput = startupError;
1469
+ break modelAttemptsLoop;
1470
+ }
1471
+ if (!isRetryableModelFailure(error) || modelIndex === candidates.length - 1) break modelAttemptsLoop;
1472
+ attemptNotes.push(formatModelAttemptNote(attempt, candidates[modelIndex + 1]));
1473
+ modelIndex += 1;
1474
+ startupAttemptIndex = 0;
1376
1475
  }
1377
1476
 
1378
1477
  const rawOutput = finalResult?.finalOutput ?? "";
@@ -1401,6 +1500,13 @@ async function runSingleStep(
1401
1500
  const childWrittenOutput = step.outputPath
1402
1501
  ? extractChildWrittenOutput(finalResult?.messages, step.outputPath, step.cwd ?? ctx.cwd)
1403
1502
  : undefined;
1503
+ const outputState: SubagentOutputState = finalResult?.outputState === "present"
1504
+ || (finalResult as (RunPiStreamingResult & { structuredOutput?: unknown }) | undefined)?.structuredOutput !== undefined
1505
+ || Boolean(childWrittenOutput?.trim())
1506
+ ? "present"
1507
+ : resolvedOutput.savedPath
1508
+ ? "unknown"
1509
+ : finalResult?.outputState ?? "unknown";
1404
1510
  const finalizedOutput = finalizeSingleOutput({
1405
1511
  fullOutput: outputForSummary,
1406
1512
  outputPath: step.outputPath,
@@ -1473,6 +1579,8 @@ async function runSingleStep(
1473
1579
  acceptance: effectiveAcceptance,
1474
1580
  ...(capabilityAudit ? { capabilityCeiling: capabilityAudit.ceiling, capabilityAudit } : {}),
1475
1581
  launchContractDigest: actualLaunchContractDigest,
1582
+ launchResolvedExtensions,
1583
+ ...((finalResult as (RunPiStreamingResult & { runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1 }) | undefined)?.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: (finalResult as RunPiStreamingResult & { runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1 }).runtimeAcknowledgedExtensions } : {}),
1476
1584
  ...(transcriptWriter ? { transcriptPath: artifactPaths.transcriptPath } : {}),
1477
1585
  transcriptError: transcriptWriter?.getError(),
1478
1586
  skills: step.skills,
@@ -1489,6 +1597,7 @@ async function runSingleStep(
1489
1597
  ...(step.agentContract ? { agentContract: step.agentContract } : {}),
1490
1598
  launchContractDigest: actualLaunchContractDigest,
1491
1599
  output: outputForSummary,
1600
+ outputState,
1492
1601
  exitCode: effectiveFinalExitCode,
1493
1602
  error: effectiveFinalError,
1494
1603
  protocolError: finalResult?.protocolError,
@@ -1504,6 +1613,7 @@ async function runSingleStep(
1504
1613
  interrupted: timedOutAfterAcceptance || stoppedAfterAcceptance || turnBudgetExceeded ? false : finalResult?.interrupted,
1505
1614
  timedOut: timedOutAfterAcceptance ? true : finalResult?.timedOut,
1506
1615
  stopped: stoppedAfterAcceptance ? true : finalResult?.stopped,
1616
+ processSignal: finalResult?.processSignal,
1507
1617
  turnBudget,
1508
1618
  turnBudgetExceeded: turnBudgetExceeded || undefined,
1509
1619
  wrapUpRequested: finalResult?.wrapUpRequested || turnBudget?.outcome === "wrap-up-requested" || turnBudget?.outcome === "termination-deferred" || turnBudgetExceeded || undefined,
@@ -1517,6 +1627,8 @@ async function runSingleStep(
1517
1627
  acceptance: effectiveAcceptance,
1518
1628
  watchdog: finalResult?.watchdog,
1519
1629
  ...(capabilityAudit ? { capabilityCeiling: capabilityAudit.ceiling, capabilityAudit } : {}),
1630
+ launchResolvedExtensions,
1631
+ ...((finalResult as (RunPiStreamingResult & { runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1 }) | undefined)?.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: (finalResult as RunPiStreamingResult & { runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1 }).runtimeAcknowledgedExtensions } : {}),
1520
1632
  writerProcesses,
1521
1633
  writerAttemptCount,
1522
1634
  };
@@ -1525,6 +1637,7 @@ async function runSingleStep(
1525
1637
 
1526
1638
  type RunnerStatusStep = NonNullable<AsyncStatus["steps"]>[number] & {
1527
1639
  exitCode?: number | null;
1640
+ description?: string;
1528
1641
  };
1529
1642
 
1530
1643
  function appendCapabilityCeilingAppliedEvent(eventsPath: string, runId: string, stepIndex: number, agent: string, result: StepResult): void {
@@ -1722,6 +1835,10 @@ async function runSubagent(
1722
1835
  let timedOut = false;
1723
1836
  let stopped = false;
1724
1837
  let turnBudgetExceeded = false;
1838
+ let usageBudgetExceeded = false;
1839
+ let checkpointRejected = false;
1840
+ let pendingCheckpointDecision: "approved" | "rejected" | undefined;
1841
+ let wakeCheckpointDecision: (() => void) | undefined;
1725
1842
  const timeoutMessage = config.timeoutMs !== undefined ? `Subagent timed out after ${config.timeoutMs}ms.` : undefined;
1726
1843
  const stopMessage = "Subagent stopped by user.";
1727
1844
  const timeoutAbortController = new AbortController();
@@ -1736,6 +1853,19 @@ async function runSubagent(
1736
1853
  let flatStepCount = 0;
1737
1854
  for (let stepIndex = 0; stepIndex < steps.length; stepIndex++) {
1738
1855
  const step = steps[stepIndex]!;
1856
+ if (isCheckpointRunnerStep(step)) {
1857
+ initialStatusSteps.push({
1858
+ agent: `checkpoint:${step.checkpoint}`,
1859
+ phase: step.phase,
1860
+ label: step.label ?? step.checkpoint,
1861
+ status: "pending",
1862
+ checkpoint: { name: step.checkpoint, ...(step.message ? { message: step.message } : {}), status: "pending", stepIndex },
1863
+ recentTools: [],
1864
+ recentOutput: [],
1865
+ });
1866
+ flatStepCount++;
1867
+ continue;
1868
+ }
1739
1869
  if (isParallelGroup(step)) {
1740
1870
  parallelGroups.push({ start: flatStepCount, count: step.parallel.length, stepIndex });
1741
1871
  for (const task of step.parallel) {
@@ -1743,6 +1873,7 @@ async function runSubagent(
1743
1873
  const transcriptPath = resolveAsyncStepTranscriptPath({ artifactsDir, artifactConfig, runId: id, agent: task.agent, flatIndex: taskFlatIndex, flatStepCount: initialFlatStepCount });
1744
1874
  initialStatusSteps.push({
1745
1875
  agent: task.agent,
1876
+ ...(statusStepDescription(task.task) ? { description: statusStepDescription(task.task) } : {}),
1746
1877
  ...(task.context ? { context: task.context } : {}),
1747
1878
  phase: task.phase,
1748
1879
  label: task.label,
@@ -1750,6 +1881,7 @@ async function runSubagent(
1750
1881
  structured: task.structured,
1751
1882
  ...(task.agentContract ? { agentContract: task.agentContract } : {}),
1752
1883
  ...(task.launchContractDigest ? { launchContractDigest: task.launchContractDigest } : {}),
1884
+ ...(task.launchResolvedExtensions ? { launchResolvedExtensions: task.launchResolvedExtensions } : {}),
1753
1885
  ...(task.capabilityCeiling ? { capabilityCeiling: task.capabilityCeiling } : {}),
1754
1886
  status: "pending",
1755
1887
  ...(task.toolBudget ? { toolBudget: initialToolBudgetState(task.toolBudget) } : {}),
@@ -1786,6 +1918,7 @@ async function runSubagent(
1786
1918
  const transcriptPath = resolveAsyncStepTranscriptPath({ artifactsDir, artifactConfig, runId: id, agent: step.agent, flatIndex: stepFlatIndex, flatStepCount: initialFlatStepCount });
1787
1919
  initialStatusSteps.push({
1788
1920
  agent: step.agent,
1921
+ ...(statusStepDescription(step.task) ? { description: statusStepDescription(step.task) } : {}),
1789
1922
  ...(step.context ? { context: step.context } : {}),
1790
1923
  phase: step.phase,
1791
1924
  label: step.label,
@@ -1793,6 +1926,7 @@ async function runSubagent(
1793
1926
  structured: step.structured,
1794
1927
  ...(step.agentContract ? { agentContract: step.agentContract } : {}),
1795
1928
  ...(step.launchContractDigest ? { launchContractDigest: step.launchContractDigest } : {}),
1929
+ ...(step.launchResolvedExtensions ? { launchResolvedExtensions: step.launchResolvedExtensions } : {}),
1796
1930
  ...(step.capabilityCeiling ? { capabilityCeiling: step.capabilityCeiling } : {}),
1797
1931
  status: "pending",
1798
1932
  ...(step.toolBudget ? { toolBudget: initialToolBudgetState(step.toolBudget) } : {}),
@@ -1831,6 +1965,7 @@ async function runSubagent(
1831
1965
  ...(config.deadlineAt !== undefined ? { deadlineAt: config.deadlineAt } : {}),
1832
1966
  ...(config.turnBudget ? { turnBudget: initialTurnBudgetState(config.turnBudget) } : {}),
1833
1967
  ...(config.toolBudget ? { toolBudget: initialToolBudgetState(config.toolBudget) } : {}),
1968
+ ...(config.usageBudget ? { usageBudget: usageBudgetState(config.usageBudget, undefined) } : {}),
1834
1969
  pid: process.pid,
1835
1970
  cwd,
1836
1971
  currentStep: 0,
@@ -1838,6 +1973,7 @@ async function runSubagent(
1838
1973
  parallelGroups,
1839
1974
  workflowGraph: config.workflowGraph,
1840
1975
  ...(config.launchContractDigest ? { launchContractDigest: config.launchContractDigest } : {}),
1976
+ ...(config.launchResolvedExtensions ? { launchResolvedExtensions: config.launchResolvedExtensions } : {}),
1841
1977
  ...(config.capabilityCeiling ? { capabilityCeiling: config.capabilityCeiling } : {}),
1842
1978
  ...(config.runnerProcessInstanceId ? { processTerminal: { version: 1 as const, state: "pending" as const, runId: id, runnerProcessInstanceId: config.runnerProcessInstanceId } } : {}),
1843
1979
  steps: initialStatusSteps,
@@ -1848,6 +1984,23 @@ async function runSubagent(
1848
1984
 
1849
1985
  fs.mkdirSync(asyncDir, { recursive: true });
1850
1986
  writeAtomicJson(statusPath, statusPayload);
1987
+ let pendingParallelUsageCost: CostSummary = { inputTokens: 0, outputTokens: 0, costUsd: 0 };
1988
+ const currentUsageTotals = (): CostSummary => {
1989
+ const cost = results.reduce<CostSummary>((sum, result) => ({
1990
+ inputTokens: sum.inputTokens + (result.totalCost?.inputTokens ?? result.usage?.input ?? 0),
1991
+ outputTokens: sum.outputTokens + (result.totalCost?.outputTokens ?? result.usage?.output ?? 0),
1992
+ costUsd: sum.costUsd + (result.totalCost?.costUsd ?? result.usage?.cost ?? 0),
1993
+ }), { inputTokens: pendingParallelUsageCost.inputTokens, outputTokens: pendingParallelUsageCost.outputTokens, costUsd: pendingParallelUsageCost.costUsd });
1994
+ return {
1995
+ inputTokens: Math.max(cost.inputTokens, statusPayload.totalTokens?.input ?? 0),
1996
+ outputTokens: Math.max(cost.outputTokens, statusPayload.totalTokens?.output ?? 0),
1997
+ costUsd: cost.costUsd,
1998
+ };
1999
+ };
2000
+ const refreshUsageBudget = () => {
2001
+ statusPayload.usageBudget = usageBudgetState(config.usageBudget, currentUsageTotals());
2002
+ return statusPayload.usageBudget;
2003
+ };
1851
2004
  const emitNestedSelfEvent = (type: "subagent.nested.updated" | "subagent.nested.completed"): void => {
1852
2005
  if (!config.nestedRoute || !config.nestedSelf) return;
1853
2006
  try {
@@ -1873,9 +2026,9 @@ async function runSubagent(
1873
2026
  const refreshWorkflowGraph = (): void => {
1874
2027
  if (!config.workflowGraph) return;
1875
2028
  const graph = structuredClone(statusPayload.workflowGraph ?? config.workflowGraph);
1876
- const normalize = (status: RunnerStatusStep["status"]): "pending" | "running" | "completed" | "failed" | "paused" | "stopped" | "detached" => {
2029
+ const normalize = (status: RunnerStatusStep["status"]): "pending" | "running" | "completed" | "failed" | "paused" | "stopped" | "detached" | "rejected" => {
1877
2030
  if (status === "complete" || status === "completed") return "completed";
1878
- if (status === "running" || status === "failed" || status === "paused" || status === "stopped" || status === "pending") return status;
2031
+ if (status === "running" || status === "failed" || status === "paused" || status === "stopped" || status === "pending" || status === "rejected") return status;
1879
2032
  return "pending";
1880
2033
  };
1881
2034
  const updateNode = (node: NonNullable<typeof graph.nodes>[number]): void => {
@@ -1885,6 +2038,7 @@ async function runSubagent(
1885
2038
  node.status = normalize(step.status);
1886
2039
  node.error = step.error;
1887
2040
  node.acceptanceStatus = step.acceptance?.status;
2041
+ node.checkpoint = step.checkpoint;
1888
2042
  }
1889
2043
  if (statusPayload.currentStep === node.flatIndex) graph.currentNodeId = node.id;
1890
2044
  }
@@ -1893,10 +2047,11 @@ async function runSubagent(
1893
2047
  if (node.children.every((child) => child.status === "completed")) node.status = "completed";
1894
2048
  else if (node.children.some((child) => child.status === "running")) node.status = "running";
1895
2049
  else if (node.children.some((child) => child.status === "stopped")) node.status = "stopped";
2050
+ else if (node.children.some((child) => child.status === "rejected")) node.status = "rejected";
1896
2051
  else if (node.children.some((child) => child.status === "failed")) node.status = "failed";
1897
2052
  else if (node.children.some((child) => child.status === "paused")) node.status = "paused";
1898
2053
  }
1899
- if (node.error && node.status !== "stopped") node.status = "failed";
2054
+ if (node.error && node.status !== "stopped" && node.status !== "rejected") node.status = "failed";
1900
2055
  };
1901
2056
  for (const node of graph.nodes) updateNode(node);
1902
2057
  statusPayload.workflowGraph = graph;
@@ -2544,6 +2699,7 @@ async function runSubagent(
2544
2699
  const totalInput = statusPayload.totalTokens?.input ?? 0;
2545
2700
  const totalOutput = statusPayload.totalTokens?.output ?? 0;
2546
2701
  statusPayload.totalTokens = { input: totalInput + input, output: totalOutput + output, total: totalInput + totalOutput + input + output };
2702
+ refreshUsageBudget();
2547
2703
  }
2548
2704
  statusPayload.turnCount = Math.max(statusPayload.turnCount ?? 0, step.turnCount);
2549
2705
  updateStepTurnBudget(
@@ -2729,6 +2885,10 @@ async function runSubagent(
2729
2885
  onInterrupt: interruptRunner,
2730
2886
  onTimeout: timeoutRunner,
2731
2887
  onStop: stopRunner,
2888
+ onCheckpointDecision: (decision) => {
2889
+ pendingCheckpointDecision = decision;
2890
+ wakeCheckpointDecision?.();
2891
+ },
2732
2892
  onSteer: (request) => {
2733
2893
  const targetStep = request.targetIndex !== undefined ? statusPayload.steps[request.targetIndex] : undefined;
2734
2894
  if (targetStep?.status === "pending") {
@@ -2779,14 +2939,95 @@ async function runSubagent(
2779
2939
 
2780
2940
  let flatIndex = 0;
2781
2941
  let stepCursor = 0;
2942
+ const waitForCheckpointDecision = async (): Promise<"approved" | "rejected" | undefined> => {
2943
+ while (!pendingCheckpointDecision && !interrupted && !timedOut && !stopped) {
2944
+ await new Promise<void>((resolve) => {
2945
+ wakeCheckpointDecision = resolve;
2946
+ const timer = setTimeout(resolve, POLL_INTERVAL_MS);
2947
+ timer.unref?.();
2948
+ });
2949
+ wakeCheckpointDecision = undefined;
2950
+ }
2951
+ const decision = pendingCheckpointDecision;
2952
+ pendingCheckpointDecision = undefined;
2953
+ return decision;
2954
+ };
2782
2955
 
2783
2956
  while (true) {
2784
2957
  if (interrupted || timedOut || stopped || turnBudgetExceeded) break;
2785
2958
  consumePendingAppendRequests();
2786
2959
  if (stepCursor >= steps.length) break;
2960
+ refreshUsageBudget();
2961
+ if (statusPayload.usageBudget?.exhausted) {
2962
+ usageBudgetExceeded = true;
2963
+ statusPayload.state = "failed";
2964
+ statusPayload.error = usageBudgetExceededMessage(statusPayload.usageBudget);
2965
+ statusPayload.currentStep = flatIndex;
2966
+ statusPayload.lastUpdate = Date.now();
2967
+ writeStatusPayload();
2968
+ break;
2969
+ }
2787
2970
  const stepIndex = stepCursor++;
2788
2971
  const step = steps[stepIndex]!;
2789
2972
 
2973
+ if (isCheckpointRunnerStep(step)) {
2974
+ const now = Date.now();
2975
+ const statusStep = statusPayload.steps[flatIndex];
2976
+ const checkpoint = { name: step.checkpoint, ...(step.message ? { message: step.message } : {}), status: "pending" as const, stepIndex };
2977
+ statusPayload.state = "paused";
2978
+ statusPayload.currentStep = flatIndex;
2979
+ statusPayload.checkpoint = checkpoint;
2980
+ statusPayload.activityState = undefined;
2981
+ statusPayload.lastUpdate = now;
2982
+ if (statusStep) {
2983
+ statusStep.status = "paused";
2984
+ statusStep.startedAt = now;
2985
+ statusStep.checkpoint = checkpoint;
2986
+ }
2987
+ writeStatusPayload();
2988
+ appendJsonl(eventsPath, JSON.stringify({ type: "subagent.checkpoint.paused", ts: now, runId: id, stepIndex, checkpoint }));
2989
+ const decision = await waitForCheckpointDecision();
2990
+ if (decision === "approved") {
2991
+ const approvedAt = Date.now();
2992
+ const approved = { ...checkpoint, status: "approved" as const, approvedAt };
2993
+ statusPayload.state = "running";
2994
+ statusPayload.checkpoint = approved;
2995
+ if (statusStep) {
2996
+ statusStep.status = "complete";
2997
+ statusStep.endedAt = approvedAt;
2998
+ statusStep.durationMs = approvedAt - now;
2999
+ statusStep.exitCode = 0;
3000
+ statusStep.checkpoint = approved;
3001
+ }
3002
+ statusPayload.lastUpdate = approvedAt;
3003
+ writeStatusPayload();
3004
+ appendJsonl(eventsPath, JSON.stringify({ type: "subagent.checkpoint.approved", ts: approvedAt, runId: id, stepIndex, checkpoint: approved }));
3005
+ flatIndex++;
3006
+ continue;
3007
+ }
3008
+ if (decision === "rejected") {
3009
+ const rejectedAt = Date.now();
3010
+ const rejected = { ...checkpoint, status: "rejected" as const, rejectedAt };
3011
+ checkpointRejected = true;
3012
+ statusPayload.state = "rejected";
3013
+ statusPayload.error = `Checkpoint '${step.checkpoint}' rejected.`;
3014
+ statusPayload.checkpoint = rejected;
3015
+ if (statusStep) {
3016
+ statusStep.status = "rejected";
3017
+ statusStep.error = statusPayload.error;
3018
+ statusStep.endedAt = rejectedAt;
3019
+ statusStep.durationMs = rejectedAt - now;
3020
+ statusStep.exitCode = 1;
3021
+ statusStep.checkpoint = rejected;
3022
+ }
3023
+ statusPayload.lastUpdate = rejectedAt;
3024
+ writeStatusPayload();
3025
+ appendJsonl(eventsPath, JSON.stringify({ type: "subagent.checkpoint.rejected", ts: rejectedAt, runId: id, stepIndex, checkpoint: rejected }));
3026
+ break;
3027
+ }
3028
+ break;
3029
+ }
3030
+
2790
3031
  if (isDynamicRunnerGroup(step)) {
2791
3032
  const groupStartFlatIndex = flatIndex;
2792
3033
  let materialized: ReturnType<typeof materializeDynamicParallelStep>;
@@ -2931,12 +3172,14 @@ async function runSubagent(
2931
3172
  const transcriptPath = resolveAsyncStepTranscriptPath({ artifactsDir, artifactConfig, runId: id, agent: task.agent, flatIndex: groupStartFlatIndex + itemIndex, flatStepCount: dynamicFlatStepCount });
2932
3173
  return {
2933
3174
  agent: task.agent,
3175
+ ...(statusStepDescription(task.task) ? { description: statusStepDescription(task.task) } : {}),
2934
3176
  ...(task.context ? { context: task.context } : {}),
2935
3177
  phase: task.phase ?? step.phase,
2936
3178
  label: task.label,
2937
3179
  outputName: undefined,
2938
3180
  structured: Boolean(task.structuredOutputSchema),
2939
3181
  ...(task.agentContract ? { agentContract: task.agentContract } : {}),
3182
+ ...(task.launchResolvedExtensions ? { launchResolvedExtensions: task.launchResolvedExtensions } : {}),
2940
3183
  ...(task.capabilityCeiling ? { capabilityCeiling: task.capabilityCeiling } : {}),
2941
3184
  status: "pending",
2942
3185
  ...(task.sessionFile ? { sessionFile: task.sessionFile } : {}),
@@ -2997,6 +3240,22 @@ async function runSubagent(
2997
3240
  let aborted = false;
2998
3241
  const parallelResults = await mapConcurrent(dynamicSteps, concurrency, async (task, taskIdx) => {
2999
3242
  const fi = groupStartFlatIndex + taskIdx;
3243
+ refreshUsageBudget();
3244
+ if (statusPayload.usageBudget?.exhausted) {
3245
+ const skippedAt = Date.now();
3246
+ const message = usageBudgetExceededMessage(statusPayload.usageBudget);
3247
+ statusPayload.steps[fi].status = "failed";
3248
+ statusPayload.steps[fi].error = message;
3249
+ statusPayload.steps[fi].startedAt = skippedAt;
3250
+ statusPayload.steps[fi].endedAt = skippedAt;
3251
+ statusPayload.steps[fi].durationMs = 0;
3252
+ statusPayload.steps[fi].exitCode = 1;
3253
+ statusPayload.lastUpdate = skippedAt;
3254
+ usageBudgetExceeded = true;
3255
+ writeStatusPayload();
3256
+ appendJsonl(eventsPath, JSON.stringify({ type: "subagent.step.failed", ts: skippedAt, runId: id, stepIndex: fi, agent: task.agent, exitCode: 1, durationMs: 0 }));
3257
+ return { agent: task.agent, context: task.context, output: message, error: message, exitCode: 1 as number | null, skipped: true };
3258
+ }
3000
3259
  if (timedOut) return timedOutStepResult(task.agent, task.context);
3001
3260
  if (stopped) return stoppedStepResult(task.agent, task.context);
3002
3261
  if (interrupted) return pausedStepResult(task.agent, task.context);
@@ -3080,11 +3339,21 @@ async function runSubagent(
3080
3339
  statusPayload.steps[fi].attemptedModels = singleResult.attemptedModels;
3081
3340
  statusPayload.steps[fi].modelAttempts = singleResult.modelAttempts;
3082
3341
  statusPayload.steps[fi].totalCost = singleResult.totalCost;
3342
+ if (singleResult.totalCost) {
3343
+ pendingParallelUsageCost = {
3344
+ inputTokens: pendingParallelUsageCost.inputTokens + singleResult.totalCost.inputTokens,
3345
+ outputTokens: pendingParallelUsageCost.outputTokens + singleResult.totalCost.outputTokens,
3346
+ costUsd: pendingParallelUsageCost.costUsd + singleResult.totalCost.costUsd,
3347
+ };
3348
+ refreshUsageBudget();
3349
+ }
3083
3350
  statusPayload.steps[fi].error = stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error;
3084
3351
  statusPayload.steps[fi].transcriptPath = singleResult.transcriptPath ?? statusPayload.steps[fi].transcriptPath;
3085
3352
  statusPayload.steps[fi].transcriptError = singleResult.transcriptError;
3086
3353
  statusPayload.steps[fi].agentContract = singleResult.agentContract;
3087
3354
  statusPayload.steps[fi].launchContractDigest = singleResult.launchContractDigest;
3355
+ statusPayload.steps[fi].launchResolvedExtensions = singleResult.launchResolvedExtensions;
3356
+ statusPayload.steps[fi].runtimeAcknowledgedExtensions = singleResult.runtimeAcknowledgedExtensions;
3088
3357
  statusPayload.steps[fi].effects = singleResult.effects;
3089
3358
  statusPayload.steps[fi].execution = singleResult.execution;
3090
3359
  statusPayload.steps[fi].review = singleResult.review;
@@ -3116,7 +3385,10 @@ async function runSubagent(
3116
3385
  context: pr.context,
3117
3386
  agentContract: pr.agentContract,
3118
3387
  launchContractDigest: pr.launchContractDigest,
3388
+ launchResolvedExtensions: pr.launchResolvedExtensions,
3389
+ runtimeAcknowledgedExtensions: pr.runtimeAcknowledgedExtensions,
3119
3390
  output: pr.output,
3391
+ outputState: pr.outputState,
3120
3392
  error: pr.error,
3121
3393
  protocolError: pr.protocolError,
3122
3394
  success: pr.stopped !== true && pr.interrupted !== true && pr.exitCode === 0,
@@ -3151,6 +3423,8 @@ async function runSubagent(
3151
3423
  capabilityAudit: pr.capabilityAudit,
3152
3424
  });
3153
3425
  }
3426
+ pendingParallelUsageCost = { inputTokens: 0, outputTokens: 0, costUsd: 0 };
3427
+ refreshUsageBudget();
3154
3428
  const collection = collectDynamicResults(step as Parameters<typeof collectDynamicResults>[0], materialized.items, parallelResults);
3155
3429
  const failures = parallelResults.filter((result) => result.exitCode !== 0 && result.exitCode !== -1);
3156
3430
  const acceptanceFailures = parallelResults
@@ -3316,6 +3590,25 @@ async function runSubagent(
3316
3590
  concurrency,
3317
3591
  async (task, taskIdx) => {
3318
3592
  const fi = groupStartFlatIndex + taskIdx;
3593
+ refreshUsageBudget();
3594
+ if (statusPayload.usageBudget?.exhausted) {
3595
+ const skippedAt = Date.now();
3596
+ const message = usageBudgetExceededMessage(statusPayload.usageBudget);
3597
+ statusPayload.steps[fi].status = "failed";
3598
+ statusPayload.steps[fi].error = message;
3599
+ statusPayload.steps[fi].startedAt = skippedAt;
3600
+ statusPayload.steps[fi].endedAt = skippedAt;
3601
+ statusPayload.steps[fi].durationMs = 0;
3602
+ statusPayload.steps[fi].exitCode = 1;
3603
+ statusPayload.steps[fi].activityState = undefined;
3604
+ statusPayload.lastUpdate = skippedAt;
3605
+ usageBudgetExceeded = true;
3606
+ writeStatusPayload();
3607
+ appendJsonl(eventsPath, JSON.stringify({
3608
+ type: "subagent.step.failed", ts: skippedAt, runId: id, stepIndex: fi, agent: task.agent, exitCode: 1, durationMs: 0,
3609
+ }));
3610
+ return { agent: task.agent, context: task.context, output: message, error: message, exitCode: 1 as number | null, skipped: true };
3611
+ }
3319
3612
  if (timedOut) return timedOutStepResult(task.agent, task.context);
3320
3613
  if (stopped) return stoppedStepResult(task.agent, task.context);
3321
3614
  if (interrupted) return pausedStepResult(task.agent, task.context);
@@ -3421,10 +3714,20 @@ async function runSubagent(
3421
3714
  statusPayload.steps[fi].attemptedModels = singleResult.attemptedModels;
3422
3715
  statusPayload.steps[fi].modelAttempts = singleResult.modelAttempts;
3423
3716
  statusPayload.steps[fi].totalCost = singleResult.totalCost;
3717
+ if (singleResult.totalCost) {
3718
+ pendingParallelUsageCost = {
3719
+ inputTokens: pendingParallelUsageCost.inputTokens + singleResult.totalCost.inputTokens,
3720
+ outputTokens: pendingParallelUsageCost.outputTokens + singleResult.totalCost.outputTokens,
3721
+ costUsd: pendingParallelUsageCost.costUsd + singleResult.totalCost.costUsd,
3722
+ };
3723
+ refreshUsageBudget();
3724
+ }
3424
3725
  statusPayload.steps[fi].error = stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error;
3425
3726
  statusPayload.steps[fi].transcriptPath = singleResult.transcriptPath ?? statusPayload.steps[fi].transcriptPath;
3426
3727
  statusPayload.steps[fi].transcriptError = singleResult.transcriptError;
3427
3728
  statusPayload.steps[fi].agentContract = singleResult.agentContract;
3729
+ statusPayload.steps[fi].launchResolvedExtensions = singleResult.launchResolvedExtensions;
3730
+ statusPayload.steps[fi].runtimeAcknowledgedExtensions = singleResult.runtimeAcknowledgedExtensions;
3428
3731
  statusPayload.steps[fi].effects = singleResult.effects;
3429
3732
  statusPayload.steps[fi].execution = singleResult.execution;
3430
3733
  statusPayload.steps[fi].review = singleResult.review;
@@ -3492,7 +3795,9 @@ async function runSubagent(
3492
3795
  context: pr.context,
3493
3796
  agentContract: pr.agentContract,
3494
3797
  launchContractDigest: pr.launchContractDigest,
3798
+ launchResolvedExtensions: pr.launchResolvedExtensions,
3495
3799
  output: pr.output,
3800
+ outputState: pr.outputState,
3496
3801
  error: pr.error,
3497
3802
  protocolError: pr.protocolError,
3498
3803
  success: pr.stopped !== true && pr.interrupted !== true && pr.exitCode === 0,
@@ -3525,6 +3830,8 @@ async function runSubagent(
3525
3830
  watchdog: pr.watchdog,
3526
3831
  });
3527
3832
  }
3833
+ pendingParallelUsageCost = { inputTokens: 0, outputTokens: 0, costUsd: 0 };
3834
+ refreshUsageBudget();
3528
3835
  for (let t = 0; t < group.parallel.length; t++) {
3529
3836
  const outputName = group.parallel[t]?.outputName;
3530
3837
  if (outputName) outputs[outputName] = outputEntryFromAsyncResult({
@@ -3564,7 +3871,13 @@ async function runSubagent(
3564
3871
  cleanup,
3565
3872
  results: parallelResults.map((result) => ({
3566
3873
  agent: result.agent,
3567
- status: result.stopped ? "stopped" : result.interrupted ? "paused" : result.exitCode === 0 ? "completed" : "failed",
3874
+ status: result.stopped || (result.exitCode !== 0 && isUnexplainedProcessSignal({
3875
+ processSignal: result.processSignal,
3876
+ interrupted: result.interrupted,
3877
+ timedOut: result.timedOut,
3878
+ stopped: result.stopped,
3879
+ turnBudgetExceeded: result.turnBudgetExceeded,
3880
+ })) ? "stopped" : result.interrupted ? "paused" : result.exitCode === 0 ? "completed" : "failed",
3568
3881
  summary: result.output || result.error || "(no output)",
3569
3882
  ...(result.artifactPaths?.outputPath ? { outputPath: result.artifactPaths.outputPath } : {}),
3570
3883
  ...(result.structuredOutput !== undefined ? { structuredOutput: result.structuredOutput } : {}),
@@ -3668,7 +3981,10 @@ async function runSubagent(
3668
3981
  context: singleResult.context,
3669
3982
  agentContract: singleResult.agentContract,
3670
3983
  launchContractDigest: singleResult.launchContractDigest,
3984
+ launchResolvedExtensions: singleResult.launchResolvedExtensions,
3985
+ runtimeAcknowledgedExtensions: singleResult.runtimeAcknowledgedExtensions,
3671
3986
  output: stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.output,
3987
+ outputState: singleResult.outputState,
3672
3988
  error: stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error,
3673
3989
  protocolError: singleResult.protocolError,
3674
3990
  success: !stopped && !childStopped && !timedOut && singleResult.interrupted !== true && singleResult.exitCode === 0,
@@ -3758,6 +4074,8 @@ async function runSubagent(
3758
4074
  statusPayload.steps[flatIndex].transcriptPath = singleResult.transcriptPath ?? statusPayload.steps[flatIndex].transcriptPath;
3759
4075
  statusPayload.steps[flatIndex].transcriptError = singleResult.transcriptError;
3760
4076
  statusPayload.steps[flatIndex].agentContract = singleResult.agentContract;
4077
+ statusPayload.steps[flatIndex].launchResolvedExtensions = singleResult.launchResolvedExtensions;
4078
+ statusPayload.steps[flatIndex].runtimeAcknowledgedExtensions = singleResult.runtimeAcknowledgedExtensions;
3761
4079
  statusPayload.steps[flatIndex].effects = singleResult.effects;
3762
4080
  statusPayload.steps[flatIndex].execution = singleResult.execution;
3763
4081
  statusPayload.steps[flatIndex].review = singleResult.review;
@@ -3828,6 +4146,7 @@ async function runSubagent(
3828
4146
  }
3829
4147
 
3830
4148
  const resultMode = config.resultMode ?? statusPayload.mode;
4149
+ const singleRuntimeAcknowledgedExtensions = results.length === 1 ? results[0]?.runtimeAcknowledgedExtensions : undefined;
3831
4150
  const totalCost = results.reduce<CostSummary>((sum, result) => ({
3832
4151
  inputTokens: sum.inputTokens + (result.totalCost?.inputTokens ?? 0),
3833
4152
  outputTokens: sum.outputTokens + (result.totalCost?.outputTokens ?? 0),
@@ -3878,7 +4197,14 @@ async function runSubagent(
3878
4197
  clearTimeout(timeoutTimer);
3879
4198
  timeoutTimer = undefined;
3880
4199
  }
3881
- statusPayload.state = stopped ? "stopped" : timedOut || turnBudgetExceeded || statusPayload.error ? "failed" : interrupted ? "paused" : results.every((r) => r.success) ? "complete" : "failed";
4200
+ const signalTerminated = !stopped && !timedOut && !turnBudgetExceeded && !interrupted && results.some((result) => result.exitCode !== 0 && isUnexplainedProcessSignal({
4201
+ processSignal: result.processSignal,
4202
+ interrupted: result.interrupted,
4203
+ timedOut: result.timedOut,
4204
+ stopped: result.stopped,
4205
+ turnBudgetExceeded: result.turnBudgetExceeded,
4206
+ }));
4207
+ statusPayload.state = checkpointRejected ? "rejected" : stopped || signalTerminated ? "stopped" : timedOut || turnBudgetExceeded || usageBudgetExceeded || statusPayload.error ? "failed" : interrupted ? "paused" : results.every((r) => r.success) ? "complete" : "failed";
3882
4208
  closeSteerInbox(asyncDir, statusPayload.state);
3883
4209
  disposeControlInbox();
3884
4210
  for (const request of consumeSteerRequests(asyncDir)) deliverSteerRequest(request);
@@ -3900,6 +4226,8 @@ async function runSubagent(
3900
4226
  if (stopped) {
3901
4227
  statusPayload.stopped = true;
3902
4228
  statusPayload.error = stopMessage;
4229
+ } else if (signalTerminated && !statusPayload.error) {
4230
+ statusPayload.error = results.find((result) => result.processSignal)?.error;
3903
4231
  }
3904
4232
  if (timedOut) {
3905
4233
  statusPayload.timedOut = true;
@@ -3909,10 +4237,15 @@ async function runSubagent(
3909
4237
  const budget = statusPayload.turnBudget;
3910
4238
  statusPayload.error = budget ? turnBudgetExceededMessage(budget, budget.turnCount) : "Subagent exceeded turn budget.";
3911
4239
  }
4240
+ if (usageBudgetExceeded && statusPayload.usageBudget && !statusPayload.error) {
4241
+ statusPayload.error = usageBudgetExceededMessage(statusPayload.usageBudget);
4242
+ }
3912
4243
  statusPayload.endedAt = runEndedAt;
3913
4244
  statusPayload.lastUpdate = runEndedAt;
3914
4245
  statusPayload.sessionFile = effectiveSessionFile;
4246
+ if (singleRuntimeAcknowledgedExtensions) statusPayload.runtimeAcknowledgedExtensions = singleRuntimeAcknowledgedExtensions;
3915
4247
  statusPayload.totalCost = finalTotalCost;
4248
+ statusPayload.usageBudget = usageBudgetState(config.usageBudget, currentUsageTotals());
3916
4249
  statusPayload.shareUrl = shareUrl;
3917
4250
  statusPayload.gistUrl = gistUrl;
3918
4251
  statusPayload.shareError = shareError;
@@ -3934,6 +4267,7 @@ async function runSubagent(
3934
4267
  durationMs: runEndedAt - overallStartTime,
3935
4268
  totalTokens: statusPayload.totalTokens,
3936
4269
  totalCost: finalTotalCost,
4270
+ usageBudget: statusPayload.usageBudget,
3937
4271
  }),
3938
4272
  );
3939
4273
  writeRunLog(logPath, {
@@ -3961,9 +4295,9 @@ async function runSubagent(
3961
4295
  id,
3962
4296
  agent: agentName,
3963
4297
  mode: resultMode,
3964
- success: !stopped && !timedOut && !turnBudgetExceeded && !interrupted && results.every((r) => r.success),
3965
- state: stopped ? "stopped" : timedOut || turnBudgetExceeded ? "failed" : interrupted ? "paused" : results.every((r) => r.success) ? "complete" : "failed",
3966
- summary: stopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : turnBudgetExceeded ? (statusPayload.error ?? "Subagent exceeded turn budget.") : interrupted ? "Paused after interrupt. Waiting for explicit next action." : summary,
4298
+ success: !checkpointRejected && !stopped && !timedOut && !turnBudgetExceeded && !usageBudgetExceeded && !interrupted && !signalTerminated && results.every((r) => r.success),
4299
+ state: checkpointRejected ? "rejected" : stopped || signalTerminated ? "stopped" : timedOut || turnBudgetExceeded || usageBudgetExceeded ? "failed" : interrupted ? "paused" : results.every((r) => r.success) ? "complete" : "failed",
4300
+ summary: checkpointRejected ? (statusPayload.error ?? "Checkpoint rejected.") : stopped ? stopMessage : signalTerminated ? (statusPayload.error ?? "Subagent process terminated by signal.") : timedOut ? (timeoutMessage ?? "Subagent timed out.") : turnBudgetExceeded ? (statusPayload.error ?? "Subagent exceeded turn budget.") : usageBudgetExceeded ? (statusPayload.error ?? "Usage budget exhausted.") : interrupted ? "Paused after interrupt. Waiting for explicit next action." : summary,
3967
4301
  ...(config.timeoutMs !== undefined ? { timeoutMs: config.timeoutMs } : {}),
3968
4302
  ...(config.deadlineAt !== undefined ? { deadlineAt: config.deadlineAt } : {}),
3969
4303
  ...(statusPayload.turnBudget ? { turnBudget: statusPayload.turnBudget } : {}),
@@ -3971,11 +4305,14 @@ async function runSubagent(
3971
4305
  ...(statusPayload.wrapUpRequested ? { wrapUpRequested: true } : {}),
3972
4306
  ...(statusPayload.toolBudget ? { toolBudget: statusPayload.toolBudget } : {}),
3973
4307
  ...(statusPayload.toolBudgetBlocked ? { toolBudgetBlocked: true } : {}),
3974
- ...(stopped ? { stopped: true, error: stopMessage } : timedOut ? { timedOut: true, error: timeoutMessage ?? "Subagent timed out." } : turnBudgetExceeded ? { error: statusPayload.error ?? "Subagent exceeded turn budget." } : {}),
4308
+ ...(statusPayload.usageBudget ? { usageBudget: statusPayload.usageBudget } : {}),
4309
+ ...(statusPayload.checkpoint ? { checkpoint: statusPayload.checkpoint } : {}),
4310
+ ...(stopped ? { stopped: true, error: stopMessage } : timedOut ? { timedOut: true, error: timeoutMessage ?? "Subagent timed out." } : turnBudgetExceeded ? { error: statusPayload.error ?? "Subagent exceeded turn budget." } : usageBudgetExceeded ? { error: statusPayload.error ?? "Usage budget exhausted." } : {}),
3975
4311
  results: results.map((r) => ({
3976
4312
  agent: r.agent,
3977
4313
  context: r.context,
3978
4314
  output: r.output,
4315
+ outputState: r.outputState,
3979
4316
  error: r.error,
3980
4317
  protocolError: r.protocolError,
3981
4318
  success: r.success,
@@ -3983,6 +4320,7 @@ async function runSubagent(
3983
4320
  interrupted: r.interrupted || undefined,
3984
4321
  timedOut: r.timedOut || undefined,
3985
4322
  stopped: r.stopped || undefined,
4323
+ processSignal: r.processSignal || undefined,
3986
4324
  turnBudget: r.turnBudget,
3987
4325
  turnBudgetExceeded: r.turnBudgetExceeded || undefined,
3988
4326
  wrapUpRequested: r.wrapUpRequested || undefined,
@@ -4000,6 +4338,8 @@ async function runSubagent(
4000
4338
  transcriptError: r.transcriptError,
4001
4339
  agentContract: r.agentContract,
4002
4340
  launchContractDigest: r.launchContractDigest,
4341
+ launchResolvedExtensions: r.launchResolvedExtensions,
4342
+ runtimeAcknowledgedExtensions: r.runtimeAcknowledgedExtensions,
4003
4343
  execution: r.execution,
4004
4344
  review: r.review,
4005
4345
  effects: r.effects,
@@ -4016,16 +4356,20 @@ async function runSubagent(
4016
4356
  parallelHandoff: statusPayload.parallelHandoff,
4017
4357
  capabilityCeiling: statusPayload.capabilityCeiling,
4018
4358
  capabilityAudit: statusPayload.capabilityAudit,
4019
- exitCode: stopped || timedOut || turnBudgetExceeded ? 1 : interrupted || results.every((r) => r.success) ? 0 : 1,
4359
+ exitCode: checkpointRejected || stopped || timedOut || turnBudgetExceeded || usageBudgetExceeded ? 1 : interrupted || results.every((r) => r.success) ? 0 : 1,
4020
4360
  timestamp: runEndedAt,
4021
4361
  durationMs: runEndedAt - overallStartTime,
4022
4362
  totalTokens: statusPayload.totalTokens,
4023
4363
  totalCost: finalTotalCost,
4364
+ usageBudget: statusPayload.usageBudget,
4365
+ checkpoint: statusPayload.checkpoint,
4024
4366
  truncated,
4025
4367
  artifactsDir,
4026
4368
  cwd,
4027
4369
  asyncDir,
4028
4370
  launchContractDigest: config.launchContractDigest,
4371
+ launchResolvedExtensions: config.launchResolvedExtensions,
4372
+ runtimeAcknowledgedExtensions: singleRuntimeAcknowledgedExtensions,
4029
4373
  sessionId: config.sessionId,
4030
4374
  sessionFile: effectiveSessionFile,
4031
4375
  intercomTarget: config.controlIntercomTarget,