@selesai/code 0.5.19 → 0.5.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (265) hide show
  1. package/dist/extensions/handoff-new.test.ts +8 -9
  2. package/dist/extensions/handoff-new.ts +6 -8
  3. package/dist/extensions/pi-intercom/broker/spawn.test.ts +31 -0
  4. package/dist/extensions/pi-intercom/broker/spawn.ts +5 -3
  5. package/dist/extensions/pi-subagents/CHANGELOG.md +1367 -0
  6. package/dist/extensions/pi-subagents/README.md +602 -220
  7. package/dist/extensions/pi-subagents/banner.png +0 -0
  8. package/dist/extensions/pi-subagents/index.ts +1 -0
  9. package/dist/extensions/pi-subagents/install.mjs +3 -3
  10. package/dist/extensions/pi-subagents/package-lock.json +3405 -0
  11. package/dist/extensions/pi-subagents/package.json +26 -14
  12. package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
  13. package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
  14. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
  15. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
  16. package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
  17. package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
  18. package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
  19. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
  20. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
  21. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
  22. package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
  23. package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
  24. package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
  25. package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
  26. package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
  27. package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
  28. package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
  29. package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
  30. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
  31. package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
  32. package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
  33. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
  34. package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
  35. package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
  36. package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
  37. package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
  38. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
  39. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
  40. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
  41. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
  42. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
  43. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
  44. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
  45. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
  46. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
  47. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
  48. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
  49. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
  50. package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
  51. package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
  52. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
  53. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
  54. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
  55. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
  56. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
  57. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
  58. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
  59. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
  60. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
  61. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
  62. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
  63. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
  64. package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
  65. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
  66. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
  67. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
  68. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
  69. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
  70. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
  71. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
  72. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
  73. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
  74. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
  75. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
  76. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
  77. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
  78. package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
  79. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
  80. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
  81. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
  82. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
  83. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
  84. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
  85. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
  86. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
  87. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
  88. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
  89. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
  90. package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
  91. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
  92. package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
  93. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
  94. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
  95. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
  96. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
  97. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
  98. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
  99. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
  100. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
  101. package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
  102. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
  103. package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
  104. package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
  105. package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
  106. package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
  107. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
  108. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
  109. package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
  110. package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
  111. package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
  112. package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
  113. package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
  114. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
  115. package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
  116. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
  117. package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
  118. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
  119. package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
  120. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
  121. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
  122. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
  123. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
  124. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
  125. package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
  126. package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
  127. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
  128. package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
  129. package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
  130. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
  131. package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
  132. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
  133. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
  134. package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
  135. package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
  136. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
  137. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
  138. package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
  139. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
  140. package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
  141. package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
  142. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
  143. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
  144. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
  145. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
  146. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
  147. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
  148. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
  149. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
  150. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
  151. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
  152. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
  153. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
  154. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
  155. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
  156. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
  157. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
  158. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
  159. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
  160. package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
  161. package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
  162. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
  163. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
  164. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
  165. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
  166. package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
  167. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
  168. package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
  169. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
  170. package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
  171. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
  172. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
  173. package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
  174. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
  175. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
  176. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
  177. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
  178. package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
  179. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
  180. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
  181. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
  182. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
  183. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
  184. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
  185. package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
  186. package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
  187. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
  188. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
  189. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
  190. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
  191. package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
  192. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
  193. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
  194. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
  195. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
  196. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
  197. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
  198. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
  199. package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
  200. package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
  201. package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
  202. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
  203. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
  204. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
  205. package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
  206. package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
  207. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
  208. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
  209. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
  210. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
  211. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
  212. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
  213. package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
  214. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
  215. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
  216. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
  217. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
  218. package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
  219. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
  220. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
  221. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
  222. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
  223. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
  224. package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
  225. package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
  226. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
  227. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
  228. package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
  229. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
  230. package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
  231. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
  232. package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
  233. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
  234. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
  235. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
  236. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
  237. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
  238. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
  239. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
  240. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
  241. package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
  242. package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
  243. package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
  244. package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
  245. package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
  246. package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
  247. package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
  248. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
  249. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
  250. package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
  251. package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
  252. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
  253. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
  254. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
  255. package/dist/extensions/question/batch.ts +39 -0
  256. package/dist/extensions/question/dialog-adapter.ts +23 -1
  257. package/dist/extensions/question/index.ts +237 -7
  258. package/dist/extensions/question/schemas.ts +28 -15
  259. package/dist/extensions/question/tests/batch.test.ts +26 -0
  260. package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
  261. package/dist/extensions/question/tui-adapter.ts +2 -3
  262. package/dist/extensions/question/types.ts +37 -0
  263. package/dist/extensions/question/ui-protocol.ts +3 -3
  264. package/dist/skills/batch-grill-me/SKILL.md +3 -1
  265. package/package.json +2 -1
