@selesai/code 0.6.3 → 0.8.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 (1056) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/README.md +5 -3
  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/agent-browser.test.ts +195 -0
  204. package/dist/extensions/agent-browser.ts +158 -0
  205. package/dist/extensions/inline-skills.test.ts +27 -13
  206. package/dist/extensions/inline-skills.ts +18 -11
  207. package/dist/extensions/package.json +2 -1
  208. package/dist/extensions/pi-powerline-footer/.github/workflows/test.yml +27 -0
  209. package/dist/extensions/pi-powerline-footer/CHANGELOG.md +153 -0
  210. package/dist/extensions/pi-powerline-footer/CONTRIBUTING.md +16 -0
  211. package/dist/extensions/pi-powerline-footer/README.md +192 -44
  212. package/dist/extensions/pi-powerline-footer/bash-mode/completion.ts +19 -4
  213. package/dist/extensions/pi-powerline-footer/bash-mode/editor.ts +80 -25
  214. package/dist/extensions/pi-powerline-footer/bash-mode/history.ts +81 -29
  215. package/dist/extensions/pi-powerline-footer/bash-mode/types.ts +1 -1
  216. package/dist/extensions/pi-powerline-footer/cd-command.ts +190 -0
  217. package/dist/extensions/pi-powerline-footer/colors.ts +2 -1
  218. package/dist/extensions/pi-powerline-footer/context-usage.ts +121 -6
  219. package/dist/extensions/pi-powerline-footer/currency-rates.ts +142 -0
  220. package/dist/extensions/pi-powerline-footer/editor-composition.ts +32 -0
  221. package/dist/extensions/pi-powerline-footer/git-status.ts +108 -6
  222. package/dist/extensions/pi-powerline-footer/icons.ts +11 -2
  223. package/dist/extensions/pi-powerline-footer/index.ts +1056 -324
  224. package/dist/extensions/pi-powerline-footer/lifecycle.ts +10 -0
  225. package/dist/extensions/pi-powerline-footer/package.json +10 -6
  226. package/dist/extensions/pi-powerline-footer/paths.ts +22 -0
  227. package/dist/extensions/pi-powerline-footer/powerline-config.ts +297 -15
  228. package/dist/extensions/pi-powerline-footer/presets.ts +6 -25
  229. package/dist/extensions/pi-powerline-footer/queue/store.ts +361 -0
  230. package/dist/extensions/pi-powerline-footer/queue/types.ts +54 -0
  231. package/dist/extensions/pi-powerline-footer/render-scheduler.ts +12 -7
  232. package/dist/extensions/pi-powerline-footer/segments.ts +114 -107
  233. package/dist/extensions/pi-powerline-footer/session-usage.ts +1 -1
  234. package/dist/extensions/pi-powerline-footer/shortcuts.ts +17 -3
  235. package/dist/extensions/pi-powerline-footer/tests/bash-mode.test.ts +189 -17
  236. package/dist/extensions/pi-powerline-footer/tests/cd-command.test.ts +144 -0
  237. package/dist/extensions/pi-powerline-footer/tests/context-usage.test.ts +120 -2
  238. package/dist/extensions/pi-powerline-footer/tests/custom-items.test.ts +245 -22
  239. package/dist/extensions/pi-powerline-footer/tests/editor-composition.test.ts +48 -0
  240. package/dist/extensions/pi-powerline-footer/tests/editor-responsiveness.test.ts +34 -0
  241. package/dist/extensions/pi-powerline-footer/tests/fixed-editor-border.test.ts +39 -0
  242. package/dist/extensions/pi-powerline-footer/tests/git-status.test.ts +92 -0
  243. package/dist/extensions/pi-powerline-footer/tests/guide.test.ts +4 -1
  244. package/dist/extensions/pi-powerline-footer/tests/jump-shortcuts.test.ts +33 -197
  245. package/dist/extensions/pi-powerline-footer/tests/mode-aware-trigger.test.ts +79 -0
  246. package/dist/extensions/pi-powerline-footer/tests/paths.test.ts +63 -0
  247. package/dist/extensions/pi-powerline-footer/tests/queue-store.test.ts +195 -0
  248. package/dist/extensions/pi-powerline-footer/tests/quit-cursor.test.ts +14 -0
  249. package/dist/extensions/pi-powerline-footer/tests/remaining-regressions.test.ts +167 -0
  250. package/dist/extensions/pi-powerline-footer/tests/stash-shortcut.test.ts +23 -18
  251. package/dist/extensions/pi-powerline-footer/tests/thinking-segment.test.ts +16 -1
  252. package/dist/extensions/pi-powerline-footer/tests/token-stats.test.ts +249 -0
  253. package/dist/extensions/pi-powerline-footer/tests/usage-display.test.ts +237 -0
  254. package/dist/extensions/pi-powerline-footer/tests/welcome.test.ts +199 -0
  255. package/dist/extensions/pi-powerline-footer/tests/working-vibes.test.ts +191 -100
  256. package/dist/extensions/pi-powerline-footer/theme.ts +32 -18
  257. package/dist/extensions/pi-powerline-footer/token-stats.ts +304 -0
  258. package/dist/extensions/pi-powerline-footer/tsconfig.json +13 -0
  259. package/dist/extensions/pi-powerline-footer/types.ts +74 -29
  260. package/dist/extensions/pi-powerline-footer/welcome-dismiss.ts +34 -0
  261. package/dist/extensions/pi-powerline-footer/welcome.ts +65 -10
  262. package/dist/extensions/pi-powerline-footer/working-vibes.ts +44 -11
  263. package/dist/extensions/pi-subagents/CHANGELOG.md +89 -12
  264. package/dist/extensions/pi-subagents/README.md +339 -604
  265. package/dist/extensions/pi-subagents/package-lock.json +190 -2079
  266. package/dist/extensions/pi-subagents/package.json +13 -5
  267. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +1 -1
  268. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +1 -1
  269. package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
  270. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +10 -10
  271. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +32 -43
  272. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +106 -105
  273. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +3 -3
  274. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +28 -35
  275. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +167 -124
  276. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
  277. package/dist/extensions/pi-subagents/src/agents/agents.ts +163 -75
  278. package/dist/extensions/pi-subagents/src/agents/chain-serializer.ts +10 -7
  279. package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +5 -3
  280. package/dist/extensions/pi-subagents/src/agents/identity.ts +1 -1
  281. package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +14 -11
  282. package/dist/extensions/pi-subagents/src/agents/skills.ts +23 -6
  283. package/dist/extensions/pi-subagents/src/agents/task-aware-routing.ts +8 -1
  284. package/dist/extensions/pi-subagents/src/api/control-channel.ts +4 -0
  285. package/dist/extensions/pi-subagents/src/api/delegation.ts +26 -194
  286. package/dist/extensions/pi-subagents/src/api/external-runs.ts +129 -0
  287. package/dist/extensions/pi-subagents/src/api/intercom-bridge.ts +3 -0
  288. package/dist/extensions/pi-subagents/src/api/pi-args.ts +5 -0
  289. package/dist/extensions/pi-subagents/src/api/preflight.ts +4 -4
  290. package/dist/extensions/pi-subagents/src/api/shared-types.ts +19 -0
  291. package/dist/extensions/pi-subagents/src/extension/config.ts +10 -0
  292. package/dist/extensions/pi-subagents/src/extension/control-notices.ts +5 -39
  293. package/dist/extensions/pi-subagents/src/extension/doctor.ts +10 -9
  294. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +7 -4
  295. package/dist/extensions/pi-subagents/src/extension/index.ts +243 -77
  296. package/dist/extensions/pi-subagents/src/extension/rpc.ts +18 -6
  297. package/dist/extensions/pi-subagents/src/extension/schemas.ts +50 -39
  298. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +36 -103
  299. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +229 -0
  300. package/dist/extensions/pi-subagents/src/inspectors/herdr/client.ts +130 -0
  301. package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +141 -0
  302. package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +154 -0
  303. package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +330 -0
  304. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +3 -2
  305. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +5 -1
  306. package/dist/extensions/pi-subagents/src/missions/actions.ts +372 -0
  307. package/dist/extensions/pi-subagents/src/missions/lifecycle.ts +314 -0
  308. package/dist/extensions/pi-subagents/src/missions/store.ts +442 -0
  309. package/dist/extensions/pi-subagents/src/missions/types.ts +135 -0
  310. package/dist/extensions/pi-subagents/src/policy/authority.ts +46 -0
  311. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +32 -6
  312. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +103 -72
  313. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +10 -2
  314. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +6 -6
  315. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +29 -1
  316. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +3 -3
  317. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +3 -2
  318. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +9 -7
  319. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +3 -4
  320. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +3 -28
  321. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +5 -5
  322. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +18 -68
  323. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +3 -3
  324. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +35 -8
  325. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +602 -375
  326. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -3
  327. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +612 -464
  328. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +50 -9
  329. package/dist/extensions/pi-subagents/src/runs/background/wait-subscriptions.ts +253 -0
  330. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +12 -4
  331. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +3 -3
  332. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +8 -4
  333. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +74 -102
  334. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +21 -22
  335. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1050 -396
  336. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +44 -18
  337. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +0 -1
  338. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +302 -22
  339. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
  340. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +130 -0
  341. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +42 -1
  342. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +1 -1
  343. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +59 -5
  344. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +9 -4
  345. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +86 -2
  346. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +11 -2
  347. package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +95 -0
  348. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +11 -1
  349. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +15 -6
  350. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +1 -1
  351. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +9 -63
  352. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +37 -6
  353. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +5 -2
  354. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +2 -23
  355. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +6 -6
  356. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +124 -13
  357. package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +29 -7
  358. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +18 -1
  359. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +3 -2
  360. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +1 -0
  361. package/dist/extensions/pi-subagents/src/shared/settings.ts +10 -0
  362. package/dist/extensions/pi-subagents/src/shared/types.ts +158 -55
  363. package/dist/extensions/pi-subagents/src/shared/utils.ts +16 -66
  364. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +33 -199
  365. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +43 -126
  366. package/dist/extensions/pi-subagents/src/slash/inline-subagents.ts +136 -0
  367. package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +158 -205
  368. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +22 -58
  369. package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +14 -0
  370. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +44 -642
  371. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +18 -14
  372. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +156 -21
  373. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +110 -5
  374. package/dist/extensions/pi-subagents/src/tui/fleet.ts +60 -24
  375. package/dist/extensions/pi-subagents/src/tui/render.ts +296 -140
  376. package/dist/extensions/pi-subagents/src/types/pi-runtime-compat.d.ts +14 -0
  377. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +1 -1
  378. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +13 -7
  379. package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +2 -2
  380. package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +145 -0
  381. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +1 -1
  382. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +1 -1
  383. package/dist/extensions/pi-subagents/src/watchdog/review.ts +4 -1
  384. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +3 -2
  385. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +140 -0
  386. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +415 -0
  387. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +41 -144
  388. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +16 -16
  389. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +415 -298
  390. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +149 -82
  391. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +40 -40
  392. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +15 -15
  393. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +193 -133
  394. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +1 -49
  395. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +62 -0
  396. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +56 -58
  397. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +81 -68
  398. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +20 -25
  399. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +425 -317
  400. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +73 -73
  401. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +123 -98
  402. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +653 -240
  403. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +20 -1661
  404. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +9 -9
  405. package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +3 -3
  406. package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +2 -2
  407. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +8 -5
  408. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +6 -6
  409. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +4 -20
  410. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +25 -4
  411. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +1 -1
  412. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +280 -295
  413. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +47 -207
  414. package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +26 -26
  415. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +89 -89
  416. package/dist/extensions/pi-subagents/test/unit/agent-selection.test.ts +9 -9
  417. package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +10 -0
  418. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +33 -9
  419. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +24 -2
  420. package/dist/extensions/pi-subagents/test/unit/async-permission-session.test.ts +11 -9
  421. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +2 -2
  422. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +40 -40
  423. package/dist/extensions/pi-subagents/test/unit/authority-policy.test.ts +22 -0
  424. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +1 -1
  425. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +5 -39
  426. package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +19 -19
  427. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +9 -9
  428. package/dist/extensions/pi-subagents/test/unit/chain-serializer.test.ts +20 -20
  429. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +99 -0
  430. package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +9 -9
  431. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +41 -0
  432. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +2 -2
  433. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +35 -5
  434. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +7 -0
  435. package/dist/extensions/pi-subagents/test/unit/control-notices.test.ts +16 -82
  436. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +162 -620
  437. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
  438. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +25 -25
  439. package/dist/extensions/pi-subagents/test/unit/ensure-accessible-dir.test.ts +125 -0
  440. package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +94 -0
  441. package/dist/extensions/pi-subagents/test/unit/external-runs.test.ts +66 -0
  442. package/dist/extensions/pi-subagents/test/unit/extra-agent-dirs.test.ts +3 -3
  443. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +242 -52
  444. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +127 -0
  445. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +197 -36
  446. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +4 -4
  447. package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +245 -0
  448. package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +494 -0
  449. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +261 -31
  450. package/dist/extensions/pi-subagents/test/unit/inline-subagents.test.ts +127 -0
  451. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +6 -6
  452. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +217 -0
  453. package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +182 -0
  454. package/dist/extensions/pi-subagents/test/unit/mock-pi.test.ts +22 -0
  455. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +1 -1
  456. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +10 -10
  457. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -12
  458. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +47 -5
  459. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +49 -55
  460. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +20 -3
  461. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +37 -7
  462. package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +10 -10
  463. package/dist/extensions/pi-subagents/test/unit/path-handling.test.ts +3 -3
  464. package/dist/extensions/pi-subagents/test/unit/permissions.test.ts +46 -0
  465. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +31 -10
  466. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +40 -16
  467. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +42 -44
  468. package/dist/extensions/pi-subagents/test/unit/proactive-skills.test.ts +13 -13
  469. package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +4 -4
  470. package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +75 -9
  471. package/dist/extensions/pi-subagents/test/unit/prompt-template-bridge.test.ts +20 -84
  472. package/dist/extensions/pi-subagents/test/unit/prompt-workflows.test.ts +15 -16
  473. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +28 -28
  474. package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +19 -12
  475. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +37 -21
  476. package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +1 -1
  477. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +50 -50
  478. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +396 -433
  479. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +76 -153
  480. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +411 -0
  481. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +1 -91
  482. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +139 -0
  483. package/dist/extensions/pi-subagents/test/unit/slash-bridge.test.ts +29 -0
  484. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +13 -13
  485. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -2
  486. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +2 -2
  487. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +35 -35
  488. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +53 -18
  489. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +13 -1
  490. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +44 -11
  491. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +2 -26
  492. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +24 -148
  493. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +11 -9
  494. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +351 -0
  495. package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +13 -13
  496. package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +1 -1
  497. package/dist/extensions/pi-subagents/test/unit/watchdog-permission-arbiter.test.ts +79 -0
  498. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +1 -1
  499. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +8 -8
  500. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +45 -9
  501. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +197 -0
  502. package/dist/extensions/pi-subagents/test/unit/workflow-graph.test.ts +8 -8
  503. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +142 -12
  504. package/dist/extensions/pi-subagents/tsconfig.json +15 -0
  505. package/dist/extensions/ponytail/index.js +1 -31
  506. package/dist/extensions/ponytail/test/extension.test.js +5 -22
  507. package/dist/extensions/rtk.test.ts +141 -0
  508. package/dist/extensions/rtk.ts +78 -36
  509. package/dist/index.d.ts +1 -1
  510. package/dist/index.js +1 -1
  511. package/dist/main.d.ts +0 -1
  512. package/dist/main.js +0 -1
  513. package/dist/migrations.d.ts +0 -1
  514. package/dist/migrations.js +0 -1
  515. package/dist/modes/index.d.ts +0 -1
  516. package/dist/modes/index.js +0 -1
  517. package/dist/modes/interactive/components/armin.d.ts +0 -1
  518. package/dist/modes/interactive/components/armin.js +0 -1
  519. package/dist/modes/interactive/components/assistant-message.d.ts +0 -1
  520. package/dist/modes/interactive/components/assistant-message.js +0 -1
  521. package/dist/modes/interactive/components/bash-execution.d.ts +0 -1
  522. package/dist/modes/interactive/components/bash-execution.js +0 -1
  523. package/dist/modes/interactive/components/bordered-loader.d.ts +0 -1
  524. package/dist/modes/interactive/components/bordered-loader.js +0 -1
  525. package/dist/modes/interactive/components/branch-summary-message.d.ts +0 -1
  526. package/dist/modes/interactive/components/branch-summary-message.js +0 -1
  527. package/dist/modes/interactive/components/compaction-summary-message.d.ts +0 -1
  528. package/dist/modes/interactive/components/compaction-summary-message.js +0 -1
  529. package/dist/modes/interactive/components/config-selector.d.ts +0 -1
  530. package/dist/modes/interactive/components/config-selector.js +0 -1
  531. package/dist/modes/interactive/components/countdown-timer.d.ts +0 -1
  532. package/dist/modes/interactive/components/countdown-timer.js +0 -1
  533. package/dist/modes/interactive/components/custom-editor.d.ts +0 -1
  534. package/dist/modes/interactive/components/custom-editor.js +0 -1
  535. package/dist/modes/interactive/components/custom-entry.d.ts +0 -1
  536. package/dist/modes/interactive/components/custom-entry.js +0 -1
  537. package/dist/modes/interactive/components/custom-message.d.ts +0 -1
  538. package/dist/modes/interactive/components/custom-message.js +0 -1
  539. package/dist/modes/interactive/components/daxnuts.d.ts +0 -1
  540. package/dist/modes/interactive/components/daxnuts.js +0 -1
  541. package/dist/modes/interactive/components/diff.d.ts +0 -1
  542. package/dist/modes/interactive/components/diff.js +0 -1
  543. package/dist/modes/interactive/components/dynamic-border.d.ts +0 -1
  544. package/dist/modes/interactive/components/dynamic-border.js +0 -1
  545. package/dist/modes/interactive/components/earendil-announcement.d.ts +0 -1
  546. package/dist/modes/interactive/components/earendil-announcement.js +0 -1
  547. package/dist/modes/interactive/components/extension-editor.d.ts +0 -1
  548. package/dist/modes/interactive/components/extension-editor.js +0 -1
  549. package/dist/modes/interactive/components/extension-input.d.ts +0 -1
  550. package/dist/modes/interactive/components/extension-input.js +0 -1
  551. package/dist/modes/interactive/components/extension-selector.d.ts +0 -1
  552. package/dist/modes/interactive/components/extension-selector.js +0 -1
  553. package/dist/modes/interactive/components/first-time-setup.d.ts +0 -1
  554. package/dist/modes/interactive/components/first-time-setup.js +0 -1
  555. package/dist/modes/interactive/components/footer.d.ts +0 -1
  556. package/dist/modes/interactive/components/footer.js +0 -1
  557. package/dist/modes/interactive/components/index.d.ts +0 -1
  558. package/dist/modes/interactive/components/index.js +0 -1
  559. package/dist/modes/interactive/components/keybinding-hints.d.ts +0 -1
  560. package/dist/modes/interactive/components/keybinding-hints.js +0 -1
  561. package/dist/modes/interactive/components/login-dialog.d.ts +0 -1
  562. package/dist/modes/interactive/components/login-dialog.js +0 -1
  563. package/dist/modes/interactive/components/model-selector.d.ts +0 -1
  564. package/dist/modes/interactive/components/model-selector.js +0 -1
  565. package/dist/modes/interactive/components/oauth-selector.d.ts +0 -1
  566. package/dist/modes/interactive/components/oauth-selector.js +0 -1
  567. package/dist/modes/interactive/components/scoped-models-selector.d.ts +0 -1
  568. package/dist/modes/interactive/components/scoped-models-selector.js +0 -1
  569. package/dist/modes/interactive/components/session-selector-search.d.ts +0 -1
  570. package/dist/modes/interactive/components/session-selector-search.js +0 -1
  571. package/dist/modes/interactive/components/session-selector.d.ts +0 -1
  572. package/dist/modes/interactive/components/session-selector.js +0 -1
  573. package/dist/modes/interactive/components/settings-selector.d.ts +0 -3
  574. package/dist/modes/interactive/components/settings-selector.js +1 -14
  575. package/dist/modes/interactive/components/show-images-selector.d.ts +0 -1
  576. package/dist/modes/interactive/components/show-images-selector.js +0 -1
  577. package/dist/modes/interactive/components/skill-invocation-message.d.ts +0 -1
  578. package/dist/modes/interactive/components/skill-invocation-message.js +0 -1
  579. package/dist/modes/interactive/components/status-indicator.d.ts +0 -1
  580. package/dist/modes/interactive/components/status-indicator.js +0 -1
  581. package/dist/modes/interactive/components/theme-selector.d.ts +0 -1
  582. package/dist/modes/interactive/components/theme-selector.js +0 -1
  583. package/dist/modes/interactive/components/thinking-selector.d.ts +0 -1
  584. package/dist/modes/interactive/components/thinking-selector.js +0 -1
  585. package/dist/modes/interactive/components/tool-execution.d.ts +0 -1
  586. package/dist/modes/interactive/components/tool-execution.js +0 -1
  587. package/dist/modes/interactive/components/tree-selector.d.ts +0 -1
  588. package/dist/modes/interactive/components/tree-selector.js +0 -1
  589. package/dist/modes/interactive/components/trust-selector.d.ts +0 -1
  590. package/dist/modes/interactive/components/trust-selector.js +0 -1
  591. package/dist/modes/interactive/components/user-message-selector.d.ts +0 -1
  592. package/dist/modes/interactive/components/user-message-selector.js +0 -1
  593. package/dist/modes/interactive/components/user-message.d.ts +0 -1
  594. package/dist/modes/interactive/components/user-message.js +0 -1
  595. package/dist/modes/interactive/components/visual-truncate.d.ts +0 -1
  596. package/dist/modes/interactive/components/visual-truncate.js +0 -1
  597. package/dist/modes/interactive/external-editor.d.ts +0 -1
  598. package/dist/modes/interactive/external-editor.js +0 -1
  599. package/dist/modes/interactive/interactive-mode.d.ts +0 -2
  600. package/dist/modes/interactive/interactive-mode.js +1 -22
  601. package/dist/modes/interactive/model-search.d.ts +0 -1
  602. package/dist/modes/interactive/model-search.js +0 -1
  603. package/dist/modes/interactive/theme/theme-controller.d.ts +0 -1
  604. package/dist/modes/interactive/theme/theme-controller.js +0 -1
  605. package/dist/modes/interactive/theme/theme.d.ts +0 -1
  606. package/dist/modes/interactive/theme/theme.js +0 -1
  607. package/dist/modes/print-mode.d.ts +0 -1
  608. package/dist/modes/print-mode.js +0 -1
  609. package/dist/modes/rpc/jsonl.d.ts +0 -1
  610. package/dist/modes/rpc/jsonl.js +0 -1
  611. package/dist/modes/rpc/rpc-client.d.ts +1 -2
  612. package/dist/modes/rpc/rpc-client.js +1 -2
  613. package/dist/modes/rpc/rpc-mode.d.ts +0 -1
  614. package/dist/modes/rpc/rpc-mode.js +0 -9
  615. package/dist/modes/rpc/rpc-types.d.ts +0 -1
  616. package/dist/modes/rpc/rpc-types.js +0 -1
  617. package/dist/package-manager-cli.d.ts +0 -1
  618. package/dist/package-manager-cli.js +0 -1
  619. package/dist/rpc-entry.d.ts +0 -1
  620. package/dist/rpc-entry.js +0 -1
  621. package/dist/utils/ansi.d.ts +0 -1
  622. package/dist/utils/ansi.js +0 -1
  623. package/dist/utils/changelog.d.ts +0 -1
  624. package/dist/utils/changelog.js +0 -1
  625. package/dist/utils/child-process.d.ts +0 -1
  626. package/dist/utils/child-process.js +0 -1
  627. package/dist/utils/clipboard-image.d.ts +0 -1
  628. package/dist/utils/clipboard-image.js +0 -1
  629. package/dist/utils/clipboard-native.d.ts +0 -1
  630. package/dist/utils/clipboard-native.js +0 -1
  631. package/dist/utils/clipboard.d.ts +0 -1
  632. package/dist/utils/clipboard.js +0 -1
  633. package/dist/utils/deprecation.d.ts +0 -1
  634. package/dist/utils/deprecation.js +0 -1
  635. package/dist/utils/exif-orientation.d.ts +0 -1
  636. package/dist/utils/exif-orientation.js +0 -1
  637. package/dist/utils/frontmatter.d.ts +0 -1
  638. package/dist/utils/frontmatter.js +0 -1
  639. package/dist/utils/fs-watch.d.ts +0 -1
  640. package/dist/utils/fs-watch.js +0 -1
  641. package/dist/utils/git.d.ts +0 -1
  642. package/dist/utils/git.js +0 -1
  643. package/dist/utils/html.d.ts +0 -1
  644. package/dist/utils/html.js +0 -1
  645. package/dist/utils/image-convert.d.ts +0 -1
  646. package/dist/utils/image-convert.js +0 -1
  647. package/dist/utils/image-process.d.ts +0 -1
  648. package/dist/utils/image-process.js +0 -1
  649. package/dist/utils/image-resize-core.d.ts +0 -1
  650. package/dist/utils/image-resize-core.js +0 -1
  651. package/dist/utils/image-resize-worker.d.ts +0 -1
  652. package/dist/utils/image-resize-worker.js +0 -1
  653. package/dist/utils/image-resize.d.ts +0 -1
  654. package/dist/utils/image-resize.js +0 -1
  655. package/dist/utils/json.d.ts +0 -1
  656. package/dist/utils/json.js +0 -1
  657. package/dist/utils/mime.d.ts +0 -1
  658. package/dist/utils/mime.js +0 -1
  659. package/dist/utils/open-browser.d.ts +0 -1
  660. package/dist/utils/open-browser.js +0 -1
  661. package/dist/utils/paths.d.ts +0 -1
  662. package/dist/utils/paths.js +0 -1
  663. package/dist/utils/photon.d.ts +0 -1
  664. package/dist/utils/photon.js +0 -1
  665. package/dist/utils/pi-user-agent.d.ts +0 -1
  666. package/dist/utils/pi-user-agent.js +0 -1
  667. package/dist/utils/shell.d.ts +0 -1
  668. package/dist/utils/shell.js +0 -1
  669. package/dist/utils/sleep.d.ts +0 -1
  670. package/dist/utils/sleep.js +0 -1
  671. package/dist/utils/syntax-highlight.d.ts +0 -1
  672. package/dist/utils/syntax-highlight.js +0 -1
  673. package/dist/utils/thinking-tags.d.ts +0 -1
  674. package/dist/utils/thinking-tags.js +0 -1
  675. package/dist/utils/tools-manager.d.ts +3 -3
  676. package/dist/utils/tools-manager.js +125 -42
  677. package/dist/utils/version-check.d.ts +0 -1
  678. package/dist/utils/version-check.js +0 -1
  679. package/dist/utils/windows-self-update.d.ts +0 -1
  680. package/dist/utils/windows-self-update.js +0 -1
  681. package/docs/rpc.md +1 -2
  682. package/docs/settings.md +0 -1
  683. package/docs/skills.md +10 -18
  684. package/package.json +3 -2
  685. package/dist/bun/cli.d.ts.map +0 -1
  686. package/dist/bun/cli.js.map +0 -1
  687. package/dist/bun/register-bedrock.d.ts.map +0 -1
  688. package/dist/bun/register-bedrock.js.map +0 -1
  689. package/dist/bun/restore-sandbox-env.d.ts.map +0 -1
  690. package/dist/bun/restore-sandbox-env.js.map +0 -1
  691. package/dist/cli/args.d.ts.map +0 -1
  692. package/dist/cli/args.js.map +0 -1
  693. package/dist/cli/config-selector.d.ts.map +0 -1
  694. package/dist/cli/config-selector.js.map +0 -1
  695. package/dist/cli/credential-print.d.ts.map +0 -1
  696. package/dist/cli/credential-print.js.map +0 -1
  697. package/dist/cli/file-processor.d.ts.map +0 -1
  698. package/dist/cli/file-processor.js.map +0 -1
  699. package/dist/cli/initial-message.d.ts.map +0 -1
  700. package/dist/cli/initial-message.js.map +0 -1
  701. package/dist/cli/list-models.d.ts.map +0 -1
  702. package/dist/cli/list-models.js.map +0 -1
  703. package/dist/cli/project-trust.d.ts.map +0 -1
  704. package/dist/cli/project-trust.js.map +0 -1
  705. package/dist/cli/session-picker.d.ts.map +0 -1
  706. package/dist/cli/session-picker.js.map +0 -1
  707. package/dist/cli/startup-ui.d.ts.map +0 -1
  708. package/dist/cli/startup-ui.js.map +0 -1
  709. package/dist/cli.d.ts.map +0 -1
  710. package/dist/cli.js.map +0 -1
  711. package/dist/config.d.ts.map +0 -1
  712. package/dist/config.js.map +0 -1
  713. package/dist/core/agent-session-auto-handoff.test.d.ts.map +0 -1
  714. package/dist/core/agent-session-auto-handoff.test.js.map +0 -1
  715. package/dist/core/agent-session-runtime.d.ts.map +0 -1
  716. package/dist/core/agent-session-runtime.js.map +0 -1
  717. package/dist/core/agent-session-services.d.ts.map +0 -1
  718. package/dist/core/agent-session-services.js.map +0 -1
  719. package/dist/core/agent-session-skill-block.test.d.ts.map +0 -1
  720. package/dist/core/agent-session-skill-block.test.js.map +0 -1
  721. package/dist/core/agent-session.d.ts.map +0 -1
  722. package/dist/core/agent-session.js.map +0 -1
  723. package/dist/core/agents.d.ts.map +0 -1
  724. package/dist/core/agents.js.map +0 -1
  725. package/dist/core/auth-guidance.d.ts.map +0 -1
  726. package/dist/core/auth-guidance.js.map +0 -1
  727. package/dist/core/auth-storage.d.ts.map +0 -1
  728. package/dist/core/auth-storage.js.map +0 -1
  729. package/dist/core/bash-executor.d.ts.map +0 -1
  730. package/dist/core/bash-executor.js.map +0 -1
  731. package/dist/core/built-in-extensions.d.ts.map +0 -1
  732. package/dist/core/built-in-extensions.js.map +0 -1
  733. package/dist/core/cache-stats.d.ts.map +0 -1
  734. package/dist/core/cache-stats.js.map +0 -1
  735. package/dist/core/compaction/branch-summarization.d.ts.map +0 -1
  736. package/dist/core/compaction/branch-summarization.js.map +0 -1
  737. package/dist/core/compaction/compaction.d.ts.map +0 -1
  738. package/dist/core/compaction/compaction.js.map +0 -1
  739. package/dist/core/compaction/index.d.ts.map +0 -1
  740. package/dist/core/compaction/index.js.map +0 -1
  741. package/dist/core/compaction/utils.d.ts.map +0 -1
  742. package/dist/core/compaction/utils.js.map +0 -1
  743. package/dist/core/defaults.d.ts.map +0 -1
  744. package/dist/core/defaults.js.map +0 -1
  745. package/dist/core/diagnostics.d.ts.map +0 -1
  746. package/dist/core/diagnostics.js.map +0 -1
  747. package/dist/core/event-bus.d.ts.map +0 -1
  748. package/dist/core/event-bus.js.map +0 -1
  749. package/dist/core/exec.d.ts.map +0 -1
  750. package/dist/core/exec.js.map +0 -1
  751. package/dist/core/experimental.d.ts.map +0 -1
  752. package/dist/core/experimental.js.map +0 -1
  753. package/dist/core/export-html/ansi-to-html.d.ts.map +0 -1
  754. package/dist/core/export-html/ansi-to-html.js.map +0 -1
  755. package/dist/core/export-html/index.d.ts.map +0 -1
  756. package/dist/core/export-html/index.js.map +0 -1
  757. package/dist/core/export-html/tool-renderer.d.ts.map +0 -1
  758. package/dist/core/export-html/tool-renderer.js.map +0 -1
  759. package/dist/core/extensions/index.d.ts.map +0 -1
  760. package/dist/core/extensions/index.js.map +0 -1
  761. package/dist/core/extensions/loader.d.ts.map +0 -1
  762. package/dist/core/extensions/loader.js.map +0 -1
  763. package/dist/core/extensions/runner.d.ts.map +0 -1
  764. package/dist/core/extensions/runner.js.map +0 -1
  765. package/dist/core/extensions/types.d.ts.map +0 -1
  766. package/dist/core/extensions/types.js.map +0 -1
  767. package/dist/core/extensions/wrapper.d.ts.map +0 -1
  768. package/dist/core/extensions/wrapper.js.map +0 -1
  769. package/dist/core/footer-data-provider.d.ts.map +0 -1
  770. package/dist/core/footer-data-provider.js.map +0 -1
  771. package/dist/core/git-command.d.ts.map +0 -1
  772. package/dist/core/git-command.js.map +0 -1
  773. package/dist/core/http-dispatcher.d.ts.map +0 -1
  774. package/dist/core/http-dispatcher.js.map +0 -1
  775. package/dist/core/index.d.ts.map +0 -1
  776. package/dist/core/index.js.map +0 -1
  777. package/dist/core/keybindings.d.ts.map +0 -1
  778. package/dist/core/keybindings.js.map +0 -1
  779. package/dist/core/llama/client.d.ts.map +0 -1
  780. package/dist/core/llama/client.js.map +0 -1
  781. package/dist/core/llama/huggingface.d.ts.map +0 -1
  782. package/dist/core/llama/huggingface.js.map +0 -1
  783. package/dist/core/llama/index.d.ts.map +0 -1
  784. package/dist/core/llama/index.js.map +0 -1
  785. package/dist/core/llama/provider.d.ts.map +0 -1
  786. package/dist/core/llama/provider.js.map +0 -1
  787. package/dist/core/llama/ui.d.ts.map +0 -1
  788. package/dist/core/llama/ui.js.map +0 -1
  789. package/dist/core/messages.d.ts.map +0 -1
  790. package/dist/core/messages.js.map +0 -1
  791. package/dist/core/model-config.d.ts.map +0 -1
  792. package/dist/core/model-config.js.map +0 -1
  793. package/dist/core/model-registry.d.ts.map +0 -1
  794. package/dist/core/model-registry.js.map +0 -1
  795. package/dist/core/model-resolver.d.ts.map +0 -1
  796. package/dist/core/model-resolver.js.map +0 -1
  797. package/dist/core/model-runtime.d.ts.map +0 -1
  798. package/dist/core/model-runtime.js.map +0 -1
  799. package/dist/core/models-store.d.ts.map +0 -1
  800. package/dist/core/models-store.js.map +0 -1
  801. package/dist/core/output-guard.d.ts.map +0 -1
  802. package/dist/core/output-guard.js.map +0 -1
  803. package/dist/core/package-manager.d.ts.map +0 -1
  804. package/dist/core/package-manager.js.map +0 -1
  805. package/dist/core/package-manager.test.d.ts.map +0 -1
  806. package/dist/core/package-manager.test.js.map +0 -1
  807. package/dist/core/project-trust.d.ts.map +0 -1
  808. package/dist/core/project-trust.js.map +0 -1
  809. package/dist/core/prompt-templates.d.ts.map +0 -1
  810. package/dist/core/prompt-templates.js.map +0 -1
  811. package/dist/core/provider-attribution.d.ts.map +0 -1
  812. package/dist/core/provider-attribution.js.map +0 -1
  813. package/dist/core/provider-composer.d.ts.map +0 -1
  814. package/dist/core/provider-composer.js.map +0 -1
  815. package/dist/core/radius.d.ts.map +0 -1
  816. package/dist/core/radius.js.map +0 -1
  817. package/dist/core/remote-catalog-provider.d.ts.map +0 -1
  818. package/dist/core/remote-catalog-provider.js.map +0 -1
  819. package/dist/core/resolve-config-value.d.ts.map +0 -1
  820. package/dist/core/resolve-config-value.js.map +0 -1
  821. package/dist/core/resource-loader.d.ts.map +0 -1
  822. package/dist/core/resource-loader.js.map +0 -1
  823. package/dist/core/runtime-credentials.d.ts.map +0 -1
  824. package/dist/core/runtime-credentials.js.map +0 -1
  825. package/dist/core/sdk.d.ts.map +0 -1
  826. package/dist/core/sdk.js.map +0 -1
  827. package/dist/core/session-cwd.d.ts.map +0 -1
  828. package/dist/core/session-cwd.js.map +0 -1
  829. package/dist/core/session-manager.d.ts.map +0 -1
  830. package/dist/core/session-manager.js.map +0 -1
  831. package/dist/core/settings-manager-auto-handoff.test.d.ts.map +0 -1
  832. package/dist/core/settings-manager-auto-handoff.test.js.map +0 -1
  833. package/dist/core/settings-manager.d.ts.map +0 -1
  834. package/dist/core/settings-manager.js.map +0 -1
  835. package/dist/core/skills.d.ts.map +0 -1
  836. package/dist/core/skills.js.map +0 -1
  837. package/dist/core/slash-commands.d.ts.map +0 -1
  838. package/dist/core/slash-commands.js.map +0 -1
  839. package/dist/core/source-info.d.ts.map +0 -1
  840. package/dist/core/source-info.js.map +0 -1
  841. package/dist/core/system-prompt.d.ts.map +0 -1
  842. package/dist/core/system-prompt.js.map +0 -1
  843. package/dist/core/system-prompt.test.d.ts.map +0 -1
  844. package/dist/core/system-prompt.test.js.map +0 -1
  845. package/dist/core/telemetry.d.ts.map +0 -1
  846. package/dist/core/telemetry.js.map +0 -1
  847. package/dist/core/timings.d.ts.map +0 -1
  848. package/dist/core/timings.js.map +0 -1
  849. package/dist/core/tools/bash.d.ts.map +0 -1
  850. package/dist/core/tools/bash.js.map +0 -1
  851. package/dist/core/tools/edit-diff.d.ts.map +0 -1
  852. package/dist/core/tools/edit-diff.js.map +0 -1
  853. package/dist/core/tools/edit.d.ts.map +0 -1
  854. package/dist/core/tools/edit.js.map +0 -1
  855. package/dist/core/tools/file-mutation-queue.d.ts.map +0 -1
  856. package/dist/core/tools/file-mutation-queue.js.map +0 -1
  857. package/dist/core/tools/find.d.ts.map +0 -1
  858. package/dist/core/tools/find.js.map +0 -1
  859. package/dist/core/tools/grep.d.ts.map +0 -1
  860. package/dist/core/tools/grep.js.map +0 -1
  861. package/dist/core/tools/index.d.ts.map +0 -1
  862. package/dist/core/tools/index.js.map +0 -1
  863. package/dist/core/tools/ls.d.ts.map +0 -1
  864. package/dist/core/tools/ls.js.map +0 -1
  865. package/dist/core/tools/output-accumulator.d.ts.map +0 -1
  866. package/dist/core/tools/output-accumulator.js.map +0 -1
  867. package/dist/core/tools/path-utils.d.ts.map +0 -1
  868. package/dist/core/tools/path-utils.js.map +0 -1
  869. package/dist/core/tools/read.d.ts.map +0 -1
  870. package/dist/core/tools/read.js.map +0 -1
  871. package/dist/core/tools/render-utils.d.ts.map +0 -1
  872. package/dist/core/tools/render-utils.js.map +0 -1
  873. package/dist/core/tools/tool-definition-wrapper.d.ts.map +0 -1
  874. package/dist/core/tools/tool-definition-wrapper.js.map +0 -1
  875. package/dist/core/tools/truncate.d.ts.map +0 -1
  876. package/dist/core/tools/truncate.js.map +0 -1
  877. package/dist/core/tools/write.d.ts.map +0 -1
  878. package/dist/core/tools/write.js.map +0 -1
  879. package/dist/core/trust-manager.d.ts.map +0 -1
  880. package/dist/core/trust-manager.js.map +0 -1
  881. package/dist/core/usage-totals.d.ts.map +0 -1
  882. package/dist/core/usage-totals.js.map +0 -1
  883. package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  884. package/dist/extensions/pi-subagents/test/unit/slash-chain-groups.test.ts +0 -464
  885. package/dist/index.d.ts.map +0 -1
  886. package/dist/index.js.map +0 -1
  887. package/dist/main.d.ts.map +0 -1
  888. package/dist/main.js.map +0 -1
  889. package/dist/migrations.d.ts.map +0 -1
  890. package/dist/migrations.js.map +0 -1
  891. package/dist/modes/index.d.ts.map +0 -1
  892. package/dist/modes/index.js.map +0 -1
  893. package/dist/modes/interactive/components/armin.d.ts.map +0 -1
  894. package/dist/modes/interactive/components/armin.js.map +0 -1
  895. package/dist/modes/interactive/components/assistant-message.d.ts.map +0 -1
  896. package/dist/modes/interactive/components/assistant-message.js.map +0 -1
  897. package/dist/modes/interactive/components/bash-execution.d.ts.map +0 -1
  898. package/dist/modes/interactive/components/bash-execution.js.map +0 -1
  899. package/dist/modes/interactive/components/bordered-loader.d.ts.map +0 -1
  900. package/dist/modes/interactive/components/bordered-loader.js.map +0 -1
  901. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +0 -1
  902. package/dist/modes/interactive/components/branch-summary-message.js.map +0 -1
  903. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +0 -1
  904. package/dist/modes/interactive/components/compaction-summary-message.js.map +0 -1
  905. package/dist/modes/interactive/components/config-selector.d.ts.map +0 -1
  906. package/dist/modes/interactive/components/config-selector.js.map +0 -1
  907. package/dist/modes/interactive/components/countdown-timer.d.ts.map +0 -1
  908. package/dist/modes/interactive/components/countdown-timer.js.map +0 -1
  909. package/dist/modes/interactive/components/custom-editor.d.ts.map +0 -1
  910. package/dist/modes/interactive/components/custom-editor.js.map +0 -1
  911. package/dist/modes/interactive/components/custom-entry.d.ts.map +0 -1
  912. package/dist/modes/interactive/components/custom-entry.js.map +0 -1
  913. package/dist/modes/interactive/components/custom-message.d.ts.map +0 -1
  914. package/dist/modes/interactive/components/custom-message.js.map +0 -1
  915. package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
  916. package/dist/modes/interactive/components/daxnuts.js.map +0 -1
  917. package/dist/modes/interactive/components/diff.d.ts.map +0 -1
  918. package/dist/modes/interactive/components/diff.js.map +0 -1
  919. package/dist/modes/interactive/components/dynamic-border.d.ts.map +0 -1
  920. package/dist/modes/interactive/components/dynamic-border.js.map +0 -1
  921. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +0 -1
  922. package/dist/modes/interactive/components/earendil-announcement.js.map +0 -1
  923. package/dist/modes/interactive/components/extension-editor.d.ts.map +0 -1
  924. package/dist/modes/interactive/components/extension-editor.js.map +0 -1
  925. package/dist/modes/interactive/components/extension-input.d.ts.map +0 -1
  926. package/dist/modes/interactive/components/extension-input.js.map +0 -1
  927. package/dist/modes/interactive/components/extension-selector.d.ts.map +0 -1
  928. package/dist/modes/interactive/components/extension-selector.js.map +0 -1
  929. package/dist/modes/interactive/components/first-time-setup.d.ts.map +0 -1
  930. package/dist/modes/interactive/components/first-time-setup.js.map +0 -1
  931. package/dist/modes/interactive/components/footer.d.ts.map +0 -1
  932. package/dist/modes/interactive/components/footer.js.map +0 -1
  933. package/dist/modes/interactive/components/index.d.ts.map +0 -1
  934. package/dist/modes/interactive/components/index.js.map +0 -1
  935. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +0 -1
  936. package/dist/modes/interactive/components/keybinding-hints.js.map +0 -1
  937. package/dist/modes/interactive/components/login-dialog.d.ts.map +0 -1
  938. package/dist/modes/interactive/components/login-dialog.js.map +0 -1
  939. package/dist/modes/interactive/components/model-selector.d.ts.map +0 -1
  940. package/dist/modes/interactive/components/model-selector.js.map +0 -1
  941. package/dist/modes/interactive/components/oauth-selector.d.ts.map +0 -1
  942. package/dist/modes/interactive/components/oauth-selector.js.map +0 -1
  943. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +0 -1
  944. package/dist/modes/interactive/components/scoped-models-selector.js.map +0 -1
  945. package/dist/modes/interactive/components/session-selector-search.d.ts.map +0 -1
  946. package/dist/modes/interactive/components/session-selector-search.js.map +0 -1
  947. package/dist/modes/interactive/components/session-selector.d.ts.map +0 -1
  948. package/dist/modes/interactive/components/session-selector.js.map +0 -1
  949. package/dist/modes/interactive/components/settings-selector.d.ts.map +0 -1
  950. package/dist/modes/interactive/components/settings-selector.js.map +0 -1
  951. package/dist/modes/interactive/components/show-images-selector.d.ts.map +0 -1
  952. package/dist/modes/interactive/components/show-images-selector.js.map +0 -1
  953. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +0 -1
  954. package/dist/modes/interactive/components/skill-invocation-message.js.map +0 -1
  955. package/dist/modes/interactive/components/status-indicator.d.ts.map +0 -1
  956. package/dist/modes/interactive/components/status-indicator.js.map +0 -1
  957. package/dist/modes/interactive/components/theme-selector.d.ts.map +0 -1
  958. package/dist/modes/interactive/components/theme-selector.js.map +0 -1
  959. package/dist/modes/interactive/components/thinking-selector.d.ts.map +0 -1
  960. package/dist/modes/interactive/components/thinking-selector.js.map +0 -1
  961. package/dist/modes/interactive/components/tool-execution.d.ts.map +0 -1
  962. package/dist/modes/interactive/components/tool-execution.js.map +0 -1
  963. package/dist/modes/interactive/components/tree-selector.d.ts.map +0 -1
  964. package/dist/modes/interactive/components/tree-selector.js.map +0 -1
  965. package/dist/modes/interactive/components/trust-selector.d.ts.map +0 -1
  966. package/dist/modes/interactive/components/trust-selector.js.map +0 -1
  967. package/dist/modes/interactive/components/user-message-selector.d.ts.map +0 -1
  968. package/dist/modes/interactive/components/user-message-selector.js.map +0 -1
  969. package/dist/modes/interactive/components/user-message.d.ts.map +0 -1
  970. package/dist/modes/interactive/components/user-message.js.map +0 -1
  971. package/dist/modes/interactive/components/visual-truncate.d.ts.map +0 -1
  972. package/dist/modes/interactive/components/visual-truncate.js.map +0 -1
  973. package/dist/modes/interactive/external-editor.d.ts.map +0 -1
  974. package/dist/modes/interactive/external-editor.js.map +0 -1
  975. package/dist/modes/interactive/interactive-mode.d.ts.map +0 -1
  976. package/dist/modes/interactive/interactive-mode.js.map +0 -1
  977. package/dist/modes/interactive/model-search.d.ts.map +0 -1
  978. package/dist/modes/interactive/model-search.js.map +0 -1
  979. package/dist/modes/interactive/theme/theme-controller.d.ts.map +0 -1
  980. package/dist/modes/interactive/theme/theme-controller.js.map +0 -1
  981. package/dist/modes/interactive/theme/theme.d.ts.map +0 -1
  982. package/dist/modes/interactive/theme/theme.js.map +0 -1
  983. package/dist/modes/print-mode.d.ts.map +0 -1
  984. package/dist/modes/print-mode.js.map +0 -1
  985. package/dist/modes/rpc/jsonl.d.ts.map +0 -1
  986. package/dist/modes/rpc/jsonl.js.map +0 -1
  987. package/dist/modes/rpc/rpc-client.d.ts.map +0 -1
  988. package/dist/modes/rpc/rpc-client.js.map +0 -1
  989. package/dist/modes/rpc/rpc-mode.d.ts.map +0 -1
  990. package/dist/modes/rpc/rpc-mode.js.map +0 -1
  991. package/dist/modes/rpc/rpc-types.d.ts.map +0 -1
  992. package/dist/modes/rpc/rpc-types.js.map +0 -1
  993. package/dist/package-manager-cli.d.ts.map +0 -1
  994. package/dist/package-manager-cli.js.map +0 -1
  995. package/dist/rpc-entry.d.ts.map +0 -1
  996. package/dist/rpc-entry.js.map +0 -1
  997. package/dist/utils/ansi.d.ts.map +0 -1
  998. package/dist/utils/ansi.js.map +0 -1
  999. package/dist/utils/changelog.d.ts.map +0 -1
  1000. package/dist/utils/changelog.js.map +0 -1
  1001. package/dist/utils/child-process.d.ts.map +0 -1
  1002. package/dist/utils/child-process.js.map +0 -1
  1003. package/dist/utils/clipboard-image.d.ts.map +0 -1
  1004. package/dist/utils/clipboard-image.js.map +0 -1
  1005. package/dist/utils/clipboard-native.d.ts.map +0 -1
  1006. package/dist/utils/clipboard-native.js.map +0 -1
  1007. package/dist/utils/clipboard.d.ts.map +0 -1
  1008. package/dist/utils/clipboard.js.map +0 -1
  1009. package/dist/utils/deprecation.d.ts.map +0 -1
  1010. package/dist/utils/deprecation.js.map +0 -1
  1011. package/dist/utils/exif-orientation.d.ts.map +0 -1
  1012. package/dist/utils/exif-orientation.js.map +0 -1
  1013. package/dist/utils/frontmatter.d.ts.map +0 -1
  1014. package/dist/utils/frontmatter.js.map +0 -1
  1015. package/dist/utils/fs-watch.d.ts.map +0 -1
  1016. package/dist/utils/fs-watch.js.map +0 -1
  1017. package/dist/utils/git.d.ts.map +0 -1
  1018. package/dist/utils/git.js.map +0 -1
  1019. package/dist/utils/html.d.ts.map +0 -1
  1020. package/dist/utils/html.js.map +0 -1
  1021. package/dist/utils/image-convert.d.ts.map +0 -1
  1022. package/dist/utils/image-convert.js.map +0 -1
  1023. package/dist/utils/image-process.d.ts.map +0 -1
  1024. package/dist/utils/image-process.js.map +0 -1
  1025. package/dist/utils/image-resize-core.d.ts.map +0 -1
  1026. package/dist/utils/image-resize-core.js.map +0 -1
  1027. package/dist/utils/image-resize-worker.d.ts.map +0 -1
  1028. package/dist/utils/image-resize-worker.js.map +0 -1
  1029. package/dist/utils/image-resize.d.ts.map +0 -1
  1030. package/dist/utils/image-resize.js.map +0 -1
  1031. package/dist/utils/json.d.ts.map +0 -1
  1032. package/dist/utils/json.js.map +0 -1
  1033. package/dist/utils/mime.d.ts.map +0 -1
  1034. package/dist/utils/mime.js.map +0 -1
  1035. package/dist/utils/open-browser.d.ts.map +0 -1
  1036. package/dist/utils/open-browser.js.map +0 -1
  1037. package/dist/utils/paths.d.ts.map +0 -1
  1038. package/dist/utils/paths.js.map +0 -1
  1039. package/dist/utils/photon.d.ts.map +0 -1
  1040. package/dist/utils/photon.js.map +0 -1
  1041. package/dist/utils/pi-user-agent.d.ts.map +0 -1
  1042. package/dist/utils/pi-user-agent.js.map +0 -1
  1043. package/dist/utils/shell.d.ts.map +0 -1
  1044. package/dist/utils/shell.js.map +0 -1
  1045. package/dist/utils/sleep.d.ts.map +0 -1
  1046. package/dist/utils/sleep.js.map +0 -1
  1047. package/dist/utils/syntax-highlight.d.ts.map +0 -1
  1048. package/dist/utils/syntax-highlight.js.map +0 -1
  1049. package/dist/utils/thinking-tags.d.ts.map +0 -1
  1050. package/dist/utils/thinking-tags.js.map +0 -1
  1051. package/dist/utils/tools-manager.d.ts.map +0 -1
  1052. package/dist/utils/tools-manager.js.map +0 -1
  1053. package/dist/utils/version-check.d.ts.map +0 -1
  1054. package/dist/utils/version-check.js.map +0 -1
  1055. package/dist/utils/windows-self-update.d.ts.map +0 -1
  1056. package/dist/utils/windows-self-update.js.map +0 -1
