@selesai/code 0.5.20 → 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 (263) 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-subagents/CHANGELOG.md +1367 -0
  4. package/dist/extensions/pi-subagents/README.md +602 -220
  5. package/dist/extensions/pi-subagents/banner.png +0 -0
  6. package/dist/extensions/pi-subagents/index.ts +1 -0
  7. package/dist/extensions/pi-subagents/install.mjs +3 -3
  8. package/dist/extensions/pi-subagents/package-lock.json +3405 -0
  9. package/dist/extensions/pi-subagents/package.json +26 -14
  10. package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
  11. package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
  12. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
  13. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
  14. package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
  15. package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
  16. package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
  17. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
  18. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
  19. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
  20. package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
  21. package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
  22. package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
  23. package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
  24. package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
  25. package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
  26. package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
  27. package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
  28. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
  29. package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
  30. package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
  31. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
  32. package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
  33. package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
  34. package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
  35. package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
  36. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
  37. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
  38. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
  39. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
  40. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
  41. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
  42. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
  43. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
  44. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
  45. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
  46. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
  47. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
  48. package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
  49. package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
  50. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
  51. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
  52. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
  53. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
  54. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
  55. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
  56. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
  57. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
  58. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
  59. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
  60. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
  61. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
  62. package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
  63. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
  64. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
  65. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
  66. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
  67. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
  68. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
  69. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
  70. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
  71. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
  72. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
  73. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
  74. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
  75. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
  76. package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
  77. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
  78. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
  79. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
  80. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
  81. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
  82. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
  83. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
  84. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
  85. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
  86. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
  87. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
  88. package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
  89. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
  90. package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
  91. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
  92. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
  93. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
  94. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
  95. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
  96. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
  97. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
  98. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
  99. package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
  100. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
  101. package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
  102. package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
  103. package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
  104. package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
  105. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
  106. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
  107. package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
  108. package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
  109. package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
  110. package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
  111. package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
  112. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
  113. package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
  114. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
  115. package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
  116. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
  117. package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
  118. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
  119. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
  120. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
  121. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
  122. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
  123. package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
  124. package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
  125. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
  126. package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
  127. package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
  128. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
  129. package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
  130. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
  131. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
  132. package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
  133. package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
  134. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
  135. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
  136. package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
  137. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
  138. package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
  139. package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
  140. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
  141. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
  142. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
  143. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
  144. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
  145. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
  146. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
  147. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
  148. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
  149. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
  150. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
  151. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
  152. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
  153. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
  154. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
  155. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
  156. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
  157. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
  158. package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
  159. package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
  160. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
  161. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
  162. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
  163. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
  164. package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
  165. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
  166. package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
  167. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
  168. package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
  169. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
  170. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
  171. package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
  172. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
  173. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
  174. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
  175. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
  176. package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
  177. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
  178. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
  179. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
  180. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
  181. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
  182. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
  183. package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
  184. package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
  185. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
  186. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
  187. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
  188. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
  189. package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
  190. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
  191. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
  192. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
  193. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
  194. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
  195. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
  196. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
  197. package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
  198. package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
  199. package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
  200. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
  201. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
  202. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
  203. package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
  204. package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
  205. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
  206. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
  207. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
  208. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
  209. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
  210. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
  211. package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
  212. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
  213. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
  214. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
  215. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
  216. package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
  217. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
  218. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
  219. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
  220. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
  221. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
  222. package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
  223. package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
  224. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
  225. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
  226. package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
  227. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
  228. package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
  229. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
  230. package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
  231. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
  232. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
  233. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
  234. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
  235. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
  236. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
  237. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
  238. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
  239. package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
  240. package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
  241. package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
  242. package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
  243. package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
  244. package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
  245. package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
  246. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
  247. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
  248. package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
  249. package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
  250. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
  251. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
  252. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
  253. package/dist/extensions/question/batch.ts +39 -0
  254. package/dist/extensions/question/dialog-adapter.ts +23 -1
  255. package/dist/extensions/question/index.ts +237 -7
  256. package/dist/extensions/question/schemas.ts +28 -15
  257. package/dist/extensions/question/tests/batch.test.ts +26 -0
  258. package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
  259. package/dist/extensions/question/tui-adapter.ts +2 -3
  260. package/dist/extensions/question/types.ts +37 -0
  261. package/dist/extensions/question/ui-protocol.ts +3 -3
  262. package/dist/skills/batch-grill-me/SKILL.md +3 -1
  263. package/package.json +1 -1
@@ -1,11 +1,14 @@
1
1
  import * as fs from "node:fs";
2
+ import { createRequire } from "node:module";
2
3
  import * as os from "node:os";
