@selesai/code 0.12.0 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (466) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/core/agent-session.d.ts +1 -1
  3. package/dist/core/agent-session.js +1 -1
  4. package/dist/core/sdk.d.ts +2 -2
  5. package/dist/core/sdk.js +1 -1
  6. package/dist/core/system-prompt.d.ts +1 -1
  7. package/dist/core/system-prompt.js +1 -1
  8. package/dist/core/usage-totals.d.ts +2 -0
  9. package/dist/core/usage-totals.js +10 -0
  10. package/dist/extensions/ascii.txt +9 -0
  11. package/dist/extensions/package.json +1 -2
  12. package/dist/extensions/pi-hermes-memory/CHANGELOG.md +371 -0
  13. package/dist/extensions/pi-hermes-memory/LICENSE +21 -0
  14. package/dist/extensions/pi-hermes-memory/README.md +643 -0
  15. package/dist/extensions/pi-hermes-memory/docs/0.1/TASKS.md +197 -0
  16. package/dist/extensions/pi-hermes-memory/docs/0.2/PLAN.md +290 -0
  17. package/dist/extensions/pi-hermes-memory/docs/0.2/TASKS.md +134 -0
  18. package/dist/extensions/pi-hermes-memory/docs/0.2/TEST-PLAN.md +216 -0
  19. package/dist/extensions/pi-hermes-memory/docs/0.3/PLAN.md +330 -0
  20. package/dist/extensions/pi-hermes-memory/docs/0.3/TASKS.md +125 -0
  21. package/dist/extensions/pi-hermes-memory/docs/0.4/PLAN.md +160 -0
  22. package/dist/extensions/pi-hermes-memory/docs/0.4/TASKS.md +113 -0
  23. package/dist/extensions/pi-hermes-memory/docs/0.6/CHANGELOG.md +57 -0
  24. package/dist/extensions/pi-hermes-memory/docs/0.6/PLAN.md +202 -0
  25. package/dist/extensions/pi-hermes-memory/docs/0.6/TASKS.md +144 -0
  26. package/dist/extensions/pi-hermes-memory/docs/0.7/PLAN.md +349 -0
  27. package/dist/extensions/pi-hermes-memory/docs/0.7/TASKS.md +110 -0
  28. package/dist/extensions/pi-hermes-memory/docs/PUBLISHING.md +149 -0
  29. package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +468 -0
  30. package/dist/extensions/pi-hermes-memory/docs/images/memory-architecture.svg +1 -0
  31. package/dist/extensions/pi-hermes-memory/docs/images/pi-logo.svg +22 -0
  32. package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.png +0 -0
  33. package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.svg +19 -0
  34. package/dist/extensions/pi-hermes-memory/docs/images/security-flow.svg +1 -0
  35. package/dist/extensions/pi-hermes-memory/docs/images/session-lifecycle.svg +1 -0
  36. package/dist/extensions/pi-hermes-memory/docs/images/source-architecture.svg +1 -0
  37. package/dist/extensions/pi-hermes-memory/docs/mermaid/memory-architecture.mmd +49 -0
  38. package/dist/extensions/pi-hermes-memory/docs/mermaid/security-flow.mmd +40 -0
  39. package/dist/extensions/pi-hermes-memory/docs/mermaid/session-lifecycle.mmd +56 -0
  40. package/dist/extensions/pi-hermes-memory/docs/mermaid/source-architecture.mmd +54 -0
  41. package/dist/extensions/pi-hermes-memory/package-lock.json +3799 -0
  42. package/dist/extensions/pi-hermes-memory/package.json +66 -0
  43. package/dist/extensions/pi-hermes-memory/scripts/check-min-sdk.mjs +99 -0
  44. package/dist/extensions/pi-hermes-memory/scripts/ensure-dev.mjs +57 -0
  45. package/dist/extensions/pi-hermes-memory/src/auto-consolidation-warning.ts +6 -0
  46. package/dist/extensions/pi-hermes-memory/src/config.ts +178 -0
  47. package/dist/extensions/pi-hermes-memory/src/constants.ts +424 -0
  48. package/dist/extensions/pi-hermes-memory/src/extension-root-migration.ts +639 -0
  49. package/dist/extensions/pi-hermes-memory/src/handlers/auto-consolidate.ts +401 -0
  50. package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +297 -0
  51. package/dist/extensions/pi-hermes-memory/src/handlers/child-process-watchdog.mjs +90 -0
  52. package/dist/extensions/pi-hermes-memory/src/handlers/correction-detector.ts +300 -0
  53. package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +86 -0
  54. package/dist/extensions/pi-hermes-memory/src/handlers/insights.ts +78 -0
  55. package/dist/extensions/pi-hermes-memory/src/handlers/interview.ts +37 -0
  56. package/dist/extensions/pi-hermes-memory/src/handlers/learn-memory.ts +186 -0
  57. package/dist/extensions/pi-hermes-memory/src/handlers/message-parts.ts +27 -0
  58. package/dist/extensions/pi-hermes-memory/src/handlers/pi-child-process.ts +485 -0
  59. package/dist/extensions/pi-hermes-memory/src/handlers/preview-context.ts +105 -0
  60. package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +506 -0
  61. package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +145 -0
  62. package/dist/extensions/pi-hermes-memory/src/handlers/session-flush.ts +151 -0
  63. package/dist/extensions/pi-hermes-memory/src/handlers/session-live-index.ts +94 -0
  64. package/dist/extensions/pi-hermes-memory/src/handlers/skills-command.ts +1334 -0
  65. package/dist/extensions/pi-hermes-memory/src/handlers/standing-pin.ts +111 -0
  66. package/dist/extensions/pi-hermes-memory/src/handlers/switch-project.ts +75 -0
  67. package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +266 -0
  68. package/dist/extensions/pi-hermes-memory/src/index.ts +378 -0
  69. package/dist/extensions/pi-hermes-memory/src/lifecycle-timing.ts +54 -0
  70. package/dist/extensions/pi-hermes-memory/src/paths.ts +61 -0
  71. package/dist/extensions/pi-hermes-memory/src/project-context.ts +13 -0
  72. package/dist/extensions/pi-hermes-memory/src/project-memory-migration.ts +93 -0
  73. package/dist/extensions/pi-hermes-memory/src/project.ts +157 -0
  74. package/dist/extensions/pi-hermes-memory/src/prompt-context.ts +55 -0
  75. package/dist/extensions/pi-hermes-memory/src/store/atomic-lock-coordinator.ts +375 -0
  76. package/dist/extensions/pi-hermes-memory/src/store/canonical-storage-path.ts +54 -0
  77. package/dist/extensions/pi-hermes-memory/src/store/content-scanner.ts +101 -0
  78. package/dist/extensions/pi-hermes-memory/src/store/db.ts +1180 -0
  79. package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +101 -0
  80. package/dist/extensions/pi-hermes-memory/src/store/markdown-mutation-lock.ts +38 -0
  81. package/dist/extensions/pi-hermes-memory/src/store/memory-lookup.ts +24 -0
  82. package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +1191 -0
  83. package/dist/extensions/pi-hermes-memory/src/store/recovery-maintenance.ts +66 -0
  84. package/dist/extensions/pi-hermes-memory/src/store/schema.ts +118 -0
  85. package/dist/extensions/pi-hermes-memory/src/store/session-anchor-search.ts +472 -0
  86. package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +511 -0
  87. package/dist/extensions/pi-hermes-memory/src/store/session-parser.ts +213 -0
  88. package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +234 -0
  89. package/dist/extensions/pi-hermes-memory/src/store/skill-store.ts +950 -0
  90. package/dist/extensions/pi-hermes-memory/src/store/skill-utils.ts +133 -0
  91. package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +1002 -0
  92. package/dist/extensions/pi-hermes-memory/src/store/sqlite-native.ts +241 -0
  93. package/dist/extensions/pi-hermes-memory/src/store/standing-instructions.ts +247 -0
  94. package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +95 -0
  95. package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +469 -0
  96. package/dist/extensions/pi-hermes-memory/src/tools/session-search-tool.ts +246 -0
  97. package/dist/extensions/pi-hermes-memory/src/tools/shared-output-view.ts +170 -0
  98. package/dist/extensions/pi-hermes-memory/src/tools/skill-tool.ts +333 -0
  99. package/dist/extensions/pi-hermes-memory/src/tools/tool-result-views.ts +105 -0
  100. package/dist/extensions/pi-hermes-memory/src/types.ts +214 -0
  101. package/dist/extensions/pi-hermes-memory/tests/config.test.ts +434 -0
  102. package/dist/extensions/pi-hermes-memory/tests/extension-root-migration.test.ts +368 -0
  103. package/dist/extensions/pi-hermes-memory/tests/handlers/auto-consolidate.test.ts +984 -0
  104. package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +950 -0
  105. package/dist/extensions/pi-hermes-memory/tests/handlers/correction-detector.test.ts +671 -0
  106. package/dist/extensions/pi-hermes-memory/tests/handlers/insights.test.ts +157 -0
  107. package/dist/extensions/pi-hermes-memory/tests/handlers/interview.test.ts +127 -0
  108. package/dist/extensions/pi-hermes-memory/tests/handlers/pi-child-process.test.ts +905 -0
  109. package/dist/extensions/pi-hermes-memory/tests/handlers/preview-context.test.ts +152 -0
  110. package/dist/extensions/pi-hermes-memory/tests/handlers/prompt-context.test.ts +166 -0
  111. package/dist/extensions/pi-hermes-memory/tests/handlers/resources-discover.test.ts +71 -0
  112. package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +614 -0
  113. package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +192 -0
  114. package/dist/extensions/pi-hermes-memory/tests/handlers/session-flush.test.ts +677 -0
  115. package/dist/extensions/pi-hermes-memory/tests/handlers/session-live-index.test.ts +225 -0
  116. package/dist/extensions/pi-hermes-memory/tests/handlers/skills-command.test.ts +827 -0
  117. package/dist/extensions/pi-hermes-memory/tests/handlers/standing-pin.test.ts +134 -0
  118. package/dist/extensions/pi-hermes-memory/tests/handlers/sync-markdown-memories.test.ts +491 -0
  119. package/dist/extensions/pi-hermes-memory/tests/handlers/system-prompt.test.ts +199 -0
  120. package/dist/extensions/pi-hermes-memory/tests/handlers/thinking-max.test.ts +64 -0
  121. package/dist/extensions/pi-hermes-memory/tests/index.test.ts +30 -0
  122. package/dist/extensions/pi-hermes-memory/tests/integration/flow.test.ts +126 -0
  123. package/dist/extensions/pi-hermes-memory/tests/lifecycle-timing.test.ts +76 -0
  124. package/dist/extensions/pi-hermes-memory/tests/paths.test.ts +23 -0
  125. package/dist/extensions/pi-hermes-memory/tests/project-memory-migration.test.ts +80 -0
  126. package/dist/extensions/pi-hermes-memory/tests/project-rebinding.test.ts +115 -0
  127. package/dist/extensions/pi-hermes-memory/tests/project.test.ts +120 -0
  128. package/dist/extensions/pi-hermes-memory/tests/run-all-timeout.test.ts +107 -0
  129. package/dist/extensions/pi-hermes-memory/tests/run-all.sh +45 -0
  130. package/dist/extensions/pi-hermes-memory/tests/store/atomic-lock-coordinator.test.ts +381 -0
  131. package/dist/extensions/pi-hermes-memory/tests/store/content-scanner.test.ts +388 -0
  132. package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +1046 -0
  133. package/dist/extensions/pi-hermes-memory/tests/store/markdown-mutation-lock.test.ts +34 -0
  134. package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +2150 -0
  135. package/dist/extensions/pi-hermes-memory/tests/store/recovery-maintenance.test.ts +170 -0
  136. package/dist/extensions/pi-hermes-memory/tests/store/session-anchor-search.test.ts +210 -0
  137. package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +643 -0
  138. package/dist/extensions/pi-hermes-memory/tests/store/session-parser.test.ts +282 -0
  139. package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +287 -0
  140. package/dist/extensions/pi-hermes-memory/tests/store/skill-store.test.ts +678 -0
  141. package/dist/extensions/pi-hermes-memory/tests/store/skill-utils.test.ts +21 -0
  142. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-lazy-load.test.ts +78 -0
  143. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +543 -0
  144. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +164 -0
  145. package/dist/extensions/pi-hermes-memory/tests/store/standing-instructions.test.ts +171 -0
  146. package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +84 -0
  147. package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +709 -0
  148. package/dist/extensions/pi-hermes-memory/tests/tools/session-search-tool.test.ts +345 -0
  149. package/dist/extensions/pi-hermes-memory/tests/tools/shared-output-view.test.ts +362 -0
  150. package/dist/extensions/pi-hermes-memory/tests/tools/skill-tool.test.ts +478 -0
  151. package/dist/extensions/pi-hermes-memory/tests/tools/tool-result-renderer-wiring.test.ts +40 -0
  152. package/dist/extensions/pi-hermes-memory/tsconfig.json +19 -0
  153. package/dist/extensions/pi-subagents/.oxlintrc.json +43 -0
  154. package/dist/extensions/pi-subagents/AGENTS.md +5 -0
  155. package/dist/extensions/pi-subagents/CHANGELOG.md +157 -0
  156. package/dist/extensions/pi-subagents/README.md +12 -6
  157. package/dist/extensions/pi-subagents/VISION.md +81 -0
  158. package/dist/extensions/pi-subagents/agents/claude-code-writer.md +15 -0
  159. package/dist/extensions/pi-subagents/agents/claude-code.md +15 -0
  160. package/dist/extensions/pi-subagents/agents/codex-exec-writer.md +15 -0
  161. package/dist/extensions/pi-subagents/agents/codex-exec.md +15 -0
  162. package/dist/extensions/pi-subagents/agents/cursor-agent-writer.md +14 -0
  163. package/dist/extensions/pi-subagents/agents/cursor-agent.md +14 -0
  164. package/dist/extensions/pi-subagents/agents/reviewer.md +1 -3
  165. package/dist/extensions/pi-subagents/docs/agents.md +488 -0
  166. package/dist/extensions/pi-subagents/docs/configuration.md +46 -9
  167. package/dist/extensions/pi-subagents/docs/extension-api.md +42 -3
  168. package/dist/extensions/pi-subagents/docs/models.md +27 -4
  169. package/dist/extensions/pi-subagents/docs/observability.md +10 -9
  170. package/dist/extensions/pi-subagents/docs/tool-reference.md +102 -6
  171. package/dist/extensions/pi-subagents/docs/workflows.md +135 -0
  172. package/dist/extensions/pi-subagents/package-lock.json +389 -2
  173. package/dist/extensions/pi-subagents/package.json +3 -1
  174. package/dist/extensions/pi-subagents/prompts/review-loop.md +2 -2
  175. package/dist/extensions/pi-subagents/skills/council-mode/SKILL.md +1 -1
  176. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +3 -1
  177. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +7 -3
  178. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
  179. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +26 -5
  180. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +41 -22
  181. package/dist/extensions/pi-subagents/src/agents/agent-refinements.ts +4 -4
  182. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +9 -2
  183. package/dist/extensions/pi-subagents/src/agents/agents.ts +322 -75
  184. package/dist/extensions/pi-subagents/src/agents/builtin-names.ts +6 -0
  185. package/dist/extensions/pi-subagents/src/agents/runtime-agent-events.ts +70 -0
  186. package/dist/extensions/pi-subagents/src/agents/runtime-agent-registry.ts +27 -20
  187. package/dist/extensions/pi-subagents/src/api/agents.ts +10 -5
  188. package/dist/extensions/pi-subagents/src/api/background-work.ts +5 -1
  189. package/dist/extensions/pi-subagents/src/api/delegation.ts +0 -7
  190. package/dist/extensions/pi-subagents/src/api/preflight.ts +34 -12
  191. package/dist/extensions/pi-subagents/src/extension/config.ts +70 -0
  192. package/dist/extensions/pi-subagents/src/extension/doctor.ts +3 -3
  193. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +5 -3
  194. package/dist/extensions/pi-subagents/src/extension/index.ts +83 -30
  195. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +44 -15
  196. package/dist/extensions/pi-subagents/src/extension/rpc.ts +55 -19
  197. package/dist/extensions/pi-subagents/src/extension/schemas.ts +41 -15
  198. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -31
  199. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +2 -1
  200. package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +2 -10
  201. package/dist/extensions/pi-subagents/src/inspectors/herdr/session-roots-codec.ts +42 -0
  202. package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +51 -3
  203. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +2 -0
  204. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +5 -6
  205. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +77 -10
  206. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +176 -53
  207. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +19 -12
  208. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +29 -27
  209. package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +20 -3
  210. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +23 -261
  211. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +73 -7
  212. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +8 -3
  213. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +74 -8
  214. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +37 -21
  215. package/dist/extensions/pi-subagents/src/runs/background/inspect-rpc.ts +8 -8
  216. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +184 -9
  217. package/dist/extensions/pi-subagents/src/runs/background/result-delivery-ownership.ts +45 -0
  218. package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +28 -14
  219. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +38 -15
  220. package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +1 -1
  221. package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +1 -1
  222. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +50 -13
  223. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +93 -8
  224. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +10 -4
  225. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +4 -14
  226. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +549 -377
  227. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +58 -10
  228. package/dist/extensions/pi-subagents/src/runs/background/terminal-run-index.ts +1 -1
  229. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +26 -1
  230. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +23 -9
  231. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +9 -2
  232. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +2 -2
  233. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +204 -129
  234. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +9 -0
  235. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +23 -1
  236. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +773 -311
  237. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +140 -115
  238. package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +119 -0
  239. package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +463 -0
  240. package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +19 -4
  241. package/dist/extensions/pi-subagents/src/runs/shared/child-launch-plan.ts +151 -0
  242. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +21 -7
  243. package/dist/extensions/pi-subagents/src/runs/shared/claude-code-adapter.ts +129 -0
  244. package/dist/extensions/pi-subagents/src/runs/shared/codex-exec-adapter.ts +129 -0
  245. package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +89 -0
  246. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +5 -4
  247. package/dist/extensions/pi-subagents/src/runs/shared/cursor-agent-adapter.ts +114 -0
  248. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +3 -3
  249. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-contract.ts +167 -0
  250. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +122 -0
  251. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +348 -55
  252. package/dist/extensions/pi-subagents/src/runs/shared/fast-mode-extension.ts +5 -5
  253. package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +230 -0
  254. package/dist/extensions/pi-subagents/src/runs/shared/lane-metadata.ts +105 -0
  255. package/dist/extensions/pi-subagents/src/runs/shared/launch-cwd.ts +16 -0
  256. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +2 -1
  257. package/dist/extensions/pi-subagents/src/runs/shared/mcp-config-sources.ts +422 -0
  258. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +221 -158
  259. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-grant.ts +197 -0
  260. package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +69 -7
  261. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +47 -6
  262. package/dist/extensions/pi-subagents/src/runs/shared/mutation-evidence.ts +7 -2
  263. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +9 -3
  264. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +9 -5
  265. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +419 -7
  266. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +15 -1
  267. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +81 -8
  268. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +13 -0
  269. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +21 -1
  270. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +44 -4
  271. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +98 -13
  272. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +1 -1
  273. package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +847 -0
  274. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +18 -0
  275. package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +46 -0
  276. package/dist/extensions/pi-subagents/src/shared/extension-context.ts +24 -0
  277. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +21 -0
  278. package/dist/extensions/pi-subagents/src/shared/formatters.ts +18 -3
  279. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +5 -1
  280. package/dist/extensions/pi-subagents/src/shared/pruned-fork.ts +450 -0
  281. package/dist/extensions/pi-subagents/src/shared/session-file-trust.ts +19 -0
  282. package/dist/extensions/pi-subagents/src/shared/session-tokens.ts +14 -3
  283. package/dist/extensions/pi-subagents/src/shared/settings.ts +19 -105
  284. package/dist/extensions/pi-subagents/src/shared/shortcuts.ts +17 -0
  285. package/dist/extensions/pi-subagents/src/shared/types.ts +359 -40
  286. package/dist/extensions/pi-subagents/src/shared/utils.ts +41 -84
  287. package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +116 -0
  288. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +1 -9
  289. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +0 -4
  290. package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +1 -2
  291. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +378 -88
  292. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +22 -11
  293. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +3 -0
  294. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +147 -79
  295. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +11 -5
  296. package/dist/extensions/pi-subagents/src/tui/fleet.ts +39 -18
  297. package/dist/extensions/pi-subagents/src/tui/render.ts +369 -46
  298. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +1 -1
  299. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +6 -3
  300. package/dist/extensions/pi-subagents/src/workflows/host-command.ts +230 -0
  301. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +740 -58
  302. package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +121 -0
  303. package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +270 -0
  304. package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +195 -6
  305. package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +246 -0
  306. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
  307. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1114 -260
  308. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +34 -0
  309. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +150 -3
  310. package/dist/extensions/pi-subagents/test/integration/claude-code-smoke.test.ts +52 -0
  311. package/dist/extensions/pi-subagents/test/integration/claude-code-writer-smoke.test.ts +55 -0
  312. package/dist/extensions/pi-subagents/test/integration/codex-exec-smoke.test.ts +53 -0
  313. package/dist/extensions/pi-subagents/test/integration/codex-exec-writer-smoke.test.ts +57 -0
  314. package/dist/extensions/pi-subagents/test/integration/cursor-agent-smoke.test.ts +59 -0
  315. package/dist/extensions/pi-subagents/test/integration/cursor-agent-writer-smoke.test.ts +62 -0
  316. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +57 -1
  317. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
  318. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +20 -0
  319. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +4 -3
  320. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +2 -2
  321. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +54 -4
  322. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +482 -4
  323. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +157 -9
  324. package/dist/extensions/pi-subagents/test/integration/session-tokens.test.ts +5 -5
  325. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1508 -291
  326. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +423 -1
  327. package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +8 -0
  328. package/dist/extensions/pi-subagents/test/support/cursor-smoke-inputs.ts +51 -0
  329. package/dist/extensions/pi-subagents/test/support/helpers.ts +2 -0
  330. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +5 -5
  331. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +6 -6
  332. package/dist/extensions/pi-subagents/test/unit/abort-recovery.test.ts +152 -0
  333. package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +48 -0
  334. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +184 -6
  335. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +66 -6
  336. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +77 -0
  337. package/dist/extensions/pi-subagents/test/unit/agent-refinements.test.ts +18 -0
  338. package/dist/extensions/pi-subagents/test/unit/anti-slop-oxlint.test.ts +86 -0
  339. package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +1 -1
  340. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +101 -1
  341. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +121 -0
  342. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +28 -0
  343. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +14 -7
  344. package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +53 -0
  345. package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +190 -0
  346. package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +42 -0
  347. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +8 -4
  348. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +23 -0
  349. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +78 -1
  350. package/dist/extensions/pi-subagents/test/unit/child-launch-plan.test.ts +94 -0
  351. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +21 -0
  352. package/dist/extensions/pi-subagents/test/unit/child-session-name.test.ts +50 -0
  353. package/dist/extensions/pi-subagents/test/unit/claude-code-adapter.test.ts +245 -0
  354. package/dist/extensions/pi-subagents/test/unit/codex-exec-adapter.test.ts +192 -0
  355. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +27 -0
  356. package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +150 -0
  357. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +21 -0
  358. package/dist/extensions/pi-subagents/test/unit/cursor-agent-adapter.test.ts +259 -0
  359. package/dist/extensions/pi-subagents/test/unit/cursor-smoke-inputs.test.ts +77 -0
  360. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +1 -4
  361. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
  362. package/dist/extensions/pi-subagents/test/unit/extension-context.test.ts +27 -0
  363. package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +223 -0
  364. package/dist/extensions/pi-subagents/test/unit/fast-mode-extension.test.ts +27 -0
  365. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +208 -2
  366. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +29 -1
  367. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +110 -1
  368. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +10 -0
  369. package/dist/extensions/pi-subagents/test/unit/formatters.test.ts +14 -0
  370. package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +18 -9
  371. package/dist/extensions/pi-subagents/test/unit/herdr-session-roots-codec.test.ts +63 -0
  372. package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +2 -2
  373. package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +132 -0
  374. package/dist/extensions/pi-subagents/test/unit/host-command.test.ts +156 -0
  375. package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +98 -0
  376. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +178 -26
  377. package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +2 -1
  378. package/dist/extensions/pi-subagents/test/unit/inspect-rpc.test.ts +21 -0
  379. package/dist/extensions/pi-subagents/test/unit/mcp-direct-tool-grant.test.ts +138 -0
  380. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
  381. package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +91 -0
  382. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +72 -7
  383. package/dist/extensions/pi-subagents/test/unit/mutation-evidence.test.ts +21 -0
  384. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +1 -0
  385. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +20 -2
  386. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +129 -1
  387. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +2 -2
  388. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +4 -0
  389. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +358 -0
  390. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +574 -21
  391. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +109 -1
  392. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +71 -1
  393. package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +7 -7
  394. package/dist/extensions/pi-subagents/test/unit/pruned-fork.test.ts +214 -0
  395. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +29 -8
  396. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +53 -0
  397. package/dist/extensions/pi-subagents/test/unit/result-delivery-ownership.test.ts +34 -0
  398. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +101 -3
  399. package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +1 -0
  400. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +10 -8
  401. package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +71 -1
  402. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +41 -7
  403. package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +136 -2
  404. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +137 -0
  405. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +33 -12
  406. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +504 -1
  407. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +8 -0
  408. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  409. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +12 -1
  410. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +3 -5
  411. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +5 -6
  412. package/dist/extensions/pi-subagents/test/unit/subagent-action-recovery.test.ts +0 -8
  413. package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +5 -0
  414. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +157 -2
  415. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +1 -1
  416. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +63 -4
  417. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +27 -23
  418. package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +44 -0
  419. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +1 -0
  420. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +7 -5
  421. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +106 -0
  422. package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +484 -9
  423. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +38 -4
  424. package/dist/extensions/pi-subagents/test/unit/workflow-preflight.test.ts +155 -0
  425. package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +318 -0
  426. package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +365 -0
  427. package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +349 -0
  428. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +21 -0
  429. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +2 -7
  430. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/index.ts +13 -0
  431. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/rules/no-service-constructor-imports.ts +52 -0
  432. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/index.ts +41 -0
  433. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-chained-type-assertions.ts +77 -0
  434. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-conditional-empty-object-spread.ts +49 -0
  435. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-known-value-widening.ts +247 -0
  436. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-module-mocking.ts +91 -0
  437. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-object-parameters.ts +126 -0
  438. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-apply.ts +28 -0
  439. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-get.ts +28 -0
  440. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-runtime-typeof.ts +67 -0
  441. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-shape-in-symbol-names.ts +39 -0
  442. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-parameters.ts +83 -0
  443. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-returns.ts +115 -0
  444. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-type-aliases.ts +72 -0
  445. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unsafe-dictionary-type.ts +134 -0
  446. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-widen-then-assert.ts +366 -0
  447. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/require-safety-comment-for-type-assertion.ts +62 -0
  448. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/dictionary-types.ts +502 -0
  449. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/lexical-type-parameters.ts +60 -0
  450. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/reflect-method.ts +35 -0
  451. package/dist/extensions/pi-tool-display/tests/capabilities.test.ts +1 -1
  452. package/dist/extensions/pi-tool-display/tests/settings-inspector.test.ts +2 -2
  453. package/dist/extensions/pi-tool-display/tests/tool-overrides-mcp.test.ts +1 -1
  454. package/dist/extensions/pi-zentui/extensions/zentui/format.ts +2 -1
  455. package/dist/extensions/pi-zentui/test/format.test.ts +15 -1
  456. package/dist/modes/interactive/components/footer.js +2 -2
  457. package/dist/modes/interactive/interactive-mode.js +11 -11
  458. package/dist/skills/workflow/SKILL.md +65 -50
  459. package/package.json +112 -110
  460. package/dist/extensions/enable-readonly-tools.test.ts +0 -63
  461. package/dist/extensions/enable-readonly-tools.ts +0 -24
  462. package/dist/extensions/model-prompt-injector/config.json +0 -16
  463. package/dist/extensions/model-prompt-injector/index.test.ts +0 -102
  464. package/dist/extensions/model-prompt-injector/index.ts +0 -148
  465. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +0 -98
  466. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +0 -250
