@selesai/code 0.12.0 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (466) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/core/agent-session.d.ts +1 -1
  3. package/dist/core/agent-session.js +1 -1
  4. package/dist/core/sdk.d.ts +2 -2
  5. package/dist/core/sdk.js +1 -1
  6. package/dist/core/system-prompt.d.ts +1 -1
  7. package/dist/core/system-prompt.js +1 -1
  8. package/dist/core/usage-totals.d.ts +2 -0
  9. package/dist/core/usage-totals.js +10 -0
  10. package/dist/extensions/ascii.txt +9 -0
  11. package/dist/extensions/package.json +1 -2
  12. package/dist/extensions/pi-hermes-memory/CHANGELOG.md +371 -0
  13. package/dist/extensions/pi-hermes-memory/LICENSE +21 -0
  14. package/dist/extensions/pi-hermes-memory/README.md +643 -0
  15. package/dist/extensions/pi-hermes-memory/docs/0.1/TASKS.md +197 -0
  16. package/dist/extensions/pi-hermes-memory/docs/0.2/PLAN.md +290 -0
  17. package/dist/extensions/pi-hermes-memory/docs/0.2/TASKS.md +134 -0
  18. package/dist/extensions/pi-hermes-memory/docs/0.2/TEST-PLAN.md +216 -0
  19. package/dist/extensions/pi-hermes-memory/docs/0.3/PLAN.md +330 -0
  20. package/dist/extensions/pi-hermes-memory/docs/0.3/TASKS.md +125 -0
  21. package/dist/extensions/pi-hermes-memory/docs/0.4/PLAN.md +160 -0
  22. package/dist/extensions/pi-hermes-memory/docs/0.4/TASKS.md +113 -0
  23. package/dist/extensions/pi-hermes-memory/docs/0.6/CHANGELOG.md +57 -0
  24. package/dist/extensions/pi-hermes-memory/docs/0.6/PLAN.md +202 -0
  25. package/dist/extensions/pi-hermes-memory/docs/0.6/TASKS.md +144 -0
  26. package/dist/extensions/pi-hermes-memory/docs/0.7/PLAN.md +349 -0
  27. package/dist/extensions/pi-hermes-memory/docs/0.7/TASKS.md +110 -0
  28. package/dist/extensions/pi-hermes-memory/docs/PUBLISHING.md +149 -0
  29. package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +468 -0
  30. package/dist/extensions/pi-hermes-memory/docs/images/memory-architecture.svg +1 -0
  31. package/dist/extensions/pi-hermes-memory/docs/images/pi-logo.svg +22 -0
  32. package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.png +0 -0
  33. package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.svg +19 -0
  34. package/dist/extensions/pi-hermes-memory/docs/images/security-flow.svg +1 -0
  35. package/dist/extensions/pi-hermes-memory/docs/images/session-lifecycle.svg +1 -0
  36. package/dist/extensions/pi-hermes-memory/docs/images/source-architecture.svg +1 -0
  37. package/dist/extensions/pi-hermes-memory/docs/mermaid/memory-architecture.mmd +49 -0
  38. package/dist/extensions/pi-hermes-memory/docs/mermaid/security-flow.mmd +40 -0
  39. package/dist/extensions/pi-hermes-memory/docs/mermaid/session-lifecycle.mmd +56 -0
  40. package/dist/extensions/pi-hermes-memory/docs/mermaid/source-architecture.mmd +54 -0
  41. package/dist/extensions/pi-hermes-memory/package-lock.json +3799 -0
  42. package/dist/extensions/pi-hermes-memory/package.json +66 -0
  43. package/dist/extensions/pi-hermes-memory/scripts/check-min-sdk.mjs +99 -0
  44. package/dist/extensions/pi-hermes-memory/scripts/ensure-dev.mjs +57 -0
  45. package/dist/extensions/pi-hermes-memory/src/auto-consolidation-warning.ts +6 -0
  46. package/dist/extensions/pi-hermes-memory/src/config.ts +178 -0
  47. package/dist/extensions/pi-hermes-memory/src/constants.ts +424 -0
  48. package/dist/extensions/pi-hermes-memory/src/extension-root-migration.ts +639 -0
  49. package/dist/extensions/pi-hermes-memory/src/handlers/auto-consolidate.ts +401 -0
  50. package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +297 -0
  51. package/dist/extensions/pi-hermes-memory/src/handlers/child-process-watchdog.mjs +90 -0
  52. package/dist/extensions/pi-hermes-memory/src/handlers/correction-detector.ts +300 -0
  53. package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +86 -0
  54. package/dist/extensions/pi-hermes-memory/src/handlers/insights.ts +78 -0
  55. package/dist/extensions/pi-hermes-memory/src/handlers/interview.ts +37 -0
  56. package/dist/extensions/pi-hermes-memory/src/handlers/learn-memory.ts +186 -0
  57. package/dist/extensions/pi-hermes-memory/src/handlers/message-parts.ts +27 -0
  58. package/dist/extensions/pi-hermes-memory/src/handlers/pi-child-process.ts +485 -0
  59. package/dist/extensions/pi-hermes-memory/src/handlers/preview-context.ts +105 -0
  60. package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +506 -0
  61. package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +145 -0
  62. package/dist/extensions/pi-hermes-memory/src/handlers/session-flush.ts +151 -0
  63. package/dist/extensions/pi-hermes-memory/src/handlers/session-live-index.ts +94 -0
  64. package/dist/extensions/pi-hermes-memory/src/handlers/skills-command.ts +1334 -0
  65. package/dist/extensions/pi-hermes-memory/src/handlers/standing-pin.ts +111 -0
  66. package/dist/extensions/pi-hermes-memory/src/handlers/switch-project.ts +75 -0
  67. package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +266 -0
  68. package/dist/extensions/pi-hermes-memory/src/index.ts +378 -0
  69. package/dist/extensions/pi-hermes-memory/src/lifecycle-timing.ts +54 -0
  70. package/dist/extensions/pi-hermes-memory/src/paths.ts +61 -0
  71. package/dist/extensions/pi-hermes-memory/src/project-context.ts +13 -0
  72. package/dist/extensions/pi-hermes-memory/src/project-memory-migration.ts +93 -0
  73. package/dist/extensions/pi-hermes-memory/src/project.ts +157 -0
  74. package/dist/extensions/pi-hermes-memory/src/prompt-context.ts +55 -0
  75. package/dist/extensions/pi-hermes-memory/src/store/atomic-lock-coordinator.ts +375 -0
  76. package/dist/extensions/pi-hermes-memory/src/store/canonical-storage-path.ts +54 -0
  77. package/dist/extensions/pi-hermes-memory/src/store/content-scanner.ts +101 -0
  78. package/dist/extensions/pi-hermes-memory/src/store/db.ts +1180 -0
  79. package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +101 -0
  80. package/dist/extensions/pi-hermes-memory/src/store/markdown-mutation-lock.ts +38 -0
  81. package/dist/extensions/pi-hermes-memory/src/store/memory-lookup.ts +24 -0
  82. package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +1191 -0
  83. package/dist/extensions/pi-hermes-memory/src/store/recovery-maintenance.ts +66 -0
  84. package/dist/extensions/pi-hermes-memory/src/store/schema.ts +118 -0
  85. package/dist/extensions/pi-hermes-memory/src/store/session-anchor-search.ts +472 -0
  86. package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +511 -0
  87. package/dist/extensions/pi-hermes-memory/src/store/session-parser.ts +213 -0
  88. package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +234 -0
  89. package/dist/extensions/pi-hermes-memory/src/store/skill-store.ts +950 -0
  90. package/dist/extensions/pi-hermes-memory/src/store/skill-utils.ts +133 -0
  91. package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +1002 -0
  92. package/dist/extensions/pi-hermes-memory/src/store/sqlite-native.ts +241 -0
  93. package/dist/extensions/pi-hermes-memory/src/store/standing-instructions.ts +247 -0
  94. package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +95 -0
  95. package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +469 -0
  96. package/dist/extensions/pi-hermes-memory/src/tools/session-search-tool.ts +246 -0
  97. package/dist/extensions/pi-hermes-memory/src/tools/shared-output-view.ts +170 -0
  98. package/dist/extensions/pi-hermes-memory/src/tools/skill-tool.ts +333 -0
  99. package/dist/extensions/pi-hermes-memory/src/tools/tool-result-views.ts +105 -0
  100. package/dist/extensions/pi-hermes-memory/src/types.ts +214 -0
  101. package/dist/extensions/pi-hermes-memory/tests/config.test.ts +434 -0
  102. package/dist/extensions/pi-hermes-memory/tests/extension-root-migration.test.ts +368 -0
  103. package/dist/extensions/pi-hermes-memory/tests/handlers/auto-consolidate.test.ts +984 -0
  104. package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +950 -0
  105. package/dist/extensions/pi-hermes-memory/tests/handlers/correction-detector.test.ts +671 -0
  106. package/dist/extensions/pi-hermes-memory/tests/handlers/insights.test.ts +157 -0
  107. package/dist/extensions/pi-hermes-memory/tests/handlers/interview.test.ts +127 -0
  108. package/dist/extensions/pi-hermes-memory/tests/handlers/pi-child-process.test.ts +905 -0
  109. package/dist/extensions/pi-hermes-memory/tests/handlers/preview-context.test.ts +152 -0
  110. package/dist/extensions/pi-hermes-memory/tests/handlers/prompt-context.test.ts +166 -0
  111. package/dist/extensions/pi-hermes-memory/tests/handlers/resources-discover.test.ts +71 -0
  112. package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +614 -0
  113. package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +192 -0
  114. package/dist/extensions/pi-hermes-memory/tests/handlers/session-flush.test.ts +677 -0
  115. package/dist/extensions/pi-hermes-memory/tests/handlers/session-live-index.test.ts +225 -0
  116. package/dist/extensions/pi-hermes-memory/tests/handlers/skills-command.test.ts +827 -0
  117. package/dist/extensions/pi-hermes-memory/tests/handlers/standing-pin.test.ts +134 -0
  118. package/dist/extensions/pi-hermes-memory/tests/handlers/sync-markdown-memories.test.ts +491 -0
  119. package/dist/extensions/pi-hermes-memory/tests/handlers/system-prompt.test.ts +199 -0
  120. package/dist/extensions/pi-hermes-memory/tests/handlers/thinking-max.test.ts +64 -0
  121. package/dist/extensions/pi-hermes-memory/tests/index.test.ts +30 -0
  122. package/dist/extensions/pi-hermes-memory/tests/integration/flow.test.ts +126 -0
  123. package/dist/extensions/pi-hermes-memory/tests/lifecycle-timing.test.ts +76 -0
  124. package/dist/extensions/pi-hermes-memory/tests/paths.test.ts +23 -0
  125. package/dist/extensions/pi-hermes-memory/tests/project-memory-migration.test.ts +80 -0
  126. package/dist/extensions/pi-hermes-memory/tests/project-rebinding.test.ts +115 -0
  127. package/dist/extensions/pi-hermes-memory/tests/project.test.ts +120 -0
  128. package/dist/extensions/pi-hermes-memory/tests/run-all-timeout.test.ts +107 -0
  129. package/dist/extensions/pi-hermes-memory/tests/run-all.sh +45 -0
  130. package/dist/extensions/pi-hermes-memory/tests/store/atomic-lock-coordinator.test.ts +381 -0
  131. package/dist/extensions/pi-hermes-memory/tests/store/content-scanner.test.ts +388 -0
  132. package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +1046 -0
  133. package/dist/extensions/pi-hermes-memory/tests/store/markdown-mutation-lock.test.ts +34 -0
  134. package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +2150 -0
  135. package/dist/extensions/pi-hermes-memory/tests/store/recovery-maintenance.test.ts +170 -0
  136. package/dist/extensions/pi-hermes-memory/tests/store/session-anchor-search.test.ts +210 -0
  137. package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +643 -0
  138. package/dist/extensions/pi-hermes-memory/tests/store/session-parser.test.ts +282 -0
  139. package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +287 -0
  140. package/dist/extensions/pi-hermes-memory/tests/store/skill-store.test.ts +678 -0
  141. package/dist/extensions/pi-hermes-memory/tests/store/skill-utils.test.ts +21 -0
  142. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-lazy-load.test.ts +78 -0
  143. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +543 -0
  144. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +164 -0
  145. package/dist/extensions/pi-hermes-memory/tests/store/standing-instructions.test.ts +171 -0
  146. package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +84 -0
  147. package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +709 -0
  148. package/dist/extensions/pi-hermes-memory/tests/tools/session-search-tool.test.ts +345 -0
  149. package/dist/extensions/pi-hermes-memory/tests/tools/shared-output-view.test.ts +362 -0
  150. package/dist/extensions/pi-hermes-memory/tests/tools/skill-tool.test.ts +478 -0
  151. package/dist/extensions/pi-hermes-memory/tests/tools/tool-result-renderer-wiring.test.ts +40 -0
  152. package/dist/extensions/pi-hermes-memory/tsconfig.json +19 -0
  153. package/dist/extensions/pi-subagents/.oxlintrc.json +43 -0
  154. package/dist/extensions/pi-subagents/AGENTS.md +5 -0
  155. package/dist/extensions/pi-subagents/CHANGELOG.md +157 -0
  156. package/dist/extensions/pi-subagents/README.md +12 -6
  157. package/dist/extensions/pi-subagents/VISION.md +81 -0
  158. package/dist/extensions/pi-subagents/agents/claude-code-writer.md +15 -0
  159. package/dist/extensions/pi-subagents/agents/claude-code.md +15 -0
  160. package/dist/extensions/pi-subagents/agents/codex-exec-writer.md +15 -0
  161. package/dist/extensions/pi-subagents/agents/codex-exec.md +15 -0
  162. package/dist/extensions/pi-subagents/agents/cursor-agent-writer.md +14 -0
  163. package/dist/extensions/pi-subagents/agents/cursor-agent.md +14 -0
  164. package/dist/extensions/pi-subagents/agents/reviewer.md +1 -3
  165. package/dist/extensions/pi-subagents/docs/agents.md +488 -0
  166. package/dist/extensions/pi-subagents/docs/configuration.md +46 -9
  167. package/dist/extensions/pi-subagents/docs/extension-api.md +42 -3
  168. package/dist/extensions/pi-subagents/docs/models.md +27 -4
  169. package/dist/extensions/pi-subagents/docs/observability.md +10 -9
  170. package/dist/extensions/pi-subagents/docs/tool-reference.md +102 -6
  171. package/dist/extensions/pi-subagents/docs/workflows.md +135 -0
  172. package/dist/extensions/pi-subagents/package-lock.json +389 -2
  173. package/dist/extensions/pi-subagents/package.json +3 -1
  174. package/dist/extensions/pi-subagents/prompts/review-loop.md +2 -2
  175. package/dist/extensions/pi-subagents/skills/council-mode/SKILL.md +1 -1
  176. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +3 -1
  177. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +7 -3
  178. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
  179. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +26 -5
  180. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +41 -22
  181. package/dist/extensions/pi-subagents/src/agents/agent-refinements.ts +4 -4
  182. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +9 -2
  183. package/dist/extensions/pi-subagents/src/agents/agents.ts +322 -75
  184. package/dist/extensions/pi-subagents/src/agents/builtin-names.ts +6 -0
  185. package/dist/extensions/pi-subagents/src/agents/runtime-agent-events.ts +70 -0
  186. package/dist/extensions/pi-subagents/src/agents/runtime-agent-registry.ts +27 -20
  187. package/dist/extensions/pi-subagents/src/api/agents.ts +10 -5
  188. package/dist/extensions/pi-subagents/src/api/background-work.ts +5 -1
  189. package/dist/extensions/pi-subagents/src/api/delegation.ts +0 -7
  190. package/dist/extensions/pi-subagents/src/api/preflight.ts +34 -12
  191. package/dist/extensions/pi-subagents/src/extension/config.ts +70 -0
  192. package/dist/extensions/pi-subagents/src/extension/doctor.ts +3 -3
  193. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +5 -3
  194. package/dist/extensions/pi-subagents/src/extension/index.ts +83 -30
  195. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +44 -15
  196. package/dist/extensions/pi-subagents/src/extension/rpc.ts +55 -19
  197. package/dist/extensions/pi-subagents/src/extension/schemas.ts +41 -15
  198. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -31
  199. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +2 -1
  200. package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +2 -10
  201. package/dist/extensions/pi-subagents/src/inspectors/herdr/session-roots-codec.ts +42 -0
  202. package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +51 -3
  203. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +2 -0
  204. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +5 -6
  205. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +77 -10
  206. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +176 -53
  207. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +19 -12
  208. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +29 -27
  209. package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +20 -3
  210. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +23 -261
  211. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +73 -7
  212. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +8 -3
  213. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +74 -8
  214. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +37 -21
  215. package/dist/extensions/pi-subagents/src/runs/background/inspect-rpc.ts +8 -8
  216. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +184 -9
  217. package/dist/extensions/pi-subagents/src/runs/background/result-delivery-ownership.ts +45 -0
  218. package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +28 -14
  219. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +38 -15
  220. package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +1 -1
  221. package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +1 -1
  222. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +50 -13
  223. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +93 -8
  224. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +10 -4
  225. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +4 -14
  226. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +549 -377
  227. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +58 -10
  228. package/dist/extensions/pi-subagents/src/runs/background/terminal-run-index.ts +1 -1
  229. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +26 -1
  230. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +23 -9
  231. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +9 -2
  232. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +2 -2
  233. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +204 -129
  234. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +9 -0
  235. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +23 -1
  236. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +773 -311
  237. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +140 -115
  238. package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +119 -0
  239. package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +463 -0
  240. package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +19 -4
  241. package/dist/extensions/pi-subagents/src/runs/shared/child-launch-plan.ts +151 -0
  242. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +21 -7
  243. package/dist/extensions/pi-subagents/src/runs/shared/claude-code-adapter.ts +129 -0
  244. package/dist/extensions/pi-subagents/src/runs/shared/codex-exec-adapter.ts +129 -0
  245. package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +89 -0
  246. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +5 -4
  247. package/dist/extensions/pi-subagents/src/runs/shared/cursor-agent-adapter.ts +114 -0
  248. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +3 -3
  249. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-contract.ts +167 -0
  250. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +122 -0
  251. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +348 -55
  252. package/dist/extensions/pi-subagents/src/runs/shared/fast-mode-extension.ts +5 -5
  253. package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +230 -0
  254. package/dist/extensions/pi-subagents/src/runs/shared/lane-metadata.ts +105 -0
  255. package/dist/extensions/pi-subagents/src/runs/shared/launch-cwd.ts +16 -0
  256. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +2 -1
  257. package/dist/extensions/pi-subagents/src/runs/shared/mcp-config-sources.ts +422 -0
  258. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +221 -158
  259. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-grant.ts +197 -0
  260. package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +69 -7
  261. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +47 -6
  262. package/dist/extensions/pi-subagents/src/runs/shared/mutation-evidence.ts +7 -2
  263. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +9 -3
  264. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +9 -5
  265. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +419 -7
  266. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +15 -1
  267. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +81 -8
  268. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +13 -0
  269. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +21 -1
  270. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +44 -4
  271. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +98 -13
  272. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +1 -1
  273. package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +847 -0
  274. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +18 -0
  275. package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +46 -0
  276. package/dist/extensions/pi-subagents/src/shared/extension-context.ts +24 -0
  277. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +21 -0
  278. package/dist/extensions/pi-subagents/src/shared/formatters.ts +18 -3
  279. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +5 -1
  280. package/dist/extensions/pi-subagents/src/shared/pruned-fork.ts +450 -0
  281. package/dist/extensions/pi-subagents/src/shared/session-file-trust.ts +19 -0
  282. package/dist/extensions/pi-subagents/src/shared/session-tokens.ts +14 -3
  283. package/dist/extensions/pi-subagents/src/shared/settings.ts +19 -105
  284. package/dist/extensions/pi-subagents/src/shared/shortcuts.ts +17 -0
  285. package/dist/extensions/pi-subagents/src/shared/types.ts +359 -40
  286. package/dist/extensions/pi-subagents/src/shared/utils.ts +41 -84
  287. package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +116 -0
  288. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +1 -9
  289. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +0 -4
  290. package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +1 -2
  291. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +378 -88
  292. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +22 -11
  293. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +3 -0
  294. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +147 -79
  295. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +11 -5
  296. package/dist/extensions/pi-subagents/src/tui/fleet.ts +39 -18
  297. package/dist/extensions/pi-subagents/src/tui/render.ts +369 -46
  298. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +1 -1
  299. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +6 -3
  300. package/dist/extensions/pi-subagents/src/workflows/host-command.ts +230 -0
  301. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +740 -58
  302. package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +121 -0
  303. package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +270 -0
  304. package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +195 -6
  305. package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +246 -0
  306. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
  307. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1114 -260
  308. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +34 -0
  309. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +150 -3
  310. package/dist/extensions/pi-subagents/test/integration/claude-code-smoke.test.ts +52 -0
  311. package/dist/extensions/pi-subagents/test/integration/claude-code-writer-smoke.test.ts +55 -0
  312. package/dist/extensions/pi-subagents/test/integration/codex-exec-smoke.test.ts +53 -0
  313. package/dist/extensions/pi-subagents/test/integration/codex-exec-writer-smoke.test.ts +57 -0
  314. package/dist/extensions/pi-subagents/test/integration/cursor-agent-smoke.test.ts +59 -0
  315. package/dist/extensions/pi-subagents/test/integration/cursor-agent-writer-smoke.test.ts +62 -0
  316. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +57 -1
  317. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
  318. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +20 -0
  319. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +4 -3
  320. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +2 -2
  321. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +54 -4
  322. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +482 -4
  323. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +157 -9
  324. package/dist/extensions/pi-subagents/test/integration/session-tokens.test.ts +5 -5
  325. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1508 -291
  326. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +423 -1
  327. package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +8 -0
  328. package/dist/extensions/pi-subagents/test/support/cursor-smoke-inputs.ts +51 -0
  329. package/dist/extensions/pi-subagents/test/support/helpers.ts +2 -0
  330. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +5 -5
  331. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +6 -6
  332. package/dist/extensions/pi-subagents/test/unit/abort-recovery.test.ts +152 -0
  333. package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +48 -0
  334. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +184 -6
  335. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +66 -6
  336. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +77 -0
  337. package/dist/extensions/pi-subagents/test/unit/agent-refinements.test.ts +18 -0
  338. package/dist/extensions/pi-subagents/test/unit/anti-slop-oxlint.test.ts +86 -0
  339. package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +1 -1
  340. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +101 -1
  341. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +121 -0
  342. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +28 -0
  343. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +14 -7
  344. package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +53 -0
  345. package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +190 -0
  346. package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +42 -0
  347. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +8 -4
  348. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +23 -0
  349. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +78 -1
  350. package/dist/extensions/pi-subagents/test/unit/child-launch-plan.test.ts +94 -0
  351. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +21 -0
  352. package/dist/extensions/pi-subagents/test/unit/child-session-name.test.ts +50 -0
  353. package/dist/extensions/pi-subagents/test/unit/claude-code-adapter.test.ts +245 -0
  354. package/dist/extensions/pi-subagents/test/unit/codex-exec-adapter.test.ts +192 -0
  355. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +27 -0
  356. package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +150 -0
  357. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +21 -0
  358. package/dist/extensions/pi-subagents/test/unit/cursor-agent-adapter.test.ts +259 -0
  359. package/dist/extensions/pi-subagents/test/unit/cursor-smoke-inputs.test.ts +77 -0
  360. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +1 -4
  361. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
  362. package/dist/extensions/pi-subagents/test/unit/extension-context.test.ts +27 -0
  363. package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +223 -0
  364. package/dist/extensions/pi-subagents/test/unit/fast-mode-extension.test.ts +27 -0
  365. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +208 -2
  366. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +29 -1
  367. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +110 -1
  368. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +10 -0
  369. package/dist/extensions/pi-subagents/test/unit/formatters.test.ts +14 -0
  370. package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +18 -9
  371. package/dist/extensions/pi-subagents/test/unit/herdr-session-roots-codec.test.ts +63 -0
  372. package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +2 -2
  373. package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +132 -0
  374. package/dist/extensions/pi-subagents/test/unit/host-command.test.ts +156 -0
  375. package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +98 -0
  376. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +178 -26
  377. package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +2 -1
  378. package/dist/extensions/pi-subagents/test/unit/inspect-rpc.test.ts +21 -0
  379. package/dist/extensions/pi-subagents/test/unit/mcp-direct-tool-grant.test.ts +138 -0
  380. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
  381. package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +91 -0
  382. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +72 -7
  383. package/dist/extensions/pi-subagents/test/unit/mutation-evidence.test.ts +21 -0
  384. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +1 -0
  385. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +20 -2
  386. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +129 -1
  387. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +2 -2
  388. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +4 -0
  389. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +358 -0
  390. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +574 -21
  391. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +109 -1
  392. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +71 -1
  393. package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +7 -7
  394. package/dist/extensions/pi-subagents/test/unit/pruned-fork.test.ts +214 -0
  395. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +29 -8
  396. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +53 -0
  397. package/dist/extensions/pi-subagents/test/unit/result-delivery-ownership.test.ts +34 -0
  398. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +101 -3
  399. package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +1 -0
  400. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +10 -8
  401. package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +71 -1
  402. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +41 -7
  403. package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +136 -2
  404. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +137 -0
  405. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +33 -12
  406. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +504 -1
  407. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +8 -0
  408. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  409. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +12 -1
  410. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +3 -5
  411. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +5 -6
  412. package/dist/extensions/pi-subagents/test/unit/subagent-action-recovery.test.ts +0 -8
  413. package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +5 -0
  414. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +157 -2
  415. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +1 -1
  416. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +63 -4
  417. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +27 -23
  418. package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +44 -0
  419. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +1 -0
  420. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +7 -5
  421. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +106 -0
  422. package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +484 -9
  423. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +38 -4
  424. package/dist/extensions/pi-subagents/test/unit/workflow-preflight.test.ts +155 -0
  425. package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +318 -0
  426. package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +365 -0
  427. package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +349 -0
  428. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +21 -0
  429. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +2 -7
  430. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/index.ts +13 -0
  431. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/rules/no-service-constructor-imports.ts +52 -0
  432. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/index.ts +41 -0
  433. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-chained-type-assertions.ts +77 -0
  434. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-conditional-empty-object-spread.ts +49 -0
  435. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-known-value-widening.ts +247 -0
  436. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-module-mocking.ts +91 -0
  437. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-object-parameters.ts +126 -0
  438. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-apply.ts +28 -0
  439. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-get.ts +28 -0
  440. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-runtime-typeof.ts +67 -0
  441. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-shape-in-symbol-names.ts +39 -0
  442. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-parameters.ts +83 -0
  443. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-returns.ts +115 -0
  444. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-type-aliases.ts +72 -0
  445. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unsafe-dictionary-type.ts +134 -0
  446. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-widen-then-assert.ts +366 -0
  447. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/require-safety-comment-for-type-assertion.ts +62 -0
  448. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/dictionary-types.ts +502 -0
  449. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/lexical-type-parameters.ts +60 -0
  450. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/reflect-method.ts +35 -0
  451. package/dist/extensions/pi-tool-display/tests/capabilities.test.ts +1 -1
  452. package/dist/extensions/pi-tool-display/tests/settings-inspector.test.ts +2 -2
  453. package/dist/extensions/pi-tool-display/tests/tool-overrides-mcp.test.ts +1 -1
  454. package/dist/extensions/pi-zentui/extensions/zentui/format.ts +2 -1
  455. package/dist/extensions/pi-zentui/test/format.test.ts +15 -1
  456. package/dist/modes/interactive/components/footer.js +2 -2
  457. package/dist/modes/interactive/interactive-mode.js +11 -11
  458. package/dist/skills/workflow/SKILL.md +65 -50
  459. package/package.json +112 -110
  460. package/dist/extensions/enable-readonly-tools.test.ts +0 -63
  461. package/dist/extensions/enable-readonly-tools.ts +0 -24
  462. package/dist/extensions/model-prompt-injector/config.json +0 -16
  463. package/dist/extensions/model-prompt-injector/index.test.ts +0 -102
  464. package/dist/extensions/model-prompt-injector/index.ts +0 -148
  465. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +0 -98
  466. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +0 -250
