@selesai/code 0.6.2 → 0.7.0

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 (997) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/README.md +1 -1
  3. package/dist/bun/cli.d.ts +0 -1
  4. package/dist/bun/cli.js +0 -1
  5. package/dist/bun/register-bedrock.d.ts +0 -1
  6. package/dist/bun/register-bedrock.js +0 -1
  7. package/dist/bun/restore-sandbox-env.d.ts +0 -1
  8. package/dist/bun/restore-sandbox-env.js +0 -1
  9. package/dist/cli/args.d.ts +0 -1
  10. package/dist/cli/args.js +0 -1
  11. package/dist/cli/config-selector.d.ts +0 -1
  12. package/dist/cli/config-selector.js +0 -1
  13. package/dist/cli/credential-print.d.ts +0 -1
  14. package/dist/cli/credential-print.js +0 -1
  15. package/dist/cli/file-processor.d.ts +0 -1
  16. package/dist/cli/file-processor.js +0 -1
  17. package/dist/cli/initial-message.d.ts +0 -1
  18. package/dist/cli/initial-message.js +0 -1
  19. package/dist/cli/list-models.d.ts +0 -1
  20. package/dist/cli/list-models.js +0 -1
  21. package/dist/cli/project-trust.d.ts +0 -1
  22. package/dist/cli/project-trust.js +0 -1
  23. package/dist/cli/session-picker.d.ts +0 -1
  24. package/dist/cli/session-picker.js +0 -1
  25. package/dist/cli/startup-ui.d.ts +0 -1
  26. package/dist/cli/startup-ui.js +0 -1
  27. package/dist/cli.d.ts +0 -1
  28. package/dist/cli.js +0 -1
  29. package/dist/config.d.ts +0 -1
  30. package/dist/config.js +0 -1
  31. package/dist/core/agent-session-auto-handoff.test.d.ts +0 -1
  32. package/dist/core/agent-session-auto-handoff.test.js +0 -1
  33. package/dist/core/agent-session-runtime.d.ts +0 -1
  34. package/dist/core/agent-session-runtime.js +0 -1
  35. package/dist/core/agent-session-services.d.ts +0 -1
  36. package/dist/core/agent-session-services.js +0 -1
  37. package/dist/core/agent-session-skill-block.test.d.ts +0 -1
  38. package/dist/core/agent-session-skill-block.test.js +0 -1
  39. package/dist/core/agent-session.d.ts +0 -1
  40. package/dist/core/agent-session.js +0 -1
  41. package/dist/core/agents.d.ts +0 -1
  42. package/dist/core/agents.js +0 -1
  43. package/dist/core/auth-guidance.d.ts +0 -1
  44. package/dist/core/auth-guidance.js +0 -1
  45. package/dist/core/auth-storage.d.ts +0 -1
  46. package/dist/core/auth-storage.js +0 -1
  47. package/dist/core/bash-executor.d.ts +0 -1
  48. package/dist/core/bash-executor.js +0 -1
  49. package/dist/core/built-in-extensions.d.ts +0 -1
  50. package/dist/core/built-in-extensions.js +0 -1
  51. package/dist/core/cache-stats.d.ts +0 -1
  52. package/dist/core/cache-stats.js +0 -1
  53. package/dist/core/compaction/branch-summarization.d.ts +0 -1
  54. package/dist/core/compaction/branch-summarization.js +0 -1
  55. package/dist/core/compaction/compaction.d.ts +0 -1
  56. package/dist/core/compaction/compaction.js +0 -1
  57. package/dist/core/compaction/index.d.ts +0 -1
  58. package/dist/core/compaction/index.js +0 -1
  59. package/dist/core/compaction/utils.d.ts +0 -1
  60. package/dist/core/compaction/utils.js +0 -1
  61. package/dist/core/defaults.d.ts +0 -1
  62. package/dist/core/defaults.js +0 -1
  63. package/dist/core/diagnostics.d.ts +0 -1
  64. package/dist/core/diagnostics.js +0 -1
  65. package/dist/core/event-bus.d.ts +0 -1
  66. package/dist/core/event-bus.js +0 -1
  67. package/dist/core/exec.d.ts +0 -1
  68. package/dist/core/exec.js +0 -1
  69. package/dist/core/experimental.d.ts +0 -1
  70. package/dist/core/experimental.js +0 -1
  71. package/dist/core/export-html/ansi-to-html.d.ts +0 -1
  72. package/dist/core/export-html/ansi-to-html.js +0 -1
  73. package/dist/core/export-html/index.d.ts +0 -1
  74. package/dist/core/export-html/index.js +0 -1
  75. package/dist/core/export-html/tool-renderer.d.ts +0 -1
  76. package/dist/core/export-html/tool-renderer.js +0 -1
  77. package/dist/core/extensions/index.d.ts +0 -1
  78. package/dist/core/extensions/index.js +0 -1
  79. package/dist/core/extensions/loader.d.ts +0 -1
  80. package/dist/core/extensions/loader.js +0 -1
  81. package/dist/core/extensions/runner.d.ts +0 -1
  82. package/dist/core/extensions/runner.js +0 -1
  83. package/dist/core/extensions/types.d.ts +0 -1
  84. package/dist/core/extensions/types.js +0 -1
  85. package/dist/core/extensions/wrapper.d.ts +0 -1
  86. package/dist/core/extensions/wrapper.js +0 -1
  87. package/dist/core/footer-data-provider.d.ts +0 -1
  88. package/dist/core/footer-data-provider.js +0 -1
  89. package/dist/core/git-command.d.ts +0 -1
  90. package/dist/core/git-command.js +0 -1
  91. package/dist/core/http-dispatcher.d.ts +0 -1
  92. package/dist/core/http-dispatcher.js +0 -1
  93. package/dist/core/index.d.ts +0 -1
  94. package/dist/core/index.js +0 -1
  95. package/dist/core/keybindings.d.ts +0 -1
  96. package/dist/core/keybindings.js +0 -1
  97. package/dist/core/llama/client.d.ts +0 -1
  98. package/dist/core/llama/client.js +0 -1
  99. package/dist/core/llama/huggingface.d.ts +0 -1
  100. package/dist/core/llama/huggingface.js +0 -1
  101. package/dist/core/llama/index.d.ts +0 -1
  102. package/dist/core/llama/index.js +0 -1
  103. package/dist/core/llama/provider.d.ts +0 -1
  104. package/dist/core/llama/provider.js +0 -1
  105. package/dist/core/llama/ui.d.ts +0 -1
  106. package/dist/core/llama/ui.js +0 -1
  107. package/dist/core/messages.d.ts +0 -1
  108. package/dist/core/messages.js +0 -1
  109. package/dist/core/model-config.d.ts +0 -1
  110. package/dist/core/model-config.js +0 -1
  111. package/dist/core/model-registry.d.ts +0 -1
  112. package/dist/core/model-registry.js +0 -1
  113. package/dist/core/model-resolver.d.ts +0 -1
  114. package/dist/core/model-resolver.js +0 -1
  115. package/dist/core/model-runtime.d.ts +0 -1
  116. package/dist/core/model-runtime.js +0 -1
  117. package/dist/core/models-store.d.ts +0 -1
  118. package/dist/core/models-store.js +0 -1
  119. package/dist/core/output-guard.d.ts +0 -1
  120. package/dist/core/output-guard.js +0 -1
  121. package/dist/core/package-manager.d.ts +0 -1
  122. package/dist/core/package-manager.js +0 -1
  123. package/dist/core/package-manager.test.d.ts +0 -1
  124. package/dist/core/package-manager.test.js +0 -1
  125. package/dist/core/project-trust.d.ts +0 -1
  126. package/dist/core/project-trust.js +0 -1
  127. package/dist/core/prompt-templates.d.ts +0 -1
  128. package/dist/core/prompt-templates.js +0 -1
  129. package/dist/core/provider-attribution.d.ts +0 -1
  130. package/dist/core/provider-attribution.js +0 -1
  131. package/dist/core/provider-composer.d.ts +0 -1
  132. package/dist/core/provider-composer.js +0 -1
  133. package/dist/core/radius.d.ts +0 -1
  134. package/dist/core/radius.js +0 -1
  135. package/dist/core/remote-catalog-provider.d.ts +0 -1
  136. package/dist/core/remote-catalog-provider.js +0 -1
  137. package/dist/core/resolve-config-value.d.ts +0 -1
  138. package/dist/core/resolve-config-value.js +0 -1
  139. package/dist/core/resource-loader.d.ts +0 -1
  140. package/dist/core/resource-loader.js +0 -1
  141. package/dist/core/runtime-credentials.d.ts +0 -1
  142. package/dist/core/runtime-credentials.js +0 -1
  143. package/dist/core/sdk.d.ts +0 -1
  144. package/dist/core/sdk.js +0 -1
  145. package/dist/core/session-cwd.d.ts +0 -1
  146. package/dist/core/session-cwd.js +0 -1
  147. package/dist/core/session-manager.d.ts +0 -1
  148. package/dist/core/session-manager.js +0 -1
  149. package/dist/core/settings-manager-auto-handoff.test.d.ts +0 -1
  150. package/dist/core/settings-manager-auto-handoff.test.js +0 -1
  151. package/dist/core/settings-manager.d.ts +0 -4
  152. package/dist/core/settings-manager.js +0 -12
  153. package/dist/core/skills.d.ts +0 -1
  154. package/dist/core/skills.js +0 -1
  155. package/dist/core/slash-commands.d.ts +0 -1
  156. package/dist/core/slash-commands.js +0 -1
  157. package/dist/core/source-info.d.ts +0 -1
  158. package/dist/core/source-info.js +0 -1
  159. package/dist/core/system-prompt.d.ts +0 -1
  160. package/dist/core/system-prompt.js +0 -1
  161. package/dist/core/system-prompt.test.d.ts +0 -1
  162. package/dist/core/system-prompt.test.js +0 -1
  163. package/dist/core/telemetry.d.ts +0 -1
  164. package/dist/core/telemetry.js +0 -1
  165. package/dist/core/timings.d.ts +0 -1
  166. package/dist/core/timings.js +0 -1
  167. package/dist/core/tools/bash.d.ts +0 -1
  168. package/dist/core/tools/bash.js +0 -1
  169. package/dist/core/tools/edit-diff.d.ts +0 -1
  170. package/dist/core/tools/edit-diff.js +0 -1
  171. package/dist/core/tools/edit.d.ts +0 -1
  172. package/dist/core/tools/edit.js +0 -1
  173. package/dist/core/tools/file-mutation-queue.d.ts +0 -1
  174. package/dist/core/tools/file-mutation-queue.js +0 -1
  175. package/dist/core/tools/find.d.ts +0 -1
  176. package/dist/core/tools/find.js +0 -1
  177. package/dist/core/tools/grep.d.ts +0 -1
  178. package/dist/core/tools/grep.js +0 -1
  179. package/dist/core/tools/index.d.ts +0 -1
  180. package/dist/core/tools/index.js +0 -1
  181. package/dist/core/tools/ls.d.ts +0 -1
  182. package/dist/core/tools/ls.js +0 -1
  183. package/dist/core/tools/output-accumulator.d.ts +0 -1
  184. package/dist/core/tools/output-accumulator.js +0 -1
  185. package/dist/core/tools/path-utils.d.ts +0 -1
  186. package/dist/core/tools/path-utils.js +0 -1
  187. package/dist/core/tools/read.d.ts +0 -1
  188. package/dist/core/tools/read.js +0 -1
  189. package/dist/core/tools/render-utils.d.ts +0 -1
  190. package/dist/core/tools/render-utils.js +0 -1
  191. package/dist/core/tools/tool-definition-wrapper.d.ts +0 -1
  192. package/dist/core/tools/tool-definition-wrapper.js +0 -1
  193. package/dist/core/tools/truncate.d.ts +0 -1
  194. package/dist/core/tools/truncate.js +0 -1
  195. package/dist/core/tools/write.d.ts +0 -1
  196. package/dist/core/tools/write.js +0 -1
  197. package/dist/core/trust-manager.d.ts +0 -1
  198. package/dist/core/trust-manager.js +0 -1
  199. package/dist/core/usage-totals.d.ts +0 -1
  200. package/dist/core/usage-totals.js +0 -1
  201. package/dist/defaults/models.json +8 -0
  202. package/dist/defaults/settings.json +6 -7
  203. package/dist/extensions/inline-skills.test.ts +13 -13
  204. package/dist/extensions/inline-skills.ts +6 -6
  205. package/dist/extensions/pi-subagents/CHANGELOG.md +89 -12
  206. package/dist/extensions/pi-subagents/README.md +339 -604
  207. package/dist/extensions/pi-subagents/package-lock.json +190 -2079
  208. package/dist/extensions/pi-subagents/package.json +13 -5
  209. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +1 -1
  210. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +1 -1
  211. package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
  212. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +10 -10
  213. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +32 -43
  214. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +106 -105
  215. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +3 -3
  216. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +28 -35
  217. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +167 -124
  218. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
  219. package/dist/extensions/pi-subagents/src/agents/agents.ts +163 -75
  220. package/dist/extensions/pi-subagents/src/agents/chain-serializer.ts +10 -7
  221. package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +5 -3
  222. package/dist/extensions/pi-subagents/src/agents/identity.ts +1 -1
  223. package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +14 -11
  224. package/dist/extensions/pi-subagents/src/agents/skills.ts +23 -6
  225. package/dist/extensions/pi-subagents/src/agents/task-aware-routing.ts +8 -1
  226. package/dist/extensions/pi-subagents/src/api/control-channel.ts +4 -0
  227. package/dist/extensions/pi-subagents/src/api/delegation.ts +26 -194
  228. package/dist/extensions/pi-subagents/src/api/external-runs.ts +129 -0
  229. package/dist/extensions/pi-subagents/src/api/intercom-bridge.ts +3 -0
  230. package/dist/extensions/pi-subagents/src/api/pi-args.ts +5 -0
  231. package/dist/extensions/pi-subagents/src/api/preflight.ts +4 -4
  232. package/dist/extensions/pi-subagents/src/api/shared-types.ts +19 -0
  233. package/dist/extensions/pi-subagents/src/extension/config.ts +10 -0
  234. package/dist/extensions/pi-subagents/src/extension/control-notices.ts +5 -39
  235. package/dist/extensions/pi-subagents/src/extension/doctor.ts +10 -9
  236. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +7 -4
  237. package/dist/extensions/pi-subagents/src/extension/index.ts +243 -77
  238. package/dist/extensions/pi-subagents/src/extension/rpc.ts +18 -6
  239. package/dist/extensions/pi-subagents/src/extension/schemas.ts +50 -39
  240. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +36 -103
  241. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +229 -0
  242. package/dist/extensions/pi-subagents/src/inspectors/herdr/client.ts +130 -0
  243. package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +141 -0
  244. package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +154 -0
  245. package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +330 -0
  246. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +3 -2
  247. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +5 -1
  248. package/dist/extensions/pi-subagents/src/missions/actions.ts +372 -0
  249. package/dist/extensions/pi-subagents/src/missions/lifecycle.ts +314 -0
  250. package/dist/extensions/pi-subagents/src/missions/store.ts +442 -0
  251. package/dist/extensions/pi-subagents/src/missions/types.ts +135 -0
  252. package/dist/extensions/pi-subagents/src/policy/authority.ts +46 -0
  253. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +32 -6
  254. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +103 -72
  255. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +10 -2
  256. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +6 -6
  257. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +29 -1
  258. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +3 -3
  259. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +3 -2
  260. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +9 -7
  261. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +3 -4
  262. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +3 -28
  263. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +5 -5
  264. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +18 -68
  265. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +3 -3
  266. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +35 -8
  267. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +602 -375
  268. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -3
  269. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +612 -464
  270. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +50 -9
  271. package/dist/extensions/pi-subagents/src/runs/background/wait-subscriptions.ts +253 -0
  272. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +12 -4
  273. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +3 -3
  274. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +8 -4
  275. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +74 -102
  276. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +21 -22
  277. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1050 -396
  278. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +44 -18
  279. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +0 -1
  280. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +302 -22
  281. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
  282. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +130 -0
  283. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +42 -1
  284. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +1 -1
  285. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +59 -5
  286. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +9 -4
  287. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +86 -2
  288. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +11 -2
  289. package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +95 -0
  290. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +11 -1
  291. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +15 -6
  292. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +1 -1
  293. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +9 -63
  294. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +37 -6
  295. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +5 -2
  296. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +2 -23
  297. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +6 -6
  298. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +124 -13
  299. package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +29 -7
  300. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +18 -1
  301. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +3 -2
  302. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +1 -0
  303. package/dist/extensions/pi-subagents/src/shared/settings.ts +10 -0
  304. package/dist/extensions/pi-subagents/src/shared/types.ts +158 -55
  305. package/dist/extensions/pi-subagents/src/shared/utils.ts +16 -66
  306. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +33 -199
  307. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +43 -126
  308. package/dist/extensions/pi-subagents/src/slash/inline-subagents.ts +103 -0
  309. package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +158 -205
  310. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +22 -58
  311. package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +14 -0
  312. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +44 -642
  313. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +18 -14
  314. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +156 -21
  315. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +110 -5
  316. package/dist/extensions/pi-subagents/src/tui/fleet.ts +60 -24
  317. package/dist/extensions/pi-subagents/src/tui/render.ts +296 -140
  318. package/dist/extensions/pi-subagents/src/types/pi-runtime-compat.d.ts +14 -0
  319. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +1 -1
  320. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +13 -7
  321. package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +2 -2
  322. package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +145 -0
  323. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +1 -1
  324. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +1 -1
  325. package/dist/extensions/pi-subagents/src/watchdog/review.ts +4 -1
  326. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +3 -2
  327. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +140 -0
  328. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +415 -0
  329. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +41 -144
  330. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +16 -16
  331. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +415 -298
  332. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +149 -82
  333. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +40 -40
  334. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +15 -15
  335. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +193 -133
  336. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +1 -49
  337. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +62 -0
  338. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +56 -58
  339. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +81 -68
  340. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +20 -25
  341. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +425 -317
  342. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +73 -73
  343. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +123 -98
  344. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +653 -240
  345. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +20 -1661
  346. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +9 -9
  347. package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +3 -3
  348. package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +2 -2
  349. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +8 -5
  350. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +6 -6
  351. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +4 -20
  352. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +25 -4
  353. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +1 -1
  354. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +280 -295
  355. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +47 -207
  356. package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +26 -26
  357. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +89 -89
  358. package/dist/extensions/pi-subagents/test/unit/agent-selection.test.ts +9 -9
  359. package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +10 -0
  360. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +33 -9
  361. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +24 -2
  362. package/dist/extensions/pi-subagents/test/unit/async-permission-session.test.ts +11 -9
  363. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +2 -2
  364. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +40 -40
  365. package/dist/extensions/pi-subagents/test/unit/authority-policy.test.ts +22 -0
  366. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +1 -1
  367. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +5 -39
  368. package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +19 -19
  369. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +9 -9
  370. package/dist/extensions/pi-subagents/test/unit/chain-serializer.test.ts +20 -20
  371. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +99 -0
  372. package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +9 -9
  373. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +41 -0
  374. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +2 -2
  375. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +35 -5
  376. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +7 -0
  377. package/dist/extensions/pi-subagents/test/unit/control-notices.test.ts +16 -82
  378. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +162 -620
  379. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
  380. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +25 -25
  381. package/dist/extensions/pi-subagents/test/unit/ensure-accessible-dir.test.ts +125 -0
  382. package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +94 -0
  383. package/dist/extensions/pi-subagents/test/unit/external-runs.test.ts +66 -0
  384. package/dist/extensions/pi-subagents/test/unit/extra-agent-dirs.test.ts +3 -3
  385. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +242 -52
  386. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +127 -0
  387. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +197 -36
  388. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +4 -4
  389. package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +245 -0
  390. package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +494 -0
  391. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +261 -31
  392. package/dist/extensions/pi-subagents/test/unit/inline-subagents.test.ts +52 -0
  393. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +6 -6
  394. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +217 -0
  395. package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +182 -0
  396. package/dist/extensions/pi-subagents/test/unit/mock-pi.test.ts +22 -0
  397. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +1 -1
  398. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +10 -10
  399. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -12
  400. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +47 -5
  401. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +49 -55
  402. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +20 -3
  403. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +37 -7
  404. package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +10 -10
  405. package/dist/extensions/pi-subagents/test/unit/path-handling.test.ts +3 -3
  406. package/dist/extensions/pi-subagents/test/unit/permissions.test.ts +46 -0
  407. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +31 -10
  408. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +40 -16
  409. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +42 -44
  410. package/dist/extensions/pi-subagents/test/unit/proactive-skills.test.ts +13 -13
  411. package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +4 -4
  412. package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +75 -9
  413. package/dist/extensions/pi-subagents/test/unit/prompt-template-bridge.test.ts +20 -84
  414. package/dist/extensions/pi-subagents/test/unit/prompt-workflows.test.ts +15 -16
  415. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +28 -28
  416. package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +19 -12
  417. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +37 -21
  418. package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +1 -1
  419. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +50 -50
  420. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +396 -433
  421. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +76 -153
  422. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +411 -0
  423. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +1 -91
  424. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +139 -0
  425. package/dist/extensions/pi-subagents/test/unit/slash-bridge.test.ts +29 -0
  426. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +13 -13
  427. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -2
  428. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +2 -2
  429. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +35 -35
  430. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +53 -18
  431. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +13 -1
  432. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +44 -11
  433. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +2 -26
  434. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +24 -148
  435. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +11 -9
  436. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +351 -0
  437. package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +13 -13
  438. package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +1 -1
  439. package/dist/extensions/pi-subagents/test/unit/watchdog-permission-arbiter.test.ts +79 -0
  440. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +1 -1
  441. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +8 -8
  442. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +45 -9
  443. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +197 -0
  444. package/dist/extensions/pi-subagents/test/unit/workflow-graph.test.ts +8 -8
  445. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +142 -12
  446. package/dist/extensions/pi-subagents/tsconfig.json +15 -0
  447. package/dist/extensions/pi-web-agent/package.json +1 -1
  448. package/dist/extensions/rtk.test.ts +126 -0
  449. package/dist/extensions/rtk.ts +56 -20
  450. package/dist/index.d.ts +1 -1
  451. package/dist/index.js +1 -1
  452. package/dist/main.d.ts +0 -1
  453. package/dist/main.js +0 -1
  454. package/dist/migrations.d.ts +0 -1
  455. package/dist/migrations.js +0 -1
  456. package/dist/modes/index.d.ts +0 -1
  457. package/dist/modes/index.js +0 -1
  458. package/dist/modes/interactive/components/armin.d.ts +0 -1
  459. package/dist/modes/interactive/components/armin.js +0 -1
  460. package/dist/modes/interactive/components/assistant-message.d.ts +0 -1
  461. package/dist/modes/interactive/components/assistant-message.js +0 -1
  462. package/dist/modes/interactive/components/bash-execution.d.ts +0 -1
  463. package/dist/modes/interactive/components/bash-execution.js +0 -1
  464. package/dist/modes/interactive/components/bordered-loader.d.ts +0 -1
  465. package/dist/modes/interactive/components/bordered-loader.js +0 -1
  466. package/dist/modes/interactive/components/branch-summary-message.d.ts +0 -1
  467. package/dist/modes/interactive/components/branch-summary-message.js +0 -1
  468. package/dist/modes/interactive/components/compaction-summary-message.d.ts +0 -1
  469. package/dist/modes/interactive/components/compaction-summary-message.js +0 -1
  470. package/dist/modes/interactive/components/config-selector.d.ts +0 -1
  471. package/dist/modes/interactive/components/config-selector.js +0 -1
  472. package/dist/modes/interactive/components/countdown-timer.d.ts +0 -1
  473. package/dist/modes/interactive/components/countdown-timer.js +0 -1
  474. package/dist/modes/interactive/components/custom-editor.d.ts +0 -1
  475. package/dist/modes/interactive/components/custom-editor.js +0 -1
  476. package/dist/modes/interactive/components/custom-entry.d.ts +0 -1
  477. package/dist/modes/interactive/components/custom-entry.js +0 -1
  478. package/dist/modes/interactive/components/custom-message.d.ts +0 -1
  479. package/dist/modes/interactive/components/custom-message.js +0 -1
  480. package/dist/modes/interactive/components/daxnuts.d.ts +0 -1
  481. package/dist/modes/interactive/components/daxnuts.js +0 -1
  482. package/dist/modes/interactive/components/diff.d.ts +0 -1
  483. package/dist/modes/interactive/components/diff.js +0 -1
  484. package/dist/modes/interactive/components/dynamic-border.d.ts +0 -1
  485. package/dist/modes/interactive/components/dynamic-border.js +0 -1
  486. package/dist/modes/interactive/components/earendil-announcement.d.ts +0 -1
  487. package/dist/modes/interactive/components/earendil-announcement.js +0 -1
  488. package/dist/modes/interactive/components/extension-editor.d.ts +0 -1
  489. package/dist/modes/interactive/components/extension-editor.js +0 -1
  490. package/dist/modes/interactive/components/extension-input.d.ts +0 -1
  491. package/dist/modes/interactive/components/extension-input.js +0 -1
  492. package/dist/modes/interactive/components/extension-selector.d.ts +0 -1
  493. package/dist/modes/interactive/components/extension-selector.js +0 -1
  494. package/dist/modes/interactive/components/first-time-setup.d.ts +0 -1
  495. package/dist/modes/interactive/components/first-time-setup.js +0 -1
  496. package/dist/modes/interactive/components/footer.d.ts +0 -1
  497. package/dist/modes/interactive/components/footer.js +0 -1
  498. package/dist/modes/interactive/components/index.d.ts +0 -1
  499. package/dist/modes/interactive/components/index.js +0 -1
  500. package/dist/modes/interactive/components/keybinding-hints.d.ts +0 -1
  501. package/dist/modes/interactive/components/keybinding-hints.js +0 -1
  502. package/dist/modes/interactive/components/login-dialog.d.ts +0 -1
  503. package/dist/modes/interactive/components/login-dialog.js +0 -1
  504. package/dist/modes/interactive/components/model-selector.d.ts +0 -1
  505. package/dist/modes/interactive/components/model-selector.js +0 -1
  506. package/dist/modes/interactive/components/oauth-selector.d.ts +0 -1
  507. package/dist/modes/interactive/components/oauth-selector.js +0 -1
  508. package/dist/modes/interactive/components/scoped-models-selector.d.ts +0 -1
  509. package/dist/modes/interactive/components/scoped-models-selector.js +0 -1
  510. package/dist/modes/interactive/components/session-selector-search.d.ts +0 -1
  511. package/dist/modes/interactive/components/session-selector-search.js +0 -1
  512. package/dist/modes/interactive/components/session-selector.d.ts +0 -1
  513. package/dist/modes/interactive/components/session-selector.js +0 -1
  514. package/dist/modes/interactive/components/settings-selector.d.ts +0 -3
  515. package/dist/modes/interactive/components/settings-selector.js +1 -14
  516. package/dist/modes/interactive/components/show-images-selector.d.ts +0 -1
  517. package/dist/modes/interactive/components/show-images-selector.js +0 -1
  518. package/dist/modes/interactive/components/skill-invocation-message.d.ts +0 -1
  519. package/dist/modes/interactive/components/skill-invocation-message.js +0 -1
  520. package/dist/modes/interactive/components/status-indicator.d.ts +0 -1
  521. package/dist/modes/interactive/components/status-indicator.js +0 -1
  522. package/dist/modes/interactive/components/theme-selector.d.ts +0 -1
  523. package/dist/modes/interactive/components/theme-selector.js +0 -1
  524. package/dist/modes/interactive/components/thinking-selector.d.ts +0 -1
  525. package/dist/modes/interactive/components/thinking-selector.js +0 -1
  526. package/dist/modes/interactive/components/tool-execution.d.ts +0 -1
  527. package/dist/modes/interactive/components/tool-execution.js +0 -1
  528. package/dist/modes/interactive/components/tree-selector.d.ts +0 -1
  529. package/dist/modes/interactive/components/tree-selector.js +0 -1
  530. package/dist/modes/interactive/components/trust-selector.d.ts +0 -1
  531. package/dist/modes/interactive/components/trust-selector.js +0 -1
  532. package/dist/modes/interactive/components/user-message-selector.d.ts +0 -1
  533. package/dist/modes/interactive/components/user-message-selector.js +0 -1
  534. package/dist/modes/interactive/components/user-message.d.ts +0 -1
  535. package/dist/modes/interactive/components/user-message.js +0 -1
  536. package/dist/modes/interactive/components/visual-truncate.d.ts +0 -1
  537. package/dist/modes/interactive/components/visual-truncate.js +0 -1
  538. package/dist/modes/interactive/external-editor.d.ts +0 -1
  539. package/dist/modes/interactive/external-editor.js +0 -1
  540. package/dist/modes/interactive/interactive-mode.d.ts +0 -2
  541. package/dist/modes/interactive/interactive-mode.js +1 -22
  542. package/dist/modes/interactive/model-search.d.ts +0 -1
  543. package/dist/modes/interactive/model-search.js +0 -1
  544. package/dist/modes/interactive/theme/theme-controller.d.ts +0 -1
  545. package/dist/modes/interactive/theme/theme-controller.js +0 -1
  546. package/dist/modes/interactive/theme/theme.d.ts +0 -1
  547. package/dist/modes/interactive/theme/theme.js +0 -1
  548. package/dist/modes/print-mode.d.ts +0 -1
  549. package/dist/modes/print-mode.js +0 -1
  550. package/dist/modes/rpc/jsonl.d.ts +0 -1
  551. package/dist/modes/rpc/jsonl.js +0 -1
  552. package/dist/modes/rpc/rpc-client.d.ts +1 -2
  553. package/dist/modes/rpc/rpc-client.js +1 -2
  554. package/dist/modes/rpc/rpc-mode.d.ts +0 -1
  555. package/dist/modes/rpc/rpc-mode.js +0 -9
  556. package/dist/modes/rpc/rpc-types.d.ts +0 -1
  557. package/dist/modes/rpc/rpc-types.js +0 -1
  558. package/dist/package-manager-cli.d.ts +0 -1
  559. package/dist/package-manager-cli.js +0 -1
  560. package/dist/rpc-entry.d.ts +0 -1
  561. package/dist/rpc-entry.js +0 -1
  562. package/dist/utils/ansi.d.ts +0 -1
  563. package/dist/utils/ansi.js +0 -1
  564. package/dist/utils/changelog.d.ts +0 -1
  565. package/dist/utils/changelog.js +0 -1
  566. package/dist/utils/child-process.d.ts +0 -1
  567. package/dist/utils/child-process.js +0 -1
  568. package/dist/utils/clipboard-image.d.ts +0 -1
  569. package/dist/utils/clipboard-image.js +0 -1
  570. package/dist/utils/clipboard-native.d.ts +0 -1
  571. package/dist/utils/clipboard-native.js +0 -1
  572. package/dist/utils/clipboard.d.ts +0 -1
  573. package/dist/utils/clipboard.js +0 -1
  574. package/dist/utils/deprecation.d.ts +0 -1
  575. package/dist/utils/deprecation.js +0 -1
  576. package/dist/utils/exif-orientation.d.ts +0 -1
  577. package/dist/utils/exif-orientation.js +0 -1
  578. package/dist/utils/frontmatter.d.ts +0 -1
  579. package/dist/utils/frontmatter.js +0 -1
  580. package/dist/utils/fs-watch.d.ts +0 -1
  581. package/dist/utils/fs-watch.js +0 -1
  582. package/dist/utils/git.d.ts +0 -1
  583. package/dist/utils/git.js +0 -1
  584. package/dist/utils/html.d.ts +0 -1
  585. package/dist/utils/html.js +0 -1
  586. package/dist/utils/image-convert.d.ts +0 -1
  587. package/dist/utils/image-convert.js +0 -1
  588. package/dist/utils/image-process.d.ts +0 -1
  589. package/dist/utils/image-process.js +0 -1
  590. package/dist/utils/image-resize-core.d.ts +0 -1
  591. package/dist/utils/image-resize-core.js +0 -1
  592. package/dist/utils/image-resize-worker.d.ts +0 -1
  593. package/dist/utils/image-resize-worker.js +0 -1
  594. package/dist/utils/image-resize.d.ts +0 -1
  595. package/dist/utils/image-resize.js +0 -1
  596. package/dist/utils/json.d.ts +0 -1
  597. package/dist/utils/json.js +0 -1
  598. package/dist/utils/mime.d.ts +0 -1
  599. package/dist/utils/mime.js +0 -1
  600. package/dist/utils/open-browser.d.ts +0 -1
  601. package/dist/utils/open-browser.js +0 -1
  602. package/dist/utils/paths.d.ts +0 -1
  603. package/dist/utils/paths.js +0 -1
  604. package/dist/utils/photon.d.ts +0 -1
  605. package/dist/utils/photon.js +0 -1
  606. package/dist/utils/pi-user-agent.d.ts +0 -1
  607. package/dist/utils/pi-user-agent.js +0 -1
  608. package/dist/utils/shell.d.ts +0 -1
  609. package/dist/utils/shell.js +0 -1
  610. package/dist/utils/sleep.d.ts +0 -1
  611. package/dist/utils/sleep.js +0 -1
  612. package/dist/utils/syntax-highlight.d.ts +0 -1
  613. package/dist/utils/syntax-highlight.js +0 -1
  614. package/dist/utils/thinking-tags.d.ts +0 -1
  615. package/dist/utils/thinking-tags.js +0 -1
  616. package/dist/utils/tools-manager.d.ts +3 -3
  617. package/dist/utils/tools-manager.js +125 -42
  618. package/dist/utils/version-check.d.ts +0 -1
  619. package/dist/utils/version-check.js +0 -1
  620. package/dist/utils/windows-self-update.d.ts +0 -1
  621. package/dist/utils/windows-self-update.js +0 -1
  622. package/docs/rpc.md +1 -2
  623. package/docs/settings.md +0 -1
  624. package/docs/skills.md +10 -18
  625. package/package.json +4 -3
  626. package/dist/bun/cli.d.ts.map +0 -1
  627. package/dist/bun/cli.js.map +0 -1
  628. package/dist/bun/register-bedrock.d.ts.map +0 -1
  629. package/dist/bun/register-bedrock.js.map +0 -1
  630. package/dist/bun/restore-sandbox-env.d.ts.map +0 -1
  631. package/dist/bun/restore-sandbox-env.js.map +0 -1
  632. package/dist/cli/args.d.ts.map +0 -1
  633. package/dist/cli/args.js.map +0 -1
  634. package/dist/cli/config-selector.d.ts.map +0 -1
  635. package/dist/cli/config-selector.js.map +0 -1
  636. package/dist/cli/credential-print.d.ts.map +0 -1
  637. package/dist/cli/credential-print.js.map +0 -1
  638. package/dist/cli/file-processor.d.ts.map +0 -1
  639. package/dist/cli/file-processor.js.map +0 -1
  640. package/dist/cli/initial-message.d.ts.map +0 -1
  641. package/dist/cli/initial-message.js.map +0 -1
  642. package/dist/cli/list-models.d.ts.map +0 -1
  643. package/dist/cli/list-models.js.map +0 -1
  644. package/dist/cli/project-trust.d.ts.map +0 -1
  645. package/dist/cli/project-trust.js.map +0 -1
  646. package/dist/cli/session-picker.d.ts.map +0 -1
  647. package/dist/cli/session-picker.js.map +0 -1
  648. package/dist/cli/startup-ui.d.ts.map +0 -1
  649. package/dist/cli/startup-ui.js.map +0 -1
  650. package/dist/cli.d.ts.map +0 -1
  651. package/dist/cli.js.map +0 -1
  652. package/dist/config.d.ts.map +0 -1
  653. package/dist/config.js.map +0 -1
  654. package/dist/core/agent-session-auto-handoff.test.d.ts.map +0 -1
  655. package/dist/core/agent-session-auto-handoff.test.js.map +0 -1
  656. package/dist/core/agent-session-runtime.d.ts.map +0 -1
  657. package/dist/core/agent-session-runtime.js.map +0 -1
  658. package/dist/core/agent-session-services.d.ts.map +0 -1
  659. package/dist/core/agent-session-services.js.map +0 -1
  660. package/dist/core/agent-session-skill-block.test.d.ts.map +0 -1
  661. package/dist/core/agent-session-skill-block.test.js.map +0 -1
  662. package/dist/core/agent-session.d.ts.map +0 -1
  663. package/dist/core/agent-session.js.map +0 -1
  664. package/dist/core/agents.d.ts.map +0 -1
  665. package/dist/core/agents.js.map +0 -1
  666. package/dist/core/auth-guidance.d.ts.map +0 -1
  667. package/dist/core/auth-guidance.js.map +0 -1
  668. package/dist/core/auth-storage.d.ts.map +0 -1
  669. package/dist/core/auth-storage.js.map +0 -1
  670. package/dist/core/bash-executor.d.ts.map +0 -1
  671. package/dist/core/bash-executor.js.map +0 -1
  672. package/dist/core/built-in-extensions.d.ts.map +0 -1
  673. package/dist/core/built-in-extensions.js.map +0 -1
  674. package/dist/core/cache-stats.d.ts.map +0 -1
  675. package/dist/core/cache-stats.js.map +0 -1
  676. package/dist/core/compaction/branch-summarization.d.ts.map +0 -1
  677. package/dist/core/compaction/branch-summarization.js.map +0 -1
  678. package/dist/core/compaction/compaction.d.ts.map +0 -1
  679. package/dist/core/compaction/compaction.js.map +0 -1
  680. package/dist/core/compaction/index.d.ts.map +0 -1
  681. package/dist/core/compaction/index.js.map +0 -1
  682. package/dist/core/compaction/utils.d.ts.map +0 -1
  683. package/dist/core/compaction/utils.js.map +0 -1
  684. package/dist/core/defaults.d.ts.map +0 -1
  685. package/dist/core/defaults.js.map +0 -1
  686. package/dist/core/diagnostics.d.ts.map +0 -1
  687. package/dist/core/diagnostics.js.map +0 -1
  688. package/dist/core/event-bus.d.ts.map +0 -1
  689. package/dist/core/event-bus.js.map +0 -1
  690. package/dist/core/exec.d.ts.map +0 -1
  691. package/dist/core/exec.js.map +0 -1
  692. package/dist/core/experimental.d.ts.map +0 -1
  693. package/dist/core/experimental.js.map +0 -1
  694. package/dist/core/export-html/ansi-to-html.d.ts.map +0 -1
  695. package/dist/core/export-html/ansi-to-html.js.map +0 -1
  696. package/dist/core/export-html/index.d.ts.map +0 -1
  697. package/dist/core/export-html/index.js.map +0 -1
  698. package/dist/core/export-html/tool-renderer.d.ts.map +0 -1
  699. package/dist/core/export-html/tool-renderer.js.map +0 -1
  700. package/dist/core/extensions/index.d.ts.map +0 -1
  701. package/dist/core/extensions/index.js.map +0 -1
  702. package/dist/core/extensions/loader.d.ts.map +0 -1
  703. package/dist/core/extensions/loader.js.map +0 -1
  704. package/dist/core/extensions/runner.d.ts.map +0 -1
  705. package/dist/core/extensions/runner.js.map +0 -1
  706. package/dist/core/extensions/types.d.ts.map +0 -1
  707. package/dist/core/extensions/types.js.map +0 -1
  708. package/dist/core/extensions/wrapper.d.ts.map +0 -1
  709. package/dist/core/extensions/wrapper.js.map +0 -1
  710. package/dist/core/footer-data-provider.d.ts.map +0 -1
  711. package/dist/core/footer-data-provider.js.map +0 -1
  712. package/dist/core/git-command.d.ts.map +0 -1
  713. package/dist/core/git-command.js.map +0 -1
  714. package/dist/core/http-dispatcher.d.ts.map +0 -1
  715. package/dist/core/http-dispatcher.js.map +0 -1
  716. package/dist/core/index.d.ts.map +0 -1
  717. package/dist/core/index.js.map +0 -1
  718. package/dist/core/keybindings.d.ts.map +0 -1
  719. package/dist/core/keybindings.js.map +0 -1
  720. package/dist/core/llama/client.d.ts.map +0 -1
  721. package/dist/core/llama/client.js.map +0 -1
  722. package/dist/core/llama/huggingface.d.ts.map +0 -1
  723. package/dist/core/llama/huggingface.js.map +0 -1
  724. package/dist/core/llama/index.d.ts.map +0 -1
  725. package/dist/core/llama/index.js.map +0 -1
  726. package/dist/core/llama/provider.d.ts.map +0 -1
  727. package/dist/core/llama/provider.js.map +0 -1
  728. package/dist/core/llama/ui.d.ts.map +0 -1
  729. package/dist/core/llama/ui.js.map +0 -1
  730. package/dist/core/messages.d.ts.map +0 -1
  731. package/dist/core/messages.js.map +0 -1
  732. package/dist/core/model-config.d.ts.map +0 -1
  733. package/dist/core/model-config.js.map +0 -1
  734. package/dist/core/model-registry.d.ts.map +0 -1
  735. package/dist/core/model-registry.js.map +0 -1
  736. package/dist/core/model-resolver.d.ts.map +0 -1
  737. package/dist/core/model-resolver.js.map +0 -1
  738. package/dist/core/model-runtime.d.ts.map +0 -1
  739. package/dist/core/model-runtime.js.map +0 -1
  740. package/dist/core/models-store.d.ts.map +0 -1
  741. package/dist/core/models-store.js.map +0 -1
  742. package/dist/core/output-guard.d.ts.map +0 -1
  743. package/dist/core/output-guard.js.map +0 -1
  744. package/dist/core/package-manager.d.ts.map +0 -1
  745. package/dist/core/package-manager.js.map +0 -1
  746. package/dist/core/package-manager.test.d.ts.map +0 -1
  747. package/dist/core/package-manager.test.js.map +0 -1
  748. package/dist/core/project-trust.d.ts.map +0 -1
  749. package/dist/core/project-trust.js.map +0 -1
  750. package/dist/core/prompt-templates.d.ts.map +0 -1
  751. package/dist/core/prompt-templates.js.map +0 -1
  752. package/dist/core/provider-attribution.d.ts.map +0 -1
  753. package/dist/core/provider-attribution.js.map +0 -1
  754. package/dist/core/provider-composer.d.ts.map +0 -1
  755. package/dist/core/provider-composer.js.map +0 -1
  756. package/dist/core/radius.d.ts.map +0 -1
  757. package/dist/core/radius.js.map +0 -1
  758. package/dist/core/remote-catalog-provider.d.ts.map +0 -1
  759. package/dist/core/remote-catalog-provider.js.map +0 -1
  760. package/dist/core/resolve-config-value.d.ts.map +0 -1
  761. package/dist/core/resolve-config-value.js.map +0 -1
  762. package/dist/core/resource-loader.d.ts.map +0 -1
  763. package/dist/core/resource-loader.js.map +0 -1
  764. package/dist/core/runtime-credentials.d.ts.map +0 -1
  765. package/dist/core/runtime-credentials.js.map +0 -1
  766. package/dist/core/sdk.d.ts.map +0 -1
  767. package/dist/core/sdk.js.map +0 -1
  768. package/dist/core/session-cwd.d.ts.map +0 -1
  769. package/dist/core/session-cwd.js.map +0 -1
  770. package/dist/core/session-manager.d.ts.map +0 -1
  771. package/dist/core/session-manager.js.map +0 -1
  772. package/dist/core/settings-manager-auto-handoff.test.d.ts.map +0 -1
  773. package/dist/core/settings-manager-auto-handoff.test.js.map +0 -1
  774. package/dist/core/settings-manager.d.ts.map +0 -1
  775. package/dist/core/settings-manager.js.map +0 -1
  776. package/dist/core/skills.d.ts.map +0 -1
  777. package/dist/core/skills.js.map +0 -1
  778. package/dist/core/slash-commands.d.ts.map +0 -1
  779. package/dist/core/slash-commands.js.map +0 -1
  780. package/dist/core/source-info.d.ts.map +0 -1
  781. package/dist/core/source-info.js.map +0 -1
  782. package/dist/core/system-prompt.d.ts.map +0 -1
  783. package/dist/core/system-prompt.js.map +0 -1
  784. package/dist/core/system-prompt.test.d.ts.map +0 -1
  785. package/dist/core/system-prompt.test.js.map +0 -1
  786. package/dist/core/telemetry.d.ts.map +0 -1
  787. package/dist/core/telemetry.js.map +0 -1
  788. package/dist/core/timings.d.ts.map +0 -1
  789. package/dist/core/timings.js.map +0 -1
  790. package/dist/core/tools/bash.d.ts.map +0 -1
  791. package/dist/core/tools/bash.js.map +0 -1
  792. package/dist/core/tools/edit-diff.d.ts.map +0 -1
  793. package/dist/core/tools/edit-diff.js.map +0 -1
  794. package/dist/core/tools/edit.d.ts.map +0 -1
  795. package/dist/core/tools/edit.js.map +0 -1
  796. package/dist/core/tools/file-mutation-queue.d.ts.map +0 -1
  797. package/dist/core/tools/file-mutation-queue.js.map +0 -1
  798. package/dist/core/tools/find.d.ts.map +0 -1
  799. package/dist/core/tools/find.js.map +0 -1
  800. package/dist/core/tools/grep.d.ts.map +0 -1
  801. package/dist/core/tools/grep.js.map +0 -1
  802. package/dist/core/tools/index.d.ts.map +0 -1
  803. package/dist/core/tools/index.js.map +0 -1
  804. package/dist/core/tools/ls.d.ts.map +0 -1
  805. package/dist/core/tools/ls.js.map +0 -1
  806. package/dist/core/tools/output-accumulator.d.ts.map +0 -1
  807. package/dist/core/tools/output-accumulator.js.map +0 -1
  808. package/dist/core/tools/path-utils.d.ts.map +0 -1
  809. package/dist/core/tools/path-utils.js.map +0 -1
  810. package/dist/core/tools/read.d.ts.map +0 -1
  811. package/dist/core/tools/read.js.map +0 -1
  812. package/dist/core/tools/render-utils.d.ts.map +0 -1
  813. package/dist/core/tools/render-utils.js.map +0 -1
  814. package/dist/core/tools/tool-definition-wrapper.d.ts.map +0 -1
  815. package/dist/core/tools/tool-definition-wrapper.js.map +0 -1
  816. package/dist/core/tools/truncate.d.ts.map +0 -1
  817. package/dist/core/tools/truncate.js.map +0 -1
  818. package/dist/core/tools/write.d.ts.map +0 -1
  819. package/dist/core/tools/write.js.map +0 -1
  820. package/dist/core/trust-manager.d.ts.map +0 -1
  821. package/dist/core/trust-manager.js.map +0 -1
  822. package/dist/core/usage-totals.d.ts.map +0 -1
  823. package/dist/core/usage-totals.js.map +0 -1
  824. package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  825. package/dist/extensions/pi-subagents/test/unit/slash-chain-groups.test.ts +0 -464
  826. package/dist/index.d.ts.map +0 -1
  827. package/dist/index.js.map +0 -1
  828. package/dist/main.d.ts.map +0 -1
  829. package/dist/main.js.map +0 -1
  830. package/dist/migrations.d.ts.map +0 -1
  831. package/dist/migrations.js.map +0 -1
  832. package/dist/modes/index.d.ts.map +0 -1
  833. package/dist/modes/index.js.map +0 -1
  834. package/dist/modes/interactive/components/armin.d.ts.map +0 -1
  835. package/dist/modes/interactive/components/armin.js.map +0 -1
  836. package/dist/modes/interactive/components/assistant-message.d.ts.map +0 -1
  837. package/dist/modes/interactive/components/assistant-message.js.map +0 -1
  838. package/dist/modes/interactive/components/bash-execution.d.ts.map +0 -1
  839. package/dist/modes/interactive/components/bash-execution.js.map +0 -1
  840. package/dist/modes/interactive/components/bordered-loader.d.ts.map +0 -1
  841. package/dist/modes/interactive/components/bordered-loader.js.map +0 -1
  842. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +0 -1
  843. package/dist/modes/interactive/components/branch-summary-message.js.map +0 -1
  844. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +0 -1
  845. package/dist/modes/interactive/components/compaction-summary-message.js.map +0 -1
  846. package/dist/modes/interactive/components/config-selector.d.ts.map +0 -1
  847. package/dist/modes/interactive/components/config-selector.js.map +0 -1
  848. package/dist/modes/interactive/components/countdown-timer.d.ts.map +0 -1
  849. package/dist/modes/interactive/components/countdown-timer.js.map +0 -1
  850. package/dist/modes/interactive/components/custom-editor.d.ts.map +0 -1
  851. package/dist/modes/interactive/components/custom-editor.js.map +0 -1
  852. package/dist/modes/interactive/components/custom-entry.d.ts.map +0 -1
  853. package/dist/modes/interactive/components/custom-entry.js.map +0 -1
  854. package/dist/modes/interactive/components/custom-message.d.ts.map +0 -1
  855. package/dist/modes/interactive/components/custom-message.js.map +0 -1
  856. package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
  857. package/dist/modes/interactive/components/daxnuts.js.map +0 -1
  858. package/dist/modes/interactive/components/diff.d.ts.map +0 -1
  859. package/dist/modes/interactive/components/diff.js.map +0 -1
  860. package/dist/modes/interactive/components/dynamic-border.d.ts.map +0 -1
  861. package/dist/modes/interactive/components/dynamic-border.js.map +0 -1
  862. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +0 -1
  863. package/dist/modes/interactive/components/earendil-announcement.js.map +0 -1
  864. package/dist/modes/interactive/components/extension-editor.d.ts.map +0 -1
  865. package/dist/modes/interactive/components/extension-editor.js.map +0 -1
  866. package/dist/modes/interactive/components/extension-input.d.ts.map +0 -1
  867. package/dist/modes/interactive/components/extension-input.js.map +0 -1
  868. package/dist/modes/interactive/components/extension-selector.d.ts.map +0 -1
  869. package/dist/modes/interactive/components/extension-selector.js.map +0 -1
  870. package/dist/modes/interactive/components/first-time-setup.d.ts.map +0 -1
  871. package/dist/modes/interactive/components/first-time-setup.js.map +0 -1
  872. package/dist/modes/interactive/components/footer.d.ts.map +0 -1
  873. package/dist/modes/interactive/components/footer.js.map +0 -1
  874. package/dist/modes/interactive/components/index.d.ts.map +0 -1
  875. package/dist/modes/interactive/components/index.js.map +0 -1
  876. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +0 -1
  877. package/dist/modes/interactive/components/keybinding-hints.js.map +0 -1
  878. package/dist/modes/interactive/components/login-dialog.d.ts.map +0 -1
  879. package/dist/modes/interactive/components/login-dialog.js.map +0 -1
  880. package/dist/modes/interactive/components/model-selector.d.ts.map +0 -1
  881. package/dist/modes/interactive/components/model-selector.js.map +0 -1
  882. package/dist/modes/interactive/components/oauth-selector.d.ts.map +0 -1
  883. package/dist/modes/interactive/components/oauth-selector.js.map +0 -1
  884. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +0 -1
  885. package/dist/modes/interactive/components/scoped-models-selector.js.map +0 -1
  886. package/dist/modes/interactive/components/session-selector-search.d.ts.map +0 -1
  887. package/dist/modes/interactive/components/session-selector-search.js.map +0 -1
  888. package/dist/modes/interactive/components/session-selector.d.ts.map +0 -1
  889. package/dist/modes/interactive/components/session-selector.js.map +0 -1
  890. package/dist/modes/interactive/components/settings-selector.d.ts.map +0 -1
  891. package/dist/modes/interactive/components/settings-selector.js.map +0 -1
  892. package/dist/modes/interactive/components/show-images-selector.d.ts.map +0 -1
  893. package/dist/modes/interactive/components/show-images-selector.js.map +0 -1
  894. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +0 -1
  895. package/dist/modes/interactive/components/skill-invocation-message.js.map +0 -1
  896. package/dist/modes/interactive/components/status-indicator.d.ts.map +0 -1
  897. package/dist/modes/interactive/components/status-indicator.js.map +0 -1
  898. package/dist/modes/interactive/components/theme-selector.d.ts.map +0 -1
  899. package/dist/modes/interactive/components/theme-selector.js.map +0 -1
  900. package/dist/modes/interactive/components/thinking-selector.d.ts.map +0 -1
  901. package/dist/modes/interactive/components/thinking-selector.js.map +0 -1
  902. package/dist/modes/interactive/components/tool-execution.d.ts.map +0 -1
  903. package/dist/modes/interactive/components/tool-execution.js.map +0 -1
  904. package/dist/modes/interactive/components/tree-selector.d.ts.map +0 -1
  905. package/dist/modes/interactive/components/tree-selector.js.map +0 -1
  906. package/dist/modes/interactive/components/trust-selector.d.ts.map +0 -1
  907. package/dist/modes/interactive/components/trust-selector.js.map +0 -1
  908. package/dist/modes/interactive/components/user-message-selector.d.ts.map +0 -1
  909. package/dist/modes/interactive/components/user-message-selector.js.map +0 -1
  910. package/dist/modes/interactive/components/user-message.d.ts.map +0 -1
  911. package/dist/modes/interactive/components/user-message.js.map +0 -1
  912. package/dist/modes/interactive/components/visual-truncate.d.ts.map +0 -1
  913. package/dist/modes/interactive/components/visual-truncate.js.map +0 -1
  914. package/dist/modes/interactive/external-editor.d.ts.map +0 -1
  915. package/dist/modes/interactive/external-editor.js.map +0 -1
  916. package/dist/modes/interactive/interactive-mode.d.ts.map +0 -1
  917. package/dist/modes/interactive/interactive-mode.js.map +0 -1
  918. package/dist/modes/interactive/model-search.d.ts.map +0 -1
  919. package/dist/modes/interactive/model-search.js.map +0 -1
  920. package/dist/modes/interactive/theme/theme-controller.d.ts.map +0 -1
  921. package/dist/modes/interactive/theme/theme-controller.js.map +0 -1
  922. package/dist/modes/interactive/theme/theme.d.ts.map +0 -1
  923. package/dist/modes/interactive/theme/theme.js.map +0 -1
  924. package/dist/modes/print-mode.d.ts.map +0 -1
  925. package/dist/modes/print-mode.js.map +0 -1
  926. package/dist/modes/rpc/jsonl.d.ts.map +0 -1
  927. package/dist/modes/rpc/jsonl.js.map +0 -1
  928. package/dist/modes/rpc/rpc-client.d.ts.map +0 -1
  929. package/dist/modes/rpc/rpc-client.js.map +0 -1
  930. package/dist/modes/rpc/rpc-mode.d.ts.map +0 -1
  931. package/dist/modes/rpc/rpc-mode.js.map +0 -1
  932. package/dist/modes/rpc/rpc-types.d.ts.map +0 -1
  933. package/dist/modes/rpc/rpc-types.js.map +0 -1
  934. package/dist/package-manager-cli.d.ts.map +0 -1
  935. package/dist/package-manager-cli.js.map +0 -1
  936. package/dist/rpc-entry.d.ts.map +0 -1
  937. package/dist/rpc-entry.js.map +0 -1
  938. package/dist/utils/ansi.d.ts.map +0 -1
  939. package/dist/utils/ansi.js.map +0 -1
  940. package/dist/utils/changelog.d.ts.map +0 -1
  941. package/dist/utils/changelog.js.map +0 -1
  942. package/dist/utils/child-process.d.ts.map +0 -1
  943. package/dist/utils/child-process.js.map +0 -1
  944. package/dist/utils/clipboard-image.d.ts.map +0 -1
  945. package/dist/utils/clipboard-image.js.map +0 -1
  946. package/dist/utils/clipboard-native.d.ts.map +0 -1
  947. package/dist/utils/clipboard-native.js.map +0 -1
  948. package/dist/utils/clipboard.d.ts.map +0 -1
  949. package/dist/utils/clipboard.js.map +0 -1
  950. package/dist/utils/deprecation.d.ts.map +0 -1
  951. package/dist/utils/deprecation.js.map +0 -1
  952. package/dist/utils/exif-orientation.d.ts.map +0 -1
  953. package/dist/utils/exif-orientation.js.map +0 -1
  954. package/dist/utils/frontmatter.d.ts.map +0 -1
  955. package/dist/utils/frontmatter.js.map +0 -1
  956. package/dist/utils/fs-watch.d.ts.map +0 -1
  957. package/dist/utils/fs-watch.js.map +0 -1
  958. package/dist/utils/git.d.ts.map +0 -1
  959. package/dist/utils/git.js.map +0 -1
  960. package/dist/utils/html.d.ts.map +0 -1
  961. package/dist/utils/html.js.map +0 -1
  962. package/dist/utils/image-convert.d.ts.map +0 -1
  963. package/dist/utils/image-convert.js.map +0 -1
  964. package/dist/utils/image-process.d.ts.map +0 -1
  965. package/dist/utils/image-process.js.map +0 -1
  966. package/dist/utils/image-resize-core.d.ts.map +0 -1
  967. package/dist/utils/image-resize-core.js.map +0 -1
  968. package/dist/utils/image-resize-worker.d.ts.map +0 -1
  969. package/dist/utils/image-resize-worker.js.map +0 -1
  970. package/dist/utils/image-resize.d.ts.map +0 -1
  971. package/dist/utils/image-resize.js.map +0 -1
  972. package/dist/utils/json.d.ts.map +0 -1
  973. package/dist/utils/json.js.map +0 -1
  974. package/dist/utils/mime.d.ts.map +0 -1
  975. package/dist/utils/mime.js.map +0 -1
  976. package/dist/utils/open-browser.d.ts.map +0 -1
  977. package/dist/utils/open-browser.js.map +0 -1
  978. package/dist/utils/paths.d.ts.map +0 -1
  979. package/dist/utils/paths.js.map +0 -1
  980. package/dist/utils/photon.d.ts.map +0 -1
  981. package/dist/utils/photon.js.map +0 -1
  982. package/dist/utils/pi-user-agent.d.ts.map +0 -1
  983. package/dist/utils/pi-user-agent.js.map +0 -1
  984. package/dist/utils/shell.d.ts.map +0 -1
  985. package/dist/utils/shell.js.map +0 -1
  986. package/dist/utils/sleep.d.ts.map +0 -1
  987. package/dist/utils/sleep.js.map +0 -1
  988. package/dist/utils/syntax-highlight.d.ts.map +0 -1
  989. package/dist/utils/syntax-highlight.js.map +0 -1
  990. package/dist/utils/thinking-tags.d.ts.map +0 -1
  991. package/dist/utils/thinking-tags.js.map +0 -1
  992. package/dist/utils/tools-manager.d.ts.map +0 -1
  993. package/dist/utils/tools-manager.js.map +0 -1
  994. package/dist/utils/version-check.d.ts.map +0 -1
  995. package/dist/utils/version-check.js.map +0 -1
  996. package/dist/utils/windows-self-update.d.ts.map +0 -1
  997. package/dist/utils/windows-self-update.js.map +0 -1