@@ -13,6 +13,8 @@ import {
13
13
  type AsyncJobStep,
14
14
  type AsyncParallelGroupStatus,
15
15
  type Details,
16
+ type HostStepState,
17
+ type HostStepVerdict,
16
18
  type NestedRunSummary,
17
19
  type NestedStepSummary,
18
20
  type WorkflowNodeStatus,
@@ -21,15 +23,19 @@ import {
21
23
  WIDGET_ANIMATION_INTERVAL_MS,
22
24
  WIDGET_KEY,
23
25
  } from "../shared/types.ts";
24
- import { sanitizeDisplayText, truncateDisplayText } from "../shared/display-text.ts";
25
- import { formatTokens, formatUsage, formatDuration, formatModelThinking, formatToolCall, shortenPath } from "../shared/formatters.ts";
26
- import { getDisplayItems, getSingleResultOutput } from "../shared/utils.ts";
26
+ import { previewDisplayText, sanitizeDisplayText, truncateDisplayText } from "../shared/display-text.ts";
27
+ import { FLEET_OPEN_SHORTCUT, formatShortcutLabel } from "../shared/shortcuts.ts";
28
+ import { formatContextUsage, formatTokens, formatUsage, formatDuration, formatModelThinking, formatToolCall, formatTokenUsage, shortenPath } from "../shared/formatters.ts";
29
+ import { getDisplayItems, getSingleResultOutput, PROMPT_REDACTED } from "../shared/utils.ts";
27
30
  import { flatToLogicalStepIndex } from "../runs/background/parallel-groups.ts";
28
31
  import { formatNestedAggregate } from "../runs/shared/nested-render.ts";
29
32
  import { aggregateStepStatus, formatActivityLabel, formatAgentRunningLabel, formatParallelOutcome } from "../shared/status-format.ts";
30
33
  import { contextModeBadge, contextModePrefix } from "../runs/shared/context-mode.ts";
31
34
  import { buildWorkflowChatProgressRows, type WorkflowChatProgressRow } from "../workflows/chat-progress.ts";
35
+ import { formatWorkflowPreflight, formatWorkflowPreflightPlanSummary, formatWorkflowPreflightWarningSummary, formatWorkflowPreflightWarnings } from "../workflows/workflow-preflight.ts";
32
36
  import { encodeAsyncStatusSnapshotWidget } from "../runs/background/async-status-snapshot.ts";
37
+ import { projectAsyncWorkflowRows, type AsyncStatusWorkflowRow } from "../runs/shared/async-status-projection.ts";
38
+ import { hostStepReportName, hostStepVerdictLabel } from "../runs/shared/host-step-status.ts";
33
39
 
34
40
  type Theme = ExtensionContext["ui"]["theme"];
35
41
 
@@ -69,23 +75,13 @@ function liveDetailKeyText(): string {
69
75
  return keyText("app.tools.expand");
70
76
  }
71
77
 
72
- function liveDetailHintText(): string {
73
- return `Press ${liveDetailKeyText()} for live detail`;
78
+ export function liveDetailHintText(): string {
79
+ return `Press ${liveDetailKeyText()} for live detail · ${formatShortcutLabel(FLEET_OPEN_SHORTCUT)} Fleet`;
74
80
  }
75
81
 
76
82
  function foregroundSingleHintText(shortcut?: string): string {
77
83
  if (!shortcut) return liveDetailHintText();
78
- const label = shortcut
79
- .split("+")
80
- .map((part) => {
81
- const normalized = part.trim().toLowerCase();
82
- if (normalized === "ctrl") return "Ctrl";
83
- if (normalized === "alt") return "Alt";
84
- if (normalized === "shift") return "Shift";
85
- if (normalized === "super") return "Super";
86
- return normalized.length === 1 ? normalized.toUpperCase() : part.trim();
87
- })
88
- .join("+");
84
+ const label = formatShortcutLabel(shortcut);
89
85
  return `${liveDetailHintText()} · ${label} to run in background`;
90
86
  }
91
87
 
@@ -273,6 +269,203 @@ function oneLine(text: string): string {
273
269
  return text.replace(ansiEscapePattern, "").replace(/\s+/g, " ").trim();
274
270
  }
275
271
 
272
+ const COMPACT_TASK_MAX_CHARS = 96;
273
+
274
+ /** Display label for a child run: the derived session name (agent + task
275
+ * excerpt) when the launcher provided one, else the bare agent name. */
276
+ function childDisplayName(result: { agent?: string; sessionName?: string } | undefined, fallback = "subagent"): string {
277
+ return result?.sessionName?.trim() || result?.agent || fallback;
278
+ }
279
+
280
+ export function compactTaskText(task: string | undefined, label?: string): string | undefined {
281
+ const taskText = task?.trim();
282
+ const labelText = label?.trim();
283
+ const normalizedTask = taskText && taskText !== PROMPT_REDACTED ? oneLine(taskText) : "";
284
+ const normalizedLabel = labelText && labelText !== PROMPT_REDACTED ? oneLine(labelText) : "";
285
+ const normalized = normalizedLabel && normalizedTask && normalizedLabel !== normalizedTask
286
+ ? `${normalizedLabel} — ${normalizedTask}`
287
+ : normalizedLabel || normalizedTask;
288
+ if (!normalized) return undefined;
289
+ return previewDisplayText(normalized, COMPACT_TASK_MAX_CHARS);
290
+ }
291
+
292
+ export interface AsyncLaneProjection {
293
+ label?: string;
294
+ role: string;
295
+ phase?: string;
296
+ state: AsyncJobState["status"] | AsyncJobStep["status"];
297
+ gate?: string;
298
+ next?: string;
299
+ output?: string;
300
+ workspace?: string;
301
+ ref: string;
302
+ chips: string[];
303
+ }
304
+
305
+ const LANE_VALUE_MAX_CHARS = 48;
306
+
307
+ function boundedLaneValue(value: string | undefined, maxChars = LANE_VALUE_MAX_CHARS): string | undefined {
308
+ if (!value?.trim() || value.trim() === PROMPT_REDACTED) return undefined;
309
+ return previewDisplayText(oneLine(value), maxChars);
310
+ }
311
+
312
+ function laneStepForJob(job: AsyncJobState): AsyncJobStep | undefined {
313
+ const steps = job.steps ?? [];
314
+ if (steps.length === 0) return undefined;
315
+ if (job.currentStep !== undefined) {
316
+ const current = steps[job.currentStep];
317
+ if (current && (current.index === undefined || current.index === job.currentStep)) return current;
318
+ // Active parallel groups retain flat indices while exposing only the group slice.
319
+ const indexedCurrent = steps.find((step) => step.index === job.currentStep);
320
+ if (indexedCurrent) return indexedCurrent;
321
+ return steps[0];
322
+ }
323
+ return steps.find((step) => step.status === "running")
324
+ ?? steps.find((step) => step.status === "pending")
325
+ ?? steps.at(-1);
326
+ }
327
+
328
+ function laneTraceForJob(job: AsyncJobState): NonNullable<AsyncJobState["workflow"]>["trace"][number] | undefined {
329
+ return Array.isArray(job.workflow?.trace) ? job.workflow.trace.at(-1) : undefined;
330
+ }
331
+
332
+ function laneGate(step: AsyncJobStep | undefined): string | undefined {
333
+ const review = step?.review?.status ?? step?.acceptance?.reviewResult?.status;
334
+ if (review === "blockers") return "review blockers";
335
+ if (review === "review-required") return "review required";
336
+ if (review === "reviewed") return "reviewed";
337
+ const acceptance = step?.acceptance?.status;
338
+ if (acceptance === "review-required") return "acceptance review";
339
+ if (acceptance === "checked" || acceptance === "verified" || acceptance === "accepted") return "acceptance";
340
+ return undefined;
341
+ }
342
+
343
+ function laneNextAction(state: AsyncLaneProjection["state"], step: AsyncJobStep | undefined, output: string | undefined, gate: string | undefined): string | undefined {
344
+ if (step?.watchdog?.phase === "stale") return "inspect stale state";
345
+ if (step?.toolBudgetBlocked === true || step?.turnBudgetExceeded === true) return "inspect blocked state";
346
+ if (gate === "review blockers") return "resolve review blockers";
347
+ if (gate === "review required" || gate === "acceptance review") return "review output";
348
+ if (step?.activityState === "needs_attention") return "inspect attention";
349
+ if (state === "queued" || state === "pending") return "await launch";
350
+ if (state === "failed" || state === "rejected") return "inspect failure";
351
+ if (state === "partial") return "inspect partial state";
352
+ if (state === "paused") return "inspect paused state";
353
+ if (state === "stopped") return "inspect stopped state";
354
+ if ((state === "complete" || state === "completed") && gate === "reviewed") return "ready";
355
+ if ((state === "complete" || state === "completed") && output) return "inspect output";
356
+ return undefined;
357
+ }
358
+
359
+ function isTerminalLaneState(state: AsyncJobState["status"]): boolean {
360
+ return state !== "queued" && state !== "running";
361
+ }
362
+
363
+ /** Project already-loaded async status facts into one bounded, render-only lane row. */
364
+ export function projectAsyncLane(job: AsyncJobState, selectedStep = laneStepForJob(job)): AsyncLaneProjection | undefined {
365
+ const trace = laneTraceForJob(job);
366
+ const workspace = job.cwd ? boundedLaneValue(shortenPath(job.cwd)) : undefined;
367
+ const label = compactTaskText(selectedStep?.description, selectedStep?.label)
368
+ ?? boundedLaneValue(trace?.label)
369
+ ?? (workspace ? undefined : boundedLaneValue(selectedStep?.workflowKey ?? job.workflowKey));
370
+ const role = boundedLaneValue(selectedStep?.agent ?? trace?.agent ?? job.agents?.[0] ?? widgetJobName(job), 32) ?? "subagent";
371
+ const phase = boundedLaneValue(selectedStep?.phase ?? trace?.phase);
372
+ const gate = laneGate(selectedStep);
373
+ const output = boundedLaneValue(selectedStep?.outputName);
374
+ const ref = boundedLaneValue(selectedStep?.workflowKey ?? job.workflowKey ?? job.asyncId.slice(0, 8), 24) ?? job.asyncId.slice(0, 8);
375
+ const chips = [
376
+ selectedStep?.context,
377
+ selectedStep?.structured ? "structured" : undefined,
378
+ selectedStep?.activityState === "active_long_running" ? "long-running" : undefined,
379
+ selectedStep?.activityState === "needs_attention" ? "attention" : undefined,
380
+ selectedStep?.watchdog?.phase === "stale" ? "stale" : undefined,
381
+ selectedStep?.toolBudgetBlocked === true || selectedStep?.turnBudgetExceeded === true ? "blocked" : undefined,
382
+ ].filter((chip): chip is string => Boolean(chip));
383
+ const state = isTerminalLaneState(job.status) ? job.status : selectedStep?.status ?? job.status;
384
+ const next = laneNextAction(state, selectedStep, output, gate);
385
+ if (!label && !phase && !gate && !output && !selectedStep?.workflowKey && !job.workflowKey && !trace?.label && !trace?.phase) return undefined;
386
+ return { ...(label ? { label } : {}), role, ...(phase ? { phase } : {}), state, ...(gate ? { gate } : {}), ...(next ? { next } : {}), ...(output ? { output } : {}), ...(workspace ? { workspace } : {}), ref, chips };
387
+ }
388
+
389
+ function laneStateLabel(state: AsyncLaneProjection["state"], theme: Theme): string {
390
+ if (state === "running") return theme.fg("accent", "running");
391
+ if (state === "queued" || state === "pending") return theme.fg("muted", state);
392
+ if (state === "complete" || state === "completed") return theme.fg("success", "complete");
393
+ if (state === "failed" || state === "rejected") return theme.fg("error", state === "rejected" ? "rejected" : "failed");
394
+ return theme.fg("warning", state);
395
+ }
396
+
397
+ function formatLaneProjection(lane: AsyncLaneProjection, theme: Theme): string {
398
+ const label = boundedLaneValue(lane.label, 56);
399
+ const identity = [label, lane.role ? `role:${lane.role}` : undefined].filter(Boolean).join(" · ");
400
+ return `${identity ? theme.bold(identity) : theme.bold(lane.role)} · ${laneStateLabel(lane.state, theme)}`;
401
+ }
402
+
403
+ function formatLaneChip(chip: string, theme: Theme): string {
404
+ const text = `[${chip}]`;
405
+ if (chip === "blocked") return theme.fg("error", text);
406
+ if (chip === "stale") return theme.fg("warning", text);
407
+ return text;
408
+ }
409
+
410
+ function formatLaneProjectionDetails(lane: AsyncLaneProjection, theme: Theme): string | undefined {
411
+ const details = [
412
+ lane.phase ? `phase:${lane.phase}` : undefined,
413
+ lane.gate ? `gate:${lane.gate}` : undefined,
414
+ lane.next ? `next:${lane.next}` : undefined,
415
+ lane.output ? `out:${lane.output}` : undefined,
416
+ lane.workspace ? `workspace:${lane.workspace}` : lane.ref ? `ref:${lane.ref}` : undefined,
417
+ ].filter(Boolean);
418
+ const chips = lane.chips.map((chip) => formatLaneChip(chip, theme));
419
+ return [...(details.length ? [theme.fg("dim", details.join(" · "))] : []), ...chips].join(" · ") || undefined;
420
+ }
421
+
422
+ function formatLaneProjectionLines(lane: AsyncLaneProjection, theme: Theme, indent: string): string[] {
423
+ const details = formatLaneProjectionDetails(lane, theme);
424
+ return [
425
+ `${indent}${formatLaneProjection(lane, theme)}`,
426
+ ...(details ? [`${indent} ${details}`] : []),
427
+ ];
428
+ }
429
+
430
+ function laneRenderKey(job: AsyncJobState): unknown {
431
+ const lane = projectAsyncLane(job);
432
+ return lane ? [lane.label, lane.role, lane.phase, lane.state, lane.gate, lane.next, lane.output, lane.workspace, lane.ref, lane.chips] : undefined;
433
+ }
434
+
435
+ function widgetLaneDetailLines(job: AsyncJobState, theme: Theme): string[] {
436
+ if (job.steps?.length && (job.mode === "parallel" || job.mode === "chain")) return [];
437
+ const lane = projectAsyncLane(job);
438
+ return lane ? formatLaneProjectionLines(lane, theme, " ") : [];
439
+ }
440
+
441
+ function workflowPreflightLines(job: AsyncJobState, expanded = false): string[] {
442
+ if (job.mode !== "workflow" || !job.preflight) return [];
443
+ if (!expanded) {
444
+ const warning = formatWorkflowPreflightWarningSummary(job.workflow?.preflightWarnings, { indent: " ", hint: "expand for debug" });
445
+ return [
446
+ formatWorkflowPreflightPlanSummary(job.preflight, { indent: " " }),
447
+ ...(warning ? [warning] : []),
448
+ ];
449
+ }
450
+ return [
451
+ ...formatWorkflowPreflight(job.preflight, { indent: " " }).split("\n"),
452
+ ...(job.workflow?.preflightWarnings ? formatWorkflowPreflightWarnings(job.workflow.preflightWarnings, { indent: " " }).split("\n") : []),
453
+ ];
454
+ }
455
+
456
+ function workflowLabelForResult(details: Details, resultIndex: number): string | undefined {
457
+ const flatIndex = details.results[resultIndex]?.progress?.index ?? resultIndex;
458
+ const visit = (nodes: NonNullable<Details["workflowGraph"]>["nodes"]): string | undefined => {
459
+ for (const node of nodes) {
460
+ if (node.flatIndex === flatIndex && node.label.trim()) return node.label;
461
+ const nested = node.children ? visit(node.children) : undefined;
462
+ if (nested) return nested;
463
+ }
464
+ return undefined;
465
+ };
466
+ return details.workflowGraph ? visit(details.workflowGraph.nodes) : undefined;
467
+ }
468
+
276
469
  function hasLiveOutputSignal(line: string): boolean {
277
470
  const clean = oneLine(line);
278
471
  return liveOutputWordSignalPattern.test(clean) || liveOutputCodeSignalPattern.test(clean);
@@ -456,7 +649,7 @@ function resultStatusLine(result: Details["results"][number], output: string): s
456
649
 
457
650
  type ResultPresentation = {
458
651
  glyph: string;
459
- label: "running" | "detached" | "stopped" | "paused" | "failed" | "completed";
652
+ label: "running" | "detached" | "stopped" | "paused" | "failed" | "partial" | "completed";
460
653
  tone: "accent" | "warning" | "error" | "success";
461
654
  };
462
655
 
@@ -466,6 +659,7 @@ function semanticResultPresentation(input: {
466
659
  stopped?: boolean;
467
660
  interrupted?: boolean;
468
661
  failed?: boolean;
662
+ partial?: boolean;
469
663
  completedWithoutOutput?: boolean;
470
664
  seed?: number;
471
665
  frame?: number;
@@ -478,6 +672,7 @@ function semanticResultPresentation(input: {
478
672
  if (input.stopped) return { glyph: "■", label: "stopped", tone: "warning" };
479
673
  if (input.interrupted) return { glyph: "■", label: "paused", tone: "warning" };
480
674
  if (input.failed) return { glyph: "✗", label: "failed", tone: "error" };
675
+ if (input.partial) return { glyph: "■", label: "partial", tone: "warning" };
481
676
  return { glyph: "✓", label: "completed", tone: input.completedWithoutOutput ? "warning" : "success" };
482
677
  }
483
678
 
@@ -556,6 +751,7 @@ function widgetStepRenderKey(step: AsyncJobStep, index: number, expanded = false
556
751
  return [
557
752
  step.index ?? index,
558
753
  step.agent,
754
+ step.sessionName,
559
755
  step.workflowKey,
560
756
  step.phase,
561
757
  step.label,
@@ -575,6 +771,15 @@ function widgetStepRenderKey(step: AsyncJobStep, index: number, expanded = false
575
771
  step.model,
576
772
  step.thinking,
577
773
  step.context,
774
+ step.description,
775
+ step.outputName,
776
+ step.structured,
777
+ step.acceptance?.status,
778
+ step.acceptance?.reviewResult?.status,
779
+ step.review?.status,
780
+ step.toolBudgetBlocked,
781
+ step.turnBudgetExceeded,
782
+ step.watchdog?.phase,
578
783
  step.error,
579
784
  expanded ? expandedStepActivityRenderKey(step) : undefined,
580
785
  nestedRenderKey(step.children, expanded),
@@ -586,6 +791,7 @@ function nestedRenderKey(children: NestedRunSummary[] | undefined, expanded = fa
586
791
  child.id,
587
792
  child.state,
588
793
  child.agent,
794
+ child.sessionName,
589
795
  child.model,
590
796
  child.thinking,
591
797
  child.activityState,
@@ -605,6 +811,22 @@ function nestedRenderKey(children: NestedRunSummary[] | undefined, expanded = fa
605
811
  ]);
606
812
  }
607
813
 
814
+ function hostStepRenderKey(row: AsyncStatusWorkflowRow): unknown[] {
815
+ return [
816
+ row.kind,
817
+ row.name,
818
+ row.state,
819
+ row.provider,
820
+ row.role,
821
+ row.verdict,
822
+ row.reasonCode,
823
+ row.detail,
824
+ row.target,
825
+ row.freshness,
826
+ row.reportPath,
827
+ ];
828
+ }
829
+
608
830
  export function widgetRenderKey(job: AsyncJobState, expanded = false): string {
609
831
  return JSON.stringify({
610
832
  asyncDir: job.asyncDir,
@@ -621,8 +843,12 @@ export function widgetRenderKey(job: AsyncJobState, expanded = false): string {
621
843
  currentStep: job.currentStep,
622
844
  chainStepCount: job.chainStepCount,
623
845
  parallelGroups: job.parallelGroups,
846
+ workflowHostSteps: projectAsyncWorkflowRows([], job.hostSteps).map(hostStepRenderKey),
847
+ preflight: expanded ? job.preflight : job.preflight ? formatWorkflowPreflightPlanSummary(job.preflight) : undefined,
848
+ preflightWarnings: expanded ? job.workflow?.preflightWarnings : job.workflow?.preflightWarnings?.length || undefined,
624
849
  steps: job.steps?.map((step, index) => widgetStepRenderKey(step, index, expanded)),
625
850
  nestedChildren: nestedRenderKey(job.nestedChildren, expanded),
851
+ lane: laneRenderKey(job),
626
852
  stepsTotal: job.stepsTotal,
627
853
  runningSteps: job.runningSteps,
628
854
  completedSteps: job.completedSteps,
@@ -663,6 +889,7 @@ function widgetActivity(job: AsyncJobState): string {
663
889
  if (job.status === "queued") return "queued…";
664
890
  if (job.status === "paused") return "Paused";
665
891
  if (job.status === "stopped") return "Stopped";
892
+ if (job.status === "partial") return "Partial";
666
893
  if (job.status === "failed") return "Failed";
667
894
  return "Done";
668
895
  }
@@ -740,7 +967,7 @@ function widgetStepActivity(step: NonNullable<AsyncJobState["steps"]>[number], s
740
967
  if (step.currentPath) facts.push(shortenPath(step.currentPath));
741
968
  if (step.turnCount !== undefined) facts.push(`${step.turnCount} turns`);
742
969
  if (step.toolCount !== undefined) facts.push(`${step.toolCount} tools`);
743
- if (step.tokens?.total) facts.push(formatTokenStat(step.tokens.total));
970
+ if (step.tokens?.total) facts.push(formatTokenUsage(step.tokens, "token"));
744
971
  const activity = buildLiveStatusLine(step, snapshotNow);
745
972
  if (activity && facts.length) return `${activity} · ${facts.join(" · ")}`;
746
973
  if (activity) return activity;
@@ -780,7 +1007,11 @@ function widgetParallelAgentDetails(job: AsyncJobState, theme: Theme, expanded =
780
1007
  const activity = widgetStepActivity(step, job.updatedAt);
781
1008
  const itemTitle = job.mode === "parallel" || job.activeParallelGroup ? "Agent" : "Step";
782
1009
  const modelDisplay = modelThinkingBadge(theme, step.model, step.thinking);
783
- lines.push(` ${theme.fg("dim", `${marker} ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index), frame)} ${itemTitle} ${index + 1}/${total}: ${step.agent} · ${widgetStepStatus(step.status, theme)}${modelDisplay}${activity ? ` · ${activity}` : ""}`)}`);
1010
+ const label = compactTaskText(step.description, step.label);
1011
+ const display = step.sessionName?.trim() || (label ? `${label} (${step.agent})` : step.agent);
1012
+ lines.push(` ${theme.fg("dim", `${marker} ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index), frame)} ${itemTitle} ${index + 1}/${total}: ${display} · ${widgetStepStatus(step.status, theme)}${modelDisplay}${activity ? ` · ${activity}` : ""}`)}`);
1013
+ const lane = projectAsyncLane(job, step);
1014
+ if (lane) lines.push(...formatLaneProjectionLines(lane, theme, " "));
784
1015
  for (const nestedLine of formatNestedWidgetLines(step.children, theme, width, expanded, job.updatedAt, expanded ? 8 : 6)) lines.push(` ${nestedLine}`);
785
1016
  }
786
1017
  return lines;
@@ -906,12 +1137,13 @@ function buildChainRenderEntries(details: Details, label: MultiProgressLabel): C
906
1137
  continue;
907
1138
  }
908
1139
  for (let index = span.start; index < span.start + span.count; index++) {
1140
+ const result = details.results[index];
909
1141
  entries.push({
910
1142
  kind: "result",
911
1143
  resultIndex: index,
912
1144
  rowNumber: index + 1,
913
1145
  rowLabel: span.isParallel ? `Agent ${index - span.start + 1}/${span.count}` : `Step ${span.stepIndex + 1}`,
914
- agentName: details.results[index]?.agent ?? details.chainAgents?.[span.stepIndex] ?? `step-${span.stepIndex + 1}`,
1146
+ agentName: result?.sessionName?.trim() || result?.agent || details.chainAgents?.[span.stepIndex] || `step-${span.stepIndex + 1}`,
915
1147
  });
916
1148
  }
917
1149
  }
@@ -1058,7 +1290,7 @@ function widgetStats(job: AsyncJobState, theme: Theme): string {
1058
1290
  parts.push(`steps ${stepsTotal}`);
1059
1291
  }
1060
1292
  if (job.toolCount !== undefined) parts.push(formatToolUseStat(job.toolCount));
1061
- if (job.totalTokens?.total) parts.push(formatTokenStat(job.totalTokens.total));
1293
+ if (job.totalTokens?.total) parts.push(formatTokenUsage(job.totalTokens, "token"));
1062
1294
  if (job.startedAt !== undefined && job.updatedAt !== undefined) parts.push(formatDuration(Math.max(0, job.updatedAt - job.startedAt)));
1063
1295
  return statJoin(theme, parts);
1064
1296
  }
@@ -1067,7 +1299,11 @@ function widgetStepStats(theme: Theme, step: NonNullable<AsyncJobState["steps"]>
1067
1299
  return statJoin(theme, [
1068
1300
  step.turnCount !== undefined ? `${step.turnCount} turns` : "",
1069
1301
  step.toolCount !== undefined ? formatToolUseStat(step.toolCount) : "",
1070
- step.tokens?.total ? formatTokenStat(step.tokens.total) : "",
1302
+ step.tokens
1303
+ ? step.contextLimit !== undefined
1304
+ ? formatContextUsage(step.tokens, step.contextLimit) ?? formatTokenUsage(step.tokens, "token")
1305
+ : step.tokens.total ? formatTokenUsage(step.tokens, "token") : ""
1306
+ : "",
1071
1307
  step.durationMs !== undefined ? formatDuration(step.durationMs) : "",
1072
1308
  ]);
1073
1309
  }
@@ -1092,6 +1328,7 @@ function widgetOutputPath(job: AsyncJobState, step: NonNullable<AsyncJobState["s
1092
1328
  }
1093
1329
 
1094
1330
  function nestedRunName(run: NestedRunSummary): string {
1331
+ if (run.sessionName?.trim()) return run.sessionName.trim();
1095
1332
  if (run.agent) return run.agent;
1096
1333
  if (run.agents?.length) return formatWidgetAgents(run.agents);
1097
1334
  return run.id;
@@ -1101,6 +1338,7 @@ function nestedStatusGlyph(state: NestedRunSummary["state"] | NestedStepSummary[
1101
1338
  if (state === "running") return theme.fg("accent", runningGlyph(seed));
1102
1339
  if (state === "complete" || state === "completed") return theme.fg("success", "✓");
1103
1340
  if (state === "failed") return theme.fg("error", "✗");
1341
+ if (state === "partial") return theme.fg("warning", "■");
1104
1342
  if (state === "paused") return theme.fg("warning", "■");
1105
1343
  if (state === "stopped") return theme.fg("warning", "■");
1106
1344
  return theme.fg("muted", "◦");
@@ -1148,6 +1386,7 @@ function nestedActivity(input: Pick<NestedRunSummary | NestedStepSummary, "activ
1148
1386
  if (state === "queued" || state === "pending") return "queued…";
1149
1387
  if (state === "paused") return "Paused";
1150
1388
  if (state === "stopped") return "Stopped";
1389
+ if (state === "partial") return "Partial";
1151
1390
  if (state === "failed") return "Failed";
1152
1391
  return "Done";
1153
1392
  }
@@ -1172,7 +1411,7 @@ function formatNestedWidgetLines(children: NestedRunSummary[] | undefined, theme
1172
1411
  const activity = nestedActivity(step, state, snapshotNow ?? fallback);
1173
1412
  const timestamp = "status" in step ? nestedStepTimestamp(step, fallback) : formatClockTime(nestedRunEventTime(step));
1174
1413
  const error = step.error ? ` · ${step.error}` : "";
1175
- const name = "status" in step ? step.agent : nestedRunName(step);
1414
+ const name = "status" in step ? childDisplayName(step) : nestedRunName(step);
1176
1415
  rows.push({
1177
1416
  prefix,
1178
1417
  text: `${nestedTimestampPrefix(timestamp)}${nestedStatusGlyph(state, theme)} ${name} · ${state}${modelThinking ? ` · ${modelThinking}` : ""}${activity ? ` · ${activity}` : ""}${error}`,
@@ -1234,7 +1473,7 @@ function formatNestedWidgetLines(children: NestedRunSummary[] | undefined, theme
1234
1473
  for (const step of child.steps ?? []) {
1235
1474
  if (lines.length >= lineBudget) return;
1236
1475
  const modelThinking = formatModelThinking(step.model, step.thinking);
1237
- lines.push(theme.fg("dim", `${prefix} ↳ ${nestedTimestampPrefix(nestedStepTimestamp(step, child.lastUpdate))}${nestedStatusGlyph(step.status, theme)} ${step.agent} · ${step.status}${modelThinking ? ` · ${modelThinking}` : ""} · ${nestedActivity(step, step.status, snapshotNow ?? child.lastUpdate)}`));
1476
+ lines.push(theme.fg("dim", `${prefix} ↳ ${nestedTimestampPrefix(nestedStepTimestamp(step, child.lastUpdate))}${nestedStatusGlyph(step.status, theme)} ${childDisplayName(step)} · ${step.status}${modelThinking ? ` · ${modelThinking}` : ""} · ${nestedActivity(step, step.status, snapshotNow ?? child.lastUpdate)}`));
1238
1477
  append(step.children, depth + 1, `${prefix} `);
1239
1478
  }
1240
1479
  append(child.children, depth + 1, `${prefix} `);
@@ -1258,7 +1497,11 @@ function foregroundStyleWidgetStepLines(
1258
1497
  const status = widgetStepStatus(step.status, theme);
1259
1498
  const stats = widgetStepStats(theme, step);
1260
1499
  const modelDisplay = modelThinkingBadge(theme, step.model, step.thinking);
1261
- const lines = [` ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index - 1), frame)} ${itemTitle} ${index}/${total}: ${themeBold(theme, step.agent)}${contextModeBadge(theme, step.context)} ${theme.fg("dim", "·")} ${status}${modelDisplay}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`];
1500
+ const lines = [` ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index - 1), frame)} ${itemTitle} ${index}/${total}: ${themeBold(theme, childDisplayName(step))}${contextModeBadge(theme, step.context)} ${theme.fg("dim", "·")} ${status}${modelDisplay}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`];
1501
+ const lane = projectAsyncLane(job, step);
1502
+ if (lane) lines.push(...formatLaneProjectionLines(lane, theme, " "));
1503
+ const task = compactTaskText(step.description, step.label);
1504
+ if (task) lines.push(` ${theme.fg("dim", `task: ${task}`)}`);
1262
1505
  const activity = widgetStepActivityLine(step, width, expanded, job.updatedAt);
1263
1506
  if (activity) lines.push(` ${theme.fg("dim", `⎿ ${activity}`)}`);
1264
1507
  for (const nestedLine of formatNestedWidgetLines(step.children, theme, width, expanded, job.updatedAt, expanded ? 12 : 6)) {
@@ -1284,18 +1527,50 @@ function foregroundStyleWidgetStepLines(
1284
1527
  return lines;
1285
1528
  }
1286
1529
 
1530
+ function hostStepWidgetLines(job: AsyncJobState, theme: Theme, indent: string): string[] {
1531
+ const rows = projectAsyncWorkflowRows([], job.hostSteps).filter((row) => row.kind);
1532
+ const visible = rows.slice(0, 8);
1533
+ const lines = visible.map((row) => {
1534
+ const state = hostStepVerdictLabel(row.state as HostStepState, row.verdict as HostStepVerdict | undefined);
1535
+ const glyph = state === "running" ? theme.fg("accent", "●")
1536
+ : state === "pending" ? theme.fg("muted", "◦")
1537
+ : state === "pass" ? theme.fg("success", "✓")
1538
+ : state === "fail" || state === "error" ? theme.fg("error", "✗")
1539
+ : theme.fg("warning", "■");
1540
+ const details = [
1541
+ row.provider ? `provider:${row.provider}` : undefined,
1542
+ row.role ? `role:${row.role}` : undefined,
1543
+ row.target,
1544
+ row.detail,
1545
+ row.reasonCode ? `reason:${row.reasonCode}` : undefined,
1546
+ row.freshness?.stale ? "stale" : row.freshness?.observedRef ? `ref:${row.freshness.observedRef}` : undefined,
1547
+ row.reportPath ? `out:${hostStepReportName(row.reportPath)}` : undefined,
1548
+ ].filter(Boolean).join(" · ");
1549
+ return `${indent}${glyph} ${row.kind}: ${row.name} · ${state}${details ? ` · ${details}` : ""}`;
1550
+ });
1551
+ if (rows.length > visible.length) lines.push(`${indent}${theme.fg("dim", `… +${rows.length - visible.length} host steps hidden`)}`);
1552
+ return lines;
1553
+ }
1554
+
1287
1555
  function foregroundStyleWidgetDetails(job: AsyncJobState, theme: Theme, expanded: boolean, width: number, frame?: number): string[] {
1288
- if (!job.steps?.length) return [
1289
- ` ${theme.fg("dim", `⎿ ${widgetActivity(job)}`)}`,
1290
- ...formatNestedWidgetLines(job.nestedChildren, theme, width, expanded, job.updatedAt, expanded ? 12 : 6).map((line) => ` ${line}`),
1291
- ];
1556
+ if (!job.steps?.length) {
1557
+ const lane = projectAsyncLane(job);
1558
+ return [
1559
+ ...workflowPreflightLines(job, expanded),
1560
+ ...(lane ? formatLaneProjectionLines(lane, theme, " ") : []),
1561
+ ...hostStepWidgetLines(job, theme, " "),
1562
+ ` ${theme.fg("dim", `⎿ ${widgetActivity(job)}`)}`,
1563
+ ...formatNestedWidgetLines(job.nestedChildren, theme, width, expanded, job.updatedAt, expanded ? 12 : 6).map((line) => ` ${line}`),
1564
+ ];
1565
+ }
1292
1566
  if (job.mode === "chain" && !job.activeParallelGroup && job.parallelGroups?.length) return widgetChainDetails(job, theme, expanded, width, frame);
1293
1567
  const total = job.stepsTotal ?? job.steps.length;
1294
1568
  const itemTitle = job.mode === "parallel" || job.activeParallelGroup ? "Agent" : "Step";
1295
- const lines: string[] = [];
1569
+ const lines: string[] = workflowPreflightLines(job, expanded);
1296
1570
  for (const [index, step] of job.steps.entries()) {
1297
1571
  lines.push(...foregroundStyleWidgetStepLines(job, theme, step, itemTitle, index + 1, total, expanded, width, frame));
1298
1572
  }
1573
+ lines.push(...hostStepWidgetLines(job, theme, " "));
1299
1574
  const attached = new Set(job.steps.flatMap((step) => step.children?.map((child) => child.id) ?? []));
1300
1575
  const unattached = job.nestedChildren?.filter((child) => !attached.has(child.id)) ?? [];
1301
1576
  for (const nestedLine of formatNestedWidgetLines(unattached, theme, width, expanded, job.updatedAt, expanded ? 12 : 6)) {
@@ -1329,9 +1604,14 @@ function compactSingleWidgetLines(job: AsyncJobState, theme: Theme, width: numbe
1329
1604
  const stepStats = widgetStepStats(theme, step);
1330
1605
  const activitySuffix = activity ? ` ${theme.fg("dim", "·")} ${theme.fg("dim", activity)}` : "";
1331
1606
  const modelDisplay = modelThinkingBadge(theme, step.model, step.thinking);
1332
- lines.push(` ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index), frame)} ${itemTitle} ${index + 1}/${total}: ${themeBold(theme, step.agent)}${contextModeBadge(theme, step.context)} ${theme.fg("dim", "·")} ${status}${modelDisplay}${activitySuffix}${stepStats ? ` ${theme.fg("dim", "·")} ${stepStats}` : ""}`);
1607
+ const task = compactTaskText(step.description, step.label);
1608
+ const taskSuffix = task ? ` ${theme.fg("dim", "·")} ${theme.fg("dim", `task: ${task}`)}` : "";
1609
+ lines.push(` ${widgetStepGlyph(step.status, theme, widgetStepRunningSeed(step, index), frame)} ${itemTitle} ${index + 1}/${total}: ${themeBold(theme, childDisplayName(step))}${contextModeBadge(theme, step.context)} ${theme.fg("dim", "·")} ${status}${modelDisplay}${taskSuffix}${activitySuffix}${stepStats ? ` ${theme.fg("dim", "·")} ${stepStats}` : ""}`);
1610
+ const lane = projectAsyncLane(job, step);
1611
+ if (lane) lines.push(...formatLaneProjectionLines(lane, theme, " "));
1333
1612
  for (const nestedLine of formatNestedWidgetLines(step.children, theme, width, false, job.updatedAt, 6)) lines.push(` ${nestedLine}`);
1334
1613
  }
1614
+ lines.push(...hostStepWidgetLines(job, theme, " "));
1335
1615
  if (job.steps.some((step) => step.status === "running")) lines.push(theme.fg("accent", ` ${liveDetailHintText()}`));
1336
1616
  return lines.map((line) => truncLine(line, width));
1337
1617
  }
@@ -1468,9 +1748,18 @@ function progressiveJobLine(job: AsyncJobState, theme: Theme, width: number, fra
1468
1748
  const stats = widgetStats(job, theme);
1469
1749
  const activity = widgetActivity(job);
1470
1750
  const status = job.status === "complete" ? "done" : job.status;
1751
+ const lane = projectAsyncLane(job);
1752
+ const laneSummary = lane
1753
+ ? [lane.label ?? lane.role, lane.phase ? `phase:${lane.phase}` : undefined, lane.output ? `out:${lane.output}` : undefined, lane.workspace ? `workspace:${lane.workspace}` : `ref:${lane.ref}`].filter(Boolean).join(" · ")
1754
+ : "";
1755
+ const laneSignals = lane
1756
+ ? [lane.next ? `next:${lane.next}` : undefined, ...lane.chips.map((chip) => formatLaneChip(chip, theme))].filter(Boolean).join(" · ")
1757
+ : "";
1471
1758
  const parts = [
1472
1759
  `${themeBold(theme, widgetJobName(job))}${contextModeBadge(theme, job.context)}`,
1473
1760
  theme.fg("dim", status),
1761
+ laneSignals ? laneSignals : "",
1762
+ laneSummary ? theme.fg("dim", laneSummary) : "",
1474
1763
  stats,
1475
1764
  activity && activity.toLowerCase() !== status ? theme.fg("dim", activity) : "",
1476
1765
  ].filter(Boolean);
@@ -1616,6 +1905,7 @@ export function buildWidgetLines(jobs: AsyncJobState[], theme: Theme, width = ge
1616
1905
  items.push([
1617
1906
  `${widgetStatusGlyph(job, theme, frame)} ${themeBold(theme, widgetJobName(job))}${contextModeBadge(theme, job.context)}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
1618
1907
  ` ${theme.fg("dim", `⎿ ${widgetActivity(job)}`)}`,
1908
+ ...widgetLaneDetailLines(job, theme),
1619
1909
  ...widgetParallelAgentDetails(job, theme, expanded, width, frame),
1620
1910
  ]);
1621
1911
  slots--;
@@ -1633,6 +1923,7 @@ export function buildWidgetLines(jobs: AsyncJobState[], theme: Theme, width = ge
1633
1923
  items.push([
1634
1924
  `${widgetStatusGlyph(job, theme, frame)} ${themeBold(theme, widgetJobName(job))}${contextModeBadge(theme, job.context)}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
1635
1925
  ` ${theme.fg("dim", `⎿ ${widgetActivity(job)}`)}`,
1926
+ ...widgetLaneDetailLines(job, theme),
1636
1927
  ...widgetParallelAgentDetails(job, theme, expanded, width, frame),
1637
1928
  ]);
1638
1929
  slots--;
@@ -1700,9 +1991,11 @@ function renderSingleCompact(
1700
1991
  const detailIndent = mainWindowIndent(layout, 1);
1701
1992
  const continuationIndent = mainWindowIndent(layout, 2) + (layout.horizontalSpacing > 0 ? " " : "");
1702
1993
  const modelDisplay = modelThinkingBadge(theme, r.model ?? r.progress?.model, r.thinking ?? r.progress?.thinking);
1703
- c.addChild(new Text(truncLine(`${resultGlyph(r, output, theme, isRunning, undefined, frame)} ${theme.fg("toolTitle", theme.bold(r.agent))}${modelDisplay}${contextBadge}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`, width), 0, 0));
1994
+ c.addChild(new Text(truncLine(`${resultGlyph(r, output, theme, isRunning, undefined, frame)} ${theme.fg("toolTitle", theme.bold(childDisplayName(r)))}${modelDisplay}${contextBadge}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`, width), 0, 0));
1704
1995
 
1705
1996
  if (isRunning && r.progress) {
1997
+ const task = compactTaskText(r.task);
1998
+ if (task) c.addChild(new Text(truncLine(theme.fg("dim", `${detailIndent}task: ${task}`), width), 0, 0));
1706
1999
  const progressSnapshotNow = snapshotNowForProgress(r.progress);
1707
2000
  const activity = compactCurrentActivity(r.progress);
1708
2001
  c.addChild(new Text(truncLine(theme.fg("dim", `${detailIndent}⎿ ${activity}`), width), 0, 0));
@@ -1731,6 +2024,7 @@ function renderSingleCompact(
1731
2024
  }
1732
2025
 
1733
2026
  function workflowRowGlyph(row: WorkflowChatProgressRow, theme: Theme, frame?: number): string {
2027
+ if (row.state === "planned") return theme.fg("muted", "◦");
1734
2028
  if (row.state === "running") return theme.fg("accent", runningGlyph(frame));
1735
2029
  if (row.state === "complete") return theme.fg("success", "✓");
1736
2030
  if (row.state === "detached" || row.state === "stopped") return theme.fg("warning", "■");
@@ -1739,6 +2033,7 @@ function workflowRowGlyph(row: WorkflowChatProgressRow, theme: Theme, frame?: nu
1739
2033
 
1740
2034
  function workflowRowStateLabel(row: WorkflowChatProgressRow, theme: Theme): string {
1741
2035
  const label = (row.state === "complete" ? "complete" : row.state).padEnd(8);
2036
+ if (row.state === "planned") return theme.fg("dim", label);
1742
2037
  if (row.state === "running") return theme.fg("accent", label);
1743
2038
  if (row.state === "complete") return theme.fg("success", label);
1744
2039
  if (row.state === "detached" || row.state === "stopped") return theme.fg("warning", label);
@@ -1753,9 +2048,9 @@ function workflowOverallState(rows: WorkflowChatProgressRow[], hasTerminalValue:
1753
2048
  return "running";
1754
2049
  }
1755
2050
 
1756
- function renderWorkflowChatProgress(d: Details, result: AgentToolResult<Details>, theme: Theme, layout: MainWindowRenderLayout, frame?: number): Component {
2051
+ function renderWorkflowChatProgress(d: Details, result: AgentToolResult<Details>, theme: Theme, layout: MainWindowRenderLayout, frame?: number, expanded = false): Component {
1757
2052
  const workflow = d.workflow;
1758
- const rows = workflow ? buildWorkflowChatProgressRows(workflow.trace) : [];
2053
+ const rows = workflow ? buildWorkflowChatProgressRows(workflow.trace, d.preflight) : d.preflight ? buildWorkflowChatProgressRows([], d.preflight) : [];
1759
2054
  const state = workflowOverallState(rows, workflow?.value !== undefined, result.isError);
1760
2055
  const glyph = state === "running" ? theme.fg("accent", runningGlyph(frame)) : state === "complete" ? theme.fg("success", "✓") : state === "paused" ? theme.fg("warning", "■") : theme.fg("error", "✗");
1761
2056
  const width = getTermWidth() - 4;
@@ -1766,6 +2061,7 @@ function renderWorkflowChatProgress(d: Details, result: AgentToolResult<Details>
1766
2061
  const rowIndent = mainWindowIndent(layout, 1);
1767
2062
  c.addChild(new Text(truncLine(`${glyph} ${theme.fg("toolTitle", theme.bold("workflow"))} ${runId} ${theme.fg("dim", "·")} ${d.chatProgress?.repoRelation === "same" ? "same repo" : "other repo"} ${theme.fg("dim", "·")} ${state}`, width), 0, 0));
1768
2063
  c.addChild(new Text(truncLine(theme.fg("dim", `${rowIndent}Repo ${repoLabel}`), width), 0, 0));
2064
+ if (d.preflight) c.addChild(new Text(truncLine(theme.fg("dim", formatWorkflowPreflightPlanSummary(d.preflight, { indent: rowIndent })), width), 0, 0));
1769
2065
  if (phase) c.addChild(new Text(truncLine(theme.fg("dim", `${rowIndent}Phase ${phase}`), width), 0, 0));
1770
2066
  if (rows.length === 0) {
1771
2067
  c.addChild(new Text(truncLine(theme.fg("dim", `${rowIndent}◦ waiting for workflow child launches`), width), 0, 0));
@@ -1779,7 +2075,20 @@ function renderWorkflowChatProgress(d: Details, result: AgentToolResult<Details>
1779
2075
  const duration = row.durationMs !== undefined ? ` ${theme.fg("dim", `· ${formatDuration(row.durationMs)}`)}` : "";
1780
2076
  const run = row.runId ? ` ${theme.fg("dim", `[${row.runId.slice(0, 8)}]`)}` : "";
1781
2077
  const error = row.error ? ` ${theme.fg(row.state === "detached" ? "warning" : "error", `· ${compactWorkflowError(row.error)}`)}` : "";
1782
- c.addChild(new Text(truncLine(`${rowIndent}${workflowRowGlyph(row, theme, frame)} ${status} ${theme.bold(row.key)}${label}${run}${duration}${error}`, width), 0, 0));
2078
+ const hints = expanded && row.preflight ? [
2079
+ row.preflight.mode ? `mode:${row.preflight.mode}` : undefined,
2080
+ row.preflight.decision ? `decision:${row.preflight.decision}` : undefined,
2081
+ row.preflight.claims?.length ? `claims:${row.preflight.claims.join(",")}` : undefined,
2082
+ row.preflight.expectedOutput ? `expected:${row.preflight.expectedOutput}` : undefined,
2083
+ row.preflight.independence ? `independence:${row.preflight.independence}` : undefined,
2084
+ ].filter((value): value is string => Boolean(value)).join(" · ") : "";
2085
+ c.addChild(new Text(truncLine(`${rowIndent}${workflowRowGlyph(row, theme, frame)} ${status} ${theme.bold(row.key)}${label}${run}${duration}${error}${hints ? ` ${theme.fg("dim", `· ${hints}`)}` : ""}`, width), 0, 0));
2086
+ }
2087
+ if (workflow?.preflightWarnings?.length) {
2088
+ const warningLines = expanded
2089
+ ? formatWorkflowPreflightWarnings(workflow.preflightWarnings, { indent: rowIndent }).split("\n")
2090
+ : [formatWorkflowPreflightWarningSummary(workflow.preflightWarnings, { indent: rowIndent, hint: "expand for debug" })];
2091
+ for (const warningLine of warningLines) c.addChild(new Text(truncLine(theme.fg("warning", warningLine), width), 0, 0));
1783
2092
  }
1784
2093
  if (workflow?.emits.length) c.addChild(new Text(truncLine(theme.fg("dim", `${rowIndent}Emits ${workflow.emits.length}`), width), 0, 0));
1785
2094
  return c;
@@ -1795,6 +2104,7 @@ function renderMultiCompact(d: Details, theme: Theme, layout: MainWindowRenderLa
1795
2104
  || workflowGraphHasStatus(d, ["failed"]);
1796
2105
  const paused = d.results.some((r) => r.interrupted)
1797
2106
  || workflowGraphHasStatus(d, ["paused"]);
2107
+ const partial = workflowGraphHasStatus(d, ["partial"]);
1798
2108
  let totalSummary = d.progressSummary;
1799
2109
  if (!totalSummary) {
1800
2110
  let sawProgress = false;
@@ -1818,6 +2128,7 @@ function renderMultiCompact(d: Details, theme: Theme, layout: MainWindowRenderLa
1818
2128
  stopped,
1819
2129
  interrupted: paused,
1820
2130
  failed,
2131
+ partial,
1821
2132
  seed: runningSeed(progressRunningSeed(totalSummary), d.currentStepIndex),
1822
2133
  frame,
1823
2134
  });
@@ -1827,7 +2138,6 @@ function renderMultiCompact(d: Details, theme: Theme, layout: MainWindowRenderLa
1827
2138
  const width = getTermWidth() - 4;
1828
2139
  const rowIndent = mainWindowIndent(layout, 1);
1829
2140
  const detailIndent = mainWindowIndent(layout, 2);
1830
- const continuationIndent = mainWindowIndent(layout, 3) + (layout.horizontalSpacing > 0 ? " " : "");
1831
2141
  c.addChild(new Text(truncLine(`${glyph} ${theme.fg("toolTitle", theme.bold(d.mode))}${contextBadge}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`, width), 0, 0));
1832
2142
 
1833
2143
  const useResultsDirectly = multiLabel.hasParallelInChain || !d.chainAgents?.length;
@@ -1839,7 +2149,8 @@ function renderMultiCompact(d: Details, theme: Theme, layout: MainWindowRenderLa
1839
2149
  const r = d.results[i];
1840
2150
  const fallbackLabel = itemTitle.toLowerCase();
1841
2151
  const rowNumber = multiLabel.showActiveGroupOnly ? (i - multiLabel.groupStartIndex + 1) : (i + 1);
1842
- return { kind: "result", resultIndex: i, rowNumber, agentName: useResultsDirectly ? (r?.agent || `${fallbackLabel}-${rowNumber}`) : (d.chainAgents![i] || r?.agent || `${fallbackLabel}-${rowNumber}`) };
2152
+ const fallbackAgent = useResultsDirectly ? (r?.agent || `${fallbackLabel}-${rowNumber}`) : (d.chainAgents![i] || r?.agent || `${fallbackLabel}-${rowNumber}`);
2153
+ return { kind: "result", resultIndex: i, rowNumber, agentName: r?.sessionName?.trim() || fallbackAgent };
1843
2154
  });
1844
2155
  for (const entry of renderEntries) {
1845
2156
  if (entry.kind === "placeholder") {
@@ -1872,6 +2183,10 @@ function renderMultiCompact(d: Details, theme: Theme, layout: MainWindowRenderLa
1872
2183
  const rowModelDisplay = modelThinkingBadge(theme, r.model ?? rowProgressModel?.model, r.thinking ?? rowProgressModel?.thinking);
1873
2184
  const line = `${glyph} ${stepLabel}: ${themeBold(theme, agentName)}${contextModeBadge(theme, r.context)}${rowModelDisplay}${stepStats ? ` ${theme.fg("dim", "·")} ${stepStats}` : ""}${pendingLabel}`;
1874
2185
  c.addChild(new Text(truncLine(`${rowIndent}${line}`, width), 0, 0));
2186
+ if (rRunning || rPending) {
2187
+ const task = compactTaskText(r.task, workflowLabelForResult(d, i));
2188
+ if (task) c.addChild(new Text(truncLine(theme.fg("dim", `${detailIndent}task: ${task}`), width), 0, 0));
2189
+ }
1875
2190
  if (rRunning && rProg && "status" in rProg) {
1876
2191
  const liveProgress = rProg as AgentProgress;
1877
2192
  const activity = compactCurrentActivity(liveProgress);
@@ -1917,7 +2232,8 @@ export function renderSubagentSummary(
1917
2232
  const failed = result.isError === true
1918
2233
  || results.some((entry) => !hasTerminalResultFlag(entry) && entry.exitCode !== 0 && !isResultRunning(entry))
1919
2234
  || Boolean(details && workflowGraphHasStatus(details, ["failed"]));
1920
- const state = running ? "running" : failed ? "failed" : stopped ? "stopped" : paused ? "paused" : "completed";
2235
+ const partial = Boolean(details && workflowGraphHasStatus(details, ["partial"]));
2236
+ const state = running ? "running" : failed ? "failed" : stopped ? "stopped" : paused ? "paused" : partial ? "partial" : "completed";
1921
2237
  const glyph = state === "running"
1922
2238
  ? theme.fg("accent", STATIC_RUNNING_GLYPH)
1923
2239
  : state === "completed"
@@ -1926,7 +2242,7 @@ export function renderSubagentSummary(
1926
2242
  ? theme.fg("error", "✗")
1927
2243
  : theme.fg("warning", "■");
1928
2244
  const label = details?.mode === "single" && results.length === 1
1929
- ? results[0]?.agent || "subagent"
2245
+ ? childDisplayName(results[0])
1930
2246
  : details?.mode || "subagent";
1931
2247
  return new Text(
1932
2248
  truncLine(`${glyph} ${theme.fg("toolTitle", theme.bold(label))} ${theme.fg("dim", "·")} ${theme.fg(state === "failed" ? "error" : state === "completed" ? "success" : state === "running" ? "accent" : "warning", state)}`, getTermWidth() - 4),
@@ -1950,7 +2266,7 @@ export function renderSubagentResult(
1950
2266
  const compact = (component: Component): Component => capCompactMainWindowResult(component, layout, theme, !options.expanded);
1951
2267
  const d = result.details;
1952
2268
  if (d?.mode === "workflow" && d.chatProgress?.mode === "live-card" && d.workflow?.value === undefined && (!result.isError || (d.workflow?.trace.length ?? 0) > 0)) {
1953
- return compact(renderWorkflowChatProgress(d, result, theme, options.expanded ? resolveMainWindowRenderLayout() : layout, frame));
2269
+ return compact(renderWorkflowChatProgress(d, result, theme, options.expanded ? resolveMainWindowRenderLayout() : layout, frame, options.expanded));
1954
2270
  }
1955
2271
  if (!d || !d.results.length) {
1956
2272
  const t = result.content[0];
@@ -1961,9 +2277,12 @@ export function renderSubagentResult(
1961
2277
  if (d && !options.expanded && !result.isError) {
1962
2278
  const lines = text.split(/\r?\n/);
1963
2279
  const firstNonEmptyLine = lines.find((line) => line.trim())?.trim() || "(no output)";
2280
+ const compactLine = d.mode === "workflow" && d.preflight
2281
+ ? formatWorkflowPreflightPlanSummary(d.preflight)
2282
+ : firstNonEmptyLine;
1964
2283
  const c = new Container();
1965
2284
  const detailIndent = mainWindowIndent(layout, 1);
1966
- c.addChild(new Text(truncLine(`${contextPrefix}${firstNonEmptyLine} · ${lines.length} lines`, width), 0, 0));
2285
+ c.addChild(new Text(truncLine(`${contextPrefix}${compactLine} · ${lines.length} lines`, width), 0, 0));
1967
2286
  c.addChild(new Text(truncLine(theme.fg("accent", `${detailIndent}Press ${liveDetailKeyText()} for full output`), width), 0, 0));
1968
2287
  return compact(c);
1969
2288
  }
@@ -1996,7 +2315,7 @@ export function renderSubagentResult(
1996
2315
  const fit = (text: string) => expanded ? text : truncLine(text, w);
1997
2316
  const toolCallLines = getToolCallLines(r, expanded);
1998
2317
  const c = new Container();
1999
- c.addChild(new Text(fit(`${presentation.glyph} ${theme.fg("toolTitle", theme.bold(r.agent))}${contextBadge}${progressInfo} ${theme.fg("dim", "·")} ${presentation.label}`), 0, 0));
2318
+ c.addChild(new Text(fit(`${presentation.glyph} ${theme.fg("toolTitle", theme.bold(childDisplayName(r)))}${contextBadge}${progressInfo} ${theme.fg("dim", "·")} ${presentation.label}`), 0, 0));
2000
2319
  c.addChild(new Spacer(1));
2001
2320
  const taskMaxLen = Math.max(20, w - 8);
2002
2321
  const taskPreview = expanded || r.task.length <= taskMaxLen
@@ -2084,6 +2403,7 @@ export function renderSubagentResult(
2084
2403
  || workflowGraphHasStatus(d, ["failed"]);
2085
2404
  const paused = d.results.some((r) => r.interrupted)
2086
2405
  || workflowGraphHasStatus(d, ["paused"]);
2406
+ const partial = workflowGraphHasStatus(d, ["partial"]);
2087
2407
  const completedWithoutOutput = d.results.some((r) =>
2088
2408
  !hasTerminalResultFlag(r)
2089
2409
  && r.exitCode === 0
@@ -2096,6 +2416,7 @@ export function renderSubagentResult(
2096
2416
  stopped,
2097
2417
  interrupted: paused,
2098
2418
  failed,
2419
+ partial,
2099
2420
  completedWithoutOutput,
2100
2421
  frame,
2101
2422
  }), theme);
@@ -2135,6 +2456,7 @@ export function renderSubagentResult(
2135
2456
  ? d.chainAgents
2136
2457
  .map((agent, i) => {
2137
2458
  const result = d.results[i];
2459
+ const displayName = result?.sessionName?.trim() || agent;
2138
2460
  const isCurrent = i === (d.currentStepIndex ?? d.results.length);
2139
2461
  const stepPresentation = result
2140
2462
  ? styledResultPresentation(resultPresentation(result, getSingleResultOutput(result), isCurrent && hasRunning && !hasTerminalResultFlag(result)), theme)
@@ -2142,7 +2464,7 @@ export function renderSubagentResult(
2142
2464
  const stepStatus = stepPresentation
2143
2465
  ? `${stepPresentation.glyph} ${stepPresentation.label}`
2144
2466
  : theme.fg("dim", "◦ pending");
2145
- return `${stepStatus} ${agent}${contextModeBadge(theme, result?.context)}`;
2467
+ return `${stepStatus} ${displayName}${contextModeBadge(theme, result?.context)}`;
2146
2468
  })
2147
2469
  .join(theme.fg("dim", " → "))
2148
2470
  : null;
@@ -2169,7 +2491,8 @@ export function renderSubagentResult(
2169
2491
  const i = displayStart + offset;
2170
2492
  const r = d.results[i];
2171
2493
  const rowNumber = multiLabel.showActiveGroupOnly ? (i - multiLabel.groupStartIndex + 1) : (i + 1);
2172
- return { kind: "result", resultIndex: i, rowNumber, agentName: useResultsDirectly ? (r?.agent || `step-${rowNumber}`) : (d.chainAgents![i] || r?.agent || `step-${rowNumber}`) };
2494
+ const fallbackAgent = useResultsDirectly ? (r?.agent || `step-${rowNumber}`) : (d.chainAgents![i] || r?.agent || `step-${rowNumber}`);
2495
+ return { kind: "result", resultIndex: i, rowNumber, agentName: r?.sessionName?.trim() || fallbackAgent };
2173
2496
  });
2174
2497
 
2175
2498
  c.addChild(new Spacer(1));
@@ -2209,8 +2532,8 @@ export function renderSubagentResult(
2209
2532
  const stepLabel = entry.rowLabel ?? resultRowLabel(multiLabel, i, stepNumber);
2210
2533
  const contextBadge = contextModeBadge(theme, r.context);
2211
2534
  const stepHeader = rRunning
2212
- ? `${rowPresentation.glyph} ${stepLabel}: ${theme.bold(theme.fg("warning", r.agent))}${contextBadge}${modelDisplay}${stats} ${theme.fg("dim", "·")} ${rowPresentation.label}`
2213
- : `${rowPresentation.glyph} ${stepLabel}: ${theme.bold(r.agent)}${contextBadge}${modelDisplay}${stats} ${theme.fg("dim", "·")} ${rowPresentation.label}`;
2535
+ ? `${rowPresentation.glyph} ${stepLabel}: ${theme.bold(theme.fg("warning", childDisplayName(r)))}${contextBadge}${modelDisplay}${stats} ${theme.fg("dim", "·")} ${rowPresentation.label}`
2536
+ : `${rowPresentation.glyph} ${stepLabel}: ${theme.bold(childDisplayName(r))}${contextBadge}${modelDisplay}${stats} ${theme.fg("dim", "·")} ${rowPresentation.label}`;
2214
2537
  const toolCallLines = getToolCallLines(r, expanded);
2215
2538
  c.addChild(new Text(fit(stepHeader), 0, 0));
2216
2539