@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
@@ -2,12 +2,14 @@ import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import type { AgentToolResult } from "@earendil-works/pi-agent-core";
4
4
  import { safeTerminalText } from "../../shared/display-text.ts";
5
+ import { getArtifactPaths, getArtifactsDir } from "../../shared/artifacts.ts";
6
+ import { readFleetTranscript } from "../../tui/fleet-transcript.ts";
5
7
  import { formatAsyncRunList, formatAsyncRunOutputPath, formatAsyncRunProgressLabel, formatWorkflowStageLine, listAsyncRuns } from "./async-status.ts";
6
8
  import { formatAsyncResultTranscript, formatAsyncRunTranscript, formatNestedRunTranscript, inspectSubagentFleet } from "./fleet-view.ts";
7
9
  import { formatNestedRunStatusLines } from "../shared/nested-render.ts";
8
10
  import { formatModelThinking } from "../../shared/formatters.ts";
9
11
  import { formatActivityLabel } from "../../shared/status-format.ts";
10
- import { DIRS, type AsyncStatus, type Details, type ForegroundResumeRun, type NestedRunSummary, type SteeringStatus, type SubagentState } from "../../shared/types.ts";
12
+ import { DIRS, type AsyncStatus, type Details, type ForegroundRunControl, type ForegroundResumeRun, type NestedRunSummary, type SteeringStatus, type SubagentState } from "../../shared/types.ts";
11
13
  import { inspectActiveAsyncCapacityOwner, type ActiveAsyncCapacityInspection } from "./active-async-capacity.ts";
12
14
  import { readStatus } from "../../shared/utils.ts";
13
15
  import { resolveSubagentIntercomTarget } from "../../intercom/intercom-bridge.ts";