@@ -7,12 +7,14 @@ import type { Message } from "@earendil-works/pi-ai";
7
7
  import { writeAtomicJson } from "../../shared/atomic-json.ts";
8
8
  import { createChildTranscriptWriter, type ChildTranscriptWriter } from "../../shared/child-transcript.ts";
9
9
  import { closeSteerInbox, consumeInterruptRequest, consumeSteerRequests, deliverInterruptRequest, deliverStopRequest, deliverTimeoutRequest, enqueueStepSteer, steerAcksDir, steerCapabilityPath, stepSteerInboxDir, watchAsyncControlInbox, type SteerAck, type SteerCapability, type SteerRequest } from "./control-channel.ts";
10
- import { appendJsonl as appendRawJsonl, formatOutputArtifactContent, getArtifactPaths } from "../../shared/artifacts.ts";
10
+ import { appendJsonl as appendRawJsonl, formatOutputArtifactContent, getArtifactPaths, writeArtifact, writeMetadata } from "../../shared/artifacts.ts";
11
11
  import { PI_CODING_AGENT_PACKAGE, getPiSpawnCommand, resolveInstalledPiPackageRoot } from "../shared/pi-spawn.ts";
12
12
  import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, injectOutputPathSystemPrompt, injectSingleOutputInstruction, resolveSingleOutput, type SingleOutputSnapshot } from "../shared/single-output.ts";
