@selesai/code 0.13.15 → 0.13.18

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 (473) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +2 -14
  3. package/dist/bun/cli.d.ts +3 -1
  4. package/dist/bun/cli.js +3 -9
  5. package/dist/bun/{register-bedrock.js → runtime-setup.js} +5 -0
  6. package/dist/bun/sandbox-env-setup.d.ts +1 -0
  7. package/dist/bun/sandbox-env-setup.js +3 -0
  8. package/dist/cli/auth-command.d.ts +23 -0
  9. package/dist/cli/auth-command.js +102 -0
  10. package/dist/cli/config-selector.js +2 -1
  11. package/dist/cli/setup.d.ts +1 -0
  12. package/dist/cli/setup.js +11 -0
  13. package/dist/cli.js +2 -14
  14. package/dist/config.d.ts +3 -2
  15. package/dist/config.js +9 -4
  16. package/dist/core/agent-session-runtime.js +15 -7
  17. package/dist/core/agent-session.d.ts +2 -6
  18. package/dist/core/agent-session.js +15 -4
  19. package/dist/core/compaction/branch-summarization.d.ts +1 -1
  20. package/dist/core/compaction/branch-summarization.js +2 -1
  21. package/dist/core/extensions/loader.js +3 -0
  22. package/dist/core/extensions/types.d.ts +16 -2
  23. package/dist/core/http-dispatcher.js +2 -0
  24. package/dist/core/keybindings.d.ts +5 -0
  25. package/dist/core/keybindings.js +4 -0
  26. package/dist/core/messages.d.ts +1 -1
  27. package/dist/core/model-config.d.ts +15 -0
  28. package/dist/core/model-config.js +3 -0
  29. package/dist/core/model-runtime.d.ts +1 -0
  30. package/dist/core/model-runtime.js +5 -2
  31. package/dist/core/provider-composer.js +8 -2
  32. package/dist/core/session-export.d.ts +3 -0
  33. package/dist/core/session-export.js +31 -0
  34. package/dist/core/session-manager.d.ts +3 -2
  35. package/dist/core/session-manager.js +40 -13
  36. package/dist/core/skills.d.ts +1 -1
  37. package/dist/core/skills.js +4 -2
  38. package/dist/core/system-prompt.js +10 -10
  39. package/dist/core/tools/bash.js +3 -117
  40. package/dist/core/tools/edit.d.ts +1 -12
  41. package/dist/core/tools/edit.js +5 -163
  42. package/dist/core/tools/find.js +4 -55
  43. package/dist/core/tools/grep.js +4 -60
  44. package/dist/core/tools/ls.js +4 -49
  45. package/dist/core/tools/read.d.ts +4 -0
  46. package/dist/core/tools/read.js +10 -122
  47. package/dist/core/tools/renderers/bash.d.ts +11 -0
  48. package/dist/core/tools/renderers/bash.js +129 -0
  49. package/dist/core/tools/renderers/edit.d.ts +22 -0
  50. package/dist/core/tools/renderers/edit.js +166 -0
  51. package/dist/core/tools/renderers/find.d.ts +9 -0
  52. package/dist/core/tools/renderers/find.js +63 -0
  53. package/dist/core/tools/renderers/grep.d.ts +9 -0
  54. package/dist/core/tools/renderers/grep.js +68 -0
  55. package/dist/core/tools/renderers/index.d.ts +27 -0
  56. package/dist/core/tools/renderers/index.js +46 -0
  57. package/dist/core/tools/renderers/ls.d.ts +9 -0
  58. package/dist/core/tools/renderers/ls.js +57 -0
  59. package/dist/core/tools/renderers/read.d.ts +10 -0
  60. package/dist/core/tools/renderers/read.js +128 -0
  61. package/dist/core/tools/renderers/write.d.ts +9 -0
  62. package/dist/core/tools/renderers/write.js +152 -0
  63. package/dist/core/tools/write.js +5 -146
  64. package/dist/extensions/capability-gateway/index.ts +12 -1
  65. package/dist/extensions/capability-gateway/integration.test.ts +23 -0
  66. package/dist/extensions/pi-hermes-memory/CHANGELOG.md +18 -0
  67. package/dist/extensions/pi-hermes-memory/README.md +16 -12
  68. package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +1 -1
  69. package/dist/extensions/pi-hermes-memory/package-lock.json +587 -62
  70. package/dist/extensions/pi-hermes-memory/package.json +4 -4
  71. package/dist/extensions/pi-hermes-memory/src/config.ts +32 -0
  72. package/dist/extensions/pi-hermes-memory/src/constants.ts +12 -2
  73. package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +109 -51
  74. package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +9 -3
  75. package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +257 -98
  76. package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +9 -2
  77. package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +5 -0
  78. package/dist/extensions/pi-hermes-memory/src/index.ts +22 -2
  79. package/dist/extensions/pi-hermes-memory/src/paths.ts +1 -1
  80. package/dist/extensions/pi-hermes-memory/src/store/db.ts +6 -0
  81. package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +58 -1
  82. package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +60 -8
  83. package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +169 -7
  84. package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +7 -21
  85. package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +134 -15
  86. package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +4 -2
  87. package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +24 -9
  88. package/dist/extensions/pi-hermes-memory/src/types.ts +11 -0
  89. package/dist/extensions/pi-hermes-memory/tests/config.test.ts +42 -0
  90. package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +159 -3
  91. package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +452 -0
  92. package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +39 -0
  93. package/dist/extensions/pi-hermes-memory/tests/integration/corruption-recovery-integration.test.ts +91 -0
  94. package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +29 -0
  95. package/dist/extensions/pi-hermes-memory/tests/store/fts-query.test.ts +116 -0
  96. package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +163 -0
  97. package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +233 -0
  98. package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +12 -0
  99. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +175 -0
  100. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +2 -2
  101. package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +22 -0
  102. package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +37 -1
  103. package/dist/extensions/pi-intercom/CHANGELOG.md +13 -0
  104. package/dist/extensions/pi-intercom/README.md +16 -2
  105. package/dist/extensions/pi-intercom/broker/spawn.test.ts +19 -2
  106. package/dist/extensions/pi-intercom/broker/spawn.ts +4 -4
  107. package/dist/extensions/pi-intercom/index.ts +1 -1
  108. package/dist/extensions/pi-intercom/intercom.integration.test.ts +121 -2
  109. package/dist/extensions/pi-intercom/package.json +1 -1
  110. package/dist/extensions/pi-intercom/project-agent.test.ts +1 -1
  111. package/dist/extensions/pi-intercom/project-agent.ts +1 -6
  112. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +7 -6
  113. package/dist/extensions/pi-rewind-hook/index.test.ts +7 -0
  114. package/dist/extensions/pi-subagents/.github/workflows/test.yml +36 -4
  115. package/dist/extensions/pi-subagents/CHANGELOG.md +120 -0
  116. package/dist/extensions/pi-subagents/README.md +3 -3
  117. package/dist/extensions/pi-subagents/agents/researcher.md +23 -13
  118. package/dist/extensions/pi-subagents/agents/reviewer.md +1 -1
  119. package/dist/extensions/pi-subagents/agents/scout.md +1 -1
  120. package/dist/extensions/pi-subagents/docs/agents.md +32 -16
  121. package/dist/extensions/pi-subagents/docs/configuration.md +41 -15
  122. package/dist/extensions/pi-subagents/docs/extension-api.md +109 -6
  123. package/dist/extensions/pi-subagents/docs/missions.md +2 -0
  124. package/dist/extensions/pi-subagents/docs/models.md +58 -1
  125. package/dist/extensions/pi-subagents/docs/observability.md +50 -12
  126. package/dist/extensions/pi-subagents/docs/tool-reference.md +17 -10
  127. package/dist/extensions/pi-subagents/docs/watchdog.md +1 -1
  128. package/dist/extensions/pi-subagents/docs/workflows.md +26 -9
  129. package/dist/extensions/pi-subagents/package-lock.json +747 -177
  130. package/dist/extensions/pi-subagents/package.json +6 -4
  131. package/dist/extensions/pi-subagents/runner-server-preload.mjs +13 -0
  132. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +2 -1
  133. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
  134. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +21 -4
  135. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -1
  136. package/dist/extensions/pi-subagents/skills/pi-subagents/references/multi-lane-orchestration.md +2 -0
  137. package/dist/extensions/pi-subagents/src/agents/advertised-agent-prompt.ts +63 -0
  138. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +61 -16
  139. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
  140. package/dist/extensions/pi-subagents/src/agents/agents.ts +8 -0
  141. package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +0 -1
  142. package/dist/extensions/pi-subagents/src/api/{pi-args.ts → child-tool-plan.ts} +1 -1
  143. package/dist/extensions/pi-subagents/src/api/preflight.ts +7 -4
  144. package/dist/extensions/pi-subagents/src/api/shared-types.ts +2 -2
  145. package/dist/extensions/pi-subagents/src/api/workflow-resources.ts +6 -0
  146. package/dist/extensions/pi-subagents/src/extension/config.ts +4 -2
  147. package/dist/extensions/pi-subagents/src/extension/doctor.ts +2 -10
  148. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +9 -11
  149. package/dist/extensions/pi-subagents/src/extension/index.ts +99 -10
  150. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +13 -0
  151. package/dist/extensions/pi-subagents/src/extension/rpc.ts +7 -23
  152. package/dist/extensions/pi-subagents/src/extension/schemas.ts +11 -8
  153. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +25 -7
  154. package/dist/extensions/pi-subagents/src/integrations/pi-web-session-liveness.ts +73 -0
  155. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +228 -136
  156. package/dist/extensions/pi-subagents/src/intercom/supervisor-ui.ts +244 -0
  157. package/dist/extensions/pi-subagents/src/missions/workflow-state.ts +37 -16
  158. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +18 -18
  159. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +51 -25
  160. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +46 -3
  161. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -3
  162. package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +9 -0
  163. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +10 -12
  164. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -15
  165. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +40 -29
  166. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +8 -0
  167. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +79 -247
  168. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +88 -12
  169. package/dist/extensions/pi-subagents/src/runs/background/owned-process-tree.ts +6 -6
  170. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +24 -24
  171. package/dist/extensions/pi-subagents/src/runs/background/retained-nested-route-tracker.ts +96 -0
  172. package/dist/extensions/pi-subagents/src/runs/background/run-child-session.ts +642 -0
  173. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +75 -6
  174. package/dist/extensions/pi-subagents/src/runs/background/runner-aliases.ts +163 -0
  175. package/dist/extensions/pi-subagents/src/runs/background/runner-child-launch.ts +86 -0
  176. package/dist/extensions/pi-subagents/src/runs/background/runner-child-sessions.ts +31 -0
  177. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +18 -4
  178. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -1
  179. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +597 -1092
  180. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +3 -0
  181. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +4 -0
  182. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +20 -17
  183. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +296 -394
  184. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +4 -0
  185. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +3 -1
  186. package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +9 -5
  187. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +630 -283
  188. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +8 -5
  189. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-foreground-steering.ts +78 -98
  190. package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +3 -3
  191. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +16 -3
  192. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +1 -1
  193. package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +47 -47
  194. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +1 -2
  195. package/dist/extensions/pi-subagents/src/runs/shared/child-hooks.ts +174 -0
  196. package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +14 -3
  197. package/dist/extensions/pi-subagents/src/runs/shared/child-launch.ts +319 -0
  198. package/dist/extensions/pi-subagents/src/runs/shared/child-lifecycle.ts +25 -0
  199. package/dist/extensions/pi-subagents/src/runs/shared/child-runtime-config.ts +126 -0
  200. package/dist/extensions/pi-subagents/src/runs/shared/child-session.ts +373 -0
  201. package/dist/extensions/pi-subagents/src/runs/shared/child-tool-plan.ts +530 -0
  202. package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +2 -2
  203. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +2 -1
  204. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +16 -0
  205. package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +11 -11
  206. package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +30 -20
  207. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +5 -4
  208. package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +84 -15
  209. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +88 -12
  210. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +37 -53
  211. package/dist/extensions/pi-subagents/src/runs/shared/nested-path.ts +1 -1
  212. package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +18 -7
  213. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +57 -12
  214. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +3 -4
  215. package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +0 -11
  216. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +4 -1
  217. package/dist/extensions/pi-subagents/src/runs/shared/readonly-drain-observation.ts +42 -0
  218. package/dist/extensions/pi-subagents/src/runs/shared/readonly-model-continuation.ts +69 -0
  219. package/dist/extensions/pi-subagents/src/runs/shared/readonly-session-evidence.ts +307 -0
  220. package/dist/extensions/pi-subagents/src/runs/shared/run-fanout-budget.ts +8 -21
  221. package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +3 -30
  222. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +17 -4
  223. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +2 -0
  224. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +99 -386
  225. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +18 -62
  226. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +0 -14
  227. package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +31 -9
  228. package/dist/extensions/pi-subagents/src/runs/shared/worktree-setup-command.ts +190 -0
  229. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +506 -226
  230. package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +1 -1
  231. package/dist/extensions/pi-subagents/src/shared/jsonl-writer.ts +11 -0
  232. package/dist/extensions/pi-subagents/src/shared/model-response-aliases.ts +13 -0
  233. package/dist/extensions/pi-subagents/src/shared/thinking-ceiling.ts +0 -6
  234. package/dist/extensions/pi-subagents/src/shared/types.ts +145 -89
  235. package/dist/extensions/pi-subagents/src/shared/utils.ts +13 -6
  236. package/dist/extensions/pi-subagents/src/shared/watch-strategy.ts +2 -0
  237. package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +18 -13
  238. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +0 -6
  239. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +1 -1
  240. package/dist/extensions/pi-subagents/src/tui/fleet.ts +11 -6
  241. package/dist/extensions/pi-subagents/src/tui/render.ts +277 -46
  242. package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +0 -1
  243. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +12 -12
  244. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +3 -3
  245. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +116 -15
  246. package/dist/extensions/pi-subagents/src/workflows/workflow-checklist.ts +15 -18
  247. package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +57 -8
  248. package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +19 -19
  249. package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +3 -3
  250. package/dist/extensions/pi-subagents/src/workflows/workflow-resources.ts +97 -22
  251. package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +3 -0
  252. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +336 -21
  253. package/dist/extensions/pi-subagents/test/integration/async-execution.part-1.test.ts +1181 -0
  254. package/dist/extensions/pi-subagents/test/integration/async-execution.part-2.test.ts +2240 -0
  255. package/dist/extensions/pi-subagents/test/integration/async-execution.part-3.test.ts +2268 -0
  256. package/dist/extensions/pi-subagents/test/integration/async-execution.part-4.test.ts +1512 -0
  257. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +231 -16
  258. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +4 -18
  259. package/dist/extensions/pi-subagents/test/integration/foreign-workflow-steering.test.ts +95 -0
  260. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +9 -15
  261. package/dist/extensions/pi-subagents/test/integration/in-process-child.test.ts +374 -0
  262. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +20 -10
  263. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +18 -6
  264. package/dist/extensions/pi-subagents/test/integration/recovered-assistant-error.test.ts +151 -0
  265. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +42 -1
  266. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +150 -25
  267. package/dist/extensions/pi-subagents/test/integration/result-publication.test.ts +354 -0
  268. package/dist/extensions/pi-subagents/test/integration/shared-cwd-terminal-evidence.test.ts +117 -0
  269. package/dist/extensions/pi-subagents/test/integration/single-execution.part-1.test.ts +3678 -0
  270. package/dist/extensions/pi-subagents/test/integration/{single-execution.test.ts → single-execution.part-2.test.ts} +500 -4207
  271. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +1 -2
  272. package/dist/extensions/pi-subagents/test/integration/workflow-result-publication.test.ts +127 -0
  273. package/dist/extensions/pi-subagents/test/integration/workflow-steer-inbox.test.ts +365 -0
  274. package/dist/extensions/pi-subagents/test/smoke/pi085-child.ts +31 -0
  275. package/dist/extensions/pi-subagents/test/smoke/pi085-clean-install.mjs +74 -0
  276. package/dist/extensions/pi-subagents/test/smoke/pi085-extension.ts +16 -0
  277. package/dist/extensions/pi-subagents/test/support/async-execution-fixture.ts +699 -0
  278. package/dist/extensions/pi-subagents/test/support/fake-child-session.ts +418 -0
  279. package/dist/extensions/pi-subagents/test/support/foreign-workflow-steer-host.mjs +13 -0
  280. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +30 -76
  281. package/dist/extensions/pi-subagents/test/support/notify-diagnostics-fixture.ts +84 -0
  282. package/dist/extensions/pi-subagents/test/support/result-publication-capacity-preload.mjs +70 -0
  283. package/dist/extensions/pi-subagents/test/support/runner-child-session-factory.ts +17 -0
  284. package/dist/extensions/pi-subagents/test/support/single-execution-fixture.ts +390 -0
  285. package/dist/extensions/pi-subagents/test/unit/acceptance-compaction.test.ts +120 -0
  286. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +24 -3
  287. package/dist/extensions/pi-subagents/test/unit/advertised-agent-prompt.test.ts +87 -0
  288. package/dist/extensions/pi-subagents/test/unit/advertised-agent-refresh.test.ts +163 -0
  289. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +70 -31
  290. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +78 -3
  291. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +2 -8
  292. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +1 -1
  293. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +73 -66
  294. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +51 -1
  295. package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +49 -1
  296. package/dist/extensions/pi-subagents/test/unit/async-spawn-preload.test.ts +103 -0
  297. package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +3 -3
  298. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +9 -8
  299. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +10 -7
  300. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +48 -6
  301. package/dist/extensions/pi-subagents/test/unit/child-runtime-config.test.ts +90 -0
  302. package/dist/extensions/pi-subagents/test/unit/{pi-args-permission-system.test.ts → child-tool-plan-permission-system.test.ts} +48 -86
  303. package/dist/extensions/pi-subagents/test/unit/child-tool-plan.test.ts +33 -0
  304. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +18 -18
  305. package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +9 -9
  306. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +8 -7
  307. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +225 -65
  308. package/dist/extensions/pi-subagents/test/unit/extension-bindings.test.ts +17 -22
  309. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +11 -1
  310. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +47 -3
  311. package/dist/extensions/pi-subagents/test/unit/foreign-workflow-steering.test.ts +74 -0
  312. package/dist/extensions/pi-subagents/test/unit/fork-cache-key.test.ts +23 -29
  313. package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +96 -4
  314. package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +4 -4
  315. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +116 -55
  316. package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +58 -1
  317. package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +104 -3
  318. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +10 -1
  319. package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +31 -1
  320. package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +102 -51
  321. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +196 -6
  322. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +181 -38
  323. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +62 -70
  324. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +58 -53
  325. package/dist/extensions/pi-subagents/test/unit/notify-diagnostics.test.ts +42 -0
  326. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +84 -0
  327. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +13 -5
  328. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +21 -5
  329. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +5 -4
  330. package/dist/extensions/pi-subagents/test/unit/permissions.test.ts +2 -6
  331. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +28 -2
  332. package/dist/extensions/pi-subagents/test/unit/pi-web-session-liveness.test.ts +209 -0
  333. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +38 -1
  334. package/dist/extensions/pi-subagents/test/unit/prompt-audit-optional-peers.test.ts +43 -0
  335. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +24 -2
  336. package/dist/extensions/pi-subagents/test/unit/readonly-drain-observation.test.ts +174 -0
  337. package/dist/extensions/pi-subagents/test/unit/readonly-model-continuation.test.ts +94 -0
  338. package/dist/extensions/pi-subagents/test/unit/readonly-session-evidence.test.ts +1329 -0
  339. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +29 -80
  340. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +11 -8
  341. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +2 -2
  342. package/dist/extensions/pi-subagents/test/unit/retained-nested-route-tracker.test.ts +175 -0
  343. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +38 -12
  344. package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +2 -5
  345. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +89 -1
  346. package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +2 -16
  347. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +27 -3
  348. package/dist/extensions/pi-subagents/test/unit/scheduled-supervisor-demand.test.ts +215 -0
  349. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +15 -11
  350. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +237 -1
  351. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -5
  352. package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +2 -2
  353. package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +14 -1
  354. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +130 -739
  355. package/dist/extensions/pi-subagents/test/unit/supervisor-ask-registration.test.ts +682 -0
  356. package/dist/extensions/pi-subagents/test/unit/supervisor-ui.test.ts +137 -0
  357. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +1 -11
  358. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +23 -3
  359. package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +8 -1
  360. package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +19 -1
  361. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +72 -4
  362. package/dist/extensions/pi-subagents/test/unit/workflow-checklist.test.ts +17 -3
  363. package/dist/extensions/pi-subagents/test/unit/workflow-child-summary.test.ts +34 -0
  364. package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +12 -2
  365. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +46 -6
  366. package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +3 -3
  367. package/dist/extensions/pi-subagents/test/unit/workflow-resources.test.ts +133 -1
  368. package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +53 -2
  369. package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +222 -14
  370. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +526 -85
  371. package/dist/extensions/pi-web-agent/src/backends/config.ts +1 -0
  372. package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +5 -3
  373. package/dist/extensions/pi-web-agent/src/search/tokenin.ts +7 -3
  374. package/dist/extensions/pi-web-agent/src/types.ts +1 -1
  375. package/dist/extensions/pi-zentui/README.md +17 -0
  376. package/dist/extensions/pi-zentui/assets/screenshots/footer-status-hyperlink.png +0 -0
  377. package/dist/extensions/pi-zentui/docs/configuration.md +71 -2
  378. package/dist/extensions/pi-zentui/extensions/zentui/config.ts +11 -0
  379. package/dist/extensions/pi-zentui/extensions/zentui/editor-transfer.ts +14 -0
  380. package/dist/extensions/pi-zentui/extensions/zentui/extension-status.ts +29 -13
  381. package/dist/extensions/pi-zentui/extensions/zentui/footer-layout.ts +5 -4
  382. package/dist/extensions/pi-zentui/extensions/zentui/footer-text.ts +11 -0
  383. package/dist/extensions/pi-zentui/extensions/zentui/footer.ts +11 -10
  384. package/dist/extensions/pi-zentui/extensions/zentui/index.ts +77 -3
  385. package/dist/extensions/pi-zentui/extensions/zentui/presets.ts +77 -0
  386. package/dist/extensions/pi-zentui/extensions/zentui/settings-command.ts +103 -2
  387. package/dist/extensions/pi-zentui/extensions/zentui/working-line-extension-segments.ts +115 -0
  388. package/dist/extensions/pi-zentui/extensions/zentui/working-line.ts +87 -5
  389. package/dist/extensions/pi-zentui/package-lock.json +277 -517
  390. package/dist/extensions/pi-zentui/package.json +7 -4
  391. package/dist/extensions/pi-zentui/test/config-presets.test.ts +238 -0
  392. package/dist/extensions/pi-zentui/test/editor-transfer.test.ts +24 -1
  393. package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +570 -2
  394. package/dist/extensions/pi-zentui/test/extension-status.test.ts +90 -0
  395. package/dist/extensions/pi-zentui/test/footer-hyperlink.test.ts +243 -0
  396. package/dist/extensions/pi-zentui/test/package-contents.mjs +1 -0
  397. package/dist/extensions/pi-zentui/test/presets.test.ts +121 -0
  398. package/dist/extensions/pi-zentui/test/settings-command.test.ts +205 -1
  399. package/dist/extensions/pi-zentui/test/working-line-extension-segments.test.ts +139 -0
  400. package/dist/extensions/pi-zentui/test/working-line-lifecycle.integration.test.ts +237 -3
  401. package/dist/extensions/pi-zentui/test/working-line.test.ts +94 -2
  402. package/dist/index.d.ts +1 -1
  403. package/dist/main.js +4 -1
  404. package/dist/modes/interactive/chat-viewport.d.ts +19 -0
  405. package/dist/modes/interactive/chat-viewport.js +27 -0
  406. package/dist/modes/interactive/components/assistant-message.d.ts +6 -2
  407. package/dist/modes/interactive/components/assistant-message.js +30 -13
  408. package/dist/modes/interactive/components/custom-editor.d.ts +10 -1
  409. package/dist/modes/interactive/components/custom-editor.js +39 -1
  410. package/dist/modes/interactive/components/first-time-setup.js +1 -1
  411. package/dist/modes/interactive/components/index.d.ts +1 -1
  412. package/dist/modes/interactive/components/markdown-transform.d.ts +2 -0
  413. package/dist/modes/interactive/components/markdown-transform.js +18 -0
  414. package/dist/modes/interactive/components/model-selector.js +19 -17
  415. package/dist/modes/interactive/components/scoped-models-selector.js +21 -23
  416. package/dist/modes/interactive/components/settings-selector.d.ts +7 -1
  417. package/dist/modes/interactive/components/settings-selector.js +128 -20
  418. package/dist/modes/interactive/components/settings-submenu.d.ts +71 -0
  419. package/dist/modes/interactive/components/settings-submenu.js +164 -0
  420. package/dist/modes/interactive/components/status-indicator.d.ts +3 -1
  421. package/dist/modes/interactive/components/status-indicator.js +10 -3
  422. package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
  423. package/dist/modes/interactive/components/thinking-selector.js +75 -18
  424. package/dist/modes/interactive/components/tool-execution.d.ts +21 -4
  425. package/dist/modes/interactive/components/tool-execution.js +35 -33
  426. package/dist/modes/interactive/components/trust-selector.js +2 -2
  427. package/dist/modes/interactive/interactive-mode.d.ts +13 -15
  428. package/dist/modes/interactive/interactive-mode.js +144 -80
  429. package/dist/modes/interactive/session-share.d.ts +15 -0
  430. package/dist/modes/interactive/session-share.js +183 -0
  431. package/dist/modes/interactive/theme/dark.json +2 -1
  432. package/dist/modes/interactive/theme/light.json +2 -1
  433. package/dist/modes/interactive/theme/theme-controller.d.ts +1 -0
  434. package/dist/modes/interactive/theme/theme-controller.js +5 -0
  435. package/dist/modes/interactive/theme/theme-json.d.ts +83 -0
  436. package/dist/modes/interactive/theme/theme-json.js +129 -0
  437. package/dist/modes/interactive/theme/theme-schema.json +9 -1
  438. package/dist/modes/interactive/theme/theme.d.ts +14 -5
  439. package/dist/modes/interactive/theme/theme.js +18 -119
  440. package/dist/modes/interactive/tui-renderer.d.ts +20 -0
  441. package/dist/modes/interactive/tui-renderer.js +65 -0
  442. package/dist/utils/exif-orientation.js +2 -3
  443. package/dist/utils/management-http.d.ts +24 -0
  444. package/dist/utils/management-http.js +53 -0
  445. package/dist/utils/text.d.ts +7 -0
  446. package/dist/utils/text.js +8 -0
  447. package/dist/utils/tools-manager.d.ts +1 -0
  448. package/dist/utils/tools-manager.js +43 -21
  449. package/docs/docs.json +0 -4
  450. package/package.json +4 -4
  451. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +0 -415
  452. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +0 -1059
  453. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +0 -116
  454. package/dist/extensions/pi-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
  455. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +0 -224
  456. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +0 -6986
  457. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +0 -447
  458. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +0 -185
  459. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +0 -311
  460. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +0 -84
  461. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +0 -202
  462. package/dist/extensions/pi-subagents/test/unit/close-grace-timer.test.ts +0 -101
  463. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +0 -2347
  464. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +0 -104
  465. package/dist/extensions/pi-subagents/test/unit/windows-hide-spawn.test.ts +0 -49
  466. package/dist/skills/imagegen-frontend-mobile/SKILL.md +0 -1465
  467. package/dist/skills/imagegen-frontend-web/SKILL.md +0 -987
  468. package/dist/skills/implanger/SKILL.md +0 -70
  469. package/dist/skills/output/SKILL.md +0 -49
  470. package/dist/skills/planger/SKILL.md +0 -167
  471. package/dist/skills/workflow/SKILL.md +0 -95
  472. package/docs/workflows.md +0 -18
  473. /package/dist/bun/{register-bedrock.d.ts → runtime-setup.d.ts} +0 -0
