@selesai/code 0.5.19 → 0.5.21

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 (265) hide show
  1. package/dist/extensions/handoff-new.test.ts +8 -9
  2. package/dist/extensions/handoff-new.ts +6 -8
  3. package/dist/extensions/pi-intercom/broker/spawn.test.ts +31 -0
  4. package/dist/extensions/pi-intercom/broker/spawn.ts +5 -3
  5. package/dist/extensions/pi-subagents/CHANGELOG.md +1367 -0
  6. package/dist/extensions/pi-subagents/README.md +602 -220
  7. package/dist/extensions/pi-subagents/banner.png +0 -0
  8. package/dist/extensions/pi-subagents/index.ts +1 -0
  9. package/dist/extensions/pi-subagents/install.mjs +3 -3
  10. package/dist/extensions/pi-subagents/package-lock.json +3405 -0
  11. package/dist/extensions/pi-subagents/package.json +26 -14
  12. package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
  13. package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
  14. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
  15. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
  16. package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
  17. package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
  18. package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
  19. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
  20. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
  21. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
  22. package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
  23. package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
  24. package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
  25. package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
  26. package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
  27. package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
  28. package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
  29. package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
  30. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
  31. package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
  32. package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
  33. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
  34. package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
  35. package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
  36. package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
  37. package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
  38. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
  39. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
  40. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
  41. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
  42. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
  43. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
  44. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
  45. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
  46. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
  47. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
  48. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
  49. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
  50. package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
  51. package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
  52. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
  53. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
  54. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
  55. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
  56. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
  57. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
  58. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
  59. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
  60. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
  61. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
  62. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
  63. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
  64. package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
  65. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
  66. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
  67. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
  68. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
  69. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
  70. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
  71. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
  72. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
  73. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
  74. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
  75. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
  76. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
  77. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
  78. package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
  79. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
  80. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
  81. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
  82. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
  83. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
  84. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
  85. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
  86. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
  87. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
  88. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
  89. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
  90. package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
  91. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
  92. package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
  93. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
  94. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
  95. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
  96. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
  97. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
  98. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
  99. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
  100. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
  101. package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
  102. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
  103. package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
  104. package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
  105. package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
  106. package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
  107. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
  108. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
  109. package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
  110. package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
  111. package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
  112. package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
  113. package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
  114. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
  115. package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
  116. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
  117. package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
  118. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
  119. package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
  120. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
  121. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
  122. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
  123. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
  124. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
  125. package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
  126. package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
  127. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
  128. package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
  129. package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
  130. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
  131. package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
  132. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
  133. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
  134. package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
  135. package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
  136. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
  137. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
  138. package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
  139. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
  140. package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
  141. package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
  142. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
  143. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
  144. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
  145. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
  146. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
  147. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
  148. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
  149. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
  150. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
  151. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
  152. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
  153. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
  154. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
  155. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
  156. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
  157. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
  158. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
  159. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
  160. package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
  161. package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
  162. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
  163. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
  164. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
  165. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
  166. package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
  167. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
  168. package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
  169. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
  170. package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
  171. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
  172. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
  173. package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
  174. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
  175. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
  176. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
  177. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
  178. package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
  179. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
  180. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
  181. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
  182. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
  183. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
  184. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
  185. package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
  186. package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
  187. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
  188. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
  189. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
  190. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
  191. package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
  192. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
  193. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
  194. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
  195. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
  196. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
  197. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
  198. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
  199. package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
  200. package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
  201. package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
  202. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
  203. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
  204. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
  205. package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
  206. package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
  207. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
  208. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
  209. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
  210. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
  211. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
  212. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
  213. package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
  214. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
  215. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
  216. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
  217. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
  218. package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
  219. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
  220. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
  221. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
  222. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
  223. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
  224. package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
  225. package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
  226. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
  227. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
  228. package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
  229. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
  230. package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
  231. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
  232. package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
  233. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
  234. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
  235. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
  236. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
  237. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
  238. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
  239. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
  240. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
  241. package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
  242. package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
  243. package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
  244. package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
  245. package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
  246. package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
  247. package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
  248. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
  249. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
  250. package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
  251. package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
  252. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
  253. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
  254. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
  255. package/dist/extensions/question/batch.ts +39 -0
  256. package/dist/extensions/question/dialog-adapter.ts +23 -1
  257. package/dist/extensions/question/index.ts +237 -7
  258. package/dist/extensions/question/schemas.ts +28 -15
  259. package/dist/extensions/question/tests/batch.test.ts +26 -0
  260. package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
  261. package/dist/extensions/question/tui-adapter.ts +2 -3
  262. package/dist/extensions/question/types.ts +37 -0
  263. package/dist/extensions/question/ui-protocol.ts +3 -3
  264. package/dist/skills/batch-grill-me/SKILL.md +3 -1
  265. package/package.json +2 -1
