mixdog 1.2.2 → 1.2.4

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 (692) hide show
  1. package/README.md +18 -0
  2. package/package.json +2 -1
  3. package/scripts/gate-local.mjs +6 -4
  4. package/scripts/lib/gate-scheduler.mjs +29 -11
  5. package/scripts/probe-provider-catalog.mjs +31 -0
  6. package/scripts/provider-pingpong-live.mjs +599 -0
  7. package/scripts/session-sweep.mjs +5 -25
  8. package/src/agents/advisor/AGENT.md +1 -1
  9. package/src/agents/advisor/agent.json +1 -1
  10. package/src/agents/maintainer/AGENT.md +1 -1
  11. package/src/agents/maintainer/agent.json +1 -1
  12. package/src/agents/reviewer/AGENT.md +2 -4
  13. package/src/agents/security/AGENT.md +1 -2
  14. package/src/agents/writer/AGENT.md +2 -3
  15. package/src/defaults/shipped-history.json +11 -1
  16. package/src/defaults/skills/image/SKILL.md +21 -23
  17. package/src/defaults/skills/setup/SKILL.md +6 -1
  18. package/src/defaults/skills/setup/references/actions.md +44 -22
  19. package/src/defaults/skills/setup/references/surfaces.md +10 -8
  20. package/src/headless-exec.mjs +15 -8
  21. package/src/lib/keychain-cjs.cjs +20 -15
  22. package/src/output-styles/common.md +11 -10
  23. package/src/rules/agent/AGENT.md +6 -4
  24. package/src/rules/lead/LEAD.md +7 -9
  25. package/src/rules/shared/45-destructive.md +4 -0
  26. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  27. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +28 -7
  28. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -11
  29. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
  30. package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
  31. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
  32. package/src/runtime/agent/orchestrator/config.mjs +5 -0
  33. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
  34. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
  35. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
  36. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +101 -23
  37. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +2 -0
  38. package/src/runtime/agent/orchestrator/providers/anthropic-api-key-fetch.mjs +36 -0
  39. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
  40. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +3 -1
  41. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +24 -17
  42. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +9 -9
  43. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  44. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +26 -44
  45. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +31 -15
  46. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
  47. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
  48. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
  49. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
  50. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
  51. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
  52. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
  53. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -0
  54. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
  55. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +10 -0
  56. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +41 -12
  57. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +13 -1
  58. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +131 -9
  59. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +29 -10
  60. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +125 -8
  61. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +12 -62
  62. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +117 -41
  63. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  64. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +117 -72
  65. package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
  66. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +39 -5
  67. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  68. package/src/runtime/agent/orchestrator/providers/cursor-native-context.mjs +48 -0
  69. package/src/runtime/agent/orchestrator/providers/cursor-wire-exec.mjs +144 -34
  70. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +28 -4
  71. package/src/runtime/agent/orchestrator/providers/cursor-wire-request.mjs +8 -4
  72. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +42 -11
  73. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +109 -6
  74. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +17 -4
  75. package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -2
  76. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +73 -7
  77. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +75 -6
  78. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
  79. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
  80. package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
  81. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +29 -5
  82. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
  83. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +36 -13
  84. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +101 -11
  85. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
  86. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +1 -0
  87. package/src/runtime/agent/orchestrator/providers/gemini-rest-stream/watchdogs.mjs +16 -5
  88. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +19 -14
  89. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +371 -41
  90. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -2
  91. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +97 -49
  92. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +81 -10
  93. package/src/runtime/agent/orchestrator/providers/gemini.mjs +35 -8
  94. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  95. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +1 -0
  96. package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
  97. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
  98. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +253 -42
  99. package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
  100. package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
  101. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +392 -0
  102. package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
  103. package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
  104. package/src/runtime/agent/orchestrator/providers/lib/request-compression.mjs +86 -0
  105. package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
  106. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
  107. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +50 -22
  108. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +133 -21
  109. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
  110. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +7 -1
  111. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
  112. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  113. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +92 -16
  114. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -13
  115. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
  116. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +133 -62
  117. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
  118. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +5 -2
  119. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +39 -7
  120. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
  121. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +5 -0
  122. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +1 -1
  123. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +84 -2
  124. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
  125. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
  126. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +155 -0
  127. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +40 -24
  128. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +63 -25
  129. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
  130. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +183 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +87 -6
  132. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +51 -3
  133. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -1
  134. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
  135. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +103 -26
  136. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +23 -4
  137. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +11 -6
  138. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +17 -2
  139. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +15 -23
  140. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +64 -52
  141. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
  142. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +28 -5
  143. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
  144. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
  145. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +4 -0
  146. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +5 -0
  147. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
  148. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
  149. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +3 -1
  150. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +7 -0
  151. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +7 -1
  152. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +72 -24
  153. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
  154. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +50 -16
  155. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -19
  156. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
  157. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -36
  158. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
  159. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
  160. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
  161. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +18 -9
  162. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +181 -0
  163. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +78 -70
  164. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +74 -0
  165. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +150 -10
  166. package/src/runtime/agent/orchestrator/providers/registry.mjs +13 -2
  167. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +7 -1
  168. package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
  169. package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
  170. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +164 -0
  171. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +522 -0
  172. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
  173. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +195 -0
  174. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +104 -0
  175. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +8 -6
  176. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +24 -0
  177. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
  178. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +30 -2
  179. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +3 -2
  180. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -3
  181. package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
  182. package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
  183. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +16 -3
  184. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge-contract.mjs +6 -0
  185. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
  186. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  187. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
  188. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +178 -71
  189. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +102 -12
  190. package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
  191. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -8
  192. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -2
  193. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +24 -0
  194. package/src/runtime/agent/orchestrator/session/cache/tool-result-reuse.mjs +10 -2
  195. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -3
  196. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +5 -11
  197. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +6 -22
  198. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
  199. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +16 -93
  200. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +16 -2
  201. package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
  202. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +148 -0
  203. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  204. package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
  205. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
  206. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +0 -6
  207. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +0 -6
  208. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +3 -2
  209. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
  210. package/src/runtime/agent/orchestrator/session/historical-session-closure.mjs +10 -0
  211. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +2 -5
  212. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +89 -1
  213. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
  214. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
  215. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
  216. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -27
  217. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +1 -1
  218. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -10
  219. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -9
  220. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +24 -10
  221. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +135 -0
  222. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +31 -4
  223. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +76 -0
  224. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +67 -20
  225. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +10 -10
  226. package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
  227. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +6 -0
  228. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
  229. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +29 -5
  230. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  231. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +147 -0
  232. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +7 -5
  233. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +33 -3
  234. package/src/runtime/agent/orchestrator/session/manager/ask-support.mjs +0 -4
  235. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +23 -2
  236. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
  237. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +54 -13
  238. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +33 -0
  239. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
  240. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +11 -0
  241. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +22 -0
  242. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +57 -13
  243. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
  244. package/src/runtime/agent/orchestrator/session/manager/failed-turn-rewind.mjs +16 -0
  245. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +6 -120
  246. package/src/runtime/agent/orchestrator/session/manager/pending-persist-queue.mjs +1 -1
  247. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +231 -16
  248. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +42 -49
  249. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +50 -0
  250. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +47 -17
  251. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +26 -4
  252. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
  253. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +36 -35
  254. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +29 -13
  255. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +6 -3
  256. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
  257. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +45 -0
  258. package/src/runtime/agent/orchestrator/session/manager.mjs +4 -10
  259. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
  260. package/src/runtime/agent/orchestrator/session/send-instrumentation.mjs +2 -1
  261. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +17 -1
  262. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
  263. package/src/runtime/agent/orchestrator/session/side-question.mjs +197 -0
  264. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +22 -15
  265. package/src/runtime/agent/orchestrator/session/store/lifecycle-read.mjs +1 -1
  266. package/src/runtime/agent/orchestrator/session/store/listing.mjs +2 -6
  267. package/src/runtime/agent/orchestrator/session/store/live-cache-eviction.mjs +1 -1
  268. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
  269. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +46 -37
  270. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +1 -1
  271. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +1 -1
  272. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +44 -37
  273. package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
  274. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +59 -0
  275. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +1 -1
  276. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +1 -1
  277. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +27 -21
  278. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +0 -8
  279. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +6 -18
  280. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +33 -106
  281. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +4 -2
  282. package/src/runtime/agent/orchestrator/session/store-agent-worker-pool.mjs +5 -8
  283. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +136 -196
  284. package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
  285. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +53 -115
  286. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +8 -0
  287. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +10 -1
  288. package/src/runtime/agent/orchestrator/session/store-summary-locations.mjs +3 -29
  289. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +1 -1
  290. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +17 -10
  291. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +9 -20
  292. package/src/runtime/agent/orchestrator/session/store.mjs +22 -19
  293. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +12 -12
  294. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +38 -14
  295. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +15 -4
  296. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
  297. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
  298. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
  299. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +79 -0
  300. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +72 -15
  301. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +45 -0
  302. package/src/runtime/agent/orchestrator/stall-policy.mjs +50 -0
  303. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
  304. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
  305. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +5 -1
  306. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +6 -2
  307. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
  308. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +218 -20
  309. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +160 -39
  310. package/src/runtime/agent/orchestrator/tools/builtin/git-partial-stage.mjs +7 -5
  311. package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +14 -5
  312. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +4 -3
  313. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +2 -1
  314. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-path-fanout.mjs +48 -44
  315. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +10 -3
  316. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +247 -49
  317. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +5 -4
  318. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +6 -1
  319. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
  320. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +20 -0
  321. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +101 -2
  322. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
  323. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
  324. package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
  325. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +67 -0
  326. package/src/runtime/agent/orchestrator/tools/lib/process-table-fixture.mjs +50 -0
  327. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +303 -63
  328. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -0
  329. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +108 -18
  330. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +77 -11
  331. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +81 -5
  332. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
  333. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
  334. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
  335. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
  336. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
  337. package/src/runtime/attachments/store.d.mts +9 -0
  338. package/src/runtime/attachments/store.mjs +80 -9
  339. package/src/runtime/browser-bridge/browser-action-contract.d.mts +0 -1
  340. package/src/runtime/browser-bridge/browser-action-contract.mjs +0 -2
  341. package/src/runtime/computer-bridge/action-schema.mjs +219 -196
  342. package/src/runtime/computer-bridge/linux-readiness.d.mts +0 -2
  343. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -16
  344. package/src/runtime/effort-judge/judge-client.mjs +21 -4
  345. package/src/runtime/effort-judge/judge-worker.mjs +4 -1
  346. package/src/runtime/github/tool.mjs +208 -17
  347. package/src/runtime/media/adapters/codex-image.mjs +140 -21
  348. package/src/runtime/media/catalog.mjs +4 -4
  349. package/src/runtime/media/chatgpt-usage.mjs +55 -0
  350. package/src/runtime/media/defaults.mjs +37 -0
  351. package/src/runtime/media/jobs.mjs +12 -2
  352. package/src/runtime/media/lanes.mjs +12 -0
  353. package/src/runtime/media/tool-defs.mjs +15 -4
  354. package/src/runtime/media/tool.mjs +41 -12
  355. package/src/runtime/media/upstream-error.mjs +72 -6
  356. package/src/runtime/memory/index.mjs +1 -0
  357. package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
  358. package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
  359. package/src/runtime/memory/lib/ingest/transcript-rows.mjs +1 -0
  360. package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
  361. package/src/runtime/memory/lib/pg/process.mjs +36 -33
  362. package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
  363. package/src/runtime/memory/lib/pg/supervisor.mjs +112 -4
  364. package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
  365. package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
  366. package/src/runtime/office/README.md +1 -1
  367. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  368. package/src/runtime/office/authoring/html-browser.mjs +18 -8
  369. package/src/runtime/office/authoring/html-document-author.mjs +2 -0
  370. package/src/runtime/office/authoring/pdf-html-runner.mjs +1 -1
  371. package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
  372. package/src/runtime/office/authoring/pptx-html-measure.mjs +3 -1
  373. package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
  374. package/src/runtime/office/authoring/xlsx-html-runner.mjs +3 -1
  375. package/src/runtime/office/core/office-actions-read.mjs +3 -0
  376. package/src/runtime/office/core/office-render-preview.mjs +2 -0
  377. package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
  378. package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
  379. package/src/runtime/office/core/office-sessions.mjs +5 -0
  380. package/src/runtime/office/core/office-transactions.mjs +3 -0
  381. package/src/runtime/office/core/office-write-ledger.mjs +94 -0
  382. package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
  383. package/src/runtime/office/index.mjs +29 -0
  384. package/src/runtime/office/pdf/pdf-analysis.mjs +0 -68
  385. package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
  386. package/src/runtime/office/pdf/pdf-render.mjs +23 -7
  387. package/src/runtime/office/pdf/pdf-security.mjs +2 -0
  388. package/src/runtime/office/portable/portable-opc.mjs +4 -1
  389. package/src/runtime/office/quality/visual-diff.mjs +2 -0
  390. package/src/runtime/session-search/session-search-ingest.mjs +1 -1
  391. package/src/runtime/shared/agent-reap-state.mjs +13 -0
  392. package/src/runtime/shared/atomic-file.d.mts +1 -1
  393. package/src/runtime/shared/background-tasks.mjs +6 -1
  394. package/src/runtime/shared/bounded-file-read.mjs +13 -0
  395. package/src/runtime/shared/bounded-line-diff.mjs +191 -0
  396. package/src/runtime/shared/browser-launch.mjs +15 -0
  397. package/src/runtime/shared/buffered-appender.mjs +18 -0
  398. package/src/runtime/shared/config.mjs +78 -18
  399. package/src/runtime/shared/err-text.mjs +48 -4
  400. package/src/runtime/shared/file-lock.mjs +6 -5
  401. package/src/runtime/shared/file-permissions.d.mts +6 -1
  402. package/src/runtime/shared/file-permissions.mjs +54 -6
  403. package/src/runtime/shared/llm/anthropic-betas.mjs +1 -2
  404. package/src/runtime/shared/llm/anthropic-effort.mjs +6 -0
  405. package/src/runtime/shared/llm/provider-model-identities.mjs +1 -0
  406. package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
  407. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
  408. package/src/runtime/shared/loopback-listener.mjs +9 -0
  409. package/src/runtime/shared/model-route-chain.d.mts +8 -0
  410. package/src/runtime/shared/model-route-chain.mjs +48 -0
  411. package/src/runtime/shared/model-route-fallback.mjs +22 -0
  412. package/src/runtime/shared/pid-liveness.mjs +12 -0
  413. package/src/runtime/shared/provider-api-key.mjs +8 -0
  414. package/src/runtime/shared/provider-timeout-phase.mjs +17 -0
  415. package/src/runtime/shared/quiet-progress.d.mts +35 -0
  416. package/src/runtime/shared/quiet-progress.mjs +101 -0
  417. package/src/runtime/shared/quota-resume-store.mjs +32 -1
  418. package/src/runtime/shared/read-row-numbers.mjs +44 -0
  419. package/src/runtime/shared/remote-intent.mjs +2 -42
  420. package/src/runtime/shared/review-diff.mjs +52 -0
  421. package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
  422. package/src/runtime/shared/session-sidebar-host.mjs +38 -0
  423. package/src/runtime/shared/slow-span.mjs +121 -0
  424. package/src/runtime/shared/statusline/statusline-segments.mjs +52 -6
  425. package/src/runtime/shared/tool-card-model/card-header.mjs +7 -1
  426. package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
  427. package/src/runtime/shared/tool-card-model.mjs +5 -2
  428. package/src/runtime/shared/tool-output-budget.mjs +2 -0
  429. package/src/runtime/shared/tool-output-limit.mjs +4 -0
  430. package/src/runtime/shared/tool-primitives.mjs +13 -0
  431. package/src/runtime/shared/tool-result-summary.mjs +22 -1
  432. package/src/runtime/shared/tool-status.mjs +3 -2
  433. package/src/runtime/shared/tool-surface.mjs +20 -6
  434. package/src/runtime/shared/tool-work-units.mjs +54 -11
  435. package/src/runtime/shared/transcript-metadata.mjs +49 -1
  436. package/src/runtime/shared/transcript-turn-keys.mjs +33 -0
  437. package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
  438. package/src/runtime/shared/transcript-writer/transcript-file.mjs +10 -1
  439. package/src/runtime/shared/transcript-writer.mjs +24 -6
  440. package/src/runtime/shared/turn-changes.mjs +269 -100
  441. package/src/runtime/shared/turn-review-reply.mjs +8 -39
  442. package/src/runtime/shared/turn-snapshot-store.mjs +19 -108
  443. package/src/runtime/shared/turn-snapshot.mjs +865 -683
  444. package/src/runtime/shared/turn-worktree-snapshot.mjs +183 -255
  445. package/src/runtime/shared/user-data-guard.mjs +262 -49
  446. package/src/runtime/shared/worktrees/activity-gate.mjs +175 -0
  447. package/src/runtime/shared/worktrees/branch-management.mjs +179 -0
  448. package/src/runtime/shared/worktrees/carry.mjs +533 -0
  449. package/src/runtime/shared/worktrees/contract.mjs +60 -0
  450. package/src/runtime/shared/worktrees/dependencies.mjs +456 -0
  451. package/src/runtime/shared/worktrees/file-recovery.mjs +84 -0
  452. package/src/runtime/shared/worktrees/git-head.mjs +214 -0
  453. package/src/runtime/shared/worktrees/git.mjs +8 -3
  454. package/src/runtime/shared/worktrees/include.mjs +125 -7
  455. package/src/runtime/shared/worktrees/lock.mjs +1 -1
  456. package/src/runtime/shared/worktrees/maintenance.mjs +20 -2
  457. package/src/runtime/shared/worktrees/manager.mjs +525 -31
  458. package/src/runtime/shared/worktrees/merge.mjs +31 -21
  459. package/src/runtime/shared/worktrees/owner.mjs +2 -1
  460. package/src/runtime/shared/worktrees/paths.d.mts +6 -0
  461. package/src/runtime/shared/worktrees/preparation-report.mjs +79 -0
  462. package/src/runtime/shared/worktrees/setup-commands.mjs +232 -0
  463. package/src/runtime/shared/worktrees/workspace-visibility.mjs +17 -0
  464. package/src/runtime/terminal-bridge/client.mjs +57 -20
  465. package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
  466. package/src/runtime/tidy/apply.mjs +47 -2
  467. package/src/runtime/tidy/run-engines.mjs +11 -5
  468. package/src/session-runtime/agent-tool-routing.mjs +19 -13
  469. package/src/session-runtime/boot/apis.mjs +20 -6
  470. package/src/session-runtime/boot/config.mjs +2 -0
  471. package/src/session-runtime/boot/facade.mjs +4 -0
  472. package/src/session-runtime/boot/infrastructure.mjs +6 -1
  473. package/src/session-runtime/boot/session.mjs +3 -3
  474. package/src/session-runtime/boot/tools.mjs +7 -1
  475. package/src/session-runtime/conversation-import/service.mjs +1 -1
  476. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
  477. package/src/session-runtime/goal-facade-api.mjs +2 -2
  478. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +91 -0
  479. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
  480. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +15 -5
  481. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +137 -26
  482. package/src/session-runtime/internal-tool-executor.mjs +8 -2
  483. package/src/session-runtime/lifecycle/cold-heir.mjs +187 -0
  484. package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
  485. package/src/session-runtime/lifecycle/session-catalog.mjs +25 -18
  486. package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
  487. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +36 -48
  488. package/src/session-runtime/lifecycle/session-switch.mjs +1 -1
  489. package/src/session-runtime/lifecycle/shared.mjs +5 -6
  490. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -5
  491. package/src/session-runtime/lifecycle/teardown.mjs +70 -14
  492. package/src/session-runtime/lifecycle-api.mjs +1 -0
  493. package/src/session-runtime/mcp-glue/connect.mjs +17 -5
  494. package/src/session-runtime/media-api.mjs +8 -0
  495. package/src/session-runtime/model-route/route-ownership.mjs +60 -0
  496. package/src/session-runtime/model-route/route-persist.mjs +3 -2
  497. package/src/session-runtime/model-route/set-route.mjs +116 -36
  498. package/src/session-runtime/model-route/web-search-route.mjs +7 -2
  499. package/src/session-runtime/model-route-api.mjs +4 -2
  500. package/src/session-runtime/native-web-search/routes.mjs +37 -24
  501. package/src/session-runtime/native-web-search-usage.mjs +51 -0
  502. package/src/session-runtime/native-web-search.mjs +19 -9
  503. package/src/session-runtime/new-session-config.mjs +4 -2
  504. package/src/session-runtime/provider-auth/login.mjs +4 -0
  505. package/src/session-runtime/provider-auth/setup.mjs +4 -0
  506. package/src/session-runtime/provider-models/catalog-load.mjs +9 -0
  507. package/src/session-runtime/provider-models/web-search-catalog.mjs +23 -3
  508. package/src/session-runtime/provider-models.mjs +1 -0
  509. package/src/session-runtime/provider-usage.mjs +4 -0
  510. package/src/session-runtime/resource-scope-decorate.mjs +10 -3
  511. package/src/session-runtime/route-resolution.mjs +3 -1
  512. package/src/session-runtime/runtime-core.mjs +4 -0
  513. package/src/session-runtime/runtime-facade.mjs +6 -0
  514. package/src/session-runtime/runtime-review-api.mjs +8 -2
  515. package/src/session-runtime/services/agent-task-status.mjs +2 -0
  516. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +0 -3
  517. package/src/session-runtime/services/agent-tool/close-flow.mjs +6 -7
  518. package/src/session-runtime/services/agent-tool/execute-send.mjs +2 -2
  519. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +36 -3
  520. package/src/session-runtime/services/agent-tool/execute.mjs +9 -1
  521. package/src/session-runtime/services/agent-tool/helpers.mjs +30 -7
  522. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
  523. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +7 -2
  524. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +6 -3
  525. package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
  526. package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
  527. package/src/session-runtime/services/agent-tool/lead-worker-index/lead-rows.mjs +3 -4
  528. package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +9 -3
  529. package/src/session-runtime/services/agent-tool/lead-worker-index/row-settlement.mjs +7 -18
  530. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +82 -13
  531. package/src/session-runtime/services/agent-tool/model-select.mjs +82 -0
  532. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -6
  533. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -1
  534. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -5
  535. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -4
  536. package/src/session-runtime/services/agent-tool/spawn-flow.mjs +2 -1
  537. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  538. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +1 -3
  539. package/src/session-runtime/services/agent-tool/tag-registry/tag-refresh.mjs +1 -3
  540. package/src/session-runtime/services/agent-tool/tag-registry.mjs +18 -10
  541. package/src/session-runtime/services/agent-tool/terminal-reaper/scan-admission.mjs +8 -41
  542. package/src/session-runtime/services/agent-tool/terminal-reaper/stale-rows.mjs +3 -3
  543. package/src/session-runtime/services/agent-tool/terminal-reaper.mjs +6 -23
  544. package/src/session-runtime/services/agent-tool/terminal-trace.mjs +0 -1
  545. package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
  546. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +32 -20
  547. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -2
  548. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
  549. package/src/session-runtime/services/agent-tool/worker-index.mjs +74 -15
  550. package/src/session-runtime/services/agent-tool.mjs +7 -0
  551. package/src/session-runtime/services/agent-watchdog-registry.mjs +2 -0
  552. package/src/session-runtime/services/channel-admin.mjs +19 -3
  553. package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
  554. package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
  555. package/src/session-runtime/services/provider-admin.mjs +158 -15
  556. package/src/session-runtime/session-create/session-options.mjs +7 -5
  557. package/src/session-runtime/session-create/session-start-hook.mjs +2 -1
  558. package/src/session-runtime/session-transcript-purge.mjs +32 -0
  559. package/src/session-runtime/session-transcript.mjs +4 -5
  560. package/src/session-runtime/session-turn-api.mjs +17 -14
  561. package/src/session-runtime/settings-builtin-tools-api.mjs +18 -6
  562. package/src/session-runtime/setup-tool/executor.mjs +57 -9
  563. package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
  564. package/src/session-runtime/setup-tool/settings-contract.mjs +18 -3
  565. package/src/session-runtime/setup-tool/tool-defs.mjs +25 -4
  566. package/src/session-runtime/skills-api.mjs +3 -5
  567. package/src/session-runtime/tool-policy-refresh.mjs +83 -32
  568. package/src/session-runtime/tool-surface.mjs +5 -1
  569. package/src/session-runtime/turn/agent-ops.mjs +49 -2
  570. package/src/session-runtime/turn/compaction-gate.mjs +25 -0
  571. package/src/session-runtime/turn/session-ops.mjs +7 -5
  572. package/src/session-runtime/turn/side-question-ops.mjs +19 -0
  573. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +7 -1
  574. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +12 -3
  575. package/src/session-runtime/turn/turn-run/turn-settle.mjs +18 -2
  576. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  577. package/src/session-runtime/turn/turn-run.mjs +26 -45
  578. package/src/session-runtime/usage-stats-api.mjs +46 -11
  579. package/src/session-runtime/workflow-agents-api/agent-route.mjs +16 -1
  580. package/src/session-runtime/workspace/admission-gate.mjs +44 -15
  581. package/src/session-runtime/workspace/project-branches.mjs +35 -41
  582. package/src/session-runtime/workspace/transition-steps.mjs +215 -116
  583. package/src/session-runtime/workspace/transitions.mjs +428 -73
  584. package/src/standalone/channel-transport.mjs +3 -4
  585. package/src/standalone/daemon-agent-control.mjs +9 -1
  586. package/src/standalone/daemon-desktop-runtime.mjs +32 -1
  587. package/src/standalone/daemon-local-session-bridge.mjs +14 -1
  588. package/src/standalone/daemon-owner.mjs +17 -4
  589. package/src/standalone/daemon-pg-stop.mjs +49 -0
  590. package/src/standalone/daemon-session-control.mjs +88 -0
  591. package/src/standalone/daemon-stop-budget.d.mts +2 -0
  592. package/src/standalone/daemon-stop-budget.mjs +18 -0
  593. package/src/standalone/daemon-stored-session-views.mjs +25 -3
  594. package/src/standalone/daemon-telemetry.mjs +19 -0
  595. package/src/standalone/daemon.mjs +63 -1
  596. package/src/standalone/desktop-service-registry.mjs +5 -0
  597. package/src/standalone/local-session-runtime.mjs +80 -30
  598. package/src/standalone/session-client.mjs +42 -0
  599. package/src/standalone/session-protocol.mjs +14 -0
  600. package/src/standalone/session-proxy/projection.mjs +41 -4
  601. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
  602. package/src/standalone/session-runtime-inline-host.mjs +3 -0
  603. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +91 -49
  604. package/src/standalone/session-service/agent-tree/agent-child.mjs +19 -1
  605. package/src/standalone/session-service/agent-tree/agent-registry.mjs +25 -0
  606. package/src/standalone/session-service/agent-tree/agent-turns.mjs +9 -1
  607. package/src/standalone/session-service/agent-tree.mjs +28 -2
  608. package/src/standalone/session-service/entries/session-loads.mjs +16 -5
  609. package/src/standalone/session-service/entries.mjs +1 -0
  610. package/src/standalone/session-service/projection/transcript-window.mjs +39 -0
  611. package/src/standalone/session-service/quota-resume.mjs +28 -13
  612. package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
  613. package/src/standalone/session-service/session-calls/session-turns.mjs +17 -6
  614. package/src/standalone/session-service/session-calls/session-views.mjs +6 -0
  615. package/src/standalone/session-service-api.mjs +6 -1
  616. package/src/standalone/session-state-patch.d.mts +2 -1
  617. package/src/standalone/session-state-patch.mjs +41 -1
  618. package/src/standalone/session-tool-output.mjs +82 -0
  619. package/src/tui/App.jsx +25 -0
  620. package/src/tui/app/app-view/floating-panel.jsx +26 -1
  621. package/src/tui/app/app-view.jsx +2 -1
  622. package/src/tui/app/btw-controller.mjs +118 -0
  623. package/src/tui/app/create-app-pickers.mjs +2 -0
  624. package/src/tui/app/provider-setup/provider-items.mjs +8 -0
  625. package/src/tui/app/provider-setup-picker.mjs +15 -3
  626. package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
  627. package/src/tui/app/shell-layout/surfaces.mjs +3 -1
  628. package/src/tui/app/slash-commands.mjs +19 -3
  629. package/src/tui/app/slash-dispatch/session-commands.mjs +68 -6
  630. package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
  631. package/src/tui/app/use-global-key-input.mjs +5 -12
  632. package/src/tui/app/use-prompt-handlers.mjs +11 -0
  633. package/src/tui/components/BtwPanel.jsx +53 -0
  634. package/src/tui/components/QuestionPanel.jsx +275 -0
  635. package/src/tui/components/Spinner.jsx +4 -0
  636. package/src/tui/components/SpinnerByline.jsx +21 -2
  637. package/src/tui/components/question-panel-model.mjs +156 -0
  638. package/src/tui/components/status-line/local-line.mjs +10 -2
  639. package/src/tui/dist/index.mjs +2897 -1722
  640. package/src/tui/session/active-tool-summary.mjs +1 -1
  641. package/src/tui/session/context-state.mjs +4 -5
  642. package/src/tui/session/goal-continuation/continuation-queue.mjs +2 -3
  643. package/src/tui/session/goal-continuation/deadline-delivery.mjs +4 -2
  644. package/src/tui/session/goal-continuation/session-boundary.mjs +21 -0
  645. package/src/tui/session/quota-resume.mjs +140 -61
  646. package/src/tui/session/session-api/commands.mjs +14 -10
  647. package/src/tui/session/session-api/controls.mjs +14 -2
  648. package/src/tui/session/session-api/integrations.mjs +9 -2
  649. package/src/tui/session/session-api/lifecycle/dispose.mjs +3 -9
  650. package/src/tui/session/session-api/lifecycle/resume.mjs +2 -7
  651. package/src/tui/session/session-api/lifecycle.mjs +14 -11
  652. package/src/tui/session/session-api/media.mjs +2 -0
  653. package/src/tui/session/session-api/routes.mjs +81 -57
  654. package/src/tui/session/session-api/settings.mjs +9 -3
  655. package/src/tui/session/session-api/worktree.mjs +3 -2
  656. package/src/tui/session/session-api.mjs +1 -0
  657. package/src/tui/session/session-flow/auto-clear.mjs +1 -3
  658. package/src/tui/session/session-flow/drain.mjs +6 -4
  659. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -0
  660. package/src/tui/session/session-flow/queue/take-entries.mjs +2 -1
  661. package/src/tui/session/session-flow/queue.mjs +1 -1
  662. package/src/tui/session/tool-approval.mjs +20 -8
  663. package/src/tui/session/transcript-spill.mjs +14 -7
  664. package/src/tui/session/transcript-store/streaming-tail.mjs +1 -1
  665. package/src/tui/session/tui-steering-persist.mjs +3 -5
  666. package/src/tui/session/turn-quiet.mjs +53 -0
  667. package/src/tui/session/turn-stream.mjs +179 -32
  668. package/src/tui/session/turn.mjs +50 -36
  669. package/src/tui/session/worktree-setup-notice.mjs +38 -0
  670. package/src/tui/spinner-meta.mjs +10 -0
  671. package/src/tui/spinner-verbs.mjs +3 -0
  672. package/src/ui/statusline.mjs +13 -3
  673. package/src/workflows/default/WORKFLOW.md +3 -1
  674. package/src/runtime/agent/orchestrator/providers/model-pricing-rates.mjs +0 -1
  675. package/src/runtime/agent/orchestrator/session/manager/foreign-pending-messages.mjs +0 -346
  676. package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +0 -117
  677. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +0 -246
  678. package/src/session-runtime/services/agent-tool/terminal-reaper/reap-timers.mjs +0 -142
  679. package/src/session-runtime/turn/share-ops.mjs +0 -77
  680. package/src/tui/session/cross-surface-share.mjs +0 -406
  681. package/src/tui/session/live-share/delta.mjs +0 -153
  682. package/src/tui/session/live-share/mirror.mjs +0 -106
  683. package/src/tui/session/live-share/owner.mjs +0 -254
  684. package/src/tui/session/live-share/retry.mjs +0 -54
  685. package/src/tui/session/live-share/viewer/frame-router.mjs +0 -32
  686. package/src/tui/session/live-share/viewer/pipe-client.mjs +0 -108
  687. package/src/tui/session/live-share/viewer/submit-acks.mjs +0 -65
  688. package/src/tui/session/live-share/viewer/sync-waiters.mjs +0 -53
  689. package/src/tui/session/live-share/viewer.mjs +0 -99
  690. package/src/tui/session/live-share/wire.mjs +0 -44
  691. package/src/tui/session/live-share.mjs +0 -154
  692. package/src/tui/session/shared-dir-watch.mjs +0 -69
