@selesai/code 0.13.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 (461) hide show
  1. package/CHANGELOG.md +12 -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/ascii.txt +9 -0
  9. package/dist/extensions/package.json +1 -2
  10. package/dist/extensions/pi-hermes-memory/CHANGELOG.md +371 -0
  11. package/dist/extensions/pi-hermes-memory/LICENSE +21 -0
  12. package/dist/extensions/pi-hermes-memory/README.md +643 -0
  13. package/dist/extensions/pi-hermes-memory/docs/0.1/TASKS.md +197 -0
  14. package/dist/extensions/pi-hermes-memory/docs/0.2/PLAN.md +290 -0
  15. package/dist/extensions/pi-hermes-memory/docs/0.2/TASKS.md +134 -0
  16. package/dist/extensions/pi-hermes-memory/docs/0.2/TEST-PLAN.md +216 -0
  17. package/dist/extensions/pi-hermes-memory/docs/0.3/PLAN.md +330 -0
  18. package/dist/extensions/pi-hermes-memory/docs/0.3/TASKS.md +125 -0
  19. package/dist/extensions/pi-hermes-memory/docs/0.4/PLAN.md +160 -0
  20. package/dist/extensions/pi-hermes-memory/docs/0.4/TASKS.md +113 -0
  21. package/dist/extensions/pi-hermes-memory/docs/0.6/CHANGELOG.md +57 -0
  22. package/dist/extensions/pi-hermes-memory/docs/0.6/PLAN.md +202 -0
  23. package/dist/extensions/pi-hermes-memory/docs/0.6/TASKS.md +144 -0
  24. package/dist/extensions/pi-hermes-memory/docs/0.7/PLAN.md +349 -0
  25. package/dist/extensions/pi-hermes-memory/docs/0.7/TASKS.md +110 -0
  26. package/dist/extensions/pi-hermes-memory/docs/PUBLISHING.md +149 -0
  27. package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +468 -0
  28. package/dist/extensions/pi-hermes-memory/docs/images/memory-architecture.svg +1 -0
  29. package/dist/extensions/pi-hermes-memory/docs/images/pi-logo.svg +22 -0
  30. package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.png +0 -0
  31. package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.svg +19 -0
  32. package/dist/extensions/pi-hermes-memory/docs/images/security-flow.svg +1 -0
  33. package/dist/extensions/pi-hermes-memory/docs/images/session-lifecycle.svg +1 -0
  34. package/dist/extensions/pi-hermes-memory/docs/images/source-architecture.svg +1 -0
  35. package/dist/extensions/pi-hermes-memory/docs/mermaid/memory-architecture.mmd +49 -0
  36. package/dist/extensions/pi-hermes-memory/docs/mermaid/security-flow.mmd +40 -0
  37. package/dist/extensions/pi-hermes-memory/docs/mermaid/session-lifecycle.mmd +56 -0
  38. package/dist/extensions/pi-hermes-memory/docs/mermaid/source-architecture.mmd +54 -0
  39. package/dist/extensions/pi-hermes-memory/package-lock.json +3799 -0
  40. package/dist/extensions/pi-hermes-memory/package.json +66 -0
  41. package/dist/extensions/pi-hermes-memory/scripts/check-min-sdk.mjs +99 -0
  42. package/dist/extensions/pi-hermes-memory/scripts/ensure-dev.mjs +57 -0
  43. package/dist/extensions/pi-hermes-memory/src/auto-consolidation-warning.ts +6 -0
  44. package/dist/extensions/pi-hermes-memory/src/config.ts +178 -0
  45. package/dist/extensions/pi-hermes-memory/src/constants.ts +424 -0
  46. package/dist/extensions/pi-hermes-memory/src/extension-root-migration.ts +639 -0
  47. package/dist/extensions/pi-hermes-memory/src/handlers/auto-consolidate.ts +401 -0
  48. package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +297 -0
  49. package/dist/extensions/pi-hermes-memory/src/handlers/child-process-watchdog.mjs +90 -0
  50. package/dist/extensions/pi-hermes-memory/src/handlers/correction-detector.ts +300 -0
  51. package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +86 -0
  52. package/dist/extensions/pi-hermes-memory/src/handlers/insights.ts +78 -0
  53. package/dist/extensions/pi-hermes-memory/src/handlers/interview.ts +37 -0
  54. package/dist/extensions/pi-hermes-memory/src/handlers/learn-memory.ts +186 -0
  55. package/dist/extensions/pi-hermes-memory/src/handlers/message-parts.ts +27 -0
  56. package/dist/extensions/pi-hermes-memory/src/handlers/pi-child-process.ts +485 -0
  57. package/dist/extensions/pi-hermes-memory/src/handlers/preview-context.ts +105 -0
  58. package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +506 -0
  59. package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +145 -0
  60. package/dist/extensions/pi-hermes-memory/src/handlers/session-flush.ts +151 -0
  61. package/dist/extensions/pi-hermes-memory/src/handlers/session-live-index.ts +94 -0
  62. package/dist/extensions/pi-hermes-memory/src/handlers/skills-command.ts +1334 -0
  63. package/dist/extensions/pi-hermes-memory/src/handlers/standing-pin.ts +111 -0
  64. package/dist/extensions/pi-hermes-memory/src/handlers/switch-project.ts +75 -0
  65. package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +266 -0
  66. package/dist/extensions/pi-hermes-memory/src/index.ts +378 -0
  67. package/dist/extensions/pi-hermes-memory/src/lifecycle-timing.ts +54 -0
  68. package/dist/extensions/pi-hermes-memory/src/paths.ts +61 -0
  69. package/dist/extensions/pi-hermes-memory/src/project-context.ts +13 -0
  70. package/dist/extensions/pi-hermes-memory/src/project-memory-migration.ts +93 -0
  71. package/dist/extensions/pi-hermes-memory/src/project.ts +157 -0
  72. package/dist/extensions/pi-hermes-memory/src/prompt-context.ts +55 -0
  73. package/dist/extensions/pi-hermes-memory/src/store/atomic-lock-coordinator.ts +375 -0
  74. package/dist/extensions/pi-hermes-memory/src/store/canonical-storage-path.ts +54 -0
  75. package/dist/extensions/pi-hermes-memory/src/store/content-scanner.ts +101 -0
  76. package/dist/extensions/pi-hermes-memory/src/store/db.ts +1180 -0
  77. package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +101 -0
  78. package/dist/extensions/pi-hermes-memory/src/store/markdown-mutation-lock.ts +38 -0
  79. package/dist/extensions/pi-hermes-memory/src/store/memory-lookup.ts +24 -0
  80. package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +1191 -0
  81. package/dist/extensions/pi-hermes-memory/src/store/recovery-maintenance.ts +66 -0
  82. package/dist/extensions/pi-hermes-memory/src/store/schema.ts +118 -0
  83. package/dist/extensions/pi-hermes-memory/src/store/session-anchor-search.ts +472 -0
  84. package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +511 -0
  85. package/dist/extensions/pi-hermes-memory/src/store/session-parser.ts +213 -0
  86. package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +234 -0
  87. package/dist/extensions/pi-hermes-memory/src/store/skill-store.ts +950 -0
  88. package/dist/extensions/pi-hermes-memory/src/store/skill-utils.ts +133 -0
  89. package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +1002 -0
  90. package/dist/extensions/pi-hermes-memory/src/store/sqlite-native.ts +241 -0
  91. package/dist/extensions/pi-hermes-memory/src/store/standing-instructions.ts +247 -0
  92. package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +95 -0
  93. package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +469 -0
  94. package/dist/extensions/pi-hermes-memory/src/tools/session-search-tool.ts +246 -0
  95. package/dist/extensions/pi-hermes-memory/src/tools/shared-output-view.ts +170 -0
  96. package/dist/extensions/pi-hermes-memory/src/tools/skill-tool.ts +333 -0
  97. package/dist/extensions/pi-hermes-memory/src/tools/tool-result-views.ts +105 -0
  98. package/dist/extensions/pi-hermes-memory/src/types.ts +214 -0
  99. package/dist/extensions/pi-hermes-memory/tests/config.test.ts +434 -0
  100. package/dist/extensions/pi-hermes-memory/tests/extension-root-migration.test.ts +368 -0
  101. package/dist/extensions/pi-hermes-memory/tests/handlers/auto-consolidate.test.ts +984 -0
  102. package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +950 -0
  103. package/dist/extensions/pi-hermes-memory/tests/handlers/correction-detector.test.ts +671 -0
  104. package/dist/extensions/pi-hermes-memory/tests/handlers/insights.test.ts +157 -0
  105. package/dist/extensions/pi-hermes-memory/tests/handlers/interview.test.ts +127 -0
  106. package/dist/extensions/pi-hermes-memory/tests/handlers/pi-child-process.test.ts +905 -0
  107. package/dist/extensions/pi-hermes-memory/tests/handlers/preview-context.test.ts +152 -0
  108. package/dist/extensions/pi-hermes-memory/tests/handlers/prompt-context.test.ts +166 -0
  109. package/dist/extensions/pi-hermes-memory/tests/handlers/resources-discover.test.ts +71 -0
  110. package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +614 -0
  111. package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +192 -0
  112. package/dist/extensions/pi-hermes-memory/tests/handlers/session-flush.test.ts +677 -0
  113. package/dist/extensions/pi-hermes-memory/tests/handlers/session-live-index.test.ts +225 -0
  114. package/dist/extensions/pi-hermes-memory/tests/handlers/skills-command.test.ts +827 -0
  115. package/dist/extensions/pi-hermes-memory/tests/handlers/standing-pin.test.ts +134 -0
  116. package/dist/extensions/pi-hermes-memory/tests/handlers/sync-markdown-memories.test.ts +491 -0
  117. package/dist/extensions/pi-hermes-memory/tests/handlers/system-prompt.test.ts +199 -0
  118. package/dist/extensions/pi-hermes-memory/tests/handlers/thinking-max.test.ts +64 -0
  119. package/dist/extensions/pi-hermes-memory/tests/index.test.ts +30 -0
  120. package/dist/extensions/pi-hermes-memory/tests/integration/flow.test.ts +126 -0
  121. package/dist/extensions/pi-hermes-memory/tests/lifecycle-timing.test.ts +76 -0
  122. package/dist/extensions/pi-hermes-memory/tests/paths.test.ts +23 -0
  123. package/dist/extensions/pi-hermes-memory/tests/project-memory-migration.test.ts +80 -0
  124. package/dist/extensions/pi-hermes-memory/tests/project-rebinding.test.ts +115 -0
  125. package/dist/extensions/pi-hermes-memory/tests/project.test.ts +120 -0
  126. package/dist/extensions/pi-hermes-memory/tests/run-all-timeout.test.ts +107 -0
  127. package/dist/extensions/pi-hermes-memory/tests/run-all.sh +45 -0
  128. package/dist/extensions/pi-hermes-memory/tests/store/atomic-lock-coordinator.test.ts +381 -0
  129. package/dist/extensions/pi-hermes-memory/tests/store/content-scanner.test.ts +388 -0
  130. package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +1046 -0
  131. package/dist/extensions/pi-hermes-memory/tests/store/markdown-mutation-lock.test.ts +34 -0
  132. package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +2150 -0
  133. package/dist/extensions/pi-hermes-memory/tests/store/recovery-maintenance.test.ts +170 -0
  134. package/dist/extensions/pi-hermes-memory/tests/store/session-anchor-search.test.ts +210 -0
  135. package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +643 -0
  136. package/dist/extensions/pi-hermes-memory/tests/store/session-parser.test.ts +282 -0
  137. package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +287 -0
  138. package/dist/extensions/pi-hermes-memory/tests/store/skill-store.test.ts +678 -0
  139. package/dist/extensions/pi-hermes-memory/tests/store/skill-utils.test.ts +21 -0
  140. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-lazy-load.test.ts +78 -0
  141. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +543 -0
  142. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +164 -0
  143. package/dist/extensions/pi-hermes-memory/tests/store/standing-instructions.test.ts +171 -0
  144. package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +84 -0
  145. package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +709 -0
  146. package/dist/extensions/pi-hermes-memory/tests/tools/session-search-tool.test.ts +345 -0
  147. package/dist/extensions/pi-hermes-memory/tests/tools/shared-output-view.test.ts +362 -0
  148. package/dist/extensions/pi-hermes-memory/tests/tools/skill-tool.test.ts +478 -0
  149. package/dist/extensions/pi-hermes-memory/tests/tools/tool-result-renderer-wiring.test.ts +40 -0
  150. package/dist/extensions/pi-hermes-memory/tsconfig.json +19 -0
  151. package/dist/extensions/pi-subagents/.oxlintrc.json +43 -0
  152. package/dist/extensions/pi-subagents/AGENTS.md +5 -0
  153. package/dist/extensions/pi-subagents/CHANGELOG.md +157 -0
  154. package/dist/extensions/pi-subagents/README.md +12 -6
  155. package/dist/extensions/pi-subagents/VISION.md +81 -0
  156. package/dist/extensions/pi-subagents/agents/claude-code-writer.md +15 -0
  157. package/dist/extensions/pi-subagents/agents/claude-code.md +15 -0
  158. package/dist/extensions/pi-subagents/agents/codex-exec-writer.md +15 -0
  159. package/dist/extensions/pi-subagents/agents/codex-exec.md +15 -0
  160. package/dist/extensions/pi-subagents/agents/cursor-agent-writer.md +14 -0
  161. package/dist/extensions/pi-subagents/agents/cursor-agent.md +14 -0
  162. package/dist/extensions/pi-subagents/agents/reviewer.md +1 -3
  163. package/dist/extensions/pi-subagents/docs/agents.md +488 -0
  164. package/dist/extensions/pi-subagents/docs/configuration.md +46 -9
  165. package/dist/extensions/pi-subagents/docs/extension-api.md +42 -3
  166. package/dist/extensions/pi-subagents/docs/models.md +27 -4
  167. package/dist/extensions/pi-subagents/docs/observability.md +10 -9
  168. package/dist/extensions/pi-subagents/docs/tool-reference.md +102 -6
  169. package/dist/extensions/pi-subagents/docs/workflows.md +135 -0
  170. package/dist/extensions/pi-subagents/package-lock.json +389 -2
  171. package/dist/extensions/pi-subagents/package.json +3 -1
  172. package/dist/extensions/pi-subagents/prompts/review-loop.md +2 -2
  173. package/dist/extensions/pi-subagents/skills/council-mode/SKILL.md +1 -1
  174. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +3 -1
  175. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +7 -3
  176. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
  177. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +26 -5
  178. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +41 -22
  179. package/dist/extensions/pi-subagents/src/agents/agent-refinements.ts +4 -4
  180. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +9 -2
  181. package/dist/extensions/pi-subagents/src/agents/agents.ts +322 -75
  182. package/dist/extensions/pi-subagents/src/agents/builtin-names.ts +6 -0
  183. package/dist/extensions/pi-subagents/src/agents/runtime-agent-events.ts +70 -0
  184. package/dist/extensions/pi-subagents/src/agents/runtime-agent-registry.ts +27 -20
  185. package/dist/extensions/pi-subagents/src/api/agents.ts +10 -5
  186. package/dist/extensions/pi-subagents/src/api/background-work.ts +5 -1
  187. package/dist/extensions/pi-subagents/src/api/delegation.ts +0 -7
  188. package/dist/extensions/pi-subagents/src/api/preflight.ts +34 -12
  189. package/dist/extensions/pi-subagents/src/extension/config.ts +70 -0
  190. package/dist/extensions/pi-subagents/src/extension/doctor.ts +3 -3
  191. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +5 -3
  192. package/dist/extensions/pi-subagents/src/extension/index.ts +83 -30
  193. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +44 -15
  194. package/dist/extensions/pi-subagents/src/extension/rpc.ts +55 -19
  195. package/dist/extensions/pi-subagents/src/extension/schemas.ts +41 -15
  196. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -31
  197. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +2 -1
  198. package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +2 -10
  199. package/dist/extensions/pi-subagents/src/inspectors/herdr/session-roots-codec.ts +42 -0
  200. package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +51 -3
  201. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +2 -0
  202. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +5 -6
  203. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +77 -10
  204. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +176 -53
  205. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +19 -12
  206. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +29 -27
  207. package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +20 -3
  208. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +23 -261
  209. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +73 -7
  210. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +8 -3
  211. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +74 -8
  212. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +37 -21
  213. package/dist/extensions/pi-subagents/src/runs/background/inspect-rpc.ts +8 -8
  214. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +184 -9
  215. package/dist/extensions/pi-subagents/src/runs/background/result-delivery-ownership.ts +45 -0
  216. package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +28 -14
  217. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +38 -15
  218. package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +1 -1
  219. package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +1 -1
  220. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +50 -13
  221. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +93 -8
  222. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +10 -4
  223. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +4 -14
  224. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +549 -377
  225. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +58 -10
  226. package/dist/extensions/pi-subagents/src/runs/background/terminal-run-index.ts +1 -1
  227. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +26 -1
  228. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +23 -9
  229. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +9 -2
  230. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +2 -2
  231. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +204 -129
  232. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +9 -0
  233. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +23 -1
  234. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +773 -311
  235. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +140 -115
  236. package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +119 -0
  237. package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +463 -0
  238. package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +19 -4
  239. package/dist/extensions/pi-subagents/src/runs/shared/child-launch-plan.ts +151 -0
  240. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +21 -7
  241. package/dist/extensions/pi-subagents/src/runs/shared/claude-code-adapter.ts +129 -0
  242. package/dist/extensions/pi-subagents/src/runs/shared/codex-exec-adapter.ts +129 -0
  243. package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +89 -0
  244. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +5 -4
  245. package/dist/extensions/pi-subagents/src/runs/shared/cursor-agent-adapter.ts +114 -0
  246. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +3 -3
  247. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-contract.ts +167 -0
  248. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +122 -0
  249. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +348 -55
  250. package/dist/extensions/pi-subagents/src/runs/shared/fast-mode-extension.ts +5 -5
  251. package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +230 -0
  252. package/dist/extensions/pi-subagents/src/runs/shared/lane-metadata.ts +105 -0
  253. package/dist/extensions/pi-subagents/src/runs/shared/launch-cwd.ts +16 -0
  254. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +2 -1
  255. package/dist/extensions/pi-subagents/src/runs/shared/mcp-config-sources.ts +422 -0
  256. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +221 -158
  257. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-grant.ts +197 -0
  258. package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +69 -7
  259. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +47 -6
  260. package/dist/extensions/pi-subagents/src/runs/shared/mutation-evidence.ts +7 -2
  261. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +9 -3
  262. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +9 -5
  263. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +419 -7
  264. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +15 -1
  265. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +81 -8
  266. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +13 -0
  267. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +21 -1
  268. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +44 -4
  269. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +98 -13
  270. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +1 -1
  271. package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +847 -0
  272. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +18 -0
  273. package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +46 -0
  274. package/dist/extensions/pi-subagents/src/shared/extension-context.ts +24 -0
  275. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +21 -0
  276. package/dist/extensions/pi-subagents/src/shared/formatters.ts +18 -3
  277. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +5 -1
  278. package/dist/extensions/pi-subagents/src/shared/pruned-fork.ts +450 -0
  279. package/dist/extensions/pi-subagents/src/shared/session-file-trust.ts +19 -0
  280. package/dist/extensions/pi-subagents/src/shared/session-tokens.ts +14 -3
  281. package/dist/extensions/pi-subagents/src/shared/settings.ts +19 -105
  282. package/dist/extensions/pi-subagents/src/shared/shortcuts.ts +17 -0
  283. package/dist/extensions/pi-subagents/src/shared/types.ts +359 -40
  284. package/dist/extensions/pi-subagents/src/shared/utils.ts +41 -84
  285. package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +116 -0
  286. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +1 -9
  287. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +0 -4
  288. package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +1 -2
  289. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +378 -88
  290. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +22 -11
  291. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +3 -0
  292. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +147 -79
  293. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +11 -5
  294. package/dist/extensions/pi-subagents/src/tui/fleet.ts +39 -18
  295. package/dist/extensions/pi-subagents/src/tui/render.ts +369 -46
  296. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +1 -1
  297. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +6 -3
  298. package/dist/extensions/pi-subagents/src/workflows/host-command.ts +230 -0
  299. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +740 -58
  300. package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +121 -0
  301. package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +270 -0
  302. package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +195 -6
  303. package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +246 -0
  304. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
  305. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1114 -260
  306. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +34 -0
  307. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +150 -3
  308. package/dist/extensions/pi-subagents/test/integration/claude-code-smoke.test.ts +52 -0
  309. package/dist/extensions/pi-subagents/test/integration/claude-code-writer-smoke.test.ts +55 -0
  310. package/dist/extensions/pi-subagents/test/integration/codex-exec-smoke.test.ts +53 -0
  311. package/dist/extensions/pi-subagents/test/integration/codex-exec-writer-smoke.test.ts +57 -0
  312. package/dist/extensions/pi-subagents/test/integration/cursor-agent-smoke.test.ts +59 -0
  313. package/dist/extensions/pi-subagents/test/integration/cursor-agent-writer-smoke.test.ts +62 -0
  314. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +57 -1
  315. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
  316. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +20 -0
  317. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +4 -3
  318. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +2 -2
  319. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +54 -4
  320. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +482 -4
  321. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +157 -9
  322. package/dist/extensions/pi-subagents/test/integration/session-tokens.test.ts +5 -5
  323. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1508 -291
  324. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +423 -1
  325. package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +8 -0
  326. package/dist/extensions/pi-subagents/test/support/cursor-smoke-inputs.ts +51 -0
  327. package/dist/extensions/pi-subagents/test/support/helpers.ts +2 -0
  328. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +5 -5
  329. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +6 -6
  330. package/dist/extensions/pi-subagents/test/unit/abort-recovery.test.ts +152 -0
  331. package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +48 -0
  332. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +184 -6
  333. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +66 -6
  334. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +77 -0
  335. package/dist/extensions/pi-subagents/test/unit/agent-refinements.test.ts +18 -0
  336. package/dist/extensions/pi-subagents/test/unit/anti-slop-oxlint.test.ts +86 -0
  337. package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +1 -1
  338. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +101 -1
  339. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +121 -0
  340. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +28 -0
  341. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +14 -7
  342. package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +53 -0
  343. package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +190 -0
  344. package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +42 -0
  345. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +8 -4
  346. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +23 -0
  347. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +78 -1
  348. package/dist/extensions/pi-subagents/test/unit/child-launch-plan.test.ts +94 -0
  349. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +21 -0
  350. package/dist/extensions/pi-subagents/test/unit/child-session-name.test.ts +50 -0
  351. package/dist/extensions/pi-subagents/test/unit/claude-code-adapter.test.ts +245 -0
  352. package/dist/extensions/pi-subagents/test/unit/codex-exec-adapter.test.ts +192 -0
  353. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +27 -0
  354. package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +150 -0
  355. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +21 -0
  356. package/dist/extensions/pi-subagents/test/unit/cursor-agent-adapter.test.ts +259 -0
  357. package/dist/extensions/pi-subagents/test/unit/cursor-smoke-inputs.test.ts +77 -0
  358. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +1 -4
  359. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
  360. package/dist/extensions/pi-subagents/test/unit/extension-context.test.ts +27 -0
  361. package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +223 -0
  362. package/dist/extensions/pi-subagents/test/unit/fast-mode-extension.test.ts +27 -0
  363. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +208 -2
  364. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +29 -1
  365. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +110 -1
  366. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +10 -0
  367. package/dist/extensions/pi-subagents/test/unit/formatters.test.ts +14 -0
  368. package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +18 -9
  369. package/dist/extensions/pi-subagents/test/unit/herdr-session-roots-codec.test.ts +63 -0
  370. package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +2 -2
  371. package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +132 -0
  372. package/dist/extensions/pi-subagents/test/unit/host-command.test.ts +156 -0
  373. package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +98 -0
  374. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +178 -26
  375. package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +2 -1
  376. package/dist/extensions/pi-subagents/test/unit/inspect-rpc.test.ts +21 -0
  377. package/dist/extensions/pi-subagents/test/unit/mcp-direct-tool-grant.test.ts +138 -0
  378. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
  379. package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +91 -0
  380. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +72 -7
  381. package/dist/extensions/pi-subagents/test/unit/mutation-evidence.test.ts +21 -0
  382. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +1 -0
  383. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +20 -2
  384. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +129 -1
  385. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +2 -2
  386. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +4 -0
  387. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +358 -0
  388. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +574 -21
  389. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +109 -1
  390. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +71 -1
  391. package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +7 -7
  392. package/dist/extensions/pi-subagents/test/unit/pruned-fork.test.ts +214 -0
  393. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +29 -8
  394. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +53 -0
  395. package/dist/extensions/pi-subagents/test/unit/result-delivery-ownership.test.ts +34 -0
  396. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +101 -3
  397. package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +1 -0
  398. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +10 -8
  399. package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +71 -1
  400. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +41 -7
  401. package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +136 -2
  402. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +137 -0
  403. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +33 -12
  404. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +504 -1
  405. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +8 -0
  406. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  407. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +12 -1
  408. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +3 -5
  409. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +5 -6
  410. package/dist/extensions/pi-subagents/test/unit/subagent-action-recovery.test.ts +0 -8
  411. package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +5 -0
  412. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +157 -2
  413. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +1 -1
  414. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +63 -4
  415. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +27 -23
  416. package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +44 -0
  417. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +1 -0
  418. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +7 -5
  419. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +106 -0
  420. package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +484 -9
  421. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +38 -4
  422. package/dist/extensions/pi-subagents/test/unit/workflow-preflight.test.ts +155 -0
  423. package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +318 -0
  424. package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +365 -0
  425. package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +349 -0
  426. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +21 -0
  427. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +2 -7
  428. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/index.ts +13 -0
  429. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/rules/no-service-constructor-imports.ts +52 -0
  430. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/index.ts +41 -0
  431. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-chained-type-assertions.ts +77 -0
  432. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-conditional-empty-object-spread.ts +49 -0
  433. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-known-value-widening.ts +247 -0
  434. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-module-mocking.ts +91 -0
  435. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-object-parameters.ts +126 -0
  436. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-apply.ts +28 -0
  437. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-get.ts +28 -0
  438. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-runtime-typeof.ts +67 -0
  439. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-shape-in-symbol-names.ts +39 -0
  440. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-parameters.ts +83 -0
  441. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-returns.ts +115 -0
  442. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-type-aliases.ts +72 -0
  443. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unsafe-dictionary-type.ts +134 -0
  444. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-widen-then-assert.ts +366 -0
  445. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/require-safety-comment-for-type-assertion.ts +62 -0
  446. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/dictionary-types.ts +502 -0
  447. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/lexical-type-parameters.ts +60 -0
  448. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/reflect-method.ts +35 -0
  449. package/dist/extensions/pi-tool-display/tests/capabilities.test.ts +1 -1
  450. package/dist/extensions/pi-tool-display/tests/settings-inspector.test.ts +2 -2
  451. package/dist/extensions/pi-tool-display/tests/tool-overrides-mcp.test.ts +1 -1
  452. package/dist/modes/interactive/interactive-mode.js +7 -7
  453. package/dist/skills/workflow/SKILL.md +65 -50
  454. package/package.json +112 -110
  455. package/dist/extensions/enable-readonly-tools.test.ts +0 -63
  456. package/dist/extensions/enable-readonly-tools.ts +0 -24
  457. package/dist/extensions/model-prompt-injector/config.json +0 -16
  458. package/dist/extensions/model-prompt-injector/index.test.ts +0 -102
  459. package/dist/extensions/model-prompt-injector/index.ts +0 -148
  460. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +0 -98
  461. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +0 -250