@@ -87,7 +87,7 @@ function parseSkill(value: string | undefined): string | string[] | false | unde
87
87
 
88
88
  function parseAgent(frontmatter: Record<string, string>): string {
89
89
  const subagent = stringField(frontmatter, "subagent");
90
- if (!subagent || subagent === "true") return "delegate";
90
+ if (!subagent || subagent === "true") return "builder";
91
91
  return subagent;
92
92
  }
93
93
 
@@ -240,7 +240,7 @@ function workflowParams(workflow: PromptWorkflow, args: string[], runtime: Retur
240
240
  function workflowChainStep(workflow: PromptWorkflow, args: string[], runtime: ReturnType<typeof parseRuntimeOptions>): ChainStep {
241
241
  const params = workflowParams(workflow, args, runtime);
242
242
  return {
243
- agent: params.agent ?? "delegate",
243
+ agent: params.agent ?? "builder",
244
244
  task: params.task,
245
245
  ...(params.model ? { model: params.model } : {}),
246
246
  ...(params.skill !== undefined ? { skill: params.skill } : {}),
@@ -0,0 +1,147 @@
1
+ import { DynamicBorder, keyHint, rawKeyHint, type Theme } from "@selesai/code";
2
+ import { Container, fuzzyFilter, Input, type KeybindingsManager, Spacer, Text, type TUI } from "@earendil-works/pi-tui";
3
+
4
+ /** A single selectable row. `value` is returned on confirm; `label` is the primary text. */
5
+ export interface SelectorItem {
6
+ value: string;
7
+ label: string;
8
+ /** Optional dimmed badge shown after the label (e.g. a provider name). */
9
+ badge?: string;
10
+ /** Marks the current selection (rendered with a ✓ checkmark). */
11
+ current?: boolean;
12
+ }
13
+
14
+ export interface SelectorResult {
15
+ confirmed: boolean;
16
+ value?: string;
17
+ }
18
+
19
+ export interface SelectorOptions {
20
+ title: string;
21
+ /** Optional dimmed hint line under the title (e.g. the current value). */
22
+ subtitle?: string;
23
+ items: SelectorItem[];
24
+ done: (result: SelectorResult) => void;
25
+ }
26
+
27
+ const MAX_VISIBLE = 10;
28
+
29
+ /**
30
+ * A single-select list with a search field and a bounded scroll window that keeps the
31
+ * highlighted row on screen with an `(n/total)` indicator, so the selection never scrolls
32
+ * out of view when the option list is long. Composed from pi's own TUI primitives so it
33
+ * matches the built-in `/model` picker.
34
+ *
35
+ * Colors come from the `theme` passed to the factory: the module-level `theme` singleton
36
+ * is undefined under the extension's jiti module cache.
37
+ */
38
+ export class SelectorComponent extends Container {
39
+ private readonly tui: TUI;
40
+ private readonly theme: Theme;
41
+ private readonly keybindings: KeybindingsManager;
42
+ private readonly items: SelectorItem[];
43
+ private readonly done: (result: SelectorResult) => void;
44
+
45
+ private readonly searchInput: Input;
46
+ private readonly listContainer: Container;
47
+ private filtered: SelectorItem[];
48
+ private selectedIndex = 0;
49
+
50
+ constructor(tui: TUI, theme: Theme, keybindings: KeybindingsManager, options: SelectorOptions) {
51
+ super();
52
+ this.tui = tui;
53
+ this.theme = theme;
54
+ this.keybindings = keybindings;
55
+ this.items = options.items;
56
+ this.done = options.done;
57
+ this.filtered = [...this.items];
58
+
59
+ const border = () => new DynamicBorder((str) => theme.fg("border", str));
60
+ this.addChild(border());
61
+ this.addChild(new Spacer(1));
62
+ this.addChild(new Text(theme.fg("accent", theme.bold(options.title)), 0, 0));
63
+ if (options.subtitle) this.addChild(new Text(theme.fg("muted", options.subtitle), 0, 0));
64
+ this.addChild(new Spacer(1));
65
+
66
+ this.searchInput = new Input();
67
+ this.searchInput.focused = true;
68
+ this.searchInput.onSubmit = () => this.confirmSelection();
69
+ this.addChild(this.searchInput);
70
+ this.addChild(new Spacer(1));
71
+
72
+ this.listContainer = new Container();
73
+ this.addChild(this.listContainer);
74
+ this.addChild(new Spacer(1));
75
+
76
+ this.addChild(new Text(rawKeyHint("↑↓", "navigate") + " " + keyHint("tui.select.confirm", "select") + " " + keyHint("tui.select.cancel", "cancel"), 0, 0));
77
+ this.addChild(new Spacer(1));
78
+ this.addChild(border());
79
+
80
+ const currentIndex = this.filtered.findIndex((item) => item.current);
81
+ if (currentIndex >= 0) this.selectedIndex = currentIndex;
82
+ this.updateList();
83
+ }
84
+
85
+ private applyFilter(query: string): void {
86
+ const previous = this.filtered[this.selectedIndex]?.value;
87
+ this.filtered = query
88
+ ? fuzzyFilter(this.items, query, (item) => `${item.label} ${item.value} ${item.badge ?? ""}`)
89
+ : [...this.items];
90
+ const keepIndex = this.filtered.findIndex((item) => item.value === previous);
91
+ this.selectedIndex = keepIndex >= 0 ? keepIndex : Math.min(this.selectedIndex, Math.max(0, this.filtered.length - 1));
92
+ this.updateList();
93
+ }
94
+
95
+ private updateList(): void {
96
+ const th = this.theme;
97
+ this.listContainer.clear();
98
+ const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(MAX_VISIBLE / 2), this.filtered.length - MAX_VISIBLE));
99
+ const endIndex = Math.min(startIndex + MAX_VISIBLE, this.filtered.length);
100
+
101
+ for (let i = startIndex; i < endIndex; i++) {
102
+ const item = this.filtered[i]!;
103
+ const isSelected = i === this.selectedIndex;
104
+ const badge = item.badge ? ` ${th.fg("muted", `[${item.badge}]`)}` : "";
105
+ const checkmark = item.current ? th.fg("success", " ✓") : "";
106
+ const line = isSelected
107
+ ? `${th.fg("accent", "→ ")}${th.fg("accent", item.label)}${badge}${checkmark}`
108
+ : ` ${item.label}${badge}${checkmark}`;
109
+ this.listContainer.addChild(new Text(line, 0, 0));
110
+ }
111
+
112
+ if (startIndex > 0 || endIndex < this.filtered.length) {
113
+ this.listContainer.addChild(new Text(th.fg("muted", ` (${this.selectedIndex + 1}/${this.filtered.length})`), 0, 0));
114
+ }
115
+ if (this.filtered.length === 0) {
116
+ this.listContainer.addChild(new Text(th.fg("muted", " No matching entries"), 0, 0));
117
+ }
118
+ }
119
+
120
+ private confirmSelection(): void {
121
+ const selected = this.filtered[this.selectedIndex];
122
+ this.done(selected ? { confirmed: true, value: selected.value } : { confirmed: false });
123
+ }
124
+
125
+ handleInput(keyData: string): void {
126
+ const kb = this.keybindings;
127
+ if (kb.matches(keyData, "tui.select.up")) {
128
+ if (this.filtered.length === 0) return;
129
+ this.selectedIndex = this.selectedIndex === 0 ? this.filtered.length - 1 : this.selectedIndex - 1;
130
+ this.updateList();
131
+ this.tui.requestRender();
132
+ } else if (kb.matches(keyData, "tui.select.down")) {
133
+ if (this.filtered.length === 0) return;
134
+ this.selectedIndex = this.selectedIndex === this.filtered.length - 1 ? 0 : this.selectedIndex + 1;
135
+ this.updateList();
136
+ this.tui.requestRender();
137
+ } else if (kb.matches(keyData, "tui.select.confirm")) {
138
+ this.confirmSelection();
139
+ } else if (kb.matches(keyData, "tui.select.cancel")) {
140
+ this.done({ confirmed: false });
141
+ } else {
142
+ this.searchInput.handleInput(keyData);
143
+ this.applyFilter(this.searchInput.getValue());
144
+ this.tui.requestRender();
145
+ }
146
+ }
147
+ }
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import * as fs from "node:fs";
3
3
  import * as path from "node:path";
4
4
  import { keyText, type ExtensionAPI, type ExtensionContext } from "@selesai/code";
5
- import { Key, matchesKey } from "@earendil-works/pi-tui";
5
+ import { Key, matchesKey, type Component, type TUI } from "@earendil-works/pi-tui";
6
6
  import { BUILTIN_AGENT_NAMES, discoverAgents, discoverAgentsAll, type ChainConfig } from "../agents/agents.ts";
7
7
  import {
8
8
  DEFAULT_PROVIDER_MODELS_MAX_AGE_DAYS,
@@ -16,11 +16,16 @@ import {
16
16
  import type { SubagentParamsLike } from "../runs/foreground/subagent-executor.ts";
17
17
  import { isDynamicParallelStep, isParallelStep, type ChainStep } from "../shared/settings.ts";
18
18
  import { findModelInfo, toModelInfo } from "../shared/model-info.ts";
19
- import { formatTokens } from "../shared/formatters.ts";
19
+ import { formatTokens, shortenPath } from "../shared/formatters.ts";
20
+ import { listAsyncRuns, formatAsyncRunProgressLabel, type AsyncRunSummary } from "../runs/background/async-status.ts";
21
+ import { scheduledRunStorePath } from "../runs/background/scheduled-runs.ts";
22
+ import { SUBAGENT_FANOUT_CHILD_ENV } from "../runs/shared/pi-args.ts";
20
23
  import { assertJsonSchemaObject } from "../runs/shared/structured-output.ts";
21
24
  import { validateAcceptanceInput } from "../runs/shared/acceptance.ts";
22
25
  import type { SlashSubagentResponse, SlashSubagentUpdate } from "./slash-bridge.ts";
23
26
  import { registerPromptWorkflowCommands } from "./prompt-workflows.ts";
27
+ import { openSubagentsAdmin } from "./subagents-admin.ts";
28
+ import { openSubagentFleet } from "../tui/fleet.ts";
24
29
  import {
25
30
  applySlashUpdate,
26
31
  buildSlashInitialResult,
@@ -36,6 +41,7 @@ import {
36
41
  SLASH_SUBAGENT_RESPONSE_EVENT,
37
42
  SLASH_SUBAGENT_STARTED_EVENT,
38
43
  SLASH_SUBAGENT_UPDATE_EVENT,
44
+ ASYNC_DIR,
39
45
  type Details,
40
46
  type JsonSchemaObject,
41
47
  type SingleResult,
@@ -221,6 +227,160 @@ async function withSlashStatus<T>(
221
227
  }
222
228
  }
223
229
 
230
+ type Theme = ExtensionContext["ui"]["theme"];
231
+
232
+ type StopSelectorTarget = {
233
+ kind: "async" | "scheduled";
234
+ id: string;
235
+ label: string;
236
+ detail: string;
237
+ actionLabel: string;
238
+ };
239
+
240
+ type StopSelectorResult = { confirmed: boolean; target?: StopSelectorTarget };
241
+
242
+ function commandForTarget(target: StopSelectorTarget): string {
243
+ return target.kind === "scheduled"
244
+ ? `subagent({ action: "schedule-cancel", id: ${JSON.stringify(target.id)} })`
245
+ : `subagent({ action: "stop", id: ${JSON.stringify(target.id)} })`;
246
+ }
247
+
248
+ function formatAsyncStopTarget(run: AsyncRunSummary): StopSelectorTarget {
249
+ const progress = formatAsyncRunProgressLabel(run);
250
+ const cwd = run.cwd ? shortenPath(run.cwd) : shortenPath(run.asyncDir);
251
+ return {
252
+ kind: "async",
253
+ id: run.id,
254
+ label: `${run.id} · ${run.mode} · ${progress}`,
255
+ detail: `${run.state} · ${cwd}`,
256
+ actionLabel: "stop async run",
257
+ };
258
+ }
259
+
260
+ function scheduledStopTargets(ctx: ExtensionContext, state: SubagentState): StopSelectorTarget[] {
261
+ const sessionId = state.currentSessionId ?? ctx.sessionManager.getSessionId();
262
+ if (!sessionId) return [];
263
+ const storePath = scheduledRunStorePath(ctx.cwd, sessionId);
264
+ if (!fs.existsSync(storePath)) return [];
265
+ let parsed: unknown;
266
+ try {
267
+ parsed = JSON.parse(fs.readFileSync(storePath, "utf-8"));
268
+ } catch {
269
+ return [];
270
+ }
271
+ const jobs = parsed && typeof parsed === "object" && Array.isArray((parsed as { jobs?: unknown }).jobs)
272
+ ? (parsed as { jobs: Array<Record<string, unknown>> }).jobs
273
+ : [];
274
+ return jobs
275
+ .filter((job) => job.state === "scheduled" && typeof job.id === "string" && typeof job.name === "string" && typeof job.runAt === "number")
276
+ .sort((left, right) => Number(left.runAt) - Number(right.runAt))
277
+ .map((job) => ({
278
+ kind: "scheduled" as const,
279
+ id: String(job.id),
280
+ label: `${String(job.id)} · ${String(job.name)}`,
281
+ detail: `scheduled · ${new Date(Number(job.runAt)).toISOString()}`,
282
+ actionLabel: "cancel scheduled run",
283
+ }));
284
+ }
285
+
286
+ function discoverStopTargets(ctx: ExtensionContext, state: SubagentState): StopSelectorTarget[] {
287
+ const sessionId = state.currentSessionId ?? ctx.sessionManager.getSessionId() ?? undefined;
288
+ const asyncTargets = listAsyncRuns(ASYNC_DIR, {
289
+ states: ["queued", "running"],
290
+ ...(sessionId ? { sessionId } : {}),
291
+ }).map(formatAsyncStopTarget);
292
+ return [...asyncTargets, ...scheduledStopTargets(ctx, state)];
293
+ }
294
+
295
+ function stopFallbackText(targets: StopSelectorTarget[]): string {
296
+ if (targets.length === 0) return "No active current-session async runs or scheduled subagent runs to stop.";
297
+ const lines = ["Subagent stop targets:", ""];
298
+ for (const target of targets) {
299
+ lines.push(`- ${target.label}`);
300
+ lines.push(` ${target.detail}`);
301
+ lines.push(` ${target.actionLabel}: ${commandForTarget(target)}`);
302
+ if (target.kind === "async") lines.push(` slash: /subagents-stop ${target.id}`);
303
+ }
304
+ return lines.join("\n");
305
+ }
306
+
307
+ class SubagentsStopSelector implements Component {
308
+ readonly width = 84;
309
+ private selected = 0;
310
+ private confirming = false;
311
+ private readonly tui: TUI;
312
+ private readonly theme: Theme;
313
+ private readonly targets: StopSelectorTarget[];
314
+ private readonly done: (result: StopSelectorResult) => void;
315
+
316
+ constructor(tui: TUI, theme: Theme, targets: StopSelectorTarget[], done: (result: StopSelectorResult) => void) {
317
+ this.tui = tui;
318
+ this.theme = theme;
319
+ this.targets = targets;
320
+ this.done = done;
321
+ }
322
+
323
+ handleInput(data: string): void {
324
+ if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
325
+ this.done({ confirmed: false });
326
+ return;
327
+ }
328
+ if (this.confirming) {
329
+ if (matchesKey(data, "return") || data.toLowerCase() === "y") {
330
+ this.done({ confirmed: true, target: this.targets[this.selected] });
331
+ return;
332
+ }
333
+ if (data.toLowerCase() === "n" || matchesKey(data, "backspace")) {
334
+ this.confirming = false;
335
+ this.tui.requestRender();
336
+ }
337
+ return;
338
+ }
339
+ if (matchesKey(data, "up")) {
340
+ this.selected = Math.max(0, this.selected - 1);
341
+ this.tui.requestRender();
342
+ return;
343
+ }
344
+ if (matchesKey(data, "down")) {
345
+ this.selected = Math.min(this.targets.length - 1, this.selected + 1);
346
+ this.tui.requestRender();
347
+ return;
348
+ }
349
+ if (matchesKey(data, "return")) {
350
+ this.confirming = true;
351
+ this.tui.requestRender();
352
+ }
353
+ }
354
+
355
+ render(width: number): string[] {
356
+ const contentWidth = Math.max(40, Math.min(this.width, width || this.width));
357
+ const lines = [this.theme.bold("Stop subagent run"), this.theme.fg("dim", "Select a current-session async run to stop, or a scheduled run to cancel."), ""];
358
+ const maxRows = 10;
359
+ const start = Math.max(0, Math.min(this.selected - maxRows + 1, Math.max(0, this.targets.length - maxRows)));
360
+ for (let index = start; index < Math.min(this.targets.length, start + maxRows); index++) {
361
+ const target = this.targets[index]!;
362
+ const selected = index === this.selected;
363
+ const marker = selected ? "›" : " ";
364
+ const actionLabel = target.actionLabel;
365
+ const action = target.kind === "scheduled" ? this.theme.fg("warning", actionLabel) : this.theme.fg("accent", actionLabel);
366
+ const labelWidth = Math.max(0, contentWidth - marker.length - actionLabel.length - 2);
367
+ lines.push(`${marker} ${action} ${target.label.slice(0, labelWidth)}`);
368
+ if (selected) lines.push(this.theme.fg("dim", ` ${target.detail}`.slice(0, contentWidth)));
369
+ }
370
+ if (this.targets.length > maxRows) lines.push(this.theme.fg("dim", `Showing ${start + 1}-${Math.min(this.targets.length, start + maxRows)} of ${this.targets.length}`));
371
+ lines.push("");
372
+ if (this.confirming) {
373
+ const target = this.targets[this.selected]!;
374
+ lines.push(this.theme.fg("warning", `Confirm: ${target.actionLabel} ${target.id}?`));
375
+ if (target.kind === "async") lines.push(this.theme.fg("dim", "Stop ends this run; use interrupt for a resumable pause."));
376
+ lines.push(this.theme.fg("dim", "Enter/Y confirms · N returns · Esc cancels"));
377
+ } else {
378
+ lines.push(this.theme.fg("dim", "↑/↓ select · Enter confirm · Esc cancel"));
379
+ }
380
+ return lines;
381
+ }
382
+ }
383
+
224
384
  function emptyUsage(): Usage {
225
385
  return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 };
226
386
  }
@@ -334,8 +494,8 @@ function parseSingleRequiredArg(args: string, usage: string): { ok: true; value:
334
494
  return { ok: true, value: parts[0]! };
335
495
  }
336
496
 
337
- function getProfileWorkerModel(profile: { subagents?: { agentOverrides?: Record<string, { model?: string }> } }): string | undefined {
338
- const model = profile.subagents?.agentOverrides?.worker?.model;
497
+ function getProfileBuilderModel(profile: { subagents?: { agentOverrides?: Record<string, { model?: string }> } }): string | undefined {
498
+ const model = profile.subagents?.agentOverrides?.builder?.model;
339
499
  return typeof model === "string" && model.trim() ? model.trim() : undefined;
340
500
  }
341
501
 
@@ -577,6 +737,13 @@ async function runSlashSubagent(
577
737
  }
578
738
  }
579
739
 
740
+ function launchSlashSubagent(
741
+ pi: ExtensionAPI,
742
+ ctx: ExtensionContext,
743
+ params: SubagentParamsLike,
744
+ ): void {
745
+ void runSlashSubagent(pi, ctx, params);
746
+ }
580
747
 
581
748
  export interface GroupConfig { concurrency?: number; failFast?: boolean; worktree?: boolean }
582
749
  export interface ParsedStep { kind: "step"; name: string; config: InlineConfig; task?: string }
@@ -841,7 +1008,7 @@ function validateInlineAcceptanceInput(value: string, agent: string): void {
841
1008
  const errors = validateAcceptanceInput(value, `acceptance for step '${agent}'`);
842
1009
  if (errors.length > 0) throw new SlashParseError(errors[0]!);
843
1010
  if (!INLINE_ACCEPTANCE_LEVELS.has(value)) {
844
- throw new SlashParseError(`Inline acceptance for step '${agent}' supports auto, attested, or checked. Use the subagent tool API or a saved .chain.json file for none, verified, or reviewed acceptance contracts.`);
1011
+ throw new SlashParseError(`Inline acceptance for step '${agent}' supports auto, attested, or checked. Use the subagent tool API or a saved .chain.json file for none, verified, or review requirements; reviewed is an achieved status, not an input level.`);
845
1012
  }
846
1013
  }
847
1014
 
@@ -977,6 +1144,32 @@ export function registerSlashCommands(
977
1144
  pi: ExtensionAPI,
978
1145
  state: SubagentState,
979
1146
  ): void {
1147
+ let fleetOpen = false;
1148
+ const showFleet = async (ctx: ExtensionContext) => {
1149
+ state.lastUiContext = ctx;
1150
+ if (!ctx.hasUI) {
1151
+ await runSlashSubagent(pi, ctx, { action: "status", view: "fleet" });
1152
+ return;
1153
+ }
1154
+ if (fleetOpen) {
1155
+ ctx.ui.notify("Subagent fleet inspector is already open.", "info");
1156
+ return;
1157
+ }
1158
+ fleetOpen = true;
1159
+ try {
1160
+ await openSubagentFleet(ctx, state);
1161
+ } finally {
1162
+ fleetOpen = false;
1163
+ }
1164
+ };
1165
+
1166
+ pi.registerCommand("subagents", {
1167
+ description: "Administer subagents: inspect metadata and update models, thinking, or prompts",
1168
+ handler: async (args, ctx) => {
1169
+ await openSubagentsAdmin(pi, ctx, args);
1170
+ },
1171
+ });
1172
+
980
1173
  pi.registerCommand("run", {
981
1174
  description: "Run a subagent directly: /run agent[output=file] [task] [--bg] [--fork]",
982
1175
  getArgumentCompletions: makeAgentCompletions(state, false),
@@ -1003,12 +1196,12 @@ export function registerSlashCommands(
1003
1196
  if (inline.model) params.model = inline.model;
1004
1197
  if (bg) params.async = true;
1005
1198
  if (fork) params.context = "fork";
1006
- await runSlashSubagent(pi, ctx, params);
1199
+ launchSlashSubagent(pi, ctx, params);
1007
1200
  },
1008
1201
  });
1009
1202
 
1010
1203
  pi.registerCommand("chain", {
1011
- description: "Run agents in sequence: /chain scout \"task\" -> planner [--bg] [--fork]",
1204
+ description: "Run agents in sequence: /chain explorer \"task\" -> architect [--bg] [--fork]",
1012
1205
  getArgumentCompletions: makeAgentCompletions(state, true),
1013
1206
  handler: async (args, ctx) => {
1014
1207
  const { args: cleanedArgs, bg, fork } = extractExecutionFlags(args);
@@ -1017,7 +1210,7 @@ export function registerSlashCommands(
1017
1210
  const params: SubagentParamsLike = { chain: built.chain, task: built.task, clarify: false, agentScope: "both" };
1018
1211
  if (bg) params.async = true;
1019
1212
  if (fork) params.context = "fork";
1020
- await runSlashSubagent(pi, ctx, params);
1213
+ launchSlashSubagent(pi, ctx, params);
1021
1214
  },
1022
1215
  });
1023
1216
 
@@ -1047,12 +1240,12 @@ export function registerSlashCommands(
1047
1240
  const params: SubagentParamsLike = { chain: mapSavedChainSteps(chain), task, clarify: false, agentScope: "both" };
1048
1241
  if (bg) params.async = true;
1049
1242
  if (fork) params.context = "fork";
1050
- await runSlashSubagent(pi, ctx, params);
1243
+ launchSlashSubagent(pi, ctx, params);
1051
1244
  },
1052
1245
  });
1053
1246
 
1054
1247
  pi.registerCommand("parallel", {
1055
- description: "Run agents in parallel: /parallel scout \"task1\" -> reviewer \"task2\" [--bg] [--fork]",
1248
+ description: "Run agents in parallel: /parallel explorer \"task1\" -> commentator \"task2\" [--bg] [--fork]",
1056
1249
  getArgumentCompletions: makeAgentCompletions(state, true),
1057
1250
  handler: async (args, ctx) => {
1058
1251
  const { args: cleanedArgs, bg, fork } = extractExecutionFlags(args);
@@ -1071,7 +1264,7 @@ export function registerSlashCommands(
1071
1264
  const params: SubagentParamsLike = { tasks, clarify: false, agentScope: "both" };
1072
1265
  if (bg) params.async = true;
1073
1266
  if (fork) params.context = "fork";
1074
- await runSlashSubagent(pi, ctx, params);
1267
+ launchSlashSubagent(pi, ctx, params);
1075
1268
  },
1076
1269
  });
1077
1270
 
@@ -1090,15 +1283,64 @@ export function registerSlashCommands(
1090
1283
  });
1091
1284
 
1092
1285
  pi.registerCommand("subagents-fleet", {
1093
- description: "Show active subagent fleet status and transcript commands",
1094
- handler: async (_args, ctx) => {
1095
- await runSlashSubagent(pi, ctx, { action: "status", view: "fleet" });
1286
+ description: "Open the live, inspection-only subagent fleet",
1287
+ handler: async (_args, ctx) => showFleet(ctx),
1288
+ });
1289
+
1290
+ pi.registerShortcut(Key.ctrlAlt("f"), {
1291
+ description: "Open subagent fleet inspector",
1292
+ handler: async (ctx) => showFleet(ctx),
1293
+ });
1294
+
1295
+ pi.registerCommand("subagents-stop", {
1296
+ description: "Stop a current-session async subagent run",
1297
+ handler: async (args, ctx) => {
1298
+ const id = args.trim();
1299
+ if (id) {
1300
+ await runSlashSubagent(pi, ctx, { action: "stop", id });
1301
+ return;
1302
+ }
1303
+
1304
+ if (process.env[SUBAGENT_FANOUT_CHILD_ENV] === "1") {
1305
+ sendSlashText(pi, "Selector unavailable in child-safe fanout mode. Pass an explicit current-session top-level async run id, for example `/subagents-stop <run-id>` or `subagent({ action: \"stop\", id: \"<run-id>\" })`.");
1306
+ return;
1307
+ }
1308
+
1309
+ let targets: StopSelectorTarget[];
1310
+ try {
1311
+ targets = discoverStopTargets(ctx, state);
1312
+ } catch (error) {
1313
+ const message = error instanceof Error ? error.message : String(error);
1314
+ ctx.ui.notify(message, "error");
1315
+ return;
1316
+ }
1317
+ if (!ctx.hasUI) {
1318
+ sendSlashText(pi, stopFallbackText(targets));
1319
+ return;
1320
+ }
1321
+ if (targets.length === 0) {
1322
+ ctx.ui.notify("No active current-session async runs or scheduled subagent runs to stop.", "info");
1323
+ return;
1324
+ }
1325
+
1326
+ const result = await ctx.ui.custom<StopSelectorResult>(
1327
+ (tui, theme, _kb, done) => new SubagentsStopSelector(tui, theme, targets, done),
1328
+ { overlay: true, overlayOptions: { anchor: "center", width: 88, maxHeight: "80%" } },
1329
+ );
1330
+ if (!result?.confirmed || !result.target) return;
1331
+ if (result.target.kind === "scheduled") {
1332
+ await runSlashSubagent(pi, ctx, { action: "schedule-cancel", id: result.target.id });
1333
+ return;
1334
+ }
1335
+ await runSlashSubagent(pi, ctx, { action: "stop", id: result.target.id });
1096
1336
  },
1097
1337
  });
1098
1338
 
1099
1339
  registerPromptWorkflowCommands({
1100
1340
  pi,
1101
- run: (params, ctx) => runSlashSubagent(pi, ctx, params),
1341
+ run: async (params, ctx) => {
1342
+ launchSlashSubagent(pi, ctx, params);
1343
+ },
1102
1344
  });
1103
1345
 
1104
1346
  pi.registerCommand("subagents-models", {
@@ -1153,7 +1395,7 @@ export function registerSlashCommands(
1153
1395
  try {
1154
1396
  await withSlashStatus(ctx, `Loading profile ${parsed.value}…`, async () => {
1155
1397
  const { profile } = readSubagentProfile(parsed.value);
1156
- const workerModel = getProfileWorkerModel(profile);
1398
+ const builderModel = getProfileBuilderModel(profile);
1157
1399
  const result = applySubagentProfile(parsed.value);
1158
1400
  const lines = [
1159
1401
  `Loaded subagent profile: ${parsed.value}`,
@@ -1161,24 +1403,24 @@ export function registerSlashCommands(
1161
1403
  `Updated: ${result.settingsPath}`,
1162
1404
  ];
1163
1405
 
1164
- if (workerModel && typeof pi.setModel === "function" && typeof ctx.modelRegistry?.find === "function" && typeof ctx.modelRegistry?.getAvailable === "function") {
1406
+ if (builderModel && typeof pi.setModel === "function" && typeof ctx.modelRegistry?.find === "function" && typeof ctx.modelRegistry?.getAvailable === "function") {
1165
1407
  const shouldSwitch = await ctx.ui.confirm(
1166
1408
  "",
1167
- `Profile loaded. Also switch this session to the profile worker model?\n\n${workerModel}`,
1409
+ `Profile loaded. Also switch this session to the profile builder model?\n\n${builderModel}`,
1168
1410
  );
1169
1411
  if (shouldSwitch) {
1170
- const modelInfo = findModelInfo(workerModel, ctx.modelRegistry.getAvailable().map(toModelInfo));
1412
+ const modelInfo = findModelInfo(builderModel, ctx.modelRegistry.getAvailable().map(toModelInfo));
1171
1413
  const model = modelInfo ? ctx.modelRegistry.find(modelInfo.provider, modelInfo.id) : undefined;
1172
1414
  if (!modelInfo || !model) {
1173
- lines.push(`Could not switch current session model: '${workerModel}' is not available in the current model registry.`);
1415
+ lines.push(`Could not switch current session model: '${builderModel}' is not available in the current model registry.`);
1174
1416
  } else {
1175
1417
  const success = await pi.setModel(model);
1176
1418
  if (success) lines.push(`Current session model switched to: ${modelInfo.fullId}`);
1177
- else lines.push(`Could not switch current session model to '${workerModel}': no API key or provider access is available.`);
1419
+ else lines.push(`Could not switch current session model to '${builderModel}': no API key or provider access is available.`);
1178
1420
  }
1179
1421
  }
1180
- } else if (workerModel) {
1181
- lines.push(`Profile worker model: ${workerModel}`);
1422
+ } else if (builderModel) {
1423
+ lines.push(`Profile builder model: ${builderModel}`);
1182
1424
  }
1183
1425
 
1184
1426
  sendSlashText(pi, lines.join("\n"));
@@ -193,8 +193,8 @@ function cloneResultsWithProgress(
193
193
  progress: NonNullable<Details["progress"]> | undefined,
194
194
  ): SingleResult[] {
195
195
  return results.map((result, index) => {
196
- const nextProgress = progress?.find((entry) => entry.index === index)
197
- ?? progress?.[index]
196
+ const nextProgress = progress?.find((entry) => entry.index === index
197
+ || (entry.index === undefined && entry.agent === result.agent))
198
198
  ?? result.progress;
199
199
  return nextProgress ? { ...result, progress: nextProgress } : result;
200
200
  });