@selesai/code 0.5.28 → 0.6.1

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 (341) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +1 -1
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +9 -1
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/cli/config-selector.d.ts.map +1 -1
  7. package/dist/cli/config-selector.js +1 -1
  8. package/dist/cli/config-selector.js.map +1 -1
  9. package/dist/cli/credential-print.d.ts +23 -0
  10. package/dist/cli/credential-print.d.ts.map +1 -0
  11. package/dist/cli/credential-print.js +117 -0
  12. package/dist/cli/credential-print.js.map +1 -0
  13. package/dist/cli/startup-ui.d.ts.map +1 -1
  14. package/dist/cli/startup-ui.js +1 -1
  15. package/dist/cli/startup-ui.js.map +1 -1
  16. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  17. package/dist/core/agent-session-runtime.js +3 -0
  18. package/dist/core/agent-session-runtime.js.map +1 -1
  19. package/dist/core/agent-session.d.ts +12 -1
  20. package/dist/core/agent-session.d.ts.map +1 -1
  21. package/dist/core/agent-session.js +20 -14
  22. package/dist/core/agent-session.js.map +1 -1
  23. package/dist/core/compaction/compaction.d.ts.map +1 -1
  24. package/dist/core/compaction/compaction.js +11 -3
  25. package/dist/core/compaction/compaction.js.map +1 -1
  26. package/dist/core/extensions/runner.d.ts +1 -0
  27. package/dist/core/extensions/runner.d.ts.map +1 -1
  28. package/dist/core/extensions/runner.js +11 -0
  29. package/dist/core/extensions/runner.js.map +1 -1
  30. package/dist/core/extensions/types.d.ts +14 -1
  31. package/dist/core/extensions/types.d.ts.map +1 -1
  32. package/dist/core/extensions/types.js.map +1 -1
  33. package/dist/core/footer-data-provider.d.ts +10 -0
  34. package/dist/core/footer-data-provider.d.ts.map +1 -1
  35. package/dist/core/footer-data-provider.js +1 -1
  36. package/dist/core/footer-data-provider.js.map +1 -1
  37. package/dist/core/llama/provider.d.ts.map +1 -1
  38. package/dist/core/llama/provider.js +8 -3
  39. package/dist/core/llama/provider.js.map +1 -1
  40. package/dist/core/model-config.d.ts +30 -0
  41. package/dist/core/model-config.d.ts.map +1 -1
  42. package/dist/core/model-config.js +6 -0
  43. package/dist/core/model-config.js.map +1 -1
  44. package/dist/core/model-registry.d.ts.map +1 -1
  45. package/dist/core/model-registry.js +2 -2
  46. package/dist/core/model-registry.js.map +1 -1
  47. package/dist/core/model-resolver.d.ts +1 -0
  48. package/dist/core/model-resolver.d.ts.map +1 -1
  49. package/dist/core/model-resolver.js +20 -3
  50. package/dist/core/model-resolver.js.map +1 -1
  51. package/dist/core/model-runtime.d.ts +2 -0
  52. package/dist/core/model-runtime.d.ts.map +1 -1
  53. package/dist/core/model-runtime.js +5 -4
  54. package/dist/core/model-runtime.js.map +1 -1
  55. package/dist/core/package-manager.d.ts.map +1 -1
  56. package/dist/core/package-manager.js +13 -6
  57. package/dist/core/package-manager.js.map +1 -1
  58. package/dist/core/remote-catalog-provider.d.ts +1 -1
  59. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  60. package/dist/core/remote-catalog-provider.js +24 -11
  61. package/dist/core/remote-catalog-provider.js.map +1 -1
  62. package/dist/core/resource-loader.d.ts +15 -0
  63. package/dist/core/resource-loader.d.ts.map +1 -1
  64. package/dist/core/resource-loader.js +66 -9
  65. package/dist/core/resource-loader.js.map +1 -1
  66. package/dist/core/settings-manager.d.ts +1 -1
  67. package/dist/core/settings-manager.d.ts.map +1 -1
  68. package/dist/core/settings-manager.js.map +1 -1
  69. package/dist/core/system-prompt.d.ts.map +1 -1
  70. package/dist/core/system-prompt.js +19 -1
  71. package/dist/core/system-prompt.js.map +1 -1
  72. package/dist/core/system-prompt.test.d.ts +2 -0
  73. package/dist/core/system-prompt.test.d.ts.map +1 -0
  74. package/dist/core/system-prompt.test.js +89 -0
  75. package/dist/core/system-prompt.test.js.map +1 -0
  76. package/dist/core/tools/bash.d.ts +2 -0
  77. package/dist/core/tools/bash.d.ts.map +1 -1
  78. package/dist/core/tools/bash.js +34 -5
  79. package/dist/core/tools/bash.js.map +1 -1
  80. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  81. package/dist/core/tools/tool-definition-wrapper.js +3 -1
  82. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  83. package/dist/defaults/models.json +13 -45
  84. package/dist/defaults/settings.json +1 -2
  85. package/dist/extensions/copy-turn.test.ts +131 -0
  86. package/dist/extensions/copy-turn.ts +6 -1
  87. package/dist/extensions/package.json +0 -1
  88. package/dist/extensions/pi-intercom/CHANGELOG.md +249 -0
  89. package/dist/extensions/pi-intercom/README.md +102 -39
  90. package/dist/extensions/pi-intercom/broker/broker.ts +1233 -36
  91. package/dist/extensions/pi-intercom/broker/client.test.ts +83 -0
  92. package/dist/extensions/pi-intercom/broker/client.ts +315 -12
  93. package/dist/extensions/pi-intercom/broker/extension-state.ts +186 -0
  94. package/dist/extensions/pi-intercom/broker/extension.test.ts +387 -0
  95. package/dist/extensions/pi-intercom/broker/framing.test.ts +114 -0
  96. package/dist/extensions/pi-intercom/broker/framing.ts +82 -24
  97. package/dist/extensions/pi-intercom/broker/paths.test.ts +153 -0
  98. package/dist/extensions/pi-intercom/broker/paths.ts +117 -8
  99. package/dist/extensions/pi-intercom/broker/runtime-claim.test.ts +34 -0
  100. package/dist/extensions/pi-intercom/broker/runtime-claim.ts +21 -0
  101. package/dist/extensions/pi-intercom/broker/spawn.test.ts +160 -23
  102. package/dist/extensions/pi-intercom/broker/spawn.ts +113 -27
  103. package/dist/extensions/pi-intercom/config.test.ts +93 -0
  104. package/dist/extensions/pi-intercom/config.ts +55 -6
  105. package/dist/extensions/pi-intercom/cwd.test.ts +40 -0
  106. package/dist/extensions/pi-intercom/cwd.ts +31 -0
  107. package/dist/extensions/pi-intercom/extension-api.ts +44 -0
  108. package/dist/extensions/pi-intercom/format-context.test.ts +31 -0
  109. package/dist/extensions/pi-intercom/format-context.ts +32 -0
  110. package/dist/extensions/pi-intercom/index.ts +742 -145
  111. package/dist/extensions/pi-intercom/intercom.integration.test.ts +2646 -0
  112. package/dist/extensions/pi-intercom/package.json +15 -5
  113. package/dist/extensions/pi-intercom/reply-tracker.test.ts +134 -0
  114. package/dist/extensions/pi-intercom/reply-tracker.ts +31 -13
  115. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +13 -11
  116. package/dist/extensions/pi-intercom/test/inline-message.test.ts +184 -0
  117. package/dist/extensions/pi-intercom/test/overlay-width.test.ts +66 -0
  118. package/dist/extensions/pi-intercom/types.ts +94 -4
  119. package/dist/extensions/pi-intercom/ui/compose.ts +8 -4
  120. package/dist/extensions/pi-intercom/ui/inline-message.ts +61 -25
  121. package/dist/extensions/pi-intercom/ui/session-list.ts +7 -3
  122. package/dist/extensions/pi-subagents/CHANGELOG.md +88 -0
  123. package/dist/extensions/pi-subagents/LICENSE +21 -0
  124. package/dist/extensions/pi-subagents/README.md +158 -69
  125. package/dist/extensions/pi-subagents/agents/architect.md +5 -4
  126. package/dist/extensions/pi-subagents/agents/builder.md +6 -4
  127. package/dist/extensions/pi-subagents/agents/commentator.md +3 -2
  128. package/dist/extensions/pi-subagents/agents/explorer.md +3 -2
  129. package/dist/extensions/pi-subagents/agents/recapper.md +3 -2
  130. package/dist/extensions/pi-subagents/agents/researcher.md +4 -3
  131. package/dist/extensions/pi-subagents/package-lock.json +2 -2
  132. package/dist/extensions/pi-subagents/package.json +3 -3
  133. package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
  134. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +22 -988
  135. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +257 -0
  136. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +431 -0
  137. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +144 -0
  138. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +281 -0
  139. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +125 -37
  140. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +4 -0
  141. package/dist/extensions/pi-subagents/src/agents/agents.ts +118 -9
  142. package/dist/extensions/pi-subagents/src/agents/skills.ts +14 -12
  143. package/dist/extensions/pi-subagents/src/agents/task-aware-routing.ts +125 -0
  144. package/dist/extensions/pi-subagents/src/api/delegation.ts +3 -0
  145. package/dist/extensions/pi-subagents/src/api/preflight.ts +17 -13
  146. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +17 -1
  147. package/dist/extensions/pi-subagents/src/extension/index.ts +22 -8
  148. package/dist/extensions/pi-subagents/src/extension/rpc.ts +248 -6
  149. package/dist/extensions/pi-subagents/src/extension/schemas.ts +33 -8
  150. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +32 -14
  151. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +9 -4
  152. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +33 -4
  153. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +86 -21
  154. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +24 -13
  155. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +7 -5
  156. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -2
  157. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +48 -5
  158. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +68 -1
  159. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +56 -5
  160. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +92 -11
  161. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +29 -3
  162. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +388 -29
  163. package/dist/extensions/pi-subagents/src/runs/foreground/async-stop-action.ts +65 -0
  164. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +3 -3
  165. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +214 -60
  166. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +546 -252
  167. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +42 -0
  168. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +553 -154
  169. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +19 -13
  170. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +51 -19
  171. package/dist/extensions/pi-subagents/src/runs/shared/chain-outputs.ts +3 -1
  172. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
  173. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +44 -11
  174. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +8 -0
  175. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +97 -20
  176. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +43 -12
  177. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +52 -4
  178. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +19 -0
  179. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +45 -9
  180. package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +71 -0
  181. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +63 -9
  182. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +31 -1
  183. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +101 -0
  184. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +22 -1
  185. package/dist/extensions/pi-subagents/src/runs/shared/usage-budget.ts +65 -0
  186. package/dist/extensions/pi-subagents/src/runs/shared/workflow-graph.ts +26 -1
  187. package/dist/extensions/pi-subagents/src/shared/settings.ts +17 -1
  188. package/dist/extensions/pi-subagents/src/shared/types.ts +196 -12
  189. package/dist/extensions/pi-subagents/src/shared/utils.ts +102 -5
  190. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +10 -1
  191. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +46 -4
  192. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +5 -3
  193. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +87 -24
  194. package/dist/extensions/pi-subagents/src/tui/fleet.ts +182 -9
  195. package/dist/extensions/pi-subagents/src/tui/render.ts +55 -34
  196. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +14 -7
  197. package/dist/extensions/pi-subagents/src/watchdog/review.ts +5 -4
  198. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +170 -17
  199. package/dist/extensions/pi-subagents/src/watchdog/scope.ts +62 -0
  200. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +41 -1
  201. package/dist/extensions/pi-subagents/src/watchdog/types.ts +10 -0
  202. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +113 -8
  203. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +419 -47
  204. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +84 -0
  205. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +4 -2
  206. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +51 -2
  207. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +62 -22
  208. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +48 -0
  209. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +8 -6
  210. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +231 -19
  211. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +48 -7
  212. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +44 -0
  213. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +199 -17
  214. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +898 -16
  215. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +112 -23
  216. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +17 -5
  217. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +2 -0
  218. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +18 -2
  219. package/dist/extensions/pi-subagents/test/support/register-loader.mjs +3 -3
  220. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +3 -1
  221. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +1 -1
  222. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +198 -6
  223. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +161 -1
  224. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +47 -2
  225. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +60 -0
  226. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +8 -0
  227. package/dist/extensions/pi-subagents/test/unit/builtin-agent-documentation.test.ts +63 -0
  228. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +136 -0
  229. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +1 -1
  230. package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +6 -0
  231. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +1 -1
  232. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +48 -48
  233. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +23 -0
  234. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +27 -0
  235. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +28 -2
  236. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +1 -0
  237. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +176 -8
  238. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +164 -5
  239. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +41 -1
  240. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +17 -12
  241. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +18 -2
  242. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -1
  243. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +30 -2
  244. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +39 -2
  245. package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +22 -0
  246. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +103 -0
  247. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +18 -0
  248. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +48 -0
  249. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +13 -1
  250. package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +29 -4
  251. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +223 -4
  252. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +30 -0
  253. package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +52 -0
  254. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +46 -2
  255. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +91 -1
  256. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  257. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +1 -1
  258. package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +78 -0
  259. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +41 -0
  260. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +77 -0
  261. package/dist/extensions/pi-subagents/test/unit/task-aware-routing.test.ts +213 -0
  262. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +26 -1
  263. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +61 -10
  264. package/dist/extensions/pi-subagents/test/unit/total-cost.test.ts +1 -0
  265. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +210 -1
  266. package/dist/extensions/pi-subagents/test/unit/watchdog-scope.test.ts +33 -0
  267. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +32 -0
  268. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +1 -1
  269. package/dist/main.d.ts.map +1 -1
  270. package/dist/main.js +43 -0
  271. package/dist/main.js.map +1 -1
  272. package/dist/modes/interactive/components/custom-message.d.ts +3 -1
  273. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  274. package/dist/modes/interactive/components/custom-message.js +10 -2
  275. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  276. package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
  277. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  278. package/dist/modes/interactive/components/extension-editor.js +16 -46
  279. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  280. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  281. package/dist/modes/interactive/components/model-selector.js +4 -1
  282. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  283. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  284. package/dist/modes/interactive/components/scoped-models-selector.js +22 -13
  285. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  286. package/dist/modes/interactive/external-editor.d.ts +12 -0
  287. package/dist/modes/interactive/external-editor.d.ts.map +1 -0
  288. package/dist/modes/interactive/external-editor.js +37 -0
  289. package/dist/modes/interactive/external-editor.js.map +1 -0
  290. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  291. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  292. package/dist/modes/interactive/interactive-mode.js +72 -64
  293. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  294. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  295. package/dist/modes/rpc/rpc-mode.js +14 -0
  296. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  297. package/dist/skills/ponytail/SKILL.md +1 -3
  298. package/dist/utils/clipboard.d.ts.map +1 -1
  299. package/dist/utils/clipboard.js +19 -8
  300. package/dist/utils/clipboard.js.map +1 -1
  301. package/dist/utils/version-check.d.ts.map +1 -1
  302. package/dist/utils/version-check.js +1 -1
  303. package/dist/utils/version-check.js.map +1 -1
  304. package/docs/compaction.md +1 -1
  305. package/docs/custom-provider.md +14 -5
  306. package/docs/environment-variables.md +86 -0
  307. package/docs/extensions.md +15 -5
  308. package/docs/index.md +1 -0
  309. package/docs/models.md +9 -2
  310. package/docs/plans/subagent-delegation/phase-0-correctness.md +265 -0
  311. package/docs/plans/subagent-delegation/phase-1-behavioral-contract.md +486 -0
  312. package/docs/plans/subagent-delegation/phase-2-context-controls.md +282 -0
  313. package/docs/plans/subagent-delegation/phase-3-advisory-routing.md +362 -0
  314. package/docs/plans/subagent-delegation/phase-4-optional-enforcement.md +381 -0
  315. package/docs/providers.md +21 -2
  316. package/docs/rpc.md +23 -6
  317. package/docs/session-format.md +2 -0
  318. package/docs/settings.md +1 -1
  319. package/docs/usage.md +0 -13
  320. package/examples/extensions/custom-compaction.ts +5 -2
  321. package/examples/extensions/custom-provider-anthropic/index.ts +9 -3
  322. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  323. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  324. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  325. package/examples/extensions/gondolin/package-lock.json +2 -2
  326. package/examples/extensions/gondolin/package.json +1 -1
  327. package/examples/extensions/handoff.ts +11 -3
  328. package/examples/extensions/message-renderer.ts +3 -3
  329. package/examples/extensions/sandbox/package-lock.json +2 -2
  330. package/examples/extensions/sandbox/package.json +1 -1
  331. package/examples/extensions/summarize.ts +5 -2
  332. package/examples/extensions/with-deps/package-lock.json +2 -2
  333. package/examples/extensions/with-deps/package.json +1 -1
  334. package/examples/sdk/12-full-control.ts +3 -1
  335. package/package.json +16 -7
  336. package/dist/extensions/caveman/caveman-instructions.cjs +0 -11
  337. package/dist/extensions/caveman/index.js +0 -118
  338. package/dist/extensions/caveman/package.json +0 -8
  339. package/dist/extensions/caveman/test/extension.test.js +0 -203
  340. package/dist/extensions/caveman/test/helpers.test.js +0 -58
  341. package/dist/skills/caveman/SKILL.md +0 -50
