@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
@@ -6,8 +6,8 @@ import {
6
6
  TEMP_ROOT_DIR,
7
7
  type AsyncJobState,
8
8
  type AsyncStatus,
9
- type LaunchResolvedChildExtensionsV1,
10
- type RuntimeAcknowledgedChildExtensionsV1,
9
+ type LaunchResolvedChildExtensions,
10
+ type RuntimeAcknowledgedChildExtensions,
11
11
  type NestedRouteInfo,
12
12
  type TurnBudgetState,
13
13
  type NestedRunSummary,
@@ -16,17 +16,7 @@ import {
16
16
  type SubagentRunMode,
17
17
  type SubagentState,
18
18
  } from "../../shared/types.ts";
19
- import { isSafeNestedPathId, parseNestedPathEnv, sanitizeNestedPath, type NestedPathEntry } from "./nested-path.ts";
20
- import {
21
- SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV,
22
- SUBAGENT_PARENT_CHILD_INDEX_ENV,
23
- SUBAGENT_PARENT_CONTROL_INBOX_ENV,
24
- SUBAGENT_PARENT_DEPTH_ENV,
25
- SUBAGENT_PARENT_EVENT_SINK_ENV,
26
- SUBAGENT_PARENT_PATH_ENV,
27
- SUBAGENT_PARENT_ROOT_RUN_ID_ENV,
28
- SUBAGENT_PARENT_RUN_ID_ENV,
29
- } from "./pi-args.ts";
19
+ import { isSafeNestedPathId, sanitizeNestedPath, type NestedPathEntry } from "./nested-path.ts";
30
20
  import { writeAtomicJson } from "../../shared/atomic-json.ts";
31
21
  import { sanitizeProcessTerminal } from "../background/process-terminal.ts";
32
22
  import { THINKING_LEVELS } from "../../shared/model-info.ts";
@@ -141,13 +131,9 @@ export function createNestedRoute(rootRunId: string): NestedRoute {
141
131
  return { rootRunId, eventSink, controlInbox, capabilityToken };
142
132
  }
143
133
 
144
- export function resolveNestedRouteFromEnv(env: NodeJS.ProcessEnv = process.env): NestedRoute | undefined {
145
- const rootRunId = env[SUBAGENT_PARENT_ROOT_RUN_ID_ENV];
146
- const eventSink = env[SUBAGENT_PARENT_EVENT_SINK_ENV];
147
- const controlInbox = env[SUBAGENT_PARENT_CONTROL_INBOX_ENV];
148
- const capabilityToken = env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV];
149
- if (!rootRunId || !eventSink || !controlInbox || !capabilityToken) return undefined;
150
- const route = { rootRunId, eventSink, controlInbox, capabilityToken };
134
+ /** Validate a route handed to an in-process child against its on-disk metadata. */
135
+ export function resolveNestedRoute(route: NestedRoute): NestedRoute {
136
+ const { rootRunId, capabilityToken } = route;
151
137
  validateRouteShape(route);
152
138
  const routeFile = path.join(commonRouteRoot(route), ROUTE_FILE);
153
139
  const metadata = JSON.parse(fs.readFileSync(routeFile, "utf-8")) as { rootRunId?: unknown; capabilityToken?: unknown };
@@ -157,24 +143,38 @@ export function resolveNestedRouteFromEnv(env: NodeJS.ProcessEnv = process.env):
157
143
  return route;
158
144
  }
159
145
 
160
- export function resolveInheritedNestedRouteFromEnv(env: NodeJS.ProcessEnv = process.env): NestedRoute | undefined {
146
+ export function resolveInheritedNestedRoute(route: NestedRoute): NestedRoute | undefined {
161
147
  try {
162
- return resolveNestedRouteFromEnv(env);
148
+ return resolveNestedRoute(route);
163
149
  } catch (error) {
164
150
  console.error("Ignoring invalid nested subagent event route:", error);
165
151
  return undefined;
166
152
  }
167
153
  }
168
154
 
169
- export function resolveNestedParentAddressFromEnv(env: NodeJS.ProcessEnv = process.env): { parentRunId: string; parentStepIndex?: number; depth: number; path: NestedPathEntry[] } | undefined {
170
- const parentRunId = env[SUBAGENT_PARENT_RUN_ID_ENV];
171
- if (!isSafeNestedId(parentRunId)) return undefined;
172
- const rawIndex = env[SUBAGENT_PARENT_CHILD_INDEX_ENV];
173
- const parentStepIndex = rawIndex && /^\d+$/.test(rawIndex) ? Number(rawIndex) : undefined;
174
- const depth = Math.min(Math.max(1, clampNumber(Number(env[SUBAGENT_PARENT_DEPTH_ENV])) ?? 1), MAX_DEPTH);
175
- const parsedPath = parseNestedPathEnv(env[SUBAGENT_PARENT_PATH_ENV]);
176
- const nestedPath = parsedPath.length ? parsedPath : [{ runId: parentRunId, ...(parentStepIndex !== undefined ? { stepIndex: parentStepIndex } : {}) }];
177
- return { parentRunId, ...(parentStepIndex !== undefined ? { parentStepIndex } : {}), depth, path: nestedPath };
155
+ export interface NestedParentAddress {
156
+ parentRunId: string;
157
+ parentStepIndex?: number;
158
+ depth: number;
159
+ path: NestedPathEntry[];
160
+ }
161
+
162
+ /** The nested route an executor inherited from its own child runtime, validated against disk. */
163
+ export function inheritedNestedRouteOf(runtime: { nestedRoute?: NestedRoute } | undefined): NestedRoute | undefined {
164
+ return runtime?.nestedRoute ? resolveInheritedNestedRoute(runtime.nestedRoute) : undefined;
165
+ }
166
+
167
+ /** The executor's own position in the nested run tree, from its child runtime. */
168
+ export function inheritedNestedParentAddressOf(runtime: { nestedParent?: { parentRunId: string; parentChildIndex?: number; depth: number; path: NestedPathEntry[] } } | undefined): NestedParentAddress | undefined {
169
+ const parent = runtime?.nestedParent;
170
+ if (!parent || !isSafeNestedId(parent.parentRunId)) return undefined;
171
+ const depth = Math.min(Math.max(1, clampNumber(parent.depth) ?? 1), MAX_DEPTH);
172
+ return {
173
+ parentRunId: parent.parentRunId,
174
+ ...(parent.parentChildIndex !== undefined ? { parentStepIndex: parent.parentChildIndex } : {}),
175
+ depth,
176
+ path: parent.path.length ? parent.path : [{ runId: parent.parentRunId, ...(parent.parentChildIndex !== undefined ? { stepIndex: parent.parentChildIndex } : {}) }],
177
+ };
178
178
  }
179
179
 
180
180
  export function resolveNestedAsyncDir(rootRunId: string, run: NestedRunSummary): string | undefined {
@@ -217,7 +217,7 @@ function sanitizeCost(value: unknown): NestedRunSummary["totalCost"] | undefined
217
217
  : undefined;
218
218
  }
219
219
 
220
- function sanitizeLaunchResolvedExtensions(value: unknown): LaunchResolvedChildExtensionsV1 | undefined {
220
+ function sanitizeLaunchResolvedExtensions(value: unknown): LaunchResolvedChildExtensions | undefined {
221
221
  if (!value || typeof value !== "object") return undefined;
222
222
  const raw = value as Record<string, unknown>;
223
223
  if (raw.version !== 1 || raw.source !== "launch-resolved" || typeof raw.disableAmbientExtensions !== "boolean") return undefined;
@@ -241,7 +241,7 @@ function sanitizeLaunchResolvedExtensions(value: unknown): LaunchResolvedChildEx
241
241
  };
242
242
  }
243
243
 
244
- function sanitizeRuntimeAcknowledgedExtensions(value: unknown): RuntimeAcknowledgedChildExtensionsV1 | undefined {
244
+ function sanitizeRuntimeAcknowledgedExtensions(value: unknown): RuntimeAcknowledgedChildExtensions | undefined {
245
245
  if (!value || typeof value !== "object") return undefined;
246
246
  const raw = value as Record<string, unknown>;
247
247
  if (raw.version !== 1 || raw.source !== "child-runtime" || !Array.isArray(raw.ids)) return undefined;
@@ -261,7 +261,7 @@ function sanitizeRuntimeAcknowledgedExtensions(value: unknown): RuntimeAcknowled
261
261
  };
262
262
  }
263
263
 
264
- function runtimeAcknowledgedEntry(value: unknown): { runtimeAcknowledgedExtensions: RuntimeAcknowledgedChildExtensionsV1 } | Record<string, never> {
264
+ function runtimeAcknowledgedEntry(value: unknown): { runtimeAcknowledgedExtensions: RuntimeAcknowledgedChildExtensions } | Record<string, never> {
265
265
  const sanitized = sanitizeRuntimeAcknowledgedExtensions(value);
266
266
  return sanitized ? { runtimeAcknowledgedExtensions: sanitized } : {};
267
267
  }
@@ -286,7 +286,7 @@ function sanitizeTurnBudget(value: unknown): TurnBudgetState | undefined {
286
286
  }
287
287
 
288
288
  function sanitizeState(value: unknown, fallback: NestedRunState): NestedRunState {
289
- return value === "queued" || value === "running" || value === "complete" || value === "failed" || value === "partial" || value === "paused" || value === "stopped"
289
+ return value === "queued" || value === "running" || value === "complete" || value === "failed" || value === "partial" || value === "paused" || value === "stopped" || value === "rejected"
290
290
  ? value
291
291
  : fallback;
292
292
  }
@@ -296,7 +296,7 @@ function sanitizeStep(input: unknown, depth: number): NestedStepSummary | undefi
296
296
  const raw = input as Record<string, unknown>;
297
297
  const agent = stringValue(raw.agent, 128);
298
298
  if (!agent) return undefined;
299
- const status = raw.status === "pending" || raw.status === "running" || raw.status === "complete" || raw.status === "completed" || raw.status === "failed" || raw.status === "paused" || raw.status === "stopped"
299
+ const status = raw.status === "pending" || raw.status === "running" || raw.status === "complete" || raw.status === "completed" || raw.status === "failed" || raw.status === "partial" || raw.status === "paused" || raw.status === "stopped" || raw.status === "rejected"
300
300
  ? raw.status
301
301
  : "pending";
302
302
  const model = stringValue(raw.model);
@@ -438,7 +438,7 @@ export function parseNestedEventRecords(content: string, route: NestedRoute): Ne
438
438
  }
439
439
 
440
440
  function terminal(state: NestedRunState): boolean {
441
- return state === "complete" || state === "failed" || state === "partial" || state === "paused" || state === "stopped";
441
+ return state === "complete" || state === "failed" || state === "partial" || state === "paused" || state === "rejected" || state === "stopped";
442
442
  }
443
443
 
444
444
  function mergeBoundedChildren(existing: NestedRunSummary[] | undefined, incoming: NestedRunSummary[] | undefined): NestedRunSummary[] | undefined {
@@ -947,15 +947,6 @@ export function readNestedControlResults(route: NestedRoute): NestedControlResul
947
947
  .flatMap((entry) => readControlResultsFromFile(route, path.join(route.eventSink, entry)));
948
948
  }
949
949
 
950
- export function nestedRouteEnv(route: NestedRoute): Record<string, string> {
951
- return {
952
- [SUBAGENT_PARENT_EVENT_SINK_ENV]: route.eventSink,
953
- [SUBAGENT_PARENT_CONTROL_INBOX_ENV]: route.controlInbox,
954
- [SUBAGENT_PARENT_ROOT_RUN_ID_ENV]: route.rootRunId,
955
- [SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV]: route.capabilityToken,
956
- };
957
- }
958
-
959
950
  export function attachRootChildrenToSteps<T extends { children?: NestedRunSummary[]; index?: number }>(rootRunId: string, steps: T[] | undefined, children: NestedRunSummary[] | undefined): void {
960
951
  if (!steps?.length) return;
961
952
  for (const step of steps) {
@@ -1067,13 +1058,6 @@ export function nestedSummaryFromAsyncStatus(status: AsyncStatus, asyncDir: stri
1067
1058
  };
1068
1059
  }
1069
1060
 
1070
- export function nestedArtifactEnv(rootRunId: string, parentRunId: string): Record<string, string> {
1071
- return {
1072
- SELESAI_SUBAGENT_NESTED_ROOT_RUN_ID: rootRunId,
1073
- SELESAI_SUBAGENT_NESTED_PARENT_RUN_ID: parentRunId,
1074
- };
1075
- }
1076
-
1077
1061
  export function isTopLevelAsyncDir(asyncDir: string): boolean {
1078
1062
  const resolved = path.resolve(asyncDir);
1079
1063
  return containedPath(DIRS.async, resolved) && !containedPath(path.join(TEMP_ROOT_DIR, "nested-subagent-runs"), resolved);
@@ -49,4 +49,4 @@ export function parseNestedPathEnv(value: string | undefined): NestedPathEntry[]
49
49
  export function encodeNestedPathEnv(value: NestedPathEntry[]): string {
50
50
  const sanitized = sanitizeNestedPath(value);
51
51
  return sanitized.length ? JSON.stringify(sanitized) : "";
52
- }
52
+ }
@@ -53,10 +53,13 @@ const ORCA_CLEANUP_WATCHDOG_SCRIPT = [
53
53
  ].join("");
54
54
 
55
55
  export interface OrcaProgressTab {
56
+ /** Resolves when the terminal-create watchdog closes, after its final manifest/queue writes (success or failure). Not viewer completion. */
57
+ readonly creationSettled: Promise<void>;
56
58
  append(text: string): void;
57
59
  section(input: { agent: string; index: number; count: number }): void;
58
60
  event(event: { type?: string; message?: Message; toolName?: string; args?: unknown }): void;
59
- finish(status: "completed" | "failed" | "stopped", sessionFile?: string): void;
61
+ /** Resolves once the mirrored log and its done marker are on disk, so a host may exit afterwards. */
62
+ finish(status: "completed" | "failed" | "stopped", sessionFile?: string): Promise<void>;
60
63
  }
61
64
 
62
65
  function executableFile(candidate: string): boolean {
@@ -401,6 +404,8 @@ export function createOrcaProgressTab(input: {
401
404
  }
402
405
  };
403
406
  let createSettled = false;
407
+ let resolveCreationSettled!: () => void;
408
+ const creationSettled = new Promise<void>((resolve) => { resolveCreationSettled = resolve; });
404
409
  let cleanupPaths: string[] | undefined;
405
410
  const scheduleDeferredCleanup = () => {
406
411
  if (!createSettled || cleanupPaths === undefined) return;
@@ -433,6 +438,7 @@ export function createOrcaProgressTab(input: {
433
438
  createSettled = true;
434
439
  if (code !== 0) failObserver();
435
440
  scheduleDeferredCleanup();
441
+ resolveCreationSettled();
436
442
  });
437
443
  watchdog.once("error", () => {
438
444
  markCreateReady();
@@ -449,6 +455,7 @@ export function createOrcaProgressTab(input: {
449
455
 
450
456
  let finished = false;
451
457
  return {
458
+ creationSettled,
452
459
  append(text) {
453
460
  if (finished) return;
454
461
  writeProgress(text);
@@ -475,7 +482,7 @@ export function createOrcaProgressTab(input: {
475
482
  }
476
483
  },
477
484
  finish(status, sessionFile) {
478
- if (!available || finished) return;
485
+ if (!available || finished) return Promise.resolve();
479
486
  finished = true;
480
487
  const sessionId = status === "completed" ? resolvePiSessionId(sessionFile) : undefined;
481
488
  let verifiedSessionFile: string | undefined;
@@ -488,11 +495,15 @@ export function createOrcaProgressTab(input: {
488
495
  const truncation = truncated ? `\n[progress mirror truncated at ${MAX_MIRROR_BYTES} bytes]\n` : "";
489
496
  let footer = `${truncation}\n${"─".repeat(48)}\n${terminalMessage}\n`;
490
497
  if (scheduledBytes + Buffer.byteLength(footer) > MAX_MIRROR_BYTES) footer = `\n${status}\n`;
491
- logStream.end(footer, () => {
492
- if (!available) return;
493
- try { fs.writeFileSync(donePath, `${status}\n`, { encoding: "utf-8", mode: 0o600 }); } catch { /* best effort */ }
494
- cleanupPaths = [logPath, donePath];
495
- scheduleDeferredCleanup();
498
+ return new Promise<void>((resolve) => {
499
+ logStream.end(footer, () => {
500
+ if (available) {
501
+ try { fs.writeFileSync(donePath, `${status}\n`, { encoding: "utf-8", mode: 0o600 }); } catch { /* best effort */ }
502
+ cleanupPaths = [logPath, donePath];
503
+ scheduleDeferredCleanup();
504
+ }
505
+ resolve();
506
+ });
496
507
  });
497
508
  },
498
509
  };
@@ -17,6 +17,7 @@ import type {
17
17
  WorktreeCleanupReport,
18
18
  WorktreeDiff,
19
19
  WorktreeSetup,
20
+ WorktreeSetupProgress,
20
21
  WorktreeCleanupIntent,
21
22
  } from "./worktree.ts";
22
23
  import { cleanupWorktrees } from "./worktree.ts";
@@ -614,18 +615,62 @@ export function parallelHandoffPath(baseDir: string, runId?: string): string {
614
615
  return runId ? path.join(baseDir, "handoffs", `${runId}.json`) : path.join(baseDir, "handoff.json");
615
616
  }
616
617
 
617
- export function writePendingParallelHandoff(input: {
618
- manifestPath: string;
619
- runId: string;
620
- mode: "single" | "parallel" | "chain";
621
- source: "foreground" | "async";
622
- cwd: string;
623
- stepIndex: number;
624
- flatStartIndex: number;
625
- setup: WorktreeSetup;
626
- laneBindings?: ParallelHandoffLaneBinding[];
627
- }): ParallelHandoffReference {
628
- return writeParallelHandoffGroup({ ...input, diffs: [], results: [] });
618
+ /** Synchronous onProgress projection shared by setup owners; snapshots are cumulative. */
619
+ export function writeWorktreeSetupHandoff(input: Omit<Parameters<typeof writeParallelHandoffGroup>[0], "setup" | "diffs" | "results" | "cleanup" | "now"> & {
620
+ progress: WorktreeSetupProgress;
621
+ }): ParallelHandoffReference | undefined {
622
+ const { progress, ...handoff } = input;
623
+ const { setup, attempts, cleanup } = progress;
624
+ // Preflight has no allocation identity yet. Its original error belongs to the caller.
625
+ if (attempts.length === 0 && setup.worktrees.length === 0) return undefined;
626
+ if (!setup.cwd || !setup.baseCommit) throw new Error("Cannot publish worktree allocation evidence without repository and base commit.");
627
+ const diagnostic = (text: string): string => text.slice(0, 512);
628
+ // Never copy argv, environment, Error objects or captured stdout/stderr into artifacts.
629
+ const commandEvidence = (command: WorktreeSetupProgress["command"]) => command && ({
630
+ pid: command.pid,
631
+ processGroupId: command.processGroupId,
632
+ ...(command.result ? {
633
+ status: command.result.status,
634
+ signal: command.result.signal,
635
+ failed: Boolean(command.result.error),
636
+ outputIncomplete: command.result.outputIncomplete,
637
+ processTree: command.result.processTree?.state,
638
+ } : {}),
639
+ });
640
+ const errors = [
641
+ `Worktree setup ${JSON.stringify({ runId: input.runId, stepIndex: input.stepIndex, phase: progress.phase,
642
+ unknown: Boolean(progress.unknown), command: commandEvidence(progress.command) })}`,
643
+ ...attempts.map((attempt) => {
644
+ const task = cleanup?.tasks.find((candidate) => candidate.index === attempt.index);
645
+ return `Allocation attempt ${JSON.stringify({ index: attempt.index, branch: attempt.branch,
646
+ path: attempt.path ?? null, validated: attempt.validated,
647
+ command: commandEvidence(attempt.command), hookCommand: commandEvidence(attempt.hookCommand),
648
+ ...(task ? { worktreeRemoved: task.worktreeRemoved, branchRemoved: task.branchRemoved,
649
+ preserved: task.preserved, reason: task.reason && diagnostic(task.reason), errors: task.errors?.map(diagnostic) } : {}),
650
+ })}`;
651
+ }),
652
+ ...(cleanup?.errors?.map(diagnostic) ?? []),
653
+ ...(progress.unknown ? ["Setup settlement unknown; manual reconciliation required."] : []),
654
+ ];
655
+ return writeParallelHandoffGroup({
656
+ ...handoff, setup, diffs: [], results: [],
657
+ laneBindings: input.laneBindings?.filter((binding) => setup.worktrees.some((worktree) => worktree.index === binding.taskIndex)),
658
+ cleanup: {
659
+ state: cleanup?.state ?? "partial",
660
+ pruned: cleanup?.pruned ?? false,
661
+ errors,
662
+ // An attempted native path is not a validated recovery task, even during rollback.
663
+ tasks: setup.worktrees.map((worktree) => {
664
+ const task = cleanup?.tasks.find((candidate) => candidate.index === worktree.index);
665
+ return task ? { ...task, reason: task.reason && diagnostic(task.reason), errors: task.errors?.map(diagnostic) } : {
666
+ index: worktree.index, path: worktree.path, branch: worktree.branch,
667
+ provider: worktree.provider, naming: worktree.naming,
668
+ worktreeRemoved: false, branchRemoved: false, preserved: true,
669
+ reason: "setup pending durable handoff capture",
670
+ };
671
+ }),
672
+ },
673
+ });
629
674
  }
630
675
 
631
676
  export function formatParallelHandoffReference(reference: ParallelHandoffReference): string {
@@ -41,14 +41,13 @@ export interface RunnerSubagentStep {
41
41
  /** The primary model is inherited from the parent session and should not be verified against the child-reported active registry model. */
42
42
  skipPrimaryModelVerification?: boolean;
43
43
  modelVerificationRegistry?: Array<{ provider: string; id: string; fullId: string; contextWindow?: number }>;
44
+ modelResponseAliases?: Record<string, string[]>;
44
45
  tools?: string[];
45
46
  excludeTools?: string[];
46
47
  allowNestedSubagents?: boolean;
47
48
  extensions?: string[];
48
49
  subagentOnlyExtensions?: string[];
49
50
  mcpDirectTools?: string[];
50
- mcpConfig?: import("./mcp-direct-tool-allowlist.ts").McpConfig;
51
- runtimeServerNames?: string[];
52
51
  mutationTools?: string[];
53
52
  completionGuard?: boolean;
54
53
  systemPrompt?: string | null;
@@ -76,8 +75,8 @@ export interface RunnerSubagentStep {
76
75
  launchBindingTask?: string;
77
76
  launchContractDigest?: string;
78
77
  extensionBindings?: import("./extension-bindings.ts").ExtensionBindings;
79
- launchResolvedExtensions?: import("../../shared/types.ts").LaunchResolvedChildExtensionsV1;
80
- runtimeAcknowledgedExtensions?: import("../../shared/types.ts").RuntimeAcknowledgedChildExtensionsV1;
78
+ launchResolvedExtensions?: import("../../shared/types.ts").LaunchResolvedChildExtensions;
79
+ runtimeAcknowledgedExtensions?: import("../../shared/types.ts").RuntimeAcknowledgedChildExtensions;
81
80
  effectiveAcceptance?: import("../../shared/types.ts").ResolvedAcceptanceConfig;
82
81
  acceptanceInput?: import("../../shared/types.ts").AcceptanceInput;
83
82
  acceptanceRole?: import("../../shared/types.ts").AcceptanceRole;
@@ -53,17 +53,6 @@ export function permissionDecision(rules: PermissionRules | undefined, toolName:
53
53
  return rules?.[toolName] ?? "allow";
54
54
  }
55
55
 
56
- export function encodePermissionRules(rules: PermissionRules | undefined): string | undefined {
57
- if (!rules || Object.keys(rules).length === 0) return undefined;
58
- const encoded = JSON.stringify(rules);
59
- if (Buffer.byteLength(encoded, "utf-8") > MAX_POLICY_BYTES) throw new Error("Resolved permission policy is too large.");
60
- return encoded;
61
- }
62
-
63
- export function decodePermissionRules(encoded: string | undefined): PermissionRules | undefined {
64
- if (!encoded?.trim()) return undefined;
65
- return validatePermissionRules(JSON.parse(encoded), PERMISSION_POLICY_ENV);
66
- }
67
56
 
68
57
  function redact(value: unknown, key = "", depth = 0): unknown {
69
58
  if (SECRET_KEY.test(key)) return "[redacted]";
@@ -4,9 +4,12 @@ export function formatProcessSignalError(signal: string): string {
4
4
 
5
5
  export function formatMidToolExitError(input: {
6
6
  toolName: string;
7
- exitCode: number | null;
7
+ exitCode?: number | null;
8
8
  processSignal?: string | null;
9
9
  }): string {
10
+ if (input.exitCode === undefined && !input.processSignal) {
11
+ return `Subagent session ended during '${input.toolName}' tool execution before the tool completed. Earlier assistant output is not a terminal result.`;
12
+ }
10
13
  const terminal = [`exit ${input.exitCode ?? "unknown"}`, ...(input.processSignal ? [`signal ${input.processSignal}`] : [])].join(", ");
11
14
  return `Subagent process exited during '${input.toolName}' tool execution (${terminal}) before the tool completed. Earlier assistant output is not a terminal result.`;
12
15
  }
@@ -0,0 +1,42 @@
1
+ const knownStates = new Set(["queued", "running", "complete", "failed", "partial", "paused", "stopped", "rejected"]);
2
+
3
+ /**
4
+ * Private, installation-owned evidence. Never changes drain/query behavior or retains statuses.
5
+ * Observes the ordinary indexed drain, not historical ownership or outside work appearing later.
6
+ */
7
+ export class ReadonlyDrainObservation {
8
+ private state: "pending" | "empty" | "denied" = "pending";
9
+ private started = false;
10
+ private first = false;
11
+ private readonly file: string;
12
+ private readonly guard: () => boolean;
13
+ constructor(file: string, guard: () => boolean) { this.file = file; this.guard = guard; }
14
+ deny(): void { this.state = "denied"; }
15
+ check(): boolean {
16
+ try { if (!this.guard()) this.deny(); } catch { this.deny(); }
17
+ return this.state !== "denied";
18
+ }
19
+ begin(file: string | null, native: boolean): void {
20
+ if (this.started || file !== this.file || !native) this.deny();
21
+ this.started = true;
22
+ this.check();
23
+ }
24
+ /** Called at the existing initial read, before reconciliation or filtering. */
25
+ readonly status: RawDrainStatusObserver = (status) => {
26
+ if (!status || typeof status.sessionId !== "string" || !status.sessionId
27
+ || !knownStates.has(status.state as string)) this.deny();
28
+ else if (status.sessionId === this.file && (status.state === "queued" || status.state === "running")) this.deny();
29
+ };
30
+ predicate(hasWork: boolean): void {
31
+ if (this.first) return;
32
+ this.first = true;
33
+ if (hasWork) this.deny();
34
+ }
35
+ complete(): void {
36
+ if (this.started && this.first && this.check()) this.state = "empty";
37
+ }
38
+ settled(): boolean { return this.check() && this.state === "empty"; }
39
+ }
40
+
41
+ /** Internal synchronous sink; null means an existing query encountered uncertainty. */
42
+ export type RawDrainStatusObserver = (status: { sessionId?: unknown; state?: unknown } | null) => void;
@@ -0,0 +1,69 @@
1
+ import type { ChildSession } from "./child-session.ts";
2
+ import { getReadonlySessionEvidence, type SettledReadonlyEvidence } from "./readonly-session-evidence.ts";
3
+
4
+ /** Owned by the logical host run, shared with abort recovery; never reset per attempt. */
5
+ export type LogicalRecoveryState = "unused" | "abort-recovery" | "readonly-continuation";
6
+
7
+ export interface ReadonlyContinuationCandidate {
8
+ /** Actual resolved identity, not an alias or a parsed display reference. */
9
+ readonly resolved: { readonly provider: string; readonly model: string; readonly api: string } | undefined;
10
+ readonly tried: boolean;
11
+ /** Host assessment of retained input support AND context capacity, including prompt overhead. */
12
+ readonly compatibility: "compatible" | "incompatible" | "unknown";
13
+ }
14
+
15
+ export interface ReadonlyContinuationInput {
16
+ /** Retain the source child privately: its live accessor detects revoked receipts. */
17
+ readonly source: ChildSession | undefined;
18
+ readonly recoveryState: LogicalRecoveryState;
19
+ /** Ordered, already authorized and exclusion-filtered. This planner never resolves models. */
20
+ readonly candidates: readonly ReadonlyContinuationCandidate[];
21
+ readonly currentIndex: number;
22
+ /** False includes success, stop/interrupt/detach/handoff, deadline, or workflow-permit veto. */
23
+ readonly lifecycleAllowsContinuation: boolean;
24
+ /** False includes completion/structured/acceptance failures, pending input or other effects. */
25
+ readonly effectsAllowContinuation: boolean;
26
+ /** Configured tool budgets are unsupported; unknown authoritative usage allowance denies. */
27
+ readonly budget: "unconfigured" | "available" | "exhausted" | "unknown" | "tool-budget-configured";
28
+ readonly knownContextOverflow: boolean;
29
+ }
30
+
31
+ export const READONLY_CONTINUATION_PROMPT = "The previous provider request failed with HTTP 429 after read-only progress. Continue from the retained transcript and completed tool results. Do not restart or repeat completed work. Use only the existing read-only tools and finish the requested response.";
32
+
33
+ export type ReadonlyContinuationPlan =
34
+ | { readonly kind: "deny"; readonly reason: "recovery-consumed" | "veto" | "no-evidence" | "unresolved-identity" | "incompatible" | "no-sibling" }
35
+ | { readonly kind: "continue"; readonly candidateIndex: number; readonly expected: SettledReadonlyEvidence;
36
+ readonly prompt: typeof READONLY_CONTINUATION_PROMPT; readonly recoveryState: "readonly-continuation" };
37
+
38
+ /**
39
+ * Pure decision: no disk reads, dispatch, receipt minting, or state mutation.
40
+ * The host MUST recheck live source proof and lifecycle/budget at handoff, then store the
41
+ * returned consumed state BEFORE creation (even if creation subsequently fails),
42
+ * and pass expected to requestReadonlySessionEvidence on the exact-file sibling launch.
43
+ * That factory guard owns checkpoint/configured-provider revalidation before open/prompt/dispatch.
44
+ * The host must also verify the actual sibling model matches the selected resolved identity;
45
+ * a plan is not a dispatch authorization and any create/guard failure terminates recovery.
46
+ */
47
+ export function planReadonlyModelContinuation(input: ReadonlyContinuationInput): ReadonlyContinuationPlan {
48
+ if (input.recoveryState !== "unused") return { kind: "deny", reason: "recovery-consumed" };
49
+ if (!input.lifecycleAllowsContinuation || !input.effectsAllowContinuation || input.knownContextOverflow
50
+ || (input.budget !== "unconfigured" && input.budget !== "available")) return { kind: "deny", reason: "veto" };
51
+ const expected = input.source && getReadonlySessionEvidence(input.source);
52
+ if (!expected || input.source?.detached || input.source?.shutDown) return { kind: "deny", reason: "no-evidence" };
53
+ const current = Number.isInteger(input.currentIndex) && input.currentIndex >= 0 ? input.candidates[input.currentIndex]?.resolved : undefined;
54
+ if (!current || current.provider !== expected.provider || current.model !== expected.model || current.api !== expected.api) {
55
+ return { kind: "deny", reason: "unresolved-identity" };
56
+ }
57
+ for (let index = input.currentIndex + 1; index < input.candidates.length; index++) {
58
+ const candidate = input.candidates[index];
59
+ if (!candidate) return { kind: "deny", reason: "unresolved-identity" };
60
+ if (candidate.tried) continue;
61
+ const resolved = candidate.resolved;
62
+ if (!resolved?.provider || !resolved.model || !resolved.api) return { kind: "deny", reason: "unresolved-identity" };
63
+ if (resolved.provider !== expected.provider || resolved.model === expected.model) continue;
64
+ if (input.candidates.some((other) => other.tried && other.resolved?.provider === resolved.provider && other.resolved.model === resolved.model)) continue;
65
+ if (resolved.api !== expected.api || candidate.compatibility !== "compatible") return { kind: "deny", reason: "incompatible" };
66
+ return { kind: "continue", candidateIndex: index, expected, prompt: READONLY_CONTINUATION_PROMPT, recoveryState: "readonly-continuation" };
67
+ }
68
+ return { kind: "deny", reason: "no-sibling" };
69
+ }