@@ -4,9 +4,10 @@ import * as path from "node:path";
4
4
  import { afterEach, describe, it } from "node:test";
5
5
  import { registerExternalJobProvider } from "../../src/api/external-job-provider.ts";
6
6
  import { getArtifactsDir } from "../../src/shared/artifacts.ts";
7
- import { SUBAGENT_CHILD_STATUS_EVENT } from "../../src/shared/types.ts";
7
+ import { SUBAGENT_CHILD_STATUS_EVENT, SUBAGENT_CONTROL_EVENT, type ControlEvent } from "../../src/shared/types.ts";
8
8
  import { ACTIVE_RUN_INDEX_DIR, updateActiveRunIndex } from "../../src/runs/background/active-run-index.ts";
9
9
  import { EXTERNAL_JOB_BRIDGE_REQUEST_DIR } from "../../src/runs/shared/external-job-bridge.ts";
10
+ import { createNativeSupervisorChannel, ensureSupervisorChannelDir, resolveSupervisorChannelDir } from "../../src/intercom/native-supervisor-channel.ts";
10
11
  import { SubagentFleetComponent } from "../../src/tui/fleet.ts";
11
12
  import { createNestedRoute } from "../../src/runs/shared/nested-events.ts";
12
13
  import { createTempDir, removeTempDir, tryImport } from "../support/helpers.ts";