@@ -13,6 +13,7 @@ import { describe, it, before, after, beforeEach, afterEach } from "node:test";
13
13
  import assert from "node:assert/strict";
14
14
  import * as fs from "node:fs";
15
15
  import * as path from "node:path";
16
+ import { execFileSync } from "node:child_process";
16
17
  import type { MockPi } from "../support/helpers.ts";
17
18
  import {
18
19
  createMockPi,
@@ -27,19 +28,14 @@ import {
27
28
  } from "../support/helpers.ts";
28
29
  import registerSubagentExtension from "../../src/extension/index.ts";
29
30
  import {
30
- SUBAGENT_DELEGATION_PROTOCOL_VERSION,
31
- SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
32
31
  SUBAGENT_DELEGATION_REQUEST_EVENT,
33
32
  SUBAGENT_DELEGATION_RESPONSE_EVENT,
34
33
  SUBAGENT_DELEGATION_STARTED_EVENT,
35
- SUBAGENT_DELEGATION_UPDATE_EVENT,
34
+ type SubagentDelegationRequest,
36
35
  type SubagentDelegationResponse,
37
- type SubagentDelegationUpdate,
38
- type SubagentDelegationV2Request,
39
- type SubagentDelegationV2Response,
40
- type SubagentDelegationV2Started,
36
+ type SubagentDelegationStarted,
41
37
  } from "../../src/api/delegation.ts";
42
- import { INTERCOM_DETACH_REQUEST_EVENT, INTERCOM_DETACH_RESPONSE_EVENT, type SubagentState } from "../../src/shared/types.ts";
38
+ import { CHAIN_RUNS_DIR, DIRS, INTERCOM_DETACH_REQUEST_EVENT, INTERCOM_DETACH_RESPONSE_EVENT, type SubagentState } from "../../src/shared/types.ts";
43
39
  import { CHILD_WATCHDOG_STATUS_EVENT } from "../../src/watchdog/child-status.ts";
44
40
  import { WAIT_TOOL_ENABLED_ENV } from "../../src/runs/background/wait-config.ts";
45
41
  import { TOOL_BUDGET_ENV, TOOL_BUDGET_ZERO_AUTH_ENV } from "../../src/runs/shared/tool-budget.ts";
@@ -49,9 +45,11 @@ import {
49
45
  SUBAGENT_FANOUT_CHILD_ENV,
50
46
  SUBAGENT_PARENT_CHILD_INDEX_ENV,
51
47
  SUBAGENT_PARENT_CONTROL_INBOX_ENV,
48
+ SUBAGENT_PARENT_DEPTH_ENV,
52
49
  SUBAGENT_PARENT_EVENT_SINK_ENV,
53
50
  SUBAGENT_PARENT_RUN_ID_ENV,
54
51
  } from "../../src/runs/shared/pi-args.ts";
52
+ import { createNestedRoute, nestedRouteEnv, parseNestedEventRecords } from "../../src/runs/shared/nested-events.ts";
55
53
 
56
54
  interface ModelAttempt {
57
55
  success?: boolean;
@@ -324,6 +322,7 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
324
322
  initialSpawnState?: NonNullable<SubagentState["subagentSpawns"]>,
325
323
  allowMutatingManagementActions = true,
326
324
  initialAsyncJobs: SubagentState["asyncJobs"] = new Map(),
325
+ workflowControllers?: Map<string, AbortController>,
327
326
  ) {
328
327
  return createSubagentExecutor!({
329
328
  pi: { events: createEventBus(), getSessionName: () => undefined },
@@ -332,13 +331,14 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
332
331
  currentSessionId: initialSpawnState?.sessionId ?? null,
333
332
  ...(initialSpawnState ? { subagentSpawns: initialSpawnState } : {}),
334
333
  asyncJobs: initialAsyncJobs,
334
+ ...(workflowControllers ? { workflowControllers } : {}),
335
335
  foregroundControls: new Map(),
336
336
  lastForegroundControlId: null,
337
337
  },
338
338
  config,
339
339
  asyncByDefault,
340
340
  tempArtifactsDir: tempDir,
341
- getSubagentSessionRoot: () => tempDir,
341
+ getSubagentSessionRoot: () => path.join(tempDir, ".pi-subagents", "sessions"),
342
342
  expandTilde: (value: string) => value,
343
343
  discoverAgents: () => ({ agents }),
344
344
  allowMutatingManagementActions,
@@ -374,11 +374,421 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
374
374
  );
375
375
 
376
376
  assert.equal(result.isError, undefined);
377
- assert.match(result.content[0]?.text ?? "", /Output saved to: /);
378
- assert.doesNotMatch(result.content[0]?.text ?? "", /single alias finished/);
377
+ assert.match(result.content[0]?.text ?? "", /single alias finished/);
378
+ });
379
+
380
+ it("starts workflow scripts asynchronously by default and persists live status", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
381
+ mockPi.onCall({ output: "async workflow child" });
382
+ const executor = makeExecutor([makeAgent("echo")]);
383
+ const runId = `scripted-workflow-async-${Date.now()}`;
384
+
385
+ const result = await executor.execute(
386
+ runId,
387
+ { workflowScript: `emit("starting"); await runs.run("work", { agent: "echo", task: "Async work" }); return { answer: 42 };` },
388
+ new AbortController().signal,
389
+ undefined,
390
+ makeMinimalCtx(tempDir),
391
+ );
392
+
393
+ assert.equal(result.isError, undefined);
394
+ assert.equal(result.details.mode, "workflow");
395
+ assert.equal(result.details.asyncId, runId);
396
+ assert.match(result.content[0]?.text ?? "", /Async workflow/);
397
+ const statusPath = path.join(result.details.asyncDir!, "status.json");
398
+ let status: { state?: string; workflow?: { value?: unknown; emits?: unknown[]; trace?: Array<{ key?: string; state?: string }> } } = {};
399
+ for (let attempt = 0; attempt < 100; attempt++) {
400
+ status = JSON.parse(fs.readFileSync(statusPath, "utf-8"));
401
+ if (status.state === "complete" || status.state === "failed") break;
402
+ await new Promise((resolve) => setTimeout(resolve, 20));
403
+ }
404
+ assert.equal(status.state, "complete");
405
+ assert.deepEqual(status.workflow?.value, { answer: 42 });
406
+ assert.deepEqual(status.workflow?.emits, ["starting"]);
407
+ assert.ok(status.workflow?.trace?.some((entry) => entry.key === "work" && entry.state === "completed"));
408
+ const persistedResult = JSON.parse(fs.readFileSync(path.join(DIRS.results, `${runId}.json`), "utf-8")) as { agent?: string; summary?: string; workflow?: { value?: unknown } };
409
+ assert.equal(persistedResult.agent, "workflow");
410
+ assert.match(persistedResult.summary ?? "", /Return: \{\n "answer": 42\n\}/);
411
+ assert.deepEqual(persistedResult.workflow?.value, { answer: 42 });
412
+ fs.rmSync(result.details.asyncDir!, { recursive: true, force: true });
413
+ fs.rmSync(path.join(DIRS.results, `${runId}.json`), { force: true });
414
+ });
415
+
416
+ it("rejects an invalid async workflow usage budget before creating run state", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
417
+ const asyncJobs: SubagentState["asyncJobs"] = new Map();
418
+ const executor = makeExecutor([makeAgent("echo")], {}, false, undefined, true, asyncJobs);
419
+ const runId = `scripted-workflow-invalid-budget-${Date.now()}`;
420
+
421
+ const result = await executor.execute(
422
+ runId,
423
+ { workflowScript: `return "unreachable";`, usageBudget: { tokens: { hard: 0 } } },
424
+ new AbortController().signal,
425
+ undefined,
426
+ makeMinimalCtx(tempDir),
427
+ );
428
+
429
+ assert.equal(result.isError, true);
430
+ assert.match(result.content[0]?.text ?? "", /usageBudget\.tokens\.hard must be a positive number/);
431
+ assert.equal(result.details.asyncId, undefined);
432
+ assert.equal(asyncJobs.has(runId), false);
433
+ assert.equal(fs.existsSync(path.join(DIRS.async, runId)), false);
434
+ assert.equal(fs.existsSync(path.join(DIRS.results, `${runId}.json`)), false);
435
+ });
436
+
437
+ it("rejects async child launches from budgeted async workflows", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
438
+ const executor = makeExecutor([makeAgent("echo")]);
439
+ const runId = `scripted-workflow-budget-async-child-${Date.now()}`;
440
+ const started = await executor.execute(
441
+ runId,
442
+ {
443
+ workflowScript: `await runs.run("background", { agent: "echo", task: "Async child", async: true }); return "unreachable";`,
444
+ usageBudget: { tokens: { hard: 100 } },
445
+ },
446
+ new AbortController().signal,
447
+ undefined,
448
+ makeMinimalCtx(tempDir),
449
+ );
450
+
451
+ assert.equal(started.isError, undefined);
452
+ assert.equal(started.details.asyncId, runId);
453
+ const resultPath = path.join(DIRS.results, `${runId}.json`);
454
+ let persisted: { state?: string; summary?: string; results?: Array<{ success?: boolean; output?: string }> } = {};
455
+ for (let attempt = 0; attempt < 100; attempt++) {
456
+ if (fs.existsSync(resultPath)) persisted = JSON.parse(fs.readFileSync(resultPath, "utf-8"));
457
+ if (persisted.state === "failed") break;
458
+ await new Promise((resolve) => setTimeout(resolve, 20));
459
+ }
460
+ assert.equal(persisted.state, "failed");
461
+ assert.match(persisted.summary ?? "", /workflow usageBudget does not support async runs\.run launches/);
462
+ assert.equal(persisted.results?.length, 1);
463
+ assert.equal(persisted.results?.[0]?.success, false);
464
+ assert.match(persisted.results?.[0]?.output ?? "", /workflow usageBudget does not support async runs\.run launches/);
465
+ assert.equal(mockPi.callCount(), 0);
466
+ fs.rmSync(started.details.asyncDir!, { recursive: true, force: true });
467
+ fs.rmSync(resultPath, { force: true });
468
+ });
469
+
470
+ it("persists workflow parent metadata in an async worktree child status and result", { skip: !createSubagentExecutor || process.platform === "win32" ? "executor unavailable or worktree paths differ on Windows" : undefined }, async () => {
471
+ execFileSync("git", ["init"], { cwd: tempDir, stdio: "ignore" });
472
+ execFileSync("git", ["config", "user.email", "test@example.com"], { cwd: tempDir });
473
+ execFileSync("git", ["config", "user.name", "Test User"], { cwd: tempDir });
474
+ fs.writeFileSync(path.join(tempDir, "base.txt"), "base\n", "utf-8");
475
+ execFileSync("git", ["add", "base.txt"], { cwd: tempDir });
476
+ execFileSync("git", ["commit", "-m", "base"], { cwd: tempDir, stdio: "ignore" });
477
+ mockPi.onCall({ output: "async child done" });
478
+ const executor = makeExecutor([makeAgent("echo")]);
479
+ const workflowRunId = `scripted-workflow-parent-${Date.now()}`;
480
+ const started = await executor.execute(
481
+ workflowRunId,
482
+ { workflowScript: `const child = await runs.run("background", { agent: "echo", task: "Async child", async: true, worktree: true }); return child.runId;` },
483
+ new AbortController().signal,
484
+ undefined,
485
+ makeMinimalCtx(tempDir),
486
+ );
487
+ const workflowResultPath = path.join(DIRS.results, `${workflowRunId}.json`);
488
+ let childRunId: string | undefined;
489
+ for (let attempt = 0; attempt < 150; attempt++) {
490
+ if (fs.existsSync(workflowResultPath)) {
491
+ const workflowResult = JSON.parse(fs.readFileSync(workflowResultPath, "utf-8")) as { workflow?: { value?: unknown } };
492
+ if (typeof workflowResult.workflow?.value === "string") { childRunId = workflowResult.workflow.value; break; }
493
+ }
494
+ await new Promise((resolve) => setTimeout(resolve, 20));
495
+ }
496
+ assert.ok(childRunId);
497
+ const childDir = path.join(DIRS.async, childRunId);
498
+ const childStatusPath = path.join(childDir, "status.json");
499
+ let childStatus: { state?: string; mode?: string; parentWorkflowRunId?: string; workflowKey?: string; parallelHandoff?: { path?: string } } = {};
500
+ for (let attempt = 0; attempt < 200; attempt++) {
501
+ if (fs.existsSync(childStatusPath)) childStatus = JSON.parse(fs.readFileSync(childStatusPath, "utf-8"));
502
+ if (["complete", "failed", "stopped"].includes(childStatus.state ?? "")) break;
503
+ await new Promise((resolve) => setTimeout(resolve, 20));
504
+ }
505
+ assert.equal(childStatus.mode, "parallel");
506
+ assert.equal(childStatus.parentWorkflowRunId, workflowRunId);
507
+ assert.equal(childStatus.workflowKey, "background");
508
+ assert.equal(typeof childStatus.parallelHandoff?.path, "string");
509
+ const childResultPath = path.join(DIRS.results, `${childRunId}.json`);
510
+ for (let attempt = 0; attempt < 200 && !fs.existsSync(childResultPath); attempt++) {
511
+ await new Promise((resolve) => setTimeout(resolve, 20));
512
+ }
513
+ const childResult = JSON.parse(fs.readFileSync(childResultPath, "utf-8")) as { parentWorkflowRunId?: string; workflowKey?: string };
514
+ assert.equal(childResult.parentWorkflowRunId, workflowRunId);
515
+ assert.equal(childResult.workflowKey, "background");
516
+ fs.rmSync(started.details.asyncDir!, { recursive: true, force: true });
517
+ fs.rmSync(workflowResultPath, { force: true });
518
+ fs.rmSync(childDir, { recursive: true, force: true });
519
+ fs.rmSync(path.join(DIRS.results, `${childRunId}.json`), { force: true });
520
+ });
521
+
522
+ it("stops a live async workflow through its controller", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
523
+ const controller = new AbortController();
524
+ const executor = makeExecutor([makeAgent("echo")], {}, false, undefined, true, new Map(), new Map([["workflow-stop", controller]]));
525
+ const result = await executor.execute(
526
+ "stop-call",
527
+ { action: "stop", id: "workflow-stop" },
528
+ new AbortController().signal,
529
+ undefined,
530
+ makeMinimalCtx(tempDir),
531
+ );
532
+ assert.equal(result.isError, undefined);
533
+ assert.equal(controller.signal.aborted, true);
534
+ assert.match(result.content[0]?.text ?? "", /Stop requested for async workflow workflow-stop/);
535
+ });
536
+
537
+ it("reports completed async workflows as not running when stopped after completion", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
538
+ const runId = `workflow-stop-complete-${Date.now()}`;
539
+ const asyncDir = path.join(DIRS.async, runId);
540
+ fs.mkdirSync(asyncDir, { recursive: true });
541
+ fs.writeFileSync(path.join(asyncDir, "status.json"), JSON.stringify({
542
+ runId,
543
+ sessionId: "session-123",
544
+ mode: "workflow",
545
+ state: "complete",
546
+ startedAt: Date.now(),
547
+ lastUpdate: Date.now(),
548
+ cwd: tempDir,
549
+ pid: process.pid,
550
+ }), "utf-8");
551
+ const asyncJobs: SubagentState["asyncJobs"] = new Map([[runId, {
552
+ asyncId: runId,
553
+ asyncDir,
554
+ cwd: tempDir,
555
+ status: "complete",
556
+ mode: "workflow",
557
+ agents: [],
558
+ steps: [],
559
+ startedAt: Date.now(),
560
+ updatedAt: Date.now(),
561
+ }]]);
562
+ const executor = makeExecutor([makeAgent("echo")], {}, false, undefined, true, asyncJobs);
563
+
564
+ const result = await executor.execute(
565
+ "stop-completed-workflow",
566
+ { action: "stop", id: runId },
567
+ new AbortController().signal,
568
+ undefined,
569
+ makeMinimalCtx(tempDir),
570
+ );
571
+
572
+ assert.equal(result.isError, true);
573
+ assert.match(result.content[0]?.text ?? "", /No running or queued async run was found/);
574
+ assert.doesNotMatch(result.content[0]?.text ?? "", /reload recovery/);
575
+ fs.rmSync(asyncDir, { recursive: true, force: true });
379
576
  });