@@ -309,6 +309,37 @@ describe("native subagent fleet", () => {
309
309
  }
310
310
  });
311
311
 
312
+ it("does not crash Fleet render when live prompt audit stores a non-string authored task", () => {
313
+ const state = stateForTest();
314
+ const control = {
315
+ runId: "bad-prompt-run",
316
+ sessionId: "session-current",
317
+ mode: "single" as const,
318
+ startedAt: 10,
319
+ updatedAt: 20,
320
+ activeChildren: new Map([[0, { index: 0, agent: "worker", startedAt: 10, updatedAt: 20 }]]),
321
+ };
322
+ state.foregroundControls.set(control.runId, control);
323
+ registerLivePromptAudit(control, 0, { nested: "task payload" } as unknown as string, "effective prompt");
324
+ const component = new SubagentFleetComponent(
325
+ { terminal: { rows: 28, columns: 100 }, requestRender() {} } as never,
326
+ theme as never,
327
+ state,
328
+ () => {},
329
+ { refreshMs: 60_000, markdownTheme },
330
+ );
331
+ try {
332
+ assert.doesNotThrow(() => component.render(100));
333
+ const rendered = component.render(100).join("\n");
334
+ assert.doesNotMatch(rendered, /nested|task payload/);
335
+ component.handleInput("p");
336
+ assert.doesNotThrow(() => component.render(100));
337
+ assert.match(component.render(100).join("\n"), /Selected prompt unavailable/);
338
+ } finally {
339
+ component.dispose();
340
+ }
341
+ });
342
+
312
343
  it("shows live prompt summaries and opens Prompt Audit with the authored prompt visible", async () => {
313
344
  const sentinel = "PROMPT_AUDIT_SENTINEL_1021";
314
345
  const secondSentinel = "PROMPT_AUDIT_SECOND_CHILD";
@@ -761,7 +792,7 @@ describe("native subagent fleet", () => {
761
792
  cwd,
762
793
  sessionId: "session-current",
763
794
  updatedAt: 200,
764
- children: [{ agent: "worker", index: 0, status: "completed", finalOutput: "do not persist this when an artifact exists", savedOutputPath: outputPath, extensionBindings: { "shepherd.dispatch/1": { role: "coder" } } }],
795
+ children: [{ agent: "worker", index: 0, status: "completed", finalOutput: "do not persist this when an artifact exists", savedOutputPath: outputPath, resumeContract: { outputSchema: { type: "object" }, agentContract: { version: 1 }, acceptance: false, output: false, outputMode: "inline" }, extensionBindings: { "shepherd.dispatch/1": { role: "coder" } } }],
765
796
  });
766
797
  state.foregroundRuns!.set("other-session", {
767
798
  runId: "other-session",
@@ -779,6 +810,7 @@ describe("native subagent fleet", () => {
779
810
  restored.baseCwd = cwd;
780
811
  restored.artifactDirPreference = "project";
781
812
  assert.equal(restoreForegroundRunHistory(restored, { resultsDir }), 1);
813
+ assert.deepEqual(restored.foregroundRuns?.get("restored")?.children[0]?.resumeContract, { outputSchema: { type: "object" }, agentContract: { version: 1 }, acceptance: false, output: false, outputMode: "inline" });
782
814
  assert.deepEqual(restored.foregroundRuns?.get("restored")?.children[0]?.extensionBindings, { "shepherd.dispatch/1": { role: "coder" } });
783
815
  const snapshot = collectFleetSnapshot(restored);
784
816
  assert.deepEqual(snapshot.items.map((item) => item.key), ["foreground-recent:restored:0"]);
@@ -852,6 +884,45 @@ describe("native subagent fleet", () => {
852
884
  }
853
885
  });
854
886
 
887
+ it("does not restore or persist oversized foreground resume contracts", () => {
888
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-fleet-foreground-contract-bound-"));
889
+ try {
890
+ const resultsDir = path.join(root, "results");
891
+ fs.mkdirSync(resultsDir, { recursive: true });
892
+ const oversizedContract = { outputSchema: { type: "object", description: "x".repeat(65 * 1024) } };
893
+ fs.writeFileSync(path.join(resultsDir, "foreground-history.json"), JSON.stringify({
894
+ version: 1,
895
+ runs: [{
896
+ runId: "oversized",
897
+ mode: "single",
898
+ cwd: root,
899
+ sessionId: "session-current",
900
+ updatedAt: 200,
901
+ children: [{ agent: "worker", index: 0, status: "completed", resumeContract: oversizedContract }],
902
+ }],
903
+ }), "utf-8");
904
+
905
+ const restored = stateForTest();
906
+ assert.equal(restoreForegroundRunHistory(restored, { resultsDir }), 0);
907
+ assert.equal(restored.foregroundRuns?.has("oversized"), false);
908
+
909
+ const state = stateForTest();
910
+ state.foregroundRuns!.set("oversized", {
911
+ runId: "oversized",
912
+ mode: "single",
913
+ cwd: root,
914
+ sessionId: "session-current",
915
+ updatedAt: 200,
916
+ children: [{ agent: "worker", index: 0, status: "completed", resumeContract: oversizedContract }],
917
+ });
918
+ persistForegroundRunHistory(state, { resultsDir });
919
+ const persisted = JSON.parse(fs.readFileSync(path.join(resultsDir, "foreground-history.json"), "utf-8")) as { runs: Array<{ runId: string }> };
920
+ assert.deepEqual(persisted.runs, []);
921
+ } finally {
922
+ fs.rmSync(root, { recursive: true, force: true });
923
+ }
924
+ });
925
+
855
926
  it("keeps restored foreground rows when output artifacts are unavailable and bounds history", () => {
856
927
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-fleet-foreground-missing-"));
857
928
  try {
@@ -978,6 +1049,44 @@ describe("native subagent fleet", () => {
978
1049
  }
979
1050
  });
980
1051
 
1052
+ it("previews an exact runtime-recorded workflow session under the Pi sessions base", () => {
1053
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-fleet-recorded-session-"));
1054
+ try {
1055
+ const asyncDir = writeAsyncRun(root, { id: "async-recorded-session" });
1056
+ const sessionsBase = path.join(root, "sessions");
1057
+ const projectDir = path.join(sessionsBase, "project");
1058
+ fs.mkdirSync(projectDir, { recursive: true });
1059
+ const sessionFile = path.join(projectDir, "workflow-child.jsonl");
1060
+ fs.writeFileSync(sessionFile, `${JSON.stringify({ role: "assistant", content: "RECORDED WORKFLOW SESSION" })}\n`, "utf-8");
1061
+ const statusPath = path.join(asyncDir, "status.json");
1062
+ const status = JSON.parse(fs.readFileSync(statusPath, "utf-8")) as { sessionFile?: string; steps?: Array<{ sessionFile?: string; transcriptPath?: string }> };
1063
+ status.sessionFile = sessionFile;
1064
+ status.steps![0]!.sessionFile = sessionFile;
1065
+ delete status.steps![0]!.transcriptPath;
1066
+ fs.writeFileSync(statusPath, JSON.stringify(status, null, 2), "utf-8");
1067
+
1068
+ const state = stateForTest();
1069
+ state.trustedSessionRoots = [];
1070
+ state.trustedSessionFileRoot = sessionsBase;
1071
+ const component = new SubagentFleetComponent(
1072
+ { terminal: { rows: 32, columns: 100 }, requestRender() {} } as never,
1073
+ theme as never,
1074
+ state,
1075
+ () => {},
1076
+ { asyncDirRoot: root, resultsDir: path.join(root, "results"), refreshMs: 60_000 },
1077
+ );
1078
+ try {
1079
+ const rendered = component.render(100).join("\n");
1080
+ assert.match(rendered, /RECORDED WORKFLOW SESSION/);
1081
+ assert.doesNotMatch(rendered, /without a trusted root|Session read failed/);
1082
+ } finally {
1083
+ component.dispose();
1084
+ }
1085
+ } finally {
1086
+ fs.rmSync(root, { recursive: true, force: true });
1087
+ }
1088
+ });
1089
+
981
1090
  it("renders structured tool activity and assistant Markdown when a child transcript is available", () => {
982
1091
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-fleet-structured-"));
983
1092
  try {
@@ -15,6 +15,7 @@ function progress(index: number, agent: string, tokens: number): AgentProgress {
15
15
  return {
16
16
  index,
17
17
  agent,
18
+ sessionName: ` ${agent}: named task `,
18
19
  status: "running",
19
20
  task: `${agent} task`,
20
21
  recentTools: [],
@@ -25,6 +26,8 @@ function progress(index: number, agent: string, tokens: number): AgentProgress {
25
26
  thinking: "high",
26
27
  inputTokens: tokens - 20,
27
28
  outputTokens: 20,
29
+ window: 75,
30
+ windowPeak: 90,
28
31
  durationMs: 10,
29
32
  };
30
33
  }
@@ -67,9 +70,13 @@ describe("foreground child control", () => {
67
70
  assert.equal(control.currentIndex, 1);
68
71
  updateForegroundChild(control, 0, progress(0, "reviewer", 120));
69
72
  assert.equal(control.currentIndex, 0);
73
+ assert.equal(control.sessionName, " reviewer: named task ");
74
+ assert.equal(control.activeChildren?.get(0)?.sessionName, " reviewer: named task ");
70
75
  assert.equal(control.tokens, 120);
71
76
  assert.equal(control.inputTokens, 100);
72
77
  assert.equal(control.outputTokens, 20);
78
+ assert.equal(control.window, 75);
79
+ assert.equal(control.windowPeak, 90);
73
80
  assert.equal(control.model, "openai/gpt-5.6-terra:high");
74
81
  assert.equal(control.thinking, "high");
75
82
  assert.equal(control.activeChildren?.get(1)?.tokens, undefined);
@@ -89,9 +96,12 @@ describe("foreground child control", () => {
89
96
  finishForegroundChild(control, 0);
90
97
  assert.equal(control.activeChildren?.size, 0);
91
98
  assert.equal(control.currentIndex, undefined);
99
+ assert.equal(control.sessionName, undefined);
92
100
  assert.equal(control.model, undefined);
93
101
  assert.equal(control.inputTokens, undefined);
94
102
  assert.equal(control.outputTokens, undefined);
103
+ assert.equal(control.window, undefined);
104
+ assert.equal(control.windowPeak, undefined);
95
105
  assert.equal(control.interrupt, undefined);
96
106
  assert.equal(control.detach, undefined);
97
107
  });
@@ -0,0 +1,14 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { formatContextUsage, formatTokens } from "../../src/shared/formatters.ts";
4
+
5
+ test("formats million-scale token values with an M suffix", () => {
6
+ assert.equal(formatTokens(999_499), "999k");
7
+ assert.equal(formatTokens(999_500), "1M");
8
+ assert.equal(formatTokens(1_000_000), "1M");
9
+ assert.equal(formatTokens(1_250_000), "1.3M");
10
+ });
11
+
12
+ test("formats million-scale context limits clearly", () => {
13
+ assert.equal(formatContextUsage({ window: 93_000 }, 1_000_000), "ctx 93k/1M (9%)");
14
+ });
@@ -9,10 +9,20 @@ import { handleHerdrInspectorAction, readHerdrInspectorBinding } from "../../src
9
9
  import { createHerdrClient, detectHerdr, parseHerdrVersion, supportsRawPanes, type HerdrClient } from "../../src/inspectors/herdr/client.ts";
10
10
  import { formatInspectorDashboard, submitInspectorControl } from "../../src/inspectors/herdr/inspector-runner.ts";
11
11
  import { createProjectPaneManager, handleHerdrProjectPaneAction, listHerdrProjectPaneRoots, readHerdrProjectPaneBinding, restoreHerdrProjectPaneSnapshots } from "../../src/inspectors/herdr/project-panes.ts";
12
+ import { decodeSessionRoots } from "../../src/inspectors/herdr/session-roots-codec.ts";
12
13
  import { consumeSteerRequests, consumeStopRequest } from "../../src/runs/background/control-channel.ts";
13
- import { SELESAI_SUBAGENT_PI_BINARY_ENV } from "../../src/runs/shared/pi-spawn.ts";
14
+ import { SELESAI_SUBAGENT_SELESAI_BINARY_ENV } from "../../src/runs/shared/pi-spawn.ts";
14
15
  import type { AsyncStatus, SubagentState } from "../../src/shared/types.ts";
15
16
 
17
+ // `pane run` commands quote the whole --session-roots value (base64, so it has
18
+ // no spaces/quotes of its own); pull it back out and decode it the same way
19
+ // the inspector runner does, rather than pattern-matching on the raw text.
20
+ function sessionRootsFromRunCommand(command: string): string[] {
21
+ const match = /--session-roots\S*\s+['"]?([A-Za-z0-9+/=]+)/.exec(command);
22
+ assert.ok(match, `--session-roots argument not found in command: ${command}`);
23
+ return decodeSessionRoots(match[1]);
24
+ }
25
+
16
26
  function fakeChild(): EventEmitter & { stdout: PassThrough; stderr: PassThrough; kill(): boolean } {
17
27
  const child = new EventEmitter() as EventEmitter & { stdout: PassThrough; stderr: PassThrough; kill(): boolean };
18
28
  child.stdout = new PassThrough();
@@ -120,7 +130,7 @@ describe("Herdr inspector", () => {
120
130
  assert.ok(!/^[']/.test(runCall[3] ?? ""), `pane run command must not open with a quoted executable; Nushell parses it as a string expression: ${runCall[3]}`);
121
131
  }
122
132
  assert.match(runCall[3] ?? "", /--allow-steer.*true.*--allow-stop.*true/);
123
- assert.match(runCall[3] ?? "", /--session-roots.*sessions/);
133
+ assert.deepEqual(sessionRootsFromRunCommand(runCall[3] ?? ""), [sessionRoot]);
124
134
 
125
135
  const closed = await handleHerdrInspectorAction("inspector.close", { dir: asyncDir }, { cwd: root, asyncDirRoot: root, client });
126
136
  assert.equal(closed.isError, undefined, text(closed));
@@ -180,8 +190,7 @@ describe("Herdr inspector", () => {
180
190
  });
181
191
  assert.equal(opened.isError, undefined, text(opened));
182
192
  const runCall = calls.find((args) => args[0] === "pane" && args[1] === "run" && args[2] === "w1:p11");
183
- assert.match(runCall?.[3] ?? "", /--session-roots/);
184
- assert.match(runCall?.[3] ?? "", /custom-sessions/);
193
+ assert.deepEqual(sessionRootsFromRunCommand(runCall?.[3] ?? ""), [sessionRoot]);
185
194
 
186
195
  state.asyncJobs.clear();
187
196
  fs.rmSync(path.join(asyncDir, "inspectors"), { recursive: true, force: true });
@@ -195,7 +204,7 @@ describe("Herdr inspector", () => {
195
204
  });
196
205
  assert.equal(reopened.isError, undefined, text(reopened));
197
206
  const untrustedRunCall = calls.find((args) => args[0] === "pane" && args[1] === "run" && args[2] === "w1:p11");
198
- assert.doesNotMatch(untrustedRunCall?.[3] ?? "", /custom-sessions/);
207
+ assert.deepEqual(sessionRootsFromRunCommand(untrustedRunCall?.[3] ?? ""), []);
199
208
  } finally {
200
209
  fs.rmSync(root, { recursive: true, force: true });
201
210
  }
@@ -280,8 +289,8 @@ describe("Herdr inspector", () => {
280
289
 
281
290
  it("opens, reports, and closes a project-owned Herdr pane", async () => {
282
291
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi=herdr project pane-"));
283
- const previousPiBinary = process.env[SELESAI_SUBAGENT_PI_BINARY_ENV];
284
- process.env[SELESAI_SUBAGENT_PI_BINARY_ENV] = path.join(root, "pi-bin");
292
+ const previousPiBinary = process.env[SELESAI_SUBAGENT_SELESAI_BINARY_ENV];
293
+ process.env[SELESAI_SUBAGENT_SELESAI_BINARY_ENV] = path.join(root, "pi-bin");
285
294
  try {
286
295
  const projectRoot = fs.realpathSync(root);
287
296
  const ownerRoot = path.join(root, "owner");
@@ -352,8 +361,8 @@ describe("Herdr inspector", () => {
352
361
  fs.writeFileSync(path.join(ownerRoot, ".pi-subagents/project-panes/herdr-roots.json"), JSON.stringify({ schemaVersion: 1, kind: "herdr-project-pane-roots", projectRoots: [123] }));
353
362
  assert.throws(() => listHerdrProjectPaneRoots(ownerRoot), /Invalid Herdr project pane root index/);
354
363
  } finally {
355
- if (previousPiBinary === undefined) delete process.env[SELESAI_SUBAGENT_PI_BINARY_ENV];
356
- else process.env[SELESAI_SUBAGENT_PI_BINARY_ENV] = previousPiBinary;
364
+ if (previousPiBinary === undefined) delete process.env[SELESAI_SUBAGENT_SELESAI_BINARY_ENV];
365
+ else process.env[SELESAI_SUBAGENT_SELESAI_BINARY_ENV] = previousPiBinary;
357
366
  fs.rmSync(root, { recursive: true, force: true });
358
367
  }
359
368
  });
@@ -0,0 +1,63 @@
1
+ import assert from "node:assert/strict";
2
+ import { execFileSync } from "node:child_process";
3
+ import { describe, it } from "node:test";
4
+ import { decodeSessionRoots, encodeSessionRoots } from "../../src/inspectors/herdr/session-roots-codec.ts";
5
+ import { formatShellCommand } from "../../src/inspectors/herdr/shell-command.ts";
6
+
7
+ describe("session roots codec", () => {
8
+ it("round-trips an empty array, plain paths, and paths with spaces/quotes", () => {
9
+ for (const roots of [[], ["/tmp/a"], ["C:\\Users\\a b\\.selesai", "D:\\work"], ['has "quotes"', "has\\backslashes\\"]]) {
10
+ assert.deepEqual(decodeSessionRoots(encodeSessionRoots(roots)), roots);
11
+ }
12
+ });
13
+
14
+ it("still accepts raw JSON for backward compatibility with unpatched callers", () => {
15
+ assert.deepEqual(decodeSessionRoots(JSON.stringify(["/tmp/a", "/tmp/b"])), ["/tmp/a", "/tmp/b"]);
16
+ assert.deepEqual(decodeSessionRoots(JSON.stringify([])), []);
17
+ });
18
+
19
+ it("rejects malformed input from either encoding", () => {
20
+ assert.throws(() => decodeSessionRoots("not base64 and not json"), /base64-encoded or raw JSON array of strings/);
21
+ assert.throws(() => decodeSessionRoots(Buffer.from(JSON.stringify({ not: "an array" })).toString("base64")), /base64-encoded or raw JSON array of strings/);
22
+ assert.throws(() => decodeSessionRoots(Buffer.from(JSON.stringify([1, 2])).toString("base64")), /base64-encoded or raw JSON array of strings/);
23
+ });
24
+
25
+ it("produces plain-ASCII base64 output with no quote, backslash, or space characters for a shell to mangle", () => {
26
+ const encoded = encodeSessionRoots(["C:\\Users\\a b\\.selesai\\sessions", 'contains "quotes"', "D:\\work"]);
27
+ assert.match(encoded, /^[A-Za-z0-9+/=]+$/);
28
+ });
29
+
30
+ // This is the actual regression: Windows PowerShell has no backslash-escape for
31
+ // embedded double quotes (only `` `" `` or `""`), so shellQuote's win32 branch
32
+ // (which escapes `"` as `\"`) corrupts any argument containing a literal `"` -
33
+ // exactly what `JSON.stringify(sessionRoots)` produces. Spawn real powershell.exe
34
+ // to prove the old approach breaks and the new approach survives.
35
+ describe("end-to-end through real powershell.exe", { skip: process.platform !== "win32" }, () => {
36
+ function echoArgvCommand(sessionRootsArg: string): string {
37
+ const script = "process.stdout.write(JSON.stringify(process.argv.slice(1)));";
38
+ return formatShellCommand(process.execPath, ["-e", script, "--", "--session-roots", sessionRootsArg], "win32");
39
+ }
40
+
41
+ function runThroughPowerShell(command: string): string[] {
42
+ return JSON.parse(execFileSync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", command], { encoding: "utf-8" }));
43
+ }
44
+
45
+ it("mangles a raw JSON.stringify payload (documents the bug this PR fixes)", () => {
46
+ const sessionRoots = ["C:\\Users\\sgerashe\\.selesai\\sessions", "D:\\work\\proj"];
47
+ const rawJson = JSON.stringify(sessionRoots);
48
+ const argv = runThroughPowerShell(echoArgvCommand(rawJson));
49
+ const received = argv[argv.indexOf("--session-roots") + 1];
50
+ assert.notEqual(received, rawJson, "expected PowerShell to corrupt the unescaped JSON payload");
51
+ assert.throws(() => JSON.parse(received ?? ""), /Unexpected token/, "corrupted payload should no longer be valid JSON");
52
+ });
53
+
54
+ it("survives base64 encoding byte-for-byte", () => {
55
+ const sessionRoots = ["C:\\Users\\sgerashe\\.selesai\\sessions", "D:\\work\\proj", 'C:\\has "quotes"\\dir'];
56
+ const encoded = encodeSessionRoots(sessionRoots);
57
+ const argv = runThroughPowerShell(echoArgvCommand(encoded));
58
+ const received = argv[argv.indexOf("--session-roots") + 1];
59
+ assert.equal(received, encoded);
60
+ assert.deepEqual(decodeSessionRoots(received ?? ""), sessionRoots);
61
+ });
62
+ });
63
+ });
@@ -11,8 +11,8 @@ describe("formatShellCommand on POSIX shells", () => {
11
11
 
12
12
  it("keeps a shell-safe executable bare so Nushell parses it as a command", () => {
13
13
  assert.equal(
14
- formatShellCommand("/usr/bin/node", ["/home/u/.pi/inspector-runner.mjs", "--async-dir", "/tmp/run-1|fc_abc"], platform),
15
- "/usr/bin/node '/home/u/.pi/inspector-runner.mjs' '--async-dir' '/tmp/run-1|fc_abc'",
14
+ formatShellCommand("/usr/bin/node", ["/home/u/.selesai/inspector-runner.mjs", "--async-dir", "/tmp/run-1|fc_abc"], platform),
15
+ "/usr/bin/node '/home/u/.selesai/inspector-runner.mjs' '--async-dir' '/tmp/run-1|fc_abc'",
16
16
  );
17
17
  });
18
18
 
@@ -4,6 +4,7 @@ import { describe, it } from "node:test";
4
4
  import {
5
5
  registerHerdrStatusBridge,
6
6
  type HerdrStatusBridgeEvents,
7
+ type HerdrStatusRun,
7
8
  } from "../../src/integrations/herdr-status.ts";
8
9
  import { projectActiveHerdrRuns } from "../../src/extension/index.ts";
9
10
  import type { SubagentState } from "../../src/shared/types.ts";
@@ -82,6 +83,7 @@ describe("Herdr status bridge", () => {
82
83
  status: "running",
83
84
  mode: "workflow",
84
85
  agents: ["workflow"],
86
+ steps: [{ agent: "reviewer", status: "running", label: "Review auth" }],
85
87
  });
86
88
  state.foregroundControls.set("child-1", {
87
89
  runId: "child-1",
@@ -102,10 +104,32 @@ describe("Herdr status bridge", () => {
102
104
  assert.deepEqual(projectActiveHerdrRuns(state), [{
103
105
  id: "workflow-1",
104
106
  agents: ["reviewer"],
107
+ taskLabel: "Review auth",
105
108
  needsAttention: true,
106
109
  }]);
107
110
  });
108
111
 
112
+ it("synchronizes runs discovered outside lifecycle events", async () => {
113
+ const events = new FakeEvents();
114
+ const commands: string[][] = [];
115
+ const bridge = registerHerdrStatusBridge({
116
+ events,
117
+ env: { HERDR_ENV: "1", HERDR_PANE_ID: "w1:p1" },
118
+ getRuns: () => [{ id: "restored-run", agent: "worker" }],
119
+ runHerdr: (args) => commands.push([...args]),
120
+ refreshMs: 0,
121
+ });
122
+ bridge.sessionStarted({ hasUI: true, runs: [] });
123
+
124
+ bridge.syncRuns();
125
+ await bridge.flush();
126
+
127
+ assert.equal(commands.length, 1);
128
+ assert.ok(commands[0]?.includes("summary=⏳ 1 subagent (worker)"));
129
+
130
+ bridge.dispose();
131
+ });
132
+
109
133
  it("reports an async run as visible and semantically busy", async () => {
110
134
  const events = new FakeEvents();
111
135
  const commands: string[][] = [];
@@ -428,6 +452,100 @@ describe("Herdr status bridge", () => {
428
452
  bridge.dispose();
429
453
  });
430
454
 
455
+ it("publishes bounded workflow labels without leaking raw prompts and restores the previous overlapping task", async () => {
456
+ const events = new FakeEvents();
457
+ const commands: string[][] = [];
458
+ const bridge = registerHerdrStatusBridge({
459
+ events,
460
+ env: { HERDR_ENV: "1", HERDR_PANE_ID: "w1:p1" },
461
+ runHerdr: (args) => commands.push([...args]),
462
+ refreshMs: 0,
463
+ });
464
+ bridge.sessionStarted({ hasUI: true, runs: [] });
465
+
466
+ events.emit(SUBAGENT_ASYNC_STARTED_EVENT, {
467
+ id: "run-1",
468
+ agent: "worker",
469
+ goal: "raw secret prompt",
470
+ workflowGraph: {
471
+ currentNodeId: "build",
472
+ nodes: [{ id: "build", status: "running", label: "Build auth\nflow\u001b[31m" }],
473
+ },
474
+ });
475
+ await bridge.flush();
476
+ events.emit(SUBAGENT_ASYNC_STARTED_EVENT, {
477
+ id: "run-2",
478
+ agent: "reviewer",
479
+ task: "another raw prompt",
480
+ workflowGraph: {
481
+ nodes: [{ id: "review", status: "pending", label: `Review ${"x".repeat(120)}` }],
482
+ },
483
+ });
484
+ await bridge.flush();
485
+ events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, { runId: "run-2" });
486
+ await bridge.flush();
487
+ events.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, { runId: "run-1" });
488
+ await bridge.flush();
489
+
490
+ assert.ok(commands[0]?.includes("summary=⏳ 1 subagent (worker) · Build auth flow"));
491
+ assert.ok(commands[0]?.includes("title-suffix=⏳Build auth flow"));
492
+ assert.ok(commands[1]?.some((argument) => argument.startsWith("summary=⏳ 2 subagents") && argument.length < 180));
493
+ assert.ok(commands[1]?.some((argument) => argument.startsWith("title-suffix=⏳Review ") && argument.length < 70));
494
+ assert.ok(commands[2]?.includes("title-suffix=⏳Build auth flow"));
495
+ assert.ok(commands[3]?.includes("--clear-state-labels"));
496
+ assert.doesNotMatch(commands.flat().join("\n"), /raw secret prompt|another raw prompt/);
497
+
498
+ bridge.dispose();
499
+ });
500
+
501
+ it("omits refreshed task labels when sanitization removes all content", async () => {
502
+ const events = new FakeEvents();
503
+ const commands: string[][] = [];
504
+ const bridge = registerHerdrStatusBridge({
505
+ events,
506
+ env: { HERDR_ENV: "1", HERDR_PANE_ID: "w1:p1" },
507
+ runHerdr: (args) => commands.push([...args]),
508
+ refreshMs: 0,
509
+ });
510
+
511
+ bridge.sessionStarted({ hasUI: true, runs: [{ id: "run-1", agent: "worker", taskLabel: "\u001b[31m" }] });
512
+ await bridge.flush();
513
+
514
+ assert.ok(commands[0]?.includes("summary=⏳ 1 subagent (worker)"));
515
+ assert.ok(commands[0]?.includes("title-suffix=⏳worker"));
516
+ assert.doesNotMatch(commands.flat().join("\n"), /\u001b\[31m/);
517
+
518
+ bridge.dispose();
519
+ });
520
+
521
+ it("clears a completed step label when the authoritative active step is unlabeled", async () => {
522
+ const events = new FakeEvents();
523
+ const commands: string[][] = [];
524
+ const intervals = new FakeIntervals();
525
+ let authoritativeRuns: HerdrStatusRun[] = [{ id: "run-1", agent: "worker", taskLabel: "Build auth" }];
526
+ const bridge = registerHerdrStatusBridge({
527
+ events,
528
+ env: { HERDR_ENV: "1", HERDR_PANE_ID: "w1:p1" },
529
+ getRuns: () => authoritativeRuns,
530
+ runHerdr: (args) => commands.push([...args]),
531
+ refreshMs: 45_000,
532
+ timers: intervals.timers,
533
+ });
534
+ bridge.sessionStarted({ hasUI: true, runs: authoritativeRuns });
535
+ await bridge.flush();
536
+
537
+ authoritativeRuns = [{ id: "run-1", agent: "worker" }];
538
+ intervals.fireAll();
539
+ await bridge.flush();
540
+
541
+ assert.ok(commands[0]?.includes("title-suffix=⏳Build auth"));
542
+ assert.ok(commands[1]?.includes("summary=⏳ 1 subagent (worker)"));
543
+ assert.ok(commands[1]?.includes("title-suffix=⏳worker"));
544
+ assert.doesNotMatch(commands[1]?.join("\n") ?? "", /Build auth/);
545
+
546
+ bridge.dispose();
547
+ });
548
+
431
549
  it("refreshes metadata only while runs are active", async () => {
432
550
  const events = new FakeEvents();
433
551
  const commands: string[][] = [];
@@ -533,10 +651,15 @@ describe("Herdr status bridge", () => {
533
651
  const events = new FakeEvents();
534
652
  const commands: string[][] = [];
535
653
  const busyEvents: unknown[] = [];
654
+ let getRunsCalls = 0;
536
655
  events.on("herdr:busy", (payload) => busyEvents.push(payload));
537
656
  const bridge = registerHerdrStatusBridge({
538
657
  events,
539
658
  env: { HERDR_ENV: "1", HERDR_PANE_ID: "w1:p1" },
659
+ getRuns: () => {
660
+ getRunsCalls += 1;
661
+ return [{ id: "run-authoritative", agent: "worker" }];
662
+ },
540
663
  runHerdr: (args) => commands.push([...args]),
541
664
  refreshMs: 0,
542
665
  });
@@ -549,10 +672,12 @@ describe("Herdr status bridge", () => {
549
672
 
550
673
  // A headless parent (print/json mode, or a test harness) must never publish.
551
674
  bridge.sessionStarted({ hasUI: false, runs: [{ id: "run-headless", agent: "worker" }] });
675
+ bridge.syncRuns();
552
676
  events.emit(SUBAGENT_ASYNC_STARTED_EVENT, { id: "run-1", agent: "worker" });
553
677
  await bridge.flush();
554
678
  assert.deepEqual(commands, []);
555
679
  assert.deepEqual(busyEvents, []);
680
+ assert.equal(getRunsCalls, 0);
556
681
 
557
682
  // Only the root interactive session owns the pane.
558
683
  bridge.sessionStarted({ hasUI: true, runs: [] });
@@ -568,19 +693,26 @@ describe("Herdr status bridge", () => {
568
693
  it("stays inert outside a Herdr pane", async () => {
569
694
  const events = new FakeEvents();
570
695
  const commands: string[][] = [];
696
+ let getRunsCalls = 0;
571
697
  const bridge = registerHerdrStatusBridge({
572
698
  events,
573
699
  env: {},
700
+ getRuns: () => {
701
+ getRunsCalls += 1;
702
+ return [{ id: "run-2", agent: "reviewer" }];
703
+ },
574
704
  runHerdr: (args) => commands.push([...args]),
575
705
  refreshMs: 0,
576
706
  });
577
707
 
578
708
  bridge.sessionStarted({ hasUI: true, runs: [{ id: "run-2", agent: "reviewer" }] });
709
+ bridge.syncRuns();
579
710
  events.emit(SUBAGENT_ASYNC_STARTED_EVENT, { id: "run-1", agent: "worker" });
580
711
  bridge.agentStarted();
581
712
  bridge.dispose();
582
713
  await bridge.flush();
583
714
 
584
715
  assert.deepEqual(commands, []);
716
+ assert.equal(getRunsCalls, 0);
585
717
  });
586
718
  });