@@ -26,6 +27,7 @@ interface AsyncJobTrackerModule {
26
27
  watch?: typeof fs.watch;
27
28
  kill?: (pid: number, signal?: NodeJS.Signals | 0) => boolean;
28
29
  now?: () => number;
30
+ supervisorRequestState?: (event: ControlEvent) => "pending" | "resolved" | "unknown";
29
31
  },
30
32
  ): {
31
33
  ensurePoller(): void;
@@ -89,6 +91,85 @@ function createEventRecorder() {
89
91
  };
90
92
  }
91
93
 
94
+ function writeSupervisorRequest(input: { sessionId: string; runId: string; toolCallId: string }): { channelDir: string; requestId: string } {
95
+ const channelDir = resolveSupervisorChannelDir(input.runId, "worker", 0);
96
+ ensureSupervisorChannelDir(channelDir);
97
+ const requestId = `request-${input.toolCallId}`;
98
+ fs.writeFileSync(path.join(channelDir, "requests", `${requestId}.json`), JSON.stringify({
99
+ type: "subagent.supervisor.request",
100
+ id: requestId,
101
+ createdAt: Date.now(),
102
+ reason: "need_decision",
103
+ message: "Need a decision",
104
+ expectsReply: true,
105
+ orchestratorSessionId: input.sessionId,
106
+ runId: input.runId,
107
+ agent: "worker",
108
+ childIndex: 0,
109
+ toolCallId: input.toolCallId,
110
+ }), "utf-8");
111
+ return { channelDir, requestId };
112
+ }
113
+
114
+ function writeControlRecord(runDir: string, event: ControlEvent): void {
115
+ fs.appendFileSync(path.join(runDir, "events.jsonl"), `${JSON.stringify({ type: "subagent.control", channels: ["event"], event })}\n`, "utf-8");
116
+ }
117
+
118
+ function supervisorControlEvent(runId: string, toolCallId: string, currentTool = "contact_supervisor"): ControlEvent {
119
+ return {
120
+ type: "needs_attention",
121
+ to: "needs_attention",
122
+ ts: Date.now(),
123
+ runId,
124
+ agent: "worker",
125
+ index: 0,
126
+ message: "worker is waiting for a supervisor reply",
127
+ reason: "supervisor_request",
128
+ currentTool,
129
+ toolCallId,
130
+ };
131
+ }
132
+
133
+ function writeRunningAsyncStatus(runDir: string, runId: string, sessionId: string): void {
134
+ fs.mkdirSync(runDir, { recursive: true });
135
+ fs.writeFileSync(path.join(runDir, "status.json"), JSON.stringify({
136
+ runId,
137
+ mode: "single",
138
+ state: "running",
139
+ sessionId,
140
+ startedAt: Date.now(),
141
+ lastUpdate: Date.now(),
142
+ steps: [{ agent: "worker", status: "running" }],
143
+ }), "utf-8");
144
+ }
145
+
146
+ function createNativeSupervisorHarness(sessionId: string) {
147
+ const nativeState = createState();
148
+ (nativeState as { currentSessionId: string; lastUiContext: unknown }).currentSessionId = sessionId;
149
+ (nativeState as { supervisorOwnerSessionId: string }).supervisorOwnerSessionId = sessionId;
150
+ (nativeState as { currentSessionId: string; lastUiContext: unknown }).lastUiContext = {
151
+ hasUI: false,
152
+ sessionManager: {
153
+ getSessionId: () => sessionId,
154
+ getSessionFile: () => null,
155
+ getEntries: () => [],
156
+ },
157
+ };
158
+ const tools = new Map<string, { execute: (id: string, params: Record<string, unknown>) => Promise<unknown> }>();
159
+ const sent: Array<{ customType?: string; options?: { triggerTurn?: boolean } }> = [];
160
+ const pi = {
161
+ getAllTools: () => [...tools.keys()].map((name) => ({ name })),
162
+ registerTool: (tool: { name: string; execute: (...args: unknown[]) => Promise<unknown> }) => {
163
+ tools.set(tool.name, { execute: (id, params) => tool.execute(id, params) });
164
+ },
165
+ sendMessage: (message: { customType?: string }, options?: { triggerTurn?: boolean }) => {
166
+ sent.push({ customType: message.customType, options });
167
+ },
168
+ };
169
+ const channel = createNativeSupervisorChannel(pi as never, nativeState as never, { platform: "win32" });
170
+ return { channel, tools, sent };
171
+ }
172
+
92
173
  function pidGone(): never {
93
174
  const error = new Error("missing") as NodeJS.ErrnoException;
94
175
  error.code = "ESRCH";
@@ -430,7 +511,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
430
511
  updateActiveRunIndex(runDir, "running");
431
512
  const state = createState();
432
513
  state.currentSessionId = "session-restored-nested";
433
- const tracker = createTracker(createEventRecorder().selesai, state as never, asyncRoot, { pollIntervalMs: 60_000 });
514
+ const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, { pollIntervalMs: 60_000 });
434
515
  tracker.restoreActiveJobs();
