mixdog 1.2.3 → 1.2.5

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 (469) hide show
  1. package/package.json +1 -1
  2. package/scripts/gate-local.mjs +6 -4
  3. package/scripts/lib/gate-scheduler.mjs +29 -11
  4. package/scripts/mobile-release.mjs +5 -4
  5. package/scripts/probe-provider-catalog.mjs +31 -0
  6. package/scripts/provider-pingpong-live.mjs +128 -38
  7. package/scripts/session-sweep.mjs +5 -25
  8. package/src/agents/maintainer/AGENT.md +1 -1
  9. package/src/agents/maintainer/agent.json +1 -1
  10. package/src/agents/reviewer/AGENT.md +2 -4
  11. package/src/agents/security/AGENT.md +1 -2
  12. package/src/agents/writer/AGENT.md +2 -3
  13. package/src/defaults/shipped-history.json +7 -1
  14. package/src/defaults/skills/image/SKILL.md +21 -23
  15. package/src/lib/keychain-cjs.cjs +13 -11
  16. package/src/output-styles/common.md +2 -1
  17. package/src/rules/agent/AGENT.md +7 -5
  18. package/src/rules/lead/LEAD.md +13 -13
  19. package/src/rules/shared/45-destructive.md +4 -0
  20. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  21. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +28 -7
  22. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -11
  23. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +101 -23
  24. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +2 -0
  25. package/src/runtime/agent/orchestrator/providers/anthropic-api-key-fetch.mjs +36 -0
  26. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +1 -1
  27. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -3
  28. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  29. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +26 -44
  30. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2 -5
  31. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +4 -0
  32. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +41 -12
  33. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +13 -1
  34. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +81 -10
  35. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +109 -5
  36. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +2 -1
  37. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +107 -37
  38. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +4 -1
  39. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +3 -1
  40. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  41. package/src/runtime/agent/orchestrator/providers/cursor-native-context.mjs +48 -0
  42. package/src/runtime/agent/orchestrator/providers/cursor-wire-exec.mjs +144 -34
  43. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +28 -4
  44. package/src/runtime/agent/orchestrator/providers/cursor-wire-request.mjs +8 -4
  45. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +41 -11
  46. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +67 -5
  47. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +14 -4
  48. package/src/runtime/agent/orchestrator/providers/cursor.mjs +14 -1
  49. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +9 -6
  50. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -2
  51. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +26 -4
  52. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +12 -6
  53. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +14 -6
  54. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +4 -4
  55. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +1 -0
  56. package/src/runtime/agent/orchestrator/providers/gemini-rest-stream/watchdogs.mjs +16 -5
  57. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +6 -1
  58. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +22 -10
  59. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -2
  60. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +33 -7
  61. package/src/runtime/agent/orchestrator/providers/gemini.mjs +11 -2
  62. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  63. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +9 -2
  64. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +9 -5
  65. package/src/runtime/agent/orchestrator/providers/lib/request-compression.mjs +86 -0
  66. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +4 -2
  67. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -5
  68. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +7 -1
  69. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +60 -16
  70. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +11 -13
  71. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +30 -19
  72. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +5 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +42 -5
  75. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +13 -9
  76. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +1 -3
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +18 -7
  78. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +36 -3
  79. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +51 -3
  80. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +11 -1
  81. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +64 -52
  82. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +3 -1
  83. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +2 -1
  84. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +7 -1
  85. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +1 -4
  86. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +0 -1
  87. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +7 -6
  88. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +13 -2
  89. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +4 -1
  90. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +1 -2
  91. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +5 -4
  92. package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -1
  93. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +2 -1
  94. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +11 -4
  95. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +14 -4
  96. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +15 -3
  97. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +6 -2
  98. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +8 -6
  99. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +4 -1
  100. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +30 -2
  101. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +3 -2
  102. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -3
  103. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +3 -1
  104. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge-contract.mjs +6 -0
  105. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +10 -10
  106. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +3 -1
  107. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +46 -8
  108. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -8
  109. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -2
  110. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +24 -0
  111. package/src/runtime/agent/orchestrator/session/cache/tool-result-reuse.mjs +10 -2
  112. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -3
  113. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -11
  114. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +6 -22
  115. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -0
  116. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +16 -2
  117. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +28 -0
  118. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  119. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +0 -6
  120. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +0 -6
  121. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +1 -1
  122. package/src/runtime/agent/orchestrator/session/historical-session-closure.mjs +10 -0
  123. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +2 -5
  124. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +2 -4
  125. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +3 -3
  126. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +0 -27
  127. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +1 -1
  128. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -10
  129. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -9
  130. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +4 -1
  131. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +4 -1
  132. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +1 -4
  133. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +76 -0
  134. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +5 -1
  135. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +8 -9
  136. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +6 -0
  137. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -2
  138. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +1 -4
  139. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -4
  140. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +33 -3
  141. package/src/runtime/agent/orchestrator/session/manager/ask-support.mjs +0 -4
  142. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +21 -1
  143. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +38 -13
  144. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +33 -0
  145. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +5 -0
  146. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +19 -1
  147. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +57 -13
  148. package/src/runtime/agent/orchestrator/session/manager/failed-turn-rewind.mjs +16 -0
  149. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +6 -120
  150. package/src/runtime/agent/orchestrator/session/manager/pending-persist-queue.mjs +1 -1
  151. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +29 -8
  152. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +42 -49
  153. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +50 -0
  154. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +32 -14
  155. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +1 -1
  156. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +17 -33
  157. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +29 -13
  158. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -3
  159. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +45 -0
  160. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -9
  161. package/src/runtime/agent/orchestrator/session/send-instrumentation.mjs +2 -1
  162. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -2
  163. package/src/runtime/agent/orchestrator/session/side-question.mjs +12 -7
  164. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +5 -12
  165. package/src/runtime/agent/orchestrator/session/store/lifecycle-read.mjs +1 -1
  166. package/src/runtime/agent/orchestrator/session/store/listing.mjs +2 -6
  167. package/src/runtime/agent/orchestrator/session/store/live-cache-eviction.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +46 -37
  169. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +1 -1
  170. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +1 -1
  171. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +5 -11
  172. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +59 -0
  173. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +1 -1
  174. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +1 -1
  175. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +27 -32
  176. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +0 -8
  177. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +6 -18
  178. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +33 -106
  179. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +1 -1
  180. package/src/runtime/agent/orchestrator/session/store-agent-worker-pool.mjs +5 -8
  181. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +160 -212
  182. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +50 -116
  183. package/src/runtime/agent/orchestrator/session/store-summary-locations.mjs +3 -29
  184. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +1 -1
  185. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +7 -8
  186. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +9 -20
  187. package/src/runtime/agent/orchestrator/session/store.mjs +3 -16
  188. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +11 -12
  189. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +37 -13
  190. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +15 -4
  191. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +4 -2
  192. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +72 -15
  193. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +45 -0
  194. package/src/runtime/agent/orchestrator/stall-policy.mjs +50 -0
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +5 -1
  196. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +6 -2
  197. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +204 -10
  198. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +160 -39
  199. package/src/runtime/agent/orchestrator/tools/builtin/git-partial-stage.mjs +7 -5
  200. package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +14 -5
  201. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +4 -3
  202. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +2 -1
  203. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-path-fanout.mjs +48 -44
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +10 -3
  205. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +200 -17
  206. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +5 -4
  207. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +6 -1
  208. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +20 -0
  209. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +101 -2
  210. package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
  211. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +67 -0
  212. package/src/runtime/agent/orchestrator/tools/lib/process-table-fixture.mjs +50 -0
  213. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +303 -63
  214. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -0
  215. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +108 -18
  216. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +77 -11
  217. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +81 -5
  218. package/src/runtime/attachments/store.d.mts +9 -0
  219. package/src/runtime/attachments/store.mjs +80 -9
  220. package/src/runtime/browser-bridge/browser-action-contract.d.mts +0 -1
  221. package/src/runtime/browser-bridge/browser-action-contract.mjs +0 -2
  222. package/src/runtime/computer-bridge/action-schema.mjs +178 -178
  223. package/src/runtime/computer-bridge/linux-readiness.d.mts +0 -2
  224. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -16
  225. package/src/runtime/effort-judge/judge-client.mjs +21 -4
  226. package/src/runtime/effort-judge/judge-worker.mjs +4 -1
  227. package/src/runtime/github/tool.mjs +118 -17
  228. package/src/runtime/media/adapters/codex-image.mjs +140 -21
  229. package/src/runtime/media/catalog.mjs +4 -4
  230. package/src/runtime/media/chatgpt-usage.mjs +55 -0
  231. package/src/runtime/media/defaults.mjs +37 -0
  232. package/src/runtime/media/jobs.mjs +12 -2
  233. package/src/runtime/media/lanes.mjs +12 -0
  234. package/src/runtime/media/tool-defs.mjs +15 -4
  235. package/src/runtime/media/tool.mjs +41 -12
  236. package/src/runtime/media/upstream-error.mjs +72 -6
  237. package/src/runtime/memory/lib/ingest/transcript-rows.mjs +1 -0
  238. package/src/runtime/memory/lib/pg/process.mjs +5 -7
  239. package/src/runtime/memory/lib/pg/supervisor.mjs +4 -1
  240. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  241. package/src/runtime/office/authoring/html-browser.mjs +18 -8
  242. package/src/runtime/office/authoring/pdf-html-runner.mjs +1 -1
  243. package/src/runtime/office/authoring/pptx-html-measure.mjs +1 -1
  244. package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
  245. package/src/runtime/office/core/office-write-ledger.mjs +1 -5
  246. package/src/runtime/office/index.mjs +2 -3
  247. package/src/runtime/office/pdf/pdf-analysis.mjs +0 -68
  248. package/src/runtime/session-search/session-search-ingest.mjs +1 -1
  249. package/src/runtime/shared/agent-reap-state.mjs +13 -0
  250. package/src/runtime/shared/atomic-file.d.mts +1 -1
  251. package/src/runtime/shared/background-tasks.mjs +6 -1
  252. package/src/runtime/shared/bounded-line-diff.mjs +11 -2
  253. package/src/runtime/shared/browser-launch.mjs +15 -0
  254. package/src/runtime/shared/err-text.mjs +42 -4
  255. package/src/runtime/shared/file-lock.mjs +6 -5
  256. package/src/runtime/shared/llm/anthropic-betas.mjs +1 -2
  257. package/src/runtime/shared/llm/provider-model-identities.mjs +1 -0
  258. package/src/runtime/shared/model-route-chain.d.mts +8 -0
  259. package/src/runtime/shared/model-route-chain.mjs +48 -0
  260. package/src/runtime/shared/model-route-fallback.mjs +22 -0
  261. package/src/runtime/shared/pid-liveness.mjs +12 -0
  262. package/src/runtime/shared/provider-api-key.mjs +6 -0
  263. package/src/runtime/shared/provider-timeout-phase.mjs +17 -0
  264. package/src/runtime/shared/quiet-progress.d.mts +35 -0
  265. package/src/runtime/shared/quiet-progress.mjs +101 -0
  266. package/src/runtime/shared/quota-resume-store.mjs +32 -1
  267. package/src/runtime/shared/read-row-numbers.mjs +44 -0
  268. package/src/runtime/shared/remote-intent.mjs +2 -42
  269. package/src/runtime/shared/slow-span.mjs +8 -1
  270. package/src/runtime/shared/statusline/statusline-segments.mjs +24 -2
  271. package/src/runtime/shared/tool-card-model/card-header.mjs +2 -1
  272. package/src/runtime/shared/tool-output-budget.mjs +2 -0
  273. package/src/runtime/shared/tool-result-summary.mjs +16 -2
  274. package/src/runtime/shared/tool-status.mjs +3 -2
  275. package/src/runtime/shared/tool-surface.mjs +2 -3
  276. package/src/runtime/shared/tool-work-units.mjs +22 -15
  277. package/src/runtime/shared/transcript-metadata.mjs +49 -1
  278. package/src/runtime/shared/transcript-turn-keys.mjs +33 -0
  279. package/src/runtime/shared/transcript-writer/transcript-file.mjs +10 -1
  280. package/src/runtime/shared/transcript-writer.mjs +14 -4
  281. package/src/runtime/shared/turn-changes.mjs +2 -1
  282. package/src/runtime/shared/turn-snapshot.mjs +11 -3
  283. package/src/runtime/shared/worktrees/activity-gate.mjs +175 -0
  284. package/src/runtime/shared/worktrees/branch-management.mjs +179 -0
  285. package/src/runtime/shared/worktrees/carry.mjs +6 -4
  286. package/src/runtime/shared/worktrees/contract.mjs +27 -1
  287. package/src/runtime/shared/worktrees/dependencies.mjs +456 -0
  288. package/src/runtime/shared/worktrees/file-recovery.mjs +29 -13
  289. package/src/runtime/shared/worktrees/git-head.mjs +22 -13
  290. package/src/runtime/shared/worktrees/include.mjs +125 -7
  291. package/src/runtime/shared/worktrees/lock.mjs +1 -1
  292. package/src/runtime/shared/worktrees/maintenance.mjs +20 -2
  293. package/src/runtime/shared/worktrees/manager.mjs +378 -32
  294. package/src/runtime/shared/worktrees/owner.mjs +2 -1
  295. package/src/runtime/shared/worktrees/preparation-report.mjs +79 -0
  296. package/src/runtime/shared/worktrees/setup-commands.mjs +232 -0
  297. package/src/runtime/shared/worktrees/workspace-visibility.mjs +17 -0
  298. package/src/runtime/terminal-bridge/client.mjs +14 -10
  299. package/src/session-runtime/boot/apis.mjs +7 -1
  300. package/src/session-runtime/boot/config.mjs +2 -0
  301. package/src/session-runtime/boot/facade.mjs +3 -0
  302. package/src/session-runtime/boot/session.mjs +3 -2
  303. package/src/session-runtime/boot/tools.mjs +3 -0
  304. package/src/session-runtime/conversation-import/service.mjs +1 -1
  305. package/src/session-runtime/goal-facade-api.mjs +2 -2
  306. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +44 -18
  307. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +4 -1
  308. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +22 -8
  309. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  310. package/src/session-runtime/lifecycle/cold-heir.mjs +0 -1
  311. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -16
  312. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +18 -53
  313. package/src/session-runtime/lifecycle/session-switch.mjs +1 -1
  314. package/src/session-runtime/lifecycle/shared.mjs +5 -6
  315. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -5
  316. package/src/session-runtime/lifecycle/teardown.mjs +7 -16
  317. package/src/session-runtime/media-api.mjs +8 -0
  318. package/src/session-runtime/model-route/route-ownership.mjs +60 -0
  319. package/src/session-runtime/model-route/route-persist.mjs +3 -2
  320. package/src/session-runtime/model-route/set-route.mjs +114 -34
  321. package/src/session-runtime/model-route/web-search-route.mjs +7 -2
  322. package/src/session-runtime/model-route-api.mjs +4 -2
  323. package/src/session-runtime/native-web-search/routes.mjs +37 -24
  324. package/src/session-runtime/native-web-search.mjs +9 -8
  325. package/src/session-runtime/provider-auth/setup.mjs +4 -0
  326. package/src/session-runtime/provider-models/catalog-load.mjs +9 -0
  327. package/src/session-runtime/provider-models/web-search-catalog.mjs +23 -3
  328. package/src/session-runtime/provider-models.mjs +1 -0
  329. package/src/session-runtime/provider-usage.mjs +4 -0
  330. package/src/session-runtime/route-resolution.mjs +3 -1
  331. package/src/session-runtime/runtime-core.mjs +4 -0
  332. package/src/session-runtime/runtime-facade.mjs +6 -0
  333. package/src/session-runtime/services/agent-task-status.mjs +2 -0
  334. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +0 -3
  335. package/src/session-runtime/services/agent-tool/close-flow.mjs +6 -7
  336. package/src/session-runtime/services/agent-tool/execute-send.mjs +2 -2
  337. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +36 -3
  338. package/src/session-runtime/services/agent-tool/execute.mjs +9 -1
  339. package/src/session-runtime/services/agent-tool/helpers.mjs +30 -7
  340. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +7 -2
  341. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +6 -3
  342. package/src/session-runtime/services/agent-tool/lead-worker-index/lead-rows.mjs +3 -4
  343. package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +9 -3
  344. package/src/session-runtime/services/agent-tool/lead-worker-index/row-settlement.mjs +7 -18
  345. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +9 -6
  346. package/src/session-runtime/services/agent-tool/model-select.mjs +82 -0
  347. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -6
  348. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -1
  349. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -5
  350. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -4
  351. package/src/session-runtime/services/agent-tool/spawn-flow.mjs +2 -1
  352. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  353. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +1 -3
  354. package/src/session-runtime/services/agent-tool/tag-registry/tag-refresh.mjs +1 -3
  355. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -9
  356. package/src/session-runtime/services/agent-tool/terminal-reaper/scan-admission.mjs +8 -41
  357. package/src/session-runtime/services/agent-tool/terminal-reaper/stale-rows.mjs +3 -3
  358. package/src/session-runtime/services/agent-tool/terminal-reaper.mjs +6 -23
  359. package/src/session-runtime/services/agent-tool/terminal-trace.mjs +0 -1
  360. package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
  361. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +32 -20
  362. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -2
  363. package/src/session-runtime/services/agent-tool/worker-index.mjs +28 -8
  364. package/src/session-runtime/services/agent-tool.mjs +4 -0
  365. package/src/session-runtime/services/agent-watchdog-registry.mjs +2 -0
  366. package/src/session-runtime/services/provider-admin.mjs +77 -0
  367. package/src/session-runtime/session-create/session-options.mjs +7 -5
  368. package/src/session-runtime/session-create/session-start-hook.mjs +2 -1
  369. package/src/session-runtime/session-transcript.mjs +4 -5
  370. package/src/session-runtime/session-turn-api.mjs +3 -9
  371. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -6
  372. package/src/session-runtime/setup-tool/executor.mjs +23 -5
  373. package/src/session-runtime/setup-tool/extended-actions.mjs +6 -6
  374. package/src/session-runtime/setup-tool/settings-contract.mjs +7 -2
  375. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -1
  376. package/src/session-runtime/tool-policy-refresh.mjs +83 -32
  377. package/src/session-runtime/turn/agent-ops.mjs +49 -2
  378. package/src/session-runtime/turn/side-question-ops.mjs +1 -4
  379. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +2 -0
  380. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +4 -0
  381. package/src/session-runtime/turn/turn-run/turn-settle.mjs +8 -2
  382. package/src/session-runtime/turn/turn-run.mjs +1 -36
  383. package/src/session-runtime/usage-stats-api.mjs +4 -1
  384. package/src/session-runtime/workflow-agents-api/agent-route.mjs +16 -1
  385. package/src/session-runtime/workspace/admission-gate.mjs +44 -15
  386. package/src/session-runtime/workspace/project-branches.mjs +28 -36
  387. package/src/session-runtime/workspace/transition-steps.mjs +96 -95
  388. package/src/session-runtime/workspace/transitions.mjs +248 -68
  389. package/src/standalone/channel-transport.mjs +3 -4
  390. package/src/standalone/daemon-desktop-runtime.mjs +32 -1
  391. package/src/standalone/daemon-pg-stop.mjs +1 -3
  392. package/src/standalone/daemon-session-control.mjs +88 -0
  393. package/src/standalone/daemon-stored-session-views.mjs +23 -3
  394. package/src/standalone/daemon.mjs +2 -0
  395. package/src/standalone/desktop-service-registry.mjs +32 -5
  396. package/src/standalone/local-session-runtime.mjs +11 -12
  397. package/src/standalone/session-protocol.mjs +7 -0
  398. package/src/standalone/session-runtime-inline-host.mjs +2 -0
  399. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +91 -49
  400. package/src/standalone/session-service/agent-tree/agent-child.mjs +19 -1
  401. package/src/standalone/session-service/agent-tree/agent-registry.mjs +25 -0
  402. package/src/standalone/session-service/agent-tree/agent-turns.mjs +9 -1
  403. package/src/standalone/session-service/agent-tree.mjs +28 -2
  404. package/src/standalone/session-service/entries/session-loads.mjs +16 -5
  405. package/src/standalone/session-service/entries.mjs +1 -0
  406. package/src/standalone/session-service/projection/transcript-window.mjs +39 -0
  407. package/src/standalone/session-service/quota-resume.mjs +28 -13
  408. package/src/standalone/session-service/session-calls/session-turns.mjs +17 -6
  409. package/src/standalone/session-service/session-calls/session-views.mjs +6 -0
  410. package/src/standalone/session-tool-output.mjs +82 -0
  411. package/src/tui/app/app-view.jsx +2 -1
  412. package/src/tui/app/provider-setup/provider-items.mjs +8 -0
  413. package/src/tui/app/provider-setup-picker.mjs +15 -3
  414. package/src/tui/app/slash-commands.mjs +6 -0
  415. package/src/tui/app/slash-dispatch/session-commands.mjs +49 -0
  416. package/src/tui/components/Spinner.jsx +4 -0
  417. package/src/tui/components/SpinnerByline.jsx +21 -2
  418. package/src/tui/components/status-line/local-line.mjs +10 -2
  419. package/src/tui/dist/index.mjs +529 -270
  420. package/src/tui/session/active-tool-summary.mjs +1 -1
  421. package/src/tui/session/context-state.mjs +0 -3
  422. package/src/tui/session/goal-continuation/continuation-queue.mjs +2 -3
  423. package/src/tui/session/goal-continuation/deadline-delivery.mjs +4 -2
  424. package/src/tui/session/goal-continuation/session-boundary.mjs +21 -0
  425. package/src/tui/session/quota-resume.mjs +140 -61
  426. package/src/tui/session/session-api/commands.mjs +4 -10
  427. package/src/tui/session/session-api/controls.mjs +12 -0
  428. package/src/tui/session/session-api/lifecycle/dispose.mjs +2 -9
  429. package/src/tui/session/session-api/lifecycle/resume.mjs +2 -7
  430. package/src/tui/session/session-api/lifecycle.mjs +13 -11
  431. package/src/tui/session/session-api/media.mjs +2 -0
  432. package/src/tui/session/session-api/routes.mjs +81 -57
  433. package/src/tui/session/session-api/settings.mjs +3 -3
  434. package/src/tui/session/session-api/worktree.mjs +3 -2
  435. package/src/tui/session/session-flow/auto-clear.mjs +1 -3
  436. package/src/tui/session/session-flow/drain.mjs +6 -4
  437. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -0
  438. package/src/tui/session/session-flow/queue/take-entries.mjs +2 -1
  439. package/src/tui/session/session-flow/queue.mjs +1 -1
  440. package/src/tui/session/tool-approval.mjs +17 -8
  441. package/src/tui/session/transcript-store/streaming-tail.mjs +1 -1
  442. package/src/tui/session/tui-steering-persist.mjs +3 -5
  443. package/src/tui/session/turn-quiet.mjs +53 -0
  444. package/src/tui/session/turn-stream.mjs +5 -1
  445. package/src/tui/session/turn.mjs +38 -31
  446. package/src/tui/session/worktree-setup-notice.mjs +38 -0
  447. package/src/tui/spinner-meta.mjs +10 -0
  448. package/src/tui/spinner-verbs.mjs +3 -0
  449. package/src/ui/statusline.mjs +13 -3
  450. package/src/ui/streaming-markdown-heal.mjs +70 -18
  451. package/src/runtime/agent/orchestrator/providers/model-pricing-rates.mjs +0 -1
  452. package/src/runtime/agent/orchestrator/session/manager/foreign-pending-messages.mjs +0 -346
  453. package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +0 -117
  454. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +0 -302
  455. package/src/session-runtime/services/agent-tool/terminal-reaper/reap-timers.mjs +0 -142
  456. package/src/session-runtime/turn/share-ops.mjs +0 -77
  457. package/src/tui/session/cross-surface-share.mjs +0 -406
  458. package/src/tui/session/live-share/delta.mjs +0 -153
  459. package/src/tui/session/live-share/mirror.mjs +0 -106
  460. package/src/tui/session/live-share/owner.mjs +0 -254
  461. package/src/tui/session/live-share/retry.mjs +0 -54
  462. package/src/tui/session/live-share/viewer/frame-router.mjs +0 -32
  463. package/src/tui/session/live-share/viewer/pipe-client.mjs +0 -108
  464. package/src/tui/session/live-share/viewer/submit-acks.mjs +0 -65
  465. package/src/tui/session/live-share/viewer/sync-waiters.mjs +0 -53
  466. package/src/tui/session/live-share/viewer.mjs +0 -99
  467. package/src/tui/session/live-share/wire.mjs +0 -44
  468. package/src/tui/session/live-share.mjs +0 -154
  469. package/src/tui/session/shared-dir-watch.mjs +0 -69