@@ -9,7 +9,7 @@
9
9
  * Toggle: async parameter (default: true; set asyncByDefault:false in config.json to opt out)
10
10
  *
11
11
  * Config file: ~/.selesai/agent/extensions/subagent/config.json
12
- * { "asyncByDefault": true, "defaultSubagentContext": "fork", "forceTopLevelAsync": true, "maxSubagentDepth": 1, "intercomBridge": { "mode": "always", "instructionFile": "./intercom-bridge.md" }, "worktreeSetupHook": "./scripts/setup-worktree.mjs" }
12
+ * { "asyncByDefault": true, "defaultSubagentContext": "fork", "forkContext": { "mode": "pruned", "model": "provider/model" }, "forceTopLevelAsync": true, "maxSubagentDepth": 1, "intercomBridge": { "mode": "always", "instructionFile": "./intercom-bridge.md" }, "worktreeSetupHook": "./scripts/setup-worktree.mjs" }
13
13
  */
14
14
 
15
15
  import { randomUUID } from "node:crypto";
@@ -21,9 +21,12 @@ import { keyText, type ExtensionAPI, type ExtensionContext, type ToolDefinition
21
21
  import { Box, Container, Spacer, Text, truncateToWidth, visibleWidth, wrapTextWithAnsi, type Component } from "@earendil-works/pi-tui";
22
22
  import { discoverAgents, discoverAgentsAll, type AgentConfig, type AgentScope } from "../agents/agents.ts";
23
23
  import { clearRuntimeAgentsForPi, listRuntimeAgentConfigs, mergeRuntimeAgents } from "../agents/runtime-agent-registry.ts";
24
+ import { registerRuntimeAgentEventListener } from "../agents/runtime-agent-events.ts";
24
25
  import { ensureAccessibleDir } from "../shared/accessible-dir.ts";
25
26
  import { cleanupAllArtifactDirs, cleanupOldArtifacts, getArtifactsDir } from "../shared/artifacts.ts";
26
27
  import { resolveCurrentSessionId } from "../shared/session-identity.ts";
28
+ import { getAgentDir } from "../shared/utils.ts";
29
+ import { isStaleExtensionContextError, withCachedUiContext } from "../shared/extension-context.ts";
27
30
  import { currentCompletionOwnerId } from "../shared/completion-owner.ts";
28
31
  import { cleanupOldChainDirs } from "../shared/settings.ts";
29
32
  import { clearLegacyResultAnimationTimer, renderSubagentResult, renderSubagentSummary } from "../tui/render.ts";
@@ -32,10 +35,11 @@ import { SubagentFleetStatus, resolveFleetViewPlacement } from "../tui/fleet-sta
32
35
  import { createSubagentParamsSchema } from "./schemas.ts";
33
36
  import { createSubagentExecutor, type SubagentParamsLike } from "../runs/foreground/subagent-executor.ts";
34
37
  import { createAsyncJobTracker } from "../runs/background/async-job-tracker.ts";
35
- import { getActiveAsyncCapacitySnapshot, resolveMaxActiveAsyncRunsPerSession } from "../runs/background/active-async-capacity.ts";
38
+ import { getActiveAsyncCapacitySnapshot, resolveAbandonedSlotReleaseAfterMs, resolveMaxActiveAsyncRunsPerSession } from "../runs/background/active-async-capacity.ts";
36
39
  import { cleanupResultIndexes, missionObserverResultCandidateFiles } from "../runs/background/result-files.ts";
37
40
  import { ASYNC_RETENTION_DELAY_MS, cleanupAsyncRetention } from "../runs/background/async-retention.ts";
38
41
  import { createResultWatcher } from "../runs/background/result-watcher.ts";
42
+ import { createResultDeliveryOwnership } from "../runs/background/result-delivery-ownership.ts";
39
43
  import { createScheduledRunManager } from "../runs/background/scheduled-runs.ts";
40
44
  import { registerSlashCommands } from "../slash/slash-commands.ts";
41
45
  import { registerPromptTemplateDelegationBridge } from "../slash/prompt-template-bridge.ts";
@@ -46,7 +50,6 @@ import { registerHerdrStatusBridge, type HerdrStatusRun } from "../integrations/
46
50
  import { listHerdrProjectPaneRoots, restoreHerdrProjectPaneSnapshots } from "../inspectors/herdr/project-panes.ts";
47
51
  import { registerSubagentRpcBridge } from "./rpc.ts";
48
52
  import { clearSlashSnapshots, getSlashRenderableSnapshot, resolveSlashMessageDetails, restoreSlashFinalSnapshots, type SlashMessageDetails } from "../slash/slash-live-state.ts";
49
- import { inspectSubagentStatus } from "../runs/background/run-status.ts";
50
53
  import { resolveWaitToolConfig } from "../runs/background/subagent-wait.ts";
51
54
  import { registerWaitTool } from "../runs/background/wait-tool.ts";
52
55
  import { createWaitSubscriptionManager } from "../runs/background/wait-subscriptions.ts";
@@ -56,8 +59,9 @@ import { formatSteeringNotice, handleSubagentSteeringNotice, SUBAGENT_STEERING_M
56
59
  import { SUBAGENT_CHILD_ENV, SUBAGENT_PARENT_SESSION_ENV } from "../runs/shared/pi-args.ts";
57
60
  import { resolveCurrentSubagentCapabilityCeiling } from "../runs/shared/capability-ceiling.ts";
58
61
  import { formatDuration, shortenPath } from "../shared/formatters.ts";
59
- import { loadConfig, resolveAsyncByDefault, resolveScheduledStoreRoot } from "./config.ts";
62
+ import { applyModelExclusionsConfig, loadConfig, resolveAsyncByDefault, resolveScheduledStoreRoot } from "./config.ts";
60
63
  import { buildSubagentToolDescription, buildSubagentToolPromptMetadata } from "./tool-description.ts";
64
+ import { formatWorkflowPreflightSummary, normalizeWorkflowPreflight } from "../workflows/workflow-preflight.ts";
61
65
  import { finalizeToolResult } from "./tool-result.ts";
62
66
  import { collectGoalContinuationNotices } from "../missions/goal-driver.ts";
63
67
  import { restoreForegroundRunHistory } from "../runs/foreground/foreground-history.ts";
@@ -248,15 +252,25 @@ function workflowLaneKeys(script: string): string[] {
248
252
  return keys;
249
253
  }
250
254
 
251
- function formatWorkflowManifest(script: string, async: unknown, clarify: unknown): string {
255
+ function formatWorkflowPreflightCall(input: unknown): string {
256
+ if (input === undefined) return "";
257
+ try {
258
+ return formatWorkflowPreflightSummary(normalizeWorkflowPreflight(input));
259
+ } catch (error) {
260
+ return `preflight · rejected: ${error instanceof Error ? error.message : String(error)}`;
261
+ }
262
+ }
263
+
264
+ function formatWorkflowManifest(script: string, async: unknown, clarify: unknown, preflightInput?: unknown): string {
252
265
  if (clarify === true) return "workflow script · rejected: clarify UI unsupported";
253
266
  const keys = workflowLaneKeys(script);
254
267
  // The workflow executor starts background work unless callers pass async:false.
255
268
  const mode = async === false ? "foreground" : "background";
256
- if (keys.length === 0) return `workflow script · ${mode}`;
269
+ const preflight = formatWorkflowPreflightCall(preflightInput);
270
+ if (keys.length === 0) return `workflow script · ${mode}${preflight ? ` · ${preflight}` : ""}`;
257
271
  const visibleKeys = keys.slice(0, 4).join(", ");
258
272
  const remainder = keys.length > 4 ? `, +${keys.length - 4}` : "";
259
- return `workflow · ${mode} · ${keys.length} lane${keys.length === 1 ? "" : "s"}: ${visibleKeys}${remainder}`;
273
+ return `workflow · ${mode} · ${keys.length} lane${keys.length === 1 ? "" : "s"}: ${visibleKeys}${remainder}${preflight ? ` · ${preflight}` : ""}`;
260
274
  }
261
275
 
262
276
  /**
@@ -289,10 +303,6 @@ function isSlashResultError(result: { details?: Details }): boolean {
289
303
  return result.details?.results.some((entry) => entry.exitCode !== 0 && entry.progress?.status !== "running") || false;
290
304
  }
291
305
 
292
- function isStaleExtensionContextError(error: unknown): boolean {
293
- return error instanceof Error && error.message.includes("Extension context no longer active");
294
- }
295
-
296
306
  function rebuildSlashResultContainer(
297
307
  container: Container,
298
308
  result: AgentToolResult<Details>,
@@ -382,9 +392,13 @@ export function projectActiveHerdrRuns(state: SubagentState): HerdrStatusRun[] {
382
392
  .filter((job) => active(job.status))
383
393
  .map((job) => {
384
394
  const children = job.mode === "workflow" ? foregroundChildrenByWorkflow.get(job.asyncId) : undefined;
395
+ const currentStep = job.steps?.find((step) => step.status === "running")
396
+ ?? (job.currentStep !== undefined ? job.steps?.[job.currentStep] : undefined)
397
+ ?? job.steps?.find((step) => step.status === "pending");
385
398
  return {
386
399
  id: job.asyncId,
387
400
  agents: children?.length ? children.map((child) => child.agent) : job.agents,
401
+ ...(currentStep?.label ? { taskLabel: currentStep.label } : {}),
388
402
  needsAttention: job.activityState === "needs_attention" || children?.some((child) => child.needsAttention),
389
403
  };
390
404
  });
@@ -401,6 +415,8 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
401
415
  cleanupOldChainDirs();
402
416
 
403
417
  const config = loadConfig();
418
+ // Apply the process-wide exclusion TTL before any child launch can record a model failure.
419
+ applyModelExclusionsConfig(config);
404
420
  const waitToolConfig = resolveWaitToolConfig(config.waitTool);
405
421
  const asyncByDefault = resolveAsyncByDefault(config);
406
422
  const fleetViewEnabled = config.fleetView !== false;
@@ -455,16 +471,31 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
455
471
  clear: () => {},
456
472
  },
457
473
  };
474
+ const withLastUiContext = <T>(run: (ctx: ExtensionContext) => T): T | undefined => {
475
+ const cached = state.lastUiContext;
476
+ return withCachedUiContext(cached, () => {
477
+ if (state.lastUiContext === cached) state.lastUiContext = null;
478
+ }, run);
479
+ };
458
480
 
459
481
  const supervisorChannel = createNativeSupervisorChannel(pi, state);
460
482
  const waitSubscriptionManager = createWaitSubscriptionManager(pi, state);
461
483
  const mainWatchdog = registerMainWatchdog(pi);
462
- const completionNotifier = registerSubagentNotify(pi, state, { batchConfig: config.completionBatch });
484
+ const resultDeliveryOwnership = createResultDeliveryOwnership(state);
485
+ const completionNotifier = registerSubagentNotify(pi, state, { batchConfig: config.completionBatch, ownership: resultDeliveryOwnership });
463
486
  const fleetStatus = fleetViewEnabled
464
487
  ? new SubagentFleetStatus(state, async (itemKey) => {
465
- const ctx = state.lastUiContext;
466
- if (!ctx?.hasUI) return;
467
- await openSubagentFleet(ctx, state, { initialKey: itemKey, asyncDirRoot: DIRS.async, resultsDir: DIRS.results, fleetKeybindings: config.fleetKeybindings });
488
+ const ctx = withLastUiContext((current) => current);
489
+ if (!ctx) return;
490
+ try {
491
+ await openSubagentFleet(ctx, state, { initialKey: itemKey, asyncDirRoot: DIRS.async, resultsDir: DIRS.results, fleetKeybindings: config.fleetKeybindings });
492
+ } catch (error) {
493
+ if (isStaleExtensionContextError(error)) {
494
+ if (state.lastUiContext === ctx) state.lastUiContext = null;
495
+ return;
496
+ }
497
+ throw error;
498
+ }
468
499
  }, { placement: fleetViewPlacement })
469
500
  : undefined;
470
501
  let executorScheduled: ((id: string, params: SubagentParamsLike, signal: AbortSignal, ctx: ExtensionContext) => Promise<AgentToolResult<Details>>) | undefined;
@@ -493,10 +524,10 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
493
524
  if (scheduledRunManager.observedCompletionRunIds().size > 0) return true;
494
525
  return missionObserverResultCandidateFiles(DIRS.results).length > 0;
495
526
  };
496
- const discoverAgentsForRuntime = (cwd: string, scope: AgentScope) => {
497
- const discovered = discoverAgents(cwd, scope);
527
+ const discoverAgentsForRuntime = (cwd: string, scope: AgentScope, preferredModelProvider?: string) => {
528
+ const discovered = discoverAgents(cwd, scope, preferredModelProvider);
498
529
  if (listRuntimeAgentConfigs(pi).length === 0) return discovered;
499
- const all = discoverAgentsAll(cwd);
530
+ const all = discoverAgentsAll(cwd, preferredModelProvider);
500
531
  const configuredAgents: AgentConfig[] = [
501
532
  ...all.builtin,
502
533
  ...all.package,
@@ -521,6 +552,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
521
552
  10 * 60 * 1000,
522
553
  {
523
554
  notifier: completionNotifier,
555
+ ownership: resultDeliveryOwnership,
524
556
  observeCompletion: (result) => scheduledRunManager.handleAsyncCompletion(result),
525
557
  observedCompletionRunIds: () => scheduledRunManager.observedCompletionRunIds(),
526
558
  hasDeliveryDemand: hasResultDeliveryDemand,
@@ -528,7 +560,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
528
560
  resultScanLogging: config.resultScanLogging,
529
561
  },
530
562
  );
531
- const { startResultWatcher, primeExistingResults, stopResultWatcher } = resultWatcher;
563
+ const { startResultWatcher, transitionResultDelivery, primeExistingResults, stopResultWatcher } = resultWatcher;
532
564
  refreshResultDelivery = resultWatcher.refreshResultDelivery;
533
565
  const asyncRetentionAbort = new AbortController();
534
566
  const asyncRetentionTimer = setTimeout(async () => {
@@ -555,6 +587,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
555
587
  config,
556
588
  asyncByDefault,
557
589
  waitToolEnabled: waitToolConfig.enabled,
590
+ waitToolDefaultTimeoutMs: waitToolConfig.defaultTimeoutMs,
558
591
  handleScheduledRunAction: (params, ctx) => scheduledRunManager.handleToolCall(params, ctx),
559
592
  watchdog: mainWatchdog,
560
593
  tempArtifactsDir,
@@ -642,7 +675,6 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
642
675
 
643
676
  const slashBridge = registerSlashSubagentBridge({
644
677
  events: pi.events,
645
- asyncByDefault,
646
678
  getContext: () => state.lastUiContext,
647
679
  execute: (id, params, signal, onUpdate, ctx) =>
648
680
  executeSubagentCollapsed(id, params, signal, onUpdate, ctx),
@@ -691,7 +723,13 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
691
723
  }
692
724
  if (args.workflowScript)
693
725
  return new Text(
694
- `${title}${gap}${formatWorkflowManifest(args.workflowScript, args.async, false)}`,
726
+ `${title}${gap}${formatWorkflowManifest(args.workflowScript, args.async, false, args.preflight)}`,
727
+ 0,
728
+ 0,
729
+ );
730
+ if (args.workflowScriptPath)
731
+ return new Text(
732
+ `${title}${gap}${theme.fg("accent", args.workflowScriptPath)}${args.async === true ? `${gap}${theme.fg("warning", "[async]")}` : ""}${args.preflight !== undefined ? `${gap}${theme.fg("dim", formatWorkflowPreflightCall(args.preflight))}` : ""}`,
695
733
  0,
696
734
  0,
697
735
  );
@@ -715,7 +753,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
715
753
 
716
754
  pi.registerTool(tool);
717
755
 
718
- registerWaitTool(pi, state, waitToolConfig.enabled, waitSubscriptionManager);
756
+ registerWaitTool(pi, state, waitToolConfig.enabled, waitSubscriptionManager, waitToolConfig.defaultTimeoutMs);
719
757
 
720
758
  pi.on("agent_end", async (_event, ctx) => {
721
759
  if (!ctx.hasUI) await drainOutstandingWork({ state, events: pi.events });
@@ -738,7 +776,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
738
776
  }
739
777
  });
740
778
 
741
- registerSlashCommands(pi, state, {
779
+ const disposeSlashCommands = registerSlashCommands(pi, state, {
742
780
  fleetKeybindings: config.fleetKeybindings,
743
781
  foregroundDetachShortcut: config.foregroundDetachShortcut,
744
782
  });
@@ -778,6 +816,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
778
816
  fleetStatus?.refresh();
779
817
  };
780
818
  const eventUnsubscribes = [
819
+ registerRuntimeAgentEventListener(pi),
781
820
  pi.events.on(SUBAGENT_ASYNC_STARTED_EVENT, asyncStartedHandler),
782
821
  pi.events.on(SUBAGENT_ASYNC_COMPLETE_EVENT, asyncCompleteHandler),
783
822
  pi.events.on(SUBAGENT_PROCESS_TERMINAL_EVENT, () => {
@@ -794,7 +833,9 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
794
833
  if (event.toolName !== "subagent") return;
795
834
  if (!ctx.hasUI) return;
796
835
  state.lastUiContext = ctx;
836
+ const activeJobCount = state.asyncJobs.size;
797
837
  restoreActiveJobs(ctx);
838
+ if (state.asyncJobs.size > activeJobCount) herdrStatusBridge.syncRuns();
798
839
  fleetStatus?.setContext(ctx);
799
840
  fleetStatus?.refresh();
800
841
  if (state.asyncJobs.size > 0) {
@@ -817,14 +858,13 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
817
858
  const suspendWidgetsForCompaction = () => {
818
859
  if (state.widgetsSuspended) return;
819
860
  state.widgetsSuspended = true;
820
- if (state.lastUiContext?.hasUI) state.lastUiContext.ui.setWidget(WIDGET_KEY, undefined);
861
+ withLastUiContext((ctx) => ctx.ui.setWidget(WIDGET_KEY, undefined));
821
862
  fleetStatus?.refresh();
822
863
  };
823
864
  const resumeWidgetsAfterCompaction = () => {
824
865
  if (!state.widgetsSuspended) return;
825
866
  state.widgetsSuspended = false;
826
- const ctx = state.lastUiContext;
827
- if (ctx?.hasUI) refreshWidget(ctx);
867
+ withLastUiContext((ctx) => refreshWidget(ctx));
828
868
  fleetStatus?.refresh();
829
869
  };
830
870
 
@@ -836,16 +876,20 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
836
876
  state.activeAsyncCapacity = getActiveAsyncCapacitySnapshot(
837
877
  state.currentSessionId,
838
878
  resolveMaxActiveAsyncRunsPerSession(config.maxActiveAsyncRunsPerSession),
839
- { liveWorkflowRunIds: new Set(state.workflowControllers?.keys() ?? []) },
879
+ { liveWorkflowRunIds: new Set(state.workflowControllers?.keys() ?? []), abandonedSlotReleaseAfterMs: resolveAbandonedSlotReleaseAfterMs(config.capacity?.abandonedSlotReleaseAfterMs) },
840
880
  );
841
881
  };
842
882
 
843
- const resetSessionState = (ctx: ExtensionContext, recovering: boolean) => {
883
+ const resetSessionState = (ctx: ExtensionContext, recovering: boolean, previousSessionFile?: string) => {
844
884
  state.widgetsSuspended = false;
845
885
  state.baseCwd = ctx.cwd;
846
886
  goalTurnId = 0;
887
+ const previousRuntimeSessionId = state.currentSessionId;
888
+ resultDeliveryOwnership.claimPredecessor(previousSessionFile, previousRuntimeSessionId);
847
889
  state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
890
+ transitionResultDelivery();
848
891
  state.parentSessionFile = ctx.sessionManager.getSessionFile();
892
+ state.trustedSessionFileRoot = state.parentSessionFile ? path.join(getAgentDir(), "sessions") : undefined;
849
893
  state.trustedSessionRoots = [...new Set([
850
894
  ...(config.defaultSessionDir ? [path.resolve(expandTilde(config.defaultSessionDir))] : []),
851
895
  ...(state.parentSessionFile ? [getSubagentSessionRoot(state.parentSessionFile)] : []),
@@ -915,11 +959,19 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
915
959
  if (runtimeCleaned) return;
916
960
  runtimeCleaned = true;
917
961
  const shuttingDownParentSession = parentSessionEnvValue;
962
+ // Workflow continuations retain their launch context; abort them before
963
+ // teardown so a reload cannot launch through a stale context.
964
+ for (const controller of state.workflowControllers?.values() ?? []) {
965
+ if (!controller.signal.aborted) controller.abort(new Error("Workflow stopped because the extension session was replaced or reloaded."));
966
+ }
967
+ state.workflowControllers?.clear();
968
+ state.workflowChildStops?.clear();
918
969
  clearRuntimeAgentsForPi(pi);
919
970
  clearTimeout(resultIndexCleanupTimer);
920
971
  clearTimeout(asyncRetentionTimer);
921
972
  asyncRetentionAbort.abort();
922
973
  stopResultWatcher();
974
+ resultDeliveryOwnership.clear();
923
975
  completionNotifier.dispose();
924
976
  mainWatchdog.dispose();
925
977
  scheduledRunManager.stop();
@@ -937,6 +989,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
937
989
  // Best effort cleanup during shutdown or reload.
938
990
  }
939
991
  }
992
+ disposeSlashCommands.dispose();
940
993
  slashBridge.cancelAll();
941
994
  slashBridge.dispose();
942
995
  promptTemplateBridge.cancelAll();
@@ -1006,7 +1059,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
1006
1059
 
1007
1060
  pi.on("session_compact", () => {
1008
1061
  const hasActiveAsyncWork = [...state.asyncJobs.values()].some((job) => job.status === "queued" || job.status === "running");
1009
- if (!hasActiveAsyncWork || state.lastUiContext?.hasUI !== true) return;
1062
+ if (!hasActiveAsyncWork || !withLastUiContext(() => true)) return;
1010
1063
  pi.sendMessage(
1011
1064
  {
1012
1065
  customType: "subagent-compaction-resume",
@@ -1020,7 +1073,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
1020
1073
  pi.on("session_start", (event, ctx) => {
1021
1074
  installRuntime(ctx);
1022
1075
  const recovering = event.reason === "startup" || event.reason === "reload" || event.reason === "resume";
1023
- resetSessionState(ctx, recovering);
1076
+ resetSessionState(ctx, recovering, event.previousSessionFile);
1024
1077
  herdrStatusBridge.sessionStarted({
1025
1078
  hasUI: ctx.hasUI === true,
1026
1079
  runs: activeHerdrRuns(),
@@ -1,7 +1,14 @@
1
1
  export interface PublicSubagentExecutionParams {
2
2
  action?: unknown;
3
+ mode?: unknown;
4
+ repo?: unknown;
5
+ planId?: unknown;
3
6
  agent?: unknown;
4
7
  task?: unknown;
8
+ handoffPath?: unknown;
9
+ laneId?: unknown;
10
+ merge?: unknown;
11
+ supersession?: unknown;
5
12
  step?: unknown;
6
13
  tasks?: unknown;
7
14
  chain?: unknown;
@@ -11,8 +18,11 @@ export interface PublicSubagentExecutionParams {
11
18
  chainName?: unknown;
12
19
  config?: unknown;
13
20
  workflowScript?: unknown;
21
+ workflowScriptPath?: unknown;
22
+ preflight?: unknown;
14
23
  isolation?: unknown;
15
24
  worktree?: unknown;
25
+ lane?: unknown;
16
26
  async?: unknown;
17
27
  output?: unknown;
18
28
  resume?: unknown;
@@ -21,6 +31,7 @@ export interface PublicSubagentExecutionParams {
21
31
  workflowKey?: unknown;
22
32
  workflowChildAsyncId?: unknown;
23
33
  workflowAwaitAsync?: unknown;
34
+ workflowAwaitDetached?: unknown;
24
35
  workflowParentDeadlineAt?: unknown;
25
36
  suppressRoutineResultIntercom?: unknown;
26
37
  runFanoutBudget?: unknown;
@@ -37,23 +48,32 @@ export type PublicSubagentExecutionNormalization<T> =
37
48
  * Enforce the public execution cutover before requests reach the executor.
38
49
  * Internal runs.run children and structured owned delegation bypass this boundary.
39
50
  */
40
- export function normalizePublicSubagentExecution<T extends PublicSubagentExecutionParams>(params: T, options: { asyncByDefault?: boolean } = {}): PublicSubagentExecutionNormalization<T> {
51
+ export function normalizePublicSubagentExecution<T extends PublicSubagentExecutionParams>(params: T): PublicSubagentExecutionNormalization<T> {
52
+ if (params.workflowScript !== undefined && params.workflowScriptPath !== undefined) {
53
+ return { ok: false, error: "workflowScript and workflowScriptPath are mutually exclusive.", mode: "workflow" };
54
+ }
55
+ const hasWorkflowInput = params.workflowScript !== undefined || params.workflowScriptPath !== undefined;
56
+ if (params.preflight !== undefined && !hasWorkflowInput) {
57
+ return { ok: false, error: "preflight requires workflowScript or workflowScriptPath.", mode: params.action === undefined ? "workflow" : "management" };
58
+ }
59
+ const hasValidWorkflowInput = (typeof params.workflowScript === "string" && Boolean(params.workflowScript.trim()))
60
+ || (typeof params.workflowScriptPath === "string" && Boolean(params.workflowScriptPath.trim()));
41
61
  if (params.isolation !== undefined) {
42
62
  if (params.isolation !== "none" && params.isolation !== "worktree") {
43
- return { ok: false, error: "isolation must be 'none' or 'worktree'.", mode: params.workflowScript !== undefined ? "workflow" : "management" };
63
+ return { ok: false, error: "isolation must be 'none' or 'worktree'.", mode: hasWorkflowInput ? "workflow" : "management" };
44
64
  }
45
65
  const isolationWorktree = params.isolation === "worktree";
46
66
  if (params.worktree !== undefined && params.worktree !== isolationWorktree) {
47
- return { ok: false, error: `isolation '${params.isolation}' conflicts with worktree: ${String(params.worktree)}.`, mode: params.workflowScript !== undefined ? "workflow" : "management" };
67
+ return { ok: false, error: `isolation '${params.isolation}' conflicts with worktree: ${String(params.worktree)}.`, mode: hasWorkflowInput ? "workflow" : "management" };
48
68
  }
49
69
  const { isolation: _isolation, ...normalizedParams } = params;
50
70
  params = { ...normalizedParams, worktree: isolationWorktree } as T;
51
71
  }
52
72
  if (params.runFanoutBudget !== undefined || params.runFanoutAdmitted !== undefined) {
53
- return { ok: false, error: "Public execution does not accept internal run fan-out fields.", mode: params.workflowScript !== undefined ? "workflow" : "management" };
73
+ return { ok: false, error: "Public execution does not accept internal run fan-out fields.", mode: hasWorkflowInput ? "workflow" : "management" };
54
74
  }
55
- if (params.workflowParentRunId !== undefined || params.workflowKey !== undefined || params.workflowChildAsyncId !== undefined || params.workflowAwaitAsync !== undefined || params.workflowParentDeadlineAt !== undefined || params.suppressRoutineResultIntercom !== undefined) {
56
- return { ok: false, error: "Public execution does not accept internal workflow child fields.", mode: params.workflowScript !== undefined ? "workflow" : "management" };
75
+ if (params.workflowParentRunId !== undefined || params.workflowKey !== undefined || params.workflowChildAsyncId !== undefined || params.workflowAwaitAsync !== undefined || params.workflowAwaitDetached !== undefined || params.workflowParentDeadlineAt !== undefined || params.suppressRoutineResultIntercom !== undefined) {
76
+ return { ok: false, error: "Public execution does not accept internal workflow child fields.", mode: hasWorkflowInput ? "workflow" : "management" };
57
77
  }
58
78
  const action = params.action;
59
79
  if (action !== undefined && (typeof action !== "string" || !action.trim())) {
@@ -90,17 +110,26 @@ export function normalizePublicSubagentExecution<T extends PublicSubagentExecuti
90
110
  if (legacyAction === "parallel" || legacyAction === "tasks" || legacyAction === "chain") {
91
111
  return { ok: false, error: "Legacy top-level chain and parallel inputs were removed; use workflowScript.", mode: "workflow" };
92
112
  }
113
+ if (normalizedAction === "validate") {
114
+ if (params.agent !== undefined || params.task !== undefined || params.step !== undefined) {
115
+ return { ok: false, error: "validate requires workflowScript or workflowScriptPath and does not accept direct agent, task, or step execution fields.", mode: "management" };
116
+ }
117
+ if (!hasValidWorkflowInput) {
118
+ return { ok: false, error: "validate requires a non-empty workflowScript or workflowScriptPath.", mode: "management" };
119
+ }
120
+ return { ok: true, params: { ...params, action: normalizedAction } };
121
+ }
93
122
  if (normalizedAction === "schedule.create") {
94
123
  if (params.agent !== undefined || params.task !== undefined || params.step !== undefined) {
95
- return { ok: false, error: "schedule.create requires workflowScript and does not accept direct agent, task, or step execution fields.", mode: "management" };
124
+ return { ok: false, error: "schedule.create requires workflowScript or workflowScriptPath and does not accept direct agent, task, or step execution fields.", mode: "management" };
96
125
  }
97
- if (typeof params.workflowScript !== "string" || !params.workflowScript.trim()) {
98
- return { ok: false, error: "schedule.create requires a non-empty workflowScript.", mode: "management" };
126
+ if (!hasValidWorkflowInput) {
127
+ return { ok: false, error: "schedule.create requires a non-empty workflowScript or workflowScriptPath.", mode: "management" };
99
128
  }
100
129
  return { ok: true, params: { ...params, action: normalizedAction } };
101
130
  }
102
- if (params.workflowScript !== undefined) {
103
- return { ok: false, error: "workflowScript execution must omit action; only schedule.create accepts action with workflowScript.", mode: "management" };
131
+ if (hasWorkflowInput) {
132
+ return { ok: false, error: "Workflow execution must omit action; only validate and schedule.create accept action with workflowScript or workflowScriptPath.", mode: "management" };
104
133
  }
105
134
  if (params.task !== undefined) {
106
135
  return { ok: false, error: "Structured single-child task cannot be combined with a management/control action.", mode: "management" };
@@ -110,8 +139,8 @@ export function normalizePublicSubagentExecution<T extends PublicSubagentExecuti
110
139
  if (params.step !== undefined) {
111
140
  return { ok: false, error: "step is not a public execution field; use workflowScript for orchestration.", mode: "workflow" };
112
141
  }
113
- if (params.workflowScript !== undefined && (params.agent !== undefined || params.task !== undefined)) {
114
- return { ok: false, error: "Structured single-child execution cannot be combined with workflowScript.", mode: "workflow" };
142
+ if (hasWorkflowInput && (params.agent !== undefined || params.task !== undefined)) {
143
+ return { ok: false, error: "Structured single-child execution cannot be combined with workflowScript or workflowScriptPath.", mode: "workflow" };
115
144
  }
116
145
  if (params.agent !== undefined || params.task !== undefined) {
117
146
  if (typeof params.agent !== "string" || !params.agent.trim()) {
@@ -129,8 +158,8 @@ export function normalizePublicSubagentExecution<T extends PublicSubagentExecuti
129
158
  } as T,
130
159
  };
131
160
  }
132
- if (typeof params.workflowScript !== "string" || !params.workflowScript.trim()) {
133
- return { ok: false, error: "Execution requires either { agent, task? } for one child or a non-empty workflowScript for orchestration.", mode: "workflow" };
161
+ if (!hasValidWorkflowInput) {
162
+ return { ok: false, error: "Execution requires either { agent, task? } for one child or a non-empty workflowScript or workflowScriptPath for orchestration.", mode: "workflow" };
134
163
  }
135
164
  return { ok: true, params };
136
165
  }
@@ -11,6 +11,7 @@ import {
11
11
  type AsyncJobStep,
12
12
  type Details,
13
13
  type SubagentState,
14
+ type TokenUsage,
14
15
  DIRS,
15
16
  SUBAGENT_ASYNC_COMPLETE_EVENT,
16
17
  SUBAGENT_CHILD_STATUS_EVENT,
@@ -97,7 +98,7 @@ export interface SubagentRpcFleetEntry {
97
98
  model?: string;
98
99
  effort?: string;
99
100
  startedAt: number;
100
- tokens: { input: number; output: number; total: number };
101
+ tokens: TokenUsage;
101
102
  goal?: string;
102
103
  }
103
104
 
@@ -122,7 +123,7 @@ function displayText(value: unknown, maxLength: number): string | undefined {
122
123
  return normalized ? truncateDisplayText(normalized, maxLength) : undefined;
123
124
  }
124
125
 
125
- function publicTokens(value: unknown): { input: number; output: number; total: number } {
126
+ function publicTokens(value: unknown): TokenUsage {
126
127
  const record = isRecord(value) ? value : {};
127
128
  const count = (field: "input" | "output" | "total") => {
128
129
  const raw = record[field];
@@ -133,7 +134,21 @@ function publicTokens(value: unknown): { input: number; output: number; total: n
133
134
  const input = count("input");
134
135
  const output = count("output");
135
136
  const sum = Math.min(Number.MAX_SAFE_INTEGER, input + output);
136
- return { input, output, total: Math.max(sum, count("total")) };
137
+ const optionalCount = (field: "window" | "windowPeak") => {
138
+ const raw = record[field];
139
+ return typeof raw === "number" && Number.isFinite(raw) && raw >= 0
140
+ ? Math.min(Number.MAX_SAFE_INTEGER, Math.floor(raw))
141
+ : undefined;
142
+ };
143
+ const window = optionalCount("window");
144
+ const windowPeak = optionalCount("windowPeak");
145
+ return {
146
+ input,
147
+ output,
148
+ total: Math.max(sum, count("total")),
149
+ ...(window !== undefined ? { window } : {}),
150
+ ...(windowPeak !== undefined ? { windowPeak } : {}),
151
+ };
137
152
  }
138
153
 
139
154
  function activeState(value: unknown): boolean {
@@ -188,7 +203,7 @@ function buildFleetStatus(
188
203
  model: child.model,
189
204
  effort: child.thinking,
190
205
  startedAt: child.startedAt,
191
- tokens: { input: child.inputTokens ?? 0, output: child.outputTokens ?? 0, total: child.tokens ?? 0 },
206
+ tokens: { input: child.inputTokens ?? 0, output: child.outputTokens ?? 0, total: child.tokens ?? 0, ...(child.window !== undefined ? { window: child.window } : {}), ...(child.windowPeak !== undefined ? { windowPeak: child.windowPeak } : {}) },
192
207
  });
193
208
  } else {
194
209
  addCandidate({
@@ -197,7 +212,7 @@ function buildFleetStatus(
197
212
  model: control.model,
198
213
  effort: control.thinking,
199
214
  startedAt: control.startedAt,
200
- tokens: { input: control.inputTokens ?? 0, output: control.outputTokens ?? 0, total: control.tokens ?? 0 },
215
+ tokens: { input: control.inputTokens ?? 0, output: control.outputTokens ?? 0, total: control.tokens ?? 0, ...(control.window !== undefined ? { window: control.window } : {}), ...(control.windowPeak !== undefined ? { windowPeak: control.windowPeak } : {}) },
201
216
  });
202
217
  }
203
218
  }
@@ -542,7 +557,7 @@ function stopAsyncRun(
542
557
  childId: stoppedChild.id,
543
558
  status: "stopping",
544
559
  ts,
545
- reason: "user",
560
+ reason: "rpc",
546
561
  source: "rpc",
547
562
  asyncDir,
548
563
  stepIndex: stoppedChild.index,
@@ -564,20 +579,21 @@ function stopAsyncRun(
564
579
  if (initialStatus.mode === "workflow" && initialStatus.state === "running") {
565
580
  if (child) {
566
581
  const stopChild = options.state?.workflowChildStops?.get(initialRunId);
567
- if (!stopChild) throw new SubagentRpcError("invalid_state", `Workflow ${initialRunId} is not controlled by this extension runtime; child stop is unavailable.`);
568
- if (!stopChild(child.id, `Workflow child '${child.id}' stopped by RPC.`)) throw new SubagentRpcError("invalid_state", `Child '${childId}' in workflow ${initialRunId} is not available to stop.`);
569
- emitChildStopping(initialRunId, location.asyncDir, child);
570
- return {
571
- runId: initialRunId,
572
- asyncDir: location.asyncDir,
573
- previousState: initialStatus.state,
574
- state: "stopping",
575
- childId: child.id,
576
- message: `Stop requested for child ${child.id} in async run ${initialRunId}.`,
577
- };
582
+ if (stopChild) {
583
+ if (!stopChild(child.id, `Workflow child '${child.id}' stopped by RPC.`)) throw new SubagentRpcError("invalid_state", `Child '${childId}' in workflow ${initialRunId} is not available to stop.`);
584
+ emitChildStopping(initialRunId, location.asyncDir, child);
585
+ return {
586
+ runId: initialRunId,
587
+ asyncDir: location.asyncDir,
588
+ previousState: initialStatus.state,
589
+ state: "stopping",
590
+ childId: child.id,
591
+ message: `Stop requested for child ${child.id} in async run ${initialRunId}.`,
592
+ };
593
+ }
578
594
  }
579
595
  const workflowController = options.state?.workflowControllers?.get(initialRunId);
580
- if (workflowController) {
596
+ if (workflowController && !child) {
581
597
  workflowController.abort(new Error("Workflow stopped by RPC."));
582
598
  return {
583
599
  runId: initialRunId,
@@ -587,7 +603,27 @@ function stopAsyncRun(
587
603
  message: `Stop requested for async run ${initialRunId}.`,
588
604
  };
589
605
  }
590
- throw new SubagentRpcError("invalid_state", `Workflow ${initialRunId} is not controlled by this extension runtime; reload recovery cannot stop it safely.`);
606
+ try {
607
+ deliverStopRequest({
608
+ asyncDir: location.asyncDir,
609
+ pid: initialStatus.pid,
610
+ kill: options.kill,
611
+ now: options.now,
612
+ source: "rpc-stop",
613
+ ...(child ? { targetIndex: child.index, childId: child.id } : {}),
614
+ });
615
+ } catch (error) {
616
+ throw new SubagentRpcError("execution_failed", error instanceof Error ? error.message : String(error));
617
+ }
618
+ if (child) emitChildStopping(initialRunId, location.asyncDir, child);
619
+ return {
620
+ runId: initialRunId,
621
+ asyncDir: location.asyncDir,
622
+ previousState: initialStatus.state,
623
+ state: "stopping",
624
+ ...(child ? { childId: child.id } : {}),
625
+ message: child ? `Stop requested for child ${child.id} in async run ${initialRunId}.` : `Stop requested for async run ${initialRunId}.`,
626
+ };
591
627
  }
592
628
 
593
629
  let status;