435
516
  assert.equal(state.asyncJobs.get("run-restored-nested")?.nestedRoute?.eventSink, nestedRoute.eventSink);
436
517
 
@@ -483,7 +564,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
483
564
  updateActiveRunIndex(runDir, "running");
484
565
  const state = createState();
485
566
  state.currentSessionId = "session-workflow";
486
- const tracker = createTracker(createEventRecorder().selesai, state as never, asyncRoot, { pollIntervalMs: 60_000 });
567
+ const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, { pollIntervalMs: 60_000 });
487
568
  tracker.restoreActiveJobs();
488
569
  assert.deepEqual(state.asyncJobs.get("workflow-run")?.workflow?.emits, [{ stage: "scan" }]);
489
570
  assert.equal(state.asyncJobs.get("workflow-run")?.sessionRoot, "/trusted/workflow-sessions");
@@ -513,7 +594,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
513
594
  fs.mkdirSync(runDir, { recursive: true });
514
595
  const state = createState();
515
596
  state.currentSessionId = "session-late-status";
516
- const tracker = createTracker(createEventRecorder().selesai, state as never, asyncRoot, { pollIntervalMs: 60_000 });
597
+ const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, { pollIntervalMs: 60_000 });
517
598
  tracker.handleStarted({ id: "late-status-run", asyncDir: runDir, sessionId: "session-late-status", agent: "worker" });