@@ -4,17 +4,23 @@
4
4
  // updated policy.
5
5
  import { sessionHasConversationMessages } from '../runtime/agent/orchestrator/runtime-core/session-text.mjs';
6
6
  import { toSessionWorkflowMeta } from '../runtime/agent/orchestrator/runtime-core/workflow.mjs';
7
- import { applyDeferredToolSurface, filterDisallowedTools } from '../runtime/agent/orchestrator/runtime-core/tool-catalog.mjs';
7
+ import {
8
+ applyDeferredToolSurface,
9
+ filterDisallowedTools,
10
+ } from '../runtime/agent/orchestrator/runtime-core/tool-catalog.mjs';
8
11
  import { deferredSurfaceModeForLead } from '../runtime/agent/orchestrator/runtime-core/effort.mjs';
9
12
  import {
10
13
  applyInitialDeferredToolManifestToBp2,
11
14
  composeSystemPrompt,
12
15
  } from '../runtime/agent/orchestrator/context/collect.mjs';
16
+ import { _buildBaseRules } from '../runtime/agent/orchestrator/session/manager/rules-cache.mjs';
17
+ import { sessionRolePromptFields } from '../runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs';
13
18
  import {
14
- _buildBaseRules,
15
- _buildLeadRules,
16
- _buildLeadLanguageContext,
17
- } from '../runtime/agent/orchestrator/session/manager/rules-cache.mjs';
19
+ delegationDisabled,
20
+ honoredSchemaAllowlist,
21
+ } from '../runtime/agent/orchestrator/session/manager/session-tool-surface.mjs';
22
+ import { finalizeSessionToolList } from '../runtime/agent/orchestrator/session/manager/tool-resolution.mjs';
23
+ import { isAgentOwner } from '../runtime/agent/orchestrator/agent-owner.mjs';
18
24
  import { unusedModelEditToolName } from '../runtime/shared/edit-tool-dialect.mjs';