380
577
 
381
- it("admits a zero run-level tool budget only for marked v2 delegated execution", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
578
+ it("routes workflow script children through ordinary foreground execution", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
579
+ mockPi.onCall({ output: "scanned auth" });
580
+ mockPi.onCall({ output: "reviewed auth" });
581
+ const executor = makeExecutor([makeAgent("echo")]);
582
+
583
+ const result = await executor.execute(
584
+ "scripted-workflow",
585
+ {
586
+ async: false,
587
+ workflowScript: `
588
+ const scan = await runs.run("scan", { agent: "echo", task: "Scan auth" });
589
+ const review = await runs.run("review", { agent: "echo", task: "Review: " + scan.output });
590
+ return review.output;
591
+ `,
592
+ },
593
+ new AbortController().signal,
594
+ undefined,
595
+ makeMinimalCtx(tempDir),
596
+ );
597
+
598
+ assert.equal(result.isError, undefined);
599
+ assert.match(result.content[0]?.text ?? "", /reviewed auth/);
600
+ assert.equal(result.details.mode, "workflow");
601
+ assert.equal(result.details.results.length, 2);
602
+ assert.deepEqual(result.details.workflow?.trace.filter((entry) => entry.state === "completed").map((entry) => entry.key), ["scan", "review"]);
603
+ });
604
+
605
+ it("runs a direct single child in a managed worktree", { skip: !createSubagentExecutor || process.platform === "win32" ? "executor unavailable or worktree paths differ on Windows" : undefined }, async () => {
606
+ execFileSync("git", ["init"], { cwd: tempDir, stdio: "ignore" });
607
+ execFileSync("git", ["config", "user.email", "test@example.com"], { cwd: tempDir });
608
+ execFileSync("git", ["config", "user.name", "Test User"], { cwd: tempDir });
609
+ fs.writeFileSync(path.join(tempDir, "base.txt"), "base\n", "utf-8");
610
+ execFileSync("git", ["add", "base.txt"], { cwd: tempDir });
611
+ execFileSync("git", ["commit", "-m", "base"], { cwd: tempDir, stdio: "ignore" });
612
+ mockPi.onCall({ output: "isolated feature", writeFiles: [{ path: "feature.txt", content: "feature\n" }] });
613
+ const executor = makeExecutor([makeAgent("builder")]);
614
+
615
+ const result = await executor.execute(
616
+ "direct-worktree",
617
+ { async: false, agent: "builder", task: "Implement feature", worktree: true },
618
+ new AbortController().signal,
619
+ undefined,
620
+ makeMinimalCtx(tempDir),
621
+ );
622
+
623
+ assert.equal(result.isError, undefined);
624
+ assert.equal(mockPi.callCount(), 1);
625
+ assert.equal(fs.existsSync(path.join(tempDir, "feature.txt")), false);
626
+ const handoffPath = (result.content[0]?.text ?? "").match(/([^\s]+\/handoffs\/[^\s]+\.json)/)?.[1];
627
+ assert.ok(handoffPath, result.content[0]?.text);
628
+ const handoff = JSON.parse(fs.readFileSync(handoffPath, "utf-8")) as {
629
+ groups: Array<{
630
+ cleanup: { state: string; tasks: Array<{ worktreeRemoved: boolean }> };
631
+ }>;
632
+ };
633
+ assert.equal(handoff.groups[0]?.cleanup.state, "complete");
634
+ assert.equal(handoff.groups[0]?.cleanup.tasks[0]?.worktreeRemoved, true);
635
+
636
+ });
637
+
638
+ it("lets runs.all siblings settle when one child fails", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
639
+ mockPi.onCall({ exitCode: 1, stderr: "first child failed" });
640
+ mockPi.onCall({ output: "second child completed" });
641
+ const executor = makeExecutor([makeAgent("echo")]);
642
+
643
+ const result = await executor.execute(
644
+ "scripted-workflow-settlement",
645
+ {
646
+ async: false,
647
+ workflowScript: `
648
+ const children = await runs.all([
649
+ { key: "first", agent: "echo", task: "First task" },
650
+ { key: "second", agent: "echo", task: "Second task" }
651
+ ]);
652
+ return children.map(({ key, ok, error }) => error === undefined ? { key, ok } : { key, ok, error });
653
+ `,
654
+ },
655
+ new AbortController().signal,
656
+ undefined,
657
+ makeMinimalCtx(tempDir),
658
+ );
659
+
660
+ assert.equal(result.isError, undefined, result.content[0]?.text ?? "workflow failed");
661
+ assert.equal(mockPi.callCount(), 2);
662
+ const value = result.details.workflow?.value as Array<{ key: string; ok: boolean; error?: string }>;
663
+ assert.deepEqual(value.map(({ key }) => key), ["first", "second"]);
664
+ assert.deepEqual(value.map(({ ok }) => ok).sort(), [false, true]);
665
+ const failed = value.find(({ ok }) => !ok);
666
+ const succeeded = value.find(({ ok }) => ok);
667
+ assert.match(failed?.error ?? "", /first child failed/);
668
+ assert.equal(succeeded?.error, undefined);
669
+ assert.deepEqual(result.details.workflow?.trace.filter((entry) => entry.state !== "started").map(({ state }) => state).sort(), ["completed", "failed"]);
670
+ });
671
+
672
+ it("gives parallel workflow children separate managed worktrees and durable handoffs", { skip: !createSubagentExecutor || process.platform === "win32" ? "executor unavailable or worktree paths differ on Windows" : undefined }, async () => {
673
+ execFileSync("git", ["init"], { cwd: tempDir, stdio: "ignore" });
674
+ execFileSync("git", ["config", "user.email", "test@example.com"], { cwd: tempDir });
675
+ execFileSync("git", ["config", "user.name", "Test User"], { cwd: tempDir });
676
+ fs.writeFileSync(path.join(tempDir, "base.txt"), "base\n", "utf-8");
677
+ execFileSync("git", ["add", "base.txt"], { cwd: tempDir });
678
+ execFileSync("git", ["commit", "-m", "base"], { cwd: tempDir, stdio: "ignore" });
679
+ mockPi.onCall({ output: "feature a", writeFiles: [{ path: "feature-a.txt", content: "a\n" }] });
680
+ mockPi.onCall({ output: "feature b", writeFiles: [{ path: "feature-b.txt", content: "b\n" }] });
681
+ const executor = makeExecutor([makeAgent("builder")]);
682
+
683
+ const result = await executor.execute(
684
+ "scripted-workflow-worktrees",
685
+ {
686
+ async: false,
687
+ workflowScript: `
688
+ const children = await runs.all([
689
+ { key: "feature-a", agent: "builder", task: "Implement A", worktree: true },
690
+ { key: "feature-b", agent: "builder", task: "Implement B", worktree: true }
691
+ ]);
692
+ return children.map(({ key, artifactPaths }) => ({ key, artifactPaths }));
693
+ `,
694
+ },
695
+ new AbortController().signal,
696
+ undefined,
697
+ makeMinimalCtx(tempDir),
698
+ );
699
+
700
+ assert.equal(result.isError, undefined);
701
+ assert.equal(mockPi.callCount(), 2, result.content[0]?.text ?? "workflow produced no output");
702
+ assert.equal(fs.existsSync(path.join(tempDir, "feature-a.txt")), false);
703
+ assert.equal(fs.existsSync(path.join(tempDir, "feature-b.txt")), false);
704
+ const output = result.content[0]?.text ?? "";
705
+ const handoffPaths = [...output.matchAll(/"([^"\n]*\/handoffs\/[^"\n]+\.json)"/g)].map((match) => match[1]!);
706
+ assert.equal(handoffPaths.length, 2, output);
707
+ const worktreePaths = new Set<string>();
708
+ for (const handoffPath of handoffPaths) {
709
+ const handoff = JSON.parse(fs.readFileSync(handoffPath, "utf-8")) as {
710
+ groups: Array<{
711
+ children: Array<{ patch: { changed: boolean; path: string } }>;
712
+ cleanup: { state: string; tasks: Array<{ path: string; worktreeRemoved: boolean; branchRemoved: boolean }> };
713
+ }>;
714
+ };
715
+ assert.equal(handoff.groups.length, 1);
716
+ assert.equal(handoff.groups[0]?.children.length, 1);
717
+ assert.equal(handoff.groups[0]?.children[0]?.patch.changed, true);
718
+ assert.equal(fs.existsSync(handoff.groups[0]!.children[0]!.patch.path), true);
719
+ assert.equal(handoff.groups[0]?.cleanup.state, "complete");
720
+ assert.equal(handoff.groups[0]?.cleanup.tasks[0]?.worktreeRemoved, true);
721
+ assert.equal(handoff.groups[0]?.cleanup.tasks[0]?.branchRemoved, true);
722
+ worktreePaths.add(handoff.groups[0]!.cleanup.tasks[0]!.path);
723
+ }
724
+ assert.equal(worktreePaths.size, 2);
725
+ for (const worktreePath of worktreePaths) assert.equal(fs.existsSync(worktreePath), false);
726
+ assert.match(result.content[0]?.text ?? "", /handoffs/);
727
+ });
728
+
729
+ it("inherits workflow-level worktree isolation and allows a child opt-out", { skip: !createSubagentExecutor || process.platform === "win32" ? "executor unavailable or worktree paths differ on Windows" : undefined }, async () => {
730
+ execFileSync("git", ["init"], { cwd: tempDir, stdio: "ignore" });
731
+ execFileSync("git", ["config", "user.email", "test@example.com"], { cwd: tempDir });
732
+ execFileSync("git", ["config", "user.name", "Test User"], { cwd: tempDir });
733
+ fs.writeFileSync(path.join(tempDir, "base.txt"), "base\n", "utf-8");
734
+ execFileSync("git", ["add", "base.txt"], { cwd: tempDir });
735
+ execFileSync("git", ["commit", "-m", "base"], { cwd: tempDir, stdio: "ignore" });
736
+ mockPi.onCall({ output: "isolated", writeFiles: [{ path: "isolated.txt", content: "isolated\n" }] });
737
+ mockPi.onCall({ output: "shared", writeFiles: [{ path: "shared.txt", content: "shared\n" }] });
738
+ const executor = makeExecutor([makeAgent("builder")]);
739
+
740
+ const result = await executor.execute(
741
+ "scripted-workflow-worktree-default",
742
+ {
743
+ async: false,
744
+ worktree: true,
745
+ workflowScript: `
746
+ const isolated = await runs.run("isolated", { agent: "builder", task: "Isolated" });
747
+ const shared = await runs.run("shared", { agent: "builder", task: "Shared", worktree: false });
748
+ return { isolated: isolated.artifactPaths, shared: shared.artifactPaths };
749
+ `,
750
+ },
751
+ new AbortController().signal,
752
+ undefined,
753
+ makeMinimalCtx(tempDir),
754
+ );
755
+
756
+ assert.equal(result.isError, undefined, result.content[0]?.text ?? "workflow failed");
757
+ assert.equal(fs.existsSync(path.join(tempDir, "isolated.txt")), false);
758
+ assert.equal(fs.readFileSync(path.join(tempDir, "shared.txt"), "utf-8"), "shared\n");
759
+ const output = result.content[0]?.text ?? "";
760
+ const handoffPaths = [...output.matchAll(/"([^"\n]*\/handoffs\/[^"\n]+\.json)"/g)].map((match) => match[1]!);
761
+ assert.equal(handoffPaths.length, 1, output);
762
+ assert.equal(fs.existsSync(handoffPaths[0]!), true);
763
+ });
764
+
765
+ it("applies a workflow usage budget across scripted child launches", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
766
+ mockPi.onCall({ output: "first result" });
767
+ const executor = makeExecutor([makeAgent("echo")]);
768
+
769
+ const result = await executor.execute(
770
+ "scripted-workflow-usage-budget",
771
+ {
772
+ async: false,
773
+ workflowScript: `
774
+ await runs.run("first", { agent: "echo", task: "First task" });
775
+ await runs.run("second", { agent: "echo", task: "Second task" });
776
+ `,
777
+ usageBudget: { tokens: { hard: 10 } },
778
+ },
779
+ new AbortController().signal,
780
+ undefined,
781
+ makeMinimalCtx(tempDir),
782
+ );
783
+
784
+ assert.equal(result.isError, true);
785
+ assert.match(result.content[0]?.text ?? "", /Usage budget exhausted/);
786
+ assert.equal(result.details.mode, "workflow");
787
+ assert.equal(mockPi.callCount(), 1);
788
+ assert.equal(result.details.usageBudget?.exhausted, true);
789
+ });
790
+
791
+ it("admits a zero run-level tool budget only for marked structured delegated execution", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
382
792
  const zeroBudget = { hard: 0, block: "*" as const };
383
793
  const params = { agent: "echo", task: "Answer without tools", toolBudget: zeroBudget };
384
794
  const ctx = makeMinimalCtx(tempDir);
@@ -394,32 +804,27 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
394
804
  assert.equal(ordinary.isError, true);
395
805
  assert.match(ordinary.content[0]?.text ?? "", /toolBudget\.hard must be an integer >= 1/);
396
806
 
397
- const v1Delegated = await executor.executeDelegated(
398
- "v1-delegated-zero-budget",
807
+ const unmarkedDelegated = await executor.executeDelegated(
808
+ "unmarked-delegated-zero-budget",
399
809
  params,
400
810
  new AbortController().signal,
401
811
  undefined,
402
812
  ctx,
403
813
  );
404
- assert.equal(v1Delegated.isError, true);
405
- assert.match(v1Delegated.content[0]?.text ?? "", /toolBudget\.hard must be an integer >= 1/);
814
+ assert.equal(unmarkedDelegated.isError, true);
815
+ assert.match(unmarkedDelegated.content[0]?.text ?? "", /toolBudget\.hard must be an integer >= 1/);
406
816
 
407
817
  mockPi.onCall({ echoEnv: [TOOL_BUDGET_ENV, TOOL_BUDGET_ZERO_AUTH_ENV] });
408
- const v2Delegated = await executor.executeDelegated(
409
- "v2-delegated-zero-budget",
818
+ const structuredDelegated = await executor.executeDelegated(
819
+ "structured-delegated-zero-budget",
410
820
  { ...params, delegatedAllowZeroToolBudget: true },
411
821
  new AbortController().signal,
412
822
  undefined,
413
823
  ctx,
414
824
  );
415
- assert.equal(v2Delegated.isError, undefined);
416
- // Reference-first delegated completion: the full echoed env snapshot is
417
- // persisted to the generated result file; the content is the reference.
418
- const delegatedOutputsDir = path.join(tempDir, ".pi-subagents", "artifacts", "outputs");
419
- const delegatedRunDirs = fs.readdirSync(delegatedOutputsDir);
420
- assert.equal(delegatedRunDirs.length, 1);
421
- const persistedEnv = fs.readFileSync(path.join(delegatedOutputsDir, delegatedRunDirs[0]!, "result.md"), "utf-8");
422
- const env = JSON.parse(persistedEnv) as Record<string, string>;
825
+ assert.equal(structuredDelegated.isError, undefined);
826
+ assert.deepEqual(structuredDelegated.details.toolBudget, zeroBudget);
827
+ const env = JSON.parse(structuredDelegated.content[0]?.text ?? "{}") as Record<string, string>;
423
828
  assert.deepEqual(JSON.parse(env[TOOL_BUDGET_ENV] ?? "null"), zeroBudget);
424
829
  assert.equal(env[TOOL_BUDGET_ZERO_AUTH_ENV], "1");
425
830
  assert.equal(mockPi.callCount(), 1);
@@ -461,6 +866,29 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
461
866
  assert.equal(mockPi.callCount(), 0);
462
867
  });
463
868
 
869
+ it("rejects invalid verified acceptance before spawning", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
870
+ const executor = makeExecutor([makeAgent("echo")]);
871
+ const invalidPolicies = [
872
+ "verified",
873
+ { level: "verified" },
874
+ { level: "verified", verify: [] },
875
+ ] as const;
876
+
877
+ for (const [index, acceptance] of invalidPolicies.entries()) {
878
+ const result = await executor.execute(
879
+ `invalid-verified-acceptance-${index}`,
880
+ { agent: "echo", task: "Do work", acceptance: acceptance as never },
881
+ new AbortController().signal,
882
+ undefined,
883
+ makeMinimalCtx(tempDir),
884
+ );
885
+
886
+ assert.equal(result.isError, true);
887
+ assert.match(result.content[0]?.text ?? "", /(?:verified.*object form|verify.*at least one command)/i);
888
+ }
889
+ assert.equal(mockPi.callCount(), 0);
890
+ });
891
+
464
892
  it("rejects unknown action strings at runtime", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
465
893
  const executor = makeExecutor([makeAgent("echo")]);
466
894
 
@@ -547,101 +975,7 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
547
975
  assert.equal(mockPi.callCount(), 2);
548
976
  });