518
599
 
519
600
  await new Promise((resolve) => setTimeout(resolve, 150));
@@ -548,7 +629,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
548
629
  steps: [{ agent: "worker", status: "running" }],
549
630
  }), "utf-8");
550
631
  const state = createState();
551
- const tracker = createTracker(createEventRecorder().selesai, state as never, asyncRoot, {
632
+ const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
552
633
  pollIntervalMs: 10,
553
634
  watch: (() => { throw new Error("native watcher disabled for test"); }) as never,
554
635
  });
@@ -609,7 +690,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
609
690
  reattach: () => ({ providerJobId: "provider-job", state: "completed" }),
610
691
  });
611
692
  const state = createState();
612
- const tracker = createTracker(createEventRecorder().selesai, state as never, asyncRoot, {
693
+ const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
613
694
  pollIntervalMs: 10,
614
695
  watch: (() => { throw new Error("native watcher disabled for test"); }) as never,
615
696
  });
@@ -642,7 +723,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
642
723
  steps: [{ agent: "worker", status: "running", runner: { type: "external-job", provider: "tracker-provider-late", options: {} } }],
643
724
  }), "utf-8");
644
725
  const state = createState();
645
- const tracker = createTracker(createEventRecorder().selesai, state as never, asyncRoot, {
726
+ const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
646
727
  pollIntervalMs: 10,
647
728
  watch: (() => { throw new Error("native watcher disabled for test"); }) as never,
648
729
  });
@@ -692,7 +773,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
692
773
  fs.mkdirSync(path.join(runDir, EXTERNAL_JOB_BRIDGE_REQUEST_DIR), { recursive: true });
693
774
  fs.writeFileSync(path.join(runDir, EXTERNAL_JOB_BRIDGE_REQUEST_DIR, "malformed.json"), "{malformed", "utf-8");
694
775
  const state = createState();
695
- const tracker = createTracker(createEventRecorder().selesai, state as never, asyncRoot, {
776
+ const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
696
777
  pollIntervalMs: 10,
697
778
  watch: (() => { throw new Error("native watcher disabled for test"); }) as never,
698
779
  });
@@ -724,11 +805,16 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
724
805
  }), "utf-8");
725
806
  const state = createState();
726
807
  const ui = createUiContext();
727
- const tracker = createTracker(createEventRecorder().selesai, state as never, asyncRoot, { pollIntervalMs: 10 });
808
+ const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
809
+ pollIntervalMs: 10,
810
+ watch: (() => { throw new Error("native watcher disabled for test"); }) as never,
811
+ });
728
812
  tracker.resetJobs(ui.ctx as never);
729
813
  tracker.handleStarted({ id: "quiet-run", asyncDir: runDir, agent: "worker" });
730
814
 
815
+ const rendersAfterStart = ui.renderRequests;
731
816
  await waitForCondition(() => state.asyncJobs.get("quiet-run")?.status === "running", "quiet running job refresh");
817
+ await waitForCondition(() => ui.renderRequests > rendersAfterStart, "quiet running widget redraw");
732
818
  const renderRequests = ui.renderRequests;
733
819
  await new Promise((resolve) => setTimeout(resolve, 120));
734
820
 
@@ -755,7 +841,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
755
841
  const state = createState();
756
842
  let nativeWatchCalls = 0;
757
843
  let terminalHooks = 0;