@@ -1,29 +1,47 @@
1
1
  /**
2
2
  * The Lead session workspace transition authority. Every workspace change of
3
3
  * the Lead this runtime hosts — entering its retained worktree (created lazily
4
- * on the first message of a worktree task), returning to a project-folder
5
- * branch, removing the worktree — goes through applyWorkspaceTransition: one
4
+ * on the first message of a worktree task), selecting a branch (it runs where
5
+ * that branch is checked out — the project folder, a linked checkout, or a
6
+ * managed worktree made for it — and no existing folder is switched),
7
+ * removing the worktree — goes through applyWorkspaceTransition: one
6
8
  * serialized, revisioned commit that retargets the runtime cwd (and the turn's
7
9
  * cwd override), stores the durable `workspace` record, re-roots the prompt
8
- * context of the Lead and its idle workers, and persists. Failures are typed
9
- * WorktreeErrors and leave the previous workspace intact.
10
+ * context of the Lead and its idle workers, and persists, awaiting each save
11
+ * before it reports success. Failures are typed WorktreeErrors and leave the
12
+ * previous workspace intact.
10
13
  *
11
14
  * Git and registry work is delegated to the managed-worktree backend
12
15
  * (runtime/shared/worktrees/manager.mjs), loaded on first use.
13
16
  */
