@selesai/code 0.5.28 → 0.5.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. package/dist/cli/args.d.ts.map +1 -1
  2. package/dist/cli/args.js +9 -1
  3. package/dist/cli/args.js.map +1 -1
  4. package/dist/cli/config-selector.d.ts.map +1 -1
  5. package/dist/cli/config-selector.js +1 -1
  6. package/dist/cli/config-selector.js.map +1 -1
  7. package/dist/cli/credential-print.d.ts +23 -0
  8. package/dist/cli/credential-print.d.ts.map +1 -0
  9. package/dist/cli/credential-print.js +117 -0
  10. package/dist/cli/credential-print.js.map +1 -0
  11. package/dist/cli/startup-ui.d.ts.map +1 -1
  12. package/dist/cli/startup-ui.js +1 -1
  13. package/dist/cli/startup-ui.js.map +1 -1
  14. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  15. package/dist/core/agent-session-runtime.js +3 -0
  16. package/dist/core/agent-session-runtime.js.map +1 -1
  17. package/dist/core/agent-session.d.ts +12 -1
  18. package/dist/core/agent-session.d.ts.map +1 -1
  19. package/dist/core/agent-session.js +20 -14
  20. package/dist/core/agent-session.js.map +1 -1
  21. package/dist/core/compaction/compaction.d.ts.map +1 -1
  22. package/dist/core/compaction/compaction.js +11 -3
  23. package/dist/core/compaction/compaction.js.map +1 -1
  24. package/dist/core/extensions/runner.d.ts +1 -0
  25. package/dist/core/extensions/runner.d.ts.map +1 -1
  26. package/dist/core/extensions/runner.js +11 -0
  27. package/dist/core/extensions/runner.js.map +1 -1
  28. package/dist/core/extensions/types.d.ts +14 -1
  29. package/dist/core/extensions/types.d.ts.map +1 -1
  30. package/dist/core/extensions/types.js.map +1 -1
  31. package/dist/core/footer-data-provider.d.ts +10 -0
  32. package/dist/core/footer-data-provider.d.ts.map +1 -1
  33. package/dist/core/footer-data-provider.js +1 -1
  34. package/dist/core/footer-data-provider.js.map +1 -1
  35. package/dist/core/llama/provider.d.ts.map +1 -1
  36. package/dist/core/llama/provider.js +8 -3
  37. package/dist/core/llama/provider.js.map +1 -1
  38. package/dist/core/model-config.d.ts +30 -0
  39. package/dist/core/model-config.d.ts.map +1 -1
  40. package/dist/core/model-config.js +6 -0
  41. package/dist/core/model-config.js.map +1 -1
  42. package/dist/core/model-registry.d.ts.map +1 -1
  43. package/dist/core/model-registry.js +2 -2
  44. package/dist/core/model-registry.js.map +1 -1
  45. package/dist/core/model-resolver.d.ts +1 -0
  46. package/dist/core/model-resolver.d.ts.map +1 -1
  47. package/dist/core/model-resolver.js +20 -3
  48. package/dist/core/model-resolver.js.map +1 -1
  49. package/dist/core/model-runtime.d.ts +2 -0
  50. package/dist/core/model-runtime.d.ts.map +1 -1
  51. package/dist/core/model-runtime.js +5 -4
  52. package/dist/core/model-runtime.js.map +1 -1
  53. package/dist/core/package-manager.d.ts.map +1 -1
  54. package/dist/core/package-manager.js +13 -6
  55. package/dist/core/package-manager.js.map +1 -1
  56. package/dist/core/remote-catalog-provider.d.ts +1 -1
  57. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  58. package/dist/core/remote-catalog-provider.js +24 -11
  59. package/dist/core/remote-catalog-provider.js.map +1 -1
  60. package/dist/core/resource-loader.d.ts +15 -0
  61. package/dist/core/resource-loader.d.ts.map +1 -1
  62. package/dist/core/resource-loader.js +66 -9
  63. package/dist/core/resource-loader.js.map +1 -1
  64. package/dist/core/settings-manager.d.ts +1 -1
  65. package/dist/core/settings-manager.d.ts.map +1 -1
  66. package/dist/core/settings-manager.js.map +1 -1
  67. package/dist/core/system-prompt.d.ts.map +1 -1
  68. package/dist/core/system-prompt.js +1 -1
  69. package/dist/core/system-prompt.js.map +1 -1
  70. package/dist/core/tools/bash.d.ts +2 -0
  71. package/dist/core/tools/bash.d.ts.map +1 -1
  72. package/dist/core/tools/bash.js +34 -5
  73. package/dist/core/tools/bash.js.map +1 -1
  74. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  75. package/dist/core/tools/tool-definition-wrapper.js +3 -1
  76. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  77. package/dist/extensions/pi-intercom/CHANGELOG.md +249 -0
  78. package/dist/extensions/pi-intercom/README.md +102 -39
  79. package/dist/extensions/pi-intercom/broker/broker.ts +1233 -36
  80. package/dist/extensions/pi-intercom/broker/client.test.ts +83 -0
  81. package/dist/extensions/pi-intercom/broker/client.ts +315 -12
  82. package/dist/extensions/pi-intercom/broker/extension-state.ts +186 -0
  83. package/dist/extensions/pi-intercom/broker/extension.test.ts +387 -0
  84. package/dist/extensions/pi-intercom/broker/framing.test.ts +114 -0
  85. package/dist/extensions/pi-intercom/broker/framing.ts +82 -24
  86. package/dist/extensions/pi-intercom/broker/paths.test.ts +153 -0
  87. package/dist/extensions/pi-intercom/broker/paths.ts +117 -8
  88. package/dist/extensions/pi-intercom/broker/runtime-claim.test.ts +34 -0
  89. package/dist/extensions/pi-intercom/broker/runtime-claim.ts +21 -0
  90. package/dist/extensions/pi-intercom/broker/spawn.test.ts +160 -23
  91. package/dist/extensions/pi-intercom/broker/spawn.ts +113 -27
  92. package/dist/extensions/pi-intercom/config.test.ts +93 -0
  93. package/dist/extensions/pi-intercom/config.ts +55 -6
  94. package/dist/extensions/pi-intercom/cwd.test.ts +40 -0
  95. package/dist/extensions/pi-intercom/cwd.ts +31 -0
  96. package/dist/extensions/pi-intercom/extension-api.ts +44 -0
  97. package/dist/extensions/pi-intercom/format-context.test.ts +31 -0
  98. package/dist/extensions/pi-intercom/format-context.ts +32 -0
  99. package/dist/extensions/pi-intercom/index.ts +742 -145
  100. package/dist/extensions/pi-intercom/intercom.integration.test.ts +2646 -0
  101. package/dist/extensions/pi-intercom/package.json +15 -5
  102. package/dist/extensions/pi-intercom/reply-tracker.test.ts +134 -0
  103. package/dist/extensions/pi-intercom/reply-tracker.ts +31 -13
  104. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +13 -11
  105. package/dist/extensions/pi-intercom/test/inline-message.test.ts +184 -0
  106. package/dist/extensions/pi-intercom/test/overlay-width.test.ts +66 -0
  107. package/dist/extensions/pi-intercom/types.ts +94 -4
  108. package/dist/extensions/pi-intercom/ui/compose.ts +8 -4
  109. package/dist/extensions/pi-intercom/ui/inline-message.ts +61 -25
  110. package/dist/extensions/pi-intercom/ui/session-list.ts +7 -3
  111. package/dist/extensions/pi-subagents/CHANGELOG.md +85 -0
  112. package/dist/extensions/pi-subagents/LICENSE +21 -0
  113. package/dist/extensions/pi-subagents/README.md +146 -52
  114. package/dist/extensions/pi-subagents/agents/architect.md +1 -0
  115. package/dist/extensions/pi-subagents/agents/builder.md +1 -0
  116. package/dist/extensions/pi-subagents/package-lock.json +2 -2
  117. package/dist/extensions/pi-subagents/package.json +3 -3
  118. package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
  119. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +21 -989
  120. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +256 -0
  121. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +430 -0
  122. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +144 -0
  123. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +282 -0
  124. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +71 -30
  125. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +4 -0
  126. package/dist/extensions/pi-subagents/src/agents/agents.ts +118 -9
  127. package/dist/extensions/pi-subagents/src/agents/skills.ts +14 -12
  128. package/dist/extensions/pi-subagents/src/api/delegation.ts +3 -0
  129. package/dist/extensions/pi-subagents/src/api/preflight.ts +16 -12
  130. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +17 -1
  131. package/dist/extensions/pi-subagents/src/extension/index.ts +17 -7
  132. package/dist/extensions/pi-subagents/src/extension/rpc.ts +248 -6
  133. package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -6
  134. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +8 -7
  135. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +9 -4
  136. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +33 -4
  137. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +63 -16
  138. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +24 -13
  139. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +7 -5
  140. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -2
  141. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +48 -5
  142. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +68 -1
  143. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +29 -4
  144. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +29 -6
  145. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +29 -3
  146. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +372 -28
  147. package/dist/extensions/pi-subagents/src/runs/foreground/async-stop-action.ts +65 -0
  148. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +3 -3
  149. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +143 -43
  150. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +527 -247
  151. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +42 -0
  152. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +426 -123
  153. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +15 -7
  154. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +51 -19
  155. package/dist/extensions/pi-subagents/src/runs/shared/chain-outputs.ts +3 -1
  156. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
  157. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +44 -11
  158. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +8 -0
  159. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +97 -20
  160. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +43 -12
  161. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +52 -4
  162. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +19 -0
  163. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +45 -9
  164. package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +71 -0
  165. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +31 -1
  166. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +101 -0
  167. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +1 -1
  168. package/dist/extensions/pi-subagents/src/runs/shared/usage-budget.ts +65 -0
  169. package/dist/extensions/pi-subagents/src/runs/shared/workflow-graph.ts +26 -1
  170. package/dist/extensions/pi-subagents/src/shared/settings.ts +17 -1
  171. package/dist/extensions/pi-subagents/src/shared/types.ts +155 -10
  172. package/dist/extensions/pi-subagents/src/shared/utils.ts +73 -4
  173. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +5 -0
  174. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +46 -4
  175. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +5 -3
  176. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +87 -24
  177. package/dist/extensions/pi-subagents/src/tui/fleet.ts +182 -9
  178. package/dist/extensions/pi-subagents/src/tui/render.ts +27 -28
  179. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +14 -7
  180. package/dist/extensions/pi-subagents/src/watchdog/review.ts +5 -4
  181. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +170 -17
  182. package/dist/extensions/pi-subagents/src/watchdog/scope.ts +62 -0
  183. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +41 -1
  184. package/dist/extensions/pi-subagents/src/watchdog/types.ts +10 -0
  185. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
  186. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +348 -7
  187. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +84 -0
  188. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +4 -2
  189. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +51 -2
  190. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +26 -1
  191. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +48 -0
  192. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +3 -3
  193. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +213 -13
  194. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +34 -0
  195. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +44 -0
  196. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +118 -12
  197. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +850 -7
  198. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +112 -23
  199. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +17 -5
  200. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +2 -0
  201. package/dist/extensions/pi-subagents/test/support/register-loader.mjs +3 -3
  202. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +3 -1
  203. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +128 -0
  204. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +47 -2
  205. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +60 -0
  206. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +8 -0
  207. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +102 -0
  208. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +1 -1
  209. package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +6 -0
  210. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +1 -1
  211. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +48 -48
  212. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +23 -0
  213. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +27 -0
  214. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +4 -2
  215. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +1 -0
  216. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +176 -8
  217. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +164 -5
  218. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +41 -1
  219. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +11 -11
  220. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +18 -2
  221. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -1
  222. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +30 -2
  223. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +10 -2
  224. package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +22 -0
  225. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +103 -0
  226. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +18 -0
  227. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +46 -0
  228. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +13 -1
  229. package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +29 -4
  230. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +223 -4
  231. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +30 -0
  232. package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +52 -0
  233. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +34 -2
  234. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  235. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +1 -1
  236. package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +78 -0
  237. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +41 -0
  238. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +77 -0
  239. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +3 -0
  240. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +1 -1
  241. package/dist/extensions/pi-subagents/test/unit/total-cost.test.ts +1 -0
  242. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +210 -1
  243. package/dist/extensions/pi-subagents/test/unit/watchdog-scope.test.ts +33 -0
  244. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +32 -0
  245. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +1 -1
  246. package/dist/main.d.ts.map +1 -1
  247. package/dist/main.js +43 -0
  248. package/dist/main.js.map +1 -1
  249. package/dist/modes/interactive/components/custom-message.d.ts +3 -1
  250. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  251. package/dist/modes/interactive/components/custom-message.js +10 -2
  252. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  253. package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
  254. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  255. package/dist/modes/interactive/components/extension-editor.js +16 -46
  256. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  257. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  258. package/dist/modes/interactive/components/model-selector.js +4 -1
  259. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  260. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  261. package/dist/modes/interactive/components/scoped-models-selector.js +22 -13
  262. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  263. package/dist/modes/interactive/external-editor.d.ts +12 -0
  264. package/dist/modes/interactive/external-editor.d.ts.map +1 -0
  265. package/dist/modes/interactive/external-editor.js +37 -0
  266. package/dist/modes/interactive/external-editor.js.map +1 -0
  267. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  268. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  269. package/dist/modes/interactive/interactive-mode.js +72 -64
  270. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  271. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  272. package/dist/modes/rpc/rpc-mode.js +14 -0
  273. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  274. package/dist/utils/clipboard.d.ts.map +1 -1
  275. package/dist/utils/clipboard.js +19 -8
  276. package/dist/utils/clipboard.js.map +1 -1
  277. package/dist/utils/version-check.d.ts.map +1 -1
  278. package/dist/utils/version-check.js +1 -1
  279. package/dist/utils/version-check.js.map +1 -1
  280. package/docs/compaction.md +1 -1
  281. package/docs/custom-provider.md +14 -5
  282. package/docs/environment-variables.md +86 -0
  283. package/docs/extensions.md +15 -5
  284. package/docs/index.md +1 -0
  285. package/docs/models.md +9 -2
  286. package/docs/providers.md +21 -2
  287. package/docs/rpc.md +23 -6
  288. package/docs/session-format.md +2 -0
  289. package/docs/settings.md +1 -1
  290. package/docs/usage.md +0 -13
  291. package/examples/extensions/custom-compaction.ts +5 -2
  292. package/examples/extensions/custom-provider-anthropic/index.ts +9 -3
  293. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  294. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  295. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  296. package/examples/extensions/gondolin/package-lock.json +2 -2
  297. package/examples/extensions/gondolin/package.json +1 -1
  298. package/examples/extensions/handoff.ts +11 -3
  299. package/examples/extensions/message-renderer.ts +3 -3
  300. package/examples/extensions/sandbox/package-lock.json +2 -2
  301. package/examples/extensions/sandbox/package.json +1 -1
  302. package/examples/extensions/summarize.ts +5 -2
  303. package/examples/extensions/with-deps/package-lock.json +2 -2
  304. package/examples/extensions/with-deps/package.json +1 -1
  305. package/examples/sdk/12-full-control.ts +3 -1
  306. package/package.json +15 -6
  307. package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