@@ -88,6 +90,7 @@ function formatRunLifecycleDebug(input: { status: AsyncStatus; asyncDir: string;
88
90
  `Run: ${status.runId}`,
89
91
  `Dir: ${asyncDir}`,
90
92
  `Status file: ${path.join(asyncDir, "status.json")}`,
93
+ status.workflowReceiptPath ? `Workflow receipt: ${status.workflowReceiptPath}` : undefined,
91
94
  `Process terminal file: ${path.join(asyncDir, "process-terminal.json")}`,
92
95
  `Session: ${status.sessionId ?? "unknown"}`,
93
96
  `State: ${status.state}`,
@@ -241,6 +244,54 @@ function formatRememberedForegroundStatus(run: ForegroundResumeRun): string {
241
244
  return lines.join("\n");
242
245
  }
243
246
 
247
+ /** Request-only snapshot of the same artifact used by Fleet; no session or output fallback. */
248
+ function formatLiveForegroundTranscript(control: ForegroundRunControl, state: SubagentState, options: { index?: number; lines?: number }): string {
249
+ if (!state.currentSessionId || control.sessionId !== state.currentSessionId) {
250
+ throw new Error(`Foreground run '${control.runId}' is not owned by the current session.`);
251
+ }
252
+ if (options.index !== undefined && (!Number.isInteger(options.index) || options.index < 0)) {
253
+ throw new Error("Transcript index must be a non-negative integer.");
254
+ }
255
+ const children = control.activeChildren
256
+ ? [...control.activeChildren.values()]
257
+ : control.currentAgent ? [{ index: control.currentIndex ?? 0, agent: control.currentAgent, sessionName: control.sessionName }] : [];
258
+ const header = [`Run: ${control.runId}`, "State: live foreground"];
259
+ if (children.length === 0) return `${header.map((line) => safeTerminalText(line)).join("\n")}\nTranscript unavailable: no active foreground child.`;
260
+ if (options.index === undefined && children.length > 1) {
261
+ throw new Error(`Transcript view requires index for foreground run '${control.runId}'. Active child indexes: ${children.map((child) => child.index).join(", ")}.`);
262
+ }
263
+ const child = options.index === undefined ? children[0]! : children.find((child) => child.index === options.index);
264
+ if (!child) throw new Error(`Transcript index ${options.index} is not an active foreground child of '${control.runId}'.`);
265
+ const root = getArtifactsDir(state.parentSessionFile ?? null, control.cwd ?? state.baseCwd, state.artifactDirPreference);
266
+ const transcriptPath = getArtifactPaths(root, control.runId, child.agent, child.index).transcriptPath;
267
+ const transcript = readFleetTranscript(transcriptPath, { trustedRoots: [root] });
268
+ const lineLimit = Number.isFinite(options.lines) ? Math.max(1, Math.min(500, Math.trunc(options.lines!))) : 80;
269
+ const allLines = transcript.events.flatMap((event) => {
270
+ const text = event.kind === "tool"
271
+ ? [`Tool: ${event.name} (${event.status})`, event.argsPayload ?? event.args, event.output ?? event.error].filter(Boolean).join("\n")
272
+ : event.kind === "notice" ? event.text : `${event.kind === "assistant" ? "Assistant" : "Supervisor"}: ${event.text}`;
273
+ return text.split(/\r?\n/);
274
+ });
275
+ let body = allLines.slice(-lineLimit).join("\n");
276
+ let truncated = transcript.truncated || allLines.length > lineLimit
277
+ || transcript.events.some((event) => event.kind === "tool" && event.outputTruncated)
278
+ || body.includes("… message truncated");
279
+ const maxOutputBytes = 32 * 1024;
280
+ const bytes = Buffer.from(body);
281
+ if (bytes.length > maxOutputBytes) {
282
+ // Skip UTF-8 continuation bytes at the beginning of the bounded tail.
283
+ let start = bytes.length - maxOutputBytes;
284
+ while ((bytes[start]! & 0xc0) === 0x80) start++;
285
+ body = bytes.subarray(start).toString("utf-8");
286
+ truncated = true;
287
+ }
288
+ header.push(`Child: ${child.index} (${child.sessionName?.trim() || child.agent})`, `Transcript: ${transcriptPath}`);
289
+ if (transcript.warning) header.push(`Transcript warning: ${transcript.warning}`);
290
+ header.push(`Live transcript tail${truncated ? " (tail truncated)" : ""}:`);
291
+ if (!body) header.push("Transcript unavailable: no readable activity in the bounded artifact tail yet.");
292
+ return [...header.map((line) => safeTerminalText(line)), body].filter(Boolean).join("\n");
293
+ }
294
+
244
295
  function formatRememberedForegroundTranscript(run: ForegroundResumeRun, options: { index?: number; lines?: number }): string {
245
296
  let index = options.index;
246
297
  if (index !== undefined && !Number.isInteger(index)) throw new Error("Transcript index must be an integer.");
@@ -313,6 +364,12 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
313
364
  return inspectSubagentFleet(params, { asyncDirRoot, resultsDir, kill: deps.kill, now: deps.now, state: deps.state, childSafe: Boolean(deps.nested) });
314
365
  }
315
366
  if (!params.id && !params.runId && !params.dir) {
367
+ if (params.view === "transcript" && deps.state?.currentSessionId) {
368
+ const controls = [...deps.state.foregroundControls.values()].filter((control) => control.sessionId === currentSessionId);
369
+ const foreground = controls.find((control) => control.runId === deps.state?.lastForegroundControlId)
370
+ ?? controls.sort((left, right) => right.updatedAt - left.updatedAt)[0];
371
+ if (foreground) return inspectSubagentStatus({ ...params, id: foreground.runId }, deps);
372
+ }
316
373
  if (deps.nested) {
317
374
  return {
318
375
  content: [{ type: "text", text: "Child-safe subagent status requires an id when no foreground run is active." }],
@@ -353,6 +410,13 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
353
410
  } else if (!params.dir && requestedId) {
354
411
  const resolved = resolveSubagentRunId(requestedId, { asyncDirRoot, resultsDir, state: deps.state, nested: deps.nested });
355
412
  if (resolved?.kind === "foreground") {
413
+ const control = deps.state?.foregroundControls.get(resolved.id);
414
+ if (control && deps.state && params.view === "transcript") {
415
+ return {
416
+ content: [{ type: "text", text: formatLiveForegroundTranscript(control, deps.state, params) }],
417
+ details: { mode: "management", results: [] },
418
+ };
419
+ }
356
420
  const run = deps.state?.foregroundRuns?.get(resolved.id);
357
421
  if (run) {
358
422
  try {
@@ -423,7 +487,7 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
423
487
  const capacity = inspectActiveAsyncCapacityOwner({ runId: diskStatus.runId, sessionId: diskStatus.sessionId, asyncDir }, { rootDir: deps.activeCapacityRoot, liveWorkflowRunIds: new Set(deps.state?.workflowControllers?.keys() ?? []), abandonedSlotReleaseAfterMs: deps.abandonedSlotReleaseAfterMs });
424
488
  return {
425
489
  content: [{ type: "text", text: formatRunLifecycleDebug({ status: diskStatus, asyncDir, sidecarProcessTerminal: sidecar, overlayProcessTerminal: overlay, capacity }) }],
426
- details: { mode: "single", results: [], ...((sidecar ?? overlay) ? { lifecycleStatus: { processTerminal: sidecar ?? overlay } } : {}) },
490
+ details: { mode: "single", results: [], ...(diskStatus.workflowReceiptPath ? { workflowReceiptPath: diskStatus.workflowReceiptPath } : {}), ...((sidecar ?? overlay) ? { lifecycleStatus: { processTerminal: sidecar ?? overlay } } : {}) },
427
491
  };
428
492
  }
429
493
  if (params.view === "transcript") {
@@ -450,7 +514,7 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
450
514
  const capacity = inspectActiveAsyncCapacityOwner({ runId: status.runId, sessionId: status.sessionId, asyncDir }, { rootDir: deps.activeCapacityRoot, liveWorkflowRunIds: new Set(deps.state?.workflowControllers?.keys() ?? []), abandonedSlotReleaseAfterMs: deps.abandonedSlotReleaseAfterMs });
451
515
  return {
452
516
  content: [{ type: "text", text: formatRunLifecycleDebug({ status, asyncDir, sidecarProcessTerminal: sidecar, overlayProcessTerminal: overlay, capacity }) }],
453
- details: { mode: "single", results: [], ...((sidecar ?? overlay) ? { lifecycleStatus: { processTerminal: sidecar ?? overlay } } : {}) },
517
+ details: { mode: "single", results: [], ...(status.workflowReceiptPath ? { workflowReceiptPath: status.workflowReceiptPath } : {}), ...((sidecar ?? overlay) ? { lifecycleStatus: { processTerminal: sidecar ?? overlay } } : {}) },
454
518
  };
455
519
  }
456
520
  if (params.view === "transcript") {
@@ -545,7 +609,6 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
545
609
  const liveWorkflowControls = status.mode === "workflow" && deps.state?.currentSessionId === status.sessionId && deps.state?.workflowControllers?.has(status.runId)
546
610
  ? [...(deps.state?.foregroundControls.values() ?? [])].filter((control) => control.parentWorkflowRunId === status.runId
547
611
  && control.sessionId === status.sessionId
548
- && Boolean(control.workflowSteeringDir && fs.existsSync(control.workflowSteeringDir))
549
612
  && (control.activeChildren?.size ?? 0) > 0)
550
613
  : [];
551
614
  let hasExternalJobFollowUpHint = false;
@@ -627,6 +690,7 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
627
690
  }
628
691
  }
629
692
  if (nestedWarning) lines.push(`Warning: ${nestedWarning}`);
693
+ if (status.workflowReceiptPath) lines.push(`Workflow receipt: ${status.workflowReceiptPath}`);
630
694
  if (status.sessionFile) lines.push(`Session: ${status.sessionFile}`);
631
695
  const allExternal = (status.steps?.length ?? 0) > 0 && status.steps!.every((step) => step.runner?.type === "external-cli" || step.runner?.type === "external-job");
632
696
  if (status.state === "running" && !allExternal && status.mode !== "workflow") lines.push(`Steer running child: subagent({ action: "steer", id: "${status.runId}", message: "..." })`);
@@ -640,7 +704,7 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
640
704
 
641
705
  const workflowChildren = parseWorkflowChildSummary(status.workflowChildren);
642
706
  if (workflowChildren && workflowChildren.workflowRunId !== status.runId) throw new Error("workflowChildren.workflowRunId does not match async status runId.");
643
- return { content: [{ type: "text", text: lines.join("\n") }], details: { mode: "single", results: [], ...(status.preflight ? { preflight: status.preflight } : {}), ...(status.workflow?.preflightWarnings?.length ? { preflightWarnings: status.workflow.preflightWarnings } : {}), ...(workflowChildren ? { workflowChildren } : {}), ...(runFanoutBudget ? { runFanoutBudget } : {}), ...(processTerminal ? { lifecycleStatus: { processTerminal } } : {}) } };
707
+ return { content: [{ type: "text", text: lines.join("\n") }], details: { mode: "single", results: [], ...(status.workflowReceiptPath ? { workflowReceiptPath: status.workflowReceiptPath } : {}), ...(status.preflight ? { preflight: status.preflight } : {}), ...(status.workflow?.preflightWarnings?.length ? { preflightWarnings: status.workflow.preflightWarnings } : {}), ...(workflowChildren ? { workflowChildren } : {}), ...(runFanoutBudget ? { runFanoutBudget } : {}), ...(processTerminal ? { lifecycleStatus: { processTerminal } } : {}) } };
644
708
  }
645
709
  }
646
710
 
@@ -681,6 +745,11 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
681
745
  const runId = data.runId ?? data.id ?? resolvedId;
682
746
  const lines = [`Run: ${runId}`, data.toolCallId ? `Tool call: ${data.toolCallId}` : undefined, `State: ${status}`, `Result: ${resultPath}`].filter((line): line is string => Boolean(line));
683
747
  if (data.parallelHandoff?.path) lines.push(`Parallel handoff: ${data.parallelHandoff.path}`);
748
+ const receipt = (data as Record<string, unknown>).workflowReceipt;
749
+ const receiptPath = receipt && typeof receipt === "object" && !Array.isArray(receipt)
750
+ ? (receipt as Record<string, unknown>).path : undefined;
751
+ const workflowReceiptPath = typeof receiptPath === "string" && receiptPath ? receiptPath : undefined;
752
+ if (workflowReceiptPath) lines.push(`Workflow receipt: ${workflowReceiptPath}`);
684
753
  const children = Array.isArray(data.results) ? data.results : data.agent ? [{ agent: data.agent, sessionFile: data.sessionFile }] : [];
685
754
  lines.push(...formatTimeoutRecoveryLines(data.timeoutRecovery, " "));
686
755
  for (const [index, child] of children.entries()) {
@@ -695,7 +764,7 @@ export function inspectSubagentStatus(params: RunStatusParams, deps: RunStatusDe
695
764
  if (data.summary) lines.push("", data.summary);
696
765
  const workflowChildren = parseWorkflowChildSummary((data as unknown as Record<string, unknown>).workflowChildren);
697
766
  if (workflowChildren && workflowChildren.workflowRunId !== runId) throw new Error("workflowChildren.workflowRunId does not match the result run id.");
698
- return { content: [{ type: "text", text: lines.join("\n") }], details: { mode: "single", results: [], ...(workflowChildren ? { workflowChildren } : {}) } };
767
+ return { content: [{ type: "text", text: lines.join("\n") }], details: { mode: "single", results: [], ...(workflowReceiptPath ? { workflowReceiptPath } : {}), ...(workflowChildren ? { workflowChildren } : {}) } };
699
768
  } catch (error) {
700
769
  const message = error instanceof Error ? error.message : String(error);
701
770
  return {
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Module aliases for the detached async runner.
3
+ *
4
+ * The runner is a plain Node process started through jiti. The child hooks it
5
+ * loads import pi's host packages (`@selesai/code`,
6
+ * `pi-agent-core`, `pi-ai`, `pi-tui`, `typebox`), which are peer packages of
7
+ * this extension and are not installed next to it. pi's own extension loader
8
+ * aliases those specifiers to the copies shipped inside the installed pi
9
+ * package; the parent computes the same map and hands it to the runner
10
+ * through `JITI_ALIAS`, so child sessions and hooks retain host API identity.
11
+ * Only Pi 0.85.0's missing server exports may come from this extension.
12
+ */
13
+ import * as fs from "node:fs";
14
+ import * as path from "node:path";
15
+ import { fileURLToPath } from "node:url";
16
+
17
+ export const JITI_ALIAS_ENV = "JITI_ALIAS";
18
+
19
+ /** Specifiers the runner's import graph may use, with the package and export subpath each resolves to. */
20
+ export const HOST_PEER_ALIASES: ReadonlyArray<{ specifier: string; pkg: string; subpath: string }> = [
21
+ { specifier: "@selesai/code", pkg: "@selesai/code", subpath: "." },
22
+ { specifier: "@earendil-works/pi-agent-core", pkg: "@earendil-works/pi-agent-core", subpath: "." },
23
+ { specifier: "@earendil-works/pi-agent-core/node", pkg: "@earendil-works/pi-agent-core", subpath: "./node" },
24
+ { specifier: "@earendil-works/chord", pkg: "@earendil-works/chord", subpath: "." },
25
+ { specifier: "@earendil-works/chord/context", pkg: "@earendil-works/chord", subpath: "./context" },
26
+ { specifier: "@earendil-works/pi-tui", pkg: "@earendil-works/pi-tui", subpath: "." },
27
+ { specifier: "@earendil-works/pi-ai", pkg: "@earendil-works/pi-ai", subpath: "./compat" },
28
+ { specifier: "@earendil-works/pi-ai/compat", pkg: "@earendil-works/pi-ai", subpath: "./compat" },
29
+ { specifier: "@earendil-works/pi-ai/oauth", pkg: "@earendil-works/pi-ai", subpath: "./oauth" },
30
+ { specifier: "@earendil-works/pi-ai/providers/all", pkg: "@earendil-works/pi-ai", subpath: "./providers/all" },
31
+ { specifier: "typebox", pkg: "typebox", subpath: "." },
32
+ { specifier: "typebox/compile", pkg: "typebox", subpath: "./compile" },
33
+ { specifier: "typebox/value", pkg: "typebox", subpath: "./value" },
34
+ ];
35
+
36
+ /** Experimental dependencies accidentally published in exactly Pi 0.85.0. */
37
+ const PI0850_PEER_ALIASES = [
38
+ { specifier: "@earendil-works/pi-server", pkg: "@earendil-works/pi-server", subpath: "." },
39
+ { specifier: "@earendil-works/pi-server/unix", pkg: "@earendil-works/pi-server", subpath: "./unix" },
40
+ { specifier: "@earendil-works/pi-client/unix", pkg: "@earendil-works/pi-client", subpath: "./unix" },
41
+ ];
42
+
43
+ interface PackageManifest {
44
+ name?: unknown;
45
+ version?: unknown;
46
+ main?: unknown;
47
+ exports?: unknown;
48
+ }
49
+
50
+ function readManifest(packageDir: string): PackageManifest | undefined {
51
+ try {
52
+ return JSON.parse(fs.readFileSync(path.join(packageDir, "package.json"), "utf-8")) as PackageManifest;
53
+ } catch {
54
+ return undefined;
55
+ }
56
+ }
57
+
58
+ /** Pick the import target of one exports entry (string, conditions object, or array of those). */
59
+ function exportTarget(entry: unknown): string | undefined {
60
+ if (typeof entry === "string") return entry;
61
+ if (Array.isArray(entry)) {
62
+ for (const candidate of entry) {
63
+ const target = exportTarget(candidate);
64
+ if (target) return target;
65
+ }
66
+ return undefined;
67
+ }
68
+ if (entry && typeof entry === "object") {
69
+ const conditions = entry as Record<string, unknown>;
70
+ for (const condition of ["import", "node", "default"]) {
71
+ if (condition in conditions) {
72
+ const target = exportTarget(conditions[condition]);
73
+ if (target) return target;
74
+ }
75
+ }
76
+ }
77
+ return undefined;
78
+ }
79
+
80
+ /** Resolve `subpath` of the package at `packageDir` through its `exports` map (with `*` patterns) or `main`. */
81
+ export function resolvePackageSubpath(packageDir: string, subpath: string): string | undefined {
82
+ const manifest = readManifest(packageDir);
83
+ if (!manifest) return undefined;
84
+ const exportsField = manifest.exports;
85
+ if (exportsField !== undefined) {
86
+ const map: Record<string, unknown> = typeof exportsField === "string" || Array.isArray(exportsField) || (exportsField && typeof exportsField === "object" && !Object.keys(exportsField as object).some((key) => key.startsWith(".")))
87
+ ? { ".": exportsField }
88
+ : exportsField as Record<string, unknown>;
89
+ const exact = exportTarget(map[subpath]);
90
+ if (exact) return path.resolve(packageDir, exact);
91
+ for (const [pattern, entry] of Object.entries(map)) {
92
+ const star = pattern.indexOf("*");
93
+ if (star === -1) continue;
94
+ const prefix = pattern.slice(0, star);
95
+ const suffix = pattern.slice(star + 1);
96
+ if (!subpath.startsWith(prefix) || !subpath.endsWith(suffix) || subpath.length < prefix.length + suffix.length) continue;
97
+ const target = exportTarget(entry);
98
+ if (!target) continue;
99
+ const wildcard = subpath.slice(prefix.length, subpath.length - suffix.length);
100
+ return path.resolve(packageDir, target.replace("*", wildcard));
101
+ }
102
+ return undefined;
103
+ }
104
+ if (subpath !== ".") return undefined;
105
+ return path.resolve(packageDir, typeof manifest.main === "string" && manifest.main.trim() ? manifest.main : "index.js");
106
+ }
107
+
108
+ /** Find `pkg` as the pi package itself, one of its dependencies, or a sibling in a hoisted install. */
109
+ export function findHostPeerPackageDir(piPackageRoot: string, pkg: string): string | undefined {
110
+ return findPeerPackageDir(piPackageRoot, pkg, readManifest(piPackageRoot)?.name);
111
+ }
112
+
113
+ function findPeerPackageDir(piPackageRoot: string, pkg: string, hostName: unknown): string | undefined {
114
+ if (hostName === pkg) return piPackageRoot;
115
+ const candidates = [path.join(piPackageRoot, "node_modules", pkg)];
116
+ let dir = piPackageRoot;
117
+ for (;;) {
118
+ const parent = path.dirname(dir);
119
+ if (parent === dir) break;
120
+ if (path.basename(parent) === "node_modules" || path.basename(path.dirname(parent)) === "node_modules") {
121
+ const modulesRoot = path.basename(parent) === "node_modules" ? parent : path.dirname(parent);
122
+ candidates.push(path.join(modulesRoot, pkg));
123
+ }
124
+ candidates.push(path.join(parent, "node_modules", pkg));
125
+ dir = parent;
126
+ }
127
+ return candidates.find((candidate) => readManifest(candidate)?.name === pkg);
128
+ }
129
+
130
+ /** The alias map the runner needs, or the specifiers that could not be resolved. */
131
+ export function resolveHostPeerAliases(
132
+ piPackageRoot: string,
133
+ extensionRoot = fileURLToPath(new URL("../../../", import.meta.url)),
134
+ ): { aliases: Record<string, string>; missing: string[]; supplemental: string[] } {
135
+ const aliases: Record<string, string> = {};
136
+ const missing: string[] = [];
137
+ const supplemental: string[] = [];
138
+ const hostManifest = readManifest(piPackageRoot);
139
+ const isPi0850 = hostManifest?.version === "0.85.0";
140
+ const required = isPi0850 ? [...HOST_PEER_ALIASES, ...PI0850_PEER_ALIASES] : HOST_PEER_ALIASES;
141
+ for (const { specifier, pkg, subpath } of required) {
142
+ const packageDir = findPeerPackageDir(piPackageRoot, pkg, hostManifest?.name);
143
+ let target = packageDir ? resolvePackageSubpath(packageDir, subpath) : undefined;
144
+ // Pi 0.85.0 omitted this runtime dependency. Never replace working host
145
+ // exports or extend this exact version contract to other peers/hosts.
146
+ if ((!target || !fs.existsSync(target))
147
+ && (specifier === "@earendil-works/pi-server" || specifier === "@earendil-works/pi-server/unix")
148
+ && isPi0850
149
+ && (!packageDir || readManifest(packageDir)?.version === "0.85.0")) {
150
+ const localDir = findHostPeerPackageDir(extensionRoot, pkg);
151
+ if (localDir && readManifest(localDir)?.version === "0.85.0") {
152
+ const localTarget = resolvePackageSubpath(localDir, subpath);
153
+ if (localTarget && fs.existsSync(localTarget)) {
154
+ target = localTarget;
155
+ supplemental.push(specifier);
156
+ }
157
+ }
158
+ }
159
+ if (target && fs.existsSync(target)) aliases[specifier] = target;
160
+ else missing.push(specifier);
161
+ }
162
+ return { aliases, missing, supplemental };
163
+ }
@@ -0,0 +1,86 @@
1
+ /** Native runner construction, separate from its executable entrypoint and attempt loop. */
2
+ import * as path from "node:path";
3
+ import { buildInProcessChildLaunch, type BuildInProcessChildLaunchInput, type InheritedChildRuntime } from "../shared/child-launch.ts";
4
+ import { deriveForkPromptCacheKey } from "../shared/child-tool-plan.ts";
5
+ import { normalizeExtensionBindings } from "../shared/extension-bindings.ts";
6
+ import type { RunnerSubagentStep } from "../shared/parallel-utils.ts";
7
+ import { formatAcceptancePrompt } from "../shared/acceptance.ts";
8
+ import { isAgentContract } from "../shared/agent-contract.ts";
9
+
10
+ export interface RunnerChildLaunchContext {
11
+ cwd: string;
12
+ id: string;
13
+ flatIndex: number;
14
+ artifactsDir?: string;
15
+ childIntercomTarget?: string;
16
+ orchestratorIntercomTarget?: string;
17
+ nestedRoute?: BuildInProcessChildLaunchInput["nestedRoute"];
18
+ runFanoutBudget?: BuildInProcessChildLaunchInput["runFanoutBudget"];
19
+ capabilityCeiling?: BuildInProcessChildLaunchInput["capabilityCeiling"];
20
+ inheritedChildRuntime?: InheritedChildRuntime;
21
+ }
22
+
23
+ export function buildRunnerChildLaunch(step: RunnerSubagentStep, ctx: RunnerChildLaunchContext, attempt: {
24
+ model?: string;
25
+ sessionEnabled: boolean;
26
+ sessionDir?: string;
27
+ sessionName?: string;
28
+ structuredOutput?: BuildInProcessChildLaunchInput["structuredOutput"];
29
+ childWatchdog?: BuildInProcessChildLaunchInput["childWatchdog"];
30
+ watchdogStatus: NonNullable<BuildInProcessChildLaunchInput["watchdogStatus"]>;
31
+ }) {
32
+ // Resource-backed system instructions survive SDK split-turn compaction verbatim.
33
+ const acceptancePrompt = step.effectiveAcceptance
34
+ ? formatAcceptancePrompt(step.effectiveAcceptance, { reportOptional: isAgentContract(step.agentContract), structuredOutput: Boolean(step.structuredOutput?.acceptanceReportPath) })
35
+ : "";
36
+ return buildInProcessChildLaunch({
37
+ parentSessionId: step.parentSessionId,
38
+ forkCacheKey: step.context === "fork" ? deriveForkPromptCacheKey(step.parentSessionId) : undefined,
39
+ sessionEnabled: attempt.sessionEnabled,
40
+ sessionDir: attempt.sessionDir,
41
+ sessionFile: step.sessionFile,
42
+ model: attempt.model,
43
+ inheritProjectContext: step.inheritProjectContext,
44
+ inheritGlobalContext: step.inheritGlobalContext,
45
+ inheritSkills: step.inheritSkills,
46
+ requireReadTool: Boolean(step.skills?.length),
47
+ tools: step.tools,
48
+ excludeTools: step.excludeTools,
49
+ allowNestedSubagents: step.allowNestedSubagents,
50
+ extensions: step.extensions,
51
+ subagentOnlyExtensions: step.subagentOnlyExtensions,
52
+ fast: step.fast,
53
+ modelCandidates: step.modelCandidates,
54
+ systemPrompt: acceptancePrompt ? `${step.systemPrompt ?? ""}\n${acceptancePrompt}` : step.systemPrompt ?? "",
55
+ systemPromptMode: step.systemPromptMode,
56
+ mcpDirectTools: step.mcpDirectTools,
57
+ extensionBindings: normalizeExtensionBindings(step.extensionBindings)?.value,
58
+ capabilityCeiling: step.capabilityCeiling ?? ctx.capabilityCeiling,
59
+ cwd: step.cwd ?? ctx.cwd,
60
+ intercomSessionName: ctx.childIntercomTarget,
61
+ sessionName: attempt.sessionName,
62
+ orchestratorIntercomTarget: ctx.orchestratorIntercomTarget,
63
+ runId: ctx.id,
64
+ childAgentName: step.agent,
65
+ childIndex: ctx.flatIndex,
66
+ nestedRoute: ctx.nestedRoute,
67
+ runFanoutBudget: ctx.runFanoutBudget ? {
68
+ ...ctx.runFanoutBudget,
69
+ ...(step.runFanoutPath ? { parentPath: `${ctx.runFanoutBudget.parentPath ? `${ctx.runFanoutBudget.parentPath}/` : ""}${step.runFanoutPath}` } : {}),
70
+ } : undefined,
71
+ structuredOutput: attempt.structuredOutput,
72
+ toolBudget: step.toolBudget,
73
+ permissionRules: step.permissionRules,
74
+ permissionAuditPath: step.permissionRules && ctx.artifactsDir
75
+ ? path.join(ctx.artifactsDir, "permission-audit", `${ctx.id}-${ctx.flatIndex}.jsonl`) : undefined,
76
+ childWatchdog: attempt.childWatchdog,
77
+ // registerChildWatchdog returns before reading the sink when unconfigured.
78
+ ...(attempt.childWatchdog ? { watchdogStatus: attempt.watchdogStatus } : {}),
79
+ waitToolEnabled: step.waitToolEnabled,
80
+ waitToolDefaultTimeoutMs: step.waitToolDefaultTimeoutMs,
81
+ thinkingCeiling: step.thinkingCeiling,
82
+ maxSubagentDepth: step.maxSubagentDepth,
83
+ inherited: ctx.inheritedChildRuntime,
84
+ host: "runner",
85
+ });
86
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Child session factory for the detached async runner.
3
+ *
4
+ * The runner imports `@selesai/code` like the parent does;
5
+ * the parent aliases that specifier (and the other host peer packages) to the
6
+ * installed pi package through `JITI_ALIAS` when it spawns the runner, see
7
+ * `runner-aliases.ts`. Tests replace the factory with a scripted one by
8
+ * naming a module in the runner config.
9
+ */
10
+ import * as path from "node:path";
11
+ import { pathToFileURL } from "node:url";
12
+ import { createDefaultChildSessionFactory, type ChildSessionFactory } from "../shared/child-session.ts";
13
+
14
+ export interface RunnerChildSessionConfig {
15
+ /** Test seam: module whose default export is a `ChildSessionFactory`, or a function returning one. */
16
+ childSessionFactoryModule?: string;
17
+ }
18
+
19
+ function isChildSessionFactory(value: unknown): value is ChildSessionFactory {
20
+ return Boolean(value) && typeof value === "object" && typeof (value as ChildSessionFactory).create === "function" && typeof (value as ChildSessionFactory).dispose === "function";
21
+ }
22
+
23
+ export async function loadRunnerChildSessionFactory(config: RunnerChildSessionConfig): Promise<ChildSessionFactory> {
24
+ if (!config.childSessionFactoryModule) return createDefaultChildSessionFactory();
25
+ const loaded = await import(pathToFileURL(path.resolve(config.childSessionFactoryModule)).href) as { default?: unknown };
26
+ const candidate = typeof loaded.default === "function" ? (loaded.default as () => unknown)() : loaded.default;
27
+ if (!isChildSessionFactory(candidate)) {
28
+ throw new Error(`Child session factory module '${config.childSessionFactoryModule}' must default-export a ChildSessionFactory or a function returning one.`);
29
+ }
30
+ return candidate;
31
+ }
@@ -14,6 +14,7 @@ import type { ResolvedSubagentCapabilityCeiling } from "../shared/capability-cei
14
14
  import { previewSimpleWorkflowRun } from "../../workflows/scripted-workflow.ts";
15
15
  import { resolveGitRepositoryIdentity } from "../../workflows/chat-progress.ts";
16
16
  import { getConfigDirName } from "../../shared/utils.ts";
17
+ import { normalizeWorktreeBaseRef } from "../shared/worktree.ts";
17
18
 
18
19
  export const SCHEDULED_RUN_ACTIONS = [
19
20
  "schedule.create",
@@ -39,7 +40,7 @@ export type ScheduleRunState = "running" | "skipped" | "missed" | "completed" |
39
40
  export type ScheduleTrigger =
40
41
  | { kind: "once"; at: string; nextRunAt?: string }
41
42
  | { kind: "interval"; every: string; everyMs: number; anchorAt: string; nextRunAt: string };
42
- export type ScheduleTarget = { workflowScript: string };
43
+ export type ScheduleTarget = { workflowScript: string; baseRef?: string };
43
44
 
44
45
  export interface ScheduleRecord {
45
46
  schemaVersion: 1;
@@ -281,8 +282,15 @@ function readJson(file: string, label: string): unknown {
281
282
 
282
283
  function parseScheduleTarget(value: unknown, file: string): ScheduleTarget {
283
284
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`Schedule record '${file}' has invalid trigger or target.`);
284
- const target = value as { workflowScript?: unknown; agent?: unknown; task?: unknown };
285
- if (typeof target.workflowScript === "string" && target.workflowScript.trim()) return { workflowScript: target.workflowScript.trim() };
285
+ const target = value as { workflowScript?: unknown; baseRef?: unknown; agent?: unknown; task?: unknown };
286
+ if (typeof target.workflowScript === "string" && target.workflowScript.trim()) {
287
+ try {
288
+ const baseRef = normalizeWorktreeBaseRef(target.baseRef);
289
+ return { workflowScript: target.workflowScript.trim(), ...(baseRef === undefined ? {} : { baseRef }) };
290
+ } catch (error) {
291
+ throw new Error(`Schedule record '${file}' has an invalid baseRef: ${error instanceof Error ? error.message : String(error)}`);
292
+ }
293
+ }
286
294
  if (target.agent !== undefined || target.task !== undefined) throw new Error(`Schedule record '${file}' uses a removed legacy agent target; recreate it with target.workflowScript.`);
287
295
  throw new Error(`Schedule record '${file}' requires a workflowScript target.`);
288
296
  }
@@ -429,9 +437,15 @@ function sanitizeTarget(params: SubagentParamsLike): { target?: ScheduleTarget;
429
437
  if (typeof params.workflowScript !== "string" || !params.workflowScript.trim()) return { error: "schedule.create requires a non-empty workflowScript." };
430
438
  if (params.context === "fork") return { error: "Scheduled runs require fresh context." };
431
439
  if (params.async === false) return { error: "Scheduled runs are always async." };
440
+ let baseRef: string | undefined;
441
+ try {
442
+ baseRef = normalizeWorktreeBaseRef(params.baseRef);
443
+ } catch (error) {
444
+ return { error: error instanceof Error ? error.message : String(error) };
445
+ }
432
446
  const acceptanceErrors = validateExecutionAcceptance(params as Parameters<typeof validateExecutionAcceptance>[0]);
433
447
  if (acceptanceErrors.length) return { error: acceptanceErrors.join(" ") };
434
- return { target: { workflowScript: params.workflowScript.trim() } };
448
+ return { target: { workflowScript: params.workflowScript.trim(), ...(baseRef === undefined ? {} : { baseRef }) } };
435
449
  }
436
450
 
437
451
  function executionParams(schedule: ScheduleRecord): SubagentParamsLike {
@@ -9,6 +9,7 @@ import { resolveEffectiveThinking } from "../../shared/model-info.ts";
9
9
  import { normalizeParallelGroups } from "./parallel-groups.ts";
10
10
  import { nestedSummaryFromAsyncStatus, projectNestedEvents, resolveNestedAsyncDir, writeNestedEvent, type NestedRoute } from "../shared/nested-events.ts";
11
11
  import { assertWorkflowGraphHostSteps } from "../shared/host-step-status.ts";
12
+ import type { RawDrainStatusObserver } from "../shared/readonly-drain-observation.ts";
12
13
 
13
14
  export type PidLiveness = "alive" | "dead" | "unknown";
14
15
 
@@ -352,9 +353,10 @@ export function checkPidLiveness(pid: number, kill: KillFn = process.kill): PidL
352
353
  }
353
354
  }
354
355
 
355
- export function reconcileAsyncRun(asyncDir: string, options: ReconcileAsyncRunOptions = {}): ReconcileAsyncRunResult {
356
+ export function reconcileAsyncRun(asyncDir: string, options: ReconcileAsyncRunOptions = {}, observeStatus?: RawDrainStatusObserver): ReconcileAsyncRunResult {
356
357
  const now = options.now?.() ?? Date.now();
357
358
  const status = readStatus(asyncDir);
359
+ observeStatus?.(status);
358
360
  const startedStatus = !status && options.startedRun ? buildStartedStatus(asyncDir, options.startedRun, now) : undefined;
359
361
  const effectiveStatus = status ?? startedStatus;
360
362
  if (!effectiveStatus) return { status: null, repaired: false };