13
13
  import {
14
14
  type ActivityState,
15
15
  type ArtifactConfig,
16
+ type ExternalCliRunnerStatus,
17
+ type ExternalProcessStatus,
16
18
  type ArtifactPaths,
17
19
  type AsyncParallelGroupStatus,
18
20
  type AsyncStatus,
@@ -118,10 +120,11 @@ import { appendRunnerStepsToStatus, consumeChainAppendRequests, countPendingChai
118
120
  import { appendTurnBudgetSystemPrompt, formatTurnBudgetOutput, initialTurnBudgetState, turnBudgetDecision, turnBudgetDeferredNote, turnBudgetDeferredState, turnBudgetExceededMessage, turnBudgetSoftNote, turnBudgetState } from "../shared/turn-budget.ts";
119
121
  import { initialToolBudgetState, toolBudgetState } from "../shared/tool-budget.ts";
120
122
  import { usageBudgetExceededMessage, usageBudgetState } from "../shared/usage-budget.ts";
121
- import { formatParallelHandoffError, formatParallelHandoffReference, parallelHandoffPath, writeParallelHandoffGroup } from "../shared/parallel-handoff.ts";
123
+ import { formatParallelHandoffError, formatParallelHandoffReference, parallelHandoffPath, writeParallelHandoffGroup, writePendingParallelHandoff } from "../shared/parallel-handoff.ts";
122
124
  import { resolveWatchdogConfig } from "../../watchdog/settings.ts";
123
- import { createBoundedByteTail, createBoundedLineReader, formatProtocolOutputLimit, MAX_CHILD_STDERR_BYTES, projectChildLifecycle, type ChildLifecycleAction, type ProtocolOutputLimit } from "../shared/child-protocol.ts";
125
+ import { createBoundedByteTail, createBoundedLineReader, formatProtocolOutputLimit, MAX_CHILD_STDERR_BYTES, PI_AGGREGATE_EVENT_PROJECTOR, projectChildLifecycle, type ChildLifecycleAction, type ProtocolOutputLimit } from "../shared/child-protocol.ts";
124
126
  import { acquireSessionLease, type SessionLeaseRequest } from "../shared/session-lease.ts";
127
+ import { buildExternalCliPrompt, runExternalCli } from "../shared/external-cli-runner.ts";
125
128
  import { decodeSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_ENV, type ResolvedSubagentCapabilityCeiling } from "../shared/capability-ceiling.ts";
126
129
  import {
127
130
  CHILD_WATCHDOG_CONFIG_ENV,
@@ -157,6 +160,7 @@ interface SubagentRunConfig {
157
160
  controlIntercomTarget?: string;
158
161
  childIntercomTargets?: Array<string | undefined>;
159
162
  resultMode?: SubagentRunMode;
163
+ mode?: SubagentRunMode;
160
164
  dynamicFanoutMaxItems?: number;
161
165
  workflowGraph?: WorkflowGraphSnapshot;
162
166
  nestedRoute?: NestedRouteInfo;
@@ -175,6 +179,8 @@ interface SubagentRunConfig {
175
179
  launchResolvedExtensions?: LaunchResolvedChildExtensionsV1;
176
180
  runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;
177
181
  runnerProcessInstanceId?: string;
182
+ parentWorkflowRunId?: string;
183
+ workflowKey?: string;
178
184
  }
179
185
 
180
186
  interface StepResult {
@@ -188,8 +194,10 @@ interface StepResult {
188
194
  outputState?: SubagentOutputState;
189
195
  error?: string;
190
196
  protocolError?: ProtocolOutputLimit;
191
- success: boolean;
192
- exitCode?: number | null;
197
+ success?: boolean;
198
+ exitCode: number | null;
199
+ usage?: Usage;
200
+ savedOutputPath?: string;
193
201
  skipped?: boolean;
194
202
  interrupted?: boolean;
195
203
  timedOut?: boolean;
@@ -207,6 +215,8 @@ interface StepResult {
207
215
  modelAttempts?: ModelAttempt[];
208
216
  totalCost?: CostSummary;
209
217
  artifactPaths?: ArtifactPaths;
218
+ outputSaveError?: string;
219
+ metadataSaveError?: string;
210
220
  truncated?: boolean;
211
221
  transcriptPath?: string;
212
222
  transcriptError?: string;
@@ -222,6 +232,32 @@ interface StepResult {
222
232
  watchdog?: import("../../shared/types.ts").ChildWatchdogProgress;
223
233
  writerProcesses?: Array<{ processInstanceId: string; kind: "pi-writer"; attempt: number; closeObservedAt: number; exitCode: number | null; signal: string | null }>;
224
234
  writerAttemptCount?: number;
235
+ runner?: ExternalCliRunnerStatus;
236
+ externalProcess?: ExternalProcessStatus;
237
+ }
238
+
239
+ function persistStepArtifacts(input: {
240
+ artifactPaths: ArtifactPaths;
241
+ artifactConfig?: Partial<ArtifactConfig>;
242
+ output: string;
243
+ metadata: object;
244
+ }): { outputSaveError?: string; metadataSaveError?: string } {
245
+ const errors: { outputSaveError?: string; metadataSaveError?: string } = {};
246
+ if (input.artifactConfig?.includeOutput !== false) {
247
+ try {
248
+ writeArtifact(input.artifactPaths.outputPath, input.output);
249
+ } catch (error) {
250
+ errors.outputSaveError = `Artifact output post-processing failed: ${error instanceof Error ? error.message : String(error)}`;
251
+ }
252
+ }
253
+ if (input.artifactConfig?.includeMetadata !== false) {
254
+ try {
255
+ writeMetadata(input.artifactPaths.metadataPath, input.metadata);
256
+ } catch (error) {
257
+ errors.metadataSaveError = `Artifact metadata post-processing failed: ${error instanceof Error ? error.message : String(error)}`;
258
+ }
259
+ }
260
+ return errors;
225
261
  }
226
262
 
227
263
  const ASYNC_INTERRUPT_SIGNAL: NodeJS.Signals = process.platform === "win32" ? "SIGBREAK" : "SIGUSR2";
@@ -373,11 +409,44 @@ function isTerminalAssistantStop(message: Message): boolean {
373
409
  return (message as { stopReason?: string }).stopReason === "stop" && !assistantStartsToolCall(message);
374
410
  }
375
411
 
412
+ type UndefinedOmitted<T extends object> = {
413
+ [K in keyof T]: Exclude<T[K], undefined>;
414
+ };
415
+
416
+ function omitUndefinedProperties<const T extends object>(value: T): UndefinedOmitted<T> {
417
+ for (const key in value) {
418
+ if (value[key] === undefined) delete value[key];
419
+ }
420
+ return value as UndefinedOmitted<T>;
421
+ }
422
+
423
+ type WithUndefinedOptionals<T extends object> = {
424
+ [K in keyof T]: {} extends Pick<T, K> ? T[K] | undefined : T[K];
425
+ };
426
+
427
+ type RequiredKeysAllowingUndefined<T extends object> = {
428
+ [K in keyof T]-?: {} extends Pick<T, K> ? never : undefined extends T[K] ? K : never;
429
+ }[keyof T];
430
+
431
+ function compactOptional<T extends object>(
432
+ value: WithUndefinedOptionals<T> & (RequiredKeysAllowingUndefined<T> extends never ? unknown : never),
433
+ ): T {
434
+ for (const key of Object.keys(value) as Array<keyof T>) {
435
+ if (value[key] === undefined) delete value[key];
436
+ }
437
+ return value as T;
438
+ }
439
+
440
+ function setOptionalProperty<T extends object, K extends keyof T>(target: T, key: K, value: T[K]): void {
441
+ if (value === undefined) delete target[key];
442
+ else target[key] = value;
443
+ }
444
+
376
445
  function resetStepLiveDetail(step: RunnerStatusStep): void {
377
- step.currentTool = undefined;
378
- step.currentToolArgs = undefined;
379
- step.currentToolStartedAt = undefined;
380
- step.currentPath = undefined;
446
+ delete step.currentTool;
447
+ delete step.currentToolArgs;
448
+ delete step.currentToolStartedAt;
449
+ delete step.currentPath;
381
450
  step.recentTools = [];
382
451
  step.recentOutput = [];
383
452
  }
@@ -549,7 +618,7 @@ function runPiStreaming(
549
618
  return;
550
619
  }
551
620
 
552
- appendChildEvent(event);
621
+ appendChildEvent(event as unknown as Record<string, unknown>);
553
622
  transcriptWriter?.writeChildEvent(event);
554
623
  if (event.type === "agent_settled") agentSettledReceived = true;
555
624
  applyChildLifecycle(projectChildLifecycle(event));
@@ -559,9 +628,11 @@ function runPiStreaming(
559
628
  const next = acceptChildWatchdogEvent({
560
629
  current: childWatchdogState,
561
630
  event,
562
- runId: childEventContext?.runId,
563
- agent: childEventContext?.agent,
564
- childIndex: childEventContext?.stepIndex,
631
+ ...(childEventContext ? {
632
+ runId: childEventContext.runId,
633
+ agent: childEventContext.agent,
634
+ childIndex: childEventContext.stepIndex,
635
+ } : {}),
565
636
  });
566
637
  if (!next) return;
567
638
  updateChildWatchdogState(next);
@@ -663,7 +734,11 @@ function runPiStreaming(
663
734
  protocolHardKillTimer.unref?.();
664
735
  }
665
736
  };
666
- const stdoutReader = createBoundedLineReader({ onLine: processStdoutLine, onLimit: failProtocol });
737
+ const stdoutReader = createBoundedLineReader({
738
+ oversizedLineProjector: PI_AGGREGATE_EVENT_PROJECTOR,
739
+ onLine: processStdoutLine,
740
+ onLimit: failProtocol,
741
+ });
667
742
  const stderrReader = createBoundedLineReader({
668
743
  stream: "stderr",
669
744
  maxPendingLineBytes: MAX_CHILD_STDERR_BYTES,
@@ -829,7 +904,7 @@ function runPiStreaming(
829
904
  turnBudgetExceeded,
830
905
  forcedDrainAfterFinalSuccess,
831
906
  }) ? formatProcessSignalError(signal!) : undefined;
832
- resolve({
907
+ resolve(omitUndefinedProperties({
833
908
  stderr,
834
909
  exitCode: timedOut || stopped ? 1 : turnBudgetExceeded ? 1 : interrupted || forcedDrainAfterFinalSuccess ? 0 : forcedTerminationSignal || signal ? (exitCode ?? 1) : exitCode,
835
910
  messages,
@@ -852,7 +927,7 @@ function runPiStreaming(
852
927
  processInstanceId,
853
928
  processCloseObservedAt,
854
929
  processSignal: signal,
855
- });
930
+ }));
856
931
  });
857
932
 
858
933
  child.on("error", (spawnError) => {
@@ -874,7 +949,7 @@ function runPiStreaming(
874
949
  const stderr = stderrTail.text();
875
950
  const finalOutput = getFinalOutput(messages) || rawStdoutTail.text().trim();
876
951
  const spawnErrorMessage = spawnError instanceof Error ? spawnError.message : String(spawnError);
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 });
952
+ resolve(omitUndefinedProperties({ 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 }));
878
953
  });
879
954
  });
880
955
  }
@@ -901,7 +976,7 @@ async function exportSessionHtml(sessionFile: string, outputDir: string, piPacka
901
976
 
902
977
  function createShareLink(htmlPath: string): { shareUrl: string; gistUrl: string } | { error: string } {
903
978
  try {
904
- const auth = spawnSync("gh", ["auth", "status"], { encoding: "utf-8" });
979
+ const auth = spawnSync("gh", ["auth", "status"], { encoding: "utf-8", windowsHide: true });
905
980
  if (auth.status !== 0) {
906
981
  return { error: "GitHub CLI is not logged in. Run 'gh auth login' first." };
907
982
  }
@@ -910,7 +985,7 @@ function createShareLink(htmlPath: string): { shareUrl: string; gistUrl: string
910
985
  }
911
986
 
912
987
  try {
913
- const result = spawnSync("gh", ["gist", "create", htmlPath], { encoding: "utf-8" });
988
+ const result = spawnSync("gh", ["gist", "create", htmlPath], { encoding: "utf-8", windowsHide: true });
914
989
  if (result.status !== 0) {
915
990
  const err = (result.stderr || "").trim() || "Failed to create gist.";
916
991
  return { error: err };
@@ -1021,6 +1096,7 @@ interface SingleStepContext {
1021
1096
  onAttemptStart?: (attempt: { model?: string; thinking?: string }) => void;
1022
1097
  onChildEvent?: (event: ChildEvent) => void;
1023
1098
  onWriterProcess?: (writer: { state: "none" | "spawning" } | { state: "running"; pid: number }) => void;
1099
+ onExternalProcess?: (process: ExternalProcessStatus) => void;
1024
1100
  skipAcceptance?: () => boolean;
1025
1101
  }
1026
1102
 
@@ -1028,42 +1104,7 @@ interface SingleStepContext {
1028
1104
  async function runSingleStep(
1029
1105
  step: SubagentStep,
1030
1106
  ctx: SingleStepContext,
1031
- ): Promise<{
1032
- agent: string;
1033
- context?: "fresh" | "fork";
1034
- agentContract?: import("../../shared/types.ts").AgentContract;
1035
- launchContractDigest?: string;
1036
- launchResolvedExtensions?: LaunchResolvedChildExtensionsV1;
1037
- runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;
1038
- output: string;
1039
- exitCode: number | null;
1040
- error?: string;
1041
- model?: string;
1042
- attemptedModels?: string[];
1043
- modelAttempts?: ModelAttempt[];
1044
- artifactPaths?: ArtifactPaths;
1045
- transcriptPath?: string;
1046
- transcriptError?: string;
1047
- interrupted?: boolean;
1048
- timedOut?: boolean;
1049
- stopped?: boolean;
1050
- turnBudget?: TurnBudgetState;
1051
- turnBudgetExceeded?: boolean;
1052
- wrapUpRequested?: boolean;
1053
- toolBudget?: ToolBudgetState;
1054
- toolBudgetBlocked?: boolean;
1055
- sessionFile?: string;
1056
- intercomTarget?: string;
1057
- completionGuardTriggered?: boolean;
1058
- effects?: import("../../shared/types.ts").EffectsProjection;
1059
- execution?: import("../../shared/types.ts").ExecutionProjection;
1060
- review?: import("../../shared/types.ts").ReviewProjection;
1061
- structuredOutput?: unknown;
1062
- structuredOutputPath?: string;
1063
- structuredOutputSchemaPath?: string;
1064
- acceptance?: import("../../shared/types.ts").AcceptanceLedger;
1065
- writerAttemptCount?: number;
1066
- }> {
1107
+ ): Promise<StepResult & { completionGuardTriggered?: boolean }> {
1067
1108
  if (step.importAsyncRoot) {
1068
1109
  let importTimedOut = false;
1069
1110
  let importStopped = false;
@@ -1076,7 +1117,7 @@ async function runSingleStep(
1076
1117
  pid = undefined;
1077
1118
  }
1078
1119
  try {
1079
- deliverTimeoutRequest({ asyncDir: step.importAsyncRoot!.asyncDir, pid, source: "ancestor-timeout" });
1120
+ deliverTimeoutRequest(omitUndefinedProperties({ asyncDir: step.importAsyncRoot!.asyncDir, pid, source: "ancestor-timeout" }));
1080
1121
  } catch {
1081
1122
  // The parent runner's own timeout result is authoritative for the attached step.
1082
1123
  }
@@ -1090,16 +1131,16 @@ async function runSingleStep(
1090
1131
  pid = undefined;
1091
1132
  }
1092
1133
  try {
1093
- deliverStopRequest({ asyncDir: step.importAsyncRoot!.asyncDir, pid, source: "ancestor-stop" });
1134
+ deliverStopRequest(omitUndefinedProperties({ asyncDir: step.importAsyncRoot!.asyncDir, pid, source: "ancestor-stop" }));
1094
1135
  } catch {
1095
1136
  // The parent runner's own stopped result is authoritative for the attached step.
1096
1137
  }
1097
1138
  });
1098
1139
  try {
1099
- const imported = await waitForImportedAsyncRoot(step.importAsyncRoot, {
1140
+ const imported = await waitForImportedAsyncRoot(step.importAsyncRoot, omitUndefinedProperties({
1100
1141
  shouldAbort: () => importTimedOut || importStopped || ctx.timeoutSignal?.aborted === true || ctx.stopSignal?.aborted === true || ctx.skipAcceptance?.() === true,
1101
1142
  timeoutMessage: importStopped || ctx.stopSignal?.aborted === true ? ctx.stopMessage : ctx.timeoutMessage,
1102
- });
1143
+ }));
1103
1144
  try {
1104
1145
  fs.writeFileSync(ctx.outputFile, imported.output, "utf-8");
1105
1146
  } catch {
@@ -1108,7 +1149,7 @@ async function runSingleStep(
1108
1149
  const stopped = importStopped || imported.stopped === true || ctx.stopSignal?.aborted === true;
1109
1150
  const timedOut = !stopped && (importTimedOut || imported.timedOut === true || ctx.timeoutSignal?.aborted === true || ctx.skipAcceptance?.() === true);
1110
1151
  const message = stopped ? ctx.stopMessage ?? "Subagent stopped by user." : ctx.timeoutMessage ?? "Subagent timed out.";
1111
- return {
1152
+ return omitUndefinedProperties({
1112
1153
  agent: imported.agent,
1113
1154
  output: timedOut || stopped ? message : imported.output,
1114
1155
  exitCode: timedOut || stopped ? 1 : imported.exitCode,
@@ -1125,7 +1166,7 @@ async function runSingleStep(
1125
1166
  structuredOutputPath: timedOut || stopped ? undefined : imported.structuredOutputPath,
1126
1167
  structuredOutputSchemaPath: timedOut || stopped ? undefined : imported.structuredOutputSchemaPath,
1127
1168
  acceptance: timedOut || stopped ? undefined : imported.acceptance,
1128
- };
1169
+ });
1129
1170
  } finally {
1130
1171
  ctx.registerTimeout?.(undefined);
1131
1172
  ctx.registerStop?.(undefined);
@@ -1168,6 +1209,68 @@ async function runSingleStep(
1168
1209
  }
1169
1210
  transcriptWriter?.writeInitialUserMessage(task);
1170
1211
 
1212
+ if (step.runner?.type === "external-cli") {
1213
+ const runner: ExternalCliRunnerStatus = {
1214
+ type: "external-cli",
1215
+ command: step.runner.command,
1216
+ args: step.runner.args ?? [],
1217
+ promptDelivery: step.runner.promptDelivery ?? "stdin",
1218
+ capabilities: { stop: true, steer: false, resume: false, structuredOutput: false, toolEvents: false },
1219
+ };
1220
+ const outputSnapshot = captureSingleOutputSnapshot(step.outputPath);
1221
+ const external = await runExternalCli(omitUndefinedProperties({
1222
+ command: runner.command,
1223
+ args: runner.args,
1224
+ cwd: step.cwd ?? ctx.cwd,
1225
+ prompt: buildExternalCliPrompt(step.systemPrompt ?? "", task),
1226
+ asyncDir: path.dirname(ctx.outputFile),
1227
+ stepIndex: ctx.flatIndex,
1228
+ registerTimeout: ctx.registerTimeout,
1229
+ registerStop: ctx.registerStop,
1230
+ timeoutMessage: ctx.timeoutMessage,
1231
+ stopMessage: ctx.stopMessage,
1232
+ onProcess: ctx.onExternalProcess,
1233
+ }));
1234
+ try { fs.writeFileSync(ctx.outputFile, external.output, "utf-8"); } catch { /* Observability output is best-effort. */ }
1235
+ const resolvedOutput = step.outputPath && external.exitCode === 0
1236
+ ? resolveSingleOutput(step.outputPath, external.output, outputSnapshot)
1237
+ : { fullOutput: external.output };
1238
+ const outputReference = resolvedOutput.savedPath ? formatSavedOutputReference(resolvedOutput.savedPath, resolvedOutput.fullOutput) : undefined;
1239
+ const finalizedOutput = finalizeSingleOutput(omitUndefinedProperties({
1240
+ fullOutput: resolvedOutput.fullOutput,
1241
+ outputPath: step.outputPath,
1242
+ outputMode: step.outputMode,
1243
+ exitCode: external.exitCode ?? 1,
1244
+ savedPath: resolvedOutput.savedPath,
1245
+ outputReference,
1246
+ saveError: resolvedOutput.saveError,
1247
+ }));
1248
+ const artifactErrors = artifactPaths && ctx.artifactConfig?.enabled !== false
1249
+ ? persistStepArtifacts({
1250
+ artifactPaths,
1251
+ artifactConfig: ctx.artifactConfig,
1252
+ output: formatOutputArtifactContent(omitUndefinedProperties({ output: resolvedOutput.fullOutput, error: external.error, metadataPath: ctx.artifactConfig?.includeMetadata === false ? undefined : artifactPaths.metadataPath })),
1253
+ metadata: { runId: ctx.id, agent: step.agent, task, runner, externalProcess: external.externalProcess, exitCode: external.exitCode, error: external.error, timestamp: Date.now() },
1254
+ })
1255
+ : {};
1256
+ return omitUndefinedProperties({
1257
+ agent: step.agent,
1258
+ context: step.context,
1259
+ output: finalizedOutput.displayOutput,
1260
+ outputState: external.output.trim() ? "present" : "absent",
1261
+ exitCode: external.exitCode,
1262
+ error: external.error,
1263
+ timedOut: external.timedOut,
1264
+ stopped: external.stopped,
1265
+ processSignal: external.processSignal,
1266
+ artifactPaths,
1267
+ outputSaveError: artifactErrors.outputSaveError,
1268
+ metadataSaveError: artifactErrors.metadataSaveError,
1269
+ runner,
1270
+ externalProcess: external.externalProcess,
1271
+ });
1272
+ }
1273
+
1171
1274
  const candidates = step.modelCandidates && step.modelCandidates.length > 0
1172
1275
  ? step.modelCandidates
1173
1276
  : step.model
@@ -1194,7 +1297,7 @@ async function runSingleStep(
1194
1297
  modelAttemptsLoop: while (modelIndex < candidates.length) {
1195
1298
  if (ctx.timeoutSignal?.aborted || ctx.stopSignal?.aborted || ctx.skipAcceptance?.()) break;
1196
1299
  const candidate = candidates[modelIndex];
1197
- ctx.onAttemptStart?.({ model: candidate, thinking: resolveEffectiveThinking(candidate, step.thinking) });
1300
+ ctx.onAttemptStart?.(omitUndefinedProperties({ model: candidate, thinking: resolveEffectiveThinking(candidate, step.thinking) }));
1198
1301
  const outputSnapshot = captureSingleOutputSnapshot(step.outputPath);
1199
1302
  if (effectiveStructuredOutput) {
1200
1303
  try {
@@ -1212,9 +1315,9 @@ async function runSingleStep(
1212
1315
  childIndex: ctx.flatIndex,
1213
1316
  })
1214
1317
  : undefined;
1215
- const { args, env, tempDir, toolDiagnosticPath, runtimeAcknowledgedExtensionsPath, capabilityAudit: attemptCapabilityAudit } = buildPiArgs({
1318
+ const { args, env, tempDir, toolDiagnosticPath, runtimeAcknowledgedExtensionsPath, capabilityAudit: attemptCapabilityAudit } = buildPiArgs(omitUndefinedProperties({
1216
1319
  parentSessionId: step.parentSessionId,
1217
- baseArgs: ["--offline", "--mode", "json", "-p"],
1320
+ baseArgs: ["--mode", "json", "-p"],
1218
1321
  task,
1219
1322
  sessionEnabled,
1220
1323
  sessionDir,
@@ -1246,11 +1349,15 @@ async function runSingleStep(
1246
1349
  steerAckDir: ctx.steerAckDir,
1247
1350
  structuredOutput: effectiveStructuredOutput,
1248
1351
  toolBudget: step.toolBudget,
1352
+ permissionRules: step.permissionRules,
1353
+ permissionAuditPath: step.permissionRules && ctx.artifactsDir
1354
+ ? path.join(ctx.artifactsDir, "permission-audit", `${ctx.id}-${ctx.flatIndex}.jsonl`)
1355
+ : undefined,
1249
1356
  childWatchdog,
1250
1357
  waitToolEnabled: step.waitToolEnabled,
1251
- });
1358
+ }));
1252
1359
  if (step.definitionDigest) {
1253
- const toolPlan = resolvePiLaunchToolPlan({
1360
+ const toolPlan = resolvePiLaunchToolPlan(omitUndefinedProperties({
1254
1361
  tools: step.tools,
1255
1362
  extensions: step.extensions,
1256
1363
  subagentOnlyExtensions: step.subagentOnlyExtensions,
@@ -1260,13 +1367,13 @@ async function runSingleStep(
1260
1367
  structuredOutput: Boolean(effectiveStructuredOutput),
1261
1368
  capabilityCeiling: step.capabilityCeiling ?? ctx.capabilityCeiling,
1262
1369
  inheritedCapabilityCeiling: decodeSubagentCapabilityCeiling(process.env[SUBAGENT_CAPABILITY_CEILING_ENV]),
1263
- });
1370
+ }));
1264
1371
  launchResolvedExtensions = projectLaunchResolvedChildExtensions(toolPlan);
1265
- actualLaunchContractDigest = launchBindingDigest({
1372
+ actualLaunchContractDigest = launchBindingDigest(omitUndefinedProperties({
1266
1373
  definitionDigest: step.definitionDigest,
1267
1374
  task: step.launchBindingTask ?? task,
1268
1375
  ...(candidate ? { model: candidate } : {}),
1269
- modelCandidates: candidates,
1376
+ modelCandidates: candidates as string[],
1270
1377
  ...(resolveEffectiveThinking(candidate, step.thinking) ? { thinking: resolveEffectiveThinking(candidate, step.thinking) } : {}),
1271
1378
  systemPrompt: appendTurnBudgetSystemPrompt(step.systemPrompt ?? "", ctx.turnBudget),
1272
1379
  systemPromptMode: step.systemPromptMode,
@@ -1279,7 +1386,7 @@ async function runSingleStep(
1279
1386
  ...(step.outputPath ? { outputPath: step.outputPath } : {}),
1280
1387
  ...(step.outputMode ? { outputMode: step.outputMode } : {}),
1281
1388
  ...(step.structuredOutputSchema ? { structuredOutputSchema: step.structuredOutputSchema } : {}),
1282
- });
1389
+ }));
1283
1390
  }
1284
1391
  capabilityAudit = attemptCapabilityAudit;
1285
1392
  writerAttemptCount += 1;
@@ -1362,13 +1469,13 @@ async function runSingleStep(
1362
1469
  }
1363
1470
  const completionGuardEnabled = isAgentContractV1(step.agentContract) ? step.completionGuard === true : step.completionGuard !== false;
1364
1471
  const completionGuard = run.exitCode === 0 && !run.error && !toolAvailabilityError && !hiddenError?.hasError && !emptyOutputError && completionGuardEnabled
1365
- ? evaluateCompletionMutationGuard({
1472
+ ? evaluateCompletionMutationGuard(omitUndefinedProperties({
1366
1473
  agent: step.agent,
1367
1474
  task: taskForCompletionGuard,
1368
1475
  messages: run.messages,
1369
1476
  tools: step.tools,
1370
1477
  mcpDirectTools: step.mcpDirectTools,
1371
- })
1478
+ }))
1372
1479
  : undefined;
1373
1480
  const completionGuardTriggered = completionGuard?.triggered === true && !run.observedMutationAttempt;
1374
1481
  const fileMutationEffect = completionGuard
@@ -1389,13 +1496,13 @@ async function runSingleStep(
1389
1496
  : run.error && run.exitCode === 0
1390
1497
  ? 1
1391
1498
  : run.exitCode;
1392
- const signalError = run.exitCode !== 0 && isUnexplainedProcessSignal({
1499
+ const signalError = run.exitCode !== 0 && isUnexplainedProcessSignal(omitUndefinedProperties({
1393
1500
  processSignal: run.processSignal,
1394
1501
  interrupted: run.interrupted,
1395
1502
  timedOut: run.timedOut,
1396
1503
  stopped: run.stopped,
1397
1504
  turnBudgetExceeded: run.turnBudgetExceeded,
1398
- }) ? formatProcessSignalError(run.processSignal!) : undefined;
1505
+ })) ? formatProcessSignalError(run.processSignal!) : undefined;
1399
1506
  const error = toolAvailabilityError
1400
1507
  ?? completionGuardError
1401
1508
  ?? structuredError
@@ -1405,13 +1512,13 @@ async function runSingleStep(
1405
1512
  ? `${hiddenError.errorType} failed (exit ${effectiveExitCode}): ${hiddenError.details}`
1406
1513
  : `${hiddenError.errorType} failed with exit code ${effectiveExitCode}`
1407
1514
  : run.error || signalError || (run.exitCode !== 0 && run.stderr.trim() ? run.stderr.trim() : undefined));
1408
- const attempt: ModelAttempt = {
1515
+ const attempt: ModelAttempt = omitUndefinedProperties({
1409
1516
  model: candidate ?? run.model ?? step.model ?? "default",
1410
1517
  success: effectiveExitCode === 0 && !error,
1411
1518
  exitCode: effectiveExitCode,
1412
1519
  error,
1413
1520
  usage: run.usage,
1414
- };
1521
+ });
1415
1522
  modelAttempts.push(attempt);
1416
1523
  if (candidate && startupAttemptIndex === 0) attemptedModels.push(candidate);
1417
1524
  completionGuardTriggeredFinal = completionGuardTriggered;
@@ -1427,7 +1534,7 @@ async function runSingleStep(
1427
1534
  if (run.stopped || run.timedOut || ctx.timeoutSignal?.aborted || ctx.stopSignal?.aborted || ctx.skipAcceptance?.()) break modelAttemptsLoop;
1428
1535
  if (attempt.success || completionGuardTriggered) break modelAttemptsLoop;
1429
1536
 
1430
- const startupFailure = isRetryableSubagentStartupFailure({
1537
+ const startupFailure = isRetryableSubagentStartupFailure(omitUndefinedProperties({
1431
1538
  exitCode: effectiveExitCode,
1432
1539
  error,
1433
1540
  finalOutput: run.finalOutput,
@@ -1442,7 +1549,7 @@ async function runSingleStep(
1442
1549
  timedOut: run.timedOut,
1443
1550
  stopped: run.stopped,
1444
1551
  turnBudgetExceeded: run.turnBudgetExceeded,
1445
- });
1552
+ }));
1446
1553
  const retryDelayMs = SUBAGENT_STARTUP_RETRY_DELAYS_MS[startupAttemptIndex];
1447
1554
  if (startupFailure && retryDelayMs !== undefined) {
1448
1555
  const retryNote = formatSubagentStartupRetryNote({
@@ -1476,11 +1583,7 @@ async function runSingleStep(
1476
1583
 
1477
1584
  const rawOutput = finalResult?.finalOutput ?? "";
1478
1585
  const outputForPersistence = stripAcceptanceReport(rawOutput);
1479
- // Persist whenever an output path is configured and meaningful output exists,
1480
- // not only for successful runs: failed children keep a readable result file
1481
- // and a saved-output reference instead of raw inline output. Synthetic
1482
- // failures without output stay "absent" and are not promoted to a reference.
1483
- const resolvedOutput = step.outputPath && (outputForPersistence.trim() || (finalResult?.exitCode ?? 1) === 0)
1586
+ const resolvedOutput = step.outputPath && finalResult?.exitCode === 0
1484
1587
  ? resolveSingleOutput(step.outputPath, outputForPersistence, finalOutputSnapshot)
1485
1588
  : { fullOutput: outputForPersistence };
1486
1589
  const output = stripAcceptanceReport(resolvedOutput.fullOutput);
@@ -1511,7 +1614,7 @@ async function runSingleStep(
1511
1614
  : resolvedOutput.savedPath
1512
1615
  ? "unknown"
1513
1616
  : finalResult?.outputState ?? "unknown";
1514
- const finalizedOutput = finalizeSingleOutput({
1617
+ const finalizedOutput = finalizeSingleOutput(omitUndefinedProperties({
1515
1618
  fullOutput: outputForSummary,
1516
1619
  outputPath: step.outputPath,
1517
1620
  outputMode: step.outputMode,
@@ -1519,13 +1622,10 @@ async function runSingleStep(
1519
1622
  savedPath: resolvedOutput.savedPath,
1520
1623
  outputReference,
1521
1624
  saveError: resolvedOutput.saveError,
1522
- error: finalResult?.error
1523
- ?? (finalResult?.stopped ? ctx.stopMessage ?? "Subagent stopped by user." : undefined)
1524
- ?? (finalResult?.timedOut ? ctx.timeoutMessage ?? "Subagent timed out." : undefined),
1525
- });
1625
+ }));
1526
1626
  outputForSummary = finalizedOutput.displayOutput;
1527
1627
  const acceptance = step.effectiveAcceptance && !finalResult?.stopped && !finalResult?.turnBudgetExceeded && !ctx.timeoutSignal?.aborted && !ctx.stopSignal?.aborted && !ctx.skipAcceptance?.()
1528
- ? await evaluateAcceptance({
1628
+ ? await evaluateAcceptance(omitUndefinedProperties({
1529
1629
  acceptance: step.effectiveAcceptance,
1530
1630
  output: outputForAcceptance,
1531
1631
  fileOutput: childWrittenOutput !== undefined && step.outputPath
@@ -1535,7 +1635,7 @@ async function runSingleStep(
1535
1635
  signal: combinedAbortSignal([ctx.timeoutSignal, ctx.stopSignal]),
1536
1636
  abortMessage: ctx.stopSignal?.aborted ? ctx.stopMessage ?? "Subagent stopped by user." : ctx.timeoutMessage ?? "Subagent timed out.",
1537
1637
  reportOptional: isAgentContractV1(step.agentContract),
1538
- })
1638
+ }))
1539
1639
  : undefined;
1540
1640
  const stoppedAfterAcceptance = finalResult?.stopped === true || ctx.stopSignal?.aborted === true;
1541
1641
  const timedOutAfterAcceptance = !stoppedAfterAcceptance && (finalResult?.timedOut === true || ctx.timeoutSignal?.aborted === true);
@@ -1562,51 +1662,43 @@ async function runSingleStep(
1562
1662
  ? (finalResult?.error ? `${finalResult.error}\n${acceptanceFailure}` : acceptanceFailure)
1563
1663
  : finalResult?.error;
1564
1664
 
1565
- if (artifactPaths && ctx.artifactConfig?.enabled !== false) {
1566
- if (ctx.artifactConfig?.includeOutput !== false) {
1567
- fs.writeFileSync(artifactPaths.outputPath, formatOutputArtifactContent({
1665
+ const artifactErrors = artifactPaths && ctx.artifactConfig?.enabled !== false
1666
+ ? persistStepArtifacts({
1667
+ artifactPaths,
1668
+ artifactConfig: ctx.artifactConfig,
1669
+ output: formatOutputArtifactContent(omitUndefinedProperties({
1568
1670
  output,
1569
1671
  error: effectiveFinalError,
1570
1672
  transcriptPath: transcriptWriter ? artifactPaths.transcriptPath : undefined,
1571
1673
  metadataPath: ctx.artifactConfig?.includeMetadata === false ? undefined : artifactPaths.metadataPath,
1572
- }), "utf-8");
1573
- }
1574
- if (ctx.artifactConfig?.includeMetadata !== false) {
1575
- fs.writeFileSync(
1576
- artifactPaths.metadataPath,
1577
- JSON.stringify({
1578
- runId: ctx.id,
1579
- agent: step.agent,
1580
- task,
1581
- exitCode: effectiveFinalExitCode,
1582
- model: finalResult?.model,
1583
- attemptedModels: attemptedModels.length > 0 ? attemptedModels : undefined,
1584
- modelAttempts,
1585
- error: effectiveFinalError,
1586
- acceptance: effectiveAcceptance,
1587
- ...(capabilityAudit ? { capabilityCeiling: capabilityAudit.ceiling, capabilityAudit } : {}),
1588
- launchContractDigest: actualLaunchContractDigest,
1589
- launchResolvedExtensions,
1590
- ...((finalResult as (RunPiStreamingResult & { runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1 }) | undefined)?.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: (finalResult as RunPiStreamingResult & { runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1 }).runtimeAcknowledgedExtensions } : {}),
1591
- ...(transcriptWriter ? { transcriptPath: artifactPaths.transcriptPath } : {}),
1592
- transcriptError: transcriptWriter?.getError(),
1593
- skills: step.skills,
1594
- timestamp: Date.now(),
1595
- }, null, 2),
1596
- "utf-8",
1597
- );
1598
- }
1599
- }
1674
+ })),
1675
+ metadata: {
1676
+ runId: ctx.id,
1677
+ agent: step.agent,
1678
+ task,
1679
+ exitCode: effectiveFinalExitCode,
1680
+ model: finalResult?.model,
1681
+ attemptedModels: attemptedModels.length > 0 ? attemptedModels : undefined,
1682
+ modelAttempts,
1683
+ error: effectiveFinalError,
1684
+ acceptance: effectiveAcceptance,
1685
+ ...(capabilityAudit ? { capabilityCeiling: capabilityAudit.ceiling, capabilityAudit } : {}),
1686
+ launchContractDigest: actualLaunchContractDigest,
1687
+ launchResolvedExtensions,
1688
+ ...((finalResult as (RunPiStreamingResult & { runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1 }) | undefined)?.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: (finalResult as RunPiStreamingResult & { runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1 }).runtimeAcknowledgedExtensions } : {}),
1689
+ ...(transcriptWriter ? { transcriptPath: artifactPaths.transcriptPath } : {}),
1690
+ transcriptError: transcriptWriter?.getError(),
1691
+ skills: step.skills,
1692
+ timestamp: Date.now(),
1693
+ },
1694
+ })
1695
+ : {};
1600
1696
 
1601
- const result = {
1697
+ const result: StepResult & { completionGuardTriggered?: boolean } = omitUndefinedProperties({
1602
1698
  agent: step.agent,
1603
1699
  context: step.context,
1604
1700
  ...(step.agentContract ? { agentContract: step.agentContract } : {}),
1605
1701
  launchContractDigest: actualLaunchContractDigest,
1606
- // Authoritative durable output location for parent-facing delivery: the
1607
- // explicit/generated saved output path when present, otherwise the async
1608
- // per-child output log (`asyncDir/output-<flat-index>.log`).
1609
- outputPath: step.outputPath ?? ctx.outputFile,
1610
1702
  output: outputForSummary,
1611
1703
  outputState,
1612
1704
  exitCode: effectiveFinalExitCode,
@@ -1619,6 +1711,8 @@ async function runSingleStep(
1619
1711
  modelAttempts,
1620
1712
  totalCost: costSummaryFromAttempts(modelAttempts),
1621
1713
  artifactPaths,
1714
+ outputSaveError: artifactErrors.outputSaveError,
1715
+ metadataSaveError: artifactErrors.metadataSaveError,
1622
1716
  transcriptPath: transcriptWriter ? artifactPaths?.transcriptPath : undefined,
1623
1717
  transcriptError: transcriptWriter?.getError(),
1624
1718
  interrupted: timedOutAfterAcceptance || stoppedAfterAcceptance || turnBudgetExceeded ? false : finalResult?.interrupted,
@@ -1642,7 +1736,7 @@ async function runSingleStep(
1642
1736
  ...((finalResult as (RunPiStreamingResult & { runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1 }) | undefined)?.runtimeAcknowledgedExtensions ? { runtimeAcknowledgedExtensions: (finalResult as RunPiStreamingResult & { runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1 }).runtimeAcknowledgedExtensions } : {}),
1643
1737
  writerProcesses,
1644
1738
  writerAttemptCount,
1645
- };
1739
+ });
1646
1740
  return isAgentContractV1(step.agentContract) ? attachContractProjections(result as unknown as import("../../shared/types.ts").SingleResult) as unknown as typeof result : result;
1647
1741
  }
1648
1742
 
@@ -1651,6 +1745,17 @@ type RunnerStatusStep = NonNullable<AsyncStatus["steps"]>[number] & {
1651
1745
  description?: string;
1652
1746
  };
1653
1747
 
1748
+ function externalRunnerStatus(runner: SubagentStep["runner"]): ExternalCliRunnerStatus | undefined {
1749
+ if (runner?.type !== "external-cli") return undefined;
1750
+ return {
1751
+ type: "external-cli",
1752
+ command: runner.command,
1753
+ args: runner.args ?? [],
1754
+ promptDelivery: runner.promptDelivery ?? "stdin",
1755
+ capabilities: { stop: true, steer: false, resume: false, structuredOutput: false, toolEvents: false },
1756
+ };
1757
+ }
1758
+
1654
1759
  function appendCapabilityCeilingAppliedEvent(eventsPath: string, runId: string, stepIndex: number, agent: string, result: StepResult): void {
1655
1760
  if (!result.capabilityCeiling) return;
1656
1761
  appendJsonl(eventsPath, JSON.stringify({
@@ -1679,6 +1784,12 @@ type RunnerStatusPayload = Omit<AsyncStatus, "steps" | "parallelGroups" | "pid"
1679
1784
  error?: string;
1680
1785
  };
1681
1786
 
1787
+ function requiredStatusStep(statusPayload: RunnerStatusPayload, index: number): RunnerStatusStep {
1788
+ const step = statusPayload.steps[index];
1789
+ if (!step) throw new Error(`Missing status step at index ${index}`);
1790
+ return step;
1791
+ }
1792
+
1682
1793
  function markParallelGroupSetupFailure(input: {
1683
1794
  statusPayload: RunnerStatusPayload;
1684
1795
  results: StepResult[];
@@ -1694,12 +1805,15 @@ function markParallelGroupSetupFailure(input: {
1694
1805
  }): void {
1695
1806
  for (let taskIndex = 0; taskIndex < input.group.parallel.length; taskIndex++) {
1696
1807
  const flatTaskIndex = input.groupStartFlatIndex + taskIndex;
1697
- input.statusPayload.steps[flatTaskIndex].status = "failed";
1698
- input.statusPayload.steps[flatTaskIndex].startedAt = input.failedAt;
1699
- input.statusPayload.steps[flatTaskIndex].endedAt = input.failedAt;
1700
- input.statusPayload.steps[flatTaskIndex].durationMs = 0;
1701
- input.statusPayload.steps[flatTaskIndex].exitCode = 1;
1702
- input.results.push({ agent: input.group.parallel[taskIndex].agent, context: input.group.parallel[taskIndex].context, output: input.setupError, success: false, exitCode: 1, sessionFile: input.group.parallel[taskIndex].sessionFile });
1808
+ const statusStep = requiredStatusStep(input.statusPayload, flatTaskIndex);
1809
+ const task = input.group.parallel[taskIndex];
1810
+ if (!task) throw new Error(`Missing parallel task at index ${taskIndex}`);
1811
+ statusStep.status = "failed";
1812
+ statusStep.startedAt = input.failedAt;
1813
+ statusStep.endedAt = input.failedAt;
1814
+ statusStep.durationMs = 0;
1815
+ statusStep.exitCode = 1;
1816
+ input.results.push(omitUndefinedProperties({ agent: task.agent, context: task.context, output: input.setupError, success: false, exitCode: 1, sessionFile: task.sessionFile }));
1703
1817
  }
1704
1818
  input.statusPayload.currentStep = input.groupStartFlatIndex;
1705
1819
  input.statusPayload.lastUpdate = input.failedAt;
@@ -1727,16 +1841,17 @@ function markParallelGroupRunning(input: {
1727
1841
  }): void {
1728
1842
  for (let taskIndex = 0; taskIndex < input.group.parallel.length; taskIndex++) {
1729
1843
  const flatTaskIndex = input.groupStartFlatIndex + taskIndex;
1730
- input.statusPayload.steps[flatTaskIndex].status = "pending";
1731
- input.statusPayload.steps[flatTaskIndex].startedAt = undefined;
1732
- input.statusPayload.steps[flatTaskIndex].endedAt = undefined;
1733
- input.statusPayload.steps[flatTaskIndex].durationMs = undefined;
1734
- input.statusPayload.steps[flatTaskIndex].lastActivityAt = undefined;
1735
- input.statusPayload.steps[flatTaskIndex].activityState = undefined;
1736
- input.statusPayload.steps[flatTaskIndex].error = undefined;
1844
+ const statusStep = requiredStatusStep(input.statusPayload, flatTaskIndex);
1845
+ statusStep.status = "pending";
1846
+ delete statusStep.startedAt;
1847
+ delete statusStep.endedAt;
1848
+ delete statusStep.durationMs;
1849
+ delete statusStep.lastActivityAt;
1850
+ delete statusStep.activityState;
1851
+ delete statusStep.error;
1737
1852
  }
1738
1853
  input.statusPayload.currentStep = input.groupStartFlatIndex;
1739
- input.statusPayload.activityState = undefined;
1854
+ delete input.statusPayload.activityState;
1740
1855
  input.statusPayload.lastActivityAt = input.groupStartTime;
1741
1856
  input.statusPayload.lastUpdate = input.groupStartTime;
1742
1857
  input.statusPayload.outputFile = path.join(input.asyncDir, `output-${input.groupStartFlatIndex}.log`);
@@ -1758,8 +1873,9 @@ function prepareParallelTaskRun(
1758
1873
  taskIndex: number,
1759
1874
  ): { taskForRun: SubagentStep; taskCwd: string } {
1760
1875
  if (!worktreeSetup) return { taskForRun: task, taskCwd: cwd };
1876
+ const { cwd: _taskCwd, ...taskForRun } = task;
1761
1877
  return {
1762
- taskForRun: { ...task, cwd: undefined },
1878
+ taskForRun,
1763
1879
  taskCwd: worktreeSetup.worktrees[taskIndex]!.agentCwd,
1764
1880
  };
1765
1881
  }
@@ -1865,7 +1981,7 @@ async function runSubagent(
1865
1981
  for (let stepIndex = 0; stepIndex < steps.length; stepIndex++) {
1866
1982
  const step = steps[stepIndex]!;
1867
1983
  if (isCheckpointRunnerStep(step)) {
1868
- initialStatusSteps.push({
1984
+ initialStatusSteps.push(omitUndefinedProperties({
1869
1985
  agent: `checkpoint:${step.checkpoint}`,
1870
1986
  phase: step.phase,
1871
1987
  label: step.label ?? step.checkpoint,
@@ -1873,7 +1989,7 @@ async function runSubagent(
1873
1989
  checkpoint: { name: step.checkpoint, ...(step.message ? { message: step.message } : {}), status: "pending", stepIndex },
1874
1990
  recentTools: [],
1875
1991
  recentOutput: [],
1876
- });
1992
+ }));
1877
1993
  flatStepCount++;
1878
1994
  continue;
1879
1995
  }
@@ -1881,9 +1997,10 @@ async function runSubagent(
1881
1997
  parallelGroups.push({ start: flatStepCount, count: step.parallel.length, stepIndex });
1882
1998
  for (const task of step.parallel) {
1883
1999
  const taskFlatIndex = flatStepCount;
1884
- const transcriptPath = resolveAsyncStepTranscriptPath({ artifactsDir, artifactConfig, runId: id, agent: task.agent, flatIndex: taskFlatIndex, flatStepCount: initialFlatStepCount });
1885
- initialStatusSteps.push({
2000
+ const transcriptPath = resolveAsyncStepTranscriptPath(omitUndefinedProperties({ artifactsDir, artifactConfig, runId: id, agent: task.agent, flatIndex: taskFlatIndex, flatStepCount: initialFlatStepCount }));
2001
+ initialStatusSteps.push(omitUndefinedProperties({
1886
2002
  agent: task.agent,
2003
+ ...(externalRunnerStatus(task.runner) ? { runner: externalRunnerStatus(task.runner) } : {}),
1887
2004
  ...(statusStepDescription(task.task) ? { description: statusStepDescription(task.task) } : {}),
1888
2005
  ...(task.context ? { context: task.context } : {}),
1889
2006
  phase: task.phase,
@@ -1904,13 +2021,14 @@ async function runSubagent(
1904
2021
  attemptedModels: task.modelCandidates && task.modelCandidates.length > 0 ? task.modelCandidates : task.model ? [task.model] : undefined,
1905
2022
  recentTools: [],
1906
2023
  recentOutput: [],
1907
- });
2024
+ }));
1908
2025
  flatStepCount++;
1909
2026
  }
1910
2027
  } else if (isDynamicRunnerGroup(step)) {
1911
2028
  parallelGroups.push({ start: flatStepCount, count: 1, stepIndex });
1912
- initialStatusSteps.push({
2029
+ initialStatusSteps.push(omitUndefinedProperties({
1913
2030
  agent: `expand:${step.parallel.agent}`,
2031
+ ...(externalRunnerStatus(step.parallel.runner) ? { runner: externalRunnerStatus(step.parallel.runner) } : {}),
1914
2032
  ...(step.parallel.context ? { context: step.parallel.context } : {}),
1915
2033
  phase: step.phase ?? step.parallel.phase,
1916
2034
  label: step.label ?? step.parallel.label ?? `Dynamic fanout (${step.collect.as})`,
@@ -1922,13 +2040,14 @@ async function runSubagent(
1922
2040
  ...(step.parallel.toolBudget ? { toolBudget: initialToolBudgetState(step.parallel.toolBudget) } : {}),
1923
2041
  recentTools: [],
1924
2042
  recentOutput: [],
1925
- });
2043
+ }));
1926
2044
  flatStepCount++;
1927
2045
  } else {
1928
2046
  const stepFlatIndex = flatStepCount;
1929
- const transcriptPath = resolveAsyncStepTranscriptPath({ artifactsDir, artifactConfig, runId: id, agent: step.agent, flatIndex: stepFlatIndex, flatStepCount: initialFlatStepCount });
1930
- initialStatusSteps.push({
2047
+ const transcriptPath = resolveAsyncStepTranscriptPath(omitUndefinedProperties({ artifactsDir, artifactConfig, runId: id, agent: step.agent, flatIndex: stepFlatIndex, flatStepCount: initialFlatStepCount }));
2048
+ initialStatusSteps.push(omitUndefinedProperties({
1931
2049
  agent: step.agent,
2050
+ ...(externalRunnerStatus(step.runner) ? { runner: externalRunnerStatus(step.runner) } : {}),
1932
2051
  ...(statusStepDescription(step.task) ? { description: statusStepDescription(step.task) } : {}),
1933
2052
  ...(step.context ? { context: step.context } : {}),
1934
2053
  phase: step.phase,
@@ -1949,7 +2068,7 @@ async function runSubagent(
1949
2068
  attemptedModels: step.modelCandidates && step.modelCandidates.length > 0 ? step.modelCandidates : step.model ? [step.model] : undefined,
1950
2069
  recentTools: [],
1951
2070
  recentOutput: [],
1952
- });
2071
+ }));
1953
2072
  flatStepCount++;
1954
2073
  }
1955
2074
  }
@@ -1961,7 +2080,7 @@ async function runSubagent(
1961
2080
  step.processTerminal = { version: 1, state: "pending", runId: id, runnerProcessInstanceId: config.runnerProcessInstanceId };
1962
2081
  }
1963
2082
  }
1964
- const statusPayload: RunnerStatusPayload = {
2083
+ const statusPayload: RunnerStatusPayload = omitUndefinedProperties({
1965
2084
  lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
1966
2085
  runId: id,
1967
2086
  ...(config.sessionId ? { sessionId: config.sessionId } : {}),
@@ -1986,12 +2105,14 @@ async function runSubagent(
1986
2105
  ...(config.launchContractDigest ? { launchContractDigest: config.launchContractDigest } : {}),
1987
2106
  ...(config.launchResolvedExtensions ? { launchResolvedExtensions: config.launchResolvedExtensions } : {}),
1988
2107
  ...(config.capabilityCeiling ? { capabilityCeiling: config.capabilityCeiling } : {}),
2108
+ ...(config.parentWorkflowRunId ? { parentWorkflowRunId: config.parentWorkflowRunId } : {}),
2109
+ ...(config.workflowKey ? { workflowKey: config.workflowKey } : {}),
1989
2110
  ...(config.runnerProcessInstanceId ? { processTerminal: { version: 1 as const, state: "pending" as const, runId: id, runnerProcessInstanceId: config.runnerProcessInstanceId } } : {}),
1990
2111
  steps: initialStatusSteps,
1991
2112
  artifactsDir,
1992
2113
  sessionDir: config.sessionDir,
1993
2114
  outputFile: path.join(asyncDir, "output-0.log"),
1994
- };
2115
+ });
1995
2116
 
1996
2117
  fs.mkdirSync(asyncDir, { recursive: true });
1997
2118
  writeAtomicJson(statusPath, statusPayload);
@@ -2009,18 +2130,18 @@ async function runSubagent(
2009
2130
  };
2010
2131
  };
2011
2132
  const refreshUsageBudget = () => {
2012
- statusPayload.usageBudget = usageBudgetState(config.usageBudget, currentUsageTotals());
2133
+ setOptionalProperty(statusPayload, "usageBudget", usageBudgetState(config.usageBudget, currentUsageTotals()));
2013
2134
  return statusPayload.usageBudget;
2014
2135
  };
2015
2136
  const emitNestedSelfEvent = (type: "subagent.nested.updated" | "subagent.nested.completed"): void => {
2016
2137
  if (!config.nestedRoute || !config.nestedSelf) return;
2017
2138
  try {
2018
- writeNestedEvent(config.nestedRoute, {
2139
+ writeNestedEvent(config.nestedRoute, omitUndefinedProperties({
2019
2140
  type,
2020
2141
  ts: Date.now(),
2021
2142
  parentRunId: config.nestedSelf.parentRunId,
2022
2143
  parentStepIndex: config.nestedSelf.parentStepIndex,
2023
- child: nestedSummaryFromAsyncStatus(statusPayload, asyncDir, {
2144
+ child: nestedSummaryFromAsyncStatus(statusPayload, asyncDir, omitUndefinedProperties({
2024
2145
  id,
2025
2146
  parentRunId: config.nestedSelf.parentRunId,
2026
2147
  parentStepIndex: config.nestedSelf.parentStepIndex,
@@ -2028,8 +2149,8 @@ async function runSubagent(
2028
2149
  path: config.nestedSelf.path,
2029
2150
  mode: statusPayload.mode,
2030
2151
  ts: Date.now(),
2031
- }),
2032
- });
2152
+ })),
2153
+ }));
2033
2154
  } catch (error) {
2034
2155
  console.error("Failed to emit nested async status event:", error);
2035
2156
  }
@@ -2047,9 +2168,9 @@ async function runSubagent(
2047
2168
  const step = statusPayload.steps[node.flatIndex];
2048
2169
  if (step) {
2049
2170
  node.status = normalize(step.status);
2050
- node.error = step.error;
2051
- node.acceptanceStatus = step.acceptance?.status;
2052
- node.checkpoint = step.checkpoint;
2171
+ setOptionalProperty(node, "error", step.error);
2172
+ setOptionalProperty(node, "acceptanceStatus", step.acceptance?.status);
2173
+ setOptionalProperty(node, "checkpoint", step.checkpoint);
2053
2174
  }
2054
2175
  if (statusPayload.currentStep === node.flatIndex) graph.currentNodeId = node.id;
2055
2176
  }
@@ -2072,6 +2193,11 @@ async function runSubagent(
2072
2193
  writeAtomicJson(statusPath, statusPayload);
2073
2194
  emitNestedSelfEvent(statusPayload.state === "running" || statusPayload.state === "queued" ? "subagent.nested.updated" : "subagent.nested.completed");
2074
2195
  };
2196
+ const updateExternalProcess = (index: number, process: ExternalProcessStatus): void => {
2197
+ requiredStatusStep(statusPayload, index).externalProcess = process;
2198
+ statusPayload.lastUpdate = Date.now();
2199
+ writeStatusPayload();
2200
+ };
2075
2201
  const registerStepInterrupt = (flatIndex: number, interrupt: (() => void) | undefined): void => {
2076
2202
  if (!interrupt) {
2077
2203
  activeChildInterrupts.delete(flatIndex);
@@ -2138,7 +2264,7 @@ async function runSubagent(
2138
2264
  const nestedAsyncDir = run.asyncDir ?? resolveNestedAsyncDir(config.nestedRoute.rootRunId, run);
2139
2265
  if (!nestedAsyncDir) continue;
2140
2266
  try {
2141
- deliverInterruptRequest({ asyncDir: nestedAsyncDir, pid: run.pid, source: "ancestor-interrupt" });
2267
+ deliverInterruptRequest(omitUndefinedProperties({ asyncDir: nestedAsyncDir, pid: run.pid, source: "ancestor-interrupt" }));
2142
2268
  } catch (error) {
2143
2269
  appendJsonl(eventsPath, JSON.stringify({
2144
2270
  type: "subagent.nested.interrupt_failed",
@@ -2169,7 +2295,7 @@ async function runSubagent(
2169
2295
  const nestedAsyncDir = run.asyncDir ?? resolveNestedAsyncDir(config.nestedRoute.rootRunId, run);
2170
2296
  if (!nestedAsyncDir) continue;
2171
2297
  try {
2172
- deliverStopRequest({ asyncDir: nestedAsyncDir, pid: run.pid, source: "ancestor-stop" });
2298
+ deliverStopRequest(omitUndefinedProperties({ asyncDir: nestedAsyncDir, pid: run.pid, source: "ancestor-stop" }));
2173
2299
  } catch (error) {
2174
2300
  appendJsonl(eventsPath, JSON.stringify({
2175
2301
  type: "subagent.nested.stop_failed",
@@ -2200,7 +2326,7 @@ async function runSubagent(
2200
2326
  const nestedAsyncDir = run.asyncDir ?? resolveNestedAsyncDir(config.nestedRoute.rootRunId, run);
2201
2327
  if (!nestedAsyncDir) continue;
2202
2328
  try {
2203
- deliverTimeoutRequest({ asyncDir: nestedAsyncDir, pid: run.pid, source: "ancestor-timeout" });
2329
+ deliverTimeoutRequest(omitUndefinedProperties({ asyncDir: nestedAsyncDir, pid: run.pid, source: "ancestor-timeout" }));
2204
2330
  } catch (error) {
2205
2331
  appendJsonl(eventsPath, JSON.stringify({
2206
2332
  type: "subagent.nested.timeout_failed",
@@ -2212,14 +2338,14 @@ async function runSubagent(
2212
2338
  }
2213
2339
  }
2214
2340
  };
2215
- const pausedStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => ({
2341
+ const pausedStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => omitUndefinedProperties({
2216
2342
  agent,
2217
2343
  context,
2218
2344
  output: "Paused after interrupt. Waiting for explicit next action.",
2219
2345
  exitCode: 0,
2220
2346
  interrupted: true,
2221
2347
  });
2222
- const timedOutStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => ({
2348
+ const timedOutStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => omitUndefinedProperties({
2223
2349
  agent,
2224
2350
  context,
2225
2351
  output: timeoutMessage ?? "Subagent timed out.",
@@ -2227,7 +2353,7 @@ async function runSubagent(
2227
2353
  exitCode: 1,
2228
2354
  timedOut: true,
2229
2355
  });
2230
- const stoppedStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => ({
2356
+ const stoppedStepResult = (agent: string, context?: "fresh" | "fork"): SingleStepResult => omitUndefinedProperties({
2231
2357
  agent,
2232
2358
  context,
2233
2359
  output: stopMessage,
@@ -2278,8 +2404,8 @@ async function runSubagent(
2278
2404
  const groupNode = statusPayload.workflowGraph?.nodes.find((node) => node.id === `step-${stepIndex}`);
2279
2405
  if (!groupNode) return;
2280
2406
  groupNode.status = status;
2281
- groupNode.error = error;
2282
- groupNode.acceptanceStatus = acceptance?.status ?? groupNode.acceptanceStatus;
2407
+ setOptionalProperty(groupNode, "error", error);
2408
+ setOptionalProperty(groupNode, "acceptanceStatus", acceptance?.status ?? groupNode.acceptanceStatus);
2283
2409
  };
2284
2410
 
2285
2411
  const stepOutputActivityAt = (index: number): number => {
@@ -2326,9 +2452,9 @@ async function runSubagent(
2326
2452
  const activeStep = statusPayload.steps
2327
2453
  .filter((step) => step.status === "running" && typeof step.currentTool === "string" && step.currentTool.length > 0)
2328
2454
  .sort((left, right) => (right.currentToolStartedAt ?? 0) - (left.currentToolStartedAt ?? 0))[0];
2329
- statusPayload.currentTool = activeStep?.currentTool;
2330
- statusPayload.currentToolStartedAt = activeStep?.currentToolStartedAt;
2331
- statusPayload.currentPath = activeStep?.currentPath;
2455
+ setOptionalProperty(statusPayload, "currentTool", activeStep?.currentTool);
2456
+ setOptionalProperty(statusPayload, "currentToolStartedAt", activeStep?.currentToolStartedAt);
2457
+ setOptionalProperty(statusPayload, "currentPath", activeStep?.currentPath);
2332
2458
  };
2333
2459
  const syncAggregateActivityState = (): void => {
2334
2460
  const nextRunState = statusPayload.steps.some((step) => step.activityState === "needs_attention")
@@ -2337,7 +2463,7 @@ async function runSubagent(
2337
2463
  ? "active_long_running"
2338
2464
  : undefined;
2339
2465
  currentActivityState = nextRunState;
2340
- statusPayload.activityState = nextRunState;
2466
+ setOptionalProperty(statusPayload, "activityState", nextRunState);
2341
2467
  };
2342
2468
  const maybeEmitActiveLongRunning = (flatIndex: number, now: number): boolean => {
2343
2469
  if (!controlConfig.enabled || activeLongRunningSteps.has(flatIndex)) return false;
@@ -2354,7 +2480,7 @@ async function runSubagent(
2354
2480
  const previous = step.activityState;
2355
2481
  step.activityState = "active_long_running";
2356
2482
  statusPayload.activityState = statusPayload.activityState === "needs_attention" ? "needs_attention" : "active_long_running";
2357
- const event = buildControlEvent({
2483
+ const event = buildControlEvent(omitUndefinedProperties({
2358
2484
  type: "active_long_running",
2359
2485
  from: previous,
2360
2486
  to: "active_long_running",
@@ -2371,7 +2497,7 @@ async function runSubagent(
2371
2497
  currentToolDurationMs: step.currentToolStartedAt ? Math.max(0, now - step.currentToolStartedAt) : undefined,
2372
2498
  currentPath: step.currentPath,
2373
2499
  elapsedMs: now - (step.startedAt ?? overallStartTime),
2374
- });
2500
+ }));
2375
2501
  appendControlEvent(event);
2376
2502
  return true;
2377
2503
  };
@@ -2389,12 +2515,12 @@ async function runSubagent(
2389
2515
  };
2390
2516
  const recordSteeringLifecycle = (request: SteerRequest, targets: Array<{ index: number; state: SteeringTargetState; reason?: string }>): void => {
2391
2517
  const lifecycle = steeringStatus(statusPayload);
2392
- recordSteeringRequest(lifecycle, { id: request.id, requestedAt: request.ts, source: request.source, message: request.message, targets });
2518
+ recordSteeringRequest(lifecycle, omitUndefinedProperties({ id: request.id, requestedAt: request.ts, source: request.source, message: request.message, targets }));
2393
2519
  for (const target of targets) {
2394
2520
  const step = statusPayload.steps[target.index];
2395
2521
  if (!step) continue;
2396
2522
  step.steering ??= createSteeringStatus();
2397
- recordSteeringRequest(step.steering, { id: request.id, requestedAt: request.ts, source: request.source, message: request.message, targets: [target] });
2523
+ recordSteeringRequest(step.steering, omitUndefinedProperties({ id: request.id, requestedAt: request.ts, source: request.source, message: request.message, targets: [target] }));
2398
2524
  }
2399
2525
  };
2400
2526
  const updateSteeringLifecycleTarget = (
@@ -2484,7 +2610,7 @@ async function runSubagent(
2484
2610
  const late = fs.existsSync(steeringMarkerPath(ack.requestId));
2485
2611
  const now = Date.now();
2486
2612
  if (ack.state === "delivered") {
2487
- updateSteeringLifecycleTarget(ack.requestId, ack.index, late ? "late" : "delivered", now, { reason: late ? "acknowledged after recovery commit" : undefined });
2613
+ updateSteeringLifecycleTarget(ack.requestId, ack.index, late ? "late" : "delivered", now, omitUndefinedProperties({ reason: late ? "acknowledged after recovery commit" : undefined }));
2488
2614
  emitSteeringEvent("subagent.steer.delivered", { type: "steer", id: ack.requestId, ts: now, message: ack.message }, ack.index, { late, message: ack.message });
2489
2615
  } else {
2490
2616
  markSteeringAttention(ack.index);
@@ -2507,8 +2633,8 @@ async function runSubagent(
2507
2633
  const updateStepModel = (flatIndex: number, model: string | undefined, thinking: string | undefined, now = Date.now()): void => {
2508
2634
  const step = statusPayload.steps[flatIndex];
2509
2635
  if (!step) return;
2510
- step.model = model;
2511
- step.thinking = thinking;
2636
+ setOptionalProperty(step, "model", model);
2637
+ setOptionalProperty(step, "thinking", thinking);
2512
2638
  statusPayload.lastUpdate = now;
2513
2639
  writeStatusPayload();
2514
2640
  };
@@ -2605,8 +2731,8 @@ async function runSubagent(
2605
2731
  step.currentTool = event.toolName;
2606
2732
  step.currentToolArgs = extractToolArgsPreview(event.args ?? {});
2607
2733
  step.currentToolStartedAt = now;
2608
- step.currentPath = currentPath;
2609
- pendingToolResults[flatIndex] = { tool: event.toolName, path: currentPath, mutates, startedAt: now };
2734
+ setOptionalProperty(step, "currentPath", currentPath);
2735
+ pendingToolResults[flatIndex] = omitUndefinedProperties({ tool: event.toolName, path: currentPath, mutates, startedAt: now });
2610
2736
  statusPayload.toolCount = (statusPayload.toolCount ?? 0) + 1;
2611
2737
  syncTopLevelCurrentTool();
2612
2738
  if (controlConfig.enabled && isBlockingSupervisorTool(event.toolName, event.args) && step.activityState !== "needs_attention") {
@@ -2615,7 +2741,7 @@ async function runSubagent(
2615
2741
  supervisorAttentionSteps.set(flatIndex, previous);
2616
2742
  currentActivityState = "needs_attention";
2617
2743
  statusPayload.activityState = "needs_attention";
2618
- appendControlEvent(buildControlEvent({
2744
+ appendControlEvent(buildControlEvent(omitUndefinedProperties({
2619
2745
  type: "needs_attention",
2620
2746
  from: previous,
2621
2747
  to: "needs_attention",
@@ -2631,7 +2757,7 @@ async function runSubagent(
2631
2757
  currentTool: step.currentTool,
2632
2758
  currentToolDurationMs: 0,
2633
2759
  currentPath: step.currentPath,
2634
- }));
2760
+ })));
2635
2761
  }
2636
2762
  } else if (event.type === "tool_execution_end") {
2637
2763
  if (step.currentTool) {
@@ -2640,12 +2766,12 @@ async function runSubagent(
2640
2766
  }
2641
2767
  const supervisorPreviousActivity = supervisorAttentionSteps.get(flatIndex);
2642
2768
  const clearedSupervisorAttention = supervisorAttentionSteps.delete(flatIndex);
2643
- step.currentTool = undefined;
2644
- step.currentToolArgs = undefined;
2645
- step.currentToolStartedAt = undefined;
2646
- step.currentPath = undefined;
2769
+ delete step.currentTool;
2770
+ delete step.currentToolArgs;
2771
+ delete step.currentToolStartedAt;
2772
+ delete step.currentPath;
2647
2773
  if (clearedSupervisorAttention && step.activityState === "needs_attention") {
2648
- step.activityState = supervisorPreviousActivity;
2774
+ setOptionalProperty(step, "activityState", supervisorPreviousActivity);
2649
2775
  syncAggregateActivityState();
2650
2776
  }
2651
2777
  syncTopLevelCurrentTool();
@@ -2665,17 +2791,17 @@ async function runSubagent(
2665
2791
  appendRecentStepOutput(step, resultText.split("\n").slice(-10));
2666
2792
  if (toolSnapshot?.mutates && didMutatingToolFail(resultText)) {
2667
2793
  const state = mutatingFailureStates[flatIndex]!;
2668
- recordMutatingFailure(state, {
2794
+ recordMutatingFailure(state, omitUndefinedProperties({
2669
2795
  tool: toolSnapshot.tool,
2670
2796
  path: toolSnapshot.path,
2671
2797
  error: resultText.split("\n").find((line) => line.trim())?.trim().slice(0, 180) ?? "mutating tool failed",
2672
2798
  ts: now,
2673
- }, mutatingFailureWindowMs);
2799
+ }), mutatingFailureWindowMs);
2674
2800
  if (controlConfig.enabled && shouldEscalateMutatingFailures(state, controlConfig.failedToolAttemptsBeforeAttention) && step.activityState !== "needs_attention") {
2675
2801
  const previous = step.activityState;
2676
2802
  step.activityState = "needs_attention";
2677
2803
  statusPayload.activityState = "needs_attention";
2678
- appendControlEvent(buildControlEvent({
2804
+ appendControlEvent(buildControlEvent(omitUndefinedProperties({
2679
2805
  type: "needs_attention",
2680
2806
  from: previous,
2681
2807
  to: "needs_attention",
@@ -2692,7 +2818,7 @@ async function runSubagent(
2692
2818
  currentToolDurationMs: toolSnapshot.startedAt ? Math.max(0, now - toolSnapshot.startedAt) : undefined,
2693
2819
  currentPath: toolSnapshot.path,
2694
2820
  recentFailureSummary: summarizeRecentMutatingFailures(state),
2695
- }));
2821
+ })));
2696
2822
  }
2697
2823
  } else if (toolSnapshot?.mutates) {
2698
2824
  resetMutatingFailureState(mutatingFailureStates[flatIndex]!);
@@ -2741,18 +2867,18 @@ async function runSubagent(
2741
2867
  step.lastActivityAt = lastActivityAt;
2742
2868
  changed = true;
2743
2869
  }
2744
- const idleState = deriveActivityState({
2870
+ const idleState = deriveActivityState(omitUndefinedProperties({
2745
2871
  config: controlConfig,
2746
2872
  startedAt: step.startedAt ?? overallStartTime,
2747
2873
  lastActivityAt,
2748
2874
  currentTool: step.currentTool,
2749
2875
  now,
2750
- });
2876
+ }));
2751
2877
  if (idleState === "needs_attention") {
2752
2878
  const previous = step.activityState;
2753
2879
  step.activityState = "needs_attention";
2754
2880
  if (previous !== "needs_attention") {
2755
- appendControlEvent(buildControlEvent({
2881
+ appendControlEvent(buildControlEvent(omitUndefinedProperties({
2756
2882
  from: previous,
2757
2883
  to: "needs_attention",
2758
2884
  runId: id,
@@ -2760,7 +2886,7 @@ async function runSubagent(
2760
2886
  index,
2761
2887
  ts: now,
2762
2888
  lastActivityAt,
2763
- }));
2889
+ })));
2764
2890
  changed = true;
2765
2891
  }
2766
2892
  } else if (maybeEmitActiveLongRunning(index, now)) {
@@ -2778,7 +2904,7 @@ async function runSubagent(
2778
2904
  : undefined;
2779
2905
  if (nextRunState !== currentActivityState) {
2780
2906
  currentActivityState = nextRunState;
2781
- statusPayload.activityState = nextRunState;
2907
+ setOptionalProperty(statusPayload, "activityState", nextRunState);
2782
2908
  changed = true;
2783
2909
  }
2784
2910
  statusPayload.lastUpdate = now;
@@ -2801,14 +2927,14 @@ async function runSubagent(
2801
2927
  const now = Date.now();
2802
2928
  statusPayload.state = "paused";
2803
2929
  currentActivityState = undefined;
2804
- statusPayload.activityState = undefined;
2930
+ delete statusPayload.activityState;
2805
2931
  statusPayload.lastUpdate = now;
2806
2932
  for (const step of statusPayload.steps) {
2807
2933
  if (step.status === "running") {
2808
2934
  step.status = "paused";
2809
- step.activityState = undefined;
2935
+ delete step.activityState;
2810
2936
  step.endedAt = now;
2811
- step.durationMs = step.startedAt ? now - step.startedAt : undefined;
2937
+ setOptionalProperty(step, "durationMs", step.startedAt ? now - step.startedAt : undefined);
2812
2938
  step.lastActivityAt = now;
2813
2939
  }
2814
2940
  }
@@ -2829,7 +2955,7 @@ async function runSubagent(
2829
2955
  statusPayload.stopped = true;
2830
2956
  statusPayload.error = stopMessage;
2831
2957
  currentActivityState = undefined;
2832
- statusPayload.activityState = undefined;
2958
+ delete statusPayload.activityState;
2833
2959
  statusPayload.lastUpdate = now;
2834
2960
  for (const step of statusPayload.steps) {
2835
2961
  if (step.status !== "running" && step.status !== "pending") continue;
@@ -2837,7 +2963,7 @@ async function runSubagent(
2837
2963
  step.error = stopMessage;
2838
2964
  step.exitCode = 1;
2839
2965
  step.stopped = true;
2840
- step.activityState = undefined;
2966
+ delete step.activityState;
2841
2967
  step.endedAt = now;
2842
2968
  step.durationMs = step.startedAt ? now - step.startedAt : 0;
2843
2969
  step.lastActivityAt = now;
@@ -2862,7 +2988,7 @@ async function runSubagent(
2862
2988
  statusPayload.timedOut = true;
2863
2989
  statusPayload.error = message;
2864
2990
  currentActivityState = undefined;
2865
- statusPayload.activityState = undefined;
2991
+ delete statusPayload.activityState;
2866
2992
  statusPayload.lastUpdate = now;
2867
2993
  for (const step of statusPayload.steps) {
2868
2994
  if (step.status !== "running" && step.status !== "pending") continue;
@@ -2870,7 +2996,7 @@ async function runSubagent(
2870
2996
  step.error = message;
2871
2997
  step.exitCode = 1;
2872
2998
  step.timedOut = true;
2873
- step.activityState = undefined;
2999
+ delete step.activityState;
2874
3000
  step.endedAt = now;
2875
3001
  step.durationMs = step.startedAt ? now - step.startedAt : 0;
2876
3002
  step.lastActivityAt = now;
@@ -2988,7 +3114,7 @@ async function runSubagent(
2988
3114
  statusPayload.state = "paused";
2989
3115
  statusPayload.currentStep = flatIndex;
2990
3116
  statusPayload.checkpoint = checkpoint;
2991
- statusPayload.activityState = undefined;
3117
+ delete statusPayload.activityState;
2992
3118
  statusPayload.lastUpdate = now;
2993
3119
  if (statusStep) {
2994
3120
  statusStep.status = "paused";
@@ -3043,7 +3169,7 @@ async function runSubagent(
3043
3169
  const groupStartFlatIndex = flatIndex;
3044
3170
  let materialized: ReturnType<typeof materializeDynamicParallelStep>;
3045
3171
  try {
3046
- materialized = materializeDynamicParallelStep(step as Parameters<typeof materializeDynamicParallelStep>[0], outputs, stepIndex, { maxItems: config.dynamicFanoutMaxItems, allowRunnerFields: true });
3172
+ materialized = materializeDynamicParallelStep(step as Parameters<typeof materializeDynamicParallelStep>[0], outputs, stepIndex, omitUndefinedProperties({ maxItems: config.dynamicFanoutMaxItems, allowRunnerFields: true }));
3047
3173
  if (materialized.parallel.length > 1 && step.parallel.outputPath && !step.parallel.namespaceOutputPath) {
3048
3174
  throw new DynamicFanoutError(`Dynamic chain step ${stepIndex + 1} materialized ${materialized.parallel.length} items that resolve output to the same path: ${step.parallel.outputPath}. Remove the explicit output path or use an inherited relative agent output so each item can be isolated.`);
3049
3175
  }
@@ -3066,11 +3192,11 @@ async function runSubagent(
3066
3192
  statusPayload.lastUpdate = now;
3067
3193
  markDynamicGraphGroup(stepIndex, "failed", message);
3068
3194
  writeStatusPayload();
3069
- results.push({ agent: step.parallel.agent, context: step.parallel.context, output: message, error: message, success: false, exitCode: 1 });
3195
+ results.push(omitUndefinedProperties({ agent: step.parallel.agent, context: step.parallel.context, output: message, error: message, success: false, exitCode: 1 }));
3070
3196
  break;
3071
3197
  }
3072
3198
 
3073
- const effectiveDynamicGroupAcceptance = resolveEffectiveAcceptance({
3199
+ const effectiveDynamicGroupAcceptance = resolveEffectiveAcceptance(omitUndefinedProperties({
3074
3200
  explicit: step.acceptanceInput,
3075
3201
  agentName: step.parallel.agent,
3076
3202
  acceptanceRole: step.acceptanceRole,
@@ -3079,7 +3205,7 @@ async function runSubagent(
3079
3205
  async: true,
3080
3206
  dynamicGroup: true,
3081
3207
  agentContract: step.agentContract,
3082
- });
3208
+ }));
3083
3209
 
3084
3210
  if (materialized.parallel.length === 0) {
3085
3211
  const now = Date.now();
@@ -3100,7 +3226,7 @@ async function runSubagent(
3100
3226
  }
3101
3227
  previousOutput = "Dynamic fanout produced 0 results.";
3102
3228
  const groupAcceptance = effectiveDynamicGroupAcceptance.explicit && !timedOut && !stopped
3103
- ? await evaluateAcceptance({
3229
+ ? await evaluateAcceptance(omitUndefinedProperties({
3104
3230
  acceptance: effectiveDynamicGroupAcceptance,
3105
3231
  output: "",
3106
3232
  report: aggregateAcceptanceReport({
@@ -3111,7 +3237,7 @@ async function runSubagent(
3111
3237
  signal: combinedAbortSignal([timeoutAbortController.signal, stopAbortController.signal]),
3112
3238
  abortMessage: stopAbortController.signal.aborted ? stopMessage : timeoutMessage ?? "Subagent timed out.",
3113
3239
  reportOptional: isAgentContractV1(step.agentContract),
3114
- })
3240
+ }))
3115
3241
  : undefined;
3116
3242
  const groupStopped = stopped || stopAbortController.signal.aborted;
3117
3243
  const groupTimedOut = !groupStopped && (timedOut || timeoutAbortController.signal.aborted);
@@ -3122,18 +3248,18 @@ async function runSubagent(
3122
3248
  const errorMessage = groupStopped ? stopMessage : groupTimedOut ? timeoutMessage ?? "Subagent timed out." : groupAcceptanceFailure!;
3123
3249
  statusPayload.state = groupStopped ? "stopped" : "failed";
3124
3250
  statusPayload.error = errorMessage;
3125
- statusPayload.stopped = groupStopped ? true : statusPayload.stopped;
3251
+ setOptionalProperty(statusPayload, "stopped", groupStopped ? true : statusPayload.stopped);
3126
3252
  if (placeholder) {
3127
3253
  placeholder.status = groupStopped ? "stopped" : "failed";
3128
3254
  placeholder.error = errorMessage;
3129
3255
  placeholder.exitCode = 1;
3130
- placeholder.timedOut = groupTimedOut ? true : undefined;
3131
- placeholder.stopped = groupStopped ? true : undefined;
3256
+ setOptionalProperty(placeholder, "timedOut", groupTimedOut ? true : undefined);
3257
+ setOptionalProperty(placeholder, "stopped", groupStopped ? true : undefined);
3132
3258
  }
3133
3259
  markDynamicGraphGroup(stepIndex, groupStopped ? "stopped" : "failed", errorMessage, effectiveGroupAcceptance);
3134
3260
  statusPayload.lastUpdate = Date.now();
3135
3261
  writeStatusPayload();
3136
- results.push({ agent: step.parallel.agent, context: step.parallel.context, output: errorMessage, error: errorMessage, success: false, exitCode: 1, timedOut: groupTimedOut ? true : undefined, stopped: groupStopped ? true : undefined, acceptance: effectiveGroupAcceptance });
3262
+ results.push(omitUndefinedProperties({ agent: step.parallel.agent, context: step.parallel.context, output: errorMessage, error: errorMessage, success: false, exitCode: 1, timedOut: groupTimedOut ? true : undefined, stopped: groupStopped ? true : undefined, acceptance: effectiveGroupAcceptance }));
3137
3263
  break;
3138
3264
  }
3139
3265
  flatIndex++;
@@ -3152,10 +3278,10 @@ async function runSubagent(
3152
3278
  : step.parallel.outputPath;
3153
3279
  const taskText = task.task ?? step.parallel.task;
3154
3280
  const materializedTask = step.parallel.namespaceOutputPath ? injectSingleOutputInstruction(taskText, outputPath, step.parallel) : taskText;
3155
- return {
3281
+ return omitUndefinedProperties({
3156
3282
  ...step.parallel,
3157
3283
  task: materializedTask,
3158
- effectiveAcceptance: resolveEffectiveAcceptance({
3284
+ effectiveAcceptance: resolveEffectiveAcceptance(omitUndefinedProperties({
3159
3285
  explicit: step.parallel.acceptanceInput,
3160
3286
  agentName: step.parallel.agent,
3161
3287
  acceptanceRole: step.parallel.acceptanceRole,
@@ -3164,7 +3290,7 @@ async function runSubagent(
3164
3290
  async: true,
3165
3291
  dynamic: step.parallel.acceptanceInput === undefined,
3166
3292
  agentContract: step.parallel.agentContract ?? step.agentContract,
3167
- }),
3293
+ })),
3168
3294
  systemPrompt: step.parallel.namespaceOutputPath ? injectOutputPathSystemPrompt(step.parallel.systemPrompt ?? "", outputPath, step.parallel) : step.parallel.systemPrompt,
3169
3295
  outputPath,
3170
3296
  label: task.label ?? step.parallel.label,
@@ -3172,22 +3298,23 @@ async function runSubagent(
3172
3298
  ...(thinkingOverride ? {
3173
3299
  ...(model ? { model } : {}),
3174
3300
  ...(thinking ? { thinking } : {}),
3175
- ...(step.parallel.modelCandidates ? { modelCandidates: step.parallel.modelCandidates.map((candidate) => applyThinkingSuffix(candidate, thinkingOverride, true)) } : {}),
3301
+ ...(step.parallel.modelCandidates ? { modelCandidates: step.parallel.modelCandidates.flatMap((candidate) => {
3302
+ const resolved = applyThinkingSuffix(candidate, thinkingOverride, true);
3303
+ return resolved ? [resolved] : [];
3304
+ }) } : {}),
3176
3305
  } : {}),
3177
- structuredOutput: undefined,
3178
3306
  structuredOutputSchema: step.parallel.structuredOutputSchema ?? step.parallel.structuredOutput?.schema,
3179
- };
3307
+ });
3180
3308
  });
3181
3309
  const dynamicFlatStepCount = Math.max(statusPayload.steps.length - 1 + dynamicSteps.length, 1);
3182
3310
  const dynamicStatusSteps: RunnerStatusStep[] = dynamicSteps.map((task, itemIndex) => {
3183
- const transcriptPath = resolveAsyncStepTranscriptPath({ artifactsDir, artifactConfig, runId: id, agent: task.agent, flatIndex: groupStartFlatIndex + itemIndex, flatStepCount: dynamicFlatStepCount });
3184
- return {
3311
+ const transcriptPath = resolveAsyncStepTranscriptPath(omitUndefinedProperties({ artifactsDir, artifactConfig, runId: id, agent: task.agent, flatIndex: groupStartFlatIndex + itemIndex, flatStepCount: dynamicFlatStepCount }));
3312
+ return omitUndefinedProperties({
3185
3313
  agent: task.agent,
3186
3314
  ...(statusStepDescription(task.task) ? { description: statusStepDescription(task.task) } : {}),
3187
3315
  ...(task.context ? { context: task.context } : {}),
3188
- phase: task.phase ?? step.phase,
3189
- label: task.label,
3190
- outputName: undefined,
3316
+ ...(task.phase ?? step.phase ? { phase: task.phase ?? step.phase } : {}),
3317
+ ...(task.label ? { label: task.label } : {}),
3191
3318
  structured: Boolean(task.structuredOutputSchema),
3192
3319
  ...(task.agentContract ? { agentContract: task.agentContract } : {}),
3193
3320
  ...(task.launchResolvedExtensions ? { launchResolvedExtensions: task.launchResolvedExtensions } : {}),
@@ -3195,13 +3322,13 @@ async function runSubagent(
3195
3322
  status: "pending",
3196
3323
  ...(task.sessionFile ? { sessionFile: task.sessionFile } : {}),
3197
3324
  ...(transcriptPath ? { transcriptPath } : {}),
3198
- skills: task.skills,
3199
- model: task.model,
3200
- thinking: task.thinking,
3201
- attemptedModels: task.modelCandidates && task.modelCandidates.length > 0 ? task.modelCandidates : task.model ? [task.model] : undefined,
3325
+ ...(task.skills ? { skills: task.skills } : {}),
3326
+ ...(task.model ? { model: task.model } : {}),
3327
+ ...(task.thinking ? { thinking: task.thinking } : {}),
3328
+ ...(task.modelCandidates && task.modelCandidates.length > 0 ? { attemptedModels: task.modelCandidates } : task.model ? { attemptedModels: [task.model] } : {}),
3202
3329
  recentTools: [],
3203
3330
  recentOutput: [],
3204
- };
3331
+ });
3205
3332
  });
3206
3333
  statusPayload.steps.splice(groupStartFlatIndex, 1, ...dynamicStatusSteps);
3207
3334
  if (config.childIntercomTargets) {
@@ -3230,7 +3357,7 @@ async function runSubagent(
3230
3357
  shiftFlatIndexes(statusPayload.workflowGraph.nodes);
3231
3358
  const groupNode = statusPayload.workflowGraph.nodes.find((node) => node.id === `step-${stepIndex}`);
3232
3359
  if (groupNode) {
3233
- groupNode.children = materialized.items.map((item, itemIndex) => ({
3360
+ groupNode.children = materialized.items.map((item, itemIndex) => omitUndefinedProperties({
3234
3361
  id: `step-${stepIndex}-item-${item.idKey}`,
3235
3362
  kind: "agent",
3236
3363
  agent: step.parallel.agent,
@@ -3249,54 +3376,54 @@ async function runSubagent(
3249
3376
  const concurrency = step.concurrency ?? MAX_PARALLEL_CONCURRENCY;
3250
3377
  const failFast = step.failFast ?? false;
3251
3378
  let aborted = false;
3252
- const parallelResults = await mapConcurrent(dynamicSteps, concurrency, async (task, taskIdx) => {
3379
+ const parallelResults = await mapConcurrent(dynamicSteps, concurrency, async (task, taskIdx): Promise<StepResult> => {
3253
3380
  const fi = groupStartFlatIndex + taskIdx;
3254
3381
  refreshUsageBudget();
3255
3382
  if (statusPayload.usageBudget?.exhausted) {
3256
3383
  const skippedAt = Date.now();
3257
3384
  const message = usageBudgetExceededMessage(statusPayload.usageBudget);
3258
- statusPayload.steps[fi].status = "failed";
3259
- statusPayload.steps[fi].error = message;
3260
- statusPayload.steps[fi].startedAt = skippedAt;
3261
- statusPayload.steps[fi].endedAt = skippedAt;
3262
- statusPayload.steps[fi].durationMs = 0;
3263
- statusPayload.steps[fi].exitCode = 1;
3385
+ requiredStatusStep(statusPayload, fi).status = "failed";
3386
+ requiredStatusStep(statusPayload, fi).error = message;
3387
+ requiredStatusStep(statusPayload, fi).startedAt = skippedAt;
3388
+ requiredStatusStep(statusPayload, fi).endedAt = skippedAt;
3389
+ requiredStatusStep(statusPayload, fi).durationMs = 0;
3390
+ requiredStatusStep(statusPayload, fi).exitCode = 1;
3264
3391
  statusPayload.lastUpdate = skippedAt;
3265
3392
  usageBudgetExceeded = true;
3266
3393
  writeStatusPayload();
3267
3394
  appendJsonl(eventsPath, JSON.stringify({ type: "subagent.step.failed", ts: skippedAt, runId: id, stepIndex: fi, agent: task.agent, exitCode: 1, durationMs: 0 }));
3268
- return { agent: task.agent, context: task.context, output: message, error: message, exitCode: 1 as number | null, skipped: true };
3395
+ return omitUndefinedProperties({ agent: task.agent, context: task.context, output: message, error: message, exitCode: 1 as number | null, skipped: true });
3269
3396
  }
3270
3397
  if (timedOut) return timedOutStepResult(task.agent, task.context);
3271
3398
  if (stopped) return stoppedStepResult(task.agent, task.context);
3272
3399
  if (interrupted) return pausedStepResult(task.agent, task.context);
3273
3400
  if (aborted && failFast) {
3274
3401
  const skippedAt = Date.now();
3275
- statusPayload.steps[fi].status = "failed";
3276
- statusPayload.steps[fi].error = "Skipped due to fail-fast";
3277
- statusPayload.steps[fi].startedAt = skippedAt;
3278
- statusPayload.steps[fi].endedAt = skippedAt;
3279
- statusPayload.steps[fi].durationMs = 0;
3280
- statusPayload.steps[fi].exitCode = -1;
3402
+ requiredStatusStep(statusPayload, fi).status = "failed";
3403
+ requiredStatusStep(statusPayload, fi).error = "Skipped due to fail-fast";
3404
+ requiredStatusStep(statusPayload, fi).startedAt = skippedAt;
3405
+ requiredStatusStep(statusPayload, fi).endedAt = skippedAt;
3406
+ requiredStatusStep(statusPayload, fi).durationMs = 0;
3407
+ requiredStatusStep(statusPayload, fi).exitCode = -1;
3281
3408
  statusPayload.lastUpdate = skippedAt;
3282
3409
  writeStatusPayload();
3283
- return { agent: task.agent, context: task.context, output: "(skipped — fail-fast)", exitCode: -1 as number | null, skipped: true };
3410
+ return omitUndefinedProperties({ agent: task.agent, context: task.context, output: "(skipped — fail-fast)", exitCode: -1 as number | null, skipped: true });
3284
3411
  }
3285
3412
  const taskStartTime = Date.now();
3286
3413
  statusPayload.currentStep = fi;
3287
- statusPayload.steps[fi].status = "running";
3288
- statusPayload.steps[fi].error = undefined;
3289
- statusPayload.steps[fi].activityState = undefined;
3290
- resetStepLiveDetail(statusPayload.steps[fi]);
3291
- statusPayload.steps[fi].startedAt = taskStartTime;
3292
- statusPayload.steps[fi].lastActivityAt = taskStartTime;
3414
+ requiredStatusStep(statusPayload, fi).status = "running";
3415
+ delete requiredStatusStep(statusPayload, fi).error;
3416
+ delete requiredStatusStep(statusPayload, fi).activityState;
3417
+ resetStepLiveDetail(requiredStatusStep(statusPayload, fi));
3418
+ requiredStatusStep(statusPayload, fi).startedAt = taskStartTime;
3419
+ requiredStatusStep(statusPayload, fi).lastActivityAt = taskStartTime;
3293
3420
  statusPayload.outputFile = path.join(asyncDir, `output-${fi}.log`);
3294
3421
  statusPayload.lastActivityAt = taskStartTime;
3295
3422
  statusPayload.lastUpdate = taskStartTime;
3296
3423
  writeStatusPayload();
3297
3424
  appendJsonl(eventsPath, JSON.stringify({ type: "subagent.step.started", ts: taskStartTime, runId: id, stepIndex: fi, agent: task.agent }));
3298
3425
  flushPendingStepSteers(fi);
3299
- const singleResult = await runSingleStep(task, {
3426
+ const singleResult = await runSingleStep(task, compactOptional<SingleStepContext>({
3300
3427
  previousOutput, placeholder, cwd, sessionEnabled,
3301
3428
  outputs,
3302
3429
  sessionDir: config.sessionDir ? path.join(config.sessionDir, `dynamic-${stepIndex}-${taskIdx}`) : undefined,
@@ -3324,32 +3451,33 @@ async function runSubagent(
3324
3451
  onAttemptStart: (attempt) => updateStepModel(fi, attempt.model, attempt.thinking),
3325
3452
  onChildEvent: (event) => updateStepFromChildEvent(fi, event),
3326
3453
  onWriterProcess,
3454
+ onExternalProcess: (process) => updateExternalProcess(fi, process),
3327
3455
  skipAcceptance: () => timedOut || stopped,
3328
- });
3456
+ }));
3329
3457
  const taskEndTime = Date.now();
3330
3458
  const childInterrupted = singleResult.interrupted === true;
3331
3459
  const childStopped = singleResult.stopped === true;
3332
- statusPayload.steps[fi].status = stopped || childStopped ? "stopped" : timedOut ? "failed" : childInterrupted ? "paused" : singleResult.exitCode === 0 ? "complete" : "failed";
3333
- statusPayload.steps[fi].endedAt = taskEndTime;
3334
- statusPayload.steps[fi].durationMs = taskEndTime - taskStartTime;
3335
- statusPayload.steps[fi].exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
3336
- statusPayload.steps[fi].timedOut = timedOut || singleResult.timedOut ? true : undefined;
3337
- statusPayload.steps[fi].stopped = stopped || childStopped ? true : undefined;
3338
- statusPayload.steps[fi].turnBudget = singleResult.turnBudget;
3339
- statusPayload.steps[fi].turnBudgetExceeded = singleResult.turnBudgetExceeded;
3340
- statusPayload.steps[fi].wrapUpRequested = singleResult.wrapUpRequested;
3341
- statusPayload.steps[fi].toolBudget = singleResult.toolBudget;
3342
- statusPayload.steps[fi].toolBudgetBlocked = singleResult.toolBudgetBlocked;
3460
+ requiredStatusStep(statusPayload, fi).status = stopped || childStopped ? "stopped" : timedOut ? "failed" : childInterrupted ? "paused" : singleResult.exitCode === 0 ? "complete" : "failed";
3461
+ requiredStatusStep(statusPayload, fi).endedAt = taskEndTime;
3462
+ requiredStatusStep(statusPayload, fi).durationMs = taskEndTime - taskStartTime;
3463
+ requiredStatusStep(statusPayload, fi).exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
3464
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "timedOut", timedOut || singleResult.timedOut ? true : undefined);
3465
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "stopped", stopped || childStopped ? true : undefined);
3466
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "turnBudget", singleResult.turnBudget);
3467
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "turnBudgetExceeded", singleResult.turnBudgetExceeded);
3468
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "wrapUpRequested", singleResult.wrapUpRequested);
3469
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudget", singleResult.toolBudget);
3470
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudgetBlocked", singleResult.toolBudgetBlocked);
3343
3471
  if (singleResult.toolBudget) statusPayload.toolBudget = singleResult.toolBudget;
3344
3472
  if (singleResult.toolBudgetBlocked) statusPayload.toolBudgetBlocked = true;
3345
3473
  if (singleResult.turnBudget) statusPayload.turnBudget = singleResult.turnBudget;
3346
3474
  if (singleResult.turnBudgetExceeded) statusPayload.turnBudgetExceeded = true;
3347
3475
  if (singleResult.wrapUpRequested) statusPayload.wrapUpRequested = true;
3348
- statusPayload.steps[fi].model = singleResult.model;
3349
- statusPayload.steps[fi].thinking = resolveEffectiveThinking(singleResult.model, statusPayload.steps[fi].thinking);
3350
- statusPayload.steps[fi].attemptedModels = singleResult.attemptedModels;
3351
- statusPayload.steps[fi].modelAttempts = singleResult.modelAttempts;
3352
- statusPayload.steps[fi].totalCost = singleResult.totalCost;
3476
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "model", singleResult.model);
3477
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, fi).thinking));
3478
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "attemptedModels", singleResult.attemptedModels);
3479
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "modelAttempts", singleResult.modelAttempts);
3480
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "totalCost", singleResult.totalCost);
3353
3481
  if (singleResult.totalCost) {
3354
3482
  pendingParallelUsageCost = {
3355
3483
  inputTokens: pendingParallelUsageCost.inputTokens + singleResult.totalCost.inputTokens,
@@ -3358,23 +3486,23 @@ async function runSubagent(
3358
3486
  };
3359
3487
  refreshUsageBudget();
3360
3488
  }
3361
- statusPayload.steps[fi].error = stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error;
3362
- statusPayload.steps[fi].transcriptPath = singleResult.transcriptPath ?? statusPayload.steps[fi].transcriptPath;
3363
- statusPayload.steps[fi].transcriptError = singleResult.transcriptError;
3364
- statusPayload.steps[fi].agentContract = singleResult.agentContract;
3365
- statusPayload.steps[fi].launchContractDigest = singleResult.launchContractDigest;
3366
- statusPayload.steps[fi].launchResolvedExtensions = singleResult.launchResolvedExtensions;
3367
- statusPayload.steps[fi].runtimeAcknowledgedExtensions = singleResult.runtimeAcknowledgedExtensions;
3368
- statusPayload.steps[fi].effects = singleResult.effects;
3369
- statusPayload.steps[fi].execution = singleResult.execution;
3370
- statusPayload.steps[fi].review = singleResult.review;
3371
- statusPayload.steps[fi].structuredOutput = singleResult.structuredOutput;
3372
- statusPayload.steps[fi].structuredOutputPath = singleResult.structuredOutputPath;
3373
- statusPayload.steps[fi].structuredOutputSchemaPath = singleResult.structuredOutputSchemaPath;
3374
- statusPayload.steps[fi].acceptance = singleResult.acceptance;
3375
- statusPayload.steps[fi].watchdog = singleResult.watchdog;
3376
- statusPayload.steps[fi].capabilityCeiling = singleResult.capabilityCeiling;
3377
- statusPayload.steps[fi].capabilityAudit = singleResult.capabilityAudit;
3489
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "error", stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error);
3490
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "transcriptPath", singleResult.transcriptPath ?? requiredStatusStep(statusPayload, fi).transcriptPath);
3491
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "transcriptError", singleResult.transcriptError);
3492
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "agentContract", singleResult.agentContract);
3493
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "launchContractDigest", singleResult.launchContractDigest);
3494
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "launchResolvedExtensions", singleResult.launchResolvedExtensions);
3495
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "runtimeAcknowledgedExtensions", singleResult.runtimeAcknowledgedExtensions);
3496
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "effects", singleResult.effects);
3497
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "execution", singleResult.execution);
3498
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "review", singleResult.review);
3499
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutput", singleResult.structuredOutput);
3500
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputPath", singleResult.structuredOutputPath);
3501
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputSchemaPath", singleResult.structuredOutputSchemaPath);
3502
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "acceptance", singleResult.acceptance);
3503
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "watchdog", singleResult.watchdog);
3504
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityCeiling", singleResult.capabilityCeiling);
3505
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityAudit", singleResult.capabilityAudit);
3378
3506
  if (singleResult.capabilityCeiling) statusPayload.capabilityCeiling = singleResult.capabilityCeiling;
3379
3507
  if (singleResult.capabilityAudit) statusPayload.capabilityAudit = singleResult.capabilityAudit;
3380
3508
  statusPayload.lastUpdate = taskEndTime;
@@ -3391,7 +3519,7 @@ async function runSubagent(
3391
3519
 
3392
3520
  flatIndex += dynamicSteps.length;
3393
3521
  for (const pr of parallelResults) {
3394
- results.push({
3522
+ results.push(omitUndefinedProperties({
3395
3523
  agent: pr.agent,
3396
3524
  context: pr.context,
3397
3525
  agentContract: pr.agentContract,
@@ -3399,7 +3527,6 @@ async function runSubagent(
3399
3527
  launchResolvedExtensions: pr.launchResolvedExtensions,
3400
3528
  runtimeAcknowledgedExtensions: pr.runtimeAcknowledgedExtensions,
3401
3529
  output: pr.output,
3402
- outputPath: pr.outputPath,
3403
3530
  outputState: pr.outputState,
3404
3531
  error: pr.error,
3405
3532
  protocolError: pr.protocolError,
@@ -3433,7 +3560,7 @@ async function runSubagent(
3433
3560
  watchdog: pr.watchdog,
3434
3561
  capabilityCeiling: pr.capabilityCeiling,
3435
3562
  capabilityAudit: pr.capabilityAudit,
3436
- });
3563
+ }));
3437
3564
  }
3438
3565
  pendingParallelUsageCost = { inputTokens: 0, outputTokens: 0, costUsd: 0 };
3439
3566
  refreshUsageBudget();
@@ -3444,9 +3571,9 @@ async function runSubagent(
3444
3571
  .filter(({ result, task }) => isAgentContractV1(task?.agentContract ?? step.agentContract) && task?.gateOn === "acceptance" && result.acceptance?.status === "rejected");
3445
3572
  if (acceptanceFailures.length > 0) {
3446
3573
  const message = acceptanceFailures
3447
- .map(({ result, originalIndex }) => `Dynamic item ${originalIndex + 1} (${result.agent}, key ${materialized.items[originalIndex]?.key ?? originalIndex}) acceptance rejected: ${acceptanceFailureMessage(result.acceptance) ?? "acceptance rejected"}`)
3574
+ .map(({ result, originalIndex }) => `Dynamic item ${originalIndex + 1} (${result.agent}, key ${materialized.items[originalIndex]?.key ?? originalIndex}) acceptance rejected: ${(result.acceptance ? acceptanceFailureMessage(result.acceptance) : undefined) ?? "acceptance rejected"}`)
3448
3575
  .join("\n");
3449
- results.push({ agent: step.parallel.agent, context: step.parallel.context, output: message, error: message, success: false, exitCode: 1, structuredOutput: collection });
3576
+ results.push(omitUndefinedProperties({ agent: step.parallel.agent, context: step.parallel.context, output: message, error: message, success: false, exitCode: 1, structuredOutput: collection }));
3450
3577
  statusPayload.error = message;
3451
3578
  markDynamicGraphGroup(stepIndex, "failed", message);
3452
3579
  }
@@ -3461,7 +3588,7 @@ async function runSubagent(
3461
3588
  };
3462
3589
  statusPayload.outputs = outputs;
3463
3590
  const groupAcceptance = !timedOut && !stopped
3464
- ? await evaluateAcceptance({
3591
+ ? await evaluateAcceptance(omitUndefinedProperties({
3465
3592
  acceptance: effectiveDynamicGroupAcceptance,
3466
3593
  output: "",
3467
3594
  report: aggregateAcceptanceReport({
@@ -3472,7 +3599,7 @@ async function runSubagent(
3472
3599
  signal: combinedAbortSignal([timeoutAbortController.signal, stopAbortController.signal]),
3473
3600
  abortMessage: stopAbortController.signal.aborted ? stopMessage : timeoutMessage ?? "Subagent timed out.",
3474
3601
  reportOptional: isAgentContractV1(step.agentContract),
3475
- })
3602
+ }))
3476
3603
  : undefined;
3477
3604
  const groupStopped = stopped || stopAbortController.signal.aborted;
3478
3605
  const groupTimedOut = !groupStopped && (timedOut || timeoutAbortController.signal.aborted);
@@ -3481,7 +3608,7 @@ async function runSubagent(
3481
3608
  const groupError = groupStopped ? stopMessage : groupTimedOut ? timeoutMessage ?? "Subagent timed out." : groupAcceptanceFailure;
3482
3609
  markDynamicGraphGroup(stepIndex, groupError ? groupStopped ? "stopped" : "failed" : "completed", groupError, effectiveGroupAcceptance);
3483
3610
  if (groupError) {
3484
- results.push({
3611
+ results.push(omitUndefinedProperties({
3485
3612
  agent: step.parallel.agent,
3486
3613
  output: groupError,
3487
3614
  error: groupError,
@@ -3491,19 +3618,19 @@ async function runSubagent(
3491
3618
  stopped: groupStopped ? true : undefined,
3492
3619
  structuredOutput: collection,
3493
3620
  acceptance: effectiveGroupAcceptance,
3494
- });
3621
+ }));
3495
3622
  statusPayload.error = groupError;
3496
- statusPayload.stopped = groupStopped ? true : statusPayload.stopped;
3623
+ setOptionalProperty(statusPayload, "stopped", groupStopped ? true : statusPayload.stopped);
3497
3624
  }
3498
3625
  } catch (error) {
3499
3626
  const message = error instanceof DynamicFanoutError ? error.message : error instanceof Error ? error.message : String(error);
3500
- results.push({ agent: step.parallel.agent, context: step.parallel.context, output: message, error: message, success: false, exitCode: 1, structuredOutput: collection });
3627
+ results.push(omitUndefinedProperties({ agent: step.parallel.agent, context: step.parallel.context, output: message, error: message, success: false, exitCode: 1, structuredOutput: collection }));
3501
3628
  statusPayload.error = message;
3502
3629
  markDynamicGraphGroup(stepIndex, "failed", message);
3503
3630
  }
3504
3631
  }
3505
3632
  previousOutput = aggregateParallelOutputs(
3506
- parallelResults.map((r, i) => ({
3633
+ parallelResults.map((r, i) => omitUndefinedProperties({
3507
3634
  agent: r.agent,
3508
3635
  taskIndex: i,
3509
3636
  output: r.output,
@@ -3555,13 +3682,13 @@ async function runSubagent(
3555
3682
  break;
3556
3683
  }
3557
3684
  try {
3558
- worktreeSetup = createWorktrees(cwd, `${id}-s${stepIndex}`, group.parallel.length, {
3685
+ worktreeSetup = createWorktrees(cwd, `${id}-s${stepIndex}`, group.parallel.length, omitUndefinedProperties({
3559
3686
  agents: group.parallel.map((task) => task.agent),
3560
3687
  setupHook: config.worktreeSetupHook
3561
- ? { hookPath: config.worktreeSetupHook, timeoutMs: config.worktreeSetupHookTimeoutMs }
3688
+ ? omitUndefinedProperties({ hookPath: config.worktreeSetupHook, timeoutMs: config.worktreeSetupHookTimeoutMs })
3562
3689
  : undefined,
3563
3690
  baseDir: config.worktreeBaseDir,
3564
- });
3691
+ }));
3565
3692
  } catch (error) {
3566
3693
  const setupError = error instanceof Error ? error.message : String(error);
3567
3694
  const failedAt = Date.now();
@@ -3584,6 +3711,18 @@ async function runSubagent(
3584
3711
  }
3585
3712
 
3586
3713
  try {
3714
+ if (worktreeSetup) {
3715
+ writePendingParallelHandoff({
3716
+ manifestPath: parallelHandoffPath(asyncDir),
3717
+ runId: id,
3718
+ mode: (config.resultMode ?? statusPayload.mode) === "parallel" ? "parallel" : "chain",
3719
+ source: "async",
3720
+ cwd,
3721
+ stepIndex,
3722
+ flatStartIndex: groupStartFlatIndex,
3723
+ setup: worktreeSetup,
3724
+ });
3725
+ }
3587
3726
  if (group.worktree) ensureParallelProgressFile(cwd, group);
3588
3727
  const groupStartTime = Date.now();
3589
3728
  markParallelGroupRunning({
@@ -3600,57 +3739,57 @@ async function runSubagent(
3600
3739
  const parallelResults = await mapConcurrent(
3601
3740
  group.parallel,
3602
3741
  concurrency,
3603
- async (task, taskIdx) => {
3742
+ async (task, taskIdx): Promise<StepResult> => {
3604
3743
  const fi = groupStartFlatIndex + taskIdx;
3605
3744
  refreshUsageBudget();
3606
3745
  if (statusPayload.usageBudget?.exhausted) {
3607
3746
  const skippedAt = Date.now();
3608
3747
  const message = usageBudgetExceededMessage(statusPayload.usageBudget);
3609
- statusPayload.steps[fi].status = "failed";
3610
- statusPayload.steps[fi].error = message;
3611
- statusPayload.steps[fi].startedAt = skippedAt;
3612
- statusPayload.steps[fi].endedAt = skippedAt;
3613
- statusPayload.steps[fi].durationMs = 0;
3614
- statusPayload.steps[fi].exitCode = 1;
3615
- statusPayload.steps[fi].activityState = undefined;
3748
+ requiredStatusStep(statusPayload, fi).status = "failed";
3749
+ requiredStatusStep(statusPayload, fi).error = message;
3750
+ requiredStatusStep(statusPayload, fi).startedAt = skippedAt;
3751
+ requiredStatusStep(statusPayload, fi).endedAt = skippedAt;
3752
+ requiredStatusStep(statusPayload, fi).durationMs = 0;
3753
+ requiredStatusStep(statusPayload, fi).exitCode = 1;
3754
+ delete requiredStatusStep(statusPayload, fi).activityState;
3616
3755
  statusPayload.lastUpdate = skippedAt;
3617
3756
  usageBudgetExceeded = true;
3618
3757
  writeStatusPayload();
3619
3758
  appendJsonl(eventsPath, JSON.stringify({
3620
3759
  type: "subagent.step.failed", ts: skippedAt, runId: id, stepIndex: fi, agent: task.agent, exitCode: 1, durationMs: 0,
3621
3760
  }));
3622
- return { agent: task.agent, context: task.context, output: message, error: message, exitCode: 1 as number | null, skipped: true };
3761
+ return omitUndefinedProperties({ agent: task.agent, context: task.context, output: message, error: message, exitCode: 1 as number | null, skipped: true });
3623
3762
  }
3624
3763
  if (timedOut) return timedOutStepResult(task.agent, task.context);
3625
3764
  if (stopped) return stoppedStepResult(task.agent, task.context);
3626
3765
  if (interrupted) return pausedStepResult(task.agent, task.context);
3627
3766
  if (aborted && failFast) {
3628
3767
  const skippedAt = Date.now();
3629
- statusPayload.steps[fi].status = "failed";
3630
- statusPayload.steps[fi].error = "Skipped due to fail-fast";
3631
- statusPayload.steps[fi].startedAt = skippedAt;
3632
- statusPayload.steps[fi].endedAt = skippedAt;
3633
- statusPayload.steps[fi].durationMs = 0;
3634
- statusPayload.steps[fi].exitCode = -1;
3635
- statusPayload.steps[fi].activityState = undefined;
3768
+ requiredStatusStep(statusPayload, fi).status = "failed";
3769
+ requiredStatusStep(statusPayload, fi).error = "Skipped due to fail-fast";
3770
+ requiredStatusStep(statusPayload, fi).startedAt = skippedAt;
3771
+ requiredStatusStep(statusPayload, fi).endedAt = skippedAt;
3772
+ requiredStatusStep(statusPayload, fi).durationMs = 0;
3773
+ requiredStatusStep(statusPayload, fi).exitCode = -1;
3774
+ delete requiredStatusStep(statusPayload, fi).activityState;
3636
3775
  statusPayload.lastUpdate = skippedAt;
3637
3776
  writeStatusPayload();
3638
3777
  appendJsonl(eventsPath, JSON.stringify({
3639
3778
  type: "subagent.step.failed", ts: skippedAt, runId: id, stepIndex: fi, agent: task.agent, exitCode: -1, durationMs: 0,
3640
3779
  }));
3641
- return { agent: task.agent, context: task.context, output: "(skipped — fail-fast)", exitCode: -1 as number | null, skipped: true };
3780
+ return omitUndefinedProperties({ agent: task.agent, context: task.context, output: "(skipped — fail-fast)", exitCode: -1 as number | null, skipped: true });
3642
3781
  }
3643
3782
 
3644
3783
  const taskStartTime = Date.now();
3645
3784
  statusPayload.currentStep = fi;
3646
- statusPayload.steps[fi].status = "running";
3647
- statusPayload.steps[fi].error = undefined;
3648
- statusPayload.steps[fi].activityState = undefined;
3649
- resetStepLiveDetail(statusPayload.steps[fi]);
3650
- statusPayload.steps[fi].startedAt = taskStartTime;
3651
- statusPayload.steps[fi].endedAt = undefined;
3652
- statusPayload.steps[fi].durationMs = undefined;
3653
- statusPayload.steps[fi].lastActivityAt = taskStartTime;
3785
+ requiredStatusStep(statusPayload, fi).status = "running";
3786
+ delete requiredStatusStep(statusPayload, fi).error;
3787
+ delete requiredStatusStep(statusPayload, fi).activityState;
3788
+ resetStepLiveDetail(requiredStatusStep(statusPayload, fi));
3789
+ requiredStatusStep(statusPayload, fi).startedAt = taskStartTime;
3790
+ delete requiredStatusStep(statusPayload, fi).endedAt;
3791
+ delete requiredStatusStep(statusPayload, fi).durationMs;
3792
+ requiredStatusStep(statusPayload, fi).lastActivityAt = taskStartTime;
3654
3793
  statusPayload.outputFile = path.join(asyncDir, `output-${fi}.log`);
3655
3794
  statusPayload.lastActivityAt = taskStartTime;
3656
3795
  statusPayload.lastUpdate = taskStartTime;
@@ -3666,7 +3805,7 @@ async function runSubagent(
3666
3805
  const { taskForRun, taskCwd } = prepareParallelTaskRun(task, cwd, worktreeSetup, taskIdx);
3667
3806
  flushPendingStepSteers(fi);
3668
3807
 
3669
- const singleResult = await runSingleStep(taskForRun, {
3808
+ const singleResult = await runSingleStep(taskForRun, compactOptional<SingleStepContext>({
3670
3809
  previousOutput, placeholder, cwd: taskCwd, sessionEnabled,
3671
3810
  outputs,
3672
3811
  sessionDir: taskSessionDir,
@@ -3694,8 +3833,9 @@ async function runSubagent(
3694
3833
  onAttemptStart: (attempt) => updateStepModel(fi, attempt.model, attempt.thinking),
3695
3834
  onChildEvent: (event) => updateStepFromChildEvent(fi, event),
3696
3835
  onWriterProcess,
3836
+ onExternalProcess: (process) => updateExternalProcess(fi, process),
3697
3837
  skipAcceptance: () => timedOut || stopped,
3698
- });
3838
+ }));
3699
3839
  if (task.sessionFile) {
3700
3840
  latestSessionFile = task.sessionFile;
3701
3841
  }
@@ -3705,27 +3845,27 @@ async function runSubagent(
3705
3845
  const childInterrupted = singleResult.interrupted === true;
3706
3846
  const childStopped = singleResult.stopped === true;
3707
3847
 
3708
- statusPayload.steps[fi].status = stopped || childStopped ? "stopped" : timedOut ? "failed" : childInterrupted ? "paused" : singleResult.exitCode === 0 ? "complete" : "failed";
3709
- statusPayload.steps[fi].endedAt = taskEndTime;
3710
- statusPayload.steps[fi].durationMs = taskDuration;
3711
- statusPayload.steps[fi].exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
3712
- statusPayload.steps[fi].timedOut = timedOut || singleResult.timedOut ? true : undefined;
3713
- statusPayload.steps[fi].stopped = stopped || childStopped ? true : undefined;
3714
- statusPayload.steps[fi].turnBudget = singleResult.turnBudget;
3715
- statusPayload.steps[fi].turnBudgetExceeded = singleResult.turnBudgetExceeded;
3716
- statusPayload.steps[fi].wrapUpRequested = singleResult.wrapUpRequested;
3717
- statusPayload.steps[fi].toolBudget = singleResult.toolBudget;
3718
- statusPayload.steps[fi].toolBudgetBlocked = singleResult.toolBudgetBlocked;
3848
+ requiredStatusStep(statusPayload, fi).status = stopped || childStopped ? "stopped" : timedOut ? "failed" : childInterrupted ? "paused" : singleResult.exitCode === 0 ? "complete" : "failed";
3849
+ requiredStatusStep(statusPayload, fi).endedAt = taskEndTime;
3850
+ requiredStatusStep(statusPayload, fi).durationMs = taskDuration;
3851
+ requiredStatusStep(statusPayload, fi).exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
3852
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "timedOut", timedOut || singleResult.timedOut ? true : undefined);
3853
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "stopped", stopped || childStopped ? true : undefined);
3854
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "turnBudget", singleResult.turnBudget);
3855
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "turnBudgetExceeded", singleResult.turnBudgetExceeded);
3856
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "wrapUpRequested", singleResult.wrapUpRequested);
3857
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudget", singleResult.toolBudget);
3858
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "toolBudgetBlocked", singleResult.toolBudgetBlocked);
3719
3859
  if (singleResult.toolBudget) statusPayload.toolBudget = singleResult.toolBudget;
3720
3860
  if (singleResult.toolBudgetBlocked) statusPayload.toolBudgetBlocked = true;
3721
3861
  if (singleResult.turnBudget) statusPayload.turnBudget = singleResult.turnBudget;
3722
3862
  if (singleResult.turnBudgetExceeded) statusPayload.turnBudgetExceeded = true;
3723
3863
  if (singleResult.wrapUpRequested) statusPayload.wrapUpRequested = true;
3724
- statusPayload.steps[fi].model = singleResult.model;
3725
- statusPayload.steps[fi].thinking = resolveEffectiveThinking(singleResult.model, statusPayload.steps[fi].thinking);
3726
- statusPayload.steps[fi].attemptedModels = singleResult.attemptedModels;
3727
- statusPayload.steps[fi].modelAttempts = singleResult.modelAttempts;
3728
- statusPayload.steps[fi].totalCost = singleResult.totalCost;
3864
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "model", singleResult.model);
3865
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, fi).thinking));
3866
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "attemptedModels", singleResult.attemptedModels);
3867
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "modelAttempts", singleResult.modelAttempts);
3868
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "totalCost", singleResult.totalCost);
3729
3869
  if (singleResult.totalCost) {
3730
3870
  pendingParallelUsageCost = {
3731
3871
  inputTokens: pendingParallelUsageCost.inputTokens + singleResult.totalCost.inputTokens,
@@ -3734,22 +3874,22 @@ async function runSubagent(
3734
3874
  };
3735
3875
  refreshUsageBudget();
3736
3876
  }
3737
- statusPayload.steps[fi].error = stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error;
3738
- statusPayload.steps[fi].transcriptPath = singleResult.transcriptPath ?? statusPayload.steps[fi].transcriptPath;
3739
- statusPayload.steps[fi].transcriptError = singleResult.transcriptError;
3740
- statusPayload.steps[fi].agentContract = singleResult.agentContract;
3741
- statusPayload.steps[fi].launchResolvedExtensions = singleResult.launchResolvedExtensions;
3742
- statusPayload.steps[fi].runtimeAcknowledgedExtensions = singleResult.runtimeAcknowledgedExtensions;
3743
- statusPayload.steps[fi].effects = singleResult.effects;
3744
- statusPayload.steps[fi].execution = singleResult.execution;
3745
- statusPayload.steps[fi].review = singleResult.review;
3746
- statusPayload.steps[fi].structuredOutput = singleResult.structuredOutput;
3747
- statusPayload.steps[fi].structuredOutputPath = singleResult.structuredOutputPath;
3748
- statusPayload.steps[fi].structuredOutputSchemaPath = singleResult.structuredOutputSchemaPath;
3749
- statusPayload.steps[fi].acceptance = singleResult.acceptance;
3750
- statusPayload.steps[fi].watchdog = singleResult.watchdog;
3751
- statusPayload.steps[fi].capabilityCeiling = singleResult.capabilityCeiling;
3752
- statusPayload.steps[fi].capabilityAudit = singleResult.capabilityAudit;
3877
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "error", stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error);
3878
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "transcriptPath", singleResult.transcriptPath ?? requiredStatusStep(statusPayload, fi).transcriptPath);
3879
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "transcriptError", singleResult.transcriptError);
3880
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "agentContract", singleResult.agentContract);
3881
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "launchResolvedExtensions", singleResult.launchResolvedExtensions);
3882
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "runtimeAcknowledgedExtensions", singleResult.runtimeAcknowledgedExtensions);
3883
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "effects", singleResult.effects);
3884
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "execution", singleResult.execution);
3885
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "review", singleResult.review);
3886
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutput", singleResult.structuredOutput);
3887
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputPath", singleResult.structuredOutputPath);
3888
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "structuredOutputSchemaPath", singleResult.structuredOutputSchemaPath);
3889
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "acceptance", singleResult.acceptance);
3890
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "watchdog", singleResult.watchdog);
3891
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityCeiling", singleResult.capabilityCeiling);
3892
+ setOptionalProperty(requiredStatusStep(statusPayload, fi), "capabilityAudit", singleResult.capabilityAudit);
3753
3893
  if (singleResult.capabilityCeiling) statusPayload.capabilityCeiling = singleResult.capabilityCeiling;
3754
3894
  if (singleResult.capabilityAudit) statusPayload.capabilityAudit = singleResult.capabilityAudit;
3755
3895
  statusPayload.lastUpdate = taskEndTime;
@@ -3762,8 +3902,8 @@ async function runSubagent(
3762
3902
  exitCode: stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode, durationMs: taskDuration,
3763
3903
  }));
3764
3904
  if (singleResult.completionGuardTriggered) {
3765
- const event = buildControlEvent({
3766
- from: statusPayload.steps[fi].activityState,
3905
+ const event = buildControlEvent(omitUndefinedProperties({
3906
+ from: requiredStatusStep(statusPayload, fi).activityState,
3767
3907
  to: "needs_attention",
3768
3908
  runId: id,
3769
3909
  agent: task.agent,
@@ -3771,7 +3911,7 @@ async function runSubagent(
3771
3911
  ts: taskEndTime,
3772
3912
  message: `${task.agent} completed without making edits for an implementation task`,
3773
3913
  reason: "completion_guard",
3774
- });
3914
+ }));
3775
3915
  appendControlEvent(event);
3776
3916
  }
3777
3917
 
@@ -3790,7 +3930,7 @@ async function runSubagent(
3790
3930
  : null;
3791
3931
  const taskTokens = sessionTokens ?? tokenUsageFromAttempts(parallelResults[t]?.modelAttempts);
3792
3932
  if (!taskTokens) continue;
3793
- statusPayload.steps[fi].tokens = taskTokens;
3933
+ requiredStatusStep(statusPayload, fi).tokens = taskTokens;
3794
3934
  previousCumulativeTokens = {
3795
3935
  input: previousCumulativeTokens.input + taskTokens.input,
3796
3936
  output: previousCumulativeTokens.output + taskTokens.output,
@@ -3802,14 +3942,13 @@ async function runSubagent(
3802
3942
  writeStatusPayload();
3803
3943
 
3804
3944
  for (const pr of parallelResults) {
3805
- results.push({
3945
+ results.push(omitUndefinedProperties({
3806
3946
  agent: pr.agent,
3807
3947
  context: pr.context,
3808
3948
  agentContract: pr.agentContract,
3809
3949
  launchContractDigest: pr.launchContractDigest,
3810
3950
  launchResolvedExtensions: pr.launchResolvedExtensions,
3811
3951
  output: pr.output,
3812
- outputPath: pr.outputPath,
3813
3952
  outputState: pr.outputState,
3814
3953
  error: pr.error,
3815
3954
  protocolError: pr.protocolError,
@@ -3841,7 +3980,7 @@ async function runSubagent(
3841
3980
  structuredOutputSchemaPath: pr.structuredOutputSchemaPath,
3842
3981
  acceptance: pr.acceptance,
3843
3982
  watchdog: pr.watchdog,
3844
- });
3983
+ }));
3845
3984
  }
3846
3985
  pendingParallelUsageCost = { inputTokens: 0, outputTokens: 0, costUsd: 0 };
3847
3986
  refreshUsageBudget();
@@ -3856,7 +3995,7 @@ async function runSubagent(
3856
3995
  statusPayload.outputs = outputs;
3857
3996
 
3858
3997
  previousOutput = aggregateParallelOutputs(
3859
- parallelResults.map((r) => ({
3998
+ parallelResults.map((r) => omitUndefinedProperties({
3860
3999
  agent: r.agent,
3861
4000
  output: r.output,
3862
4001
  exitCode: r.exitCode,
@@ -3869,35 +4008,37 @@ async function runSubagent(
3869
4008
  const captured = captureParallelWorktreeDiffs(worktreeSetup, asyncDir, stepIndex, group);
3870
4009
  if (captured.summary) previousOutput = `${previousOutput}\n\n${captured.summary}`;
3871
4010
  worktreeFinalized = true;
3872
- const cleanup = cleanupWorktrees(worktreeSetup);
4011
+ const manifestPath = parallelHandoffPath(asyncDir);
4012
+ const handoff = {
4013
+ manifestPath,
4014
+ runId: id,
4015
+ mode: (config.resultMode ?? statusPayload.mode) === "parallel" ? "parallel" as const : "chain" as const,
4016
+ source: "async" as const,
4017
+ cwd,
4018
+ stepIndex,
4019
+ flatStartIndex: groupStartFlatIndex,
4020
+ setup: worktreeSetup,
4021
+ diffs: captured.diffs,
4022
+ results: parallelResults.map((result) => ({
4023
+ agent: result.agent,
4024
+ status: result.stopped || (result.exitCode !== 0 && isUnexplainedProcessSignal(omitUndefinedProperties({
4025
+ processSignal: result.processSignal,
4026
+ interrupted: result.interrupted,
4027
+ timedOut: result.timedOut,
4028
+ stopped: result.stopped,
4029
+ turnBudgetExceeded: result.turnBudgetExceeded,
4030
+ }))) ? "stopped" as const : result.interrupted ? "paused" as const : result.exitCode === 0 ? "completed" as const : "failed" as const,
4031
+ summary: result.output || result.error || "(no output)",
4032
+ ...(result.artifactPaths?.outputPath ? { outputPath: result.artifactPaths.outputPath } : {}),
4033
+ ...(result.structuredOutput !== undefined ? { structuredOutput: result.structuredOutput } : {}),
4034
+ ...(result.structuredOutputPath ? { structuredOutputPath: result.structuredOutputPath } : {}),
4035
+ ...(result.sessionFile ? { sessionPath: result.sessionFile } : {}),
4036
+ })),
4037
+ };
3873
4038
  try {
3874
- statusPayload.parallelHandoff = writeParallelHandoffGroup({
3875
- manifestPath: parallelHandoffPath(asyncDir),
3876
- runId: id,
3877
- mode: (config.resultMode ?? statusPayload.mode) === "parallel" ? "parallel" : "chain",
3878
- source: "async",
3879
- cwd,
3880
- stepIndex,
3881
- flatStartIndex: groupStartFlatIndex,
3882
- setup: worktreeSetup,
3883
- diffs: captured.diffs,
3884
- cleanup,
3885
- results: parallelResults.map((result) => ({
3886
- agent: result.agent,
3887
- status: result.stopped || (result.exitCode !== 0 && isUnexplainedProcessSignal({
3888
- processSignal: result.processSignal,
3889
- interrupted: result.interrupted,
3890
- timedOut: result.timedOut,
3891
- stopped: result.stopped,
3892
- turnBudgetExceeded: result.turnBudgetExceeded,
3893
- })) ? "stopped" : result.interrupted ? "paused" : result.exitCode === 0 ? "completed" : "failed",
3894
- summary: result.output || result.error || "(no output)",
3895
- ...(result.artifactPaths?.outputPath ? { outputPath: result.artifactPaths.outputPath } : {}),
3896
- ...(result.structuredOutput !== undefined ? { structuredOutput: result.structuredOutput } : {}),
3897
- ...(result.structuredOutputPath ? { structuredOutputPath: result.structuredOutputPath } : {}),
3898
- ...(result.sessionFile ? { sessionPath: result.sessionFile } : {}),
3899
- })),
3900
- });
4039
+ writeParallelHandoffGroup(handoff);
4040
+ const cleanup = cleanupWorktrees(worktreeSetup, { kind: "preserve", capturedDiffs: captured.diffs, handoffManifestPath: manifestPath });
4041
+ statusPayload.parallelHandoff = writeParallelHandoffGroup({ ...handoff, cleanup });
3901
4042
  previousOutput = `${previousOutput}\n\n${formatParallelHandoffReference(statusPayload.parallelHandoff)}`;
3902
4043
  } catch (error) {
3903
4044
  previousOutput = `${previousOutput}\n\n${formatParallelHandoffError(error)}`;
@@ -3918,7 +4059,7 @@ async function runSubagent(
3918
4059
  .map((result, index) => ({ result, index, task: group.parallel[index] }))
3919
4060
  .find(({ result, task }) => isAgentContractV1(task?.agentContract) && task?.gateOn === "acceptance" && result.acceptance?.status === "rejected");
3920
4061
  if (acceptanceGateFailure) {
3921
- statusPayload.error = acceptanceFailureMessage(acceptanceGateFailure.result.acceptance) ?? "Parallel acceptance gate rejected the step.";
4062
+ statusPayload.error = (acceptanceGateFailure.result.acceptance ? acceptanceFailureMessage(acceptanceGateFailure.result.acceptance) : undefined) ?? "Parallel acceptance gate rejected the step.";
3922
4063
  writeStatusPayload();
3923
4064
  break;
3924
4065
  }
@@ -3932,13 +4073,13 @@ async function runSubagent(
3932
4073
  const seqStep = step as SubagentStep;
3933
4074
  const stepStartTime = Date.now();
3934
4075
  statusPayload.currentStep = flatIndex;
3935
- statusPayload.steps[flatIndex].status = "running";
3936
- statusPayload.steps[flatIndex].activityState = undefined;
3937
- statusPayload.activityState = undefined;
3938
- resetStepLiveDetail(statusPayload.steps[flatIndex]);
3939
- statusPayload.steps[flatIndex].skills = seqStep.skills;
3940
- statusPayload.steps[flatIndex].startedAt = stepStartTime;
3941
- statusPayload.steps[flatIndex].lastActivityAt = stepStartTime;
4076
+ requiredStatusStep(statusPayload, flatIndex).status = "running";
4077
+ delete requiredStatusStep(statusPayload, flatIndex).activityState;
4078
+ delete statusPayload.activityState;
4079
+ resetStepLiveDetail(requiredStatusStep(statusPayload, flatIndex));
4080
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "skills", seqStep.skills);
4081
+ requiredStatusStep(statusPayload, flatIndex).startedAt = stepStartTime;
4082
+ requiredStatusStep(statusPayload, flatIndex).lastActivityAt = stepStartTime;
3942
4083
  statusPayload.lastActivityAt = stepStartTime;
3943
4084
  statusPayload.lastUpdate = stepStartTime;
3944
4085
  statusPayload.outputFile = path.join(asyncDir, `output-${flatIndex}.log`);
@@ -3953,7 +4094,7 @@ async function runSubagent(
3953
4094
  }));
3954
4095
 
3955
4096
  flushPendingStepSteers(flatIndex);
3956
- const singleResult = await runSingleStep(seqStep, {
4097
+ const singleResult = await runSingleStep(seqStep, compactOptional<SingleStepContext>({
3957
4098
  previousOutput, placeholder, cwd, sessionEnabled,
3958
4099
  outputs: statusPayload.mode === "single" ? undefined : outputs,
3959
4100
  sessionDir: config.sessionDir,
@@ -3981,15 +4122,16 @@ async function runSubagent(
3981
4122
  onAttemptStart: (attempt) => updateStepModel(flatIndex, attempt.model, attempt.thinking),
3982
4123
  onChildEvent: (event) => updateStepFromChildEvent(flatIndex, event),
3983
4124
  onWriterProcess,
4125
+ onExternalProcess: (process) => updateExternalProcess(flatIndex, process),
3984
4126
  skipAcceptance: () => timedOut || stopped,
3985
- });
4127
+ }));
3986
4128
  if (seqStep.sessionFile) {
3987
4129
  latestSessionFile = seqStep.sessionFile;
3988
4130
  }
3989
4131
 
3990
4132
  previousOutput = singleResult.output;
3991
4133
  const childStopped = singleResult.stopped === true;
3992
- results.push({
4134
+ results.push(omitUndefinedProperties({
3993
4135
  agent: singleResult.agent,
3994
4136
  context: singleResult.context,
3995
4137
  agentContract: singleResult.agentContract,
@@ -3997,7 +4139,6 @@ async function runSubagent(
3997
4139
  launchResolvedExtensions: singleResult.launchResolvedExtensions,
3998
4140
  runtimeAcknowledgedExtensions: singleResult.runtimeAcknowledgedExtensions,
3999
4141
  output: stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.output,
4000
- outputPath: singleResult.outputPath,
4001
4142
  outputState: singleResult.outputState,
4002
4143
  error: stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error,
4003
4144
  protocolError: singleResult.protocolError,
@@ -4030,7 +4171,9 @@ async function runSubagent(
4030
4171
  wrapUpRequested: singleResult.wrapUpRequested,
4031
4172
  toolBudget: singleResult.toolBudget,
4032
4173
  toolBudgetBlocked: singleResult.toolBudgetBlocked,
4033
- });
4174
+ runner: singleResult.runner,
4175
+ externalProcess: singleResult.externalProcess,
4176
+ }));
4034
4177
  if (seqStep.outputName) {
4035
4178
  outputs[seqStep.outputName] = outputEntryFromAsyncResult({
4036
4179
  agent: singleResult.agent,
@@ -4063,47 +4206,47 @@ async function runSubagent(
4063
4206
 
4064
4207
  const stepEndTime = Date.now();
4065
4208
  const childInterrupted = singleResult.interrupted === true;
4066
- statusPayload.steps[flatIndex].status = stopped || childStopped ? "stopped" : timedOut ? "failed" : childInterrupted ? "paused" : singleResult.exitCode === 0 ? "complete" : "failed";
4067
- statusPayload.steps[flatIndex].endedAt = stepEndTime;
4068
- statusPayload.steps[flatIndex].durationMs = stepEndTime - stepStartTime;
4069
- statusPayload.steps[flatIndex].exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
4070
- statusPayload.steps[flatIndex].timedOut = timedOut || singleResult.timedOut ? true : undefined;
4071
- statusPayload.steps[flatIndex].stopped = stopped || childStopped ? true : undefined;
4072
- statusPayload.steps[flatIndex].turnBudget = singleResult.turnBudget;
4073
- statusPayload.steps[flatIndex].turnBudgetExceeded = singleResult.turnBudgetExceeded;
4074
- statusPayload.steps[flatIndex].wrapUpRequested = singleResult.wrapUpRequested;
4075
- statusPayload.steps[flatIndex].toolBudget = singleResult.toolBudget;
4076
- statusPayload.steps[flatIndex].toolBudgetBlocked = singleResult.toolBudgetBlocked;
4209
+ requiredStatusStep(statusPayload, flatIndex).status = stopped || childStopped ? "stopped" : timedOut ? "failed" : childInterrupted ? "paused" : singleResult.exitCode === 0 ? "complete" : "failed";
4210
+ requiredStatusStep(statusPayload, flatIndex).endedAt = stepEndTime;
4211
+ requiredStatusStep(statusPayload, flatIndex).durationMs = stepEndTime - stepStartTime;
4212
+ requiredStatusStep(statusPayload, flatIndex).exitCode = stopped || childStopped ? 1 : timedOut ? 1 : childInterrupted ? 0 : singleResult.exitCode;
4213
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "timedOut", timedOut || singleResult.timedOut ? true : undefined);
4214
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "stopped", stopped || childStopped ? true : undefined);
4215
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "turnBudget", singleResult.turnBudget);
4216
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "turnBudgetExceeded", singleResult.turnBudgetExceeded);
4217
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "wrapUpRequested", singleResult.wrapUpRequested);
4218
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "toolBudget", singleResult.toolBudget);
4219
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "toolBudgetBlocked", singleResult.toolBudgetBlocked);
4077
4220
  if (singleResult.toolBudget) statusPayload.toolBudget = singleResult.toolBudget;
4078
4221
  if (singleResult.toolBudgetBlocked) statusPayload.toolBudgetBlocked = true;
4079
4222
  if (singleResult.turnBudget) statusPayload.turnBudget = singleResult.turnBudget;
4080
4223
  if (singleResult.turnBudgetExceeded) statusPayload.turnBudgetExceeded = true;
4081
4224
  if (singleResult.wrapUpRequested) statusPayload.wrapUpRequested = true;
4082
- statusPayload.steps[flatIndex].model = singleResult.model;
4083
- statusPayload.steps[flatIndex].thinking = resolveEffectiveThinking(singleResult.model, statusPayload.steps[flatIndex].thinking);
4084
- statusPayload.steps[flatIndex].attemptedModels = singleResult.attemptedModels;
4085
- statusPayload.steps[flatIndex].modelAttempts = singleResult.modelAttempts;
4086
- statusPayload.steps[flatIndex].totalCost = singleResult.totalCost;
4087
- statusPayload.steps[flatIndex].error = stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error;
4088
- statusPayload.steps[flatIndex].transcriptPath = singleResult.transcriptPath ?? statusPayload.steps[flatIndex].transcriptPath;
4089
- statusPayload.steps[flatIndex].transcriptError = singleResult.transcriptError;
4090
- statusPayload.steps[flatIndex].agentContract = singleResult.agentContract;
4091
- statusPayload.steps[flatIndex].launchResolvedExtensions = singleResult.launchResolvedExtensions;
4092
- statusPayload.steps[flatIndex].runtimeAcknowledgedExtensions = singleResult.runtimeAcknowledgedExtensions;
4093
- statusPayload.steps[flatIndex].effects = singleResult.effects;
4094
- statusPayload.steps[flatIndex].execution = singleResult.execution;
4095
- statusPayload.steps[flatIndex].review = singleResult.review;
4096
- statusPayload.steps[flatIndex].structuredOutput = singleResult.structuredOutput;
4097
- statusPayload.steps[flatIndex].structuredOutputPath = singleResult.structuredOutputPath;
4098
- statusPayload.steps[flatIndex].structuredOutputSchemaPath = singleResult.structuredOutputSchemaPath;
4099
- statusPayload.steps[flatIndex].acceptance = singleResult.acceptance;
4100
- statusPayload.steps[flatIndex].watchdog = singleResult.watchdog;
4101
- statusPayload.steps[flatIndex].capabilityCeiling = singleResult.capabilityCeiling;
4102
- statusPayload.steps[flatIndex].capabilityAudit = singleResult.capabilityAudit;
4225
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "model", singleResult.model);
4226
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "thinking", resolveEffectiveThinking(singleResult.model, requiredStatusStep(statusPayload, flatIndex).thinking));
4227
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "attemptedModels", singleResult.attemptedModels);
4228
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "modelAttempts", singleResult.modelAttempts);
4229
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "totalCost", singleResult.totalCost);
4230
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "error", stopped || childStopped ? stopMessage : timedOut ? (timeoutMessage ?? "Subagent timed out.") : singleResult.error);
4231
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "transcriptPath", singleResult.transcriptPath ?? requiredStatusStep(statusPayload, flatIndex).transcriptPath);
4232
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "transcriptError", singleResult.transcriptError);
4233
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "agentContract", singleResult.agentContract);
4234
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "launchResolvedExtensions", singleResult.launchResolvedExtensions);
4235
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "runtimeAcknowledgedExtensions", singleResult.runtimeAcknowledgedExtensions);
4236
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "effects", singleResult.effects);
4237
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "execution", singleResult.execution);
4238
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "review", singleResult.review);
4239
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "structuredOutput", singleResult.structuredOutput);
4240
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "structuredOutputPath", singleResult.structuredOutputPath);
4241
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "structuredOutputSchemaPath", singleResult.structuredOutputSchemaPath);
4242
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "acceptance", singleResult.acceptance);
4243
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "watchdog", singleResult.watchdog);
4244
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "capabilityCeiling", singleResult.capabilityCeiling);
4245
+ setOptionalProperty(requiredStatusStep(statusPayload, flatIndex), "capabilityAudit", singleResult.capabilityAudit);
4103
4246
  if (singleResult.capabilityCeiling) statusPayload.capabilityCeiling = singleResult.capabilityCeiling;
4104
4247
  if (singleResult.capabilityAudit) statusPayload.capabilityAudit = singleResult.capabilityAudit;
4105
4248
  if (stepTokens) {
4106
- statusPayload.steps[flatIndex].tokens = stepTokens;
4249
+ requiredStatusStep(statusPayload, flatIndex).tokens = stepTokens;
4107
4250
  statusPayload.totalTokens = { ...previousCumulativeTokens };
4108
4251
  }
4109
4252
  statusPayload.lastUpdate = stepEndTime;
@@ -4121,8 +4264,8 @@ async function runSubagent(
4121
4264
  tokens: stepTokens,
4122
4265
  }));
4123
4266
  if (singleResult.completionGuardTriggered) {
4124
- const event = buildControlEvent({
4125
- from: statusPayload.steps[flatIndex].activityState,
4267
+ const event = buildControlEvent(omitUndefinedProperties({
4268
+ from: requiredStatusStep(statusPayload, flatIndex).activityState,
4126
4269
  to: "needs_attention",
4127
4270
  runId: id,
4128
4271
  agent: seqStep.agent,
@@ -4130,7 +4273,7 @@ async function runSubagent(
4130
4273
  ts: stepEndTime,
4131
4274
  message: `${seqStep.agent} completed without making edits for an implementation task`,
4132
4275
  reason: "completion_guard",
4133
- });
4276
+ }));
4134
4277
  appendControlEvent(event);
4135
4278
  }
4136
4279
 
@@ -4211,13 +4354,13 @@ async function runSubagent(
4211
4354
  clearTimeout(timeoutTimer);
4212
4355
  timeoutTimer = undefined;
4213
4356
  }
4214
- const signalTerminated = !stopped && !timedOut && !turnBudgetExceeded && !interrupted && results.some((result) => result.exitCode !== 0 && isUnexplainedProcessSignal({
4357
+ const signalTerminated = !stopped && !timedOut && !turnBudgetExceeded && !interrupted && results.some((result) => result.exitCode !== 0 && isUnexplainedProcessSignal(omitUndefinedProperties({
4215
4358
  processSignal: result.processSignal,
4216
4359
  interrupted: result.interrupted,
4217
4360
  timedOut: result.timedOut,
4218
4361
  stopped: result.stopped,
4219
4362
  turnBudgetExceeded: result.turnBudgetExceeded,
4220
- }));
4363
+ })));
4221
4364
  statusPayload.state = checkpointRejected ? "rejected" : stopped || signalTerminated ? "stopped" : timedOut || turnBudgetExceeded || usageBudgetExceeded || statusPayload.error ? "failed" : interrupted ? "paused" : results.every((r) => r.success) ? "complete" : "failed";
4222
4365
  closeSteerInbox(asyncDir, statusPayload.state);
4223
4366
  disposeControlInbox();
@@ -4236,12 +4379,12 @@ async function runSubagent(
4236
4379
  if (changed) emitTerminalSteeringNotice(request.id, `Steering failed for run ${id}: child terminated before delivery.`);
4237
4380
  }
4238
4381
  const runEndedAt = Date.now();
4239
- statusPayload.activityState = undefined;
4382
+ delete statusPayload.activityState;
4240
4383
  if (stopped) {
4241
4384
  statusPayload.stopped = true;
4242
4385
  statusPayload.error = stopMessage;
4243
4386
  } else if (signalTerminated && !statusPayload.error) {
4244
- statusPayload.error = results.find((result) => result.processSignal)?.error;
4387
+ setOptionalProperty(statusPayload, "error", results.find((result) => result.processSignal)?.error);
4245
4388
  }
4246
4389
  if (timedOut) {
4247
4390
  statusPayload.timedOut = true;
@@ -4256,13 +4399,13 @@ async function runSubagent(
4256
4399
  }
4257
4400
  statusPayload.endedAt = runEndedAt;
4258
4401
  statusPayload.lastUpdate = runEndedAt;
4259
- statusPayload.sessionFile = effectiveSessionFile;
4402
+ setOptionalProperty(statusPayload, "sessionFile", effectiveSessionFile);
4260
4403
  if (singleRuntimeAcknowledgedExtensions) statusPayload.runtimeAcknowledgedExtensions = singleRuntimeAcknowledgedExtensions;
4261
- statusPayload.totalCost = finalTotalCost;
4262
- statusPayload.usageBudget = usageBudgetState(config.usageBudget, currentUsageTotals());
4263
- statusPayload.shareUrl = shareUrl;
4264
- statusPayload.gistUrl = gistUrl;
4265
- statusPayload.shareError = shareError;
4404
+ setOptionalProperty(statusPayload, "totalCost", finalTotalCost);
4405
+ setOptionalProperty(statusPayload, "usageBudget", usageBudgetState(config.usageBudget, currentUsageTotals()));
4406
+ setOptionalProperty(statusPayload, "shareUrl", shareUrl);
4407
+ setOptionalProperty(statusPayload, "gistUrl", gistUrl);
4408
+ setOptionalProperty(statusPayload, "shareError", shareError);
4266
4409
  if (statusPayload.state === "failed" && !statusPayload.error) {
4267
4410
  const failedStep = statusPayload.steps.find((s) => s.status === "failed");
4268
4411
  if (failedStep?.agent) {
@@ -4284,13 +4427,13 @@ async function runSubagent(
4284
4427
  usageBudget: statusPayload.usageBudget,
4285
4428
  }),
4286
4429
  );
4287
- writeRunLog(logPath, {
4430
+ writeRunLog(logPath, omitUndefinedProperties({
4288
4431
  id,
4289
4432
  mode: statusPayload.mode,
4290
4433
  cwd,
4291
4434
  startedAt: overallStartTime,
4292
4435
  endedAt: runEndedAt,
4293
- steps: statusPayload.steps.map((step) => ({
4436
+ steps: statusPayload.steps.map((step) => omitUndefinedProperties({
4294
4437
  agent: step.agent,
4295
4438
  status: step.status,
4296
4439
  durationMs: step.durationMs,
@@ -4301,7 +4444,7 @@ async function runSubagent(
4301
4444
  sessionFile: effectiveSessionFile,
4302
4445
  shareUrl,
4303
4446
  shareError,
4304
- });
4447
+ }));
4305
4448
 
4306
4449
  try {
4307
4450
  writeAtomicJson(resultPath, {
@@ -4322,10 +4465,9 @@ async function runSubagent(
4322
4465
  ...(statusPayload.usageBudget ? { usageBudget: statusPayload.usageBudget } : {}),
4323
4466
  ...(statusPayload.checkpoint ? { checkpoint: statusPayload.checkpoint } : {}),
4324
4467
  ...(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." } : {}),
4325
- results: results.map((r) => ({
4468
+ results: results.map((r) => omitUndefinedProperties({
4326
4469
  agent: r.agent,
4327
4470
  context: r.context,
4328
- outputPath: r.outputPath,
4329
4471
  output: r.output,
4330
4472
  outputState: r.outputState,
4331
4473
  error: r.error,
@@ -4348,6 +4490,8 @@ async function runSubagent(
4348
4490
  modelAttempts: r.modelAttempts,
4349
4491
  totalCost: r.totalCost,
4350
4492
  artifactPaths: r.artifactPaths,
4493
+ outputSaveError: r.outputSaveError,
4494
+ metadataSaveError: r.metadataSaveError,
4351
4495
  truncated: r.truncated,
4352
4496
  transcriptPath: r.transcriptPath,
4353
4497
  transcriptError: r.transcriptError,
@@ -4355,6 +4499,8 @@ async function runSubagent(
4355
4499
  launchContractDigest: r.launchContractDigest,
4356
4500
  launchResolvedExtensions: r.launchResolvedExtensions,
4357
4501
  runtimeAcknowledgedExtensions: r.runtimeAcknowledgedExtensions,
4502
+ runner: r.runner,
4503
+ externalProcess: r.externalProcess,
4358
4504
  execution: r.execution,
4359
4505
  review: r.review,
4360
4506
  effects: r.effects,
@@ -4371,6 +4517,8 @@ async function runSubagent(
4371
4517
  parallelHandoff: statusPayload.parallelHandoff,
4372
4518
  capabilityCeiling: statusPayload.capabilityCeiling,
4373
4519
  capabilityAudit: statusPayload.capabilityAudit,
4520
+ ...(config.parentWorkflowRunId ? { parentWorkflowRunId: config.parentWorkflowRunId } : {}),
4521
+ ...(config.workflowKey ? { workflowKey: config.workflowKey } : {}),
4374
4522
  exitCode: checkpointRejected || stopped || timedOut || turnBudgetExceeded || usageBudgetExceeded ? 1 : interrupted || results.every((r) => r.success) ? 0 : 1,
4375
4523
  timestamp: runEndedAt,
4376
4524
  durationMs: runEndedAt - overallStartTime,