@@ -6,8 +6,11 @@ import { resolveAsyncRunLocation } from "../runs/background/async-resume.ts";
6
6
  import { deliverStopRequest } from "../runs/background/control-channel.ts";
7
7
  import { reconcileAsyncRun } from "../runs/background/stale-run-reconciler.ts";
8
8
  import type { SubagentParamsLike } from "../runs/foreground/subagent-executor.ts";
9
+ import { resolveCurrentSessionId } from "../shared/session-identity.ts";
9
10
  import {
11
+ type AsyncJobStep,
10
12
  type Details,
13
+ type SubagentState,
11
14
  ASYNC_DIR,
12
15
  RESULTS_DIR,
13
16
  SUBAGENT_ASYNC_COMPLETE_EVENT,
@@ -23,7 +26,7 @@ export const SUBAGENT_RPC_REQUEST_EVENT = "subagents:rpc:v1:request";
23
26
  export const SUBAGENT_RPC_READY_EVENT = "subagents:rpc:v1:ready";
24
27
  export const SUBAGENT_RPC_REPLY_EVENT_PREFIX = "subagents:rpc:v1:reply:";
25
28
 
26
- export const SUBAGENT_RPC_METHODS = ["ping", "status", "spawn", "steer", "interrupt", "stop"] as const;
29
+ export const SUBAGENT_RPC_METHODS = ["ping", "status", "spawn", "steer", "interrupt", "stop", "resume"] as const;
27
30
  export type SubagentRpcMethod = typeof SUBAGENT_RPC_METHODS[number];
28
31
 
29
32
  export interface SubagentRpcRequestEnvelope {
@@ -69,6 +72,200 @@ interface EventBus {
69
72
  emit(event: string, data: unknown): void;
70
73
  }
71
74
 
75
+ export interface SubagentRpcFleetEntry {
76
+ /** Opaque key for client-side reconciliation; never a run or async identifier. */
77
+ key: string;
78
+ /** Resolved child agent/role name. */
79
+ agent: string;
80
+ role?: string;
81
+ model?: string;
82
+ effort?: string;
83
+ startedAt: number;
84
+ tokens: { input: number; output: number; total: number };
85
+ goal?: string;
86
+ }
87
+
88
+ export interface SubagentRpcFleetStatus {
89
+ version: 1;
90
+ entries: SubagentRpcFleetEntry[];
91
+ /** Total active children before the bounded entries window. */
92
+ totalActive: number;
93
+ omitted: number;
94
+ }
95
+
96
+ const MAX_FLEET_ENTRIES = 16;
97
+ const MAX_FLEET_CANDIDATES = 256;
98
+ const MAX_AGENT_LENGTH = 96;
99
+ const MAX_GOAL_LENGTH = 512;
100
+ const MAX_METADATA_LENGTH = 128;
101
+
102
+ function displayText(value: unknown, maxLength: number): string | undefined {
103
+ if (typeof value !== "string") return undefined;
104
+ // Strip complete CSI/OSC/DCS/APC/PM strings and C1 controls before collapsing
105
+ // whitespace; never leave CSI parameters behind after removing ESC.
106
+ const normalized = value.slice(0, 4_096)
107
+ .replace(/\x1b\[[0-?]*[ -/]*[@-~]|\x9b[0-?]*[ -/]*[@-~]|\x1b][\s\S]*?(?:\x07|\x1b\\)|\x1b[PX^_][\s\S]*?\x1b\\|[\u0000-\u001f\u007f-\u009f]/g, " ")
108
+ .replace(/\s+/g, " ").trim();
109
+ return normalized ? normalized.slice(0, maxLength) : undefined;
110
+ }
111
+
112
+ function publicTokens(value: unknown): { input: number; output: number; total: number } {
113
+ const record = isRecord(value) ? value : {};
114
+ const count = (field: "input" | "output" | "total") => {
115
+ const raw = record[field];
116
+ return typeof raw === "number" && Number.isFinite(raw) && raw >= 0
117
+ ? Math.min(Number.MAX_SAFE_INTEGER, Math.floor(raw))
118
+ : 0;
119
+ };
120
+ const input = count("input");
121
+ const output = count("output");
122
+ const sum = Math.min(Number.MAX_SAFE_INTEGER, input + output);
123
+ return { input, output, total: Math.max(sum, count("total")) };
124
+ }
125
+
126
+ function activeState(value: unknown): boolean {
127
+ return value === "running" || value === "queued" || value === "pending";
128
+ }
129
+
130
+ interface FleetKeyState {
131
+ sessionId: string | null;
132
+ next: number;
133
+ keys: Map<string, string>;
134
+ }
135
+
136
+ interface FleetCandidate {
137
+ internalKey: string;
138
+ agent: unknown;
139
+ role?: unknown;
140
+ model?: unknown;
141
+ effort?: unknown;
142
+ startedAt: unknown;
143
+ tokens?: unknown;
144
+ goal?: unknown;
145
+ }
146
+
147
+ function buildFleetStatus(
148
+ state: SubagentState | undefined,
149
+ keyState: FleetKeyState,
150
+ sessionId: string | null | undefined,
151
+ ): SubagentRpcFleetStatus {
152
+ const authoritativeSessionId = sessionId ?? null;
153
+ if (keyState.sessionId !== authoritativeSessionId) {
154
+ keyState.sessionId = authoritativeSessionId;
155
+ keyState.next = 0;
156
+ keyState.keys.clear();
157
+ }
158
+ if (!state || !authoritativeSessionId || state.currentSessionId !== authoritativeSessionId) {
159
+ keyState.keys.clear();
160
+ return { version: 1, entries: [], totalActive: 0, omitted: 0 };
161
+ }
162
+
163
+ let totalActive = 0;
164
+ const candidates: FleetCandidate[] = [];
165
+ const addCandidate = (candidate: FleetCandidate) => {
166
+ totalActive += 1;
167
+ if (candidates.length < MAX_FLEET_CANDIDATES) candidates.push(candidate);
168
+ };
169
+ for (const control of state.foregroundControls.values()) {
170
+ if (control.sessionId !== authoritativeSessionId) continue;
171
+ if (control.activeChildren?.size) {
172
+ for (const child of control.activeChildren.values()) addCandidate({
173
+ internalKey: `foreground:${control.runId}:${child.index}`,
174
+ agent: child.agent,
175
+ model: child.model,
176
+ effort: child.thinking,
177
+ startedAt: child.startedAt,
178
+ tokens: { input: child.inputTokens ?? 0, output: child.outputTokens ?? 0, total: child.tokens ?? 0 },
179
+ goal: child.description ?? control.description,
180
+ });
181
+ } else {
182
+ addCandidate({
183
+ internalKey: `foreground:${control.runId}:${control.currentIndex ?? 0}`,
184
+ agent: control.currentAgent ?? control.mode,
185
+ model: control.model,
186
+ effort: control.thinking,
187
+ startedAt: control.startedAt,
188
+ tokens: { input: control.inputTokens ?? 0, output: control.outputTokens ?? 0, total: control.tokens ?? 0 },
189
+ goal: control.description,
190
+ });
191
+ }
192
+ }
193
+ for (const job of state.asyncJobs.values()) {
194
+ if (job.sessionId !== authoritativeSessionId || !activeState(job.status)) continue;
195
+ const startedAt = job.startedAt ?? job.updatedAt;
196
+ const steps: AsyncJobStep[] | undefined = job.steps?.length
197
+ ? job.steps
198
+ : job.agents?.map((agent, index) => ({
199
+ agent,
200
+ index,
201
+ status: job.status === "queued" ? "pending" : "running",
202
+ }));
203
+ if (!steps?.length) {
204
+ addCandidate({
205
+ internalKey: `async:${job.asyncId}`,
206
+ agent: job.mode ?? "subagent",
207
+ startedAt,
208
+ tokens: job.totalTokens,
209
+ goal: job.description,
210
+ });
211
+ continue;
212
+ }
213
+ for (const [offset, step] of steps.entries()) {
214
+ if (!activeState(step.status)) continue;
215
+ const index = step.index ?? offset;
216
+ if (step.status === "pending" && job.mode === "chain" && !job.activeParallelGroup && index !== (job.currentStep ?? 0)) continue;
217
+ addCandidate({
218
+ internalKey: `async:${job.asyncId}:${index}`,
219
+ agent: step.agent,
220
+ role: step.label,
221
+ model: step.model,
222
+ effort: step.thinking,
223
+ startedAt: step.startedAt ?? startedAt,
224
+ tokens: step.tokens ?? (steps.length === 1 ? job.totalTokens : undefined),
225
+ goal: job.description,
226
+ });
227
+ }
228
+ }
229
+
230
+ candidates.sort((left, right) => {
231
+ const leftStarted = typeof left.startedAt === "number" ? left.startedAt : Number.MAX_SAFE_INTEGER;
232
+ const rightStarted = typeof right.startedAt === "number" ? right.startedAt : Number.MAX_SAFE_INTEGER;
233
+ return leftStarted - rightStarted || left.internalKey.localeCompare(right.internalKey);
234
+ });
235
+ const activeKeys = new Set(candidates.map((candidate) => candidate.internalKey));
236
+ const entries: SubagentRpcFleetEntry[] = [];
237
+ for (const candidate of candidates) {
238
+ if (entries.length >= MAX_FLEET_ENTRIES) break;
239
+ const agent = displayText(candidate.agent, MAX_AGENT_LENGTH);
240
+ const startedAt = candidate.startedAt;
241
+ if (!agent || typeof startedAt !== "number" || !Number.isSafeInteger(startedAt) || startedAt < 0) continue;
242
+ let key = keyState.keys.get(candidate.internalKey);
243
+ if (!key) {
244
+ key = `fleet-${++keyState.next}`;
245
+ keyState.keys.set(candidate.internalKey, key);
246
+ }
247
+ const role = displayText(candidate.role, MAX_AGENT_LENGTH);
248
+ const model = displayText(candidate.model, MAX_METADATA_LENGTH);
249
+ const effort = displayText(candidate.effort, MAX_METADATA_LENGTH);
250
+ const goal = displayText(candidate.goal, MAX_GOAL_LENGTH);
251
+ entries.push({
252
+ key,
253
+ agent,
254
+ ...(role ? { role } : {}),
255
+ ...(model ? { model } : {}),
256
+ ...(effort ? { effort } : {}),
257
+ startedAt,
258
+ tokens: publicTokens(candidate.tokens),
259
+ ...(goal ? { goal } : {}),
260
+ });
261
+ }
262
+ for (const internalKey of keyState.keys.keys()) {
263
+ if (!activeKeys.has(internalKey)) keyState.keys.delete(internalKey);
264
+ }
265
+ const omitted = Math.max(0, totalActive - entries.length);
266
+ return { version: 1, entries, totalActive, omitted };
267
+ }
268
+
72
269
  interface RegisterSubagentRpcBridgeOptions {
73
270
  events: EventBus;
74
271
  getContext: () => ExtensionContext | null;
@@ -83,6 +280,8 @@ interface RegisterSubagentRpcBridgeOptions {
83
280
  resultsDir?: string;
84
281
  kill?: (pid: number, signal?: NodeJS.Signals | 0) => boolean;
85
282
  now?: () => number;
283
+ /** Native live state, projected into the optional public fleet-status capability. */
284
+ state?: SubagentState;
86
285
  }
87
286
 
88
287
  class SubagentRpcError extends Error {
@@ -140,7 +339,9 @@ function textFromToolResult(result: AgentToolResult<Details>): string {
140
339
  .join("\n");
141
340
  }
142
341
 
143
- function dataFromToolResult(result: AgentToolResult<Details>): { text: string; details?: Details; isError?: boolean } {
342
+ type ToolResultWithError = AgentToolResult<Details> & { isError?: boolean };
343
+
344
+ function dataFromToolResult(result: ToolResultWithError): { text: string; details?: Details; isError?: boolean } {
144
345
  return {
145
346
  text: textFromToolResult(result),
146
347
  ...(result.details ? { details: result.details } : {}),
@@ -148,7 +349,7 @@ function dataFromToolResult(result: AgentToolResult<Details>): { text: string; d
148
349
  };
149
350
  }
150
351
 
151
- function failIfToolError(result: AgentToolResult<Details>): void {
352
+ function failIfToolError(result: ToolResultWithError): void {
152
353
  if (!result.isError) return;
153
354
  throw new SubagentRpcError("execution_failed", textFromToolResult(result) || "Subagent RPC execution failed.");
154
355
  }
@@ -178,11 +379,15 @@ function pingData(ctx: ExtensionContext | null) {
178
379
  methods: [...SUBAGENT_RPC_METHODS],
179
380
  capabilities: {
180
381
  status: true,
382
+ fleetStatus: { version: 1 },
181
383
  asyncSpawn: true,
182
384
  steer: true,
183
385
  nonRecoveringSteer: true,
184
386
  interrupt: true,
185
387
  stop: true,
388
+ resume: true,
389
+ launchResolvedExtensions: { version: 1, source: "launch-resolved" },
390
+ runtimeAcknowledgedExtensions: { version: 1, source: "child-runtime", event: "subagent:acknowledge-extension" },
186
391
  processTerminalProof: { version: 1, lifecycleArtifactVersion: SUBAGENT_LIFECYCLE_ARTIFACT_VERSION },
187
392
  },
188
393
  events: {
@@ -238,6 +443,24 @@ function steerParams(params: unknown): SubagentParamsLike {
238
443
  };
239
444
  }
240
445
 
446
+ function resumeParams(params: unknown): SubagentParamsLike {
447
+ const input = assertRecordParams(params, "resume");
448
+ if (typeof input.message !== "string" || !input.message.trim())
449
+ throw new SubagentRpcError("invalid_params", "RPC resume requires a non-empty message.");
450
+ const target = normalizeTargetParams(input, "resume");
451
+ if (!target.id && !target.runId && !target.dir) throw new SubagentRpcError("invalid_params", "RPC resume requires id, runId, or dir.");
452
+ if (input.output !== undefined && (typeof input.output !== "string" || !input.output.trim()))
453
+ throw new SubagentRpcError("invalid_params", "RPC resume output must be a non-empty path.");
454
+ if (input.outputMode !== undefined && input.outputMode !== "file-only")
455
+ throw new SubagentRpcError("invalid_params", "RPC resume supports only file-only output mode.");
456
+ return {
457
+ action: "resume",
458
+ ...target,
459
+ message: input.message.trim(),
460
+ ...(typeof input.output === "string" ? { output: input.output.trim(), outputMode: "file-only" } : {}),
461
+ };
462
+ }
463
+
241
464
  function stopAsyncRun(
242
465
  params: unknown,
243
466
  options: RegisterSubagentRpcBridgeOptions,
@@ -257,7 +480,7 @@ function stopAsyncRun(
257
480
  throw new SubagentRpcError("not_found", "Async run not found or already completed; stop requires a live async run directory.");
258
481
  }
259
482
 
260
- const currentSessionId = ctx.sessionManager.getSessionId();
483
+ const currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
261
484
  const initialStatus = readStatus(location.asyncDir);
262
485
  const initialRunId = initialStatus?.runId ?? location.resolvedId ?? path.basename(location.asyncDir);
263
486
  if (!initialStatus) throw new SubagentRpcError("not_found", `Status file not found for async run '${initialRunId}'.`);
@@ -304,6 +527,7 @@ function stopAsyncRun(
304
527
  async function handleRequest(
305
528
  request: SubagentRpcRequestEnvelope,
306
529
  options: RegisterSubagentRpcBridgeOptions,
530
+ fleetKeys: FleetKeyState,
307
531
  ): Promise<unknown> {
308
532
  const ctx = options.getContext();
309
533
  if (request.method === "ping") return pingData(ctx);
@@ -313,7 +537,21 @@ async function handleRequest(
313
537
  return executeChecked(options, ctx, request.requestId, request.method, spawnParams(request.params));
314
538
  }
315
539
  if (request.method === "status") {
316
- return executeChecked(options, ctx, request.requestId, request.method, { action: "status", ...normalizeTargetParams(request.params, "status") });
540
+ const status = await executeChecked(
541
+ options,
542
+ ctx,
543
+ request.requestId,
544
+ request.method,
545
+ { action: "status", ...normalizeTargetParams(request.params, "status") },
546
+ );
547
+ return {
548
+ ...status,
549
+ fleet: buildFleetStatus(
550
+ options.state,
551
+ fleetKeys,
552
+ resolveCurrentSessionId(ctx.sessionManager),
553
+ ),
554
+ };
317
555
  }
318
556
  if (request.method === "steer") {
319
557
  return executeChecked(options, ctx, request.requestId, request.method, steerParams(request.params));
@@ -324,6 +562,9 @@ async function handleRequest(
324
562
  if (request.method === "stop") {
325
563
  return stopAsyncRun(request.params, options, ctx);
326
564
  }
565
+ if (request.method === "resume") {
566
+ return executeChecked(options, ctx, request.requestId, request.method, resumeParams(request.params));
567
+ }
327
568
  throw new SubagentRpcError("unsupported_method", `Unsupported subagent RPC method: ${String(request.method)}`);
328
569
  }
329
570
 
@@ -377,11 +618,12 @@ export function registerSubagentRpcBridge(options: RegisterSubagentRpcBridgeOpti
377
618
  emitReady: (ctx?: ExtensionContext | null) => void;
378
619
  dispose: () => void;
379
620
  } {
621
+ const fleetKeys: FleetKeyState = { sessionId: null, next: 0, keys: new Map() };
380
622
  const unsubscribe = options.events.on(SUBAGENT_RPC_REQUEST_EVENT, async (raw) => {
381
623
  let request: SubagentRpcRequestEnvelope | undefined;
382
624
  try {
383
625
  request = parseRequest(raw);
384
- const data = await handleRequest(request, options);
626
+ const data = await handleRequest(request, options, fleetKeys);
385
627
  options.events.emit(subagentRpcReplyEvent(request.requestId), {
386
628
  version: SUBAGENT_RPC_PROTOCOL_VERSION,
387
629
  requestId: request.requestId,
@@ -65,6 +65,18 @@ const JsonSchemaObject = Type.Unsafe({
65
65
  description: "JSON Schema object for strict structured output. Non-object roots are rejected.",
66
66
  });
67
67
 
68
+ const AcceptanceEvidenceKinds = [
69
+ "changed-files",
70
+ "tests-added",
71
+ "commands-run",
72
+ "validation-output",
73
+ "residual-risks",
74
+ "no-staged-files",
75
+ "diff-summary",
76
+ "review-findings",
77
+ "manual-notes",
78
+ ];
79
+
68
80
  const AcceptanceOverride = Type.Unsafe({
69
81
  anyOf: [
70
82
  { type: "string", enum: ["auto", "attested", "checked", "verified"] },
@@ -77,7 +89,7 @@ const AcceptanceOverride = Type.Unsafe({
77
89
  { type: "boolean", enum: [false] },
78
90
  { type: "object", additionalProperties: true },
79
91
  ],
80
- description: "Optional acceptance policy. For reviewer/read-only calls, omit acceptance. Evidence levels end at verified; require independent review with acceptance.review.required. The value reviewed is an achieved status and is accepted by the schema only for actionable preflight recovery. In the current/default contract, omitted means auto-inferred. With agentContract.version=1, omitted means not requested and acceptance failures are reported separately from execution.",
92
+ description: `Optional acceptance policy. For reviewer/read-only calls, omit acceptance. Example: { level: "checked", evidence: ["commands-run", "changed-files"] }. Supported evidence kinds: ${AcceptanceEvidenceKinds.join(", ")}. Evidence levels end at verified; use acceptance.review.required for review. Omitted means auto-inferred unless agentContract.version=1.`,
81
93
  });
82
94
 
83
95
  const AgentContractOverride = Type.Object({
@@ -107,6 +119,16 @@ const ToolBudgetOverride = Type.Object({
107
119
  block: Type.Optional(ToolBudgetBlock),
108
120
  }, { additionalProperties: false, description: "Optional child tool-call budget. soft nudges the child; after hard, block tools (default read/grep/find/ls, or '*' for all tools) are blocked so the child can finalize." });
109
121
 
122
+ const UsageBudgetLimitOverride = Type.Object({
123
+ soft: Type.Optional(Type.Number({ exclusiveMinimum: 0 })),
124
+ hard: Type.Number({ exclusiveMinimum: 0 }),
125
+ }, { additionalProperties: false });
126
+
127
+ const UsageBudgetOverride = Type.Object({
128
+ tokens: Type.Optional(UsageBudgetLimitOverride),
129
+ costUsd: Type.Optional(UsageBudgetLimitOverride),
130
+ }, { additionalProperties: false, description: "Optional root-only reported-usage budget. Hard limits prevent future child launches; running children are not stopped." });
131
+
110
132
  const TaskItem = Type.Object({
111
133
  agent: Type.String(),
112
134
  task: Type.String(),
@@ -183,6 +205,8 @@ export const DynamicCollectSchema = Type.Object({
183
205
 
184
206
  // Flattened so chain steps do not need an object-shape anyOf/oneOf union.
185
207
  export const ChainItem = Type.Object({
208
+ checkpoint: Type.Optional(Type.String({ description: "Approval checkpoint name. Pauses the chain without launching a child until approve-checkpoint or reject-checkpoint is called." })),
209
+ message: Type.Optional(Type.String({ description: "Optional approval message shown while the checkpoint is paused." })),
186
210
  agent: Type.Optional(Type.String({ description: "Sequential step agent name" })),
187
211
  task: Type.Optional(Type.String({
188
212
  description: "Task template with variables: {task}=original request, {previous}=prior step's text response, {chain_dir}=shared folder, {outputs.name}=prior named output. Required for first step, defaults to '{previous}' for subsequent steps."
@@ -217,7 +241,7 @@ export const ChainItem = Type.Object({
217
241
  description: "Create isolated git worktrees for each parallel task."
218
242
  })),
219
243
  }, {
220
- description: "Chain step: use {agent, task?, ...} for sequential, {parallel: [...]} for static concurrent execution, or {expand, parallel: {...}, collect} for dynamic fanout.",
244
+ description: "Chain step: use {agent, task?, ...} for sequential, {parallel: [...]} for static concurrent execution, {expand, parallel: {...}, collect} for dynamic fanout, or {checkpoint: name, message?} for an approval pause.",
221
245
  additionalProperties: false,
222
246
  });
223
247
 
@@ -244,10 +268,10 @@ const SubagentParamsSchema = Type.Object({
244
268
  description: "Optional management/control action. Omit this field entirely for execution/delegation ({agent, task}, {tasks}, or {chain}); use it only for management/control actions."
245
269
  })),
246
270
  id: Type.Optional(Type.String({
247
- description: "Run id or prefix for action='status', action='interrupt', action='stop', action='resume', action='steer', or action='append-step'."
271
+ description: "Run id or prefix for action='status', action='interrupt', action='stop', action='resume', action='steer', action='append-step', action='approve-checkpoint', or action='reject-checkpoint'."
248
272
  })),
249
273
  runId: Type.Optional(Type.String({
250
- description: "Target run ID for action='interrupt', action='stop', action='resume', action='steer', or action='append-step'. Prefer id for new calls."
274
+ description: "Target run ID for action='interrupt', action='stop', action='resume', action='steer', action='append-step', action='approve-checkpoint', or action='reject-checkpoint'. Prefer id for new calls."
251
275
  })),
252
276
  dir: Type.Optional(Type.String({
253
277
  description: "Async run directory for action='status', action='stop', action='resume', or action='steer'."
@@ -290,10 +314,11 @@ const SubagentParamsSchema = Type.Object({
290
314
  })),
291
315
  chainDir: Type.Optional(Type.String({ description: "Persistent chain artifact directory; defaults to user-scoped temp storage." })),
292
316
  async: Type.Optional(Type.Boolean({ description: "Run in background (default: false, or per config)" })),
293
- timeoutMs: Type.Optional(Type.Integer({ minimum: 1, description: "Optional run-level timeout in ms for foreground and async/background runs. Alias of maxRuntimeMs." })),
294
- maxRuntimeMs: Type.Optional(Type.Integer({ minimum: 1, description: "Alias of timeoutMs for optional run-level timeout in foreground and async/background runs." })),
317
+ timeoutMs: Type.Optional(Type.Integer({ minimum: 1, description: "Timeout for foreground and async/background runs; foreground defaults to 30m absent call/agent. Alias maxRuntimeMs." })),
318
+ maxRuntimeMs: Type.Optional(Type.Integer({ minimum: 1, description: "Alias timeoutMs for foreground and async/background runs; foreground defaults to 30m absent call/agent." })),
295
319
  turnBudget: Type.Optional(TurnBudgetOverride),
296
320
  toolBudget: Type.Optional(ToolBudgetOverride),
321
+ usageBudget: Type.Optional(UsageBudgetOverride),
297
322
  agentScope: Type.Optional(Type.String({ description: "Agent discovery scope: 'user', 'project', or 'both' (default: 'both'; project wins on name collisions)" })),
298
323
  cwd: Type.Optional(Type.String()),
299
324
  artifacts: Type.Optional(Type.Boolean({ description: "Write debug artifacts (default: true)" })),
@@ -8,7 +8,7 @@ const CUSTOM_TOOL_DESCRIPTION_MAX_BYTES = 50 * 1024;
8
8
 
9
9
  export const SUBAGENT_SAFETY_GUIDANCE = `SAFETY-CRITICAL SUBAGENT GUIDANCE:
10
10
  • Use { action: "list" } before execution and only run executable/non-disabled agents or chains.
11
- • Keep execution and management separate: omit action for SINGLE/PARALLEL/CHAIN execution; use action only for list/get/models/create/update/delete/status/grant-spawn-budget/interrupt/stop/resume/append-step/doctor.
11
+ • Keep execution and management separate: omit action for SINGLE/PARALLEL/CHAIN execution; use action only for list/get/models/create/update/delete/status/grant-spawn-budget/interrupt/stop/resume/steer/append-step/approve-checkpoint/reject-checkpoint/doctor.
12
12
  • Async/background runs: launch with async:true only when work can proceed independently. Do not sleep or poll status just to wait. In an interactive session, normally return control and let Pi wake you; do not call subagent_wait merely to wait. Override that default and call subagent_wait when the current request is run-to-completion — for example, the user asked you to report results back before continuing or a skill must finish in one turn. Headless sessions auto-drain current-session work at agent_end; use subagent_wait when this turn must receive results before it ends.
13
13
  • Child-safety boundary: ordinary child subagents are not orchestrators and must not run subagents. Only explicitly configured fanout children may use the child-safe subagent tool, still bounded by depth/session limits.
14
14
  • Writing/review safety: keep one writer for the same cwd/worktree. Use fresh-context read-only reviewers/validators for independent review, then have the parent synthesize and apply fixes as the sole writer unless an isolated worktree was intentionally requested.
@@ -19,11 +19,11 @@ export const FULL_SUBAGENT_TOOL_DESCRIPTION = `To delegate work, call with { age
19
19
  EXECUTION (use exactly ONE mode):
20
20
  • Before executing, use { action: "list" } to inspect configured agents/chains. Only execute agents listed as executable/non-disabled.
21
21
  • SINGLE: { agent, task? } - one task; omit task for self-contained agents
22
- • CHAIN: { chain: [{agent:"agent-a"}, {parallel:[{agent:"agent-b",count:3}]}] } - sequential pipeline with optional parallel fan-out
22
+ • CHAIN: { chain: [{agent:"agent-a"}, {checkpoint:"review"}, {parallel:[{agent:"agent-b",count:3}]}] } - sequential pipeline with optional approval checkpoints and parallel fan-out
23
23
  • PARALLEL: { tasks: [{agent,task,count?,output?,reads?,progress?}, ...], concurrency?: number, worktree?: true } - concurrent execution (worktree: isolate each task in a git worktree)
24
24
  • Optional context: { context: "fresh" | "fork" } (explicit value overrides every child; when omitted, each requested agent uses its own defaultContext, otherwise "fresh"; inspect agent defaults via { action: "list" })
25
25
  • Fork thinking: model strings accept a thinking suffix (provider/model:off|minimal|low|medium|high|xhigh|max). Forking over a parent transcript that carries signed Anthropic thinking blocks forces thinking off only when a child's effective primary or fallback model resolves to the Anthropic provider or anthropic-messages API; unresolved models are treated conservatively. The result notes affected children, including on failures. Use fresh context when an Anthropic child needs thinking.
26
- • Optional timeout: { timeoutMs } or { maxRuntimeMs } sets a run-level max runtime for foreground and async/background runs
26
+ • Optional timeout: { timeoutMs } or { maxRuntimeMs } sets a run-level max runtime for foreground and async/background runs; foreground defaults to 30 minutes only when neither value nor an agent timeout is provided
27
27
  • Acceptance: omit acceptance for reviewer/read-only calls. Evidence levels end at verified. Use acceptance.review.required to require independent review of a writer result. Never request acceptance:"reviewed"; reviewed is achieved only after an independent reviewer result.
28
28
  • If { action: "list" } shows proactive skill subagent suggestions, consider a small fresh-context fanout for broad tasks where one of those skills would materially help
29
29
 
@@ -35,7 +35,7 @@ CHAIN TEMPLATE VARIABLES (use in task strings):
35
35
  CHAIN EXAMPLES (quick reference for the nested schema):
36
36
  • Sequential: { chain: [{agent:"agent-a", task:"Analyze {task}"}, {agent:"agent-b", task:"Plan based on {previous}"}] }
37
37
  • Parallel fan-out: { chain: [{parallel: [{agent:"agent-a", task:"Check part of {task}", count: 3}]}] }
38
- • Mixed: { chain: [{agent:"agent-a", task:"Research {task}"}, {parallel: [{agent:"agent-b", task:"Review {previous}", count: 2}]}, {agent:"agent-c", task:"Summarize {previous}"}] }
38
+ • Mixed: { chain: [{agent:"agent-a", task:"Research {task}"}, {checkpoint:"review", message:"Approve implementation?"}, {parallel: [{agent:"agent-b", task:"Review {previous}", count: 2}]}, {agent:"agent-c", task:"Summarize {previous}"}] }
39
39
 
40
40
  MANAGEMENT (use action field, omit agent/task/chain/tasks):
41
41
  • { action: "list" } - discover executable agents/chains
@@ -63,6 +63,7 @@ CONTROL:
63
63
  • { action: "resume", id: "...", message: "...", index?: 0 } - revive a paused, completed, or failed async/foreground child from its session; stopped runs are non-resumable; routed nested runs may accept live follow-ups; use steer for a live top-level async child
64
64
  • { action: "steer", id: "...", message: "...", index?: 0 } - await correlated child-Pi input acceptance for up to 3 seconds; returns delivered, scheduled, pending, partial, recovered, or failed with a request id. Only top-level single runs may recover after a further 15-second pause/revival bound; chain, parallel, and nested runs never auto-interrupt.
65
65
  • { action: "append-step", id: "...", chain: [{agent:"agent-c", task:"Use {previous}"}] } - append one step to the tail of a running async chain
66
+ • { action: "approve-checkpoint", id: "..." } / { action: "reject-checkpoint", id: "..." } - decide a paused current-session async chain checkpoint
66
67
 
67
68
  SCHEDULE (opt-in; requires { "scheduledRuns": { "enabled": true } } in config.json):
68
69
  • { action: "schedule", agent, task?, schedule: "+10m" | "2030-01-01T09:00:00Z", scheduleName? } - defer a subagent launch until a future time. Also accepts tasks[] or chain[]. Scheduled runs always launch async with fresh context; they become normal tracked async runs once they fire. Only schedule explicit delayed runs the user asked for.
@@ -79,8 +80,8 @@ export const COMPACT_SUBAGENT_TOOL_DESCRIPTION = `To delegate work, call with {
79
80
 
80
81
  EXECUTE:
81
82
  • Before execution, call { action: "list" }; run only executable/non-disabled configured agents/chains.
82
- • SINGLE {agent, task?}; PARALLEL {tasks:[{agent,task,count?,output?,reads?,progress?}], concurrency?, worktree?}; CHAIN {chain:[{agent,task?},{parallel:[...]}]}.
83
- • context can be "fresh" or "fork"; omitted uses each agent defaultContext, otherwise fresh. timeoutMs/maxRuntimeMs apply to foreground and async/background runs.
83
+ • SINGLE {agent, task?}; PARALLEL {tasks:[{agent,task,count?,output?,reads?,progress?}], concurrency?, worktree?}; CHAIN {chain:[{agent,task?},{checkpoint:"review"},{parallel:[...]}]}.
84
+ • context can be "fresh" or "fork"; omitted uses each agent defaultContext, otherwise fresh. timeoutMs/maxRuntimeMs apply to foreground and async/background runs; foreground defaults to 30 minutes only when neither value nor an agent timeout is provided.
84
85
  • Omit acceptance for reviewer/read-only calls. Evidence levels end at verified; use acceptance.review.required for independent writer review. reviewed is an achieved status, never an explicit input.
85
86
  • Chain templates may use {task}, {previous}, {chain_dir}, and named outputs. Parallel worktree isolation requires a clean git repo.
86
87
  • Chain example: { chain: [{agent:"agent-a", task:"Analyze {task}"}, {parallel: [{agent:"agent-b", task:"Check {previous}", count: 3}]}] }
@@ -89,7 +90,7 @@ EXECUTE:
89
90
  MANAGE / CONTROL:
90
91
  • Use action without execution fields: list, get, models, create, update, delete, eject, disable, enable, reset, grant-spawn-budget, doctor, watchdog.status, watchdog.check, watchdog.recommend-model, watchdog.configure.
91
92
  • Agent acceptanceRole (read-only or writer) affects inferred acceptance only, never tools. Explicit task intent wins; omission keeps name heuristics. Update with false or an empty string to clear it.
92
- • Async control actions: status, interrupt, stop, resume, steer, append-step. Use stop with an id for current-session top-level async runs. Use status view:"fleet" for active-run overview, view:"transcript" to tail child output, steer for acknowledged top-level live async guidance, and resume for paused/completed/failed revival or a routed nested follow-up. Stopped runs are non-resumable. Steering delivery means Pi accepted the correlated user input, not model compliance; use index for a specific child.
93
+ • Async control actions: status, interrupt, stop, resume, steer, append-step, approve-checkpoint, reject-checkpoint. Use stop with an id for current-session top-level async runs. Use status view:"fleet" for active-run overview, view:"transcript" to tail child output, steer for acknowledged top-level live async guidance, and resume for paused/completed/failed revival or a routed nested follow-up. Stopped runs are non-resumable. Steering delivery means Pi accepted the correlated user input, not model compliance; use index for a specific child.
93
94
  • Opt-in schedule actions: schedule, schedule-list, schedule-status, schedule-cancel. Schedule only explicit delayed runs the user asked for.
94
95
 
95
96
  ASYNC / WAIT:
@@ -16,6 +16,7 @@ function defaultSubagentConfigDir(agentDir = defaultAgentDir()): string {
16
16
  }
17
17
 
18
18
  const DEFAULT_INTERCOM_TARGET_PREFIX = "subagent-chat";
19
+ export const PI_INTERCOM_SESSION_ID_ENV = "PI_INTERCOM_SESSION_ID";
19
20
  export const INTERCOM_BRIDGE_MARKER = "Intercom orchestration channel:";
20
21
  const DEFAULT_INTERCOM_BRIDGE_TEMPLATE = `The inherited thread is reference-only. Do not continue that conversation or send questions, status updates, or completion handoffs to the supervisor in normal assistant text.
21
22
 
@@ -32,6 +33,7 @@ Do not use contact_supervisor or intercom for routine completion handoffs. If no
32
33
  export interface IntercomBridgeState {
33
34
  active: boolean;
34
35
  mode: IntercomBridgeMode;
36
+ resultDelivery: boolean;
35
37
  orchestratorTarget?: string;
36
38
  extensionDir: string;
37
39
  instruction: string;
@@ -55,10 +57,11 @@ interface ResolveIntercomBridgeInput {
55
57
  agentDir?: string;
56
58
  }
57
59
 
58
- export function resolveIntercomSessionTarget(sessionName: string | undefined, sessionId: string): string {
60
+ export function resolveIntercomSessionTarget(sessionName: string | undefined, sessionId: string, intercomSessionId = process.env[PI_INTERCOM_SESSION_ID_ENV]): string {
59
61
  const trimmedName = sessionName?.trim();
60
62
  if (trimmedName) return trimmedName;
61
- const normalizedSessionId = sessionId.startsWith("session-") ? sessionId.slice("session-".length) : sessionId;
63
+ const fallbackSessionId = intercomSessionId?.trim() || sessionId;
64
+ const normalizedSessionId = fallbackSessionId.startsWith("session-") ? fallbackSessionId.slice("session-".length) : fallbackSessionId;
62
65
  return `${DEFAULT_INTERCOM_TARGET_PREFIX}-${normalizedSessionId.slice(0, 8)}`;
63
66
  }
64
67
 
@@ -78,11 +81,12 @@ export function resolveIntercomBridgeMode(value: unknown): IntercomBridgeMode {
78
81
 
79
82
  function resolveIntercomBridgeConfig(value: ExtensionConfig["intercomBridge"]): Required<IntercomBridgeConfig> {
80
83
  if (!value || typeof value !== "object" || Array.isArray(value)) {
81
- return { mode: "always", instructionFile: "" };
84
+ return { mode: "always", instructionFile: "", resultDelivery: true };
82
85
  }
83
86
  return {
84
87
  mode: resolveIntercomBridgeMode(value.mode),
85
88
  instructionFile: typeof value.instructionFile === "string" ? value.instructionFile : "",
89
+ resultDelivery: value.resultDelivery !== false,
86
90
  };
87
91
  }
88
92
 
@@ -146,11 +150,12 @@ export function resolveIntercomBridge(input: ResolveIntercomBridgeInput): Interc
146
150
  );
147
151
  const reason = inactiveReason(mode, input.context, orchestratorTarget);
148
152
  if (reason || !orchestratorTarget) {
149
- return { active: false, mode, extensionDir: NATIVE_INTERCOM_EXTENSION_DIR, instruction: defaultInstruction };
153
+ return { active: false, mode, resultDelivery: config.resultDelivery, extensionDir: NATIVE_INTERCOM_EXTENSION_DIR, instruction: defaultInstruction };
150
154
  }
151
155
  return {
152
156
  active: true,
153
157
  mode,
158
+ resultDelivery: config.resultDelivery,
154
159
  orchestratorTarget,
155
160
  extensionDir: NATIVE_INTERCOM_EXTENSION_DIR,
156
161
  instruction: buildIntercomBridgeInstruction(orchestratorTarget, resolveInstructionTemplate(config.instructionFile, settingsDir)),
@@ -1,5 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import * as fs from "node:fs";
3
+ import { isUnexplainedProcessSignal } from "../runs/shared/process-signal.ts";
3
4
  import {
4
5
  type Details,
5
6
  type IntercomEventBus,
@@ -10,6 +11,7 @@ import {
10
11
  type SubagentResultIntercomChild,
11
12
  type SubagentResultIntercomPayload,
12
13
  type SubagentResultStatus,
14
+ type SubagentOutputState,
13
15
  type SubagentRunMode,
14
16
  SUBAGENT_RESULT_INTERCOM_DELIVERY_EVENT,
15
17
  SUBAGENT_RESULT_INTERCOM_EVENT,
@@ -21,11 +23,17 @@ export function resolveSubagentResultStatus(input: {
21
23
  state?: string;
22
24
  interrupted?: boolean;
23
25
  detached?: boolean;
26
+ processSignal?: string | null;
27
+ timedOut?: boolean;
28
+ stopped?: boolean;
29
+ turnBudgetExceeded?: boolean;
24
30
  }): SubagentResultStatus {
25
31
  if (input.detached) return "detached";
26
- if (input.state === "stopped") return "stopped";
32
+ if (input.stopped || input.state === "stopped") return "stopped";
27
33
  if (input.interrupted || input.state === "paused") return "paused";
28
- if (typeof input.success === "boolean") return input.success ? "completed" : "failed";
34
+ if (input.success === true) return "completed";
35
+ if (isUnexplainedProcessSignal(input) && input.exitCode !== 0) return "stopped";
36
+ if (input.success === false) return "failed";
29
37
  if (input.state === "complete") return "completed";
30
38
  if (input.state === "failed") return "failed";
31
39
  if (typeof input.exitCode === "number") return input.exitCode === 0 ? "completed" : "failed";
@@ -57,6 +65,21 @@ function formatStatusCounts(counts: Record<SubagentResultStatus, number>): strin
57
65
  return parts.length ? parts.join(", ") : "0 results";
58
66
  }
59
67
 
68
+ function countOutputStates(children: SubagentResultIntercomChild[]): Record<SubagentOutputState, number> {
69
+ const counts: Record<SubagentOutputState, number> = { present: 0, absent: 0, unknown: 0 };
70
+ for (const child of children) counts[child.outputState ?? "unknown"] += 1;
71
+ return counts;
72
+ }
73
+
74
+ function formatOutputCounts(counts: Record<SubagentOutputState, number>): string {
75
+ const parts = [
76
+ counts.present ? `${counts.present} present` : undefined,
77
+ counts.absent ? `${counts.absent} absent` : undefined,
78
+ counts.unknown ? `${counts.unknown} unknown` : undefined,
79
+ ].filter((part): part is string => Boolean(part));
80
+ return parts.length ? parts.join(", ") : "0 outputs";
81
+ }
82
+
60
83
  function resolveGroupedStatus(children: SubagentResultIntercomChild[]): SubagentResultStatus {
61
84
  const counts = countStatuses(children);
62
85
  if (counts.failed > 0) return "failed";
@@ -212,14 +235,19 @@ function formatSubagentResultIntercomMessage(input: {
212
235
  parallelHandoff?: ParallelHandoffReference;
213
236
  }): string {
214
237
  const counts = countStatuses(input.children);
238
+ const outputCounts = countOutputStates(input.children);
215
239
  const lines: string[] = [
216
240
  "subagent results",
217
241
  "",
218
242
  `Run: ${input.runId}`,
219
243
  `Mode: ${input.mode}`,
220
- `Status: ${input.status}`,
244
+ `Process status: ${input.status}`,
221
245
  `Children: ${formatStatusCounts(counts)}`,
246
+ `Outputs: ${formatOutputCounts(outputCounts)} (semantic adequacy unassessed)`,
222
247
  ];
248
+ if (input.children.some((child) => child.status === "failed" && child.outputState === "present")) {
249
+ lines.push("Recovery: At least one failed process produced output. Inspect that output before retrying; output presence does not establish task completion.");
250
+ }
223
251
  if (input.mode === "chain" && typeof input.chainSteps === "number") {
224
252
  lines.push(`Chain steps: ${input.chainSteps}`);
225
253
  }
@@ -238,7 +266,7 @@ function formatSubagentResultIntercomMessage(input: {
238
266
  for (let index = 0; index < input.children.length; index++) {
239
267
  const child = input.children[index]!;
240
268
  lines.push("");
241
- lines.push(`${index + 1}. ${child.agent} — ${child.status}`);
269
+ lines.push(`${index + 1}. ${child.agent} — process ${child.status} · output ${child.outputState ?? "unknown"}`);
242
270
  if (child.intercomTarget) lines.push(`${input.source === "async" ? "Previous intercom target" : "Run intercom target"}: ${child.intercomTarget}`);
243
271
  if (child.artifactPath) lines.push(`Output artifact: ${child.artifactPath}`);
244
272
  if (child.sessionPath) lines.push(`Session: ${child.sessionPath}`);
@@ -253,6 +281,7 @@ function formatSubagentResultIntercomMessage(input: {
253
281
  export function buildSubagentResultIntercomPayload(input: GroupedResultIntercomMessageInput): SubagentResultIntercomPayload {
254
282
  const children = input.children.map((child) => ({
255
283
  ...child,
284
+ outputState: child.outputState ?? "unknown",
256
285
  summary: child.summary.trim() || "(no output)",
257
286
  children: compactNestedResultChildren(child.children),
258
287
  }));