549
977
 
550
- it("routes registered strict v1 delegation through the concurrent executor", async () => {
551
- mockPi.onCall({
552
- steps: [
553
- { jsonl: [events.toolStart("read", { path: "package.json" })], delay: 20 },
554
- { jsonl: [events.toolEnd("read"), events.toolResult("read", "{}")], delay: 20 },
555
- { jsonl: [events.assistantMessage("registered first delegated call")] },
556
- ],
557
- });
558
- mockPi.onCall({ output: "registered second delegated call", delay: 100 });
559
- const extensionEvents = createEventBus();
560
- const runtimeHandlers = new Map<string, Array<(event: unknown, ctx: ReturnType<typeof makeMinimalCtx>) => void>>();
561
- const fakePi = new Proxy({
562
- events: extensionEvents,
563
- on(event: string, handler: (event: unknown, ctx: ReturnType<typeof makeMinimalCtx>) => void) {
564
- const handlers = runtimeHandlers.get(event) ?? [];
565
- handlers.push(handler);
566
- runtimeHandlers.set(event, handlers);
567
- return () => runtimeHandlers.set(event, (runtimeHandlers.get(event) ?? []).filter((entry) => entry !== handler));
568
- },
569
- registerTool() {},
570
- registerCommand() {},
571
- registerShortcut() {},
572
- registerMessageRenderer() {},
573
- sendMessage() {},
574
- getSessionName() { return undefined; },
575
- }, {
576
- get(target, prop) {
577
- if (prop in target) return target[prop as keyof typeof target];
578
- return () => undefined;
579
- },
580
- });
581
- const ctx = {
582
- ...makeMinimalCtx(tempDir),
583
- sessionManager: {
584
- getSessionId: () => "registered-delegation-session",
585
- getSessionFile: () => path.join(tempDir, "registered-delegation-session.jsonl"),
586
- getEntries: () => [],
587
- },
588
- };
589
- const responses: SubagentDelegationResponse[] = [];
590
- const updates: SubagentDelegationUpdate[] = [];
591
- extensionEvents.on(SUBAGENT_DELEGATION_RESPONSE_EVENT, (payload) => responses.push(payload as SubagentDelegationResponse));
592
- extensionEvents.on(SUBAGENT_DELEGATION_UPDATE_EVENT, (payload) => updates.push(payload as SubagentDelegationUpdate));
593
-
594
- try {
595
- registerSubagentExtension(fakePi as never);
596
- for (const handler of runtimeHandlers.get("session_start") ?? []) {
597
- await handler({ reason: "startup" }, ctx);
598
- }
599
- extensionEvents.emit(SUBAGENT_DELEGATION_REQUEST_EVENT, {
600
- version: SUBAGENT_DELEGATION_PROTOCOL_VERSION,
601
- requestId: "registered-a",
602
- agent: "builder",
603
- task: "First registered delegated call",
604
- context: "fresh",
605
- cwd: tempDir,
606
- agentContract: { version: 1 },
607
- });
608
- extensionEvents.emit(SUBAGENT_DELEGATION_REQUEST_EVENT, {
609
- version: SUBAGENT_DELEGATION_PROTOCOL_VERSION,
610
- requestId: "registered-b",
611
- agent: "commentator",
612
- task: "Second registered delegated call",
613
- context: "fresh",
614
- cwd: tempDir,
615
- agentContract: { version: 1 },
616
- });
617
-
618
- const callDeadlineAt = Date.now() + 30_000;
619
- while (mockPi.callCount() < 2 && Date.now() < callDeadlineAt) {
620
- await new Promise((resolve) => setTimeout(resolve, 20));
621
- }
622
- assert.equal(mockPi.callCount(), 2, "registered strict v1 requests should bypass the ordinary one-call guard");
623
-
624
- const responseDeadlineAt = Date.now() + 30_000;
625
- while (responses.length < 2 && Date.now() < responseDeadlineAt) {
626
- await new Promise((resolve) => setTimeout(resolve, 20));
627
- }
628
- assert.deepEqual(responses.map((response) => response.requestId).sort(), ["registered-a", "registered-b"]);
629
- assert.ok(responses.every((response) => response.status === "completed"));
630
- assert.deepEqual(responses.map((response) => response.output).sort(), [
631
- "registered first delegated call",
632
- "registered second delegated call",
633
- ]);
634
- const toolResponse = responses.find((response) => response.output === "registered first delegated call");
635
- assert.ok(toolResponse);
636
- assert.equal(updates.some((update) => update.requestId === toolResponse.requestId && update.currentTool === "read"), true);
637
- } finally {
638
- for (const handler of runtimeHandlers.get("session_shutdown") ?? []) {
639
- await handler({}, ctx);
640
- }
641
- }
642
- });
643
-
644
- it("routes registered strict v2 text delegation through the concurrent executor", async () => {
978
+ it("routes registered structured text delegation through the concurrent executor", async () => {
645
979
  const literalJsonText = '{"looks":"json"}';
646
980
  mockPi.onCall({
647
981
  steps: [
@@ -668,7 +1002,7 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
668
1002
  },
669
1003
  ],
670
1004
  });
671
- mockPi.onCall({ output: "registered v2 second node", delay: 100 });
1005
+ mockPi.onCall({ output: "registered structured second node", delay: 100 });
672
1006
  const extensionEvents = createEventBus();
673
1007
  const runtimeHandlers = new Map<string, Array<(event: unknown, ctx: ReturnType<typeof makeMinimalCtx>) => void>>();
674
1008
  const fakePi = new Proxy({
@@ -697,28 +1031,27 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
697
1031
  getAvailable: () => [{ provider: "mock", id: "test-model", reasoning: true }],
698
1032
  },
699
1033
  sessionManager: {
700
- getSessionId: () => "registered-delegation-v2-session",
701
- getSessionFile: () => path.join(tempDir, "registered-delegation-v2-session.jsonl"),
1034
+ getSessionId: () => "registered-delegation-session",
1035
+ getSessionFile: () => path.join(tempDir, "registered-delegation-session.jsonl"),
702
1036
  getEntries: () => [],
703
1037
  },
704
1038
  };
705
- const started: SubagentDelegationV2Started[] = [];
706
- const responses: SubagentDelegationV2Response[] = [];
1039
+ const started: SubagentDelegationStarted[] = [];
1040
+ const responses: SubagentDelegationResponse[] = [];
707
1041
  extensionEvents.on(SUBAGENT_DELEGATION_STARTED_EVENT, (payload) => {
708
- if ((payload as { version?: unknown }).version === SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION) {
709
- started.push(payload as SubagentDelegationV2Started);
1042
+ if ((payload as { ownerRunId?: unknown }).ownerRunId === "owner-delegation") {
1043
+ started.push(payload as SubagentDelegationStarted);
710
1044
  }
711
1045
  });
712
1046
  extensionEvents.on(SUBAGENT_DELEGATION_RESPONSE_EVENT, (payload) => {
713
- if ((payload as { version?: unknown }).version === SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION) {
714
- responses.push(payload as SubagentDelegationV2Response);
1047
+ if ((payload as { ownerRunId?: unknown }).ownerRunId === "owner-delegation") {
1048
+ responses.push(payload as SubagentDelegationResponse);
715
1049
  }
716
1050
  });
717
1051
 
718
1052
  const firstRequest = {
719
- version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
720
- requestId: "registered-v2-a",
721
- ownerRunId: "owner-v2",
1053
+ requestId: "registered-a",
1054
+ ownerRunId: "owner-delegation",
722
1055
  nodeId: "node-a",
723
1056
  agent: "builder",
724
1057
  task: "Return literal JSON-looking text",
@@ -727,11 +1060,10 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
727
1060
  model: "mock/test-model",
728
1061
  thinking: "high",
729
1062
  result: { kind: "text" },
730
- } satisfies SubagentDelegationV2Request;
1063
+ } satisfies SubagentDelegationRequest;
731
1064
  const secondRequest = {
732
- version: SUBAGENT_DELEGATION_V2_PROTOCOL_VERSION,
733
- requestId: "registered-v2-b",
734
- ownerRunId: "owner-v2",
1065
+ requestId: "registered-b",
1066
+ ownerRunId: "owner-delegation",
735
1067
  nodeId: "node-b",
736
1068
  agent: "commentator",
737
1069
  task: "Run the second logical node",
@@ -740,7 +1072,7 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
740
1072
  model: "mock/test-model",
741
1073
  thinking: "high",
742
1074
  result: { kind: "text" },
743
- } satisfies SubagentDelegationV2Request;
1075
+ } satisfies SubagentDelegationRequest;
744
1076
 
745
1077
  try {
746
1078
  registerSubagentExtension(fakePi as never);
@@ -754,10 +1086,10 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
754
1086
  while (mockPi.callCount() < 2 && responses.length < 2 && Date.now() < callDeadlineAt) {
755
1087
  await new Promise((resolve) => setTimeout(resolve, 20));
756
1088
  }
757
- assert.equal(mockPi.callCount(), 2, `different V2 logical nodes should use the concurrent delegated execution path: ${JSON.stringify(responses)}`);
1089
+ assert.equal(mockPi.callCount(), 2, `different logical nodes should use the concurrent delegated execution path: ${JSON.stringify(responses)}`);
758
1090
  assert.deepEqual(started.map(({ requestId, ownerRunId, nodeId }) => ({ requestId, ownerRunId, nodeId })).sort((a, b) => a.nodeId.localeCompare(b.nodeId)), [
759
- { requestId: "registered-v2-a", ownerRunId: "owner-v2", nodeId: "node-a" },
760
- { requestId: "registered-v2-b", ownerRunId: "owner-v2", nodeId: "node-b" },
1091
+ { requestId: "registered-a", ownerRunId: "owner-delegation", nodeId: "node-a" },
1092
+ { requestId: "registered-b", ownerRunId: "owner-delegation", nodeId: "node-b" },
761
1093
  ]);
762
1094
 
763
1095
  const responseDeadlineAt = Date.now() + 30_000;
@@ -769,7 +1101,7 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
769
1101
  const terminalResponses = responses.filter((response) => response.status !== "invalid_request");
770
1102
  assert.equal(terminalResponses.length, 2);
771
1103
  for (const response of terminalResponses) {
772
- assert.equal(response.ownerRunId, "owner-v2");
1104
+ assert.equal(response.ownerRunId, "owner-delegation");
773
1105
  assert.equal(response.model, "mock/test-model:high");
774
1106
  assert.equal(response.thinking, "high");
775
1107
  assert.match(response.launchContractDigest ?? "", /^[0-9a-f]{64}$/);
@@ -795,7 +1127,7 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
795
1127
  toolCalls: 1,
796
1128
  });
797
1129
  assert.equal(typeof literalResponse.usage?.durationMs, "number");
798
- const plainResponse = terminalResponses.find((response) => response.result?.kind === "text" && response.result.text === "registered v2 second node");
1130
+ const plainResponse = terminalResponses.find((response) => response.result?.kind === "text" && response.result.text === "registered structured second node");
799
1131
  assert.ok(plainResponse);
800
1132
  } finally {
801
1133
  for (const handler of runtimeHandlers.get("session_shutdown") ?? []) {
@@ -1077,6 +1409,45 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1077
1409
  assert.deepEqual(result.details?.totalCost, { inputTokens: 100, outputTokens: 50, costUsd: 0.001 });
1078
1410
  });
1079
1411
 
1412
+ it("emits resolved model and thinking for nested foreground starts", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
1413
+ mockPi.onCall({ output: "nested result" });
1414
+ const route = createNestedRoute("root-nested-model");
1415
+ const envPatch = {
1416
+ ...nestedRouteEnv(route),
1417
+ [SUBAGENT_PARENT_RUN_ID_ENV]: "parent-run",
1418
+ [SUBAGENT_PARENT_CHILD_INDEX_ENV]: "2",
1419
+ [SUBAGENT_PARENT_DEPTH_ENV]: "1",
1420
+ };
1421
+ const savedEnv = Object.fromEntries(Object.keys(envPatch).map((key) => [key, process.env[key]]));
1422
+ try {
1423
+ Object.assign(process.env, envPatch);
1424
+ const executor = makeExecutor([makeAgent("echo", { model: "openai/gpt-5-mini", thinking: "high" })]);
1425
+
1426
+ const result = await executor.execute(
1427
+ "nested-model-start",
1428
+ { agent: "echo", task: "Nested task" },
1429
+ new AbortController().signal,
1430
+ undefined,
1431
+ makeMinimalCtx(tempDir),
1432
+ );
1433
+
1434
+ assert.equal(result.isError, undefined);
1435
+ const records = fs.readdirSync(route.eventSink)
1436
+ .sort()
1437
+ .flatMap((name) => parseNestedEventRecords(fs.readFileSync(path.join(route.eventSink, name), "utf-8"), route));
1438
+ const started = records.find((record) => record.type === "subagent.nested.started");
1439
+ assert.equal(started?.child.model, "openai/gpt-5-mini");
1440
+ assert.equal(started?.child.thinking, "high");
1441
+ assert.deepEqual(started?.child.steps, [{ agent: "echo", status: "running", model: "openai/gpt-5-mini", thinking: "high" }]);
1442
+ } finally {
1443
+ for (const [key, value] of Object.entries(savedEnv)) {
1444
+ if (value === undefined) delete process.env[key];
1445
+ else process.env[key] = value;
1446
+ }
1447
+ fs.rmSync(path.dirname(route.eventSink), { recursive: true, force: true });
1448
+ }
1449
+ });
1450
+
1080
1451
  it("blocks later foreground chain children when hard reported usage is exhausted", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
1081
1452
  mockPi.onCall({ output: "first result" });
1082
1453
  const executor = makeExecutor([makeAgent("echo"), makeAgent("second")]);
@@ -1131,10 +1502,10 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1131
1502
 
1132
1503
  it("fails implementation runs that complete without mutation attempts", async () => {
1133
1504
  mockPi.onCall({ output: "Validation:\nlet rawFilename = params.filename.trim();" });
1134
- const agents = [makeAgent("worker")];
1505
+ const agents = [makeAgent("builder")];
1135
1506
  const controlEvents: Array<{ message: string }> = [];
1136
1507
 
1137
- const result = await runSync(tempDir, agents, "worker", "Implement the approved file changes", {
1508
+ const result = await runSync(tempDir, agents, "builder", "Implement the approved file changes", {
1138
1509
  runId: "guard-run",
1139
1510
  onControlEvent: (event: { message: string }) => controlEvents.push(event),
1140
1511
  });
@@ -1144,18 +1515,18 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1144
1515
  assert.equal(result.finalOutput, "Validation:\nlet rawFilename = params.filename.trim();");
1145
1516
  assert.equal(result.progress.status, "failed");
1146
1517
  assert.deepEqual(controlEvents.map((event) => event.message), [
1147
- "worker completed without making edits for an implementation task",
1518
+ "builder completed without making edits for an implementation task",
1148
1519
  ]);
1149
1520
  assert.deepEqual(result.controlEvents?.map((event) => event.message), [
1150
- "worker completed without making edits for an implementation task",
1521
+ "builder completed without making edits for an implementation task",
1151
1522
  ]);
1152
1523
  });
1153
1524
 
1154
1525
  it("agent contract v1 reports omitted acceptance separately without injecting a prompt", async () => {
1155
1526
  mockPi.onCall({ output: "Plan only" });
1156
- const agents = [makeAgent("worker", { tools: ["read", "write"] })];
1527
+ const agents = [makeAgent("builder", { tools: ["read", "write"] })];
1157
1528
 
1158
- const result = await runSync(tempDir, agents, "worker", "Implement the approved file changes", {
1529
+ const result = await runSync(tempDir, agents, "builder", "Implement the approved file changes", {
1159
1530
  runId: "v1-no-acceptance",
1160
1531
  agentContract: { version: 1 },
1161
1532
  });
@@ -1172,9 +1543,9 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1172
1543
 
1173
1544
  it("agent contract v1 keeps acceptance rejection out of execution status", async () => {
1174
1545
  mockPi.onCall({ output: "Done\n```acceptance-report\n{\"criteriaSatisfied\":[{\"id\":\"criterion-1\",\"status\":\"not-satisfied\",\"evidence\":\"no proof\"}]}\n```" });
1175
- const agents = [makeAgent("worker", { tools: ["read"], completionGuard: false })];
1546
+ const agents = [makeAgent("builder", { tools: ["read"], completionGuard: false })];
1176
1547
 
1177
- const result = await runSync(tempDir, agents, "worker", "Summarize the fix", {
1548
+ const result = await runSync(tempDir, agents, "builder", "Summarize the fix", {
1178
1549
  runId: "v1-acceptance-reject",
1179
1550
  agentContract: { version: 1 },
1180
1551
  acceptance: { level: "checked", criteria: ["Return required proof"] },
@@ -1190,9 +1561,9 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1190
1561
 
1191
1562
  it("agent contract v1 records explicit completion guard as an effect", async () => {
1192
1563
  mockPi.onCall({ output: "Plan only" });
1193
- const agents = [makeAgent("worker", { tools: ["read", "write"], completionGuard: true })];
1564
+ const agents = [makeAgent("builder", { tools: ["read", "write"], completionGuard: true })];
1194
1565
 
1195
- const result = await runSync(tempDir, agents, "worker", "Implement the approved file changes", {
1566
+ const result = await runSync(tempDir, agents, "builder", "Implement the approved file changes", {
1196
1567
  runId: "v1-completion-effect",
1197
1568
  agentContract: { version: 1 },
1198
1569
  });
@@ -1224,7 +1595,10 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1224
1595
  );
1225
1596
 
1226
1597
  assert.equal(result.isError, undefined);
1227
- assert.deepEqual(result.details?.results?.[0]?.structuredOutput, { ok: true, note: "captured" });
1598
+ const child = result.details?.results?.[0];
1599
+ assert.deepEqual(child?.structuredOutput, { ok: true, note: "captured" });
1600
+ assert.match(child?.finalOutput ?? "", /"ok": true/);
1601
+ if (child?.artifactPaths?.outputPath) assert.match(fs.readFileSync(child.artifactPaths.outputPath, "utf-8"), /"note": "captured"/);
1228
1602
  });
1229
1603
 
1230
1604
  it("rejects structured output capture files that were not produced by the structured_output tool", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
@@ -1255,7 +1629,7 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1255
1629
 
1256
1630
  const result = await executor.execute(
1257
1631
  "single-schema-file-only-missing-path",
1258
- { agent: "echo", task: "Return structured data", outputSchema: { type: "object", required: ["ok"], properties: { ok: { type: "boolean" } } }, outputMode: "file-only", output: false, acceptance: false, artifacts: false },
1632
+ { agent: "echo", task: "Return structured data", outputSchema: { type: "object", required: ["ok"], properties: { ok: { type: "boolean" } } }, outputMode: "file-only", acceptance: false, artifacts: false },
1259
1633
  new AbortController().signal,
1260
1634
  undefined,
1261
1635
  makeMinimalCtx(tempDir),
@@ -1308,11 +1682,11 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1308
1682
 
1309
1683
  it("returns captured output when the foreground executor fails an implementation run", async () => {
1310
1684
  mockPi.onCall({ output: "Oracle review:\n- finding one\n- finding two" });
1311
- const executor = makeExecutor([makeAgent("oracle")]);
1685
+ const executor = makeExecutor([makeAgent("commentator")]);
1312
1686
 
1313
1687
  const result = await executor.execute(
1314
1688
  "failed-single-output",
1315
- { agent: "oracle", task: "Implement the approved file changes", artifacts: true },
1689
+ { agent: "commentator", task: "Implement the approved file changes" },
1316
1690
  new AbortController().signal,
1317
1691
  undefined,
1318
1692
  makeMinimalCtx(tempDir),
@@ -1321,21 +1695,15 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1321
1695
  const text = result.content[0]?.text ?? "";
1322
1696
  assert.equal(result.isError, true);
1323
1697
  assert.match(text, /completed without making edits/);
1324
- // Reference-first failure: error/status plus the saved-output reference;
1325
- // the full output stays readable in the persisted result file.
1326
- assert.match(text, /Output saved to: /);
1327
- assert.doesNotMatch(text, /Output:\nOracle review:/);
1328
- const outputsDir = path.join(tempDir, ".pi-subagents", "artifacts", "outputs");
1329
- const runDirs = fs.readdirSync(outputsDir);
1330
- assert.equal(runDirs.length, 1);
1331
- assert.equal(fs.readFileSync(path.join(outputsDir, runDirs[0]!, "result.md"), "utf-8"), "Oracle review:\n- finding one\n- finding two");
1698
+ assert.match(text, /Output:\nOracle review:\n- finding one\n- finding two/);
1699
+ assert.match(text, /Output artifact: /);
1332
1700
  });
1333
1701
 
1334
1702
  it("fails future-tense implementation summaries when no mutation attempt occurred", async () => {
1335
1703
  mockPi.onCall({ output: "I’ll do that now and report back after implementing." });
1336
- const agents = [makeAgent("worker")];
1704
+ const agents = [makeAgent("builder")];
1337
1705
 
1338
- const result = await runSync(tempDir, agents, "worker", "Implement the approved fixes", {
1706
+ const result = await runSync(tempDir, agents, "builder", "Implement the approved fixes", {
1339
1707
  runId: "guard-future-tense",
1340
1708
  });
1341
1709
 
@@ -1393,9 +1761,9 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1393
1761
  events.assistantMessage("Applied edit"),
1394
1762
  ],
1395
1763
  });
1396
- const agents = [makeAgent("worker")];
1764
+ const agents = [makeAgent("builder")];
1397
1765
 
1398
- const result = await runSync(tempDir, agents, "worker", "Implement the approved file changes", {
1766
+ const result = await runSync(tempDir, agents, "builder", "Implement the approved file changes", {
1399
1767
  runId: "guard-success",
1400
1768
  });
1401
1769
 
@@ -1406,14 +1774,13 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1406
1774
 
1407
1775
  it("resolves explicit agent aliases to canonical execution names", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
1408
1776
  mockPi.onCall({ output: "Implemented" });
1409
- const executor = makeExecutor([makeAgent("worker", { aliases: ["developer"], completionGuard: false })]);
1777
+ const executor = makeExecutor([makeAgent("builder", { aliases: ["developer"], completionGuard: false })]);
1410
1778
 
1411
1779
  const result = await executor.execute("single", { agent: "developer", task: "Implement" }, new AbortController().signal, undefined, makeMinimalCtx(tempDir));
1412
1780
 
1413
1781
  assert.equal(result.isError, undefined);
1414
- assert.equal(result.details?.results[0]?.agent, "worker");
1415
- assert.match(result.content[0]?.text ?? "", /Output saved to: /);
1416
- assert.doesNotMatch(result.content[0]?.text ?? "", /^Implemented$/);
1782
+ assert.equal(result.details?.results[0]?.agent, "builder");
1783
+ assert.match(result.content[0]?.text ?? "", /Implemented/);
1417
1784
  });
1418
1785
 
1419
1786
  it("returns error for unknown agent", async () => {
@@ -1465,10 +1832,10 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1465
1832
  events.assistantMessage("I need to retry the same edit."),
1466
1833
  ],
1467
1834
  });
1468
- const agents = [makeAgent("worker")];
1835
+ const agents = [makeAgent("builder")];
1469
1836
  const controlEvents: NonNullable<RunSyncResult["controlEvents"]> = [];
1470
1837
 
1471
- const result = await runSync(tempDir, agents, "worker", "Implement the approved fixes", {
1838
+ const result = await runSync(tempDir, agents, "builder", "Implement the approved fixes", {
1472
1839
  runId: "run-failures",
1473
1840
  controlConfig: { enabled: true, failedToolAttemptsBeforeAttention: 3, notifyOn: ["active_long_running", "needs_attention"] },
1474
1841
  onControlEvent: (event: NonNullable<RunSyncResult["controlEvents"]>[number]) => controlEvents.push(event),
@@ -1517,12 +1884,12 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1517
1884
  it("retries a zero-activity startup exit on the same model", async () => {
1518
1885
  mockPi.onCall({ exitCode: 1 });
1519
1886
  mockPi.onCall({ output: "Recovered after startup race" });
1520
- const agents = [makeAgent("worker", {
1887
+ const agents = [makeAgent("builder", {
1521
1888
  model: "openai/gpt-5-mini",
1522
1889
  fallbackModels: ["anthropic/claude-sonnet-4"],
1523
1890
  })];
1524
1891
 
1525
- const result = await runSync(tempDir, agents, "worker", "Do work", {
1892
+ const result = await runSync(tempDir, agents, "builder", "Do work", {
1526
1893
  runId: "startup-retry-sync",
1527
1894
  acceptance: false,
1528
1895
  });
@@ -1540,12 +1907,12 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1540
1907
  it("does not retry a non-zero exit after tool activity", async () => {
1541
1908
  mockPi.onCall({ jsonl: [events.toolStart("read", { path: "package.json" })], exitCode: 1 });
1542
1909
  mockPi.onCall({ output: "must not run" });
1543
- const agents = [makeAgent("worker", {
1910
+ const agents = [makeAgent("builder", {
1544
1911
  model: "openai/gpt-5-mini",
1545
1912
  fallbackModels: ["anthropic/claude-sonnet-4"],
1546
1913
  })];
1547
1914
 
1548
- const result = await runSync(tempDir, agents, "worker", "Read a file", {
1915
+ const result = await runSync(tempDir, agents, "builder", "Read a file", {
1549
1916
  runId: "startup-no-retry-after-tool",
1550
1917
  acceptance: false,
1551
1918
  });
@@ -1555,28 +1922,28 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1555
1922
  assert.equal(mockPi.callCount(), 1);
1556
1923
  });
1557
1924
 
1558
- it("does not retry a signaled child exit", { skip: process.platform === "win32" ? "POSIX child signal reporting is unavailable on Windows" : false }, async () => {
1559
- mockPi.onCall({ signal: "SIGKILL" });
1925
+ it("does not retry non-SIGKILL signaled child exits", { skip: process.platform === "win32" ? "POSIX child signal reporting is unavailable on Windows" : false }, async () => {
1926
+ mockPi.onCall({ signal: "SIGTERM" });
1560
1927
  mockPi.onCall({ output: "must not run" });
1561
- const agents = [makeAgent("worker", { model: "openai/gpt-5-mini" })];
1928
+ const agents = [makeAgent("builder", { model: "openai/gpt-5-mini" })];
1562
1929
 
1563
- const result = await runSync(tempDir, agents, "worker", "Do work", {
1930
+ const result = await runSync(tempDir, agents, "builder", "Do work", {
1564
1931
  runId: "startup-no-retry-after-signal",
1565
1932
  acceptance: false,
1566
1933
  });
1567
1934
 
1568
1935
  assert.equal(result.exitCode, 1);
1569
- assert.equal(result.processSignal, "SIGKILL");
1570
- assert.equal(result.error, "Subagent process terminated by signal SIGKILL.");
1936
+ assert.equal(result.processSignal, "SIGTERM");
1937
+ assert.equal(result.error, "Subagent process terminated by signal SIGTERM.");
1571
1938
  assert.equal(result.modelAttempts?.length, 1);
1572
1939
  assert.equal(mockPi.callCount(), 1);
1573
1940
  });
1574
1941
 
1575
1942
  it("prefers signal termination errors over stderr tails", { skip: process.platform === "win32" ? "POSIX child signal reporting is unavailable on Windows" : false }, async () => {
1576
1943
  mockPi.onCall({ stderr: "INFO benign startup line\n", signal: "SIGTERM" });
1577
- const agents = [makeAgent("worker", { model: "openai/gpt-5-mini" })];
1944
+ const agents = [makeAgent("builder", { model: "openai/gpt-5-mini" })];
1578
1945
 
1579
- const result = await runSync(tempDir, agents, "worker", "Do work", {
1946
+ const result = await runSync(tempDir, agents, "builder", "Do work", {
1580
1947
  runId: "signal-error-over-stderr",
1581
1948
  acceptance: false,
1582
1949
  });
@@ -1590,9 +1957,9 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1590
1957
  it("does not retry a child exit with raw stdout diagnostics", async () => {
1591
1958
  mockPi.onCall({ stdoutRaw: "configuration failed before protocol startup\n", exitCode: 1 });
1592
1959
  mockPi.onCall({ output: "must not run" });
1593
- const agents = [makeAgent("worker", { model: "openai/gpt-5-mini" })];
1960
+ const agents = [makeAgent("builder", { model: "openai/gpt-5-mini" })];
1594
1961
 
1595
- const result = await runSync(tempDir, agents, "worker", "Do work", {
1962
+ const result = await runSync(tempDir, agents, "builder", "Do work", {
1596
1963
  runId: "startup-no-retry-after-stdout-diagnostic",
1597
1964
  acceptance: false,
1598
1965
  });
@@ -1605,12 +1972,12 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1605
1972
 
1606
1973
  it("reports an actionable error after startup retries are exhausted", async () => {
1607
1974
  mockPi.onCall({ exitCode: 1 });
1608
- const agents = [makeAgent("worker", {
1975
+ const agents = [makeAgent("builder", {
1609
1976
  model: "openai/gpt-5-mini",
1610
1977
  fallbackModels: ["anthropic/claude-sonnet-4"],
1611
1978
  })];
1612
1979
 
1613
- const result = await runSync(tempDir, agents, "worker", "Do work", {
1980
+ const result = await runSync(tempDir, agents, "builder", "Do work", {
1614
1981
  runId: "startup-retry-exhausted-sync",
1615
1982
  acceptance: false,
1616
1983
  });
@@ -1688,6 +2055,19 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
1688
2055
  assert.equal(getFinalOutput(result.messages), "你好 from fragmented JSON");
1689
2056
  });
1690
2057
 
2058
+ it("projects an oversized turn_end aggregate without losing the foreground result", async () => {
2059
+ mockPi.onCall({ jsonl: [
2060
+ events.assistantMessage("result before oversized aggregate"),
2061
+ { type: "turn_end", message: {}, toolResults: [{ content: "x".repeat(MAX_CHILD_PENDING_LINE_BYTES) }] },
2062
+ { type: "agent_end", willRetry: false },
2063
+ { type: "agent_settled" },
2064
+ ] });
2065
+ const result = await runSync(tempDir, makeAgentConfigs(["echo"]), "echo", "Read parallel images", { acceptance: false });
2066
+ assert.equal(result.exitCode, 0);
2067
+ assert.equal(result.protocolError, undefined);
2068
+ assert.equal(getFinalOutput(result.messages), "result before oversized aggregate");
2069
+ });
2070
+
1691
2071
  it("fails with protocol_output_limit when a child emits an oversized stdout line", async () => {
1692
2072
  mockPi.onCall({ stdoutRaw: "x".repeat(MAX_CHILD_PENDING_LINE_BYTES + 1) });
1693
2073
  const result = await runSync(tempDir, makeAgentConfigs(["echo"]), "echo", "Emit malformed output", { acceptance: false });
@@ -2183,9 +2563,9 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
2183
2563
  events.assistantMessage("Found 2 files: file1.txt and file2.txt"),
2184
2564
  ],
2185
2565
  });
2186
- const agents = makeAgentConfigs(["scout"]);
2566
+ const agents = makeAgentConfigs(["explorer"]);
2187
2567
 
2188
- const result = await runSync(tempDir, agents, "scout", "List files", {});
2568
+ const result = await runSync(tempDir, agents, "explorer", "List files", {});
2189
2569
 
2190
2570
  assert.equal(result.exitCode, 0);
2191
2571
  const output = getFinalOutput(result.messages);
@@ -2212,13 +2592,13 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
2212
2592
 
2213
2593
  it("injects an agent-file-relative local skill into the foreground child prompt", async () => {
2214
2594
  mockPi.onCall({ output: "Done" });
2215
- const agentFile = path.join(tempDir, "agents", "nested", "worker.md");
2595
+ const agentFile = path.join(tempDir, "agents", "nested", "builder.md");
2216
2596
  const skillFile = path.join(path.dirname(agentFile), "skills", "local", "SKILL.md");
2217
2597
  fs.mkdirSync(path.dirname(skillFile), { recursive: true });
2218
2598
  fs.writeFileSync(skillFile, "---\ndescription: local skill description\n---\nLocal skill body\n", "utf-8");
2219
- const agents = [makeAgent("worker", { filePath: agentFile, skills: ["local"], skillPath: ["./skills"] })];
2599
+ const agents = [makeAgent("builder", { filePath: agentFile, skills: ["local"], skillPath: ["./skills"] })];
2220
2600
 
2221
- const result = await runSync(tempDir, agents, "worker", "Task", {});
2601
+ const result = await runSync(tempDir, agents, "builder", "Task", {});
2222
2602
 
2223
2603
  assert.equal(result.exitCode, 0);
2224
2604
  assert.deepEqual(result.skills, ["local"]);
@@ -2242,9 +2622,9 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
2242
2622
  });
2243
2623
 
2244
2624
  it("fails foreground runs on explicit unavailable pi-subagents skill requests without spawning", async () => {
2245
- const agents = [makeAgent("worker")];
2625
+ const agents = [makeAgent("builder")];
2246
2626
 
2247
- const result = await runSync(tempDir, agents, "worker", "Task", { skills: ["pi-subagents"] });
2627
+ const result = await runSync(tempDir, agents, "builder", "Task", { skills: ["pi-subagents"] });
2248
2628
 
2249
2629
  assert.equal(result.exitCode, 1);
2250
2630
  assert.equal(result.error, "Skills not found: pi-subagents");
@@ -2252,9 +2632,9 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
2252
2632
  });
2253
2633
 
2254
2634
  it("fails foreground runs when an agent default requests pi-subagents skill", async () => {
2255
- const agents = [makeAgent("worker", { skills: ["pi-subagents"] })];
2635
+ const agents = [makeAgent("builder", { skills: ["pi-subagents"] })];
2256
2636
 
2257
- const result = await runSync(tempDir, agents, "worker", "Task", {});
2637
+ const result = await runSync(tempDir, agents, "builder", "Task", {});
2258
2638
 
2259
2639
  assert.equal(result.exitCode, 1);
2260
2640
  assert.equal(result.error, "Skills not found: pi-subagents");
@@ -2297,29 +2677,6 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
2297
2677
  assert.ok(!JSON.stringify(result.launchResolvedExtensions).includes(tempDir), "projection should not expose raw extension paths");
2298
2678
  });
2299
2679
 
2300
- it("does not write debug artifacts by default", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
2301
- mockPi.onCall({ output: "plain result" });
2302
- const executor = makeExecutor([makeAgent("echo")]);
2303
- const result = await executor.execute(
2304
- "default-no-artifacts",
2305
- { agent: "echo", task: "Run without debug artifacts", runId: "default-no-artifacts" },
2306
- new AbortController().signal,
2307
- undefined,
2308
- makeMinimalCtx(tempDir),
2309
- );
2310
-
2311
- assert.equal(result.isError, undefined);
2312
- assert.equal(result.details?.artifacts, undefined);
2313
- // Generated durable output persists even with artifacts:false; per-child
2314
- // debug artifacts (_input/_output/_meta/_transcript) remain opt-in.
2315
- const defaultOutputsDir = path.join(tempDir, ".pi-subagents", "artifacts", "outputs");
2316
- const defaultRunDirs = fs.readdirSync(defaultOutputsDir);
2317
- assert.equal(defaultRunDirs.length, 1);
2318
- const defaultRunDir = path.join(defaultOutputsDir, defaultRunDirs[0]!);
2319
- assert.equal(fs.readFileSync(path.join(defaultRunDir, "result.md"), "utf-8"), "plain result");
2320
- assert.deepEqual(fs.readdirSync(defaultRunDir), ["result.md"]);
2321
- });
2322
-
2323
2680
  it("routes foreground artifacts to the configured session directory", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
2324
2681
  mockPi.onCall({ output: "session artifact result" });
2325
2682
  const sessionFile = path.join(tempDir, "sessions", "parent-session", "session.jsonl");
@@ -2329,7 +2686,7 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
2329
2686
 
2330
2687
  const result = await executor.execute(
2331
2688
  "session-artifact-dir",
2332
- { agent: "echo", task: "Write session-scoped artifacts", runId: "session-artifacts", artifacts: true },
2689
+ { agent: "echo", task: "Write session-scoped artifacts", runId: "session-artifacts" },
2333
2690
  new AbortController().signal,
2334
2691
  undefined,
2335
2692
  ctx,
@@ -2343,6 +2700,30 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
2343
2700
  assert.equal(fs.existsSync(path.join(tempDir, ".pi-subagents", "artifacts")), false);
2344
2701
  });
2345
2702
 
2703
+ for (const artifactDir of ["session", "temp"] as const) {
2704
+ it(`keeps foreground chain scratch files out of the project for artifactDir=${artifactDir}`, { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
2705
+ mockPi.onCall({ output: `${artifactDir} chain result` });
2706
+ const sessionFile = path.join(tempDir, "sessions", "parent-session", "session.jsonl");
2707
+ const ctx = makeMinimalCtx(tempDir);
2708
+ ctx.sessionManager.getSessionFile = () => sessionFile;
2709
+ const executor = makeExecutor([makeAgent("echo")], { artifactDir });
2710
+
2711
+ const result = await executor.execute(
2712
+ `${artifactDir}-chain-artifact-dir`,
2713
+ { chain: [{ agent: "echo", task: "Run without project-local scratch files in {chain_dir}" }] },
2714
+ new AbortController().signal,
2715
+ undefined,
2716
+ ctx,
2717
+ );
2718
+
2719
+ const taskArg = readCallArgs().at(-1) ?? "";
2720
+ assert.equal(result.isError, undefined);
2721
+ assert.ok(taskArg.includes(`${CHAIN_RUNS_DIR}${path.sep}`), taskArg);
2722
+ assert.equal(fs.existsSync(path.join(tempDir, ".pi-subagents", "chain-runs")), false);
2723
+ assert.equal(fs.existsSync(path.join(tempDir, ".pi-subagents", "artifacts")), false);
2724
+ });
2725
+ }
2726
+
2346
2727
  it("writes a failure stub to foreground output artifacts when no output was produced", async () => {
2347
2728
  mockPi.onCall({ output: "", stderr: "model unavailable", exitCode: 1 });
2348
2729
  const artifactsDir = path.join(tempDir, "artifacts-failed-output");
@@ -2578,7 +2959,7 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
2578
2959
  {
2579
2960
  action: "append-step",
2580
2961
  id: "missing-run",
2581
- chain: [{ agent: "echo", task: "Review the previous work", acceptance: { level: "reviewed" } }],
2962
+ step: { agent: "echo", task: "Review the previous work", acceptance: { level: "reviewed" } },
2582
2963
  },
2583
2964
  new AbortController().signal,
2584
2965
  undefined,
@@ -2653,6 +3034,39 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
2653
3034
  assert.equal(agentResult.details?.timeoutMs, 4_000);
2654
3035
  });
2655
3036
 
3037
+ it("runs omitted async launches in the background when the global default is enabled", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
3038
+ const executor = makeExecutor([makeAgent("echo")], {}, true);
3039
+
3040
+ const result = await executor.execute(
3041
+ "global-async-default",
3042
+ { agent: "echo", task: "Task" },
3043
+ new AbortController().signal,
3044
+ undefined,
3045
+ makeMinimalCtx(tempDir),
3046
+ );
3047
+
3048
+ assert.equal(result.isError, undefined);
3049
+ assert.match(result.content[0]?.text ?? "", /Async:/);
3050
+ assert.equal(typeof result.details?.asyncId, "string");
3051
+ });
3052
+
3053
+ it("keeps omitted async launches foreground when the global default is disabled", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
3054
+ mockPi.onCall({ output: "config foreground default finished" });
3055
+ const executor = makeExecutor([makeAgent("echo")], {}, false);
3056
+
3057
+ const result = await executor.execute(
3058
+ "global-foreground-opt-out",
3059
+ { agent: "echo", task: "Task" },
3060
+ new AbortController().signal,
3061
+ undefined,
3062
+ makeMinimalCtx(tempDir),
3063
+ );
3064
+
3065
+ assert.equal(result.isError, undefined);
3066
+ assert.match(result.content[0]?.text ?? "", /config foreground default finished/);
3067
+ assert.equal(result.details?.asyncId, undefined);
3068
+ });
3069
+
2656
3070
  it("applies agent frontmatter defaults to single-agent launches", { skip: !createSubagentExecutor ? "executor not importable" : undefined }, async () => {
2657
3071
  const executor = makeExecutor([
2658
3072
  makeAgent("echo", {
@@ -2723,8 +3137,7 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
2723
3137
  );
2724
3138
 
2725
3139
  assert.equal(result.isError, undefined);
2726
- assert.match(result.content[0]?.text ?? "", /Output saved to: /);
2727
- assert.doesNotMatch(result.content[0]?.text ?? "", /agent foreground default finished/);
3140
+ assert.match(result.content[0]?.text ?? "", /agent foreground default finished/);
2728
3141
  assert.equal(result.details?.asyncId, undefined);
2729
3142
  });
2730
3143
 
@@ -2753,8 +3166,7 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
2753
3166
  );
2754
3167
 
2755
3168
  assert.equal(result.isError, undefined);
2756
- assert.match(result.content[0]?.text ?? "", /Output saved to: /);
2757
- assert.doesNotMatch(result.content[0]?.text ?? "", /explicit foreground finished/);
3169
+ assert.match(result.content[0]?.text ?? "", /explicit foreground finished/);
2758
3170
  assert.equal(result.details?.asyncId, undefined);
2759
3171
  });
2760
3172
 
@@ -2898,8 +3310,8 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
2898
3310
  });
2899
3311
 
2900
3312
  mockPi.onCall({ echoEnv: envKeys });
2901
- const nonFanoutAgents = [makeAgent("worker", { tools: ["read"] })];
2902
- const nonFanout = await runSync(tempDir, nonFanoutAgents, "worker", "Task", { runId: "non-fanout-run" });
3313
+ const nonFanoutAgents = [makeAgent("builder", { tools: ["read"] })];
3314
+ const nonFanout = await runSync(tempDir, nonFanoutAgents, "builder", "Task", { runId: "non-fanout-run" });
2903
3315
  assert.equal(nonFanout.exitCode, 0);
2904
3316
  assert.deepEqual(JSON.parse(nonFanout.finalOutput ?? "{}"), {
2905
3317
  SELESAI_SUBAGENT_FANOUT_CHILD: "0",
@@ -2945,9 +3357,9 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
2945
3357
 
2946
3358
  it("fails with actionable diagnostics when a requested extension tool is not loaded", async () => {
2947
3359
  mockPi.onCall({ output: "Model incorrectly claimed success", missingTools: ["fixture_search"] });
2948
- const agents = [makeAgent("extension-worker", { tools: ["read", "fixture_search"], fallbackModels: ["mock/fallback-model"] })];
3360
+ const agents = [makeAgent("extension-builder", { tools: ["read", "fixture_search"], fallbackModels: ["mock/fallback-model"] })];
2949
3361
 
2950
- const result = await runSync(tempDir, agents, "extension-worker", "Use fixture search", { runId: "missing-extension-tool" });
3362
+ const result = await runSync(tempDir, agents, "extension-builder", "Use fixture search", { runId: "missing-extension-tool" });
2951
3363
 
2952
3364
  assert.equal(result.exitCode, 1);
2953
3365
  assert.match(result.error ?? "", /requested unavailable child tools: fixture_search/);
@@ -3173,9 +3585,9 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
3173
3585
  mockAssistantMessage("final wrapped output", "stop"),
3174
3586
  ],
3175
3587
  });
3176
- const agents = makeAgentConfigs(["worker"]);
3588
+ const agents = makeAgentConfigs(["builder"]);
3177
3589
 
3178
- const result = await runSync(tempDir, agents, "worker", "Use the final grace turn to wrap up.", {
3590
+ const result = await runSync(tempDir, agents, "builder", "Use the final grace turn to wrap up.", {
3179
3591
  turnBudget: { maxTurns: 1, graceTurns: 1 },
3180
3592
  runId: "foreground-turn-budget-soft",
3181
3593
  });
@@ -3189,7 +3601,7 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
3189
3601
  assert.match(result.finalOutput ?? "", /final wrapped output/);
3190
3602
  });
3191
3603
 
3192
- it("defers a foreground hard turn limit through active tool work and aborts at the next assistant boundary", async () => {
3604
+ it("preserves a clean foreground completion after turn-budget work defers", async () => {
3193
3605
  mockPi.onCall({
3194
3606
  steps: [
3195
3607
  {
@@ -3208,7 +3620,7 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
3208
3620
  },
3209
3621
  ],
3210
3622
  });
3211
- const agents = makeAgentConfigs(["worker"]);
3623
+ const agents = makeAgentConfigs(["builder"]);
3212
3624
  const snapshots: Array<{
3213
3625
  turnBudget?: { outcome?: string; terminationDeferredAtTurn?: number };
3214
3626
  turnBudgetExceeded?: boolean;
@@ -3217,7 +3629,7 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
3217
3629
  status?: string;
3218
3630
  }> = [];
3219
3631
 
3220
- const result = await runSync(tempDir, agents, "worker", "Finish active tool work before enforcing the hard limit.", {
3632
+ const result = await runSync(tempDir, agents, "builder", "Finish active tool work before enforcing the hard limit.", {
3221
3633
  turnBudget: { maxTurns: 1, graceTurns: 0 },
3222
3634
  runId: "foreground-turn-budget-deferred",
3223
3635
  onUpdate(update: { details?: { results?: Array<{ turnBudget?: { outcome?: string; terminationDeferredAtTurn?: number }; turnBudgetExceeded?: boolean; error?: string }>; progress?: Array<{ currentTool?: string; status?: string }> } }) {
@@ -3239,8 +3651,9 @@ describe("single sync execution", { skip: !available ? "pi packages not availabl
3239
3651
  assert.equal(duringTool.turnBudgetExceeded, undefined);
3240
3652
  assert.equal(duringTool.error, undefined);
3241
3653
  assert.equal(duringTool.status, "running");
3242
- assert.equal(result.turnBudgetExceeded, true);
3243
- assert.equal(result.turnBudget?.outcome, "exceeded");
3654
+ assert.equal(result.exitCode, 0);
3655
+ assert.equal(result.turnBudgetExceeded, undefined);
3656
+ assert.equal(result.turnBudget?.outcome, "wrap-up-requested");
3244
3657
  assert.equal(result.turnBudget?.turnCount, 2);
3245
3658
  assert.match(result.finalOutput ?? "", /safe assistant boundary reached/);
3246
3659
  assert.ok(result.messages?.some((message) => message.role === "toolResult" && JSON.stringify(message.content).includes("build completed")));