19
25
 
20
26
  function toolNames(list) {
@@ -69,6 +75,7 @@ export function createToolPolicyRefresh({
69
75
  getMode,
70
76
  getConfig,
71
77
  getDataDir,
78
+ getActiveTurnCount,
72
79
  modelStandaloneTools,
73
80
  featureDisallowedTools,
74
81
  loadCoreMemoryContext,
@@ -78,13 +85,23 @@ export function createToolPolicyRefresh({
78
85
  }) {
79
86
  // Denied tools leave every surface, then the deferred surface is rebuilt
80
87
  // for the lead's current mode.
81
- function applyToolDenials(session, denied) {
88
+ function applyToolDenials(session, denied, schemaAllowedTools, ownerIsAgent) {
82
89
  session.disallowedTools = denied;
83
90
  session.tools = filterDisallowedTools(session.tools, denied);
84
91
  if (Array.isArray(session.deferredToolCatalog)) {
85
92
  session.deferredToolCatalog = filterDisallowedTools(session.deferredToolCatalog, denied);
86
93
  }
87
- applyDeferredToolSurface(session, deferredSurfaceModeForLead(getMode()), modelStandaloneTools(), {
94
+ const catalogTools = finalizeSessionToolList(modelStandaloneTools(), {
95
+ schemaAllowedTools,
96
+ disallowedTools: denied,
97
+ ownerIsAgent,
98
+ });
99
+ session.tools = finalizeSessionToolList(session.tools, {
100
+ schemaAllowedTools,
101
+ disallowedTools: denied,
102
+ ownerIsAgent,
103
+ });
104
+ applyDeferredToolSurface(session, deferredSurfaceModeForLead(getMode()), catalogTools, {
88
105
  provider: getRoute()?.provider,
89
106
  });
90
107
  const catalog = Array.isArray(session.deferredToolCatalog) ? session.deferredToolCatalog : [];
@@ -101,16 +118,40 @@ export function createToolPolicyRefresh({
101
118
  }
102
119
  }
103
120
 
121
+ // A turn is executing from the moment it opens until it settles, even when
122
+ // its transcript holds only notifications (which are not conversation
123
+ // content). Its tool surface is frozen for that whole span.
124
+ function turnInFlight(session) {
125
+ return (getActiveTurnCount?.() || 0) > 0 || Array.isArray(session.liveTurnMessages);
126
+ }
127
+
128
+ // Admission: the session is still the current one, no turn is executing and
129
+ // no conversation has started. Checked before staging and again right
130
+ // before the staged change is applied.
131
+ function admitsRefresh(session) {
132
+ return (
133
+ getSession?.() === session &&
134
+ !turnInFlight(session) &&
135
+ !sessionHasConversationMessages(session) &&
136
+ !sessionHasConversationMessages({ messages: session.liveTurnMessages })
137
+ );
138
+ }
139
+
104
140
  async function refreshEmptySessionToolPolicy() {
105
141
  invalidatePreSessionToolSurface?.();
106
142
  const session = getSession?.();
107
143
  if (!session?.id) return { appliedToCurrentSession: true };
108
- if (
109
- sessionHasConversationMessages(session) ||
110
- sessionHasConversationMessages({ messages: session.liveTurnMessages })
111
- ) {
112
- return { appliedToCurrentSession: false };
113
- }
144
+ if (!admitsRefresh(session)) return { appliedToCurrentSession: false };
145
+ // Older records contain only compiled prompt text; rebuilding would guess
146
+ // away custom instructions. Keep that immutable material for every owner.
147
+ const identity = session.promptIdentity;
148
+ if (!identity) return { appliedToCurrentSession: false, reason: 'missing-prompt-identity' };
149
+ const ownerIsAgent = isAgentOwner(session);
150
+ const schemaAllowedTools = honoredSchemaAllowlist(session.schemaAllowedTools, {
151
+ ownerIsAgent,
152
+ agent: identity.agent,
153
+ });
154
+ const toolFreeRole = ownerIsAgent && schemaAllowedTools?.length === 0;
114
155
 
115
156
  const {
116
157
  summary: workflow,
@@ -118,34 +159,44 @@ export function createToolPolicyRefresh({
118
159
  packContext,
119
160
  orchestrationMode,
120
161
  } = activeWorkflowContext(getConfig(), getDataDir());
121
- const workflowContext = session.owner === 'agent' ? packContext : leadWorkflowContext;
122
- const denied = [...featureDisallowedTools(), ...(workflow?.delegatesAgents === false ? ['agent'] : [])]
162
+ const workflowContext = ownerIsAgent ? packContext : leadWorkflowContext;
163
+ const denied = [
164
+ ...session.callerDisallowedTools,
165
+ ...featureDisallowedTools(),
166
+ ...(workflow?.delegatesAgents === false ? ['agent'] : []),
167
+ ]
123
168
  .map((name) => String(name || ''))
124
169
  .filter(Boolean);
125
- session.workflow = toSessionWorkflowMeta(workflow);
126
- session.orchestrationMode = orchestrationMode;
127
- applyToolDenials(session, denied);
128
170
 
129
- const allowsAgents = workflow?.delegatesAgents !== false;
130
- const baseRules = _buildBaseRules({
131
- omitTools: [...denied, unusedModelEditToolName(getRoute()?.model)],
132
- allowTools: session.schemaAllowedTools,
133
- provider: getRoute()?.provider,
134
- model: getRoute()?.model,
135
- });
136
- const roleRules = _buildLeadRules({ includeLeadBrief: allowsAgents });
171
+ // Stage: everything below is computed without touching the session, so a
172
+ // turn that starts during the async rebuild cannot lose tools to it.
173
+ const baseRules =
174
+ identity.skipAgentRules || toolFreeRole
175
+ ? ''
176
+ : _buildBaseRules({
177
+ omitTools: [...denied, unusedModelEditToolName(getRoute()?.model)],
178
+ allowTools: schemaAllowedTools,
179
+ provider: getRoute()?.provider,
180
+ model: getRoute()?.model,
181
+ });
137
182
  const coreMemoryContext = await leadCoreMemoryContext();
138
183
  const { sessionMarkerCore } = composeSystemPrompt({
139
- roleRules,
140
- skipRoleCatalog: true,
184
+ ...sessionRolePromptFields(identity, {
185
+ ownerIsAgent,
186
+ toolFreeRole,
187
+ delegationFree: delegationDisabled(session, ownerIsAgent),
188
+ }),
189
+ provider: getRoute()?.provider,
141
190
  workflowContext,
142
191
  coreMemoryContext,
143
192
  // The rebuilt core keeps (or newly applies) the instruction-files setting.
144
- instructionFilesContext: loadInstructionFilesContext?.(session) || null,
145
- // BP3 rebuild must keep the trailing language block, or a workflow
146
- // switch would silently drop the response-language directive.
147
- languageContext: _buildLeadLanguageContext(),
193
+ instructionFilesContext: toolFreeRole ? null : loadInstructionFilesContext?.(session) || null,
148
194
  });
195
+ // Apply: re-check admission after the await, then mutate synchronously.
196
+ if (!admitsRefresh(session)) return { appliedToCurrentSession: false };
197
+ session.workflow = toSessionWorkflowMeta(workflow);
198
+ session.orchestrationMode = orchestrationMode;
199
+ applyToolDenials(session, denied, schemaAllowedTools, ownerIsAgent);
149
200
  rewriteSystemHeading(session, '# Tool Use', baseRules);
150
201
  rewriteBp3Core(session, sessionMarkerCore);
151
202
  session.updatedAt = Date.now();
@@ -3,7 +3,12 @@
3
3
  * runtime notifications, and the deferred tool surface (status + selection).
4
4
  */
5
5
  import { clean } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
6
- import { toolRow, toolSearchMatches, sortedNamesByMeasuredUsage, selectDeferredTools } from '../../runtime/agent/orchestrator/runtime-core/tool-catalog.mjs';
6
+ import {
7
+ toolRow,
8
+ toolSearchMatches,
9
+ sortedNamesByMeasuredUsage,
10
+ selectDeferredTools,
11
+ } from '../../runtime/agent/orchestrator/runtime-core/tool-catalog.mjs';
7
12
 
8
13
  function splitToolStatusCounts(rows) {
9
14
  const list = Array.isArray(rows) ? rows : [];
@@ -67,6 +72,39 @@ export function createAgentOps(deps) {
67
72
  });
68
73
  }
69
74
 
75
+ // Explicit user force-release ("Release anyway") of a shell job whose
76
+ // termination is unconfirmed: drops its workspace hold. The surface has
77
+ // already asked the user to confirm. The caller session's own holds, and
78
+ // holds of a closed session whose workspace this session's folder sees.
79
+ async function releaseShellJob(taskId) {
80
+ const session = getSession();
81
+ const { forceReleaseTerminationHold } = await import(
82
+ '../../runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs'
83
+ );
84
+ return forceReleaseTerminationHold(taskId, {
85
+ callerSessionId: session?.id || null,
86
+ callerCwd: getCurrentCwd?.() || null,
87
+ });
88
+ }
89
+
90
+ // This session's live shell jobs (the readout rows), each carrying
91
+ // `terminationUnconfirmed` when it is held without confirmed termination,
92
+ // plus held shells a closed session left in a workspace this session sees.
93
+ async function listShellJobs() {
94
+ const session = getSession();
95
+ const { shellJobsStatusFresh, shellJobVisibleFrom } = await import(
96
+ '../../runtime/shared/statusline/statusline-segments.mjs'
97
+ );
98
+ const status = await shellJobsStatusFresh({ clientHostPid: session?.clientHostPid || process.pid });
99
+ const own = session?.id ? status?.sessions?.[session.id]?.jobs : status?.jobs;
100
+ const jobs = Array.isArray(own) ? [...own] : [];
101
+ const cwd = getCurrentCwd?.() || null;
102
+ for (const job of status?.orphaned || []) {
103
+ if (shellJobVisibleFrom(job, cwd) && !jobs.some((row) => row.taskId === job.taskId)) jobs.push(job);
104
+ }
105
+ return { jobs };
106
+ }
107
+
70
108
  function onNotification(listener) {
71
109
  if (typeof listener !== 'function') return () => {};
72
110
  const sessionId = getSession()?.id || getReservedSessionId?.() || '';
@@ -105,5 +143,14 @@ export function createAgentOps(deps) {
105
143
  return { ...result, status: toolsStatus() };
106
144
  }
107
145
 
108
- return { agentControl, taskControl, stopShellJob, onNotification, toolsStatus, selectTools };
146
+ return {
147
+ agentControl,
148
+ taskControl,
149
+ stopShellJob,
150
+ releaseShellJob,
151
+ listShellJobs,
152
+ onNotification,
153
+ toolsStatus,
154
+ selectTools,
155
+ };
109
156
  }
@@ -3,10 +3,7 @@
3
3
  * runtime's current session. They run beside an in-progress turn and touch no
4
4
  * session state (see orchestrator/session/side-question.mjs).
5
5
  */
6
- import {
7
- askSideQuestion,
8
- cancelSideQuestion,
9
- } from '../../runtime/agent/orchestrator/session/side-question.mjs';
6
+ import { askSideQuestion, cancelSideQuestion } from '../../runtime/agent/orchestrator/session/side-question.mjs';
10
7
 
11
8
  export function createSideQuestionOps({ getSession, getReservedSessionId }) {
12
9
  const sessionId = () => getSession()?.id || getReservedSessionId?.() || '';
@@ -75,6 +75,8 @@ export function createAskCallbacks({ transcript, notifyFnForSession, scheduleSea
75
75
  transcriptMeta: stampCheckpoint(options),
76
76
  promptSource: options.promptSource,
77
77
  retryFailedTurn: options.retryFailedTurn === true,
78
+ retryTurnId: options.retryTurnId,
79
+ retryAttemptId: options.retryAttemptId,
78
80
  onTextDelta: options.onTextDelta,
79
81
  onTextReset: options.onTextReset,
80
82
  onReasoningDelta: options.onReasoningDelta,
@@ -23,6 +23,7 @@ export function createTurnPreparation({
23
23
  assertSessionAdmission,
24
24
  prepareTurnWorkspace,
25
25
  admitTurnWorkspace,
26
+ applyPendingRoute,
26
27
  }) {
27
28
  const scopedMcpTools = (session) => scopedMcpToolsFor(session, getConfig());
28
29
 
@@ -129,6 +130,9 @@ export function createTurnPreparation({
129
130
  throwIfAborted(turn.signal);
130
131
  assertSessionAdmission?.();
131
132
  }
133
+ const modelSwitch = applyPendingRoute?.();
134
+ options.onRouteApplied?.(getSession());
135
+ if (modelSwitch) options.onModelSwitch?.(modelSwitch);
132
136
  ensureSessionTranscriptWriter?.();
133
137
  transcript.appendUser(prompt);
134
138
  const session0 = getSession();
@@ -86,11 +86,16 @@ export function createTurnSettlement({
86
86
  turn.releaseFirstTitle?.();
87
87
  turn.emitTiming(turn.timing.status);
88
88
  turn.armHeavyRuntimeWarmup('turn-settled');
89
+ let settleError;
89
90
  try {
90
91
  await turn.snapshot.finish(turn.signal, turn.awaitTurn);
91
- } finally {
92
- // The turn no longer works in its checkout: transitions may proceed.
92
+ } catch (error) {
93
+ settleError = error;
94
+ }
95
+ try {
93
96
  turn.releaseWorkspace?.();
97
+ } catch (error) {
98
+ settleError = settleError ? new AggregateError([settleError, error], 'Turn cleanup failed.') : error;
94
99
  }
95
100
  try {
96
101
  turn.unregister?.();
@@ -101,6 +106,7 @@ export function createTurnSettlement({
101
106
  /* lead pool must never break turn teardown */
102
107
  }
103
108
  setActiveTurnCount(Math.max(0, getActiveTurnCount() - 1));
109
+ if (settleError) throw settleError;
104
110
  // A compaction the model scheduled (session tool) runs once the turn is over.
105
111
  // Only while the settled session is still the live one; otherwise it stays
106
112
  // pending for that session and never compacts another. The runner chains
@@ -1,6 +1,5 @@
1
1
  /**
2
- * src/session-runtime/turn/turn-run.mjs - one user turn end to end: viewer
3
- * forwarding, turn open (abort controller, timing, warmup arming), session
2
+ * src/session-runtime/turn/turn-run.mjs - one user turn end to end: turn open (abort controller, timing, warmup arming), session
4
3
  * preparation (workspace provisioning, then the worktree review snapshot), the
5
4
  * askSession callback bridge, and the settlement that always runs. The phases
6
5
  * live under turn-run/.
@@ -49,18 +48,6 @@ export function createTurnRunner(deps) {
49
48
  deferComputerSessionRelease,
50
49
  });
51
50
 
52
- const enqueueRemoteAttachedPrompt = (prompt) => {
53
- const attachedSession = getSession();
54
- if (!attachedSession?.remoteAttached || !attachedSession.id) return false;
55
- try {
56
- // prompt may be a string or { content/text, id } so the submission id
57
- // survives spool fallback after a live-share ack miss.
58
- return Number(mgr.enqueueRemotePendingMessage?.(attachedSession.id, prompt)) > 0;
59
- } catch {
60
- return false;
61
- }
62
- };
63
-
64
51
  function getTurnLiveness() {
65
52
  const sessionId = getSession()?.id;
66
53
  if (!sessionId || typeof mgr.getSessionProgressSnapshot !== 'function') return null;
@@ -69,28 +56,7 @@ export function createTurnRunner(deps) {
69
56
  return { ...snapshot };
70
57
  }
71
58
 
72
- // Remote-attach: this surface is a viewer on a session that another live
73
- // process owns. Never run a turn here — persist the prompt into the shared
74
- // pending spool; the owner's injection poller submits it as a normal user
75
- // turn and this surface refreshes from disk.
76
- function forwardAttachedPrompt(attachedSession, prompt, options) {
77
- // Carry the submission id into the spool: the owner reuses it for the
78
- // queue entry and the settled user row, so the submitting surface's
79
- // optimistic bubble is reconciled with the mirrored row.
80
- const submissionId = String(options.id || '').trim();
81
- const delivered = enqueueRemoteAttachedPrompt(submissionId ? { content: prompt, id: submissionId } : prompt);
82
- return {
83
- // This branch is only a race-safe fallback for callers that reached
84
- // ask() before the live pipe was ready. Never manufacture an
85
- // assistant response: the owner's mirrored transcript is authoritative.
86
- result: { content: '', remoteAttached: true, delivered },
87
- session: attachedSession,
88
- };
89
- }
90
-
91
59
  async function runTurn(prompt, options) {
92
- const attachedSession = getSession();
93
- if (attachedSession?.remoteAttached) return forwardAttachedPrompt(attachedSession, prompt, options);
94
60
  const turn = openTurn(options);
95
61
  try {
96
62
  const session0 = await prepareSession(turn, prompt, options);
@@ -129,7 +95,6 @@ export function createTurnRunner(deps) {
129
95
  }
130
96
 
131
97
  return {
132
- enqueueRemoteAttachedPrompt,
133
98
  getTurnLiveness,
134
99
  ask: (prompt, options = {}) => runWithCwdOverride(getCurrentCwd(), () => runTurn(prompt, options)),
135
100
  };
@@ -251,7 +251,10 @@ export function createUsageStatsApi({
251
251
  const others = otherSessionIds(options, sessionId);
252
252
  if (!others.length) return result;
253
253
  const totals = await Promise.all(
254
- others.map(async (id) => [id, sessionUsageSnapshot(await store.sessionUsageAsync(sessionUsageIdsFor(scopes, id)))])
254
+ others.map(async (id) => [
255
+ id,
256
+ sessionUsageSnapshot(await store.sessionUsageAsync(sessionUsageIdsFor(scopes, id))),
257
+ ])
255
258
  );
256
259
  return { ...result, sessions: Object.fromEntries(totals) };
257
260
  },
@@ -6,6 +6,7 @@ import { ensureProviderEnabled } from '../../runtime/agent/orchestrator/runtime-
6
6
  import { resolveRouteContextState, selectionFastCapable } from '../route-state.mjs';
7
7
  import { canonicalizeAgentRouteStorage, withAgentDisabled } from '../../runtime/shared/agent-route-config.mjs';
8
8
  import { agentEditorId } from './shared.mjs';
9
+ import { routeChain, validateRouteChainProviders } from '../../runtime/shared/model-route-chain.mjs';
9
10
 
10
11
  // Agent route persistence. Route-scope isolation: an agent route owns its
11
12
  // model AND its effort/fast, stored in config.agents[<id>]. The shared
@@ -109,7 +110,21 @@ export function createAgentRouteApi(deps) {
109
110
  }
110
111
  if (!clean(requested.provider)) return clearOverride(id);
111
112
  if (!clean(requested.model)) throw new Error('agent route requires provider and model');
112
- const routeToSave = normalizeWorkflowRoute(await resolveSelectedRoute(requested, stored));
113
+ const chain = routeChain({
114
+ ...requested,
115
+ fallbacks: hasOwn(requested, 'fallbacks') ? requested.fallbacks : stored.fallbacks,
116
+ });
117
+ validateRouteChainProviders(chain);
118
+ const storedChain = routeChain(stored);
119
+ const resolved = [];
120
+ for (const entry of chain) {
121
+ const previous = storedChain.find(
122
+ (candidate) => candidate.provider === entry.provider && candidate.model === entry.model
123
+ );
124
+ resolved.push(await resolveSelectedRoute(entry, previous || {}));
125
+ }
126
+ const [primary, ...fallbacks] = resolved;
127
+ const routeToSave = normalizeWorkflowRoute({ ...primary, fallbacks });
113
128
  if (!routeToSave) throw new Error('agent route requires provider and model');
114
129
  // Picking a model is also the "on" switch unless the request keeps it off.
115
130
  const nextConfig = withAgentDisabled(getConfig(), id, keepOff);
@@ -13,9 +13,11 @@
13
13
  * - Each worktree-bound Lead's execution root, which every worker of that Lead
14
14
  * runs in.
15
15
  */
16
- import { worktreeError } from '../../runtime/shared/worktrees/contract.mjs';
16
+ import { worktreeError, worktreeRefusal } from '../../runtime/shared/worktrees/contract.mjs';
17
17
  import { throwIfAborted } from '../../runtime/shared/worktrees/git.mjs';
18
18
  import { isWithin } from '../../runtime/shared/worktrees/paths.mjs';
19
+ import { tryAdmitWorkspaceActivity } from '../../runtime/shared/worktrees/activity-gate.mjs';
20
+ import { setTimeout as delay } from 'node:timers/promises';
19
21
 
20
22
  /** @type {Map<string, { txId: string, settled: Promise<void> }>} Lead session id → in-flight transition. */
21
23
  const transitions = new Map();
@@ -42,8 +44,8 @@ function once(fn) {
42
44
  let done = false;
43
45
  return () => {
44
46
  if (done) return;
45
- done = true;
46
47
  fn();
48
+ done = true;
47
49
  };
48
50
  }
49
51
 
@@ -78,21 +80,18 @@ export function beginWorkspaceTransition(sessionId, txId) {
78
80
  * admitted turn runs inside it, and (`transition`) while another change holds
79
81
  * an overlapping checkout; turns arriving meanwhile wait (admitTurn). The
80
82
  * holder's own turns are its own business (the Lead busy check).
83
+ * `hold: false` (an external checkout, never lock-blocked) only refuses.
81
84
  * @param {string|null} sessionId The changing session; '' / null for a session-less change.
82
85
  * @returns {() => void} Release.
83
86
  */
84
- export function holdCheckoutFolder(sessionId, folder) {
87
+ export function holdCheckoutFolder(sessionId, folder, { hold = true } = {}) {
85
88
  const id = key(sessionId);
86
89
  const users = new Set();
87
90
  for (const turn of turns.values()) {
88
91
  if (turn.sessionId !== id && within(folder, turn.cwd())) users.add(turn.sessionId);
89
92
  }
90
- if (users.size) {
91
- throw worktreeError('WORKTREE_BUSY_JOBS', 'Other sessions are working in the project folder.', {
92
- reason: 'folder-in-use',
93
- sessions: [...users],
94
- });
95
- }
93
+ if (users.size) throw worktreeRefusal('folder-in-use', { sessions: [...users] });
94
+ if (!hold) return () => {};
96
95
  if ([...folderHolds.values()].some((hold) => within(hold.folder, folder) || within(folder, hold.folder))) {
97
96
  throw worktreeError('WORKTREE_BUSY_JOBS', 'Another branch change is in progress in the project folder.', {
98
97
  reason: 'transition',
@@ -145,14 +144,44 @@ function settledOrAborted(promise, signal) {
145
144
  */
146
145
  export async function admitTurn({ sessionId, cwd, signal }) {
147
146
  const id = key(sessionId);
148
- for (let blocker = admissionBlocker(id, cwd); blocker; blocker = admissionBlocker(id, cwd)) {
147
+ for (;;) {
149
148
  throwIfAborted(signal);
150
- await settledOrAborted(blocker, signal);
149
+ const blocker = admissionBlocker(id, cwd);
150
+ if (blocker) {
151
+ await settledOrAborted(blocker, signal);
152
+ continue;
153
+ }
154
+ const release = tryAdmitWorkspaceActivity(id, cwd());
155
+ if (!release) {
156
+ await delay(100, undefined, { signal });
157
+ continue;
158
+ }
159
+ const token = Symbol('turn');
160
+ const leases = [release];
161
+ turns.set(token, { sessionId: id, cwd, leases });
162
+ return once(() => {
163
+ const errors = [];
164
+ for (const leave of leases) {
165
+ try {
166
+ leave();
167
+ } catch (error) {
168
+ errors.push(error);
169
+ }
170
+ }
171
+ turns.delete(token);
172
+ if (errors.length) throw new AggregateError(errors, 'Workspace admission could not be released.');
173
+ });
174
+ }
175
+ }
176
+
177
+ /** Keep the old root protected and acquire the destination before an admitted turn moves. */
178
+ export function retainAdmittedTurnWorkspace(sessionId, cwd) {
179
+ for (const turn of turns.values()) {
180
+ if (turn.sessionId !== key(sessionId) || turn.cwd() === cwd) continue;
181
+ const leave = tryAdmitWorkspaceActivity(sessionId, cwd);
182
+ if (!leave) throw worktreeRefusal('folder-in-use');
183
+ turn.leases.push(leave);
151
184
  }
152
- throwIfAborted(signal);
153
- const token = Symbol('turn');
154
- turns.set(token, { sessionId: id, cwd });
155
- return once(() => turns.delete(token));
156
185
  }
157
186
 
158
187
  /**
@@ -2,42 +2,32 @@
2
2
  * Session-less branch operations on a registered Project's folder (a New
3
3
  * Task draft, the source-control dock): its branch menu, a guarded checkout
4
4
  * and a guarded merge. They act only on a registered Project (a repository
5
- * subfolder Project included) and hold the checkout (withProjectFolder) while
6
- * git changes it.
5
+ * subfolder Project included): a checkout holds the folder (withProjectFolder)
6
+ * while git changes it, a merge takes the shared management path.
7
7
  */
8
8
  import { branchMenuEntries, projectWorkspace, worktreeError } from '../../runtime/shared/worktrees/contract.mjs';
9
+ import * as branchManagement from '../../runtime/shared/worktrees/branch-management.mjs';
9
10
 
10
11
  function requireText(value, name) {
11
12
  if (typeof value !== 'string' || !value.trim()) throw new TypeError(`${name} must be a non-empty string.`);
12
13
  return value.trim();
13
14
  }
14
15
 
15
- /**
16
- * WORKTREE_UNSUPPORTED_REPO when the project folder has no checked-out branch
17
- * to merge into; WORKTREE_TARGET_MISMATCH when the confirmed `target` (null:
18
- * none confirmed) is no longer the checked-out branch.
19
- */
20
- export function assertMergeTarget(currentBranch, target) {
21
- if (!currentBranch) {
22
- throw worktreeError('WORKTREE_UNSUPPORTED_REPO', 'The project folder has no checked-out branch to merge into.');
23
- }
24
- if (target !== null && target !== currentBranch) {
25
- throw worktreeError(
26
- 'WORKTREE_TARGET_MISMATCH',
27
- `The project folder is now on "${currentBranch}"; confirm the merge again.`,
28
- { target, current: currentBranch }
29
- );
30
- }
31
- }
32
-
33
16
  /**
34
17
  * @param {object} deps
35
18
  * @param {() => Promise<any>} deps.backend The managed-worktree backend.
36
19
  * @param {(path: string) => Promise<any>} deps.inspectProject
37
20
  * @param {(path: string) => Promise<string|null>} deps.findRegisteredProject
38
21
  * @param {<T>(sessionId: string|null, folder: string, fn: () => Promise<T>) => Promise<T>} deps.withProjectFolder
22
+ * @param {Function} deps.withManagementFolders The shared admission of every merge and cleanup.
39
23
  */
40
- export function createProjectBranchOps({ backend, inspectProject, findRegisteredProject, withProjectFolder }) {
24
+ export function createProjectBranchOps({
25
+ backend,
26
+ inspectProject,
27
+ findRegisteredProject,
28
+ withProjectFolder,
29
+ withManagementFolders,
30
+ }) {
41
31
  /** WORKTREE_PROJECT_UNKNOWN unless `projectPath` is a registered Project. */
42
32
  async function registeredProject(projectPath) {
43
33
  const path = requireText(projectPath, 'projectPath');
@@ -114,25 +104,27 @@ export function createProjectBranchOps({ backend, inspectProject, findRegistered
114
104
  /**
115
105
  * Merge a local branch into a Project folder's checked-out branch with no
116
106
  * session: `target` is the branch the user confirmed and must still be
117
- * checked out (WORKTREE_TARGET_MISMATCH); refused while another session
118
- * works in that checkout, which is held (turn admission waits) until the
119
- * merge is done.
107
+ * checked out (WORKTREE_TARGET_MISMATCH). The same guarded path as the
108
+ * branch-row merge (manageProjectBranch): source and destination validated
109
+ * and both folders held.
120
110
  */
121
111
  async function mergeProjectBranch({ projectPath, branch, target } = {}) {
122
112
  const path = await registeredProject(projectPath);
123
- const source = requireText(branch, 'branch');
124
- const confirmedTarget = requireText(target, 'target');
125
- const project = await inspectProject(path);
126
- assertMergeTarget(project.currentBranch, confirmedTarget);
127
- return withProjectFolder(null, project.topLevel || path, async () =>
128
- (await backend()).mergeBranchIntoProject({
129
- projectPath: path,
130
- source,
131
- target: confirmedTarget,
132
- confirmed: true,
133
- })
113
+ return branchManagement.mergeConfirmedTarget(
114
+ { projectPath: path, branch: requireText(branch, 'branch'), target: requireText(target, 'target') },
115
+ withManagementFolders
134
116
  );
135
117
  }
136
118
 
137
- return { getProjectBranchMenu, selectProjectBranch, mergeProjectBranch };
119
+ async function inspectProjectBranch({ projectPath, branch } = {}) {
120
+ const path = await registeredProject(projectPath);
121
+ return branchManagement.inspectProjectBranch({ projectPath: path, branch: requireText(branch, 'branch') });
122
+ }
123
+
124
+ async function manageProjectBranch(input = {}) {
125
+ const path = await registeredProject(input.projectPath);
126
+ return branchManagement.manageProjectBranch({ ...input, projectPath: path }, withManagementFolders);
127
+ }
128
+
129
+ return { getProjectBranchMenu, selectProjectBranch, mergeProjectBranch, inspectProjectBranch, manageProjectBranch };
138
130
  }