@selesai/code 0.13.0 → 0.13.2

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 (463) hide show
  1. package/CHANGELOG.md +22 -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/extensions/package.json +1 -2
  9. package/dist/extensions/pi-hermes-memory/CHANGELOG.md +371 -0
  10. package/dist/extensions/pi-hermes-memory/LICENSE +21 -0
  11. package/dist/extensions/pi-hermes-memory/README.md +643 -0
  12. package/dist/extensions/pi-hermes-memory/docs/0.1/TASKS.md +197 -0
  13. package/dist/extensions/pi-hermes-memory/docs/0.2/PLAN.md +290 -0
  14. package/dist/extensions/pi-hermes-memory/docs/0.2/TASKS.md +134 -0
  15. package/dist/extensions/pi-hermes-memory/docs/0.2/TEST-PLAN.md +216 -0
  16. package/dist/extensions/pi-hermes-memory/docs/0.3/PLAN.md +330 -0
  17. package/dist/extensions/pi-hermes-memory/docs/0.3/TASKS.md +125 -0
  18. package/dist/extensions/pi-hermes-memory/docs/0.4/PLAN.md +160 -0
  19. package/dist/extensions/pi-hermes-memory/docs/0.4/TASKS.md +113 -0
  20. package/dist/extensions/pi-hermes-memory/docs/0.6/CHANGELOG.md +57 -0
  21. package/dist/extensions/pi-hermes-memory/docs/0.6/PLAN.md +202 -0
  22. package/dist/extensions/pi-hermes-memory/docs/0.6/TASKS.md +144 -0
  23. package/dist/extensions/pi-hermes-memory/docs/0.7/PLAN.md +349 -0
  24. package/dist/extensions/pi-hermes-memory/docs/0.7/TASKS.md +110 -0
  25. package/dist/extensions/pi-hermes-memory/docs/PUBLISHING.md +149 -0
  26. package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +468 -0
  27. package/dist/extensions/pi-hermes-memory/docs/images/memory-architecture.svg +1 -0
  28. package/dist/extensions/pi-hermes-memory/docs/images/pi-logo.svg +22 -0
  29. package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.png +0 -0
  30. package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.svg +19 -0
  31. package/dist/extensions/pi-hermes-memory/docs/images/security-flow.svg +1 -0
  32. package/dist/extensions/pi-hermes-memory/docs/images/session-lifecycle.svg +1 -0
  33. package/dist/extensions/pi-hermes-memory/docs/images/source-architecture.svg +1 -0
  34. package/dist/extensions/pi-hermes-memory/docs/mermaid/memory-architecture.mmd +49 -0
  35. package/dist/extensions/pi-hermes-memory/docs/mermaid/security-flow.mmd +40 -0
  36. package/dist/extensions/pi-hermes-memory/docs/mermaid/session-lifecycle.mmd +56 -0
  37. package/dist/extensions/pi-hermes-memory/docs/mermaid/source-architecture.mmd +54 -0
  38. package/dist/extensions/pi-hermes-memory/package-lock.json +3799 -0
  39. package/dist/extensions/pi-hermes-memory/package.json +66 -0
  40. package/dist/extensions/pi-hermes-memory/scripts/check-min-sdk.mjs +99 -0
  41. package/dist/extensions/pi-hermes-memory/scripts/ensure-dev.mjs +57 -0
  42. package/dist/extensions/pi-hermes-memory/src/auto-consolidation-warning.ts +6 -0
  43. package/dist/extensions/pi-hermes-memory/src/config.ts +178 -0
  44. package/dist/extensions/pi-hermes-memory/src/constants.ts +424 -0
  45. package/dist/extensions/pi-hermes-memory/src/extension-root-migration.ts +639 -0
  46. package/dist/extensions/pi-hermes-memory/src/handlers/auto-consolidate.ts +401 -0
  47. package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +297 -0
  48. package/dist/extensions/pi-hermes-memory/src/handlers/child-process-watchdog.mjs +90 -0
  49. package/dist/extensions/pi-hermes-memory/src/handlers/correction-detector.ts +300 -0
  50. package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +86 -0
  51. package/dist/extensions/pi-hermes-memory/src/handlers/insights.ts +78 -0
  52. package/dist/extensions/pi-hermes-memory/src/handlers/interview.ts +37 -0
  53. package/dist/extensions/pi-hermes-memory/src/handlers/learn-memory.ts +186 -0
  54. package/dist/extensions/pi-hermes-memory/src/handlers/message-parts.ts +27 -0
  55. package/dist/extensions/pi-hermes-memory/src/handlers/pi-child-process.ts +485 -0
  56. package/dist/extensions/pi-hermes-memory/src/handlers/preview-context.ts +105 -0
  57. package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +506 -0
  58. package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +145 -0
  59. package/dist/extensions/pi-hermes-memory/src/handlers/session-flush.ts +151 -0
  60. package/dist/extensions/pi-hermes-memory/src/handlers/session-live-index.ts +94 -0
  61. package/dist/extensions/pi-hermes-memory/src/handlers/skills-command.ts +1334 -0
  62. package/dist/extensions/pi-hermes-memory/src/handlers/standing-pin.ts +111 -0
  63. package/dist/extensions/pi-hermes-memory/src/handlers/switch-project.ts +75 -0
  64. package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +266 -0
  65. package/dist/extensions/pi-hermes-memory/src/index.ts +378 -0
  66. package/dist/extensions/pi-hermes-memory/src/lifecycle-timing.ts +54 -0
  67. package/dist/extensions/pi-hermes-memory/src/paths.ts +61 -0
  68. package/dist/extensions/pi-hermes-memory/src/project-context.ts +13 -0
  69. package/dist/extensions/pi-hermes-memory/src/project-memory-migration.ts +93 -0
  70. package/dist/extensions/pi-hermes-memory/src/project.ts +157 -0
  71. package/dist/extensions/pi-hermes-memory/src/prompt-context.ts +55 -0
  72. package/dist/extensions/pi-hermes-memory/src/store/atomic-lock-coordinator.ts +375 -0
  73. package/dist/extensions/pi-hermes-memory/src/store/canonical-storage-path.ts +54 -0
  74. package/dist/extensions/pi-hermes-memory/src/store/content-scanner.ts +101 -0
  75. package/dist/extensions/pi-hermes-memory/src/store/db.ts +1180 -0
  76. package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +101 -0
  77. package/dist/extensions/pi-hermes-memory/src/store/markdown-mutation-lock.ts +38 -0
  78. package/dist/extensions/pi-hermes-memory/src/store/memory-lookup.ts +24 -0
  79. package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +1191 -0
  80. package/dist/extensions/pi-hermes-memory/src/store/recovery-maintenance.ts +66 -0
  81. package/dist/extensions/pi-hermes-memory/src/store/schema.ts +118 -0
  82. package/dist/extensions/pi-hermes-memory/src/store/session-anchor-search.ts +472 -0
  83. package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +511 -0
  84. package/dist/extensions/pi-hermes-memory/src/store/session-parser.ts +213 -0
  85. package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +234 -0
  86. package/dist/extensions/pi-hermes-memory/src/store/skill-store.ts +950 -0
  87. package/dist/extensions/pi-hermes-memory/src/store/skill-utils.ts +133 -0
  88. package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +1002 -0
  89. package/dist/extensions/pi-hermes-memory/src/store/sqlite-native.ts +241 -0
  90. package/dist/extensions/pi-hermes-memory/src/store/standing-instructions.ts +247 -0
  91. package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +95 -0
  92. package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +469 -0
  93. package/dist/extensions/pi-hermes-memory/src/tools/session-search-tool.ts +246 -0
  94. package/dist/extensions/pi-hermes-memory/src/tools/shared-output-view.ts +170 -0
  95. package/dist/extensions/pi-hermes-memory/src/tools/skill-tool.ts +333 -0
  96. package/dist/extensions/pi-hermes-memory/src/tools/tool-result-views.ts +105 -0
  97. package/dist/extensions/pi-hermes-memory/src/types.ts +214 -0
  98. package/dist/extensions/pi-hermes-memory/tests/config.test.ts +434 -0
  99. package/dist/extensions/pi-hermes-memory/tests/extension-root-migration.test.ts +368 -0
  100. package/dist/extensions/pi-hermes-memory/tests/handlers/auto-consolidate.test.ts +984 -0
  101. package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +950 -0
  102. package/dist/extensions/pi-hermes-memory/tests/handlers/correction-detector.test.ts +671 -0
  103. package/dist/extensions/pi-hermes-memory/tests/handlers/insights.test.ts +157 -0
  104. package/dist/extensions/pi-hermes-memory/tests/handlers/interview.test.ts +127 -0
  105. package/dist/extensions/pi-hermes-memory/tests/handlers/pi-child-process.test.ts +905 -0
  106. package/dist/extensions/pi-hermes-memory/tests/handlers/preview-context.test.ts +152 -0
  107. package/dist/extensions/pi-hermes-memory/tests/handlers/prompt-context.test.ts +166 -0
  108. package/dist/extensions/pi-hermes-memory/tests/handlers/resources-discover.test.ts +71 -0
  109. package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +614 -0
  110. package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +192 -0
  111. package/dist/extensions/pi-hermes-memory/tests/handlers/session-flush.test.ts +677 -0
  112. package/dist/extensions/pi-hermes-memory/tests/handlers/session-live-index.test.ts +225 -0
  113. package/dist/extensions/pi-hermes-memory/tests/handlers/skills-command.test.ts +827 -0
  114. package/dist/extensions/pi-hermes-memory/tests/handlers/standing-pin.test.ts +134 -0
  115. package/dist/extensions/pi-hermes-memory/tests/handlers/sync-markdown-memories.test.ts +491 -0
  116. package/dist/extensions/pi-hermes-memory/tests/handlers/system-prompt.test.ts +199 -0
  117. package/dist/extensions/pi-hermes-memory/tests/handlers/thinking-max.test.ts +64 -0
  118. package/dist/extensions/pi-hermes-memory/tests/index.test.ts +30 -0
  119. package/dist/extensions/pi-hermes-memory/tests/integration/flow.test.ts +126 -0
  120. package/dist/extensions/pi-hermes-memory/tests/lifecycle-timing.test.ts +76 -0
  121. package/dist/extensions/pi-hermes-memory/tests/paths.test.ts +23 -0
  122. package/dist/extensions/pi-hermes-memory/tests/project-memory-migration.test.ts +80 -0
  123. package/dist/extensions/pi-hermes-memory/tests/project-rebinding.test.ts +115 -0
  124. package/dist/extensions/pi-hermes-memory/tests/project.test.ts +120 -0
  125. package/dist/extensions/pi-hermes-memory/tests/run-all-timeout.test.ts +107 -0
  126. package/dist/extensions/pi-hermes-memory/tests/run-all.sh +45 -0
  127. package/dist/extensions/pi-hermes-memory/tests/store/atomic-lock-coordinator.test.ts +381 -0
  128. package/dist/extensions/pi-hermes-memory/tests/store/content-scanner.test.ts +388 -0
  129. package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +1046 -0
  130. package/dist/extensions/pi-hermes-memory/tests/store/markdown-mutation-lock.test.ts +34 -0
  131. package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +2150 -0
  132. package/dist/extensions/pi-hermes-memory/tests/store/recovery-maintenance.test.ts +170 -0
  133. package/dist/extensions/pi-hermes-memory/tests/store/session-anchor-search.test.ts +210 -0
  134. package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +643 -0
  135. package/dist/extensions/pi-hermes-memory/tests/store/session-parser.test.ts +282 -0
  136. package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +287 -0
  137. package/dist/extensions/pi-hermes-memory/tests/store/skill-store.test.ts +678 -0
  138. package/dist/extensions/pi-hermes-memory/tests/store/skill-utils.test.ts +21 -0
  139. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-lazy-load.test.ts +78 -0
  140. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +543 -0
  141. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +164 -0
  142. package/dist/extensions/pi-hermes-memory/tests/store/standing-instructions.test.ts +171 -0
  143. package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +84 -0
  144. package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +709 -0
  145. package/dist/extensions/pi-hermes-memory/tests/tools/session-search-tool.test.ts +345 -0
  146. package/dist/extensions/pi-hermes-memory/tests/tools/shared-output-view.test.ts +362 -0
  147. package/dist/extensions/pi-hermes-memory/tests/tools/skill-tool.test.ts +478 -0
  148. package/dist/extensions/pi-hermes-memory/tests/tools/tool-result-renderer-wiring.test.ts +40 -0
  149. package/dist/extensions/pi-hermes-memory/tsconfig.json +19 -0
  150. package/dist/extensions/pi-rewind-hook/README.md +4 -1
  151. package/dist/extensions/pi-rewind-hook/index.ts +151 -21
  152. package/dist/extensions/pi-rewind-hook/package.json +5 -3
  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 -7
  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 +136 -6
  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/modes/interactive/interactive-mode.js +7 -7
  455. package/dist/skills/workflow/SKILL.md +65 -50
  456. package/package.json +112 -110
  457. package/dist/extensions/enable-readonly-tools.test.ts +0 -63
  458. package/dist/extensions/enable-readonly-tools.ts +0 -24
  459. package/dist/extensions/model-prompt-injector/config.json +0 -16
  460. package/dist/extensions/model-prompt-injector/index.test.ts +0 -102
  461. package/dist/extensions/model-prompt-injector/index.ts +0 -148
  462. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +0 -98
  463. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +0 -250