@@ -0,0 +1,161 @@
1
+ import { SUBAGENT_WATCHDOG_WARNING_TYPE } from "./types.ts";
2
+
3
+ type MessageLike = {
4
+ role?: string;
5
+ content?: unknown;
6
+ customType?: string;
7
+ toolName?: string;
8
+ name?: string;
9
+ input?: unknown;
10
+ args?: unknown;
11
+ arguments?: unknown;
12
+ error?: unknown;
13
+ isError?: boolean;
14
+ details?: unknown;
15
+ stopReason?: string;
16
+ };
17
+
18
+ export interface WatchdogTurnDeltaInput {
19
+ userPrompt?: string;
20
+ includeUserPrompt?: boolean;
21
+ messages?: unknown[];
22
+ events?: unknown[];
23
+ finalAssistantStop?: boolean;
24
+ }
25
+
26
+ function textFromContent(content: unknown): string {
27
+ if (typeof content === "string") return content;
28
+ if (Array.isArray(content)) {
29
+ return content.map((block) => {
30
+ if (typeof block === "string") return block;
31
+ if (block && typeof block === "object") {
32
+ const item = block as { type?: string; text?: unknown; thinking?: unknown; content?: unknown; name?: unknown; input?: unknown; args?: unknown; arguments?: unknown };
33
+ if (item.type === "text" && typeof item.text === "string") return item.text;
34
+ if (item.type === "thinking" && typeof item.thinking === "string") return ["Thinking:", item.thinking].join("\n");
35
+ if (item.type === "toolCall") return formatToolCall(item.name, item.input ?? item.args ?? item.arguments);
36
+ if (typeof item.content === "string") return item.content;
37
+ }
38
+ return "";
39
+ }).filter(Boolean).join("\n");
40
+ }
41
+ if (content === undefined || content === null) return "";
42
+ return formatValue(content);
43
+ }
44
+
45
+ function formatValue(value: unknown, indent = ""): string {
46
+ if (typeof value === "string") return value;
47
+ if (value === undefined) return "undefined";
48
+ if (value === null || typeof value === "number" || typeof value === "boolean") return JSON.stringify(value);
49
+ if (Array.isArray(value)) {
50
+ return value.map((item, index) => `${indent}- ${formatValue(item, `${indent} `)}`).join("\n");
51
+ }
52
+ if (typeof value === "object") {
53
+ const lines: string[] = [];
54
+ for (const [key, item] of Object.entries(value as Record<string, unknown>)) {
55
+ if (typeof item === "string" && item.includes("\n")) lines.push(`${indent}${key}:\n${item}`);
56
+ else lines.push(`${indent}${key}: ${formatValue(item, `${indent} `)}`);
57
+ }
58
+ return lines.join("\n");
59
+ }
60
+ return String(value);
61
+ }
62
+
63
+ function redactEditWriteInput(input: unknown): unknown {
64
+ if (Array.isArray(input)) return input.map(redactEditWriteInput);
65
+ if (!input || typeof input !== "object") return input;
66
+ const sanitized: Record<string, unknown> = {};
67
+ for (const [key, value] of Object.entries(input as Record<string, unknown>)) {
68
+ sanitized[key] = ["oldText", "newText", "content"].includes(key) && typeof value === "string"
69
+ ? `[omitted ${value.length} chars; use tool result diff]`
70
+ : redactEditWriteInput(value);
71
+ }
72
+ return sanitized;
73
+ }
74
+
75
+ function formatToolArguments(name: string, input: unknown): string {
76
+ if (name === "edit" || name === "write") return formatValue(redactEditWriteInput(input));
77
+ return formatValue(input);
78
+ }
79
+
80
+ function formatToolCall(name: unknown, input: unknown): string {
81
+ const toolName = typeof name === "string" && name ? name : "tool";
82
+ return [`Tool call: ${toolName}`, "Arguments:", formatToolArguments(toolName, input ?? {})].join("\n");
83
+ }
84
+
85
+ function formatToolResult(name: string, content: unknown, details: unknown, error: unknown, isError: boolean | undefined): string {
86
+ const failed = isError === true || Boolean(error);
87
+ const lines = [`Tool result: ${name}`];
88
+ if (failed) lines.push(`Error: ${error ? (typeof error === "string" ? error : formatValue(error)) : "tool reported an error"}`);
89
+ if (!failed && details && typeof details === "object" && "diff" in details && typeof (details as { diff?: unknown }).diff === "string") {
90
+ lines.push("Diff:", (details as { diff: string }).diff);
91
+ } else {
92
+ const body = textFromContent(content);
93
+ if (body) lines.push(failed ? "Output:" : "Result:", body);
94
+ }
95
+ return lines.join("\n");
96
+ }
97
+
98
+ function messagesFromEvent(event: unknown): unknown[] {
99
+ if (!event || typeof event !== "object") return [];
100
+ const input = event as Record<string, unknown>;
101
+ if (input.type === "turn_end" || input.event === "turn_end") {
102
+ return [input.message, ...(Array.isArray(input.toolResults) ? input.toolResults : [])].filter(Boolean);
103
+ }
104
+ if (input.message) return [input.message];
105
+ if (input.type === "tool_execution_start" || input.event === "tool_execution_start") {
106
+ return [{ role: "toolCall", name: input.toolName ?? input.name, input: input.args ?? input.input }];
107
+ }
108
+ if (input.type === "tool_execution_end" || input.event === "tool_execution_end") {
109
+ const result = input.result && typeof input.result === "object" && !Array.isArray(input.result) ? input.result as Record<string, unknown> : undefined;
110
+ return [{
111
+ role: "toolResult",
112
+ toolName: input.toolName ?? input.name,
113
+ content: result?.content ?? input.content ?? input.result,
114
+ details: result?.details ?? input.details,
115
+ error: input.error,
116
+ isError: input.isError,
117
+ }];
118
+ }
119
+ if (input.type === "tool_result" || input.event === "tool_result") {
120
+ return [{ role: "toolResult", toolName: input.toolName ?? input.name, content: input.content, details: input.details, error: input.error, isError: input.isError }];
121
+ }
122
+ return [];
123
+ }
124
+
125
+ export function formatWatchdogReviewMessage(message: unknown): string | undefined {
126
+ if (!message || typeof message !== "object") return undefined;
127
+ const input = message as MessageLike;
128
+ if (input.role === "custom" && input.customType === SUBAGENT_WATCHDOG_WARNING_TYPE) return undefined;
129
+ if (input.role === "assistant") {
130
+ const text = textFromContent(input.content);
131
+ const lines = text ? ["Assistant:", text] : ["Assistant: (no text)"];
132
+ if (input.stopReason === "stop") lines.push("Assistant stop: stop");
133
+ return lines.join("\n");
134
+ }
135
+ if (input.role === "toolCall") return formatToolCall(input.name ?? input.toolName, input.input ?? input.args ?? input.arguments);
136
+ if (input.role === "toolResult" || input.role === "tool") {
137
+ return formatToolResult(input.toolName ?? input.name ?? "tool", input.content, input.details, input.error, input.isError);
138
+ }
139
+ if (input.role === "user") {
140
+ const text = textFromContent(input.content);
141
+ return text ? ["User:", text].join("\n") : undefined;
142
+ }
143
+ return undefined;
144
+ }
145
+
146
+ export function formatWatchdogTurnDelta(input: WatchdogTurnDeltaInput): string {
147
+ const sections: string[] = [];
148
+ if (input.includeUserPrompt && input.userPrompt?.trim()) sections.push(["User prompt:", input.userPrompt].join("\n"));
149
+ for (const message of input.messages ?? []) {
150
+ const section = formatWatchdogReviewMessage(message);
151
+ if (section) sections.push(section);
152
+ }
153
+ for (const event of input.events ?? []) {
154
+ for (const message of messagesFromEvent(event)) {
155
+ const section = formatWatchdogReviewMessage(message);
156
+ if (section) sections.push(section);
157
+ }
158
+ }
159
+ if (input.finalAssistantStop) sections.push("Final assistant stop: stop without tool call");
160
+ return sections.join("\n\n---\n\n");
161
+ }
@@ -0,0 +1,188 @@
1
+ export const SUBAGENT_WATCHDOG_WARNING_TYPE = "subagent_watchdog_warning";
2
+
3
+ export const WATCHDOG_WARNING_SEVERITIES = ["concern", "blocker"] as const;
4
+ export type WatchdogSeverity = typeof WATCHDOG_WARNING_SEVERITIES[number];
5
+
6
+ export const WATCHDOG_WARNING_CATEGORIES = [
7
+ "correctness",
8
+ "missed-constraint",
9
+ "test-gap",
10
+ "unsafe-change",
11
+ "scope-drift",
12
+ "stale-fact",
13
+ "loop-risk",
14
+ "other",
15
+ ] as const;
16
+ export type WatchdogCategory = typeof WATCHDOG_WARNING_CATEGORIES[number];
17
+
18
+ export const WATCHDOG_WARNING_CONFIDENCES = ["medium", "high"] as const;
19
+ export type WatchdogConfidence = typeof WATCHDOG_WARNING_CONFIDENCES[number];
20
+
21
+ export const WATCHDOG_WARNING_SOURCES = ["main", "child", "async-completion", "lsp"] as const;
22
+ export type WatchdogWarningSource = typeof WATCHDOG_WARNING_SOURCES[number];
23
+
24
+ export const WATCHDOG_LSP_DIAGNOSTIC_SEVERITIES = ["error", "warning", "info", "hint"] as const;
25
+ export type WatchdogLspDiagnosticSeverity = typeof WATCHDOG_LSP_DIAGNOSTIC_SEVERITIES[number];
26
+
27
+ export const WATCHDOG_LSP_STATUSES = ["disabled", "ok", "skipped", "unavailable", "timeout", "failed"] as const;
28
+ export type WatchdogLspStatus = typeof WATCHDOG_LSP_STATUSES[number];
29
+
30
+ export const WATCHDOG_RUNTIME_STATUSES = ["idle", "queued", "reviewing", "waiting-at-agent-end", "stale", "failed"] as const;
31
+ export type WatchdogRuntimeStatus = typeof WATCHDOG_RUNTIME_STATUSES[number];
32
+
33
+ export const WATCHDOG_WARNING_STATES = [
34
+ "candidate",
35
+ "confirmed",
36
+ "displayed",
37
+ "stale",
38
+ "failed",
39
+ "resolved",
40
+ "stalemate",
41
+ "suppressed",
42
+ ] as const;
43
+ export type WatchdogWarningState = typeof WATCHDOG_WARNING_STATES[number];
44
+
45
+ export const WATCHDOG_LATE_WARNING_POLICIES = ["show-stale-no-autofollow"] as const;
46
+ export type WatchdogLateWarningPolicy = typeof WATCHDOG_LATE_WARNING_POLICIES[number];
47
+
48
+ export const WATCHDOG_DELIVERY_MODES = ["held"] as const;
49
+ export type WatchdogDeliveryMode = typeof WATCHDOG_DELIVERY_MODES[number];
50
+
51
+ export type WatchdogSyncBacklog = "off" | number;
52
+
53
+ export interface WatchdogWarning {
54
+ severity: WatchdogSeverity;
55
+ summary: string;
56
+ evidence: string;
57
+ recommendedAction: string;
58
+ category?: WatchdogCategory;
59
+ confidence?: WatchdogConfidence;
60
+ source?: WatchdogWarningSource;
61
+ agent?: string;
62
+ runId?: string;
63
+ stale?: boolean;
64
+ autoFollowAttempt?: number;
65
+ state?: WatchdogWarningState;
66
+ }
67
+
68
+ export interface WatchdogWarningDetails extends WatchdogWarning {
69
+ category: WatchdogCategory;
70
+ source: WatchdogWarningSource;
71
+ identity?: string;
72
+ displayedAt?: string;
73
+ error?: string;
74
+ stalemateRepeats?: number;
75
+ }
76
+
77
+ export interface WatchdogWarningMessage {
78
+ customType: typeof SUBAGENT_WATCHDOG_WARNING_TYPE;
79
+ content: string;
80
+ display: boolean;
81
+ details: WatchdogWarningDetails;
82
+ }
83
+
84
+ export interface WatchdogAutoFollowConfig {
85
+ blockers: boolean;
86
+ maxAttempts: number | null;
87
+ stalemateRepeats: number;
88
+ }
89
+
90
+ export interface WatchdogGuidanceConfig {
91
+ watchdogMd: boolean;
92
+ systemPromptPath: string | null;
93
+ }
94
+
95
+ export interface WatchdogEndpointConfig {
96
+ enabled: boolean;
97
+ model?: string;
98
+ thinking?: string | false;
99
+ }
100
+
101
+ export interface WatchdogChildOverrideConfig {
102
+ enabled?: boolean;
103
+ model?: string;
104
+ thinking?: string | false;
105
+ }
106
+
107
+ export interface WatchdogChildrenConfig extends WatchdogEndpointConfig {
108
+ watchdogTailTimeoutMs: number;
109
+ autoFollow: WatchdogAutoFollowConfig;
110
+ overrides: Record<string, WatchdogChildOverrideConfig>;
111
+ }
112
+
113
+ export interface WatchdogAsyncCompletionConfig {
114
+ enabled: boolean;
115
+ autoFollowBlockers: boolean;
116
+ }
117
+
118
+ export interface WatchdogLspConfig {
119
+ enabled: boolean;
120
+ timeoutMs: number;
121
+ maxFiles: number;
122
+ maxDiagnostics: number;
123
+ }
124
+
125
+ export interface WatchdogLspDiagnostic {
126
+ path: string;
127
+ line: number;
128
+ column: number;
129
+ severity: WatchdogLspDiagnosticSeverity;
130
+ source: string;
131
+ code?: string;
132
+ message: string;
133
+ }
134
+
135
+ export interface WatchdogLspResult {
136
+ status: WatchdogLspStatus;
137
+ provider?: string;
138
+ checkedPaths: string[];
139
+ skippedPaths: string[];
140
+ diagnostics: WatchdogLspDiagnostic[];
141
+ message?: string;
142
+ }
143
+
144
+ export interface WatchdogLspRuntimeSnapshot extends WatchdogLspResult {
145
+ enabled: boolean;
146
+ diagnosticCount: number;
147
+ freshDiagnosticCount: number;
148
+ updatedAt?: string;
149
+ }
150
+
151
+ export interface ResolvedWatchdogConfig {
152
+ enabled: boolean;
153
+ delivery: WatchdogDeliveryMode;
154
+ showDuringRun: boolean;
155
+ syncBacklog: WatchdogSyncBacklog;
156
+ agentEndTimeoutMs: number;
157
+ lateWarningPolicy: WatchdogLateWarningPolicy;
158
+ severityThreshold: WatchdogSeverity;
159
+ maxWarnings: number | null;
160
+ guidance: WatchdogGuidanceConfig;
161
+ autoFollow: WatchdogAutoFollowConfig;
162
+ main: WatchdogEndpointConfig;
163
+ children: WatchdogChildrenConfig;
164
+ asyncCompletion: WatchdogAsyncCompletionConfig;
165
+ lsp: WatchdogLspConfig;
166
+ compactAtPercent: number;
167
+ reviewRetryDelayMs: number;
168
+ maxReviewFailures: number;
169
+ }
170
+
171
+ export interface WatchdogSettingsError {
172
+ scope: "user" | "project" | "session";
173
+ path?: string;
174
+ message: string;
175
+ }
176
+
177
+ export interface WatchdogSettingsSource {
178
+ scope: "user" | "project" | "session";
179
+ path?: string;
180
+ exists: boolean;
181
+ }
182
+
183
+ export interface WatchdogSettingsResult {
184
+ ok: boolean;
185
+ config: ResolvedWatchdogConfig;
186
+ errors: WatchdogSettingsError[];
187
+ sources: WatchdogSettingsSource[];
188
+ }
@@ -0,0 +1,73 @@
1
+ import {
2
+ SUBAGENT_WATCHDOG_WARNING_TYPE,
3
+ type WatchdogWarning,
4
+ type WatchdogWarningDetails,
5
+ type WatchdogWarningMessage,
6
+ } from "./types.ts";
7
+
8
+ function escapeXmlText(value: string): string {
9
+ return value
10
+ .replace(/&/g, "&amp;")
11
+ .replace(/</g, "&lt;")
12
+ .replace(/>/g, "&gt;");
13
+ }
14
+
15
+ function escapeXmlAttribute(value: string): string {
16
+ return escapeXmlText(value).replace(/"/g, "&quot;");
17
+ }
18
+
19
+ function tag(name: string, value: string | number | boolean | undefined): string | undefined {
20
+ if (value === undefined) return undefined;
21
+ return `<${name}>${escapeXmlText(String(value))}</${name}>`;
22
+ }
23
+
24
+ export function normalizeWatchdogWarningDetails(warning: WatchdogWarning, extras: Partial<WatchdogWarningDetails> = {}): WatchdogWarningDetails {
25
+ return {
26
+ ...warning,
27
+ category: warning.category ?? extras.category ?? "other",
28
+ source: warning.source ?? extras.source ?? "main",
29
+ ...extras,
30
+ };
31
+ }
32
+
33
+ export function formatWatchdogWarningContent(warning: WatchdogWarning): string {
34
+ const details = normalizeWatchdogWarningDetails(warning);
35
+ const attrs = [
36
+ `severity="${escapeXmlAttribute(details.severity)}"`,
37
+ `category="${escapeXmlAttribute(details.category)}"`,
38
+ `source="${escapeXmlAttribute(details.source)}"`,
39
+ `guidance="weigh, don't blindly obey"`,
40
+ ];
41
+ const optionalTags = [
42
+ tag("confidence", details.confidence),
43
+ tag("agent", details.agent),
44
+ tag("run_id", details.runId),
45
+ tag("state", details.state),
46
+ tag("stale", details.stale),
47
+ tag("auto_follow_attempt", details.autoFollowAttempt),
48
+ ];
49
+ return [
50
+ `<subagent_watchdog ${attrs.join(" ")}>`,
51
+ `<summary>${escapeXmlText(details.summary)}</summary>`,
52
+ `<evidence>${escapeXmlText(details.evidence)}</evidence>`,
53
+ `<recommended_action>${escapeXmlText(details.recommendedAction)}</recommended_action>`,
54
+ ...optionalTags.filter((line): line is string => Boolean(line)),
55
+ details.severity === "blocker"
56
+ ? "<blocker_guidance>If this warning changes the outcome, produce a new self-contained final answer after addressing it.</blocker_guidance>"
57
+ : undefined,
58
+ "</subagent_watchdog>",
59
+ ].filter((line): line is string => Boolean(line)).join("\n");
60
+ }
61
+
62
+ export function createWatchdogWarningMessage(
63
+ warning: WatchdogWarning,
64
+ options: { display?: boolean; details?: Partial<WatchdogWarningDetails> } = {},
65
+ ): WatchdogWarningMessage {
66
+ const details = normalizeWatchdogWarningDetails(warning, options.details);
67
+ return {
68
+ customType: SUBAGENT_WATCHDOG_WARNING_TYPE,
69
+ content: formatWatchdogWarningContent(details),
70
+ display: options.display ?? true,
71
+ details,
72
+ };
73
+ }
@@ -37,7 +37,7 @@ const ISOLATED_ENV_KEYS = [
37
37
  "SELESAI_SUBAGENT_EXTRA_AGENT_DIRS",
38
38
  "SELESAI_SUBAGENT_PARENT_SESSION",
39
39
  "SELESAI_SUBAGENT_PI_BINARY",
40
- "SELESAI_SUBAGENTS_PI_CODING_AGENT_PACKAGE_ROOT",
40
+ "SELESAI_SUBAGENTS_SELESAI_CODING_AGENT_PACKAGE_ROOT",
41
41
  ] as const;
42
42
 
43
43
  describe("real Pi-session subagent E2E", { skip: !available ? "pi runtime packages not available" : undefined }, () => {
@@ -48,6 +48,134 @@ describe("real Pi-session subagent E2E", { skip: !available ? "pi runtime packag
48
48
  run = undefined;
49
49
  });
50
50
 
51
+ it("loads requested extension tools in direct and chain children and diagnoses missing providers", async () => {
52
+ const { runRealSubagentSession, subagentCall, subagentToolResults } = await import("../support/real-session-runner.ts");
53
+ const extensionAgent = `---
54
+ name: extension-worker
55
+ description: Uses a child-only fixture tool
56
+ tools: read, fixture_search
57
+ subagentOnlyExtensions: ./fixture-extension.ts
58
+ completionGuard: false
59
+ ---
60
+ Use the available tools.`;
61
+ const missingAgent = `---
62
+ name: missing-extension-worker
63
+ description: Requests an extension tool without loading its provider
64
+ tools: read, missing_search
65
+ completionGuard: false
66
+ ---
67
+ Use the available tools.`;
68
+ const fixtureExtension = `export default function (pi) {
69
+ pi.registerTool({
70
+ name: "fixture_search",
71
+ label: "Fixture Search",
72
+ description: "Search the E2E fixture.",
73
+ parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"], additionalProperties: false },
74
+ async execute() { return { content: [{ type: "text", text: "fixture result" }] }; },
75
+ });
76
+ }`;
77
+
78
+ run = await runRealSubagentSession({
79
+ prompt: "Run the direct, chain, and missing-provider child checks.",
80
+ childText: CHILD_MARKER,
81
+ reportChildTools: true,
82
+ projectFiles: {
83
+ ".selesai/agents/extension-worker.md": extensionAgent,
84
+ ".selesai/agents/missing-extension-worker.md": missingAgent,
85
+ "fixture-extension.ts": fixtureExtension,
86
+ },
87
+ respond(context) {
88
+ const resultCount = (context.messages as Array<{ role?: string; toolName?: string }>).filter((message) => message.role === "toolResult" && message.toolName === "subagent").length;
89
+ if (resultCount === 0) {
90
+ return subagentCall({ agent: "extension-worker", task: "Report active tools.", context: "fresh", agentScope: "project" }, "call-direct-extension");
91
+ }
92
+ if (resultCount === 1) {
93
+ return subagentCall({ chain: [{ agent: "extension-worker", task: "Report active tools." }], async: false, clarify: false, agentScope: "project" }, "call-chain-extension");
94
+ }
95
+ if (resultCount === 2) {
96
+ return subagentCall({
97
+ chain: [{
98
+ agent: "extension-worker",
99
+ task: "Submit the required structured marker.",
100
+ outputSchema: {
101
+ type: "object",
102
+ properties: { marker: { type: "string" } },
103
+ required: ["marker"],
104
+ additionalProperties: false,
105
+ },
106
+ }],
107
+ async: false,
108
+ clarify: false,
109
+ agentScope: "project",
110
+ }, "call-structured-output");
111
+ }
112
+ if (resultCount === 3) {
113
+ return subagentCall({ agent: "missing-extension-worker", task: "Report active tools.", context: "fresh", agentScope: "project" }, "call-missing-extension");
114
+ }
115
+ return "Child tool checks complete.";
116
+ },
117
+ timeoutMs: 60_000,
118
+ });
119
+
120
+ const results = subagentToolResults(run.parentSession);
121
+ const toolMessages = run.parentSession.messages.filter((message) => message.role === "toolResult" && (message as { toolName?: string }).toolName === "subagent");
122
+ const chainDetails = JSON.stringify((toolMessages[1] as { details?: unknown } | undefined)?.details);
123
+ const structuredDetails = JSON.stringify((toolMessages[2] as { details?: unknown } | undefined)?.details);
124
+ assert.equal(results.length, 4);
125
+ assert.match(results[0] ?? "", /ACTIVE_TOOLS:[^\n]*fixture_search/);
126
+ assert.match(results[0] ?? "", /ACTIVE_TOOLS:[^\n]*read/);
127
+ assert.match(chainDetails, /ACTIVE_TOOLS:[^\n]*fixture_search/);
128
+ assert.match(chainDetails, /ACTIVE_TOOLS:[^\n]*read/);
129
+ assert.match(structuredDetails, /STRUCTURED_OUTPUT_OK/);
130
+ assert.match(results[3] ?? "", /requested unavailable child tools: missing_search/);
131
+ assert.match(results[3] ?? "", /subagentOnlyExtensions/);
132
+ });
133
+
134
+ it("accepts child tools registered by async before_agent_start hooks", async () => {
135
+ const { runRealSubagentSession, subagentCall, subagentToolResults } = await import("../support/real-session-runner.ts");
136
+ const asyncExtensionAgent = `---
137
+ name: async-extension-worker
138
+ description: Uses a child-only tool registered from before_agent_start
139
+ tools: read, fixture_async_search
140
+ subagentOnlyExtensions: ./fixture-async-extension.ts
141
+ completionGuard: false
142
+ ---
143
+ Report active tools.`;
144
+ const fixtureAsyncExtension = `export default function (pi) {
145
+ pi.on("before_agent_start", async () => {
146
+ await new Promise((resolve) => setTimeout(resolve, 0));
147
+ pi.registerTool({
148
+ name: "fixture_async_search",
149
+ label: "Fixture Async Search",
150
+ description: "Search the async E2E fixture.",
151
+ parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"], additionalProperties: false },
152
+ async execute() { return { content: [{ type: "text", text: "async fixture result" }] }; },
153
+ });
154
+ });
155
+ }`;
156
+
157
+ run = await runRealSubagentSession({
158
+ prompt: "Run the async child tool check.",
159
+ childText: CHILD_MARKER,
160
+ reportChildTools: true,
161
+ projectFiles: {
162
+ ".selesai/agents/async-extension-worker.md": asyncExtensionAgent,
163
+ "fixture-async-extension.ts": fixtureAsyncExtension,
164
+ },
165
+ respond(context) {
166
+ const resultCount = (context.messages as Array<{ role?: string; toolName?: string }>).filter((message) => message.role === "toolResult" && message.toolName === "subagent").length;
167
+ if (resultCount > 0) return "Async child tool check complete.";
168
+ return subagentCall({ agent: "async-extension-worker", task: "Report active tools.", context: "fresh", agentScope: "project" }, "call-async-extension");
169
+ },
170
+ timeoutMs: 60_000,
171
+ });
172
+
173
+ const results = subagentToolResults(run.parentSession);
174
+ assert.equal(results.length, 1);
175
+ assert.match(results[0] ?? "", /ACTIVE_TOOLS:[^\n]*fixture_async_search/);
176
+ assert.doesNotMatch(results[0] ?? "", /requested unavailable child tools/);
177
+ });
178
+
51
179
  it("boots the extension in a real parent session and delivers a faux child result", async () => {
52
180
  const { routeParentThroughSubagent, runRealSubagentSession, subagentToolResults } = await import("../support/real-session-runner.ts");
53
181
 
@@ -59,7 +187,7 @@ describe("real Pi-session subagent E2E", { skip: !available ? "pi runtime packag
59
187
  process.env.SELESAI_SUBAGENT_EXTRA_AGENT_DIRS = BOGUS_EXTRA_DIRS;
60
188
  process.env.SELESAI_SUBAGENT_PARENT_SESSION = "polluted-parent";
61
189
  process.env.SELESAI_SUBAGENT_PI_BINARY = BOGUS_PI_BINARY;
62
- process.env.SELESAI_SUBAGENTS_PI_CODING_AGENT_PACKAGE_ROOT = BOGUS_PI_PACKAGE_ROOT;
190
+ process.env.SELESAI_SUBAGENTS_SELESAI_CODING_AGENT_PACKAGE_ROOT = BOGUS_PI_PACKAGE_ROOT;
63
191
 
64
192
  try {
65
193
  run = await runRealSubagentSession({