14
17
  import { randomUUID } from 'node:crypto';
18
+ import { isDeepStrictEqual } from 'node:util';
15
19
  import {
20
+ WORKTREE_CARRY_CHOICES,
16
21
  branchMenuEntries,
17
22
  isWorktreeBound,
18
23
  isWorktreeError,
19
24
  normalizeSessionWorkspace,
20
25
  worktreeError,
21
26
  worktreeNameError,
27
+ worktreeRefusal,
22
28
  } from '../../runtime/shared/worktrees/contract.mjs';
23
29
  import { normalizeWorktreeSettings } from '../../runtime/shared/worktrees/settings.mjs';
24
30
  import * as maintenance from '../../runtime/shared/worktrees/maintenance.mjs';
25
31
  import { inspectRepo, throwIfAborted } from '../../runtime/shared/worktrees/git.mjs';
32
+ import { worktreePreparationNote } from '../../runtime/shared/worktrees/preparation-report.mjs';
26
33
  import { isWithin, samePath } from '../../runtime/shared/worktrees/paths.mjs';
34
+ import { readGitHead } from '../../runtime/shared/worktrees/git-head.mjs';
35
+ import {
36
+ holdWorkspaceActivity,
37
+ isExternalCheckout,
38
+ releaseAll,
39
+ } from '../../runtime/shared/worktrees/activity-gate.mjs';
40
+ import { mergeConfirmedTarget } from '../../runtime/shared/worktrees/branch-management.mjs';
41
+ import {
42
+ clearReadDedupSession,
43
+ resetReadStateAfterCompaction,
44
+ } from '../../runtime/agent/orchestrator/session/cache/read-cache.mjs';
27
45
  import { sessionHasConversationMessages } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
