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
@@ -6,14 +6,22 @@ import { PATCH_EDIT_MAX_BYTES } from './bounded-file-read.mjs';
6
6
  import { cleanString as clean } from './clean.mjs';
7
7
  import { runGitOffThread } from './git-runner.mjs';
8
8
  import { resolvePluginData } from './plugin-paths.mjs';
9
- import { normalizeChangeStatus, splitPatchSections } from './turn-changes.mjs';
9
+ import {
10
+ createReviewPatchBudget,
11
+ PATCH_TOO_LARGE,
12
+ patchOmittedFile,
13
+ REVIEW_FILE_PATCH_MAX_BYTES,
14
+ REVIEW_PATCH_MAX_BYTES,
15
+ reviewDiffTooLarge,
16
+ } from './review-diff.mjs';
17
+ import { splitPatchSections } from './turn-changes.mjs';
10
18
 
11
19
  const COMMAND_TIMEOUT_MS = 30_000;
12
20
  const COMMAND_MAX_BYTES = 8 * 1024 * 1024;
13
- const PATCH_MAX_BYTES = 2 * 1024 * 1024;
14
- // The complete (replay-safe) patch a sealing turn records; per-file and
15
- // per-session bounds are applied on top of this by the change record.
16
- const FREEZE_PATCH_MAX_BYTES = 64 * 1024 * 1024;
21
+ // Room for git's diagnostics beside a patch read up to its byte cap.
22
+ const PATCH_OUTPUT_SLACK_BYTES = 64 * 1024;
23
+ // Paths per patch read once the whole range overflowed (bounded command line).
24
+ const PATCH_BATCH_FILES = 32;
17
25
  const MAX_UNTRACKED_FILE_BYTES = 2 * 1024 * 1024;
18
26
  // Largest tool-supplied baseline kept for `hash-object`: the apply_patch edit
19
27
  // limit. (2–64 MiB explicit untracked edits keep their exact revert.)
@@ -32,9 +40,6 @@ const SHADOW_GC_PRUNE = '7.days.ago';
32
40
  // signal reports (an external editor, a command the shell classifies
33
41
  // read-only) still show within this gap.
34
42
  const MIN_RECAPTURE_GAP_MS = 15_000;
35
- // The same gap for a timer poll of a review the user has open. Shorter than
36
- // the desktop bar's 6 s poll, so each of those polls still captures.
37
- const VISIBLE_RECAPTURE_GAP_MS = 5_000;
38
43
  const states = new Map();
39
44
 