@@ -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
 
@@ -238,16 +262,16 @@ const ControlOverrides = Type.Object({
238
262
 
239
263
  const SubagentParamsSchema = Type.Object({
240
264
  agent: Type.Optional(Type.String({ description: "Agent name (SINGLE mode) or target for management get/update/delete" })),
241
- task: Type.Optional(Type.String({ description: "Task (SINGLE mode, optional for self-contained agents)" })),
265
+ task: Type.Optional(Type.String({ description: "Task for SINGLE-mode execution, or an optional advisory intent for action:'list' (list only appends a task-aware recommendation and never launches work; explicitly call subagent with the recommended canonical agent name and the task to execute)" })),
242
266
  // Management action (when present, tool operates in management mode)
243
267
  action: Type.Optional(Type.String({
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,13 +314,14 @@ 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
- artifacts: Type.Optional(Type.Boolean({ description: "Write debug artifacts (default: true)" })),
324
+ artifacts: Type.Optional(Type.Boolean({ description: "Write debug artifacts (default: false)" })),
300
325
  includeProgress: Type.Optional(Type.Boolean({ description: "Include full progress in result (default: false)" })),
301
326
  share: Type.Optional(Type.Boolean({ description: "Upload session to GitHub Gist for sharing (default: false)" })),
302
327
  sessionDir: Type.Optional(
@@ -6,24 +6,38 @@ import { getAgentDir, getProjectConfigDir } from "../shared/utils.ts";
6
6
  const CUSTOM_TOOL_DESCRIPTION_FILE = "subagent-tool-description.md";
7
7
  const CUSTOM_TOOL_DESCRIPTION_MAX_BYTES = 50 * 1024;
8
8
 
9
+ /**
10
+ * Generic parent-only delegation routing contract. Deliberately contains no
11
+ * bundled agent names: agents are selected from runtime catalog metadata only.
12
+ * Attached to the parent `subagent` tool as promptGuidelines and embedded in
13
+ * the mandatory safety guidance so custom descriptions cannot remove it.
14
+ */
15
+ export const SUBAGENT_PARENT_ROUTING_GUIDANCE = `PARENT-ONLY SUBAGENT ROUTING:
16
+ • Before any execution, call { action: "list" } and select only an executable entry using its current role, context, and tool metadata.
17
+ • Keep tiny targeted reads and simple answers local with the parent.
18
+ • Send broad local investigation, external research, and mutation/implementation work to a capable delegated agent.
19
+ • The parent remains the decision-maker and normally the sole writer.`;
20
+
9
21
  export const SUBAGENT_SAFETY_GUIDANCE = `SAFETY-CRITICAL SUBAGENT GUIDANCE:
10
22
  • 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.
23
+ • 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
24
  • 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
25
  • 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
26
  • 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.
15
- • Artifacts/status essentials: chain outputs live under {chain_dir}; async runs expose asyncId/asyncDir with status.json, events.jsonl, output logs, and status via { action: "status", id }. Include output paths and residual risks when reporting results.`;
27
+ • Artifacts/status essentials: chain outputs live under {chain_dir}; async runs expose asyncId/asyncDir with status.json, events.jsonl, output logs, and status via { action: "status", id }. Normal delegated results are reference-first: completion returns saved-output references plus lifecycle/status information, not child prose — inspect full output through the saved output path, async status/transcript, or resume. Include output paths and residual risks when reporting results.
28
+
29
+ ${SUBAGENT_PARENT_ROUTING_GUIDANCE}`;
16
30
 
17
31
  export const FULL_SUBAGENT_TOOL_DESCRIPTION = `To delegate work, call with { agent, task }, { tasks }, or { chain }; omit action. Use action only for management/control actions listed below.
18
32
 
19
33
  EXECUTION (use exactly ONE mode):
20
34
  • Before executing, use { action: "list" } to inspect configured agents/chains. Only execute agents listed as executable/non-disabled.
21
35
  • 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
36
+ • CHAIN: { chain: [{agent:"agent-a"}, {checkpoint:"review"}, {parallel:[{agent:"agent-b",count:3}]}] } - sequential pipeline with optional approval checkpoints and parallel fan-out
23
37
  • PARALLEL: { tasks: [{agent,task,count?,output?,reads?,progress?}, ...], concurrency?: number, worktree?: true } - concurrent execution (worktree: isolate each task in a git worktree)
24
38
  • 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
39
  • 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
40
+ • 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
41
  • 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
42
  • 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
43
 
@@ -35,10 +49,11 @@ CHAIN TEMPLATE VARIABLES (use in task strings):
35
49
  CHAIN EXAMPLES (quick reference for the nested schema):
36
50
  • Sequential: { chain: [{agent:"agent-a", task:"Analyze {task}"}, {agent:"agent-b", task:"Plan based on {previous}"}] }
37
51
  • 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}"}] }
52
+ • 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
53
 
40
- MANAGEMENT (use action field, omit agent/task/chain/tasks):
54
+ MANAGEMENT (use action field; omit agent/chain/tasks — the sole field exception is list's optional advisory task):
41
55
  • { action: "list" } - discover executable agents/chains
56
+ • { action: "list", task: "..." } - same, plus optional task-aware advisory routing: recommends one canonical agent (implementation or read-only) for the task, or explains why none is safe. It only recommends and never launches; to proceed, explicitly call subagent with the recommended canonical agent name and the task.
42
57
  • { action: "get", agent: "name" } - full detail; packaged agents use dotted runtime names like "package.agent"
43
58
  • { action: "models", agent?: "name" } - show the runtime-loaded builtin subagent model mapping, optionally filtered to one builtin
44
59
  • { action: "watchdog.status" | "watchdog.check" | "watchdog.recommend-model" } - inspect the opt-in subagent watchdog and its strong complementary model recommendation
@@ -47,10 +62,10 @@ MANAGEMENT (use action field, omit agent/task/chain/tasks):
47
62
  • acceptanceRole affects inferred acceptance only, never tool access. Explicit task mutation/no-edit intent wins; omission preserves name heuristics. Update with false or an empty string to clear it.
48
63
  • { action: "update", agent: "code-analysis.custom-agent", config: { package: "analysis", ... } } - merge
49
64
  • { action: "delete", agent: "code-analysis.custom-agent" }
50
- • { action: "eject", agent: "commentator", agentScope?: "user" | "project" } - copy a bundled/package agent to user/project scope as an editable custom file that shadows the original (default scope: user)
51
- • { action: "disable", agent: "commentator", agentScope?: "user" | "project" } - hide any agent from runtime discovery via a reversible settings override (default scope: user)
52
- • { action: "enable", agent: "commentator", agentScope?: "user" | "project" } - remove a disabled override and restore discovery
53
- • { action: "reset", agent: "commentator", agentScope?: "user" | "project" } - delete the scope's custom agent file and/or settings override, restoring the bundled default
65
+ • { action: "eject", agent: "agent-name", agentScope?: "user" | "project" } - copy a bundled/package agent to user/project scope as an editable custom file that shadows the original (default scope: user)
66
+ • { action: "disable", agent: "agent-name", agentScope?: "user" | "project" } - hide any agent from runtime discovery via a reversible settings override (default scope: user)
67
+ • { action: "enable", agent: "agent-name", agentScope?: "user" | "project" } - remove a disabled override and restore discovery
68
+ • { action: "reset", agent: "agent-name", agentScope?: "user" | "project" } - delete the scope's custom agent file and/or settings override, restoring the bundled default
54
69
  • { action: "grant-spawn-budget", additional: 10 } - add bounded capacity from the root interactive parent after native user confirmation; grants are rejected while children are active and cumulative grants cannot exceed the original configured cap
55
70
  • Use chainName for chain operations; packaged chains also use dotted runtime names
56
71
 
@@ -63,6 +78,7 @@ CONTROL:
63
78
  • { 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
79
  • { 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
80
  • { action: "append-step", id: "...", chain: [{agent:"agent-c", task:"Use {previous}"}] } - append one step to the tail of a running async chain
81
+ • { action: "approve-checkpoint", id: "..." } / { action: "reject-checkpoint", id: "..." } - decide a paused current-session async chain checkpoint
66
82
 
67
83
  SCHEDULE (opt-in; requires { "scheduledRuns": { "enabled": true } } in config.json):
68
84
  • { 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,17 +95,18 @@ export const COMPACT_SUBAGENT_TOOL_DESCRIPTION = `To delegate work, call with {
79
95
 
80
96
  EXECUTE:
81
97
  • 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.
98
+ • SINGLE {agent, task?}; PARALLEL {tasks:[{agent,task,count?,output?,reads?,progress?}], concurrency?, worktree?}; CHAIN {chain:[{agent,task?},{checkpoint:"review"},{parallel:[...]}]}.
99
+ • 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
100
  • 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
101
  • Chain templates may use {task}, {previous}, {chain_dir}, and named outputs. Parallel worktree isolation requires a clean git repo.
86
102
  • Chain example: { chain: [{agent:"agent-a", task:"Analyze {task}"}, {parallel: [{agent:"agent-b", task:"Check {previous}", count: 3}]}] }
87
103
  • If list shows proactive skill subagent suggestions, use a small fresh-context fanout only when the task is broad enough.
88
104
 
89
105
  MANAGE / CONTROL:
90
- • 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.
106
+ • Use action without execution fields (list may add an optional advisory task): list, get, models, create, update, delete, eject, disable, enable, reset, grant-spawn-budget, doctor, watchdog.status, watchdog.check, watchdog.recommend-model, watchdog.configure.
107
+ • { action: "list", task: "..." } optionally appends task-aware advisory routing that recommends a canonical agent but never launches; execute the recommended agent explicitly in a separate call.
91
108
  • 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.
109
+ • 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
110
  • Opt-in schedule actions: schedule, schedule-list, schedule-status, schedule-cancel. Schedule only explicit delayed runs the user asked for.
94
111
 
95
112
  ASYNC / WAIT:
@@ -97,6 +114,7 @@ ASYNC / WAIT:
97
114
  • Status and artifacts live under asyncId/asyncDir with status.json, events.jsonl, output logs, session files, and { action:"status", id:"..." }.
98
115
 
99
116
  SAFETY:
117
+ • Parent-only routing: call { action: "list" } before any execution and select only an executable entry using its current role, context, and tool metadata. Keep tiny targeted reads and simple answers local; send broad local investigation, external research, and mutation/implementation work to a capable delegated agent. The parent remains the decision-maker and normally the sole writer.
100
118
  • Ordinary child subagents are not orchestrators and must not run subagents. Only explicit fanout children may use child-safe subagent, still bounded by depth/session limits.
101
119
  • Keep one writer per cwd/worktree. Use fresh read-only review/validation fanout, then synthesize and apply fixes from the parent unless isolated worktrees were intentionally requested.`;
102
120
 
@@ -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)),