28
46
  import { buildWorkspacePromptContext } from '../../runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs';
29
47
  import {
@@ -33,7 +51,7 @@ import {
33
51
  import { AGENT_OWNER } from '../../runtime/agent/orchestrator/agent-owner.mjs';
34
52
  import { _liveSessions } from '../../runtime/agent/orchestrator/session/store/live-state.mjs';
35
53
  import { admitTurn, beginWorkspaceTransition, holdCheckoutFolder } from './admission-gate.mjs';
36
- import { assertMergeTarget, createProjectBranchOps } from './project-branches.mjs';
54
+ import { createProjectBranchOps } from './project-branches.mjs';
37
55
  import { assertRetainedFits, createTransitionSteps, undoAll } from './transition-steps.mjs';
38
56
  import { readSessionWorkspace } from './workspace-state.mjs';
39
57
 
@@ -53,18 +71,39 @@ async function defaultOwnShellJobCount(sessionIds) {
53
71
 
54
72
  const lower = (value) => String(value || '').toLowerCase();
55
73
 
74
+ const WORKTREE_BOUND_SWITCH =
75
+ 'The session works in a managed worktree; exit the worktree first (switch to a project-folder branch, or merge or remove the worktree) before moving it to another project.';
76
+
56
77
  /** The registered Project (projects.json) at `path`, or null. */
57
78
  async function defaultRegisteredProject(path) {
58
79
  const { listProjectsStrict } = await import('../../runtime/shared/projects.mjs');
59
80
  return listProjectsStrict().find((entry) => samePath(entry.path, path))?.path ?? null;
60
81
  }
61
82
 
83
+ /** The dependency installs a new worktree folder still needs (dependencies.mjs). */
84
+ async function defaultPlanWorktreeSetup(input) {
85
+ const { planDependencySetup } = await import('../../runtime/shared/worktrees/dependencies.mjs');
86
+ return planDependencySetup(input);
87
+ }
88
+
89
+ async function defaultRunWorktreeSetup(input) {
90
+ const { runWorktreeSetupCommands } = await import('../../runtime/shared/worktrees/setup-commands.mjs');
91
+ return runWorktreeSetupCommands(input);
92
+ }
93
+
62
94
  /**
63
95
  * Re-root one session's prompt at `cwd`: environment facts and instruction
64
96
  * files for every session, project memory for the Lead only (workers never
65
- * carried it).
97
+ * carried it). A session with a conversation keeps its system prompt (cache
98
+ * intact) and gets a tail notice instead (refreshSessionWorkspaceContext);
99
+ * `move` ({ from, changes }: the session left the project folder `from` for
100
+ * a worktree) adds the uncommitted-changes and path lines to that notice.
66
101
  */
67
- export async function refreshWorkspacePrompt(session, cwd, { loadCoreMemoryContext } = {}) {
102
+ export async function refreshWorkspacePrompt(session, cwd, { loadCoreMemoryContext, move = null } = {}) {
103
+ // A new checkout invalidates observed-file snapshots as well as read/search
104
+ // results. Conversation text remains historical evidence, not a file cache.
105
+ clearReadDedupSession(session?.id);
106
+ resetReadStateAfterCompaction(session?.id);
68
107
  const { environmentContext, instructionFilesContext } = buildWorkspacePromptContext(session, cwd);
69
108
  const coreMemoryContext =
70
109
  session?.owner === AGENT_OWNER || typeof loadCoreMemoryContext !== 'function'
@@ -75,6 +114,7 @@ export async function refreshWorkspacePrompt(session, cwd, { loadCoreMemoryConte
75
114
  environmentContext,
76
115
  coreMemoryContext,
77
116
  instructionFilesContext,
117
+ ...(move ? { move } : {}),
78
118
  });
79
119
  }
80
120
 
@@ -137,9 +177,10 @@ const TRANSITION_STATE = { worktree: 'provisioning', branch: 'switching', 'remov
137
177
  * @param {object} deps
138
178
  * @param {() => any} deps.getSession The Lead session this runtime hosts.
139
179
  * @param {() => string} deps.getCurrentCwd
140
- * @param {(cwd: string) => unknown} deps.applyResolvedCwd Retargets rt cwd, session.cwd and the cwd override.
141
- * @param {(session: any) => unknown} deps.persistSession
142
- * @param {(session: any, cwd: string) => Promise<unknown>} deps.refreshWorkspaceContext
180
+ * @param {(cwd: string, options?: { persistProjectSelection?: boolean }) => unknown} deps.applyResolvedCwd Retargets rt cwd, session.cwd and the cwd override (and, persisting, the Project selection).
181
+ * @param {(desktopSession: any) => unknown} [deps.setDesktopSession] Restores the runtime's desktop metadata on a rollback.
182
+ * @param {(session: any) => Promise<unknown>|unknown} deps.persistSession Durable save: resolves once the session is on disk, rejects (throws) when it is not.
183
+ * @param {(session: any, cwd: string, move?: { from: string, changes: 'carried'|'left'|null }|null) => Promise<unknown>} deps.refreshWorkspaceContext
143
184
  * @param {() => number} deps.getActiveTurnCount
144
185
  * @param {() => { agentWorkers?: any[], agentJobs?: any[] }} deps.agentStatusState
145
186
  * @param {(sessionId: string, cwd: string) => unknown} [deps.updateLeadWorkerCwd] Moves the Lead's pool row (lead-workers.json).
@@ -149,6 +190,7 @@ export function createWorkspaceTransitions({
149
190
  getReservedSessionId = () => null,
150
191
  getCurrentCwd,
151
192
  getDesktopSession = () => null,
193
+ setDesktopSession = () => {},
152
194
  getConfig = () => null,
153
195
  createCurrentSession = null,
154
196
  applyResolvedCwd,
@@ -167,11 +209,24 @@ export function createWorkspaceTransitions({
167
209
  inspectProject = inspectRepo,
168
210
  findRegisteredProject = defaultRegisteredProject,
169
211
  listStoredSessionIds = maintenance.storedSessionIds,
212
+ listWorkspaceConsumers = maintenance.storedWorkspaceConsumers,
213
+ listWorkspaceJobs = async () => {
214
+ const { listShellJobRecords } = await import(
215
+ '../../runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs'
216
+ );
217
+ return listShellJobRecords({ strict: true });
218
+ },
170
219
  runtimeToken = randomUUID(),
171
220
  newTxId = randomUUID,
221
+ planWorktreeSetup = defaultPlanWorktreeSetup,
222
+ runWorktreeSetup = defaultRunWorktreeSetup,
172
223
  }) {
173
224
  const worktreeSettings = () => normalizeWorktreeSettings(getConfig?.()?.worktree);
174
225
  let pendingIntent = creationIntent(initialIntent, worktreeSettings());
226
+ // The new worktree whose dependencies have not been prepared yet, bound to
227
+ // that worktree (worktreeId + cwd): it runs only while the session is there.
228
+ let pendingSetup = null;
229
+ const setupListeners = new Set();
175
230
  let managerPromise = null;
176
231
  const backend = () => {
177
232
  if (manager) return Promise.resolve(manager);
@@ -207,6 +262,37 @@ export function createWorkspaceTransitions({
207
262
  return normalizeSessionWorkspace({ projectPath, cwd: getCurrentCwd() || projectPath, revision: 0 });
208
263
  }
209
264
 
265
+ let liveWorkspace = null;
266
+
267
+ /**
268
+ * The workspace the session publishes: a worktree-bound record as stored; a
269
+ * project-folder session (never moved, back from a worktree, or carrying a
270
+ * transition stub) with the folder's checked-out branch / detached commit and
271
+ * repoCommonDir read straight from HEAD — no git process. Null outside a git
272
+ * repository for a session without a record. Identity-stable while equal.
273
+ */
274
+ function getLiveWorkspace() {
275
+ const session = getSession();
276
+ const stored = readSessionWorkspace(session);
277
+ if (isWorktreeBound(stored)) return session.workspace;
278
+ let base;
279
+ try {
280
+ base = stored ?? currentWorkspace(session);
281
+ } catch {
282
+ return session?.workspace ?? null;
283
+ }
284
+ const head = readGitHead(base.cwd);
285
+ if (!head) return session?.workspace ?? null;
286
+ const next = {
287
+ ...base,
288
+ repoCommonDir: head.repoCommonDir,
289
+ branch: head.branch,
290
+ baseCommit: head.branch ? base.baseCommit : head.commit,
291
+ };
292
+ if (!liveWorkspace || !isDeepStrictEqual(liveWorkspace, next)) liveWorkspace = next;
293
+ return liveWorkspace;
294
+ }
295
+
210
296
  function isSessionActive(session) {
211
297
  const runtime = sessionManager?.getSessionRuntime?.(session.id);
212
298
  if (runtime?.controller?.signal && !runtime.controller.signal.aborted) return true;
@@ -223,8 +309,11 @@ export function createWorkspaceTransitions({
223
309
  (candidate.ownerSessionId === session.id || candidate.parentSessionId === session.id)
224
310
  );
225
311
 
226
- /** WORKTREE_BUSY_JOBS while this Lead has a turn, workers or background shells running. */
227
- async function assertLeadIdle(session, { ownTurn = false } = {}) {
312
+ /**
313
+ * WORKTREE_BUSY_JOBS while this Lead has a turn, workers or background
314
+ * shells running (`shellJobs: false` tolerates background shells).
315
+ */
316
+ async function assertLeadIdle(session, { ownTurn = false, shellJobs: checkShellJobs = true } = {}) {
228
317
  if (!ownTurn && getActiveTurnCount() > 0) {
229
318
  throw worktreeError('WORKTREE_BUSY_JOBS', 'The session is running a turn; wait for it to finish.', {
230
319
  reason: 'turn',
@@ -240,6 +329,7 @@ export function createWorkspaceTransitions({
240
329
  if (busyWorkers || busyJobs) {
241
330
  throw worktreeError('WORKTREE_BUSY_JOBS', undefined, { reason: 'workers', workers: busyWorkers, jobs: busyJobs });
242
331
  }
332
+ if (!checkShellJobs) return;
243
333
  const ids = new Set([session.id, ...workers.map((row) => row?.sessionId).filter(Boolean)]);
244
334
  for (const worker of workersOf(session)) ids.add(worker.id);
245
335
  const shellJobs = await countOwnShellJobs([...ids]);
@@ -253,25 +343,19 @@ export function createWorkspaceTransitions({
253
343
  * wait (admission gate). `sessionId` null: a session-less (draft) change.
254
344
  * @returns {() => void}
255
345
  */
256
- function holdProjectFolder(sessionId, folder) {
346
+ function holdProjectFolder(sessionId, folder, { hold = true } = {}) {
257
347
  const users = listLiveSessions().filter(
258
348
  (candidate) =>
259
349
  candidate?.id &&
260
350
  candidate.id !== sessionId &&
261
351
  candidate.closed !== true &&
262
- candidate.remoteAttached !== true &&
263
352
  (!sessionId || (candidate.ownerSessionId !== sessionId && candidate.parentSessionId !== sessionId)) &&
264
353
  typeof candidate.cwd === 'string' &&
265
354
  isWithin(folder, candidate.cwd) &&
266
355
  isSessionActive(candidate)
267
356
  );
268
- if (users.length) {
269
- throw worktreeError('WORKTREE_BUSY_JOBS', 'Other sessions are working in the project folder.', {
270
- reason: 'folder-in-use',
271
- sessions: users.map((candidate) => candidate.id),
272
- });
273
- }
274
- return holdCheckoutFolder(sessionId, folder);
357
+ if (users.length) throw worktreeRefusal('folder-in-use', { sessions: users.map((candidate) => candidate.id) });
358
+ return holdCheckoutFolder(sessionId, folder, { hold });
275
359
  }
276
360
 
277
361
  /** Run `fn` holding the checkout `folder` (holdProjectFolder); released when it settles. */
@@ -284,11 +368,81 @@ export function createWorkspaceTransitions({
284
368
  }
285
369
  }
286
370
 
371
+ /**
372
+ * Before a carry clears the shared checkout `folder` (held by the caller,
373
+ * so no new turn starts there): WORKTREE_BUSY_JOBS while any other session
374
+ * working in it — idle or not, this Lead's workers included — owns a
375
+ * running background shell (holdProjectFolder already refused running
376
+ * turns and agents there, assertLeadIdle this Lead's own). Processes
377
+ * outside Mixdog (editors, watchers) cannot be excluded.
378
+ */
379
+ async function assertCheckoutQuiet(session, folder) {
380
+ const sharing = listLiveSessions()
381
+ .filter(
382
+ (candidate) =>
383
+ candidate?.id &&
384
+ candidate.id !== session.id &&
385
+ candidate.closed !== true &&
386
+ typeof candidate.cwd === 'string' &&
387
+ isWithin(folder, candidate.cwd)
388
+ )
389
+ .map((candidate) => candidate.id);
390
+ if (!sharing.length) return;
391
+ const shellJobs = await countOwnShellJobs(sharing);
392
+ if (shellJobs > 0) throw worktreeRefusal('folder-shell-jobs', { shellJobs });
393
+ }
394
+
395
+ /**
396
+ * The shared admission of every merge and folder cleanup (manageProjectBranch):
397
+ * refuses while a session or worker runs in an affected folder, or a
398
+ * background command does; `removing` refuses while any session still uses
399
+ * one. Then holds the folders — Mixdog checkouts only; an external checkout
400
+ * is never lock-blocked — so new Mixdog work there waits until `run`
401
+ * settles. `actor`: the session acting on its own checkout, whose own turn
402
+ * and workers its caller already checked (assertLeadIdle).
403
+ */
404
+ async function withManagementFolders(folders, removing, run, { actor = null } = {}) {
405
+ const release = [];
406
+ try {
407
+ for (const folder of [...new Set(folders)].sort()) {
408
+ release.push(holdProjectFolder(actor, folder, { hold: !isExternalCheckout(folder) }));
409
+ }
410
+ release.push(holdWorkspaceActivity(folders, { sessionId: actor }));
411
+ const stored = await listWorkspaceConsumers();
412
+ const consumers = new Map(stored.map((session) => [session.id, session]));
413
+ for (const session of listLiveSessions()) if (session?.closed !== true) consumers.set(session.id, session);
414
+ const affected = [...consumers.values()].filter((session) =>
415
+ folders.some((folder) => session.cwd && isWithin(folder, session.cwd))
416
+ );
417
+ const blocking = removing
418
+ ? affected
419
+ : affected.filter(
420
+ (session) =>
421
+ !(actor && [session.id, session.ownerSessionId, session.parentSessionId].includes(actor)) &&
422
+ isSessionActive(session)
423
+ );
424
+ if (blocking.length) throw worktreeRefusal('folder-in-use', { sessions: blocking.map((session) => session.id) });
425
+ const jobs = await listWorkspaceJobs();
426
+ if (jobs.some((job) => !job.terminal && folders.some((folder) => isWithin(folder, job.cwd)))) {
427
+ throw worktreeRefusal('folder-shell-jobs');
428
+ }
429
+ if ((await countOwnShellJobs(affected.map((session) => session.id))) > 0) {
430
+ throw worktreeRefusal('folder-shell-jobs');
431
+ }
432
+ return await run([...consumers.keys()]);
433
+ } finally {
434
+ releaseAll(release);
435
+ }
436
+ }
437
+
287
438
  const steps = createTransitionSteps({
439
+ assertCheckoutQuiet,
288
440
  backend,
289
441
  inspectProject,
290
442
  runtimeToken,
291
443
  getCurrentCwd,
444
+ getDesktopSession,
445
+ setDesktopSession,
292
446
  applyResolvedCwd,
293
447
  persistSession,
294
448
  refreshWorkspaceContext,
@@ -302,6 +456,7 @@ export function createWorkspaceTransitions({
302
456
  inspectProject,
303
457
  findRegisteredProject,
304
458
  withProjectFolder,
459
+ withManagementFolders,
305
460
  });
306
461
 
307
462
  async function transition(session, target, options = {}) {
@@ -326,21 +481,48 @@ export function createWorkspaceTransitions({
326
481
  await assertLeadIdle(session, { ownTurn: options.ownTurn === true });
327
482
  const run = { signal: options.signal, txId, journal };
328
483
  if (target.kind === 'worktree') {
329
- return await steps.enterWorktree(session, previous, {
484
+ const { created, ...entered } = await steps.enterWorktree(session, previous, {
330
485
  ...run,
331
486
  name: target.name,
332
487
  nameHint: options.nameHint,
333
488
  confirmLarge: options.confirmLarge,
489
+ changes: options.changes,
334
490
  });
491
+ // A new checkout gets its dependencies prepared at the start of the
492
+ // session's next turn there (prepareTurnWorkspace).
493
+ if (created) {
494
+ pendingSetup = {
495
+ ...created,
496
+ sessionId: session.id,
497
+ worktreeId: entered.workspace.worktreeId,
498
+ cwd: entered.workspace.cwd,
499
+ mainDir: previous.projectPath,
500
+ };
501
+ }
502
+ return entered;
335
503
  }
336
504
  if (target.kind === 'branch') {
337
- return await steps.enterProjectBranch(session, previous, {
505
+ const { created, ...entered } = await steps.enterProjectBranch(session, previous, {
338
506
  ...run,
339
507
  branch: target.branch,
340
508
  create: target.create,
509
+ confirmLarge: options.confirmLarge,
341
510
  });
511
+ if (created && entered.workspace?.worktreeId) {
512
+ pendingSetup = {
513
+ ...created,
514
+ sessionId: session.id,
515
+ worktreeId: entered.workspace.worktreeId,
516
+ cwd: entered.workspace.cwd,
517
+ mainDir: previous.projectPath,
518
+ };
519
+ }
520
+ return entered;
342
521
  }
343
- return await steps.removeRetainedWorktree(session, previous, { ...run, force: target.force });
522
+ const removed = await steps.removeRetainedWorktree(session, previous, { ...run, force: target.force });
523
+ // The session's retained worktree is gone: its pending setup goes with it.
524
+ if (pendingSetup?.sessionId === session.id) pendingSetup = null;
525
+ return removed;
344
526
  } catch (error) {
345
527
  // Whatever already moved (cwd, record, prompts, worker roots, lease)
346
528
  // goes back exactly; the previous workspace stays authoritative.
@@ -414,21 +596,77 @@ export function createWorkspaceTransitions({
414
596
  );
415
597
  }
416
598
  const intent = intentFor(session);
417
- if (!intent) return null;
599
+ let result = null;
600
+ if (intent) {
601
+ try {
602
+ result = await provisionIntent(session, intent, submissionId, prompt, {
603
+ confirmLarge: intent.confirmLarge || confirmLarge === true,
604
+ signal,
605
+ ownTurn: true,
606
+ });
607
+ } catch (error) {
608
+ // The settings default never blocks a task outside a git repository.
609
+ if (!intent.explicit && isWorktreeError(error, 'WORKTREE_UNSUPPORTED_REPO')) {
610
+ if (pendingIntent === intent) pendingIntent = null;
611
+ return null;
612
+ }
613
+ throw error;
614
+ }
615
+ }
616
+ await runPendingSetup(session, signal);
617
+ return result;
618
+ }
619
+
620
+ /**
621
+ * Prepare the session's new worktree, once, under the turn (its admission
622
+ * keeps the folder from being merged or removed; its signal — the Stop
623
+ * button — cancels): the frozen installs the links made at creation did
624
+ * not cover. While an install runs, every onWorktreeSetup listener gets its
625
+ * one-line progress; nothing else reaches the user. The agent gets one
626
+ * compact note with this turn (`session.pendingSetupNotice`): the main
627
+ * checkout, what was copied, linked and installed, what failed (with the
628
+ * output tail) and what was skipped. A failure or timeout is in the note
629
+ * and the turn goes on; a cancel aborts the turn like any other stop. The
630
+ * worktree stays either way. The setup belongs to the worktree it was made
631
+ * for: while the session works elsewhere (it returned to a project-folder
632
+ * branch before its first turn there) it is deferred, never run in another
633
+ * folder, and runs on the first turn after the session re-enters it.
634
+ */
635
+ async function runPendingSetup(session, signal) {
636
+ const pending = pendingSetup;
637
+ if (!pending || pending.sessionId !== session.id) return;
638
+ const here = readSessionWorkspace(session);
639
+ if (!isWorktreeBound(here) || here.worktreeId !== pending.worktreeId || !samePath(here.cwd, pending.cwd)) return;
640
+ pendingSetup = null;
641
+ const id = newTxId();
642
+ const report = { root: pending.root, prepared: pending.prepared, dependencyNotes: [], installs: null, notes: [] };
643
+ const emit = (event) => {
644
+ for (const listener of setupListeners) {
645
+ try {
646
+ listener({ ...event, id, sessionId: session.id, cwd: pending.cwd });
647
+ } catch {
648
+ /* a viewer's failure never stops the setup */
649
+ }
650
+ }
651
+ };
418
652
  try {
419
- return await provisionIntent(session, intent, submissionId, prompt, {
420
- confirmLarge: intent.confirmLarge || confirmLarge === true,
421
- signal,
422
- ownTurn: true,
423
- });
424
- } catch (error) {
425
- // The settings default never blocks a task outside a git repository.
426
- if (!intent.explicit && isWorktreeError(error, 'WORKTREE_UNSUPPORTED_REPO')) {
427
- if (pendingIntent === intent) pendingIntent = null;
428
- return null;
653
+ const plan = await planWorktreeSetup({ worktreeDir: pending.cwd, mainDir: pending.mainDir, signal });
654
+ report.dependencyNotes = plan.notes;
655
+ if (plan.commands.length) {
656
+ report.installs = await runWorktreeSetup({ commands: plan.commands, signal, onProgress: emit });
429
657
  }
430
- throw error;
658
+ } catch (error) {
659
+ if (!signal?.aborted) report.notes.push(`Dependencies could not be prepared: ${error?.message || error}`);
431
660
  }
661
+ session.pendingSetupNotice = { revision: Date.now(), content: worktreePreparationNote(report) };
662
+ throwIfAborted(signal);
663
+ }
664
+
665
+ /** Subscribe to worktree setup progress; returns the unsubscribe. */
666
+ function onWorktreeSetup(listener) {
667
+ if (typeof listener !== 'function') return () => {};
668
+ setupListeners.add(listener);
669
+ return () => setupListeners.delete(listener);
432
670
  }
433
671
 
434
672
  async function getBranchMenu() {
@@ -440,15 +678,30 @@ export function createWorkspaceTransitions({
440
678
  projectPath: workspace.projectPath,
441
679
  sessionId: session?.id || null,
442
680
  });
443
- // A session in the project folder (never moved, or back from a worktree)
681
+ const selectedEntry = workspace.worktreeId ? await (await backend()).findWorktreeContaining(workspace.cwd) : null;
682
+ // A session outside a managed worktree (the project folder — never moved,
683
+ // or back from a worktree — or a linked checkout of the selected branch)
444
684
  // is on whatever that folder has checked out now.
445
- const checkedOut = menu.occupancy.find((row) => row.kind === 'current')?.branch ?? null;
685
+ // Its repository is the project's (a never-moved session has no stored
686
+ // record), and a detached checkout shows branch null with the commit in
687
+ // baseCommit — never mistaken for "not a repository".
688
+ let view = workspace;
689
+ if (!isWorktreeBound(workspace)) {
690
+ const project = await inspectProject(workspace.cwd);
691
+ const checkedOut = project.currentBranch ?? null;
692
+ view = {
693
+ ...workspace,
694
+ repoCommonDir: project.repoCommonDir ?? workspace.repoCommonDir,
695
+ branch: checkedOut,
696
+ baseCommit: checkedOut ? workspace.baseCommit : (project.headCommit ?? null),
697
+ };
698
+ }
446
699
  return {
447
- workspace: isWorktreeBound(workspace) || !checkedOut ? workspace : { ...workspace, branch: checkedOut },
700
+ workspace: view,
448
701
  pendingWorktree: pendingIntent ? { name: pendingIntent.name } : null,
449
702
  branches: branchMenuEntries(menu.branches, menu.occupancy),
450
703
  occupancy: menu.occupancy,
451
- retainedWorktree: menu.retainedWorktree ?? null,
704
+ retainedWorktree: selectedEntry ?? menu.retainedWorktree ?? null,
452
705
  // Creation notes of the retained worktree (submodules, include entries).
453
706
  warnings: Array.isArray(menu.retainedWorktree?.warnings) ? [...menu.retainedWorktree.warnings] : [],
454
707
  };
@@ -487,11 +740,13 @@ export function createWorkspaceTransitions({
487
740
 
488
741
  async function selectBranch({ branch, create = false, expectedRevision, confirmLarge = false } = {}) {
489
742
  const session = await ensureSession();
490
- const retained = await (await backend()).getSessionWorktree(session.id);
491
- const target =
492
- retained && retained.branch === branch && create !== true
493
- ? { kind: 'worktree' }
494
- : { kind: 'branch', branch, create: create === true };
743
+ const current = currentWorkspace(session);
744
+ if (current.branch === branch && current.worktreeId) {
745
+ assertRevision(current.revision, validRevision(expectedRevision));
746
+ pendingIntent = null;
747
+ return { revision: current.revision, workspace: current };
748
+ }
749
+ const target = { kind: 'branch', branch, create: create === true };
495
750
  const result = await applyWorkspaceTransition({ sessionId: session.id }, target, {
496
751
  expectedRevision,
497
752
  confirmLarge,
@@ -510,17 +765,28 @@ export function createWorkspaceTransitions({
510
765
  * reuse it. Typed failures (large repository, disk, busy) therefore reach
511
766
  * the sender while its draft is still unsent, and the turn that follows
512
767
  * finds the session already bound.
768
+ *
769
+ * A provisioning that creates a new worktree decides the project folder's
770
+ * uncommitted changes (tracked and untracked): none → it proceeds; without
771
+ * `carryChanges` it refuses with WORKTREE_DIRTY_CHOICE (`details.count`);
772
+ * `leave` starts the worktree at HEAD and leaves them; `carry` moves them
773
+ * into it (the result's `changes` reports which). Re-entering a retained
774
+ * worktree never touches them.
513
775
  */
514
776
  async function requestWorktree({
515
777
  name = null,
516
778
  confirmLarge = false,
517
779
  provision = false,
780
+ carryChanges,
518
781
  prompt = '',
519
782
  txId = '',
520
783
  expectedRevision,
521
784
  } = {}) {
522
785
  const nameHint = validName(name);
523
786
  const expected = validRevision(expectedRevision);
787
+ if (carryChanges !== undefined && carryChanges !== null && !WORKTREE_CARRY_CHOICES.includes(carryChanges)) {
788
+ throw new TypeError(`carryChanges must be one of ${WORKTREE_CARRY_CHOICES.join(', ')}.`);
789
+ }
524
790
  const session = provision === true ? await ensureSession() : getSession();
525
791
  // No session yet: the menu it was read from had revision 0.
526
792
  const current = session?.id ? currentWorkspace(session) : null;
@@ -536,6 +802,7 @@ export function createWorkspaceTransitions({
536
802
  return { ...entered, pending: false };
537
803
  }
538
804
  }
805
+ const priorIntent = pendingIntent;
539
806
  pendingIntent = {
540
807
  name: nameHint ?? pendingIntent?.name ?? null,
541
808
  confirmLarge: confirmLarge === true || pendingIntent?.confirmLarge === true,
@@ -544,10 +811,21 @@ export function createWorkspaceTransitions({
544
811
  txId: pendingIntent?.txId ?? null,
545
812
  };
546
813
  if (provision === true) {
547
- return {
548
- ...(await provisionIntent(session, pendingIntent, txId, prompt, { expectedRevision: expected })),
549
- pending: false,
550
- };
814
+ const intent = pendingIntent;
815
+ try {
816
+ return {
817
+ ...(await provisionIntent(session, intent, txId, prompt, {
818
+ expectedRevision: expected,
819
+ changes: carryChanges ?? 'ask',
820
+ })),
821
+ pending: false,
822
+ };
823
+ } catch (error) {
824
+ // A refused move (uncommitted changes to decide, busy, …) is never
825
+ // re-armed for the next turn, where nobody could answer it.
826
+ if (pendingIntent === intent) pendingIntent = priorIntent;
827
+ throw error;
828
+ }
551
829
  }
552
830
  const workspace = session?.id ? currentWorkspace(session) : null;
553
831
  return { revision: workspace?.revision ?? 0, workspace, pending: true };
@@ -570,23 +848,54 @@ export function createWorkspaceTransitions({
570
848
  if (cleanup !== true || merged.merged !== true) return merged;
571
849
  // "Merge and clean up": with autoCleanup on, the merged worktree goes now
572
850
  // (a dirty one stays, reported); off, nothing is removed automatically.
851
+ // The merge is committed: a failed or refused cleanup (dirty, retained
852
+ // file recovery data, ...) is a cleanup notice, never a merge failure.
573
853
  if (worktreeSettings().autoCleanup !== true) {
574
- return { ...merged, cleanup: { removed: false, reason: 'auto-cleanup-off' } };
854
+ return {
855
+ ...merged,
856
+ cleanup: { removed: false, reason: 'auto-cleanup-off', message: 'Auto cleanup is off; the worktree is kept.' },
857
+ };
575
858
  }
859
+ // The cleanup never moves a session: while this session still works in the
860
+ // merged folder (or any other session uses it) the removal is refused.
576
861
  try {
577
- const removed = await removeWorktree({ force: false }, { ownTurn });
862
+ if (isWorktreeBound(currentWorkspace(session))) {
863
+ throw worktreeRefusal('folder-in-use', { sessions: [session.id] });
864
+ }
865
+ const entry = await (await backend()).getSessionWorktree(session.id);
866
+ const removed = await withManagementFolders(
867
+ entry ? [entry.path] : [],
868
+ true,
869
+ () => removeWorktree({ force: false }, { ownTurn }),
870
+ { actor: session.id }
871
+ );
578
872
  return { ...merged, cleanup: removed.removed, revision: removed.revision, workspace: removed.workspace };
579
873
  } catch (error) {
580
- if (!isWorktreeError(error, 'WORKTREE_DIRTY') && !isWorktreeError(error, 'WORKTREE_UNMERGED')) throw error;
581
- return { ...merged, cleanup: { removed: false, reason: error.code } };
874
+ // The merge stands: a refused or incomplete cleanup (in use, dirty,
875
+ // unmerged, retained file recovery data, partly removed, …) is
876
+ // reported, never thrown, with the workspace as it is now.
877
+ const workspace = currentWorkspace(session);
878
+ const code = typeof error?.code === 'string' ? error.code : '';
879
+ return {
880
+ ...merged,
881
+ cleanup: {
882
+ removed: false,
883
+ reason: code || 'WORKTREE_CLEANUP_FAILED',
884
+ ...(code ? { code } : {}),
885
+ message: String(error?.message || error),
886
+ },
887
+ revision: workspace.revision,
888
+ workspace,
889
+ };
582
890
  }
583
891
  }
584
892
 
585
893
  /**
586
894
  * The merge itself. The retained worktree must belong to this session's
587
895
  * Project (same repository and Project folder — a Project switch may have
588
- * left it behind): its recorded project folder is the destination that is
589
- * guarded, compared with the confirmed target and merged into.
896
+ * left it behind); its branch, or the branch of the linked checkout the
897
+ * session works in, is merged into the project folder through the shared
898
+ * guarded path (mergeConfirmedTarget): both folders validated and held.
590
899
  */
591
900
  async function mergeRetainedWorktree(session, { target, ownTurn, expectedRevision }) {
592
901
  const workspace = currentWorkspace(session);
@@ -594,32 +903,72 @@ export function createWorkspaceTransitions({
594
903
  const leave = beginWorkspaceTransition(session.id, `merge:${newTxId()}`);
595
904
  try {
596
905
  await assertLeadIdle(session, { ownTurn: ownTurn === true });
597
- const backendApi = await backend();
598
- const entry = await backendApi.getSessionWorktree(session.id);
599
- if (!entry) throw worktreeError('WORKTREE_MISSING', 'This session has no worktree to merge.');
600
906
  const project = await inspectProject(workspace.projectPath);
601
- assertRetainedFits(entry, project, workspace.projectPath);
602
- if (!samePath(entry.projectPath, workspace.projectPath)) {
603
- throw worktreeError('WORKTREE_PROJECT_MISMATCH', undefined, {
604
- worktreeId: entry.id,
605
- worktreeProject: entry.projectPath,
606
- projectPath: workspace.projectPath,
607
- });
907
+ let branch;
908
+ if (!workspace.worktreeId && !samePath(workspace.cwd, workspace.projectPath)) {
909
+ const source = await inspectProject(workspace.cwd);
910
+ if (!samePath(source.repoCommonDir, project.repoCommonDir)) throw worktreeError('WORKTREE_PROJECT_MISMATCH');
911
+ branch = source.currentBranch;
912
+ } else {
913
+ const backendApi = await backend();
914
+ const entry = workspace.worktreeId
915
+ ? await backendApi.findWorktreeContaining(workspace.cwd)
916
+ : await backendApi.getSessionWorktree(session.id);
917
+ if (!entry) throw worktreeError('WORKTREE_MISSING', 'This session has no worktree to merge.');
918
+ assertRetainedFits(entry, project, workspace.projectPath);
919
+ if (!samePath(entry.projectPath, workspace.projectPath)) {
920
+ throw worktreeError('WORKTREE_PROJECT_MISMATCH', undefined, {
921
+ worktreeId: entry.id,
922
+ worktreeProject: entry.projectPath,
923
+ projectPath: workspace.projectPath,
924
+ });
925
+ }
926
+ branch = entry.branch;
608
927
  }
609
- assertMergeTarget(project.currentBranch, target);
610
- return await withProjectFolder(session.id, project.topLevel || workspace.projectPath, () =>
611
- backendApi.mergeWorktreeIntoProject({
612
- entryId: entry.id,
613
- target: project.currentBranch,
614
- confirmed: true,
615
- projectPath: entry.projectPath,
616
- })
928
+ return await mergeConfirmedTarget(
929
+ { projectPath: workspace.projectPath, branch, target },
930
+ (folders, removing, run) => withManagementFolders(folders, removing, run, { actor: session.id })
617
931
  );
618
932
  } finally {
619
933
  leave();
620
934
  }
621
935
  }
622
936
 
937
+ /**
938
+ * Move the hosted Lead to another Project folder (session set-project, the
939
+ * desktop/remote setCwd): the one authority for a Project switch, admitted
940
+ * like a workspace transition. Refused while a turn runs (`ownTurn`: the
941
+ * Lead's own tool call tolerates its calling turn), while workers run, and
942
+ * while the session works in a managed worktree. Serialized with turns and
943
+ * other workspace changes; the prompt refresh of the Lead and its idle
944
+ * workers completes (or rolls the switch back) before it resolves. Without
945
+ * a session (a draft) only the runtime cwd and the selection move.
946
+ * `classifyByMembership` (the desktop/remote move): a folder outside every
947
+ * registered Project is classified as a task (cwd-apply).
948
+ * @returns {Promise<string>} the runtime cwd after the switch
949
+ */
950
+ async function switchProject(cwd, { ownTurn = false, classifyByMembership = false } = {}) {
951
+ const selection = { classifyByMembership: classifyByMembership === true };
952
+ const session = getSession();
953
+ if (!session?.id) {
954
+ applyResolvedCwd(cwd, { persistProjectSelection: true, ...selection });
955
+ return getCurrentCwd();
956
+ }
957
+ const leave = beginWorkspaceTransition(session.id, `project:${newTxId()}`);
958
+ const journal = [];
959
+ try {
960
+ await assertLeadIdle(session, { ownTurn: ownTurn === true, shellJobs: false });
961
+ if (isWorktreeBound(readSessionWorkspace(session))) throw new Error(WORKTREE_BOUND_SWITCH);
962
+ await steps.switchProject(session, cwd, journal, selection);
963
+ return getCurrentCwd();
964
+ } catch (error) {
965
+ await undoAll(journal, error);
966
+ throw error;
967
+ } finally {
968
+ leave();
969
+ }
970
+ }
971
+
623
972
  async function removeWorktree({ force = false, expectedRevision } = {}, { ownTurn = false } = {}) {
624
973
  const expected = validRevision(expectedRevision);
625
974
  const session = hostedSession(null);
@@ -636,16 +985,22 @@ export function createWorkspaceTransitions({
636
985
  admitTurnWorkspace,
637
986
  /** The durable workspace record of the hosted session (null: project folder, never moved). */
638
987
  getWorkspace: () => getSession()?.workspace ?? null,
988
+ /** What the session snapshot publishes (see getLiveWorkspace). */
989
+ getLiveWorkspace,
639
990
  getBranchMenu,
640
991
  getProjectBranchMenu: projectBranches.getProjectBranchMenu,
641
992
  selectBranch,
642
993
  selectProjectBranch: projectBranches.selectProjectBranch,
643
994
  mergeProjectBranch: projectBranches.mergeProjectBranch,
995
+ inspectProjectBranch: projectBranches.inspectProjectBranch,
996
+ manageProjectBranch: projectBranches.manageProjectBranch,
644
997
  requestWorktree,
645
998
  mergeWorkspace,
646
999
  removeWorktree,
1000
+ switchProject,
647
1001
  listWorktrees,
648
1002
  pruneWorktrees,
649
1003
  cleanupDeletedSession,
1004
+ onWorktreeSetup,
650
1005
  };
651
1006
  }