40
45
  function pathKey(value) {
@@ -44,7 +49,7 @@ function pathKey(value) {
44
49
 
45
50
  /** `resolve` plus symlinks of the nearest existing ancestor: git reports the
46
51
  * worktree root canonically (macOS /var -> /private/var), callers may not. */
47
- function canonicalPath(value, dirs = null) {
52
+ export function canonicalPath(value, dirs = null) {
48
53
  const full = resolve(value);
49
54
  if (dirs) {
50
55
  // Same result as the walk below without repeating it per file: the parent
@@ -529,7 +534,6 @@ function withOmittedBaselines(snapshot, review) {
529
534
  omitted: true,
530
535
  size,
531
536
  });
532
- if (review.patchOmitted) continue;
533
537
  const newHeader = present ? `b/${entry.path}` : '/dev/null';
534
538
  patch +=
535
539
  `diff --git a/${entry.path} b/${entry.path}\n` +
@@ -538,19 +542,7 @@ function withOmittedBaselines(snapshot, review) {
538
542
  `Binary files a/${entry.path} and ${newHeader} differ\n`;
539
543
  }
540
544
  files.sort((left, right) => left.path.localeCompare(right.path));
541
- return { ...review, files, patch };
542
- }
543
-
544
- /** Revert never claims success for a path whose baseline bytes were not captured. */
545
- function assertRevertable(snapshot, targets) {
546
- for (const target of targets) {
547
- const entry = snapshot.baselineFiles.get(pathKey(target));
548
- if (entry?.omitted === true) {
549
- throw new Error(
550
- `turn review revert is unavailable for ${target}: binary/large file content was not captured (${Number(entry.size) || 0} bytes)`
551
- );
552
- }
553
- }
545
+ return { ...review, files, patch, diffTooLarge: reviewDiffTooLarge(files, patch) };
554
546
  }
555
547
 
556
548
  async function applyBaselineFilesUnlocked(state, tree, allEntries) {
@@ -694,9 +686,98 @@ function parseNumstat(text) {
694
686
  return out;
695
687
  }
696
688
 
697
- async function diffTreesUnlocked(state, baselineTree, currentTree, paths = null, { omitPatch = false } = {}) {
689
+ const literalPathspec = (path) => `:(literal)${path}`;
690
+
691
+ /** The `diff --git` sections of one patch read, keyed by path; null once its
692
+ * output passed `maxBytes`. */
693
+ async function patchSectionsByPath(state, baselineTree, currentTree, pathspec, maxBytes) {
694
+ let result;
695
+ try {
696
+ result = await runGit(
697
+ shadowArgs(state, [
698
+ 'diff',
699
+ '--no-ext-diff',
700
+ '--unified=3',
701
+ '--find-renames',
702
+ baselineTree,
703
+ currentTree,
704
+ '--',
705
+ ...pathspec,
706
+ ]),
707
+ { cwd: state.root, maxBytes: maxBytes + PATCH_OUTPUT_SLACK_BYTES }
708
+ );
709
+ } catch (error) {
710
+ if (error?.code === 'EMAXBUFFER') return null;
711
+ throw error;
712
+ }
713
+ const sections = new Map();
714
+ for (const section of splitPatchSections(Buffer.from(result.stdout, 'utf8'))) {
715
+ const path = section.newPath ?? section.oldPath;
716
+ if (path) sections.set(pathKey(path), section.patch);
717
+ }
718
+ return sections;
719
+ }
720
+
721
+ /** After the whole range overflowed: patches read in path batches, the
722
+ * smallest changes first, until the reply's total is spent. A batch that
723
+ * overflows is halved; a single file that does is too large. */
724
+ async function batchedPatchSections(state, baselineTree, currentTree, files, sections) {
725
+ const lines = (file) => (Number(file.additions) || 0) + (Number(file.deletions) || 0);
726
+ let remaining = REVIEW_PATCH_MAX_BYTES;
727
+ const read = async (batch) => {
728
+ if (batch.length === 0 || remaining <= 0) return;
729
+ const pathspec = batch.flatMap((file) => [file.path, file.oldPath].filter(Boolean).map(literalPathspec));
730
+ const found = await patchSectionsByPath(state, baselineTree, currentTree, pathspec, remaining);
731
+ if (!found) {
732
+ if (batch.length === 1) return;
733
+ const half = Math.ceil(batch.length / 2);
734
+ await read(batch.slice(0, half));
735
+ await read(batch.slice(half));
736
+ return;
737
+ }
738
+ for (const [key, section] of found) {
739
+ sections.set(key, section);
740
+ if (section.length <= REVIEW_FILE_PATCH_MAX_BYTES) remaining -= section.length;
741
+ }
742
+ };
743
+ // Every changed line costs at least its marker and newline: a file whose
744
+ // counts alone pass the per-file cap is never read.
745
+ const queue = files
746
+ .filter((file) => 2 * lines(file) <= REVIEW_FILE_PATCH_MAX_BYTES)
747
+ .sort((left, right) => lines(left) - lines(right));
748
+ for (let index = 0; index < queue.length && remaining > 0; index += PATCH_BATCH_FILES) {
749
+ await read(queue.slice(index, index + PATCH_BATCH_FILES));
750
+ }
751
+ }
752
+
753
+ /** Every file's patch within the reply caps. A file past the per-file cap or
754
+ * the remaining total is listed without one (`patchOmitted`, too large). */
755
+ async function boundedTreePatch(state, baselineTree, currentTree, pathspec, files) {
756
+ let sections = await patchSectionsByPath(state, baselineTree, currentTree, pathspec, COMMAND_MAX_BYTES);
757
+ // Read whole, every file has its section; read in batches, a file without
758
+ // one was too large or past the total.
759
+ const whole = Boolean(sections);
760
+ if (!sections) {
761
+ sections = new Map();
762
+ await batchedPatchSections(state, baselineTree, currentTree, files, sections);
763
+ }
764
+ const budget = createReviewPatchBudget();
765
+ const kept = [];
766
+ const bounded = files.map((file) => {
767
+ const section = sections.get(pathKey(file.path));
768
+ if (!section && whole) return file;
769
+ if (section && budget.admit(section.length)) {
770
+ kept.push(section);
771
+ return file;
772
+ }
773
+ return patchOmittedFile(file);
774
+ });
775
+ return { patch: Buffer.concat(kept).toString('utf8'), files: bounded };
776
+ }
777
+
778
+ async function diffTreesUnlocked(state, baselineTree, currentTree, paths = null) {
698
779
  if (!baselineTree || !currentTree || baselineTree === currentTree) {
699
- return { patch: '', files: [], patchTruncated: false, currentTree };
780
+ return { patch: '', files: [], patchTruncated: false, diffTooLarge: false, currentTree };
700
781
  }
701
782
  // A scoped review restricts the range to the paths its session owns: the
702
783
  // baseline describes the whole worktree, concurrent sessions included.
@@ -706,23 +787,6 @@ async function diffTreesUnlocked(state, baselineTree, currentTree, paths = null,
706
787
  runGit(shadowArgs(state, ['diff', '--name-status', '-z', ...rangeArgs]), { cwd: state.root }),
707
788
  runGit(shadowArgs(state, ['diff', '--numstat', '-z', ...rangeArgs]), { cwd: state.root }),
708
789
  ]);
709
- let patch = '';
710
- let patchTruncated = false;
711
- // A files-and-counts read skips the patch text, the one part whose cost
712
- // grows with the size of the change.
713
- if (!omitPatch) {
714
- try {
715
- const result = await runGit(shadowArgs(state, ['diff', '--no-ext-diff', '--unified=3', ...rangeArgs]), {
716
- cwd: state.root,
717
- maxBytes: PATCH_MAX_BYTES + 256 * 1024,
718
- });
719
- patch = result.stdout.length <= PATCH_MAX_BYTES ? result.stdout : result.stdout.slice(0, PATCH_MAX_BYTES);
720
- patchTruncated = result.stdout.length > PATCH_MAX_BYTES;
721
- } catch (error) {
722
- if (error?.code !== 'EMAXBUFFER') throw error;
723
- patchTruncated = true;
724
- }
725
- }
726
790
  const statuses = parseNameStatus(nameStatus.stdout);
727
791
  const stats = parseNumstat(numstat.stdout);
728
792
  const keys = [...new Set([...statuses.keys(), ...stats.keys()])];
@@ -740,83 +804,27 @@ async function diffTreesUnlocked(state, baselineTree, currentTree, paths = null,
740
804
  };
741
805
  })
742
806
  .sort((left, right) => left.path.localeCompare(right.path));
743
- return { patch, files, patchTruncated, currentTree, ...(omitPatch ? { patchOmitted: true } : {}) };
807
+ const bounded = await boundedTreePatch(state, baselineTree, currentTree, pathspec, files);
808
+ return {
809
+ patch: bounded.patch,
810
+ files: bounded.files,
811
+ patchTruncated: false,
812
+ diffTooLarge: reviewDiffTooLarge(bounded.files, bounded.patch),
813
+ currentTree,
814
+ };
744
815
  }
745
816
 
746
- /**
747
- * Freeze the snapshot's last captured net diff into replayable per-file
748
- * patches: one complete `--binary --full-index` diff (independent of the
749
- * bounded display patch), split back into its `diff --git` sections. `paths`
750
- * scopes a contended worktree to the session-owned files. Callers refresh the
751
- * snapshot first; this never captures. Files whose bytes cannot be replayed
752
- * (an uncaptured baseline, a type change, an over-limit diff) stay in the
753
- * record as non-revertable with a reason.
754
- */
755
- export async function freezeTurnWorktreeChanges(snapshot, paths = null) {
756
- if (!snapshot?.state || !snapshot.baselineTree) return null;
757
- const scope = Array.isArray(paths) ? [...new Set(paths.filter(Boolean))] : null;
758
- if (scope && scope.length === 0) return { root: snapshot.root, files: [] };
759
- return await withStateLock(snapshot.state, async () => {
760
- const { state, baselineTree, currentTree } = snapshot;
761
- let review = { files: [], patch: '', patchTruncated: false };
762
- let sections = [];
763
- let unavailable = '';
764
- if (currentTree && currentTree !== baselineTree) {
765
- review = await diffTreesUnlocked(state, baselineTree, currentTree, scope, { omitPatch: true });
766
- const args = [
767
- 'diff',
768
- '--binary',
769
- '--full-index',
770
- '--no-color',
771
- '--no-ext-diff',
772
- '--no-textconv',
773
- '--src-prefix=a/',
774
- '--dst-prefix=b/',
775
- '--find-renames',
776
- baselineTree,
777
- currentTree,
778
- '--',
779
- ...(scope || ['.']),
780
- ];
781
- try {
782
- const result = await runGit(shadowArgs(state, args), {
783
- cwd: state.root,
784
- maxBytes: FREEZE_PATCH_MAX_BYTES,
785
- stdoutEncoding: 'base64',
786
- });
787
- sections = splitPatchSections(Buffer.from(result.stdout, 'base64'));
788
- } catch (error) {
789
- if (error?.code !== 'EMAXBUFFER') throw error;
790
- unavailable = 'the turn changed too much to keep its patches for undo';
791
- }
792
- }
793
- const listed = withOmittedBaselines({ ...snapshot, scopePaths: scope }, { ...review, patchOmitted: true });
794
- const byPath = new Map();
795
- for (const section of sections) {
796
- const key = pathKey(section.newPath ?? section.oldPath ?? '');
797
- // A type change diffs as a delete plus an add of one path: not one patch.
798
- byPath.set(key, byPath.has(key) ? null : section.patch);
799
- }
800
- const files = (listed.files || []).map((file) => {
801
- const entry = {
802
- path: file.path,
803
- ...(file.oldPath ? { oldPath: file.oldPath } : {}),
804
- status: normalizeChangeStatus(file.status),
805
- additions: Number(file.additions) || 0,
806
- deletions: Number(file.deletions) || 0,
807
- ...(file.binary ? { binary: true } : {}),
808
- };
809
- if (entry.status !== 'R') delete entry.oldPath;
810
- if (file.omitted === true) {
811
- return { ...entry, revertable: false, reason: 'binary/large file content was not captured' };
812
- }
813
- if (file.status === 'T') return { ...entry, revertable: false, reason: 'the file type changed' };
814
- const patch = byPath.get(pathKey(file.path));
815
- if (!patch) return { ...entry, revertable: false, reason: unavailable || 'no replayable patch was recorded' };
816
- return { ...entry, revertable: true, patch };
817
- });
818
- return { root: snapshot.root, files };
819
- });
817
+ /** One file's patch between two trees (a rename read with its old path), up
818
+ * to `maxBytes`; past it, the file is too large. */
819
+ async function filePatchUnlocked(state, baselineTree, currentTree, path, oldPath, maxBytes) {
820
+ if (!baselineTree || !currentTree || baselineTree === currentTree) return { patch: '' };
821
+ const pathspec = [path, oldPath].filter(Boolean).map(literalPathspec);
822
+ const sections = await patchSectionsByPath(state, baselineTree, currentTree, pathspec, maxBytes);
823
+ const section = sections?.get(pathKey(path)) ?? (oldPath ? sections?.get(pathKey(oldPath)) : undefined);
824
+ if (!sections || (section && section.length > maxBytes)) {
825
+ return { patch: '', patchOmitted: true, reason: PATCH_TOO_LARGE };
826
+ }
827
+ return { patch: section ? section.toString('utf8') : '' };
820
828
  }
821
829
 
822
830
  // One maintenance pass per shadow repository per process, off the turn's
@@ -910,14 +918,8 @@ export async function createTurnWorktreeSnapshot(worktree) {
910
918
 
911
919
  /** Re-open a recorded baseline after the runtime lost its in-memory tracker.
912
920
  * The tree object is the durable half of a review; `paths` scopes both this
913
- * diff and any later revert to what the recording session actually owns.
914
- * `omitPatch` leaves out the patch text: only a snapshot read once and then
915
- * discarded may ask for that, never one a later refresh keeps updating. */
916
- export async function resumeTurnWorktreeSnapshot(
917
- worktree,
918
- baselineTree,
919
- { paths = null, baselineFiles = [], omitPatch = false } = {}
920
- ) {
921
+ * diff and any later revert to what the recording session actually owns. */
922
+ export async function resumeTurnWorktreeSnapshot(worktree, baselineTree, { paths = null, baselineFiles = [] } = {}) {
921
923
  const tree = clean(baselineTree);
922
924
  if (!tree) return null;
923
925
  const root = await repositoryRoot(worktree).catch(() => null);
@@ -927,14 +929,7 @@ export async function resumeTurnWorktreeSnapshot(
927
929
  return await withStateLock(
928
930
  state,
929
931
  async () => {
930
- await ensureState(state);
931
- // A collected or never-written baseline restores nothing. Report that as
932
- // "no snapshot" instead of failing every later call made against it.
933
- const kind = await runGit(shadowArgs(state, ['cat-file', '-t', tree]), {
934
- cwd: state.root,
935
- allowFailure: true,
936
- });
937
- if (kind.code !== 0 || clean(kind.stdout) !== 'tree') return null;
932
+ if (!(await recordedTreeUnlocked(state, tree))) return null;
938
933
  const scopePaths = Array.isArray(paths) && paths.length > 0 ? [...new Set(paths)] : null;
939
934
  const applied = await applyBaselineFilesUnlocked(state, tree, baselineFiles || []);
940
935
  const snapshot = {
@@ -953,10 +948,7 @@ export async function resumeTurnWorktreeSnapshot(
953
948
  const currentTree = await captureTreeUnlocked(state, snapshot.toolPaths, { after });
954
949
  Object.assign(
955
950
  snapshot,
956
- withOmittedBaselines(
957
- snapshot,
958
- await diffTreesUnlocked(state, snapshot.baselineTree, currentTree, scopePaths, { omitPatch })
959
- )
951
+ withOmittedBaselines(snapshot, await diffTreesUnlocked(state, snapshot.baselineTree, currentTree, scopePaths))
960
952
  );
961
953
  return snapshot;
962
954
  },
@@ -964,34 +956,55 @@ export async function resumeTurnWorktreeSnapshot(
964
956
  );
965
957
  }
966
958
 
967
- // Git's well-known empty tree: what an unborn HEAD (no commit yet) compares as.
968
- const EMPTY_TREE = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
969
-
970
- /** The files among `paths` whose bytes in the snapshot's last capture still
971
- * differ from the source repository's current HEAD (staged or not), with
972
- * their counts against HEAD; no patch text. An ignored file that HEAD does
973
- * not hold is no uncommitted change and is left out. */
974
- export async function diffTurnWorktreeHead(snapshot, paths) {
975
- const scope = [...new Set((paths || []).filter(Boolean))];
976
- if (!snapshot?.state || !snapshot.currentTree || scope.length === 0) return [];
977
- return await withStateLock(snapshot.state, async () => {
978
- const { state } = snapshot;
979
- const head = await runGit(['rev-parse', '--verify', '--quiet', 'HEAD^{tree}'], {
980
- cwd: state.root,
981
- allowFailure: true,
982
- });
983
- const headTree = head.code === 0 ? clean(head.stdout) : EMPTY_TREE;
984
- const { files } = await diffTreesUnlocked(state, headTree, snapshot.currentTree, scope, { omitPatch: true });
985
- const added = files.filter((file) => file.status === 'A').map((file) => file.path);
986
- if (added.length === 0) return files;
987
- const ignored = await runGit(['check-ignore', '-z', '--stdin'], {
988
- cwd: state.root,
989
- input: `${added.join('\0')}\0`,
990
- allowFailure: true,
991
- });
992
- const skip = new Set(splitNulList(ignored.stdout).map(pathKey));
993
- return files.filter((file) => file.status !== 'A' || !skip.has(pathKey(file.path)));
959
+ /** A collected or never-written baseline restores nothing: false reports it
960
+ * as "no snapshot" instead of failing every later call made against it. */
961
+ async function recordedTreeUnlocked(state, tree) {
962
+ await ensureState(state);
963
+ const kind = await runGit(shadowArgs(state, ['cat-file', '-t', tree]), {
964
+ cwd: state.root,
965
+ allowFailure: true,
994
966
  });
967
+ return kind.code === 0 && clean(kind.stdout) === 'tree';
968
+ }
969
+
970
+ /** One file's patch of a recorded baseline against the worktree now, up to
971
+ * `maxBytes`. `paths` is the recording session's scope, every target checked
972
+ * on its own: a file outside it answers with no patch, a rename source
973
+ * outside it is left out of the diff. Null when the baseline is gone. */
974
+ export async function resumeTurnWorktreeFilePatch(
975
+ worktree,
976
+ baselineTree,
977
+ { paths = null, baselineFiles = [], path, oldPath = '', maxBytes } = {}
978
+ ) {
979
+ const tree = clean(baselineTree);
980
+ if (!tree) return null;
981
+ const root = await repositoryRoot(worktree).catch(() => null);
982
+ if (!root) return null;
983
+ const state = stateForRoot(root);
984
+ const scope = Array.isArray(paths) && paths.length > 0 ? new Set(paths.map(pathKey)) : null;
985
+ const allowed = (rel) => !scope || scope.has(pathKey(rel));
986
+ const target = safeRelativePath(root, path);
987
+ if (!allowed(target)) return { patch: '' };
988
+ const source = clean(oldPath) ? safeRelativePath(root, oldPath) : '';
989
+ // Only authorized paths reach the diff.
990
+ const targets = source && allowed(source) && pathKey(source) !== pathKey(target) ? [target, source] : [target];
991
+ const keys = new Set(targets.map(pathKey));
992
+ const after = captureSequence(state);
993
+ return await withStateLock(
994
+ state,
995
+ async () => {
996
+ if (!(await recordedTreeUnlocked(state, tree))) return null;
997
+ // Only this file's recorded first states change its side of the tree.
998
+ const applied = await applyBaselineFilesUnlocked(
999
+ state,
1000
+ tree,
1001
+ (baselineFiles || []).filter((entry) => keys.has(pathKey(safeRelativePath(root, entry?.path))))
1002
+ );
1003
+ const currentTree = await captureTreeUnlocked(state, targets, { after });
1004
+ return await filePatchUnlocked(state, applied.tree, currentTree, targets[0], targets[1] || '', maxBytes);
1005
+ },
1006
+ 'file-patch'
1007
+ );
995
1008
  }
996
1009
 
997
1010
  /** What a capture starting now has seen: the change stamp, the source index
@@ -1001,11 +1014,11 @@ async function captureMark(state) {
1001
1014
  }
1002
1015
 
1003
1016
  /** Could the worktree differ from the snapshot's last capture? */
1004
- async function captureNeeded(snapshot, gapMs) {
1017
+ async function captureNeeded(snapshot) {
1005
1018
  const mark = snapshot.captured;
1006
1019
  if (!mark || snapshot.pendingBaselines.size > 0) return true;
1007
1020
  if (mark.stamp !== snapshot.state.changeStamp) return true;
1008
- if (Date.now() - mark.at >= gapMs) return true;
1021
+ if (Date.now() - mark.at >= MIN_RECAPTURE_GAP_MS) return true;
1009
1022
  return (await sourceIndexIdentity(snapshot.state)) !== mark.index;
1010
1023
  }
1011
1024
 
@@ -1037,13 +1050,10 @@ function startRefresh(snapshot) {
1037
1050
  /** Bring the snapshot up to date with the worktree. Single-flight: a call
1038
1051
  * made while a capture runs waits for it, then captures again only if a
1039
1052
  * change was reported after that capture began. Without a reported change,
1040
- * an index change or the recapture gap elapsed (VISIBLE_RECAPTURE_GAP_MS
1041
- * for an open review's poll, `visible`; else MIN_RECAPTURE_GAP_MS), the
1042
- * last capture stands. `force` always answers with a capture that began
1043
- * after this call. */
1044
- export async function refreshTurnWorktreeSnapshot(snapshot, { force = false, visible = false } = {}) {
1053
+ * an index change or MIN_RECAPTURE_GAP_MS elapsed, the last capture stands.
1054
+ * `force` always answers with a capture that began after this call. */
1055
+ export async function refreshTurnWorktreeSnapshot(snapshot, { force = false } = {}) {
1045
1056
  if (!snapshot?.state || !snapshot.baselineTree) return null;
1046
- const gapMs = visible ? VISIBLE_RECAPTURE_GAP_MS : MIN_RECAPTURE_GAP_MS;
1047
1057
  const calledAtSeq = snapshot.refreshSeq || 0;
1048
1058
  for (;;) {
1049
1059
  const flight = snapshot.refreshing;
@@ -1052,7 +1062,7 @@ export async function refreshTurnWorktreeSnapshot(snapshot, { force = false, vis
1052
1062
  if (flight.seq > calledAtSeq) return snapshot;
1053
1063
  continue;
1054
1064
  }
1055
- if (!force && !(await captureNeeded(snapshot, gapMs))) return snapshot;
1065
+ if (!force && !(await captureNeeded(snapshot))) return snapshot;
1056
1066
  if (snapshot.refreshing) continue;
1057
1067
  return await startRefresh(snapshot);
1058
1068
  }
@@ -1069,88 +1079,6 @@ function safeRelativePath(root, value) {
1069
1079
  return rel.replace(/\\/g, '/');
1070
1080
  }
1071
1081
 
1072
- async function restorePathFromTree(snapshot, rel) {
1073
- snapshot.state.lastCapture = null;
1074
- const listed = await runGit(
1075
- shadowArgs(snapshot.state, ['ls-tree', '-z', '--name-only', snapshot.baselineTree, '--', rel]),
1076
- { cwd: snapshot.root }
1077
- );
1078
- if (listed.stdout.split('\0').some((value) => value === rel)) {
1079
- await runGit(shadowArgs(snapshot.state, ['checkout', snapshot.baselineTree, '--', rel]), { cwd: snapshot.root });
1080
- return;
1081
- }
1082
- const target = resolve(snapshot.root, rel);
1083
- try {
1084
- const stat = await lstat(target);
1085
- if (stat.isDirectory()) throw new Error('turn review revert refuses to remove a directory');
1086
- await rm(target, { force: true });
1087
- } catch (error) {
1088
- if (error?.code !== 'ENOENT') throw error;
1089
- }
1090
- }
1091
-
1092
- async function revertPathsUnlocked(snapshot, targets) {
1093
- // Checked for every target before the first restore: no partial revert.
1094
- assertRevertable(snapshot, targets);
1095
- for (const target of targets) {
1096
- await restorePathFromTree(snapshot, target);
1097
- }
1098
- // Restores report no change signal; the next poll captures afresh.
1099
- snapshot.captured = null;
1100
- const currentTree = await captureTreeUnlocked(snapshot.state, snapshot.toolPaths);
1101
- Object.assign(
1102
- snapshot,
1103
- withOmittedBaselines(
1104
- snapshot,
1105
- await diffTreesUnlocked(snapshot.state, snapshot.baselineTree, currentTree, snapshot.scopePaths)
1106
- )
1107
- );
1108
- // The absolute paths now back at their baseline bytes.
1109
- return targets.map((target) => resolve(snapshot.root, target));
1110
- }
1111
-
1112
- export async function revertTurnWorktreeFile(snapshot, value) {
1113
- if (!snapshot?.state || !snapshot.baselineTree) throw new Error('turn worktree snapshot is unavailable');
1114
- await refreshTurnWorktreeSnapshot(snapshot, { force: true });
1115
- return await withStateLock(snapshot.state, async () => {
1116
- const rel = safeRelativePath(snapshot.root, value);
1117
- const entry = snapshot.files.find(
1118
- (file) => pathKey(file.path) === pathKey(rel) || pathKey(file.oldPath) === pathKey(rel)
1119
- );
1120
- const targets = [...new Set([entry?.path || rel, entry?.oldPath].filter(Boolean))].map((target) =>
1121
- safeRelativePath(snapshot.root, target)
1122
- );
1123
- return await revertPathsUnlocked(snapshot, targets);
1124
- });
1125
- }
1126
-
1127
- export async function revertTurnWorktreeSnapshot(snapshot) {
1128
- if (!snapshot?.state || !snapshot.baselineTree) throw new Error('turn worktree snapshot is unavailable');
1129
- await refreshTurnWorktreeSnapshot(snapshot, { force: true });
1130
- return await withStateLock(snapshot.state, async () => {
1131
- // Resolve and validate every path before the first mutation. Renames and
1132
- // copies contribute both sides so the worktree returns to the exact
1133
- // turn-start tree rather than leaving a destination behind.
1134
- const targets = [...new Set(snapshot.files.flatMap((file) => [file.path, file.oldPath]).filter(Boolean))].map(
1135
- (target) => safeRelativePath(snapshot.root, target)
1136
- );
1137
- return await revertPathsUnlocked(snapshot, targets);
1138
- });
1139
- }
1140
-
1141
- /** Restore only the listed paths. This is the session-owned revert: a shared
1142
- * worktree cannot attribute the whole-tree diff, but the paths this session's
1143
- * own tools wrote are exactly attributable. */
1144
- export async function revertTurnWorktreePaths(snapshot, values) {
1145
- if (!snapshot?.state || !snapshot.baselineTree) throw new Error('turn worktree snapshot is unavailable');
1146
- const requested = (Array.isArray(values) ? values : []).filter(Boolean);
1147
- if (requested.length === 0) throw new Error('turn review revert has no restorable files');
1148
- return await withStateLock(snapshot.state, async () => {
1149
- const targets = [...new Set(requested.map((value) => safeRelativePath(snapshot.root, value)))];
1150
- return await revertPathsUnlocked(snapshot, targets);
1151
- });
1152
- }
1153
-
1154
1082
  export function _resetTurnWorktreeSnapshotsForTest() {
1155
1083
  states.clear();
1156
1084
  }