@@ -2,6 +2,7 @@ import type { AgentToolResult } from "@earendil-works/pi-agent-core";
2
2
  import type { Message } from "@earendil-works/pi-ai";
3
3
  import type { SubagentParamsLike } from "../runs/foreground/subagent-executor.ts";
4
4
  import { previewSimpleWorkflowRun } from "../workflows/scripted-workflow.ts";
5
+ import { deriveChildSessionName } from "../shared/child-session-name.ts";
5
6
  import type { SlashSubagentResponse, SlashSubagentUpdate } from "./slash-bridge.ts";
6
7
  import { type Details, type SingleResult, type Usage, SLASH_RESULT_TYPE } from "../shared/types.ts";
7
8
 
@@ -54,9 +55,11 @@ function createPlaceholderResult(
54
55
  status: "pending" | "running",
55
56
  index: number,
56
57
  ): SingleResult {
58
+ const sessionName = deriveChildSessionName({ agent, task });
57
59
  return {
58
60
  agent,
59
61
  task,
62
+ ...(sessionName ? { sessionName } : {}),
60
63
  index,
61
64
  exitCode: 0,
62
65
  messages: EMPTY_MESSAGES,
@@ -64,6 +67,7 @@ function createPlaceholderResult(
64
67
  progress: {
65
68
  index,
66
69
  agent,
70
+ ...(sessionName ? { sessionName } : {}),
67
71
  status,
68
72
  task,
69
73
  recentTools: [],
@@ -84,17 +88,21 @@ function buildParallelInitialResult(params: SubagentParamsLike): AgentToolResult
84
88
  ...(params.async ? { background: true } : {}),
85
89
  ...(params.context === "fresh" || params.context === "fork" ? { context: params.context } : {}),
86
90
  results: tasks.map((task, index) => createPlaceholderResult(task.agent, task.task, "running", index)),
87
- progress: tasks.map((task, index) => ({
88
- index,
89
- agent: task.agent,
90
- status: "running" as const,
91
- task: task.task,
92
- recentTools: [],
93
- recentOutput: [],
94
- toolCount: 0,
95
- tokens: 0,
96
- durationMs: 0,
97
- })),
91
+ progress: tasks.map((task, index) => {
92
+ const sessionName = deriveChildSessionName({ agent: task.agent, task: task.task });
93
+ return {
94
+ index,
95
+ agent: task.agent,
96
+ ...(sessionName ? { sessionName } : {}),
97
+ status: "running" as const,
98
+ task: task.task,
99
+ recentTools: [],
100
+ recentOutput: [],
101
+ toolCount: 0,
102
+ tokens: 0,
103
+ durationMs: 0,
104
+ };
105
+ }),
98
106
  },
99
107
  };
100
108
  }
@@ -143,6 +151,7 @@ function buildChainInitialResult(params: SubagentParamsLike): AgentToolResult<De
143
151
  progress: results.map((result, index) => ({
144
152
  index,
145
153
  agent: result.agent,
154
+ ...(result.sessionName ? { sessionName: result.sessionName } : {}),
146
155
  status: index === 0 ? "running" as const : "pending" as const,
147
156
  task: result.task,
148
157
  recentTools: [],
@@ -162,6 +171,7 @@ function buildSingleInitialResult(params: SubagentParamsLike): AgentToolResult<D
162
171
  const preview = previewSimpleWorkflowRun(params.workflowScript) ?? {};
163
172
  const agent = params.agent ?? preview.agent ?? "subagent";
164
173
  const task = params.task ?? preview.task ?? "";
174
+ const sessionName = deriveChildSessionName({ agent, task });
165
175
  return {
166
176
  content: [{ type: "text", text: task }],
167
177
  details: {
@@ -172,6 +182,7 @@ function buildSingleInitialResult(params: SubagentParamsLike): AgentToolResult<D
172
182
  progress: [{
173
183
  index: 0,
174
184
  agent,
185
+ ...(sessionName ? { sessionName } : {}),
175
186
  status: "running",
176
187
  task,
177
188
  recentTools: [],
@@ -89,6 +89,7 @@ function buildBuiltinBase(agent: AgentConfig): BuiltinAgentOverrideBase {
89
89
  ...(agent.thinking !== undefined ? { thinking: agent.thinking } : {}),
90
90
  systemPromptMode: agent.systemPromptMode,
91
91
  inheritProjectContext: agent.inheritProjectContext,
92
+ inheritGlobalContext: agent.inheritGlobalContext,
92
93
  inheritSkills: agent.inheritSkills,
93
94
  ...(agent.defaultContext !== undefined ? { defaultContext: agent.defaultContext } : {}),
94
95
  ...(agent.acceptanceRole !== undefined ? { acceptanceRole: agent.acceptanceRole } : {}),
@@ -98,6 +99,7 @@ function buildBuiltinBase(agent: AgentConfig): BuiltinAgentOverrideBase {
98
99
  ...(agent.tools !== undefined ? { tools: [...agent.tools] } : {}),
99
100
  ...(agent.mcpDirectTools !== undefined ? { mcpDirectTools: [...agent.mcpDirectTools] } : {}),
100
101
  ...(agent.subagentOnlyExtensions !== undefined ? { subagentOnlyExtensions: [...agent.subagentOnlyExtensions] } : {}),
102
+ ...(agent.mutationTools !== undefined ? { mutationTools: [...agent.mutationTools] } : {}),
101
103
  ...(agent.completionGuard !== undefined ? { completionGuard: agent.completionGuard } : {}),
102
104
  ...(agent.toolBudget !== undefined ? { toolBudget: agent.toolBudget } : {}),
103
105
  };
@@ -189,6 +191,7 @@ function metadataFor(agent: AgentConfig): string {
189
191
  if (agent.skills?.length) lines.push(`Skills: ${agent.skills.join(", ")}`);
190
192
  lines.push(`System prompt mode: ${agent.systemPromptMode}`);
191
193
  lines.push(`Inherit project context: ${agent.inheritProjectContext ? "true" : "false"}`);
194
+ lines.push(`Inherit global context: ${agent.inheritGlobalContext ? "true" : "false"}`);
192
195
  lines.push(`Inherit skills: ${agent.inheritSkills ? "true" : "false"}`);
193
196
  if (agent.defaultContext) lines.push(`Default context: ${agent.defaultContext}`);
194
197
  if (agent.output) lines.push(`Output: ${agent.output}`);
@@ -2,8 +2,11 @@ import type { ExtensionContext } from "@selesai/code";
2
2
  import { type EditorComponent, isKeyRelease, Key, matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
3
3
  import { snapshotExternalRuns } from "../api/external-runs.ts";
4
4
  import { formatModelThinking } from "../shared/formatters.ts";
5
- import type { AsyncJobState, AsyncJobStep, FleetViewPlacement, HerdrProjectPaneSnapshot, NestedRunSummary, NestedStepSummary, SubagentState } from "../shared/types.ts";
5
+ import type { AsyncJobState, AsyncJobStep, FleetViewPlacement, HerdrProjectPaneSnapshot, HostStepState, HostStepVerdict, NestedRunSummary, NestedStepSummary, SubagentState } from "../shared/types.ts";
6
+ import { projectAsyncWorkflowRows, type AsyncStatusWorkflowRow } from "../runs/shared/async-status-projection.ts";
6
7
  import { formatWorkflowJsonPreview } from "../workflows/scripted-workflow.ts";
8
+ import { hostStepReportName, hostStepVerdictLabel } from "../runs/shared/host-step-status.ts";
9
+ import { isStaleExtensionContextError } from "../shared/extension-context.ts";
7
10
 
8
11
  export const FLEET_STATUS_WIDGET_KEY = "subagent-fleet-status";
9
12
 
@@ -25,21 +28,12 @@ type FleetStatusEntry = {
25
28
  description?: string;
26
29
  startedAt: number;
27
30
  tokens: number;
31
+ window?: number;
28
32
  state: string;
29
33
  external?: true;
30
34
  projectPane?: HerdrProjectPaneSnapshot;
31
35
  nestedChildren?: NestedRunSummary[];
32
- workflowRows?: FleetWorkflowRow[];
33
- };
34
-
35
- type FleetWorkflowRow = {
36
- name: string;
37
- state: AsyncJobStep["status"];
38
- modelThinking?: string;
39
- activity?: string;
40
- startedAt?: number;
41
- tokens?: number;
42
- overflow?: number;
36
+ workflowRows?: AsyncStatusWorkflowRow[];
43
37
  };
44
38
 
45
39
  type FleetNestedRow = {
@@ -55,7 +49,7 @@ type FleetNestedRow = {
55
49
  type FleetTreeRow =
56
50
  | { kind: "owner"; entry: FleetStatusEntry }
57
51
  | { kind: "child"; entry: FleetStatusEntry; last: boolean }
58
- | { kind: "workflow"; ownerKey: string; row: FleetWorkflowRow; last: boolean }
52
+ | { kind: "workflow"; ownerKey: string; row: AsyncStatusWorkflowRow; last: boolean }
59
53
  | { kind: "nested"; ownerKey: string; row: FleetNestedRow; last: boolean };
60
54
 
61
55
  export interface FleetStatusOptions {
@@ -72,12 +66,15 @@ export function formatFleetElapsed(ms: number): string {
72
66
  return `${Math.max(0, Math.round(ms / 1000))}s`;
73
67
  }
74
68
 
75
- export function formatFleetTokens(count: number): string {
76
- let compact: string;
77
- if (count >= 1_000_000) compact = `${(count / 1_000_000).toFixed(1)}M`;
78
- else if (count >= 1_000) compact = `${(count / 1_000).toFixed(1)}k`;
79
- else compact = `${Math.max(0, Math.round(count))}`;
80
- return `↓ ${compact} tokens`;
69
+ export function formatFleetTokens(count: number, window?: number): string {
70
+ const compact = (value: number): string => value >= 1_000_000
71
+ ? `${(value / 1_000_000).toFixed(1)}M`
72
+ : value >= 1_000
73
+ ? `${(value / 1_000).toFixed(1)}k`
74
+ : `${Math.max(0, Math.round(value))}`;
75
+ return window !== undefined
76
+ ? `↓ ${compact(window)} window · ${compact(count)} spent`
77
+ : `↓ ${compact(count)} tokens`;
81
78
  }
82
79
 
83
80
  function rightAlign(left: string, right: string, width: number): string {
@@ -106,44 +103,12 @@ function nestedActivity(node: NestedRunSummary | NestedStepSummary): string | un
106
103
  return undefined;
107
104
  }
108
105
 
109
- function workflowStepActivity(step: AsyncJobStep): string | undefined {
110
- if (step.currentTool) return `tool ${step.currentTool}`;
111
- if (step.currentPath) return step.currentPath.split(/[\\/]/).at(-1);
112
- if (step.activityState === "needs_attention") return "needs attention";
113
- if (step.activityState === "active_long_running") return "long-running";
114
- if (step.turnCount !== undefined) return `${step.turnCount} turns`;
115
- if (step.toolCount !== undefined) return `${step.toolCount} tools`;
116
- return undefined;
117
- }
118
-
119
- function workflowStepName(step: AsyncJobStep, index: number): string {
120
- const key = step.workflowKey ?? `step ${index + 1}`;
121
- const label = step.label && step.label !== key ? ` · ${step.label}` : "";
122
- const phase = step.phase ? `${step.phase}: ` : "";
123
- return `${phase}${key}${label} (${step.agent})`;
124
- }
125
-
126
- function workflowFleetRows(steps: AsyncJobStep[] | undefined): FleetWorkflowRow[] {
127
- return (steps ?? []).map((step, index) => {
128
- const modelThinking = formatModelThinking(step.model, step.thinking) || undefined;
129
- const activity = workflowStepActivity(step);
130
- return {
131
- name: workflowStepName(step, index),
132
- state: step.status,
133
- ...(modelThinking ? { modelThinking } : {}),
134
- ...(activity ? { activity } : {}),
135
- ...(step.startedAt !== undefined ? { startedAt: step.startedAt } : {}),
136
- ...(step.tokens?.total !== undefined ? { tokens: step.tokens.total } : {}),
137
- };
138
- });
139
- }
140
-
141
- function visibleWorkflowRows(rows: FleetWorkflowRow[] | undefined, visibleLimit: number): FleetWorkflowRow[] {
106
+ function visibleWorkflowRows(rows: AsyncStatusWorkflowRow[] | undefined, visibleLimit: number): AsyncStatusWorkflowRow[] {
142
107
  if (!rows?.length) return [];
143
108
  if (rows.length <= visibleLimit) return rows;
144
109
  const selected = new Set<number>();
145
110
  for (const [index, row] of rows.entries()) {
146
- if (row.state !== "complete" && row.state !== "completed") selected.add(index);
111
+ if (!isWorkflowRowTerminal(row)) selected.add(index);
147
112
  if (selected.size >= visibleLimit) break;
148
113
  }
149
114
  for (let index = rows.length - 1; index >= 0 && selected.size < visibleLimit; index--) selected.add(index);
@@ -151,9 +116,14 @@ function visibleWorkflowRows(rows: FleetWorkflowRow[] | undefined, visibleLimit:
151
116
  return [{ name: `… +${rows.length - visible.length} hidden workflow steps`, state: "complete", overflow: rows.length - visible.length }, ...visible];
152
117
  }
153
118
 
154
- function nestedStatusGlyph(state: FleetNestedRow["state"], theme: Theme): string {
119
+ function isWorkflowRowTerminal(row: AsyncStatusWorkflowRow): boolean {
120
+ if (row.kind) return row.state === "done" || row.state === "cancelled" || row.state === "error";
121
+ return row.state === "complete" || row.state === "completed";
122
+ }
123
+
124
+ function nestedStatusGlyph(state: FleetNestedRow["state"] | "planned", theme: Theme): string {
155
125
  if (state === "running") return theme.fg("accent", "●");
156
- if (state === "queued" || state === "pending") return theme.fg("muted", "◦");
126
+ if (state === "queued" || state === "pending" || state === "planned") return theme.fg("muted", "◦");
157
127
  if (state === "complete" || state === "completed") return theme.fg("success", "✓");
158
128
  if (state === "failed" || state === "rejected") return theme.fg("error", "✗");
159
129
  return theme.fg("warning", "■");
@@ -272,19 +242,31 @@ function fleetTreeRows(entries: FleetStatusEntry[]): FleetTreeRow[] {
272
242
  return rows;
273
243
  }
274
244
 
275
- function isStaleExtensionContextError(error: unknown): boolean {
276
- // Pi currently exposes stale contexts as plain Errors without a stable code or subtype.
277
- return error instanceof Error
278
- && (error.message.includes("This extension ctx is stale")
279
- || error.message.includes("Extension context no longer active"));
280
- }
281
-
282
245
  function foregroundDescription(control: { parentWorkflowRunId?: string; workflowKey?: string }, description: string | undefined): string | undefined {
283
246
  if (!control.parentWorkflowRunId) return description;
284
247
  const workflow = `workflow child: ${control.parentWorkflowRunId}${control.workflowKey ? ` (${control.workflowKey})` : ""}`;
285
248
  return description ? `${workflow} · ${description}` : workflow;
286
249
  }
287
250
 
251
+ function workflowIdentityCandidates(step: Pick<AsyncJobStep, "workflowKey" | "runId">): string[] {
252
+ return [...new Set([step.workflowKey, step.runId].filter((value): value is string => typeof value === "string" && value.length > 0))];
253
+ }
254
+
255
+ function asyncJobIdentityCandidates(job: AsyncJobState): string[] {
256
+ return [...new Set([job.workflowKey, job.asyncId].filter((value): value is string => typeof value === "string" && value.length > 0))];
257
+ }
258
+
259
+ function linkedWorkflowParentKey(parentWorkflowRunId: string | undefined, activeWorkflowKeys: ReadonlySet<string>): string | undefined {
260
+ if (!parentWorkflowRunId) return undefined;
261
+ const parentKey = `async:${parentWorkflowRunId}`;
262
+ return activeWorkflowKeys.has(parentKey) ? parentKey : undefined;
263
+ }
264
+
265
+ function workflowStepsWithoutMaterializedChildren(steps: AsyncJobStep[] | undefined, materializedChildIds: ReadonlySet<string> | undefined): AsyncJobStep[] | undefined {
266
+ if (!steps?.length || !materializedChildIds?.size) return steps;
267
+ return steps.filter((step) => !workflowIdentityCandidates(step).some((identity) => materializedChildIds.has(identity)));
268
+ }
269
+
288
270
  function activeLeafAgentCount(entries: FleetStatusEntry[]): number {
289
271
  return entries.filter((entry) => !entry.workflowWrapper && !entry.surface).length;
290
272
  }
@@ -319,12 +301,30 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
319
301
  const activeWorkflowKeys = new Set([...state.asyncJobs.values()]
320
302
  .filter((job) => job.mode === "workflow" && isActiveState(job.status))
321
303
  .map((job) => `async:${job.asyncId}`));
304
+ const materializedChildrenByWorkflow = new Map<string, Set<string>>();
305
+ for (const job of state.asyncJobs.values()) {
306
+ if (!isActiveState(job.status) || !job.parentWorkflowRunId) continue;
307
+ const parentKey = linkedWorkflowParentKey(job.parentWorkflowRunId, activeWorkflowKeys);
308
+ if (!parentKey) continue;
309
+ const childIds = materializedChildrenByWorkflow.get(parentKey) ?? new Set<string>();
310
+ for (const identity of asyncJobIdentityCandidates(job)) childIds.add(identity);
311
+ materializedChildrenByWorkflow.set(parentKey, childIds);
312
+ }
322
313
  for (const control of state.foregroundControls.values()) {
323
- const parentKey = control.parentWorkflowRunId ? `async:${control.parentWorkflowRunId}` : undefined;
324
- const linkedParentKey = parentKey && activeWorkflowKeys.has(parentKey) ? parentKey : undefined;
314
+ const linkedParentKey = linkedWorkflowParentKey(control.parentWorkflowRunId, activeWorkflowKeys);
325
315
  if (control.activeChildren) {
316
+ const nestedChildren = control.nestedChildren ?? [];
317
+ const nestedChildrenByParentStep = new Map<number, NestedRunSummary[]>();
318
+ for (const nested of nestedChildren) {
319
+ if (nested.parentStepIndex === undefined) continue;
320
+ const children = nestedChildrenByParentStep.get(nested.parentStepIndex) ?? [];
321
+ children.push(nested);
322
+ nestedChildrenByParentStep.set(nested.parentStepIndex, children);
323
+ }
326
324
  for (const child of [...control.activeChildren.values()].sort((left, right) => left.index - right.index)) {
327
325
  const modelThinking = formatModelThinking(child.model, child.thinking) || undefined;
326
+ const childNestedChildren = nestedChildrenByParentStep.get(child.index)
327
+ ?? (control.activeChildren.size === 1 && nestedChildren.length ? nestedChildren : undefined);
328
328
  entries.push({
329
329
  key: `foreground-active:${control.runId}:${child.index}`,
330
330
  ...(linkedParentKey ? { parentKey: linkedParentKey } : {}),
@@ -333,10 +333,9 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
333
333
  description: foregroundDescription(control, child.description),
334
334
  startedAt: child.startedAt,
335
335
  tokens: child.tokens ?? 0,
336
+ ...(child.window !== undefined ? { window: child.window } : {}),
336
337
  state: "running",
337
- ...((control.nestedChildren?.filter((nested) => nested.parentStepIndex === child.index).length ?? 0) > 0
338
- ? { nestedChildren: control.nestedChildren!.filter((nested) => nested.parentStepIndex === child.index) }
339
- : control.activeChildren.size === 1 && control.nestedChildren?.length ? { nestedChildren: control.nestedChildren } : {}),
338
+ ...(childNestedChildren?.length ? { nestedChildren: childNestedChildren } : {}),
340
339
  });
341
340
  }
342
341
  continue;
@@ -350,6 +349,7 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
350
349
  description: foregroundDescription(control, control.description),
351
350
  startedAt: control.startedAt,
352
351
  tokens: control.tokens ?? 0,
352
+ ...(control.window !== undefined ? { window: control.window } : {}),
353
353
  state: "running",
354
354
  ...(control.nestedChildren?.length ? { nestedChildren: control.nestedChildren } : {}),
355
355
  });
@@ -358,17 +358,22 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
358
358
  for (const job of state.asyncJobs.values()) {
359
359
  if (!isActiveState(job.status)) continue;
360
360
  const startedAt = job.startedAt ?? job.updatedAt ?? Date.now();
361
+ const linkedParentKey = linkedWorkflowParentKey(job.parentWorkflowRunId, activeWorkflowKeys);
361
362
  if (job.mode === "workflow") {
362
363
  const latestEmit = job.workflow?.emits?.length ? formatWorkflowJsonPreview(job.workflow.emits.at(-1), 120) : undefined;
364
+ const workflowSteps = workflowStepsWithoutMaterializedChildren(job.steps, materializedChildrenByWorkflow.get(`async:${job.asyncId}`));
365
+ const workflowRows = projectAsyncWorkflowRows(workflowSteps, job.hostSteps, job.preflight);
363
366
  entries.push({
364
367
  key: `async:${job.asyncId}`,
368
+ ...(linkedParentKey ? { parentKey: linkedParentKey } : {}),
365
369
  workflowWrapper: true,
366
370
  agent: "workflow",
367
371
  description: latestEmit !== undefined ? `latest emit: ${latestEmit}` : job.description,
368
372
  startedAt,
369
373
  tokens: job.totalTokens?.total ?? 0,
374
+ ...(job.totalTokens?.window !== undefined ? { window: job.totalTokens.window } : {}),
370
375
  state: job.status,
371
- ...(job.steps?.length ? { workflowRows: workflowFleetRows(job.steps) } : {}),
376
+ ...(workflowRows.length ? { workflowRows } : {}),
372
377
  ...(job.nestedChildren?.length ? { nestedChildren: job.nestedChildren } : {}),
373
378
  });
374
379
  continue;
@@ -383,10 +388,12 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
383
388
  if (!steps?.length) {
384
389
  entries.push({
385
390
  key: `async:${job.asyncId}`,
391
+ ...(linkedParentKey ? { parentKey: linkedParentKey } : {}),
386
392
  agent: job.mode ?? "subagent",
387
393
  description: job.description,
388
394
  startedAt,
389
395
  tokens: job.totalTokens?.total ?? 0,
396
+ ...(job.totalTokens?.window !== undefined ? { window: job.totalTokens.window } : {}),
390
397
  state: job.status,
391
398
  ...(job.nestedChildren?.length ? { nestedChildren: job.nestedChildren } : {}),
392
399
  });
@@ -399,11 +406,15 @@ export function collectFleetStatusEntries(state: SubagentState): FleetStatusEntr
399
406
  const modelThinking = formatModelThinking(step.model, step.thinking) || undefined;
400
407
  entries.push({
401
408
  key: `async:${job.asyncId}:${index}`,
409
+ ...(linkedParentKey ? { parentKey: linkedParentKey } : {}),
402
410
  agent: step.label ? `${step.label} (${step.agent})` : step.agent,
403
411
  ...(modelThinking ? { modelThinking } : {}),
404
412
  description: step.description ?? job.description,
405
413
  startedAt: step.startedAt ?? startedAt,
406
414
  tokens: step.tokens?.total ?? (steps.length === 1 ? job.totalTokens?.total ?? 0 : 0),
415
+ ...((step.tokens?.window ?? (steps.length === 1 ? job.totalTokens?.window : undefined)) !== undefined
416
+ ? { window: step.tokens?.window ?? job.totalTokens?.window }
417
+ : {}),
407
418
  state: step.status,
408
419
  ...((step.children?.length ?? 0) > 0
409
420
  ? { nestedChildren: step.children }
@@ -611,6 +622,10 @@ export class SubagentFleetStatus {
611
622
  const workEntries = this.entries.filter((entry) => !entry.surface);
612
623
  const projectEntries = this.entries.filter((entry) => entry.surface === "project-pane");
613
624
  const tokens = workEntries.reduce((total, entry) => total + entry.tokens, 0);
625
+ const nativeEntries = workEntries.filter((entry) => !entry.external);
626
+ const window = nativeEntries.length > 0 && nativeEntries.every((entry) => entry.window !== undefined)
627
+ ? nativeEntries.reduce((total, entry) => total + entry.window!, 0)
628
+ : undefined;
614
629
  const capacity = this.state.activeAsyncCapacity;
615
630
  const hasNativeRows = workEntries.some((entry) => !entry.external);
616
631
  const showNativeSummary = hasNativeRows || Boolean(capacity?.used);
@@ -621,11 +636,15 @@ export class SubagentFleetStatus {
621
636
  const paneAttention = projectEntries.filter((entry) => entry.projectPane && projectPaneNeedsAttention(entry.projectPane)).length;
622
637
  const panes = projectEntries.length > 0 ? `${projectEntries.length} pane${projectEntries.length === 1 ? "" : "s"}${paneAttention ? ` (${paneAttention} ⚠)` : ""}` : "";
623
638
  const label = [agents, asyncRuns, panes].filter(Boolean).join(" · ");
624
- const detail = [showNativeSummary ? formatFleetTokens(tokens) : undefined, "↓/← to inspect"].filter(Boolean).join(" · ");
639
+ const detail = [showNativeSummary ? formatFleetTokens(tokens, window) : undefined, "↓/← to inspect"].filter(Boolean).join(" · ");
625
640
  return [truncateToWidth(` ${theme.fg("muted", label)}${label && detail ? " · " : ""}${theme.fg("dim", detail)}`, width)];
626
641
  }
627
642
  const roster = this.rosterKeys();
628
643
  const selectedIndex = Math.max(0, roster.indexOf(this.selectedKey));
644
+ const rosterIndexByKey = new Map<string, number>();
645
+ for (const [index, entry] of this.entries.entries()) {
646
+ if (!rosterIndexByKey.has(entry.key)) rosterIndexByKey.set(entry.key, index + 1);
647
+ }
629
648
  const lines = [truncateToWidth(` ${theme.fg("dim", "↑↓/jk select · enter inspect · esc back")}`, width), ""];
630
649
  lines.push(truncateToWidth(` ${this.bullet(0, selectedIndex, theme)} main`, width));
631
650
 
@@ -639,8 +658,8 @@ export class SubagentFleetStatus {
639
658
  for (let index = start; index < start + visibleCount; index++) {
640
659
  const row = tree[index]!;
641
660
  if (row.kind === "owner" || row.kind === "child") {
642
- const ownerIndex = this.entries.findIndex((entry) => entry.key === row.entry.key);
643
- lines.push(this.renderEntry(ownerIndex + 1, selectedIndex, row.entry, width, theme, row.kind === "child" ? (row.last ? "└─" : "├─") : undefined));
661
+ const rosterIndex = rosterIndexByKey.get(row.entry.key) ?? 0;
662
+ lines.push(this.renderEntry(rosterIndex, selectedIndex, row.entry, width, theme, row.kind === "child" ? (row.last ? "└─" : "├─") : undefined));
644
663
  } else if (row.kind === "workflow") {
645
664
  lines.push(this.renderWorkflowRow(row.row, row.last, width, theme));
646
665
  } else {
@@ -648,16 +667,16 @@ export class SubagentFleetStatus {
648
667
  }
649
668
  }
650
669
  if (hiddenBelow > 0) lines.push(rightAlign("", theme.fg("dim", `↓ ${hiddenBelow} more`), width));
651
- this.renderProjectPaneSection(lines, selectedIndex, width, theme);
670
+ this.renderProjectPaneSection(lines, selectedIndex, width, theme, rosterIndexByKey);
652
671
  return lines;
653
672
  }
654
673
 
655
- private renderProjectPaneSection(lines: string[], selectedIndex: number, width: number, theme: Theme): void {
674
+ private renderProjectPaneSection(lines: string[], selectedIndex: number, width: number, theme: Theme, rosterIndexByKey: ReadonlyMap<string, number>): void {
656
675
  const entries = this.entries.filter((entry) => entry.surface === "project-pane");
657
676
  if (!entries.length) return;
658
677
  lines.push("", truncateToWidth(` ${theme.fg("dim", "project panes")}`, width));
659
678
  for (const entry of entries) {
660
- const rosterIndex = this.entries.findIndex((candidate) => candidate.key === entry.key) + 1;
679
+ const rosterIndex = rosterIndexByKey.get(entry.key) ?? 0;
661
680
  lines.push(this.renderEntry(rosterIndex, selectedIndex, entry, width, theme));
662
681
  }
663
682
  }
@@ -670,7 +689,7 @@ export class SubagentFleetStatus {
670
689
  const elapsed = Date.now() - entry.startedAt;
671
690
  const rightText = entry.projectPane
672
691
  ? `${entry.projectPane.summary ?? "—"} · ${formatFleetElapsed(Date.now() - entry.projectPane.refreshedAt)} ago`
673
- : entry.external ? formatFleetElapsed(elapsed) : `${formatFleetElapsed(elapsed)} · ${formatFleetTokens(entry.tokens)}`;
692
+ : entry.external ? formatFleetElapsed(elapsed) : `${formatFleetElapsed(elapsed)} · ${formatFleetTokens(entry.tokens, entry.window)}`;
674
693
  const right = theme.fg("dim", rightText);
675
694
  return rightAlign(left, right, width);
676
695
  }
@@ -686,16 +705,50 @@ export class SubagentFleetStatus {
686
705
  return truncateToWidth(`${left}${theme.fg("dim", elapsed)}`, width);
687
706
  }
688
707
 
689
- private renderWorkflowRow(row: FleetWorkflowRow, last: boolean, width: number, theme: Theme): string {
708
+ private workflowRowGlyph(row: AsyncStatusWorkflowRow, theme: Theme): string {
709
+ if (!row.kind) return nestedStatusGlyph(row.state as FleetNestedRow["state"], theme);
710
+ const state = row.state as HostStepState;
711
+ if (state === "pending") return theme.fg("muted", "◦");
712
+ if (state === "running") return theme.fg("accent", "●");
713
+ if (state === "done") return row.verdict === "pass" ? theme.fg("success", "✓") : row.verdict === "fail" ? theme.fg("error", "✗") : theme.fg("warning", "■");
714
+ if (state === "error") return theme.fg("error", "✗");
715
+ return theme.fg("warning", "■");
716
+ }
717
+
718
+ private workflowRowStateLabel(row: AsyncStatusWorkflowRow, theme: Theme): string {
719
+ const state = row.kind ? hostStepVerdictLabel(row.state as HostStepState, row.verdict as HostStepVerdict | undefined) : row.state;
720
+ if (state === "running") return theme.fg("accent", state);
721
+ if (state === "pending" || state === "queued") return theme.fg("muted", state);
722
+ if (state === "pass" || state === "complete" || state === "completed") return theme.fg("success", state === "pass" ? "pass" : "complete");
723
+ if (state === "fail" || state === "failed" || state === "error") return theme.fg("error", state === "fail" ? "fail" : state);
724
+ return theme.fg("warning", state);
725
+ }
726
+
727
+ private renderWorkflowRow(row: AsyncStatusWorkflowRow, last: boolean, width: number, theme: Theme): string {
690
728
  const marker = last ? "└─" : "├─";
691
729
  const indent = " ";
692
730
  if (row.overflow !== undefined) return truncateToWidth(`${indent}${marker} ${theme.fg("dim", `+${row.overflow} hidden workflow steps`)}`, width);
693
731
  const modelThinking = row.modelThinking ? ` (${row.modelThinking})` : "";
694
732
  const activity = row.activity ? ` · ${row.activity}` : "";
695
- const left = `${indent}${marker} ${nestedStatusGlyph(row.state, theme)} ${theme.fg("muted", `${row.name}${modelThinking}`)} · ${row.state}${activity}`;
733
+ const kind = row.kind ? `${row.kind}: ` : "";
734
+ const hints = row.preflight ? [
735
+ row.preflight.mode ? `mode:${row.preflight.mode}` : undefined,
736
+ row.preflight.decision ? `decision:${row.preflight.decision}` : undefined,
737
+ row.preflight.claims?.length ? `claims:${row.preflight.claims.join(",")}` : undefined,
738
+ row.preflight.expectedOutput ? `expected:${row.preflight.expectedOutput}` : undefined,
739
+ row.preflight.independence ? `independence:${row.preflight.independence}` : undefined,
740
+ ].filter((value): value is string => Boolean(value)).join(" · ") : "";
741
+ const left = `${indent}${marker} ${this.workflowRowGlyph(row, theme)} ${theme.fg("muted", `${kind}${row.name}${modelThinking}`)} · ${this.workflowRowStateLabel(row, theme)}${activity}${hints ? ` · ${hints}` : ""}`;
696
742
  const details = [
697
743
  row.startedAt !== undefined ? formatFleetElapsed(Date.now() - row.startedAt) : undefined,
698
- row.tokens !== undefined ? formatFleetTokens(row.tokens) : undefined,
744
+ row.tokens !== undefined ? formatFleetTokens(row.tokens, row.window) : undefined,
745
+ row.provider ? `provider:${row.provider}` : undefined,
746
+ row.role ? `role:${row.role}` : undefined,
747
+ row.target,
748
+ row.detail,
749
+ row.reasonCode ? `reason:${row.reasonCode}` : undefined,
750
+ row.freshness?.stale ? "stale" : row.freshness?.observedRef ? `ref:${row.freshness.observedRef}` : undefined,
751
+ row.reportPath ? `out:${hostStepReportName(row.reportPath)}` : undefined,
699
752
  ].filter(Boolean).join(" · ");
700
753
  return truncateToWidth(`${left}${details ? theme.fg("dim", ` · ${details}`) : ""}`, width);
701
754
  }
@@ -750,12 +803,21 @@ export class SubagentFleetStatus {
750
803
  Math.round((now - entry.startedAt) / 1000),
751
804
  entry.tokens,
752
805
  visibleWorkflowRows(entry.workflowRows, entry.parentKey ? 2 : 4).map((row) => [
806
+ row.kind,
753
807
  row.name,
754
808
  row.state,
755
809
  row.modelThinking,
756
810
  row.activity,
757
811
  row.startedAt,
758
812
  row.tokens,
813
+ row.provider,
814
+ row.role,
815
+ row.verdict,
816
+ row.reasonCode,
817
+ row.detail,
818
+ row.target,
819
+ row.freshness,
820
+ row.reportPath,
759
821
  row.overflow,
760
822
  ]),
761
823
  nestedFleetRows(entry.nestedChildren, entry.parentKey ? 3 : 4).map((row) => [
@@ -790,7 +852,13 @@ export class SubagentFleetStatus {
790
852
 
791
853
  private clearWidget(): void {
792
854
  if (!this.widgetRegistered) return;
793
- this.ui?.setWidget(FLEET_STATUS_WIDGET_KEY, undefined);
855
+ try {
856
+ this.ui?.setWidget(FLEET_STATUS_WIDGET_KEY, undefined);
857
+ } catch (error) {
858
+ if (!isStaleExtensionContextError(error)) throw error;
859
+ this.clearUiRegistration();
860
+ return;
861
+ }
794
862
  this.widgetRegistered = false;
795
863
  this.tui = undefined;
796
864
  }
@@ -3,6 +3,7 @@ import * as path from "node:path";
3
3
  import { getLanguageFromPath, highlightCode, type ExtensionContext } from "@selesai/code";
4
4
  import { Markdown, truncateToWidth, visibleWidth, wrapTextWithAnsi, type MarkdownTheme } from "@earendil-works/pi-tui";
5
5
  import { safeTerminalText as safeDisplayText } from "../shared/display-text.ts";
6
+ import { isTrustedRecordedSessionFile } from "../shared/session-file-trust.ts";
6
7
 
7
8
  const DEFAULT_MAX_RECORDS = 240;
8
9
  const DEFAULT_MAX_BYTES = 2 * 1024 * 1024;
@@ -61,6 +62,8 @@ export interface FleetTranscript {
61
62
 
62
63
  interface FleetTranscriptReadOptions {
63
64
  trustedRoots: string[];
65
+ trustedFiles?: string[];
66
+ trustedFileRoot?: string;
64
67
  maxRecords?: number;
65
68
  maxBytes?: number;
66
69
  }
@@ -109,10 +112,13 @@ function isNotFoundError(error: unknown): boolean {
109
112
  return Boolean(objectValue(error)?.code === "ENOENT");
110
113
  }
111
114
 
112
- function validateTranscriptPath(filePath: string, trustedRoots: string[]): { resolvedPath?: string; warning?: string } {
113
- if (trustedRoots.length === 0) return { warning: `Transcript preview has no trusted root: ${filePath}` };
115
+ function validateTranscriptPath(filePath: string, trustedRoots: string[], trustedFiles: string[] = [], trustedFileRoot?: string): { resolvedPath?: string; warning?: string } {
116
+ if (trustedRoots.length === 0 && (!trustedFileRoot || trustedFiles.length === 0)) return { warning: `Transcript preview has no trusted root: ${filePath}` };
114
117
  const resolvedPath = path.resolve(filePath);
115
- if (!trustedRoots.some((root) => pathWithin(root, resolvedPath))) {
118
+ const recordedCandidate = trustedFileRoot
119
+ && pathWithin(trustedFileRoot, resolvedPath)
120
+ && trustedFiles.some((file) => path.resolve(file) === resolvedPath);
121
+ if (!trustedRoots.some((root) => pathWithin(root, resolvedPath)) && !recordedCandidate) {
116
122
  return { warning: `Transcript is outside trusted roots: ${filePath}` };
117
123
  }
118
124
  let stat: fs.Stats;
@@ -129,7 +135,7 @@ function validateTranscriptPath(filePath: string, trustedRoots: string[]): { res
129
135
  const realRoots = trustedRoots
130
136
  .filter((root) => fs.existsSync(root))
131
137
  .map((root) => fs.realpathSync(root));
132
- if (!realRoots.some((root) => pathWithin(root, realPath))) {
138
+ if (!realRoots.some((root) => pathWithin(root, realPath)) && !isTrustedRecordedSessionFile(realPath, trustedFiles, trustedFileRoot)) {
133
139
  return { warning: `Transcript resolves outside trusted roots: ${filePath}` };
134
140
  }
135
141
  return { resolvedPath: realPath };
@@ -335,7 +341,7 @@ function parseTranscriptLines(lines: string[], conversationStarted = false): { e
335
341
  }
336
342
 
337
343
  export function readFleetTranscript(filePath: string, options: FleetTranscriptReadOptions): FleetTranscript {
338
- const validated = validateTranscriptPath(filePath, options.trustedRoots);
344
+ const validated = validateTranscriptPath(filePath, options.trustedRoots, options.trustedFiles, options.trustedFileRoot);
339
345
  if (!validated.resolvedPath) {
340
346
  return { path: filePath, events: [], truncated: false, ...(validated.warning ? { warning: safeDisplayText(validated.warning) } : {}) };
341
347
  }