@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
@@ -23,6 +23,7 @@ import { getDisplayItems, getSingleResultOutput } from "../shared/utils.ts";
23
23
  import { flatToLogicalStepIndex } from "../runs/background/parallel-groups.ts";
24
24
  import { formatNestedAggregate } from "../runs/shared/nested-render.ts";
25
25
  import { aggregateStepStatus, formatActivityLabel, formatAgentRunningLabel, formatParallelOutcome } from "../shared/status-format.ts";
26
+ import { contextModeBadge, contextModePrefix } from "../runs/shared/context-mode.ts";
26
27
 
27
28
  type Theme = ExtensionContext["ui"]["theme"];
28
29
 
@@ -268,6 +269,7 @@ function firstOutputLine(text: string): string {
268
269
 
269
270
  function resultStatusLine(result: Details["results"][number], output: string): string {
270
271
  if (result.detached) return result.detachedReason ? `Detached: ${result.detachedReason}` : "Detached";
272
+ if (result.stopped) return "Stopped";
271
273
  if (result.interrupted) return "Paused";
272
274
  if (result.exitCode !== 0) return `Error: ${result.error ?? (firstOutputLine(output) || `exit ${result.exitCode}`)}`;
273
275
  if (result.acceptance?.status && result.acceptance.status !== "not-required") return `Done · acceptance: ${result.acceptance.status}`;
@@ -281,6 +283,7 @@ function resultGlyph(result: Details["results"][number], output: string, theme:
281
283
  return theme.fg("accent", runningGlyph(seed));
282
284
  }
283
285
  if (result.detached) return theme.fg("warning", "■");
286
+ if (result.stopped) return theme.fg("warning", "■");
284
287
  if (result.interrupted) return theme.fg("warning", "■");
285
288
  if (result.exitCode !== 0) return theme.fg("error", "✗");
286
289
  if (hasEmptyTextOutputWithoutOutputTarget(result.task, output)) return theme.fg("warning", "✓");
@@ -349,6 +352,7 @@ function widgetActivity(job: AsyncJobState): string {
349
352
  if (job.status === "running") return "thinking…";
350
353
  if (job.status === "queued") return "queued…";
351
354
  if (job.status === "paused") return "Paused";
355
+ if (job.status === "stopped") return "Stopped";
352
356
  if (job.status === "failed") return "Failed";
353
357
  return "Done";
354
358
  }
@@ -397,6 +401,7 @@ function widgetStatusGlyph(job: AsyncJobState, theme: Theme): string {
397
401
  if (job.status === "queued") return theme.fg("muted", "◦");
398
402
  if (job.status === "complete") return theme.fg("success", "✓");
399
403
  if (job.status === "paused") return theme.fg("warning", "■");
404
+ if (job.status === "stopped") return theme.fg("warning", "■");
400
405
  return theme.fg("error", "✗");
401
406
  }
402
407
 
@@ -405,6 +410,7 @@ function widgetStepGlyph(status: AsyncJobStep["status"], theme: Theme, seed?: nu
405
410
  if (status === "complete" || status === "completed") return theme.fg("success", "✓");
406
411
  if (status === "failed") return theme.fg("error", "✗");
407
412
  if (status === "paused") return theme.fg("warning", "■");
413
+ if (status === "stopped") return theme.fg("warning", "■");
408
414
  return theme.fg("muted", "◦");
409
415
  }
410
416
 
@@ -413,6 +419,7 @@ function widgetStepStatus(status: AsyncJobStep["status"], theme: Theme): string
413
419
  if (status === "complete" || status === "completed") return theme.fg("success", "complete");
414
420
  if (status === "failed") return theme.fg("error", "failed");
415
421
  if (status === "paused") return theme.fg("warning", "paused");
422
+ if (status === "stopped") return theme.fg("warning", "stopped");
416
423
  return theme.fg("dim", status);
417
424
  }
418
425
 
@@ -620,7 +627,7 @@ function buildMultiProgressLabel(details: Pick<Details, "mode" | "results" | "pr
620
627
 
621
628
  if (details.mode === "parallel") {
622
629
  const totalCount = details.totalSteps ?? details.results.length;
623
- const statuses = new Array(totalCount).fill("pending") as Array<"pending" | "running" | "completed" | "failed" | "detached">;
630
+ const statuses = new Array(totalCount).fill("pending") as Array<"pending" | "running" | "completed" | "failed" | "stopped" | "detached">;
624
631
  for (const progress of details.progress ?? []) {
625
632
  if (progress.index >= 0 && progress.index < totalCount) statuses[progress.index] = progress.status;
626
633
  }
@@ -631,11 +638,13 @@ function buildMultiProgressLabel(details: Pick<Details, "mode" | "results" | "pr
631
638
  const index = result.progress?.index ?? progressFromArray?.index ?? i;
632
639
  if (index < 0 || index >= totalCount) continue;
633
640
  const status = result.progress?.status
634
- ?? (result.interrupted || result.detached
635
- ? "detached"
636
- : result.exitCode === 0
637
- ? "completed"
638
- : "failed");
641
+ ?? (result.stopped
642
+ ? "stopped"
643
+ : result.interrupted || result.detached
644
+ ? "detached"
645
+ : result.exitCode === 0
646
+ ? "completed"
647
+ : "failed");
639
648
  statuses[index] = status;
640
649
  }
641
650
  const running = statuses.filter((status) => status === "running").length;
@@ -788,6 +797,7 @@ function nestedStatusGlyph(state: NestedRunSummary["state"] | NestedStepSummary[
788
797
  if (state === "complete" || state === "completed") return theme.fg("success", "✓");
789
798
  if (state === "failed") return theme.fg("error", "✗");
790
799
  if (state === "paused") return theme.fg("warning", "■");
800
+ if (state === "stopped") return theme.fg("warning", "■");
791
801
  return theme.fg("muted", "◦");
792
802
  }
793
803
 
@@ -795,6 +805,29 @@ function nestedRunSeed(run: NestedRunSummary): number | undefined {
795
805
  return runningSeed(run.lastUpdate, run.lastActivityAt, run.currentStep, run.toolCount, run.turnCount, run.totalTokens?.total, run.currentToolStartedAt);
796
806
  }
797
807
 
808
+ function formatClockTime(ms: number | undefined): string | undefined {
809
+ if (ms === undefined || !Number.isFinite(ms)) return undefined;
810
+ const date = new Date(ms);
811
+ const pad = (value: number) => value.toString().padStart(2, "0");
812
+ return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
813
+ }
814
+
815
+ function nestedRunEventTime(run: NestedRunSummary): number | undefined {
816
+ return run.state === "running"
817
+ ? (run.lastActivityAt ?? run.currentToolStartedAt ?? run.lastUpdate ?? run.startedAt)
818
+ : (run.endedAt ?? run.lastUpdate ?? run.lastActivityAt ?? run.startedAt);
819
+ }
820
+
821
+ function nestedStepTimestamp(step: NestedStepSummary, fallback?: number): string | undefined {
822
+ return formatClockTime(step.status === "running"
823
+ ? (step.lastActivityAt ?? step.currentToolStartedAt ?? fallback ?? step.startedAt)
824
+ : (step.endedAt ?? step.lastActivityAt ?? fallback ?? step.startedAt));
825
+ }
826
+
827
+ function nestedTimestampPrefix(timestamp: string | undefined): string {
828
+ return timestamp ? `[${timestamp}] ` : "";
829
+ }
830
+
798
831
  function nestedActivity(input: Pick<NestedRunSummary | NestedStepSummary, "activityState" | "lastActivityAt" | "currentTool" | "currentToolStartedAt" | "currentPath" | "turnCount" | "toolCount">, state: NestedRunSummary["state"] | NestedStepSummary["status"], snapshotNow?: number): string {
799
832
  const facts: string[] = [];
800
833
  if (input.currentTool && input.currentToolStartedAt !== undefined && snapshotNow !== undefined) facts.push(`${input.currentTool} ${formatDuration(Math.max(0, snapshotNow - input.currentToolStartedAt))}`);
@@ -809,6 +842,7 @@ function nestedActivity(input: Pick<NestedRunSummary | NestedStepSummary, "activ
809
842
  if (state === "running") return "thinking…";
810
843
  if (state === "queued" || state === "pending") return "queued…";
811
844
  if (state === "paused") return "Paused";
845
+ if (state === "stopped") return "Stopped";
812
846
  if (state === "failed") return "Failed";
813
847
  return "Done";
814
848
  }
@@ -817,7 +851,8 @@ function formatNestedWidgetLines(children: NestedRunSummary[] | undefined, theme
817
851
  if (!children?.length || lineBudget <= 0) return [];
818
852
  if (!expanded) {
819
853
  const aggregate = formatNestedAggregate(children);
820
- return aggregate ? [theme.fg("dim", `↳ ${aggregate}`)] : [];
854
+ const latest = children.reduce((acc, child) => Math.max(acc, nestedRunEventTime(child) ?? 0), 0);
855
+ return aggregate ? [theme.fg("dim", `↳ ${nestedTimestampPrefix(formatClockTime(latest))}${aggregate}`)] : [];
821
856
  }
822
857
  const lines: string[] = [];
823
858
  const maxDepth = 2;
@@ -837,7 +872,7 @@ function formatNestedWidgetLines(children: NestedRunSummary[] | undefined, theme
837
872
  }
838
873
  const activity = nestedActivity(child, child.state, snapshotNow ?? child.lastUpdate);
839
874
  const error = child.error ? ` · ${child.error}` : "";
840
- lines.push(theme.fg("dim", `${prefix}↳ ${nestedStatusGlyph(child.state, theme, nestedRunSeed(child))} ${nestedRunName(child)} · ${child.state} · ${activity}${error}`));
875
+ lines.push(theme.fg("dim", `${prefix}↳ ${nestedTimestampPrefix(formatClockTime(nestedRunEventTime(child)))}${nestedStatusGlyph(child.state, theme, nestedRunSeed(child))} ${nestedRunName(child)} · ${child.state} · ${activity}${error}`));
841
876
  if (depth === maxDepth) {
842
877
  const aggregate = formatNestedAggregate([...(child.steps?.flatMap((step) => step.children ?? []) ?? []), ...(child.children ?? [])]);
843
878
  if (aggregate && lines.length < lineBudget) lines.push(theme.fg("dim", `${prefix} ↳ ${aggregate}`));
@@ -845,7 +880,7 @@ function formatNestedWidgetLines(children: NestedRunSummary[] | undefined, theme
845
880
  }
846
881
  for (const step of child.steps ?? []) {
847
882
  if (lines.length >= lineBudget) return;
848
- lines.push(theme.fg("dim", `${prefix} ↳ ${nestedStatusGlyph(step.status, theme)} ${step.agent} · ${step.status} · ${nestedActivity(step, step.status, snapshotNow ?? child.lastUpdate)}`));
883
+ lines.push(theme.fg("dim", `${prefix} ↳ ${nestedTimestampPrefix(nestedStepTimestamp(step, child.lastUpdate))}${nestedStatusGlyph(step.status, theme)} ${step.agent} · ${step.status} · ${nestedActivity(step, step.status, snapshotNow ?? child.lastUpdate)}`));
849
884
  append(step.children, depth + 1, `${prefix} `);
850
885
  }
851
886
  append(child.children, depth + 1, `${prefix} `);
@@ -868,7 +903,7 @@ function foregroundStyleWidgetStepLines(
868
903
  const status = widgetStepStatus(step.status, theme);
869
904
  const stats = widgetStepStats(theme, step);
870
905
  const modelDisplay = modelThinkingBadge(theme, step.model, step.thinking);
871
- const lines = [` ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index - 1))} ${itemTitle} ${index}/${total}: ${themeBold(theme, step.agent)} ${theme.fg("dim", "·")} ${status}${modelDisplay}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`];
906
+ const lines = [` ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index - 1))} ${itemTitle} ${index}/${total}: ${themeBold(theme, step.agent)}${contextModeBadge(theme, step.context)} ${theme.fg("dim", "·")} ${status}${modelDisplay}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`];
872
907
  const activity = widgetStepActivityLine(step, width, expanded, job.updatedAt);
873
908
  if (activity) lines.push(` ${theme.fg("dim", `⎿ ${activity}`)}`);
874
909
  for (const nestedLine of formatNestedWidgetLines(step.children, theme, width, expanded, job.updatedAt)) {
@@ -921,7 +956,7 @@ function buildSingleWidgetLines(job: AsyncJobState, theme: Theme, width: number,
921
956
  const title = `async subagent ${mode}${count && count > 1 ? ` (${count})` : ""}`;
922
957
  return [
923
958
  `${theme.fg("toolTitle", themeBold(theme, title))} ${theme.fg("dim", "· background")}`,
924
- `${widgetStatusGlyph(job, theme)} ${themeBold(theme, mode)}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
959
+ `${widgetStatusGlyph(job, theme)} ${themeBold(theme, mode)}${contextModeBadge(theme, job.context)}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
925
960
  ...foregroundStyleWidgetDetails(job, theme, expanded, width),
926
961
  ].map((line) => truncLine(line, width));
927
962
  }
@@ -939,7 +974,7 @@ function compactSingleWidgetLines(job: AsyncJobState, theme: Theme, width: numbe
939
974
  const stepStats = widgetStepStats(theme, step);
940
975
  const activitySuffix = activity ? ` ${theme.fg("dim", "·")} ${theme.fg("dim", activity)}` : "";
941
976
  const modelDisplay = modelThinkingBadge(theme, step.model, step.thinking);
942
- lines.push(` ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index))} ${itemTitle} ${index + 1}/${total}: ${themeBold(theme, step.agent)} ${theme.fg("dim", "·")} ${status}${modelDisplay}${activitySuffix}${stepStats ? ` ${theme.fg("dim", "·")} ${stepStats}` : ""}`);
977
+ lines.push(` ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index))} ${itemTitle} ${index + 1}/${total}: ${themeBold(theme, step.agent)}${contextModeBadge(theme, step.context)} ${theme.fg("dim", "·")} ${status}${modelDisplay}${activitySuffix}${stepStats ? ` ${theme.fg("dim", "·")} ${stepStats}` : ""}`);
943
978
  for (const nestedLine of formatNestedWidgetLines(step.children, theme, width, false, job.updatedAt)) lines.push(` ${nestedLine}`);
944
979
  }
945
980
  if (job.steps.some((step) => step.status === "running")) lines.push(theme.fg("accent", ` ${liveDetailHintText()}`));
@@ -984,13 +1019,14 @@ function widgetSessionMatches(expanded: boolean): boolean {
984
1019
  && widgetLayoutSession.columns === currentTerminalColumns();
985
1020
  }
986
1021
 
987
- function widgetHeaderCounts(jobs: AsyncJobState[]): { running: AsyncJobState[]; queued: AsyncJobState[]; complete: AsyncJobState[]; failed: AsyncJobState[]; paused: AsyncJobState[] } {
1022
+ function widgetHeaderCounts(jobs: AsyncJobState[]): { running: AsyncJobState[]; queued: AsyncJobState[]; complete: AsyncJobState[]; failed: AsyncJobState[]; paused: AsyncJobState[]; stopped: AsyncJobState[] } {
988
1023
  return {
989
1024
  running: jobs.filter((job) => job.status === "running"),
990
1025
  queued: jobs.filter((job) => job.status === "queued"),
991
1026
  complete: jobs.filter((job) => job.status === "complete"),
992
1027
  failed: jobs.filter((job) => job.status === "failed"),
993
1028
  paused: jobs.filter((job) => job.status === "paused"),
1029
+ stopped: jobs.filter((job) => job.status === "stopped"),
994
1030
  };
995
1031
  }
996
1032
 
@@ -1002,6 +1038,7 @@ function buildSingleLineWidgetLines(jobs: AsyncJobState[], theme: Theme, width:
1002
1038
  if (counts.running.length > 0) parts.push(`${counts.running.length}/${jobs.length} running`);
1003
1039
  if (counts.queued.length > 0) parts.push(`${counts.queued.length} queued`);
1004
1040
  if (counts.failed.length > 0) parts.push(`${counts.failed.length} failed`);
1041
+ if (counts.stopped.length > 0) parts.push(`${counts.stopped.length} stopped`);
1005
1042
  if (counts.paused.length > 0) parts.push(`${counts.paused.length} paused`);
1006
1043
  if (!hasActive && counts.complete.length > 0) parts.push(`${counts.complete.length}/${jobs.length} done`);
1007
1044
  return [truncLine(`${theme.fg(hasActive ? "accent" : "dim", glyph)} ${theme.fg(hasActive ? "accent" : "dim", "subagents")} (${parts.join(", ") || `${jobs.length} total`})`, width)];
@@ -1065,6 +1102,7 @@ function progressiveHeaderLine(jobs: AsyncJobState[], theme: Theme, width: numbe
1065
1102
  if (counts.queued.length > 0) parts.push(`${counts.queued.length} queued`);
1066
1103
  if (!hasActive) {
1067
1104
  if (counts.failed.length > 0) parts.push(`${counts.failed.length} failed`);
1105
+ if (counts.stopped.length > 0) parts.push(`${counts.stopped.length} stopped`);
1068
1106
  if (counts.paused.length > 0) parts.push(`${counts.paused.length} paused`);
1069
1107
  if (counts.complete.length > 0) parts.push(`${counts.complete.length}/${jobs.length} done`);
1070
1108
  }
@@ -1076,7 +1114,7 @@ function progressiveJobLine(job: AsyncJobState, theme: Theme, width: number): st
1076
1114
  const activity = widgetActivity(job);
1077
1115
  const status = job.status === "complete" ? "done" : job.status;
1078
1116
  const parts = [
1079
- themeBold(theme, widgetJobName(job)),
1117
+ `${themeBold(theme, widgetJobName(job))}${contextModeBadge(theme, job.context)}`,
1080
1118
  theme.fg("dim", status),
1081
1119
  stats,
1082
1120
  activity && activity.toLowerCase() !== status ? theme.fg("dim", activity) : "",
@@ -1089,7 +1127,7 @@ function progressiveHiddenLine(hiddenJobs: AsyncJobState[], theme: Theme, width:
1089
1127
  const parts: string[] = [];
1090
1128
  if (counts.running.length > 0) parts.push(`${counts.running.length} running`);
1091
1129
  if (counts.queued.length > 0) parts.push(`${counts.queued.length} queued`);
1092
- const finished = counts.complete.length + counts.failed.length + counts.paused.length;
1130
+ const finished = counts.complete.length + counts.failed.length + counts.paused.length + counts.stopped.length;
1093
1131
  if (finished > 0) parts.push(`${finished} finished`);
1094
1132
  return truncLine(theme.fg("dim", ` +${hiddenJobs.length} more${parts.length ? ` (${parts.join(", ")})` : ""}`), width);
1095
1133
  }
@@ -1211,7 +1249,7 @@ export function buildWidgetLines(jobs: AsyncJobState[], theme: Theme, width = ge
1211
1249
  if (slots <= 0) { hiddenRunning++; continue; }
1212
1250
  const stats = widgetStats(job, theme);
1213
1251
  items.push([
1214
- `${widgetStatusGlyph(job, theme)} ${themeBold(theme, widgetJobName(job))}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
1252
+ `${widgetStatusGlyph(job, theme)} ${themeBold(theme, widgetJobName(job))}${contextModeBadge(theme, job.context)}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
1215
1253
  ` ${theme.fg("dim", `⎿ ${widgetActivity(job)}`)}`,
1216
1254
  ...widgetParallelAgentDetails(job, theme, expanded, width),
1217
1255
  ]);
@@ -1228,7 +1266,7 @@ export function buildWidgetLines(jobs: AsyncJobState[], theme: Theme, width = ge
1228
1266
  if (slots <= 0) { hiddenFinished++; continue; }
1229
1267
  const stats = widgetStats(job, theme);
1230
1268
  items.push([
1231
- `${widgetStatusGlyph(job, theme)} ${themeBold(theme, widgetJobName(job))}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
1269
+ `${widgetStatusGlyph(job, theme)} ${themeBold(theme, widgetJobName(job))}${contextModeBadge(theme, job.context)}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
1232
1270
  ` ${theme.fg("dim", `⎿ ${widgetActivity(job)}`)}`,
1233
1271
  ...widgetParallelAgentDetails(job, theme, expanded, width),
1234
1272
  ]);
@@ -1276,7 +1314,7 @@ function renderSingleCompact(d: Details, r: Details["results"][number], theme: T
1276
1314
  const output = r.truncation?.text || getSingleResultOutput(r);
1277
1315
  const progress = r.progress || r.progressSummary;
1278
1316
  const isRunning = r.progress?.status === "running";
1279
- const contextBadge = d.context === "fork" ? theme.fg("warning", " [fork]") : "";
1317
+ const contextBadge = contextModeBadge(theme, r.context ?? d.context);
1280
1318
  const stats = statJoin(theme, [
1281
1319
  r.usage?.turns ? `⟳ ${r.usage.turns}` : "",
1282
1320
  formatProgressStats(theme, progress),
@@ -1292,11 +1330,17 @@ function renderSingleCompact(d: Details, r: Details["results"][number], theme: T
1292
1330
  c.addChild(new Text(truncLine(theme.fg("dim", ` ⎿ ${activity}`), width), 0, 0));
1293
1331
  const liveStatus = buildLiveStatusLine(r.progress, progressSnapshotNow);
1294
1332
  if (liveStatus && liveStatus !== activity) c.addChild(new Text(truncLine(theme.fg("dim", ` ${liveStatus}`), width), 0, 0));
1333
+ for (const nestedLine of formatNestedWidgetLines(r.children, theme, width, false, progressSnapshotNow)) {
1334
+ c.addChild(new Text(truncLine(` ${nestedLine}`, width), 0, 0));
1335
+ }
1295
1336
  c.addChild(new Text(truncLine(theme.fg("accent", ` ${liveDetailHintText()}`), width), 0, 0));
1296
1337
  if (r.artifactPaths) c.addChild(new Text(truncLine(theme.fg("dim", ` output: ${shortenPath(r.artifactPaths.outputPath)}`), width), 0, 0));
1297
1338
  return c;
1298
1339
  }
1299
1340
 
1341
+ for (const nestedLine of formatNestedWidgetLines(r.children, theme, width, false, r.progress?.lastActivityAt)) {
1342
+ c.addChild(new Text(truncLine(` ${nestedLine}`, width), 0, 0));
1343
+ }
1300
1344
  c.addChild(new Text(truncLine(theme.fg("dim", ` ⎿ ${resultStatusLine(r, output)}`), width), 0, 0));
1301
1345
  const preview = firstOutputLine(output);
1302
1346
  if (preview && r.exitCode === 0 && !hasEmptyTextOutputWithoutOutputTarget(r.task, output)) {
@@ -1312,7 +1356,9 @@ function renderMultiCompact(d: Details, theme: Theme, frame?: number): Component
1312
1356
  const hasRunning = d.progress?.some((p) => p.status === "running")
1313
1357
  || d.results.some((r) => r.progress?.status === "running")
1314
1358
  || workflowGraphHasStatus(d, ["running"]);
1315
- const failed = d.results.some((r) => r.exitCode !== 0 && r.progress?.status !== "running")
1359
+ const stopped = d.results.some((r) => r.stopped && r.progress?.status !== "running")
1360
+ || workflowGraphHasStatus(d, ["stopped"]);
1361
+ const failed = d.results.some((r) => !r.stopped && r.exitCode !== 0 && r.progress?.status !== "running")
1316
1362
  || workflowGraphHasStatus(d, ["failed"]);
1317
1363
  const paused = d.results.some((r) => (r.interrupted || r.detached) && r.progress?.status !== "running")
1318
1364
  || workflowGraphHasStatus(d, ["paused", "detached"]);
@@ -1335,12 +1381,14 @@ function renderMultiCompact(d: Details, theme: Theme, frame?: number): Component
1335
1381
  const stats = statJoin(theme, [multiLabel.headerLabel, formatProgressStats(theme, totalSummary), formatTotalCostStat(d.totalCost)]);
1336
1382
  const glyph = hasRunning
1337
1383
  ? theme.fg("accent", runningGlyph(frame !== undefined ? (runningSeed(progressRunningSeed(totalSummary), d.currentStepIndex) ?? 0) + frame : runningSeed(progressRunningSeed(totalSummary), d.currentStepIndex)))
1338
- : failed
1339
- ? theme.fg("error", "✗")
1384
+ : stopped
1385
+ ? theme.fg("warning", "■")
1386
+ : failed
1387
+ ? theme.fg("error", "✗")
1340
1388
  : paused
1341
1389
  ? theme.fg("warning", "■")
1342
1390
  : theme.fg("success", "✓");
1343
- const contextBadge = d.context === "fork" ? theme.fg("warning", " [fork]") : "";
1391
+ const contextBadge = contextModeBadge(theme, d.context);
1344
1392
  const c = new Container();
1345
1393
  const width = getTermWidth() - 4;
1346
1394
  c.addChild(new Text(truncLine(`${glyph} ${theme.fg("toolTitle", theme.bold(d.mode))}${contextBadge}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`, width), 0, 0));
@@ -1383,15 +1431,23 @@ function renderMultiCompact(d: Details, theme: Theme, frame?: number): Component
1383
1431
  const glyph = rPending ? theme.fg("dim", "◦") : resultGlyph(r, output, theme, rRunning, progressRunningSeed(rProg), frame);
1384
1432
  const pendingLabel = rPending ? ` ${theme.fg("dim", "· pending")}` : "";
1385
1433
  const stepLabel = resultRowLabel(d, multiLabel, i, stepNumber);
1386
- const line = `${glyph} ${stepLabel}: ${themeBold(theme, agentName)}${stepStats ? ` ${theme.fg("dim", "·")} ${stepStats}` : ""}${pendingLabel}`;
1434
+ const line = `${glyph} ${stepLabel}: ${themeBold(theme, agentName)}${contextModeBadge(theme, r.context)}${stepStats ? ` ${theme.fg("dim", "·")} ${stepStats}` : ""}${pendingLabel}`;
1387
1435
  c.addChild(new Text(truncLine(` ${line}`, width), 0, 0));
1388
1436
  if (rRunning && rProg && "status" in rProg) {
1389
1437
  const activity = compactCurrentActivity(rProg);
1390
1438
  c.addChild(new Text(truncLine(theme.fg("dim", ` ⎿ ${activity}`), width), 0, 0));
1439
+ for (const nestedLine of formatNestedWidgetLines(r.children, theme, width, false, snapshotNowForProgress(rProg))) {
1440
+ c.addChild(new Text(truncLine(` ${nestedLine}`, width), 0, 0));
1441
+ }
1391
1442
  c.addChild(new Text(truncLine(theme.fg("accent", ` ${liveDetailHintText()}`), width), 0, 0));
1392
1443
  } else if (!rPending && (r.exitCode !== 0 || r.interrupted || r.detached || hasEmptyTextOutputWithoutOutputTarget(r.task, output))) {
1393
1444
  c.addChild(new Text(truncLine(theme.fg(r.exitCode !== 0 ? "error" : "dim", ` ⎿ ${resultStatusLine(r, output)}`), width), 0, 0));
1394
1445
  }
1446
+ if (!rRunning && !rPending) {
1447
+ for (const nestedLine of formatNestedWidgetLines(r.children, theme, width, false, r.progress?.lastActivityAt)) {
1448
+ c.addChild(new Text(truncLine(` ${nestedLine}`, width), 0, 0));
1449
+ }
1450
+ }
1395
1451
  const outputTarget = extractOutputTarget(r.task);
1396
1452
  if (outputTarget) c.addChild(new Text(truncLine(theme.fg("dim", ` output: ${outputTarget}`), width), 0, 0));
1397
1453
  if (r.artifactPaths) c.addChild(new Text(truncLine(theme.fg("dim", ` output: ${shortenPath(r.artifactPaths.outputPath)}`), width), 0, 0));
@@ -1413,9 +1469,17 @@ export function renderSubagentResult(
1413
1469
  if (!d || !d.results.length) {
1414
1470
  const t = result.content[0];
1415
1471
  const text = t?.type === "text" ? t.text : "(no output)";
1416
- const contextPrefix = d?.context === "fork" ? `${theme.fg("warning", "[fork]")} ` : "";
1472
+ const contextPrefix = contextModePrefix(theme, d?.context);
1417
1473
  const width = getTermWidth() - 4;
1418
1474
  if (!text.includes("\n")) return new Text(truncLine(`${contextPrefix}${text}`, width), 0, 0);
1475
+ if (d && !options.expanded && !result.isError) {
1476
+ const lines = text.split(/\r?\n/);
1477
+ const firstNonEmptyLine = lines.find((line) => line.trim())?.trim() || "(no output)";
1478
+ const c = new Container();
1479
+ c.addChild(new Text(truncLine(`${contextPrefix}${firstNonEmptyLine} · ${lines.length} lines`, width), 0, 0));
1480
+ c.addChild(new Text(truncLine(theme.fg("accent", ` Press ${liveDetailKeyText()} for full output`), width), 0, 0));
1481
+ return c;
1482
+ }
1419
1483
  const c = new Container();
1420
1484
  const wrapped = wrapPlainText(`${contextPrefix}${text}`, width);
1421
1485
  for (const line of wrapped) c.addChild(new Text(line, 0, 0));
@@ -1436,7 +1500,7 @@ export function renderSubagentResult(
1436
1500
  : r.exitCode === 0
1437
1501
  ? theme.fg("success", "ok")
1438
1502
  : theme.fg("error", "failed");
1439
- const contextBadge = d.context === "fork" ? theme.fg("warning", " [fork]") : "";
1503
+ const contextBadge = contextModeBadge(theme, r.context ?? d.context);
1440
1504
  const output = r.truncation?.text || getSingleResultOutput(r);
1441
1505
 
1442
1506
  const progressInfo = isRunning && r.progress
@@ -1462,6 +1526,9 @@ export function renderSubagentResult(
1462
1526
 
1463
1527
  if (isRunning && r.progress) {
1464
1528
  const progressSnapshotNow = snapshotNowForProgress(r.progress);
1529
+ for (const nestedLine of formatNestedWidgetLines(r.children, theme, w, true, progressSnapshotNow, 12)) {
1530
+ c.addChild(new Text(fit(` ${nestedLine}`), 0, 0));
1531
+ }
1465
1532
  const toolLine = formatCurrentToolLine(r.progress, w, expanded, progressSnapshotNow);
1466
1533
  if (toolLine) {
1467
1534
  c.addChild(new Text(fit(theme.fg("warning", `> ${toolLine}`)), 0, 0));
@@ -1489,6 +1556,10 @@ export function renderSubagentResult(
1489
1556
  if (toolLine || liveStatusLine || r.progress.recentTools?.length || r.progress.recentOutput?.length || r.artifactPaths) {
1490
1557
  c.addChild(new Spacer(1));
1491
1558
  }
1559
+ } else {
1560
+ for (const nestedLine of formatNestedWidgetLines(r.children, theme, w, true, r.progress?.lastActivityAt, 8)) {
1561
+ c.addChild(new Text(fit(` ${nestedLine}`), 0, 0));
1562
+ }
1492
1563
  }
1493
1564
 
1494
1565
  if (expanded) {
@@ -1533,6 +1604,7 @@ export function renderSubagentResult(
1533
1604
  && hasEmptyTextOutputWithoutOutputTarget(r.task, getSingleResultOutput(r)),
1534
1605
  );
1535
1606
  const hasWorkflowFailure = workflowGraphHasStatus(d, ["failed"]);
1607
+ const hasWorkflowStop = d.results.some((r) => r.stopped && r.progress?.status !== "running") || workflowGraphHasStatus(d, ["stopped"]);
1536
1608
  const hasWorkflowPause = workflowGraphHasStatus(d, ["paused", "detached"]);
1537
1609
  const icon = hasRunning
1538
1610
  ? theme.fg("warning", "running")
@@ -1540,8 +1612,10 @@ export function renderSubagentResult(
1540
1612
  ? theme.fg("warning", "warning")
1541
1613
  : hasWorkflowFailure
1542
1614
  ? theme.fg("error", "failed")
1543
- : hasWorkflowPause
1544
- ? theme.fg("warning", "paused")
1615
+ : hasWorkflowStop
1616
+ ? theme.fg("warning", "stopped")
1617
+ : hasWorkflowPause
1618
+ ? theme.fg("warning", "paused")
1545
1619
  : ok === d.results.length
1546
1620
  ? theme.fg("success", "ok")
1547
1621
  : theme.fg("error", "failed");
@@ -1573,7 +1647,7 @@ export function renderSubagentResult(
1573
1647
  const summaryStr = summaryParts.length ? ` | ${summaryParts.join(", ")}` : "";
1574
1648
 
1575
1649
  const modeLabel = d.mode;
1576
- const contextBadge = d.context === "fork" ? theme.fg("warning", " [fork]") : "";
1650
+ const contextBadge = contextModeBadge(theme, d.context);
1577
1651
  const multiLabel = buildMultiProgressLabel(d, hasRunning);
1578
1652
  const itemTitle = multiLabel.itemTitle;
1579
1653
 
@@ -1596,7 +1670,7 @@ export function renderSubagentResult(
1596
1670
  : isCurrent && hasRunning
1597
1671
  ? theme.fg("warning", "running")
1598
1672
  : theme.fg("dim", "pending");
1599
- return `${stepIcon} ${agent}`;
1673
+ return `${stepIcon} ${agent}${contextModeBadge(theme, result?.context)}`;
1600
1674
  })
1601
1675
  .join(theme.fg("dim", " → "))
1602
1676
  : null;
@@ -1667,9 +1741,10 @@ export function renderSubagentResult(
1667
1741
  const stats = rProg ? ` | ${rProg.toolCount} tools, ${formatDuration(rProg.durationMs)}` : "";
1668
1742
  const modelDisplay = modelThinkingBadge(theme, r.model);
1669
1743
  const stepLabel = resultRowLabel(d, multiLabel, i, stepNumber);
1744
+ const contextBadge = contextModeBadge(theme, r.context);
1670
1745
  const stepHeader = rRunning
1671
- ? `${statusIcon} ${stepLabel}: ${theme.bold(theme.fg("warning", r.agent))}${modelDisplay}${stats}`
1672
- : `${statusIcon} ${stepLabel}: ${theme.bold(r.agent)}${modelDisplay}${stats}`;
1746
+ ? `${statusIcon} ${stepLabel}: ${theme.bold(theme.fg("warning", r.agent))}${contextBadge}${modelDisplay}${stats}`
1747
+ : `${statusIcon} ${stepLabel}: ${theme.bold(r.agent)}${contextBadge}${modelDisplay}${stats}`;
1673
1748
  const toolCallLines = getToolCallLines(r, expanded);
1674
1749
  c.addChild(new Text(fit(stepHeader), 0, 0));
1675
1750
 
@@ -1707,6 +1782,9 @@ export function renderSubagentResult(
1707
1782
  if (liveStatusLine) {
1708
1783
  c.addChild(new Text(fit(theme.fg("accent", ` ${liveStatusLine}`)), 0, 0));
1709
1784
  }
1785
+ for (const nestedLine of formatNestedWidgetLines(r.children, theme, w, true, progressSnapshotNow, 8)) {
1786
+ c.addChild(new Text(fit(` ${nestedLine}`), 0, 0));
1787
+ }
1710
1788
  c.addChild(new Text(fit(theme.fg("accent", ` ${liveDetailHintText()}`)), 0, 0));
1711
1789
  if (r.artifactPaths) {
1712
1790
  c.addChild(new Text(fit(theme.fg("dim", ` artifacts: ${shortenPath(r.artifactPaths.outputPath)}`)), 0, 0));
@@ -1726,6 +1804,12 @@ export function renderSubagentResult(
1726
1804
  }
1727
1805
  }
1728
1806
 
1807
+ if (!rRunning) {
1808
+ for (const nestedLine of formatNestedWidgetLines(r.children, theme, w, true, r.progress?.lastActivityAt, 8)) {
1809
+ c.addChild(new Text(fit(` ${nestedLine}`), 0, 0));
1810
+ }
1811
+ }
1812
+
1729
1813
  if (!rRunning && r.artifactPaths) {
1730
1814
  c.addChild(new Text(fit(theme.fg("dim", ` artifacts: ${shortenPath(r.artifactPaths.outputPath)}`)), 0, 0));
1731
1815
  }