758
- const tracker = createTracker(createEventRecorder().selesai, state as never, asyncRoot, {
844
+ const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
759
845
  platform: "darwin",
760
846
  pollIntervalMs: 10,
761
847
  onJobTerminal: () => terminalHooks++,
@@ -804,7 +890,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
804
890
  };
805
891
  fs.writeFileSync(statusPath, JSON.stringify(statusPayload), "utf-8");
806
892
  const state = createState();
807
- const tracker = createTracker(createEventRecorder().selesai, state as never, asyncRoot, { pollIntervalMs: 60_000 });
893
+ const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, { pollIntervalMs: 60_000 });
808
894
  tracker.handleStarted({ id: "run-nested-events", asyncDir: runDir, agent: "worker", nestedRoute });
809
895
 
810
896
  await new Promise((resolve) => setTimeout(resolve, 150));
@@ -854,7 +940,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
854
940
  updateActiveRunIndex(runDir, "running");
855
941
  const state = createState();
856
942
  state.currentSessionId = "session-workflow";
857
- const tracker = createTracker(createEventRecorder().selesai, state as never, asyncRoot, { pollIntervalMs: 10 });
943
+ const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, { pollIntervalMs: 10 });
858
944
  tracker.restoreActiveJobs();
859
945
  assert.equal(state.asyncJobs.get("workflow-child")?.parentWorkflowRunId, "workflow-parent");
860
946
  assert.equal(state.asyncJobs.get("workflow-child")?.workflowKey, "review");
@@ -892,7 +978,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
892
978
 
893
979
  const state = createState();
894
980
  state.currentSessionId = "session-owner";
895
- const tracker = createTracker(createEventRecorder().selesai, state as never, asyncRoot, {
981
+ const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
896
982
  pollIntervalMs: 10,
897
983
  });
898
984
  tracker.restoreActiveJobs();
@@ -909,7 +995,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
909
995
  try {
910
996
  const state = createState();
911
997
  state.currentSessionId = "session-owner";
912
- const tracker = createTracker(createEventRecorder().selesai, state as never, asyncRoot, {
998
+ const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
913
999
  completionRetentionMs: 5,
914
1000
  pollIntervalMs: 10,
915
1001
  });
@@ -1205,7 +1291,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
1205
1291
  try {
1206
1292
  const runDir = path.join(asyncRoot, "run-late-dir");
1207
1293
  const state = createState();
1208
- const tracker = createTracker(createEventRecorder().selesai, state as never, asyncRoot, {
1294
+ const tracker = createTracker(createEventRecorder().pi, state as never, asyncRoot, {
1209
1295
  completionRetentionMs: 5,
1210
1296
  pollIntervalMs: 60_000,
1211
1297
  });
@@ -1472,6 +1558,135 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
1472
1558
  }
1473
1559
  });
1474
1560
 
1561
+ it("suppresses a resolved native supervisor notice before async replay", async () => {
1562
+ const asyncRoot = createTempDir("pi-async-job-supervisor-replay-resolved-");
1563
+ const sessionId = `session-${Date.now()}`;
1564
+ const runId = `run-${Date.now()}`;
1565
+ const toolCallId = `call-${Date.now()}`;
1566
+ const { channel, tools, sent } = createNativeSupervisorHarness(sessionId);
1567
+ const { channelDir, requestId } = writeSupervisorRequest({ sessionId, runId, toolCallId });
1568
+ try {
1569
+ const runDir = path.join(asyncRoot, runId);
1570
+ writeRunningAsyncStatus(runDir, runId, sessionId);
1571
+ const event = supervisorControlEvent(runId, toolCallId);
1572
+ writeControlRecord(runDir, event);
1573
+
1574
+ channel.start();
1575
+ assert.equal(channel.getSupervisorRequestState(event), "pending");
1576
+ const state = createState();
1577
+ const recorder = createEventRecorder();
1578
+ const tracker = createTracker(recorder.pi, state as never, asyncRoot, {
1579
+ pollIntervalMs: 10,
1580
+ supervisorRequestState: channel.getSupervisorRequestState,
1581
+ });
1582
+ tracker.handleStarted({ id: runId, asyncDir: runDir, agent: "worker", sessionId });
1583
+ await tools.get("subagent_supervisor")!.execute("reply", { action: "reply", replyTo: requestId, message: "Approved" });
1584
+ assert.equal(channel.getSupervisorRequestState(event), "resolved");
1585
+ await waitForCondition(() => (state.asyncJobs.get(runId)?.controlEventCursor ?? 0) > 0, "resolved control event cursor");
1586
+
1587
+ assert.equal(recorder.events.some((entry) => entry.channel === SUBAGENT_CONTROL_EVENT), false);
1588
+ assert.deepEqual(sent, [{ customType: "subagent_supervisor_request", options: { triggerTurn: true } }]);
1589
+ } finally {
1590
+ channel.dispose();
1591
+ fs.rmSync(channelDir, { recursive: true, force: true });
1592
+ removeTempDir(asyncRoot);
1593
+ }
1594
+ });
1595
+
1596
+ it("delivers a native supervisor notice while its request is pending through replay", async () => {
1597
+ const asyncRoot = createTempDir("pi-async-job-supervisor-replay-pending-");
1598
+ const sessionId = `session-${Date.now()}`;
1599
+ const runId = `run-${Date.now()}`;
1600
+ const toolCallId = `call-${Date.now()}`;
1601
+ const { channel, sent } = createNativeSupervisorHarness(sessionId);
1602
+ const { channelDir } = writeSupervisorRequest({ sessionId, runId, toolCallId });
1603
+ try {
1604
+ const runDir = path.join(asyncRoot, runId);
1605
+ writeRunningAsyncStatus(runDir, runId, sessionId);
1606
+ const event = supervisorControlEvent(runId, toolCallId);
1607
+ writeControlRecord(runDir, event);
1608
+
1609
+ channel.start();
1610
+ assert.equal(channel.getSupervisorRequestState(event), "pending");
1611
+ const state = createState();
1612
+ const recorder = createEventRecorder();
1613
+ const tracker = createTracker(recorder.pi, state as never, asyncRoot, {
1614
+ pollIntervalMs: 10,
1615
+ supervisorRequestState: channel.getSupervisorRequestState,
1616
+ });
1617
+ tracker.handleStarted({ id: runId, asyncDir: runDir, agent: "worker", sessionId });
1618
+ await waitForCondition(() => recorder.events.some((entry) => entry.channel === SUBAGENT_CONTROL_EVENT), "pending control event replay");
1619
+
1620
+ const payload = recorder.events.find((entry) => entry.channel === SUBAGENT_CONTROL_EVENT)?.data as { event?: ControlEvent } | undefined;
1621
+ assert.equal(payload?.event?.toolCallId, toolCallId);
1622
+ assert.deepEqual(sent.map((entry) => entry.customType), ["subagent_supervisor_request"]);
1623
+ } finally {
1624
+ channel.dispose();
1625
+ fs.rmSync(channelDir, { recursive: true, force: true });
1626
+ removeTempDir(asyncRoot);
1627
+ }
1628
+ });
1629
+
1630
+ it("keeps the first native supervisor notice after resolution and suppresses later replay", async () => {
1631
+ const asyncRoot = createTempDir("pi-async-job-supervisor-replay-late-");
1632
+ const sessionId = `session-${Date.now()}`;
1633
+ const runId = `run-${Date.now()}`;
1634
+ const toolCallId = `call-${Date.now()}`;
1635
+ const { channel, tools } = createNativeSupervisorHarness(sessionId);
1636
+ const { channelDir, requestId } = writeSupervisorRequest({ sessionId, runId, toolCallId });
1637
+ try {
1638
+ const runDir = path.join(asyncRoot, runId);
1639
+ writeRunningAsyncStatus(runDir, runId, sessionId);
1640
+ const event = supervisorControlEvent(runId, toolCallId);
1641
+ writeControlRecord(runDir, event);
1642
+
1643
+ channel.start();
1644
+ const state = createState();
1645
+ const recorder = createEventRecorder();
1646
+ const tracker = createTracker(recorder.pi, state as never, asyncRoot, {
1647
+ pollIntervalMs: 10,
1648
+ supervisorRequestState: channel.getSupervisorRequestState,
1649
+ });
1650
+ tracker.handleStarted({ id: runId, asyncDir: runDir, agent: "worker", sessionId });
1651
+ await waitForCondition(() => recorder.events.filter((entry) => entry.channel === SUBAGENT_CONTROL_EVENT).length === 1, "first control event replay");
1652
+
1653
+ await tools.get("subagent_supervisor")!.execute("reply", { action: "reply", replyTo: requestId, message: "Approved" });
1654
+ writeControlRecord(runDir, event);
1655
+ const eventSize = fs.statSync(path.join(runDir, "events.jsonl")).size;
1656
+ await waitForCondition(() => (state.asyncJobs.get(runId)?.controlEventCursor ?? 0) >= eventSize, "resolved replay cursor");
1657
+ assert.equal(recorder.events.filter((entry) => entry.channel === SUBAGENT_CONTROL_EVENT).length, 1);
1658
+ } finally {
1659
+ channel.dispose();
1660
+ fs.rmSync(channelDir, { recursive: true, force: true });
1661
+ removeTempDir(asyncRoot);
1662
+ }
1663
+ });
1664
+
1665
+ it("delivers an external intercom ask with the native lifecycle lookup enabled", async () => {
1666
+ const asyncRoot = createTempDir("pi-async-job-supervisor-replay-external-");
1667
+ const sessionId = `session-${Date.now()}`;
1668
+ const runId = `run-${Date.now()}`;
1669
+ const { channel } = createNativeSupervisorHarness(sessionId);
1670
+ try {
1671
+ const runDir = path.join(asyncRoot, runId);
1672
+ writeRunningAsyncStatus(runDir, runId, sessionId);
1673
+ const event = supervisorControlEvent(runId, "external-call", "intercom");
1674
+ writeControlRecord(runDir, event);
1675
+ assert.equal(channel.getSupervisorRequestState(event), "unknown");
1676
+ const state = createState();
1677
+ const recorder = createEventRecorder();
1678
+ const tracker = createTracker(recorder.pi, state as never, asyncRoot, {
1679
+ pollIntervalMs: 10,
1680
+ supervisorRequestState: channel.getSupervisorRequestState,
1681
+ });
1682
+ tracker.handleStarted({ id: runId, asyncDir: runDir, agent: "worker", sessionId });
1683
+ await waitForCondition(() => recorder.events.some((entry) => entry.channel === SUBAGENT_CONTROL_EVENT), "external control event replay");
1684
+ } finally {
1685
+ channel.dispose();
1686
+ removeTempDir(asyncRoot);
1687
+ }
1688
+ });
1689
+
1475
1690
  it("keeps incomplete async control event lines for the next poll", async () => {
1476
1691
  const asyncRoot = createTempDir("pi-async-job-tracker-");
1477
1692
  try {
@@ -1997,4 +2212,4 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
1997
2212
  removeTempDir(asyncRoot);
1998
2213
  }
1999
2214
  });
2000
- });
2215
+ });
@@ -130,13 +130,13 @@ describe("runSync error handling", { skip: !piAvailable ? "pi packages not avail
130
130
  removeTempDir(tempDir);
131
131
  });