3
4
  import * as path from "node:path";
4
- import { Compile } from "typebox/compile";
5
+ import { pathToFileURL } from "node:url";
6
+ import { SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV } from "../../shared/utils.ts";
5
7
  import type { JsonSchemaObject } from "../../shared/types.ts";
6
8
 
7
9
  export const STRUCTURED_OUTPUT_SCHEMA_ENV = "SELESAI_SUBAGENT_STRUCTURED_OUTPUT_SCHEMA";
8
10
  export const STRUCTURED_OUTPUT_CAPTURE_ENV = "SELESAI_SUBAGENT_STRUCTURED_OUTPUT_CAPTURE";
11
+ export const MISSING_STRUCTURED_OUTPUT_CALL_ERROR = "Missing structured_output call; this step has outputSchema and must finish by calling structured_output.";
9
12
 
10
13
  export interface StructuredOutputRuntime {
11
14
  schema: JsonSchemaObject;
@@ -13,11 +16,108 @@ export interface StructuredOutputRuntime {
13
16
  outputPath: string;
14
17
  }
15
18
 
19
+ const SCHEMA_MAP_KEYWORDS = ["properties", "patternProperties", "$defs", "definitions", "dependentSchemas"] as const;
20
+ const SCHEMA_SINGLE_KEYWORDS = ["additionalItems", "additionalProperties", "contains", "not", "propertyNames", "if", "then", "else", "unevaluatedItems", "unevaluatedProperties", "contentSchema"] as const;
21
+ const SCHEMA_ARRAY_KEYWORDS = ["allOf", "anyOf", "oneOf", "prefixItems"] as const;
22
+
23
+ function rewriteLocalJsonPointerRefs(schema: unknown, pointerPrefix: string, inheritsWrapperResource = true): unknown {
24
+ if (typeof schema === "boolean" || !schema || typeof schema !== "object" || Array.isArray(schema)) return schema;
25
+ const source = schema as Record<string, unknown>;
26
+ const rewritten: Record<string, unknown> = { ...source };
27
+ const sharesWrapperResource = inheritsWrapperResource && typeof source.$id !== "string";
28
+ if (sharesWrapperResource) {
29
+ for (const keyword of ["$ref", "$dynamicRef", "$recursiveRef"] as const) {
30
+ const ref = source[keyword];
31
+ if (ref === "#") rewritten[keyword] = pointerPrefix;
32
+ else if (typeof ref === "string" && ref.startsWith("#/")) rewritten[keyword] = `${pointerPrefix}${ref.slice(1)}`;
33
+ }
34
+ }
35
+ for (const keyword of SCHEMA_MAP_KEYWORDS) {
36
+ const entries = source[keyword];
37
+ if (!entries || typeof entries !== "object" || Array.isArray(entries)) continue;
38
+ rewritten[keyword] = Object.fromEntries(Object.entries(entries).map(([name, nested]) => [
39
+ name,
40
+ rewriteLocalJsonPointerRefs(nested, pointerPrefix, sharesWrapperResource),
41
+ ]));
42
+ }
43
+ const items = source.items;
44
+ if (Array.isArray(items)) rewritten.items = items.map((nested) => rewriteLocalJsonPointerRefs(nested, pointerPrefix, sharesWrapperResource));
45
+ else if (items !== undefined) rewritten.items = rewriteLocalJsonPointerRefs(items, pointerPrefix, sharesWrapperResource);
46
+ for (const keyword of SCHEMA_SINGLE_KEYWORDS) {
47
+ if (source[keyword] !== undefined) rewritten[keyword] = rewriteLocalJsonPointerRefs(source[keyword], pointerPrefix, sharesWrapperResource);
48
+ }
49
+ for (const keyword of SCHEMA_ARRAY_KEYWORDS) {
50
+ if (Array.isArray(source[keyword])) rewritten[keyword] = source[keyword].map((nested) => rewriteLocalJsonPointerRefs(nested, pointerPrefix, sharesWrapperResource));
51
+ }
52
+ const dependencies = source.dependencies;
53
+ if (dependencies && typeof dependencies === "object" && !Array.isArray(dependencies)) {
54
+ rewritten.dependencies = Object.fromEntries(Object.entries(dependencies).map(([name, nested]) => [
55
+ name,
56
+ Array.isArray(nested) ? nested : rewriteLocalJsonPointerRefs(nested, pointerPrefix, sharesWrapperResource),
57
+ ]));
58
+ }
59
+ return rewritten;
60
+ }
61
+
62
+ export function createStructuredOutputToolParameters(schema: JsonSchemaObject): JsonSchemaObject {
63
+ return {
64
+ type: "object",
65
+ properties: { value: rewriteLocalJsonPointerRefs(schema, "#/properties/value") },
66
+ required: ["value"],
67
+ additionalProperties: false,
68
+ };
69
+ }
70
+
16
71
  interface CompiledJsonSchema {
17
72
  Check(value: unknown): boolean;
18
73
  Errors(value: unknown): Iterable<{ instancePath?: string; message?: string }>;
19
74
  }
20
75
 
76
+ type CompileJsonSchema = (schema: unknown) => CompiledJsonSchema;
77
+
78
+ let cachedCompile: Promise<CompileJsonSchema> | undefined;
79
+
80
+ export async function resolveCompileFromPackageRoot(packageRoot: string): Promise<CompileJsonSchema | undefined> {
81
+ const requireFromRoot = createRequire(path.join(packageRoot, "package.json"));
82
+ const resolved = requireFromRoot.resolve("typebox/compile");
83
+ const mod = (await import(pathToFileURL(resolved).href)) as { Compile?: unknown };
84
+ return typeof mod.Compile === "function" ? (mod.Compile as CompileJsonSchema) : undefined;
85
+ }
86
+
87
+ async function importCompile(): Promise<CompileJsonSchema> {
88
+ const failures: string[] = [];
89
+ try {
90
+ const mod = (await import("typebox/compile")) as { Compile?: unknown };
91
+ if (typeof mod.Compile === "function") return mod.Compile as CompileJsonSchema;
92
+ failures.push("typebox/compile did not export a Compile function");
93
+ } catch (error) {
94
+ failures.push(`direct import failed: ${error instanceof Error ? error.message : String(error)}`);
95
+ }
96
+ const packageRoot = process.env[SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV];
97
+ if (packageRoot) {
98
+ try {
99
+ const compile = await resolveCompileFromPackageRoot(packageRoot);
100
+ if (compile) return compile;
101
+ failures.push("Pi package root typebox/compile did not export a Compile function");
102
+ } catch (error) {
103
+ failures.push(`Pi package root import failed: ${error instanceof Error ? error.message : String(error)}`);
104
+ }
105
+ } else {
106
+ failures.push(`${SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV} is not set`);
107
+ }
108
+ throw new Error(`Cannot load typebox/compile for structured output validation (${failures.join("; ")})`);
109
+ }
110
+
111
+ function loadCompile(): Promise<CompileJsonSchema> {
112
+ if (!cachedCompile) {
113
+ cachedCompile = importCompile().catch((error) => {
114
+ cachedCompile = undefined;
115
+ throw error;
116
+ });
117
+ }
118
+ return cachedCompile;
119
+ }
120
+
21
121
  export function assertJsonSchemaObject(schema: unknown, label = "outputSchema"): asserts schema is JsonSchemaObject {
22
122
  if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
23
123
  throw new Error(`${label} must be a JSON Schema object.`);
@@ -35,10 +135,11 @@ export function createStructuredOutputRuntime(schema: JsonSchemaObject, baseDir?
35
135
  return { schema, schemaPath, outputPath };
36
136
  }
37
137
 
38
- export function validateStructuredOutputValue(schema: JsonSchemaObject, value: unknown): { status: "valid" } | { status: "invalid"; message: string } {
138
+ export async function validateStructuredOutputValue(schema: JsonSchemaObject, value: unknown): Promise<{ status: "valid" } | { status: "invalid"; message: string }> {
139
+ const compile = await loadCompile();
39
140
  let validator: CompiledJsonSchema;
40
141
  try {
41
- validator = (Compile as (schema: unknown) => CompiledJsonSchema)(schema);
142
+ validator = compile(schema);
42
143
  } catch (error) {
43
144
  return { status: "invalid", message: `invalid outputSchema: ${error instanceof Error ? error.message : String(error)}` };
44
145
  }
@@ -52,9 +153,9 @@ export function validateStructuredOutputValue(schema: JsonSchemaObject, value: u
52
153
  return { status: "invalid", message: errors.join("; ") || "schema validation failed" };
53
154
  }
54
155
 
55
- export function readStructuredOutput(runtime: StructuredOutputRuntime): { value?: unknown; error?: string } {
156
+ export async function readStructuredOutput(runtime: StructuredOutputRuntime): Promise<{ value?: unknown; error?: string }> {
56
157
  if (!fs.existsSync(runtime.outputPath)) {
57
- return { error: "Missing structured_output call; this step has outputSchema and must finish by calling structured_output." };
158
+ return { error: MISSING_STRUCTURED_OUTPUT_CALL_ERROR };
58
159
  }
59
160
  let value: unknown;
60
161
  try {
@@ -62,8 +163,12 @@ export function readStructuredOutput(runtime: StructuredOutputRuntime): { value?
62
163
  } catch (error) {
63
164
  return { error: `Failed to read structured output: ${error instanceof Error ? error.message : String(error)}` };
64
165
  }
65
- const validation = validateStructuredOutputValue(runtime.schema, value);
66
- if (validation.status === "invalid") return { error: `Structured output validation failed: ${validation.message}` };
166
+ try {
167
+ const validation = await validateStructuredOutputValue(runtime.schema, value);
168
+ if (validation.status === "invalid") return { error: `Structured output validation failed: ${validation.message}` };
169
+ } catch (error) {
170
+ return { error: `Failed to validate structured output: ${error instanceof Error ? error.message : String(error)}` };
171
+ }
67
172
  return { value };
68
173
  }
69
174
 
@@ -74,9 +74,10 @@ export function deriveActivityState(input: {
74
74
  config: ResolvedControlConfig;
75
75
  startedAt: number;
76
76
  lastActivityAt?: number;
77
+ currentTool?: string;
77
78
  now?: number;
78
79
  }): ActivityState | undefined {
79
- if (!input.config.enabled) return undefined;
80
+ if (!input.config.enabled || input.currentTool) return undefined;
80
81
  const now = input.now ?? Date.now();
81
82
  const lastActivity = input.lastActivityAt ?? input.startedAt;
82
83
  const ageMs = Math.max(0, now - lastActivity);
@@ -174,7 +175,8 @@ export function formatControlNoticeMessage(event: ControlEvent, childIntercomTar
174
175
  }
175
176
 
176
177
  const nudgeMessage = "What are you blocked on? Reply with the smallest next step or ask for a decision.";
177
- const nudgeCommand = `subagent({ action: "resume", id: "${runTarget}", ${event.index !== undefined ? `index: ${event.index}, ` : ""}message: "${nudgeMessage}" })`;
178
+ const steerCommand = `subagent({ action: "steer", id: "${runTarget}", ${event.index !== undefined ? `index: ${event.index}, ` : ""}message: "${nudgeMessage}" })`;
179
+ const nestedResumeCommand = `subagent({ action: "resume", id: "${runTarget}", message: "${nudgeMessage}" })`;
178
180
  if (event.type === "active_long_running") {
179
181
  const facts = formatLongRunningFacts(event);
180
182
  return [
@@ -182,21 +184,27 @@ export function formatControlNoticeMessage(event: ControlEvent, childIntercomTar
182
184
  `Run: ${runTarget}${event.index !== undefined ? ` step ${event.index + 1}` : ""}`,
183
185
  `Signal: ${event.message}`,
184
186
  facts ? `Facts: ${facts}` : undefined,
185
- "Hint: Inspect status, then nudge if the work seems stuck. Live async nudges interrupt the child before sending the follow-up.",
186
- `Nudge: ${nudgeCommand}`,
187
+ "Hint: Inspect status first. Use steer for a top-level live async child, routed resume for a live nested child, or resume to revive a paused/completed/failed child.",
188
+ `Top-level live async nudge: ${steerCommand}`,
189
+ `Routed live nested nudge: ${nestedResumeCommand}`,
187
190
  childIntercomTarget ? `Direct intercom target: ${childIntercomTarget}` : undefined,
188
191
  `Status: subagent({ action: "status", id: "${runTarget}" })`,
189
192
  `Interrupt: subagent({ action: "interrupt", id: "${runTarget}" })`,
190
193
  ].filter((line): line is string => Boolean(line)).join("\n");
191
194
  }
192
195
 
196
+ const supervisorHint = event.reason === "supervisor_request"
197
+ ? "Supervisor request: reply to the pending request. If subagent_supervisor pending is empty, check intercom pending because an external intercom tool may own the request."
198
+ : undefined;
193
199
  return [
194
200
  `Subagent needs attention: ${event.agent}`,
195
201
  `Run: ${runTarget}${event.index !== undefined ? ` step ${event.index + 1}` : ""}`,
196
202
  `Signal: ${event.message}`,
197
203
  event.recentFailureSummary ? `Recent failures: ${event.recentFailureSummary}` : undefined,
198
- "Hint: Inspect status first unless the run is clearly blocked. Live async nudges interrupt the child before sending the follow-up.",
199
- `Nudge: ${nudgeCommand}`,
204
+ supervisorHint,
205
+ "Hint: Inspect status first unless the run is clearly blocked. Use steer for a top-level live async child, routed resume for a live nested child, or resume to revive a paused/completed/failed child.",
206
+ `Top-level live async nudge: ${steerCommand}`,
207
+ `Routed live nested nudge: ${nestedResumeCommand}`,
200
208
  childIntercomTarget ? `Direct intercom target: ${childIntercomTarget}` : undefined,
201
209
  `Status: subagent({ action: "status", id: "${runTarget}" })`,
202
210
  `Interrupt: subagent({ action: "interrupt", id: "${runTarget}" })`,
@@ -2,11 +2,25 @@ import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import type { ExtensionAPI } from "@selesai/code";
4
4
  import { registerNativeSupervisorClient } from "../../intercom/native-supervisor-channel.ts";
5
- import { consumeSteerRequestsFromDir, writeSteerRequestToDir, type SteerRequest } from "../background/control-channel.ts";
6
- import { SUBAGENT_FANOUT_CHILD_ENV, SUBAGENT_STEER_INBOX_ENV } from "./pi-args.ts";
7
- import { STRUCTURED_OUTPUT_CAPTURE_ENV, STRUCTURED_OUTPUT_SCHEMA_ENV, validateStructuredOutputValue } from "./structured-output.ts";
8
- import { TOOL_BUDGET_ENV, decodeToolBudgetEnv, shouldBlockToolForBudget, toolBudgetBlockedMessage, toolBudgetSoftNudge } from "./tool-budget.ts";
9
- import type { JsonSchemaObject, ResolvedToolBudget } from "../../shared/types.ts";
5
+ import { consumeSteerRequestsFromDir, steerAckPathFromDir, writeSteerAckAt, writeSteerCapabilityAt, writeSteerRequestToDir, type SteerRequest } from "../background/control-channel.ts";
6
+ import { SUBAGENT_CHILD_AGENT_ENV, SUBAGENT_CHILD_INDEX_ENV, SUBAGENT_FANOUT_CHILD_ENV, SUBAGENT_STEER_ACK_DIR_ENV, SUBAGENT_STEER_CAPABILITY_ENV, SUBAGENT_STEER_INBOX_ENV } from "./pi-args.ts";
7
+ import { createStructuredOutputToolParameters, STRUCTURED_OUTPUT_CAPTURE_ENV, STRUCTURED_OUTPUT_SCHEMA_ENV, validateStructuredOutputValue } from "./structured-output.ts";
8
+ import {
9
+ CHILD_TOOL_DIAGNOSTIC_PATH_ENV,
10
+ MCP_DIRECT_CHILD_TOOLS_ENV,
11
+ REQUIRED_CHILD_TOOLS_ENV,
12
+ writeChildToolDiagnostic,
13
+ type ChildToolDiagnostic,
14
+ } from "./tool-availability.ts";
15
+ import { TOOL_BUDGET_ENV, TOOL_BUDGET_ZERO_AUTH_ENV, decodeToolBudgetEnv, shouldBlockToolForBudget, toolBudgetBlockedMessage, toolBudgetSoftNudge } from "./tool-budget.ts";
16
+ import type { JsonSchemaObject, ResolvedToolBudget, SubagentState } from "../../shared/types.ts";
17
+ import { resolveCurrentSessionId } from "../../shared/session-identity.ts";
18
+ import { resolveWatchPath } from "../../shared/utils.ts";
19
+ import { registerChildWatchdog } from "../../watchdog/register-child.ts";
20
+ import { SUBAGENT_WATCHDOG_WARNING_TYPE } from "../../watchdog/types.ts";
21
+ import { resolveWaitToolConfig } from "../background/wait-config.ts";
22
+ import { registerWaitTool } from "../background/wait-tool.ts";
23
+ import { drainOutstandingWork } from "../background/auto-drain.ts";
10
24
 
11
25
  const SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV = "SELESAI_SUBAGENT_INHERIT_PROJECT_CONTEXT";
12
26
  const SUBAGENT_INHERIT_SKILLS_ENV = "SELESAI_SUBAGENT_INHERIT_SKILLS";
@@ -55,6 +69,36 @@ function readBooleanEnv(name: string): boolean | undefined {
55
69
  return value !== "0";
56
70
  }
57
71
 
72
+ function readRequiredChildTools(): string[] | undefined {
73
+ const encoded = process.env[REQUIRED_CHILD_TOOLS_ENV]?.trim();
74
+ if (!encoded) return undefined;
75
+ const required = JSON.parse(encoded) as unknown;
76
+ if (!Array.isArray(required) || required.some((name) => typeof name !== "string" || !name)) {
77
+ throw new Error(`Invalid ${REQUIRED_CHILD_TOOLS_ENV} payload.`);
78
+ }
79
+ return required;
80
+ }
81
+
82
+ function readMcpDirectChildTools(): string[] | undefined {
83
+ const encoded = process.env[MCP_DIRECT_CHILD_TOOLS_ENV]?.trim();
84
+ if (!encoded) return undefined;
85
+ try {
86
+ const tools = JSON.parse(encoded) as unknown;
87
+ if (!Array.isArray(tools) || tools.some((name) => typeof name !== "string" || !name)) return undefined;
88
+ return tools;
89
+ } catch {
90
+ return undefined;
91
+ }
92
+ }
93
+
94
+ function refreshChildToolDiagnostic(pi: ExtensionAPI): ChildToolDiagnostic | undefined {
95
+ const filePath = process.env[CHILD_TOOL_DIAGNOSTIC_PATH_ENV]?.trim();
96
+ const required = readRequiredChildTools();
97
+ if (!filePath || !required) return undefined;
98
+ const available = pi.getAllTools().map((tool) => tool.name);
99
+ return writeChildToolDiagnostic(filePath, required, available, process.env[SUBAGENT_CHILD_AGENT_ENV]?.trim(), readMcpDirectChildTools());
100
+ }
101
+
58
102
  function findSectionEnd(prompt: string, startIndex: number, nextHeaders: string[]): number {
59
103
  let endIndex = prompt.length;
60
104
  for (const header of nextHeaders) {
@@ -114,9 +158,9 @@ export function rewriteSubagentPrompt(
114
158
 
115
159
  function isParentOnlySubagentMessage(message: unknown): boolean {
116
160
  const m = message as { role?: string; customType?: string };
117
- return m?.role === "custom"
118
- && typeof m.customType === "string"
119
- && PARENT_ONLY_CUSTOM_MESSAGE_TYPES.has(m.customType);
161
+ if (m?.role !== "custom" || typeof m.customType !== "string") return false;
162
+ if (m.customType === SUBAGENT_WATCHDOG_WARNING_TYPE) return true;
163
+ return PARENT_ONLY_CUSTOM_MESSAGE_TYPES.has(m.customType);
120
164
  }
121
165
 
122
166
  function isSubagentToolResultMessage(message: unknown): boolean {
@@ -190,29 +234,59 @@ function registerToolBudget(pi: ExtensionAPI, budget: ResolvedToolBudget | undef
190
234
  });
191
235
  }
192
236
 
193
- function registerSteeringInbox(pi: ExtensionAPI): void {
237
+ export function registerSteeringInbox(
238
+ pi: ExtensionAPI,
239
+ deps: { watch?: typeof fs.watch; nativeRealpath?: (filePath: string) => string } = {},
240
+ ): void {
194
241
  const steerInbox = process.env[SUBAGENT_STEER_INBOX_ENV]?.trim();
195
242
  if (!steerInbox) return;
243
+ const capabilityPath = process.env[SUBAGENT_STEER_CAPABILITY_ENV]?.trim();
244
+ const ackDir = process.env[SUBAGENT_STEER_ACK_DIR_ENV]?.trim();
196
245
  const sendUserMessage = (pi as { sendUserMessage?: (content: string, options: { deliverAs: "steer" }) => unknown }).sendUserMessage;
197
- if (typeof sendUserMessage !== "function") return;
198
-
199
- let canSteer = false;
246
+ const childIndex = Number(process.env[SUBAGENT_CHILD_INDEX_ENV]);
247
+ const pending = new Map<string, string[]>();
200
248
  let disposed = false;
201
249
  let flushing = false;
202
250
  let started = false;
251
+ let canSteer = typeof sendUserMessage === "function";
203
252
  let watcher: fs.FSWatcher | undefined;
204
253
  let interval: NodeJS.Timeout | undefined;
254
+ const acknowledge = (request: SteerRequest, state: "delivered" | "failed", message: string): void => {
255
+ if (!ackDir || !Number.isInteger(childIndex) || childIndex < 0) return;
256
+ writeSteerAckAt(steerAckPathFromDir(ackDir, request.id), {
257
+ requestId: request.id,
258
+ index: childIndex,
259
+ ts: Date.now(),
260
+ state,
261
+ message,
262
+ });
263
+ };
264
+ const publishCapability = (): void => {
265
+ if (!capabilityPath || !Number.isInteger(childIndex) || childIndex < 0) return;
266
+ writeSteerCapabilityAt(capabilityPath, { index: childIndex, pid: process.pid, readyAt: Date.now(), supported: canSteer });
267
+ };
205
268
  const flush = (): void => {
206
- if (disposed || flushing || !canSteer) return;
269
+ if (disposed || flushing) return;
207
270
  flushing = true;
208
271
  try {
209
272
  const requests = consumeSteerRequestsFromDir(steerInbox);
210
273
  for (let index = 0; index < requests.length; index++) {
211
274
  const request = requests[index]!;
275
+ if (!canSteer || typeof sendUserMessage !== "function") {
276
+ acknowledge(request, "failed", "Child Pi session does not support sendUserMessage steering.");
277
+ continue;
278
+ }
279
+ const formatted = formatSteerMessage(request);
280
+ const ids = pending.get(formatted) ?? [];
281
+ ids.push(request.id);
282
+ pending.set(formatted, ids);
212
283
  try {
213
- sendUserMessage(formatSteerMessage(request), { deliverAs: "steer" });
214
- } catch {
215
- for (const pending of requests.slice(index)) writeSteerRequestToDir(steerInbox, pending);
284
+ sendUserMessage(formatted, { deliverAs: "steer" });
285
+ } catch (error) {
286
+ ids.pop();
287
+ if (ids.length === 0) pending.delete(formatted);
288
+ acknowledge(request, "failed", error instanceof Error ? error.message : String(error));
289
+ for (const retry of requests.slice(index + 1)) writeSteerRequestToDir(steerInbox, retry);
216
290
  break;
217
291
  }
218
292
  }
@@ -220,16 +294,30 @@ function registerSteeringInbox(pi: ExtensionAPI): void {
220
294
  flushing = false;
221
295
  }
222
296
  };
297
+ const onInput = (event: unknown): undefined => {
298
+ if (disposed || !event || typeof event !== "object") return undefined;
299
+ const input = event as { source?: unknown; streamingBehavior?: unknown; text?: unknown; content?: unknown };
300
+ if (input.source !== "extension" || input.streamingBehavior !== "steer") return undefined;
301
+ const text = typeof input.text === "string" ? input.text : typeof input.content === "string" ? input.content : undefined;
302
+ if (!text) return undefined;
303
+ const ids = pending.get(text);
304
+ const requestId = ids?.shift();
305
+ if (!requestId) return undefined;
306
+ if (ids?.length === 0) pending.delete(text);
307
+ acknowledge({ type: "steer", id: requestId, ts: Date.now(), message: text }, "delivered", "Pi accepted the correlated steering input.");
308
+ return undefined;
309
+ };
223
310
  const start = (): void => {
224
311
  if (started || disposed) return;
225
312
  try {
226
313
  fs.mkdirSync(steerInbox, { recursive: true });
314
+ publishCapability();
227
315
  } catch {
228
316
  return;
229
317
  }
230
318
  started = true;
231
319
  try {
232
- watcher = fs.watch(steerInbox, () => flush());
320
+ watcher = (deps.watch ?? fs.watch)(resolveWatchPath(steerInbox, deps.nativeRealpath), () => flush());
233
321
  watcher.on("error", () => {});
234
322
  } catch {
235
323
  watcher = undefined;
@@ -239,28 +327,44 @@ function registerSteeringInbox(pi: ExtensionAPI): void {
239
327
  };
240
328
  const activate = (): undefined => {
241
329
  start();
242
- canSteer = true;
243
330
  flush();
244
331
  return undefined;
245
332
  };
246
333
 
247
334
  const onRuntimeEvent = pi.on as unknown as (event: string, handler: (event: unknown) => unknown) => void;
335
+ // Register input before the watcher so an accepted extension input cannot race request dispatch.
336
+ onRuntimeEvent("input", onInput);
248
337
  onRuntimeEvent("session_start", () => start());
249
338
  for (const eventName of ["message_start", "message_update", "message_end", "tool_execution_start", "tool_execution_end", "turn_end"] as const) {
250
339
  onRuntimeEvent(eventName, activate);
251
340
  }
252
341
  onRuntimeEvent("session_shutdown", () => {
253
342
  disposed = true;
254
- try {
255
- watcher?.close();
256
- } catch {}
343
+ try { watcher?.close(); } catch {}
257
344
  if (interval) clearInterval(interval);
258
345
  });
259
346
  }
260
347
 
261
348
  export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
262
349
  registerSteeringInbox(pi);
263
- registerToolBudget(pi, decodeToolBudgetEnv(process.env[TOOL_BUDGET_ENV]));
350
+ registerToolBudget(pi, decodeToolBudgetEnv(process.env[TOOL_BUDGET_ENV], { allowZero: process.env[TOOL_BUDGET_ZERO_AUTH_ENV] === "1" }));
351
+ registerChildWatchdog(pi);
352
+ const waitToolEnabled = resolveWaitToolConfig().enabled;
353
+ const waitState = {
354
+ baseCwd: "",
355
+ currentSessionId: null,
356
+ asyncJobs: new Map(),
357
+ foregroundControls: new Map(),
358
+ lastForegroundControlId: null,
359
+ cleanupTimers: new Map(),
360
+ lastUiContext: null,
361
+ poller: null,
362
+ completionSeen: new Map(),
363
+ watcher: null,
364
+ watcherRestartTimer: null,
365
+ resultFileCoalescer: { schedule: () => false, clear: () => {} },
366
+ } as unknown as SubagentState;
367
+ if (typeof pi.registerTool === "function") registerWaitTool(pi, waitState, waitToolEnabled);
264
368
  let nativeSupervisorClientRegistered = false;
265
369
  let nativeSupervisorFallbackRegistered = false;
266
370
  const registerNativeSupervisorClientOnce = (): void => {
@@ -275,17 +379,24 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
275
379
  registerNativeSupervisorClient(pi);
276
380
  };
277
381
  const onRuntimeEvent = pi.on as unknown as (event: string, handler: (event: unknown) => unknown) => void;
278
- onRuntimeEvent("session_start", registerNativeSupervisorClientOnce);
382
+ onRuntimeEvent("session_start", (_event: unknown, ctx: unknown) => {
383
+ const sessionManager = (ctx as { sessionManager?: Parameters<typeof resolveCurrentSessionId>[0] } | undefined)?.sessionManager;
384
+ waitState.currentSessionId = sessionManager ? resolveCurrentSessionId(sessionManager) : null;
385
+ registerNativeSupervisorClientOnce();
386
+ if (readRequiredChildTools()?.includes("intercom")) registerNativeSupervisorFallbackOnce();
387
+ });
388
+ onRuntimeEvent("agent_start", () => {
389
+ refreshChildToolDiagnostic(pi);
390
+ });
391
+ onRuntimeEvent("agent_end", async (_event: unknown, ctx: unknown) => {
392
+ if ((ctx as { hasUI?: boolean } | undefined)?.hasUI === true) return;
393
+ await drainOutstandingWork({ state: waitState, events: pi.events });
394
+ });
279
395
  const structuredOutputPath = process.env[STRUCTURED_OUTPUT_CAPTURE_ENV];
280
396
  const structuredSchemaPath = process.env[STRUCTURED_OUTPUT_SCHEMA_ENV];
281
397
  if (structuredOutputPath && structuredSchemaPath) {
282
398
  const schema = JSON.parse(fs.readFileSync(structuredSchemaPath, "utf-8")) as JsonSchemaObject;
283
- const parameters = {
284
- type: "object",
285
- properties: { value: schema },
286
- required: ["value"],
287
- additionalProperties: false,
288
- };
399
+ const parameters = createStructuredOutputToolParameters(schema);
289
400
  const registerTool = pi.registerTool as unknown as (tool: {
290
401
  name: string;
291
402
  label: string;
@@ -299,7 +410,7 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
299
410
  description: "Submit the required final structured output for this subagent step. This terminates the step.",
300
411
  parameters: parameters as never,
301
412
  async execute(_id: string, params: { value: unknown }) {
302
- const validation = validateStructuredOutputValue(schema, params.value);
413
+ const validation = await validateStructuredOutputValue(schema, params.value);
303
414
  if (validation.status === "invalid") {
304
415
  throw new Error(`Structured output validation failed: ${validation.message}`);
305
416
  }
@@ -330,12 +441,14 @@ export default function registerSubagentPromptRuntime(pi: ExtensionAPI): void {
330
441
  const inheritProjectContext = readBooleanEnv(SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV);
331
442
  const inheritSkills = readBooleanEnv(SUBAGENT_INHERIT_SKILLS_ENV);
332
443
  const fanoutChild = readBooleanEnv(SUBAGENT_FANOUT_CHILD_ENV);
333
- if (inheritProjectContext === undefined && inheritSkills === undefined && fanoutChild === undefined) return;
334
- const rewritten = rewriteSubagentPrompt(event.systemPrompt, {
335
- inheritProjectContext: inheritProjectContext ?? true,
336
- inheritSkills: inheritSkills ?? true,
337
- fanoutChild: fanoutChild === true,
338
- });
444
+ let rewritten = event.systemPrompt;
445
+ if (inheritProjectContext !== undefined || inheritSkills !== undefined || fanoutChild !== undefined) {
446
+ rewritten = rewriteSubagentPrompt(event.systemPrompt, {
447
+ inheritProjectContext: inheritProjectContext ?? true,
448
+ inheritSkills: inheritSkills ?? true,
449
+ fanoutChild: fanoutChild === true,
450
+ });
451
+ }
339
452
  if (rewritten === event.systemPrompt) return;
340
453
  return { systemPrompt: rewritten };
341
454
  });