132
132
 
133
- it("captures stderr on non-zero exit", async () => {
133
+ it("reports a child session failure as the run error", async () => {
134
134
  mockPi.onCall({ exitCode: 2, stderr: "Fatal: out of memory" });
135
135
  const agents = makeAgentConfigs(["crash"]);
136
136
 
137
137
  const result = await runSync(tempDir, agents, "crash", "Do heavy work", {});
138
138
 
139
- assert.equal(result.exitCode, 2);
139
+ assert.equal(result.exitCode, 1);
140
140
  assert.ok(result.error?.includes("out of memory"));
141
141
  });
142
142
 
@@ -170,25 +170,11 @@ describe("runSync error handling", { skip: !piAvailable ? "pi packages not avail
170
170
  const result = await runSync(tempDir, agents, "worker", "Do work", {});
171
171
 
172
172
  assert.equal(result.exitCode, 1);
173
- assert.match(result.error ?? "", /exited during 'bash' tool execution \(exit 0\)/);
173
+ assert.match(result.error ?? "", /ended during 'bash' tool execution before the tool completed/);
174
174
  assert.match(result.error ?? "", /Earlier assistant output is not a terminal result/);
175
175
  assert.doesNotMatch(result.error ?? "", /cold-start/);
176
176
  });
177
177
 
178
- it("includes an unexpected process signal in a mid-tool exit diagnosis", { skip: process.platform === "win32" ? "signal delivery differs on Windows" : undefined }, async () => {
179
- mockPi.onCall({
180
- jsonl: [events.toolStart("bash", { command: "wait" })],
181
- signal: "SIGTERM",
182
- });
183
- const agents = makeAgentConfigs(["worker"]);
184
-
185
- const result = await runSync(tempDir, agents, "worker", "Do work", {});
186
-
187
- assert.equal(result.exitCode, 1);
188
- assert.match(result.error ?? "", /exited during 'bash' tool execution/);
189
- assert.match(result.error ?? "", /signal SIGTERM/);
190
- });
191
-
192
178
  it("keeps a terminal answer authoritative over an earlier tool timeout", async () => {
193
179
  mockPi.onCall({
194
180
  steps: [
@@ -278,4 +264,4 @@ describe("runSync error handling", { skip: !piAvailable ? "pi packages not avail
278
264
  assert.ok(elapsed < 5000, `should abort early, took ${elapsed}ms`);
279
265
  assert.doesNotMatch(result.error ?? "", /exited during 'bash' tool execution/);
280
266
  });
281
- });
267
+ });
@@ -0,0 +1,95 @@
1
+ import { describe, it } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import * as fs from "node:fs";
4
+ import * as path from "node:path";
5
+ import { execFile } from "node:child_process";
6
+ import { promisify } from "node:util";
7
+ import { fileURLToPath, pathToFileURL } from "node:url";
8
+ import { events, makeAgent, makeMinimalCtx, createEventBus } from "../support/helpers.ts";
9
+ import { installAsyncExecutionHooks, available, createSubagentExecutor, waitForMockPiCall, waitForAsyncState, ASYNC_DIR, tempDir, mockPi } from "../support/async-execution-fixture.ts";
10
+ import { steerRequestsDir } from "../../src/runs/background/control-channel.ts";
11
+ const repo = fileURLToPath(new URL("../../", import.meta.url));
12
+ const execFileAsync = promisify(execFile);
13
+ async function hostB(sessionFile: string, params: object, label: string, policy = "auto"): Promise<any> {
14
+ const output = path.join(tempDir, `${label}.json`);
15
+ await execFileAsync(process.execPath, ["--experimental-strip-types", "--import", pathToFileURL(path.join(repo, "test/support/register-loader.mjs")).href, path.join(repo, "test/support/foreign-workflow-steer-host.mjs"), tempDir, sessionFile, JSON.stringify(params), output, policy], { cwd: repo, env: process.env, timeout: 15000, killSignal: "SIGKILL" });
16
+ return JSON.parse(fs.readFileSync(output, "utf8"));
17
+ }
18
+
19
+ describe("foreign workflow tool steering (separate processes)", () => {
20
+ installAsyncExecutionHooks();
21
+ it("delivers ID and directory requests with file-preferred identity; refuses wrong sessions and terminal runs", { timeout: 60000 }, async () => {
22
+ assert.ok(available && createSubagentExecutor, "fixture must not skip");
23
+ const release = path.join(tempDir, "release");
24
+ mockPi.onCall({ steps: [{ waitForPath: release, jsonl: [events.assistantMessage("done")] }] });
25
+ const sessionFile = path.join(tempDir, "parent-session.jsonl");
26
+ const ctx = makeMinimalCtx(tempDir);
27
+ ctx.sessionManager.getSessionFile = () => sessionFile;
28
+ ctx.sessionManager.getSessionId = () => "different-runtime-id-in-owner";
29
+ const state: any = { baseCwd: tempDir, currentSessionId: null, asyncJobs: new Map(), foregroundControls: new Map(), lastForegroundControlId: null };
30
+ const executor = createSubagentExecutor({ pi: { events: createEventBus(), getSessionName: () => undefined }, state, config: {}, asyncByDefault: false, tempArtifactsDir: tempDir, getSubagentSessionRoot: () => tempDir, expandTilde: p => p, discoverAgents: () => ({ agents: [makeAgent("worker", { completionGuard: false })] }) });
31
+ const launch = await executor.execute("owner", { workflowScript: 'return await runs.run("A", { agent: "worker", task: "Wait" });', async: true, mission: false }, new AbortController().signal, undefined, ctx);
32
+ assert.notEqual(launch.isError, true, JSON.stringify(launch));
33
+ const runId = launch.details.asyncId!;
34
+ const dir = path.join(ASYNC_DIR, runId);
35
+ try {
36
+ await waitForMockPiCall(mockPi, 0, 10000);
37
+ assert.equal(state.workflowControllers.has(runId), true);
38
+ const status = JSON.parse(fs.readFileSync(path.join(dir, "status.json"), "utf8"));
39
+ assert.equal(status.sessionId, sessionFile);
40
+ for (const [label, params] of [["id", { id: runId }], ["dir", { dir, index: 0 }]] as const) {
41
+ const b = await hostB(sessionFile, params, label);
42
+ assert.notEqual(b.pid, process.pid);
43
+ assert.notEqual(b.completionOwnerId, status.completionOwnerId);
44
+ assert.equal(b.sessionId, sessionFile);
45
+ assert.equal(b.controllers, 0); assert.equal(b.controls, 0);
46
+ assert.notEqual(b.result.isError, true, JSON.stringify(b));
47
+ assert.equal(b.result.details.steering.state, "delivered");
48
+ const receipt = JSON.parse(fs.readFileSync(path.join(dir, "status.json"), "utf8")).steering.recent.find((r: any) => r.id === b.result.details.steering.requestId);
49
+ assert.equal(receipt.targets[0].state, "delivered");
50
+ }
51
+ assert.match(fs.readFileSync(path.join(mockPi.dir, "steers.jsonl"), "utf8"), /B actual tool route/);
52
+ const wrong = await hostB(`${sessionFile}-wrong`, { id: runId }, "wrong");
53
+ assert.equal(wrong.result.isError, true);
54
+ assert.match(wrong.result.content[0].text, /active session/);
55
+ const malformed = await hostB(sessionFile, { dir, index: 0.5 }, "malformed");
56
+ assert.equal(malformed.result.isError, true);
57
+ assert.deepEqual(fs.readdirSync(steerRequestsDir(dir)), []);
58
+ fs.writeFileSync(release, "go");
59
+ await waitForAsyncState(runId, s => s.state === "complete", 10000);
60
+ const terminal = await hostB(sessionFile, { dir }, "terminal");
61
+ assert.equal(terminal.result.isError, true);
62
+ assert.match(terminal.result.content[0].text, /not running or queued/);
63
+ } finally { fs.writeFileSync(release, "go"); }
64
+ });
65
+
66
+ it("leaves an unavailable owner's request pending without reconciliation or recovery", { timeout: 20000 }, async () => {
67
+ const runId = "foreign-unacknowledged";
68
+ const dir = path.join(ASYNC_DIR, runId);
69
+ fs.mkdirSync(dir, { recursive: true });
70
+ const sessionFile = path.join(tempDir, "parent.jsonl");
71
+ const status = JSON.stringify({ runId, mode: "workflow", state: "running", sessionId: sessionFile, completionOwnerId: "unavailable-owner", pid: 99999999, updatedAt: 1, steps: [{ status: "running", workflowKey: "A" }, { status: "running", workflowKey: "B" }] });
72
+ fs.writeFileSync(path.join(dir, "status.json"), status);
73
+ for (const policy of ["forbid", "confirm"]) {
74
+ const refused = await hostB(sessionFile, { dir }, policy, policy);
75
+ assert.equal(refused.result.isError, true);
76
+ assert.match(refused.result.content[0].text, /Authority policy/);
77
+ assert.equal(fs.existsSync(steerRequestsDir(dir)), false);
78
+ }
79
+ const mismatch = await hostB(sessionFile, { dir, id: "another-workflow" }, "mismatch");
80
+ assert.equal(mismatch.result.isError, true);
81
+ assert.match(mismatch.result.content[0].text, /does not match directory/);
82
+ const b = await hostB(sessionFile, { id: runId }, "noack");
83
+ assert.notEqual(b.result.isError, true, JSON.stringify(b));
84
+ assert.equal(b.result.details.steering.state, "pending");
85
+ assert.equal(b.result.details.steering.deliveryStatus, "queued");
86
+ assert.deepEqual(b.result.details.steering.targets, []);
87
+ assert.equal(fs.readFileSync(path.join(dir, "status.json"), "utf8"), status);
88
+ const requests = fs.readdirSync(steerRequestsDir(dir));
89
+ assert.equal(requests.length, 1);
90
+ const request = JSON.parse(fs.readFileSync(path.join(steerRequestsDir(dir), requests[0]!), "utf8"));
91
+ assert.equal(request.id, b.result.details.steering.requestId);
92
+ assert.equal(request.targetIndex, undefined); assert.equal(request.targetIndexes, undefined);
93
+ assert.deepEqual(fs.readdirSync(dir).sort(), ["control", "status.json"]);
94
+ });
95
+ });
@@ -192,10 +192,6 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
192
192
  .filter((sessionFile): sessionFile is string => Boolean(sessionFile));
193
193
  }
194
194
 
195
- function isTaskFileArg(arg: string): boolean {
196
- return arg.startsWith("@") && arg.endsWith("task.md");
197
- }
198
-
199
195
  function readSessionArg(args: string[]): string {
200
196
  const sessionIndex = args.indexOf("--session");
201
197
  assert.notEqual(sessionIndex, -1);
@@ -309,11 +305,10 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
309
305
  assert.equal(result.isError, undefined);
310
306
  const args = readAllCallArgs()[0] ?? [];
311
307
  const taskArg = args.at(-1) ?? "";
312
- if (process.platform === "darwin") {
313
- assert.ok(isTaskFileArg(taskArg));
314
- } else {
315
- assert.ok(taskArg.startsWith("Task: \n\n## Acceptance Contract"));
316
- }
308
+ assert.equal(taskArg, "Task: ");
309
+ const systemIndex = args.findIndex((arg) => arg === "--system-prompt" || arg === "--append-system-prompt");
310
+ assert.notEqual(systemIndex, -1);
311
+ assert.match(args[systemIndex + 1] ?? "", /## Acceptance Contract/);
317
312
  });
318
313
 
319
314
  it("fails pruned fork model auth before child spawn", async () => {
@@ -1315,11 +1310,10 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
1315
1310
  assert.equal(result.isError, undefined);
1316
1311
  const args = readAllCallArgs()[0] ?? [];
1317
1312
  const taskArg = args.at(-1) ?? "";
1318
- if (process.platform === "darwin") {
1319
- assert.ok(isTaskFileArg(taskArg));
1320
- } else {
1321
- assert.ok(taskArg.startsWith(`Task: ${task}\n\n## Acceptance Contract`));
1322
- }
1313
+ assert.equal(taskArg, `Task: ${task}`);
1314
+ const systemIndex = args.findIndex((arg) => arg === "--system-prompt" || arg === "--append-system-prompt");
1315
+ assert.notEqual(systemIndex, -1);
1316
+ assert.match(args[systemIndex + 1] ?? "", /## Acceptance Contract/);
1323
1317
  const modelIndex = args.indexOf("--model");
1324
1318
  assert.notEqual(modelIndex, -1);
1325
1319
  assert.equal(args[modelIndex + 1], "anthropic/claude-haiku-4-5");
@@ -1353,4 +1347,4 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
1353
1347
  removeTempDir(tempHome);
1354
1348
  }
1355
1349
  });
1356
- });
1350
+ });