mixdog 1.2.3 → 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 (465) hide show
  1. package/package.json +1 -1
  2. package/scripts/gate-local.mjs +6 -4
  3. package/scripts/lib/gate-scheduler.mjs +29 -11
  4. package/scripts/probe-provider-catalog.mjs +31 -0
  5. package/scripts/provider-pingpong-live.mjs +128 -38
  6. package/scripts/session-sweep.mjs +5 -25
  7. package/src/agents/maintainer/AGENT.md +1 -1
  8. package/src/agents/maintainer/agent.json +1 -1
  9. package/src/agents/reviewer/AGENT.md +2 -4
  10. package/src/agents/security/AGENT.md +1 -2
  11. package/src/agents/writer/AGENT.md +2 -3
  12. package/src/defaults/shipped-history.json +6 -1
  13. package/src/defaults/skills/image/SKILL.md +21 -23
  14. package/src/lib/keychain-cjs.cjs +13 -11
  15. package/src/rules/agent/AGENT.md +7 -5
  16. package/src/rules/lead/LEAD.md +7 -9
  17. package/src/rules/shared/45-destructive.md +4 -0
  18. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  19. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +28 -7
  20. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -11
  21. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +101 -23
  22. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +2 -0
  23. package/src/runtime/agent/orchestrator/providers/anthropic-api-key-fetch.mjs +36 -0
  24. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +1 -1
  25. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -3
  26. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  27. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +26 -44
  28. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2 -5
  29. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +4 -0
  30. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +41 -12
  31. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +13 -1
  32. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +81 -10
  33. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +109 -5
  34. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +2 -1
  35. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +107 -37
  36. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +4 -1
  37. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +3 -1
  38. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  39. package/src/runtime/agent/orchestrator/providers/cursor-native-context.mjs +48 -0
  40. package/src/runtime/agent/orchestrator/providers/cursor-wire-exec.mjs +144 -34
  41. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +28 -4
  42. package/src/runtime/agent/orchestrator/providers/cursor-wire-request.mjs +8 -4
  43. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +41 -11
  44. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +67 -5
  45. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +14 -4
  46. package/src/runtime/agent/orchestrator/providers/cursor.mjs +14 -1
  47. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +9 -6
  48. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -2
  49. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +26 -4
  50. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +12 -6
  51. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +14 -6
  52. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +4 -4
  53. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +1 -0
  54. package/src/runtime/agent/orchestrator/providers/gemini-rest-stream/watchdogs.mjs +16 -5
  55. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +6 -1
  56. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +22 -10
  57. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -2
  58. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +33 -7
  59. package/src/runtime/agent/orchestrator/providers/gemini.mjs +11 -2
  60. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  61. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +9 -2
  62. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +9 -5
  63. package/src/runtime/agent/orchestrator/providers/lib/request-compression.mjs +86 -0
  64. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +4 -2
  65. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -5
  66. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +7 -1
  67. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +60 -16
  68. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +11 -13
  69. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +30 -19
  70. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  71. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +5 -0
  72. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +42 -5
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +13 -9
  74. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +1 -3
  75. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +18 -7
  76. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +36 -3
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +51 -3
  78. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +11 -1
  79. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +64 -52
  80. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +3 -1
  81. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +2 -1
  82. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +7 -1
  83. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +1 -4
  84. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +0 -1
  85. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +7 -6
  86. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +13 -2
  87. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +4 -1
  88. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +1 -2
  89. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +5 -4
  90. package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -1
  91. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +2 -1
  92. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +11 -4
  93. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +14 -4
  94. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +15 -3
  95. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +6 -2
  96. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +8 -6
  97. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +4 -1
  98. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +30 -2
  99. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +3 -2
  100. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -3
  101. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +3 -1
  102. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge-contract.mjs +6 -0
  103. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +10 -10
  104. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +3 -1
  105. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +46 -8
  106. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -8
  107. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -2
  108. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +24 -0
  109. package/src/runtime/agent/orchestrator/session/cache/tool-result-reuse.mjs +10 -2
  110. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -3
  111. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -11
  112. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +6 -22
  113. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -0
  114. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +16 -2
  115. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +28 -0
  116. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  117. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +0 -6
  118. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +0 -6
  119. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +1 -1
  120. package/src/runtime/agent/orchestrator/session/historical-session-closure.mjs +10 -0
  121. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +2 -5
  122. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +2 -4
  123. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +3 -3
  124. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +0 -27
  125. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +1 -1
  126. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -10
  127. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -9
  128. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +4 -1
  129. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +4 -1
  130. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +1 -4
  131. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +76 -0
  132. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +5 -1
  133. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +8 -9
  134. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +6 -0
  135. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -2
  136. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +1 -4
  137. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -4
  138. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +33 -3
  139. package/src/runtime/agent/orchestrator/session/manager/ask-support.mjs +0 -4
  140. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +21 -1
  141. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +38 -13
  142. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +33 -0
  143. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +5 -0
  144. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +19 -1
  145. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +57 -13
  146. package/src/runtime/agent/orchestrator/session/manager/failed-turn-rewind.mjs +16 -0
  147. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +6 -120
  148. package/src/runtime/agent/orchestrator/session/manager/pending-persist-queue.mjs +1 -1
  149. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +29 -8
  150. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +42 -49
  151. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +50 -0
  152. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +32 -14
  153. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +1 -1
  154. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +17 -33
  155. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +29 -13
  156. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -3
  157. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +45 -0
  158. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -9
  159. package/src/runtime/agent/orchestrator/session/send-instrumentation.mjs +2 -1
  160. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -2
  161. package/src/runtime/agent/orchestrator/session/side-question.mjs +12 -7
  162. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +5 -12
  163. package/src/runtime/agent/orchestrator/session/store/lifecycle-read.mjs +1 -1
  164. package/src/runtime/agent/orchestrator/session/store/listing.mjs +2 -6
  165. package/src/runtime/agent/orchestrator/session/store/live-cache-eviction.mjs +1 -1
  166. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +46 -37
  167. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +1 -1
  169. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +5 -11
  170. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +59 -0
  171. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +1 -1
  172. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +1 -1
  173. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +27 -32
  174. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +0 -8
  175. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +6 -18
  176. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +33 -106
  177. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +1 -1
  178. package/src/runtime/agent/orchestrator/session/store-agent-worker-pool.mjs +5 -8
  179. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +136 -196
  180. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +50 -116
  181. package/src/runtime/agent/orchestrator/session/store-summary-locations.mjs +3 -29
  182. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +1 -1
  183. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +7 -8
  184. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +9 -20
  185. package/src/runtime/agent/orchestrator/session/store.mjs +3 -16
  186. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +11 -12
  187. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +37 -13
  188. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +15 -4
  189. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +4 -2
  190. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +72 -15
  191. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +45 -0
  192. package/src/runtime/agent/orchestrator/stall-policy.mjs +50 -0
  193. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +5 -1
  194. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +6 -2
  195. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +204 -10
  196. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +160 -39
  197. package/src/runtime/agent/orchestrator/tools/builtin/git-partial-stage.mjs +7 -5
  198. package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +14 -5
  199. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +4 -3
  200. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +2 -1
  201. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-path-fanout.mjs +48 -44
  202. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +10 -3
  203. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +200 -17
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +5 -4
  205. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +6 -1
  206. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +20 -0
  207. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +101 -2
  208. package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
  209. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +67 -0
  210. package/src/runtime/agent/orchestrator/tools/lib/process-table-fixture.mjs +50 -0
  211. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +303 -63
  212. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -0
  213. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +108 -18
  214. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +77 -11
  215. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +81 -5
  216. package/src/runtime/attachments/store.d.mts +9 -0
  217. package/src/runtime/attachments/store.mjs +80 -9
  218. package/src/runtime/browser-bridge/browser-action-contract.d.mts +0 -1
  219. package/src/runtime/browser-bridge/browser-action-contract.mjs +0 -2
  220. package/src/runtime/computer-bridge/action-schema.mjs +178 -178
  221. package/src/runtime/computer-bridge/linux-readiness.d.mts +0 -2
  222. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -16
  223. package/src/runtime/effort-judge/judge-client.mjs +21 -4
  224. package/src/runtime/effort-judge/judge-worker.mjs +4 -1
  225. package/src/runtime/github/tool.mjs +118 -17
  226. package/src/runtime/media/adapters/codex-image.mjs +140 -21
  227. package/src/runtime/media/catalog.mjs +4 -4
  228. package/src/runtime/media/chatgpt-usage.mjs +55 -0
  229. package/src/runtime/media/defaults.mjs +37 -0
  230. package/src/runtime/media/jobs.mjs +12 -2
  231. package/src/runtime/media/lanes.mjs +12 -0
  232. package/src/runtime/media/tool-defs.mjs +15 -4
  233. package/src/runtime/media/tool.mjs +41 -12
  234. package/src/runtime/media/upstream-error.mjs +72 -6
  235. package/src/runtime/memory/lib/ingest/transcript-rows.mjs +1 -0
  236. package/src/runtime/memory/lib/pg/process.mjs +5 -7
  237. package/src/runtime/memory/lib/pg/supervisor.mjs +4 -1
  238. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  239. package/src/runtime/office/authoring/html-browser.mjs +18 -8
  240. package/src/runtime/office/authoring/pdf-html-runner.mjs +1 -1
  241. package/src/runtime/office/authoring/pptx-html-measure.mjs +1 -1
  242. package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
  243. package/src/runtime/office/core/office-write-ledger.mjs +1 -5
  244. package/src/runtime/office/index.mjs +2 -3
  245. package/src/runtime/office/pdf/pdf-analysis.mjs +0 -68
  246. package/src/runtime/session-search/session-search-ingest.mjs +1 -1
  247. package/src/runtime/shared/agent-reap-state.mjs +13 -0
  248. package/src/runtime/shared/atomic-file.d.mts +1 -1
  249. package/src/runtime/shared/background-tasks.mjs +6 -1
  250. package/src/runtime/shared/bounded-line-diff.mjs +11 -2
  251. package/src/runtime/shared/browser-launch.mjs +15 -0
  252. package/src/runtime/shared/err-text.mjs +42 -4
  253. package/src/runtime/shared/file-lock.mjs +6 -5
  254. package/src/runtime/shared/llm/anthropic-betas.mjs +1 -2
  255. package/src/runtime/shared/llm/provider-model-identities.mjs +1 -0
  256. package/src/runtime/shared/model-route-chain.d.mts +8 -0
  257. package/src/runtime/shared/model-route-chain.mjs +48 -0
  258. package/src/runtime/shared/model-route-fallback.mjs +22 -0
  259. package/src/runtime/shared/pid-liveness.mjs +12 -0
  260. package/src/runtime/shared/provider-api-key.mjs +6 -0
  261. package/src/runtime/shared/provider-timeout-phase.mjs +17 -0
  262. package/src/runtime/shared/quiet-progress.d.mts +35 -0
  263. package/src/runtime/shared/quiet-progress.mjs +101 -0
  264. package/src/runtime/shared/quota-resume-store.mjs +32 -1
  265. package/src/runtime/shared/read-row-numbers.mjs +44 -0
  266. package/src/runtime/shared/remote-intent.mjs +2 -42
  267. package/src/runtime/shared/slow-span.mjs +8 -1
  268. package/src/runtime/shared/statusline/statusline-segments.mjs +24 -2
  269. package/src/runtime/shared/tool-card-model/card-header.mjs +2 -1
  270. package/src/runtime/shared/tool-output-budget.mjs +2 -0
  271. package/src/runtime/shared/tool-result-summary.mjs +16 -2
  272. package/src/runtime/shared/tool-status.mjs +3 -2
  273. package/src/runtime/shared/tool-surface.mjs +2 -3
  274. package/src/runtime/shared/tool-work-units.mjs +22 -15
  275. package/src/runtime/shared/transcript-metadata.mjs +49 -1
  276. package/src/runtime/shared/transcript-turn-keys.mjs +33 -0
  277. package/src/runtime/shared/transcript-writer/transcript-file.mjs +10 -1
  278. package/src/runtime/shared/transcript-writer.mjs +14 -4
  279. package/src/runtime/shared/turn-changes.mjs +2 -1
  280. package/src/runtime/shared/turn-snapshot.mjs +11 -3
  281. package/src/runtime/shared/worktrees/activity-gate.mjs +175 -0
  282. package/src/runtime/shared/worktrees/branch-management.mjs +179 -0
  283. package/src/runtime/shared/worktrees/carry.mjs +6 -4
  284. package/src/runtime/shared/worktrees/contract.mjs +27 -1
  285. package/src/runtime/shared/worktrees/dependencies.mjs +456 -0
  286. package/src/runtime/shared/worktrees/file-recovery.mjs +29 -13
  287. package/src/runtime/shared/worktrees/git-head.mjs +22 -13
  288. package/src/runtime/shared/worktrees/include.mjs +125 -7
  289. package/src/runtime/shared/worktrees/lock.mjs +1 -1
  290. package/src/runtime/shared/worktrees/maintenance.mjs +20 -2
  291. package/src/runtime/shared/worktrees/manager.mjs +378 -32
  292. package/src/runtime/shared/worktrees/owner.mjs +2 -1
  293. package/src/runtime/shared/worktrees/preparation-report.mjs +79 -0
  294. package/src/runtime/shared/worktrees/setup-commands.mjs +232 -0
  295. package/src/runtime/shared/worktrees/workspace-visibility.mjs +17 -0
  296. package/src/runtime/terminal-bridge/client.mjs +14 -10
  297. package/src/session-runtime/boot/apis.mjs +7 -1
  298. package/src/session-runtime/boot/config.mjs +2 -0
  299. package/src/session-runtime/boot/facade.mjs +3 -0
  300. package/src/session-runtime/boot/session.mjs +3 -2
  301. package/src/session-runtime/boot/tools.mjs +3 -0
  302. package/src/session-runtime/conversation-import/service.mjs +1 -1
  303. package/src/session-runtime/goal-facade-api.mjs +2 -2
  304. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +44 -18
  305. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +4 -1
  306. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +22 -8
  307. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  308. package/src/session-runtime/lifecycle/cold-heir.mjs +0 -1
  309. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -16
  310. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +18 -53
  311. package/src/session-runtime/lifecycle/session-switch.mjs +1 -1
  312. package/src/session-runtime/lifecycle/shared.mjs +5 -6
  313. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -5
  314. package/src/session-runtime/lifecycle/teardown.mjs +7 -16
  315. package/src/session-runtime/media-api.mjs +8 -0
  316. package/src/session-runtime/model-route/route-ownership.mjs +60 -0
  317. package/src/session-runtime/model-route/route-persist.mjs +3 -2
  318. package/src/session-runtime/model-route/set-route.mjs +114 -34
  319. package/src/session-runtime/model-route/web-search-route.mjs +7 -2
  320. package/src/session-runtime/model-route-api.mjs +4 -2
  321. package/src/session-runtime/native-web-search/routes.mjs +37 -24
  322. package/src/session-runtime/native-web-search.mjs +9 -8
  323. package/src/session-runtime/provider-auth/setup.mjs +4 -0
  324. package/src/session-runtime/provider-models/catalog-load.mjs +9 -0
  325. package/src/session-runtime/provider-models/web-search-catalog.mjs +23 -3
  326. package/src/session-runtime/provider-models.mjs +1 -0
  327. package/src/session-runtime/provider-usage.mjs +4 -0
  328. package/src/session-runtime/route-resolution.mjs +3 -1
  329. package/src/session-runtime/runtime-core.mjs +4 -0
  330. package/src/session-runtime/runtime-facade.mjs +6 -0
  331. package/src/session-runtime/services/agent-task-status.mjs +2 -0
  332. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +0 -3
  333. package/src/session-runtime/services/agent-tool/close-flow.mjs +6 -7
  334. package/src/session-runtime/services/agent-tool/execute-send.mjs +2 -2
  335. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +36 -3
  336. package/src/session-runtime/services/agent-tool/execute.mjs +9 -1
  337. package/src/session-runtime/services/agent-tool/helpers.mjs +30 -7
  338. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +7 -2
  339. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +6 -3
  340. package/src/session-runtime/services/agent-tool/lead-worker-index/lead-rows.mjs +3 -4
  341. package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +9 -3
  342. package/src/session-runtime/services/agent-tool/lead-worker-index/row-settlement.mjs +7 -18
  343. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +9 -6
  344. package/src/session-runtime/services/agent-tool/model-select.mjs +82 -0
  345. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -6
  346. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -1
  347. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -5
  348. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -4
  349. package/src/session-runtime/services/agent-tool/spawn-flow.mjs +2 -1
  350. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  351. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +1 -3
  352. package/src/session-runtime/services/agent-tool/tag-registry/tag-refresh.mjs +1 -3
  353. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -9
  354. package/src/session-runtime/services/agent-tool/terminal-reaper/scan-admission.mjs +8 -41
  355. package/src/session-runtime/services/agent-tool/terminal-reaper/stale-rows.mjs +3 -3
  356. package/src/session-runtime/services/agent-tool/terminal-reaper.mjs +6 -23
  357. package/src/session-runtime/services/agent-tool/terminal-trace.mjs +0 -1
  358. package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
  359. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +32 -20
  360. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -2
  361. package/src/session-runtime/services/agent-tool/worker-index.mjs +28 -8
  362. package/src/session-runtime/services/agent-tool.mjs +4 -0
  363. package/src/session-runtime/services/agent-watchdog-registry.mjs +2 -0
  364. package/src/session-runtime/services/provider-admin.mjs +77 -0
  365. package/src/session-runtime/session-create/session-options.mjs +7 -5
  366. package/src/session-runtime/session-create/session-start-hook.mjs +2 -1
  367. package/src/session-runtime/session-transcript.mjs +4 -5
  368. package/src/session-runtime/session-turn-api.mjs +3 -9
  369. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -6
  370. package/src/session-runtime/setup-tool/executor.mjs +23 -5
  371. package/src/session-runtime/setup-tool/extended-actions.mjs +6 -6
  372. package/src/session-runtime/setup-tool/settings-contract.mjs +7 -2
  373. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -1
  374. package/src/session-runtime/tool-policy-refresh.mjs +83 -32
  375. package/src/session-runtime/turn/agent-ops.mjs +49 -2
  376. package/src/session-runtime/turn/side-question-ops.mjs +1 -4
  377. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +2 -0
  378. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +4 -0
  379. package/src/session-runtime/turn/turn-run/turn-settle.mjs +8 -2
  380. package/src/session-runtime/turn/turn-run.mjs +1 -36
  381. package/src/session-runtime/usage-stats-api.mjs +4 -1
  382. package/src/session-runtime/workflow-agents-api/agent-route.mjs +16 -1
  383. package/src/session-runtime/workspace/admission-gate.mjs +44 -15
  384. package/src/session-runtime/workspace/project-branches.mjs +28 -36
  385. package/src/session-runtime/workspace/transition-steps.mjs +96 -95
  386. package/src/session-runtime/workspace/transitions.mjs +248 -68
  387. package/src/standalone/channel-transport.mjs +3 -4
  388. package/src/standalone/daemon-desktop-runtime.mjs +32 -1
  389. package/src/standalone/daemon-pg-stop.mjs +1 -3
  390. package/src/standalone/daemon-session-control.mjs +88 -0
  391. package/src/standalone/daemon-stored-session-views.mjs +23 -3
  392. package/src/standalone/daemon.mjs +2 -0
  393. package/src/standalone/local-session-runtime.mjs +11 -12
  394. package/src/standalone/session-protocol.mjs +7 -0
  395. package/src/standalone/session-runtime-inline-host.mjs +2 -0
  396. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +91 -49
  397. package/src/standalone/session-service/agent-tree/agent-child.mjs +19 -1
  398. package/src/standalone/session-service/agent-tree/agent-registry.mjs +25 -0
  399. package/src/standalone/session-service/agent-tree/agent-turns.mjs +9 -1
  400. package/src/standalone/session-service/agent-tree.mjs +28 -2
  401. package/src/standalone/session-service/entries/session-loads.mjs +16 -5
  402. package/src/standalone/session-service/entries.mjs +1 -0
  403. package/src/standalone/session-service/projection/transcript-window.mjs +39 -0
  404. package/src/standalone/session-service/quota-resume.mjs +28 -13
  405. package/src/standalone/session-service/session-calls/session-turns.mjs +17 -6
  406. package/src/standalone/session-service/session-calls/session-views.mjs +6 -0
  407. package/src/standalone/session-tool-output.mjs +82 -0
  408. package/src/tui/app/app-view.jsx +2 -1
  409. package/src/tui/app/provider-setup/provider-items.mjs +8 -0
  410. package/src/tui/app/provider-setup-picker.mjs +15 -3
  411. package/src/tui/app/slash-commands.mjs +6 -0
  412. package/src/tui/app/slash-dispatch/session-commands.mjs +49 -0
  413. package/src/tui/components/Spinner.jsx +4 -0
  414. package/src/tui/components/SpinnerByline.jsx +21 -2
  415. package/src/tui/components/status-line/local-line.mjs +10 -2
  416. package/src/tui/dist/index.mjs +478 -251
  417. package/src/tui/session/active-tool-summary.mjs +1 -1
  418. package/src/tui/session/context-state.mjs +0 -3
  419. package/src/tui/session/goal-continuation/continuation-queue.mjs +2 -3
  420. package/src/tui/session/goal-continuation/deadline-delivery.mjs +4 -2
  421. package/src/tui/session/goal-continuation/session-boundary.mjs +21 -0
  422. package/src/tui/session/quota-resume.mjs +140 -61
  423. package/src/tui/session/session-api/commands.mjs +4 -10
  424. package/src/tui/session/session-api/controls.mjs +12 -0
  425. package/src/tui/session/session-api/lifecycle/dispose.mjs +2 -9
  426. package/src/tui/session/session-api/lifecycle/resume.mjs +2 -7
  427. package/src/tui/session/session-api/lifecycle.mjs +13 -11
  428. package/src/tui/session/session-api/media.mjs +2 -0
  429. package/src/tui/session/session-api/routes.mjs +81 -57
  430. package/src/tui/session/session-api/settings.mjs +3 -3
  431. package/src/tui/session/session-api/worktree.mjs +3 -2
  432. package/src/tui/session/session-flow/auto-clear.mjs +1 -3
  433. package/src/tui/session/session-flow/drain.mjs +6 -4
  434. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -0
  435. package/src/tui/session/session-flow/queue/take-entries.mjs +2 -1
  436. package/src/tui/session/session-flow/queue.mjs +1 -1
  437. package/src/tui/session/tool-approval.mjs +17 -8
  438. package/src/tui/session/transcript-store/streaming-tail.mjs +1 -1
  439. package/src/tui/session/tui-steering-persist.mjs +3 -5
  440. package/src/tui/session/turn-quiet.mjs +53 -0
  441. package/src/tui/session/turn-stream.mjs +5 -1
  442. package/src/tui/session/turn.mjs +38 -31
  443. package/src/tui/session/worktree-setup-notice.mjs +38 -0
  444. package/src/tui/spinner-meta.mjs +10 -0
  445. package/src/tui/spinner-verbs.mjs +3 -0
  446. package/src/ui/statusline.mjs +13 -3
  447. package/src/runtime/agent/orchestrator/providers/model-pricing-rates.mjs +0 -1
  448. package/src/runtime/agent/orchestrator/session/manager/foreign-pending-messages.mjs +0 -346
  449. package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +0 -117
  450. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +0 -302
  451. package/src/session-runtime/services/agent-tool/terminal-reaper/reap-timers.mjs +0 -142
  452. package/src/session-runtime/turn/share-ops.mjs +0 -77
  453. package/src/tui/session/cross-surface-share.mjs +0 -406
  454. package/src/tui/session/live-share/delta.mjs +0 -153
  455. package/src/tui/session/live-share/mirror.mjs +0 -106
  456. package/src/tui/session/live-share/owner.mjs +0 -254
  457. package/src/tui/session/live-share/retry.mjs +0 -54
  458. package/src/tui/session/live-share/viewer/frame-router.mjs +0 -32
  459. package/src/tui/session/live-share/viewer/pipe-client.mjs +0 -108
  460. package/src/tui/session/live-share/viewer/submit-acks.mjs +0 -65
  461. package/src/tui/session/live-share/viewer/sync-waiters.mjs +0 -53
  462. package/src/tui/session/live-share/viewer.mjs +0 -99
  463. package/src/tui/session/live-share/wire.mjs +0 -44
  464. package/src/tui/session/live-share.mjs +0 -154
  465. package/src/tui/session/shared-dir-watch.mjs +0 -69
@@ -1,406 +0,0 @@
1
- /**
2
- * src/tui/session/cross-surface-share.mjs - owner/viewer wiring for one session
3
- * opened on several surfaces (terminal + desktop pane).
4
- *
5
- * Presence + the durable pending spool remain the ownership/base layer; a
6
- * local pipe layer (live-share) streams frame deltas so co-open surfaces
7
- * mirror each other in real time.
8
- * - presence: mark OUR current session as held open (idle included) so a
9
- * cross-open elsewhere attaches as a viewer instead of splitting
10
- * ownership; cleared on session switch here and on dispose
11
- * (session-api-ext), with sidecar staleness covering crashes.
12
- * - owner leg: host the live pipe, push transcript/tail/spinner deltas,
13
- * and run foreign submits through the normal queue — full user bubble +
14
- * streaming on every surface. The spool drain stays as the fallback
15
- * intake (instant via fs.watch, 3s tick as safety net).
16
- * - viewer leg: connect to the owner's pipe and mirror its live state.
17
- * While the pipe is up the disk-mtime re-resume is skipped (no turn-end
18
- * flicker); when the owner disappears the quiet re-resume promotes this
19
- * surface to real ownership.
20
- */
21
- import { statSync } from 'node:fs';
22
- import { basename, dirname } from 'node:path';
23
- import { sessionPath } from '../../runtime/agent/orchestrator/session/store/paths-heartbeat.mjs';
24
- import { createLiveShare, forwardViewerSubmit, liveSharePipePath } from './live-share.mjs';
25
- import { promptDisplayText } from './queue-helpers.mjs';
26
- import { sharedDirWatch } from './shared-dir-watch.mjs';
27
-
28
- const SPOOL_WATCH_DEBOUNCE_MS = 120;
29
- const OWNER_CLOSED_PROMOTE_DELAY_MS = 1500;
30
- const REMOTE_ATTACH_TICK_MS = 3000;
31
- // A healthy local owner serves its full frame on connect within tens of ms; a
32
- // dead presence sidecar or an owner blocked mid-turn never will. The old
33
- // 1500ms default made exactly those sessions stall entry for the full budget
34
- // (measured 1571/1519ms resumes — user: 세션 로드가 가끔 매우 느림). Cap the
35
- // boundary wait low: late owner frames still land through viewerApply and
36
- // simply replace the disk restore when they arrive.
37
- const VIEWER_SYNC_WAIT_MS = 400;
38
-
39
- // The spool drain waits for its cross-process lock OFF the event loop now, so
40
- // a watch event and the 3s tick can overlap: one drain at a time.
41
- function createRemoteInjectionDrain({ runtime, bag }) {
42
- let inFlight = null;
43
- return () => {
44
- if (inFlight) return inFlight;
45
- const run = (async () => {
46
- const injected = (await runtime.takeRemoteInjections?.()) || [];
47
- if (injected.length === 0) return;
48
- for (const item of injected) {
49
- if (!item || typeof item !== 'object' || (item.text == null && item.content == null)) continue;
50
- const content = item.content ?? item.text;
51
- const id = typeof item.id === 'string' && item.id.trim() ? item.id.trim() : undefined;
52
- bag.enqueue(content, {
53
- ...(item.options && typeof item.options === 'object' ? item.options : {}),
54
- ...(item.text ? { displayText: item.text } : {}),
55
- ...(id ? { id } : {}),
56
- });
57
- }
58
- void bag.drain();
59
- })().catch(() => {
60
- /* the watch/tick pair retries */
61
- });
62
- const tracked = run.finally(() => {
63
- if (inFlight === tracked) inFlight = null;
64
- });
65
- inFlight = tracked;
66
- return tracked;
67
- };
68
- }
69
-
70
- const quietResume = (api, id) =>
71
- void Promise.resolve(api.resume(id, { quiet: true })).catch(() => {
72
- /* next tick retries */
73
- });
74
-
75
- function createSessionLiveShare({ api, bag, flags, getState, getPublishedState, listeners, set, createShare }) {
76
- const liveShare = createShare({
77
- ownerSessionId: () => {
78
- const state = getState();
79
- return flags.disposed || flags.pendingSessionReset || state.sessionRemoteAttached
80
- ? ''
81
- : String(state.sessionId || '');
82
- },
83
- viewerSessionId: () => {
84
- const state = getState();
85
- return flags.disposed || !state.sessionRemoteAttached ? '' : String(state.sessionId || '');
86
- },
87
- socketPathFor: (id) => liveSharePipePath(id, sessionPath(id)),
88
- getPublishedState,
89
- listeners,
90
- onRemoteSubmit: (prompt, meta) => {
91
- // A refusal must be REPORTED, never silent. This session runtime can be unable to
92
- // take a foreign prompt (disposed, or it became an attached viewer
93
- // itself); swallowing it here is what made a submitted message vanish
94
- // with no transcript row and no error (user: 입력이 씹힘). The ack sent
95
- // by live-share carries this verdict back so the sender can re-deliver.
96
- if (flags.disposed || getState().sessionRemoteAttached) return false;
97
- // Preserve the viewer's submission id end-to-end: the queue entry and
98
- // the settled user item then carry the id the submitting surface used
99
- // for its optimistic row, so that row releases instead of duplicating.
100
- const queued = bag.enqueue(prompt, meta && typeof meta === 'object' ? meta : {}) !== false;
101
- void bag.drain();
102
- return queued;
103
- },
104
- onRemoteAbort: () => {
105
- // Forwarded viewer stop: interrupt OUR active turn (we are the owner).
106
- if (flags.disposed || getState().sessionRemoteAttached) return;
107
- try {
108
- api.abort?.();
109
- } catch {
110
- /* abort is best-effort */
111
- }
112
- },
113
- onOwnerClosed: (id) => {
114
- // Owner left (clean close or crash): promote via the normal quiet
115
- // re-resume once its final save/presence-clear has landed.
116
- const timer = setTimeout(() => {
117
- const state = getState();
118
- if (flags.disposed || !state.sessionRemoteAttached) return;
119
- if (String(state.sessionId || '') !== id) return;
120
- if (liveShare.viewerConnected()) return;
121
- quietResume(api, id);
122
- }, OWNER_CLOSED_PROMOTE_DELAY_MS);
123
- timer.unref?.();
124
- },
125
- viewerApply: {
126
- getState,
127
- set,
128
- replaceItems: (...args) => bag.replaceItems(...args),
129
- patchItem: (...args) => bag.patchItem(...args),
130
- appendItems: (...args) => bag.appendItems(...args),
131
- updateStreamingTail: (...args) => bag.updateStreamingTail(...args),
132
- clearStreamingTail: (...args) => bag.clearStreamingTail(...args),
133
- },
134
- });
135
- return liveShare;
136
- }
137
-
138
- // Viewer legs ride the owner's pipe (instant user bubble + shared streaming);
139
- // the durable spool remains the fallback. Every intake boundary the daemon or
140
- // UI can reach (submit, submitAsync, abort) is wrapped, otherwise a hosted
141
- // viewer queues the prompt locally and its own user row stands beside the
142
- // owner's mirrored twin.
143
- function wrapViewerApi({ api, bag, runtime, liveShare, getState, ensureLiveShare }) {
144
- // Returns null when this surface is NOT an attached viewer, so the local
145
- // session runtime keeps the prompt.
146
- const viewerSubmitIntake = (prompt, options = {}) => {
147
- if (!getState().sessionRemoteAttached) return null;
148
- const text = String(promptDisplayText(prompt, options) || '').trim();
149
- if (!text) return { accepted: false };
150
- return {
151
- accepted: forwardViewerSubmit({
152
- prompt,
153
- text,
154
- options,
155
- share: liveShare,
156
- // Writing to the owner's spool instead of starting a fake local turn
157
- // that would render an error/synthetic assistant message here.
158
- spool: (submissionId) =>
159
- runtime.enqueueRemoteAttachedPrompt?.({
160
- content: prompt,
161
- text,
162
- id: submissionId,
163
- options,
164
- }) === true,
165
- }),
166
- };
167
- };
168
- if (typeof api.submit === 'function') {
169
- const baseSubmit = api.submit;
170
- api.submit = (prompt, options = {}) => {
171
- const forwarded = viewerSubmitIntake(prompt, options);
172
- return forwarded ? forwarded.accepted : baseSubmit(prompt, options);
173
- };
174
- }
175
- if (typeof api.submitAsync === 'function') {
176
- const baseSubmitAsync = api.submitAsync;
177
- api.submitAsync = async (prompt, options = {}) => {
178
- const forwarded = viewerSubmitIntake(prompt, options);
179
- return forwarded ? forwarded.accepted : baseSubmitAsync(prompt, options);
180
- };
181
- }
182
- // Viewer stop button: the local session runtime has no in-flight turn to
183
- // cancel — forward the interrupt to the owner over the pipe. Falls back to
184
- // the local abort (no-op safe) when the pipe is down.
185
- if (typeof api.abort === 'function') {
186
- const baseAbort = api.abort;
187
- api.abort = (...args) => {
188
- if (getState().sessionRemoteAttached && liveShare.viewerConnected() && liveShare.sendAbort()) {
189
- return true;
190
- }
191
- return baseAbort(...args);
192
- };
193
- }
194
- // Attach-time pipe fast-path: session entry (resume) reconciles the live
195
- // pipe IMMEDIATELY instead of waiting for the 3s share tick. The attach
196
- // render comes from the last disk save WITHOUT the in-flight turn, so that
197
- // tick-wide window is exactly when a running tool call / mid-turn
198
- // conversation looks missing and then pops in late (user report). The
199
- // owner leg benefits equally: its pipe server starts the moment the
200
- // session opens, so cross-surface viewers can connect at once.
201
- for (const method of ['resume', 'newSession', 'switchContext']) {
202
- if (typeof api[method] !== 'function') continue;
203
- const base = api[method].bind(api);
204
- api[method] = async (...args) => {
205
- const result = await base(...args);
206
- bag.cancelQueuedGoalContinuations?.();
207
- bag.refreshGoalState?.();
208
- bag.scheduleGoalContinuation?.();
209
- ensureLiveShare();
210
- if (method === 'resume' && result === true && getState().sessionRemoteAttached) {
211
- const id = String(getState().sessionId || '');
212
- // The session projection holds renderer publications across resume.
213
- // Keep that hold until the owner's first FULL frame replaces the
214
- // persisted transcript, then synchronously publish the complete draft
215
- // before getState().
216
- if (id && (await liveShare.waitForViewerSync(id, VIEWER_SYNC_WAIT_MS))) bag.flushEmit();
217
- }
218
- return result;
219
- };
220
- }
221
- }
222
-
223
- // Instant input pickup: watch the shared pending spool so an attached
224
- // surface's fallback submit reaches this owner immediately instead of on the
225
- // 3s tick. Best-effort — the tick remains the safety net. The spool sits
226
- // directly in the data dir, so that is the narrowest directory to watch; the
227
- // handle is shared by every session in the process (shared-dir-watch.mjs)
228
- // and each session keeps its own filter/debounce below.
229
- function startSpoolWatcher({ runtime, flags, getState, drainRemoteInjections, watchDir }) {
230
- let release = null;
231
- let debounce = null;
232
- try {
233
- const spoolPath = String(runtime.pendingSpoolPath?.() || '');
234
- if (spoolPath) {
235
- const spoolFile = basename(spoolPath);
236
- release = watchDir(dirname(spoolPath), (_event, filename) => {
237
- if (filename && String(filename) !== spoolFile) return;
238
- if (flags.disposed || debounce) return;
239
- debounce = setTimeout(() => {
240
- debounce = null;
241
- if (flags.disposed || flags.pendingSessionReset) return;
242
- const state = getState();
243
- if (state.busy || state.commandBusy || state.sessionRemoteAttached) return;
244
- try {
245
- void drainRemoteInjections();
246
- } catch {
247
- /* tick fallback */
248
- }
249
- }, SPOOL_WATCH_DEBOUNCE_MS);
250
- debounce.unref?.();
251
- });
252
- }
253
- } catch {
254
- /* spool watch is an optimization; the 3s tick remains */
255
- }
256
- return {
257
- close: () => {
258
- release?.();
259
- release = null;
260
- if (debounce) {
261
- clearTimeout(debounce);
262
- debounce = null;
263
- }
264
- },
265
- };
266
- }
267
-
268
- // Viewer leg of the tick: follow the owner live over the pipe, otherwise
269
- // re-resume from disk when the owner saved or disappeared.
270
- function createViewerTick({ runtime, api, liveShare, getState }) {
271
- let storeMtime = 0;
272
- return {
273
- reset: () => {
274
- storeMtime = 0;
275
- },
276
- run: () => {
277
- const id = String(getState().sessionId || '');
278
- if (!id) return;
279
- // Pipe-connected viewers follow the owner live; the disk-mtime
280
- // re-resume would only reload mid-stream state and flicker.
281
- if (liveShare.viewerConnected()) {
282
- storeMtime = 0;
283
- return;
284
- }
285
- // Self-heal: a force-killed owner never announces onOwnerClosed and
286
- // its final save never bumps the store mtime, so without this probe
287
- // the surface stays a viewer forever, spooling messages to nobody.
288
- // When the resume guard says the owner is gone, promote via the same
289
- // quiet re-resume (it drains the pending spool on the next tick).
290
- if (runtime.sessionOwnerGone?.(id) === true) {
291
- storeMtime = 0;
292
- quietResume(api, id);
293
- return;
294
- }
295
- let mtime = 0;
296
- try {
297
- mtime = statSync(sessionPath(id)).mtimeMs || 0;
298
- } catch {
299
- return;
300
- }
301
- // First attached tick only baselines: the resume that attached this
302
- // surface already loaded the current on-disk transcript.
303
- if (!storeMtime) {
304
- storeMtime = mtime;
305
- return;
306
- }
307
- if (mtime > storeMtime) {
308
- storeMtime = mtime;
309
- quietResume(api, id);
310
- }
311
- },
312
- };
313
- }
314
-
315
- function startRemoteAttachTicker({ runtime, api, flags, getState, liveShare, spoolWatcher, drainRemoteInjections }) {
316
- let heldPresenceId = '';
317
- const viewerTick = createViewerTick({ runtime, api, liveShare, getState });
318
- const timer = setInterval(() => {
319
- if (flags.disposed) {
320
- clearInterval(timer);
321
- try {
322
- liveShare.dispose();
323
- } catch {
324
- /* best-effort */
325
- }
326
- spoolWatcher.close();
327
- return;
328
- }
329
- if (flags.pendingSessionReset) return;
330
- try {
331
- const heldId = runtime.publishSessionPresence?.() || '';
332
- if (heldPresenceId && heldPresenceId !== heldId) runtime.clearSessionPresence?.(heldPresenceId);
333
- heldPresenceId = heldId;
334
- } catch {
335
- /* best-effort */
336
- }
337
- try {
338
- liveShare.ensure();
339
- } catch {
340
- /* next tick retries */
341
- }
342
- try {
343
- const state = getState();
344
- if (state.busy || state.commandBusy) return;
345
- if (state.sessionRemoteAttached) {
346
- viewerTick.run();
347
- return;
348
- }
349
- viewerTick.reset();
350
- void drainRemoteInjections();
351
- } catch {
352
- /* best-effort */
353
- }
354
- }, REMOTE_ATTACH_TICK_MS);
355
- timer.unref?.();
356
- }
357
-
358
- export function attachCrossSurfaceShare({
359
- runtime,
360
- api,
361
- bag,
362
- flags,
363
- getState,
364
- getPublishedState,
365
- listeners,
366
- set,
367
- // Test seams: the pipe layer is replaced by a fake share in unit tests, and
368
- // the process-wide directory watch by an isolated registry.
369
- createShare = createLiveShare,
370
- watchDir = sharedDirWatch.subscribe,
371
- }) {
372
- const drainRemoteInjections = createRemoteInjectionDrain({ runtime, bag });
373
- const liveShare = createSessionLiveShare({
374
- api,
375
- bag,
376
- flags,
377
- getState,
378
- getPublishedState,
379
- listeners,
380
- set,
381
- createShare,
382
- });
383
- // Immediate live-share reconcile for session entry/promotion. Waiting for
384
- // the 3s share tick left a just-resumed live-owned session showing the
385
- // stale disk snapshot, then full-swapped the transcript mid-view once the
386
- // pipe finally connected (visible up/down lurch until heights resettled).
387
- // resume() calls this right after installing the restored items so the
388
- // owner's full frame lands at the entry boundary instead of seconds later.
389
- const ensureLiveShare = () => {
390
- try {
391
- liveShare.ensure();
392
- } catch {
393
- /* share tick retries */
394
- }
395
- };
396
- bag.ensureLiveShare = ensureLiveShare;
397
- // Pulse guard: while this surface is an attached viewer with a live pipe,
398
- // owner frames own stats/agent/tool state (see the runtime pulse timer).
399
- bag.liveShareMirroring = () => getState().sessionRemoteAttached && liveShare.viewerConnected();
400
- wrapViewerApi({ api, bag, runtime, liveShare, getState, ensureLiveShare });
401
- // Cover session runtimes whose runtime already has a session at construction
402
- // time; do not wait for a lifecycle method or the 3s safety pulse to open the pipe.
403
- ensureLiveShare();
404
- const spoolWatcher = startSpoolWatcher({ runtime, flags, getState, drainRemoteInjections, watchDir });
405
- startRemoteAttachTicker({ runtime, api, flags, getState, liveShare, spoolWatcher, drainRemoteInjections });
406
- }
@@ -1,153 +0,0 @@
1
- /**
2
- * src/tui/session/live-share/delta.mjs - owner-side frame shaping: the live
3
- * state subset mirrored to viewers, the full snapshot frame, and the
4
- * frame-to-frame delta against the last published baseline.
5
- */
6
- // Above this many patched rows per frame the delta degenerates to a full
7
- // items push (bulk rewrites: compaction, clear, history restore).
8
- const MAX_FRAME_PATCHES = 48;
9
-
10
- // Live-state mirror (attach parity): the transcript alone left an attached
11
- // viewer blind to the owner's activity — busy/stop state, the queued
12
- // follow-up list, the web-search summary, agent workers/jobs, and the
13
- // context gauge stats all live in owner process state. Mirror a compact
14
- // subset so viewer surfaces render them natively. queued entries are
15
- // projected to display fields only (content parts may carry images).
16
- const LIVE_STATS_KEYS = [
17
- 'currentContextSource',
18
- 'currentContextTokens',
19
- 'currentEstimatedContextTokens',
20
- 'currentContextUpdatedAt',
21
- 'costUsd',
22
- 'turns',
23
- 'inputTokens',
24
- 'outputTokens',
25
- 'latestInputTokens',
26
- 'latestPromptTokens',
27
- 'contextTokens',
28
- ];
29
-
30
- function liveStateOf(st) {
31
- const stats = st.stats && typeof st.stats === 'object' ? st.stats : {};
32
- const statsSubset = {};
33
- for (const key of LIVE_STATS_KEYS) {
34
- if (stats[key] !== undefined) statsSubset[key] = stats[key];
35
- }
36
- return {
37
- busy: st.busy === true,
38
- commandBusy: st.commandBusy === true,
39
- queued: (Array.isArray(st.queued) ? st.queued : []).map((entry) => ({
40
- id: entry?.id,
41
- text: String(entry?.displayText ?? entry?.text ?? entry?.message ?? '').slice(0, 2000),
42
- ...(entry?.enqueuedAt ? { enqueuedAt: entry.enqueuedAt } : {}),
43
- })),
44
- activeToolSummary: st.activeToolSummary || null,
45
- activeTools: st.activeTools || null,
46
- agentWorkers: Array.isArray(st.agentWorkers) ? st.agentWorkers : [],
47
- agentJobs: Array.isArray(st.agentJobs) ? st.agentJobs : [],
48
- ownerClientHostPid: Number(st.clientHostPid) || process.pid,
49
- displayContextWindow: Number(st.displayContextWindow) || 0,
50
- compactBoundaryTokens: Number(st.compactBoundaryTokens) || 0,
51
- autoCompactTokenLimit: Number(st.autoCompactTokenLimit) || 0,
52
- stats: statsSubset,
53
- };
54
- }
55
-
56
- export function fullFrame(sessionId, st) {
57
- return {
58
- t: 'full',
59
- sessionId,
60
- items: Array.isArray(st.items) ? st.items : [],
61
- tail: st.streamingTail || null,
62
- spinner: st.spinner || null,
63
- live: liveStateOf(st),
64
- };
65
- }
66
-
67
- // References the next delta is computed against. Pure pointer assignments,
68
- // so re-baselining on every publish with no viewers is effectively free.
69
- export function baselineOf(st, liveSig = JSON.stringify(liveStateOf(st))) {
70
- return { items: st.items, tail: st.streamingTail, spinner: st.spinner, liveSig };
71
- }
72
-
73
- export const EMPTY_BASELINE = Object.freeze({ items: null, tail: null, spinner: null, liveSig: '' });
74
-
75
- function itemsDelta(prevItems, nextItems) {
76
- const prev = Array.isArray(prevItems) ? prevItems : [];
77
- const next = Array.isArray(nextItems) ? nextItems : [];
78
- let structural = next.length < prev.length;
79
- const changed = [];
80
- if (!structural) {
81
- for (let i = 0; i < prev.length; i++) {
82
- if (next[i] === prev[i]) continue;
83
- if (!next[i]?.id || next[i].id !== prev[i]?.id) {
84
- structural = true;
85
- break;
86
- }
87
- changed.push(next[i]);
88
- if (changed.length > MAX_FRAME_PATCHES) {
89
- structural = true;
90
- break;
91
- }
92
- }
93
- }
94
- if (structural) return { items: next };
95
- const delta = {};
96
- if (changed.length) delta.changed = changed;
97
- if (next.length > prev.length) delta.appended = next.slice(prev.length);
98
- return delta;
99
- }
100
-
101
- // Streaming text grows append-only frame to frame: ship just the new suffix
102
- // so long responses stay a few bytes per frame, not O(text).
103
- function tailDelta(prevTail, nextTail) {
104
- const next = nextTail || null;
105
- const prev = prevTail || null;
106
- const appendOnly =
107
- next &&
108
- prev &&
109
- next.id === prev.id &&
110
- typeof next.text === 'string' &&
111
- typeof prev.text === 'string' &&
112
- next.text.length >= prev.text.length &&
113
- next.text.startsWith(prev.text);
114
- if (!appendOnly) return { tail: next };
115
- const meta = {};
116
- for (const [key, value] of Object.entries(next)) {
117
- if (key === 'text') continue;
118
- if (!Object.is(prev[key], value)) meta[key] = value;
119
- }
120
- return {
121
- tailAppend: {
122
- id: next.id,
123
- base: prev.text.length,
124
- text: next.text.slice(prev.text.length),
125
- ...(Object.keys(meta).length ? { meta } : {}),
126
- },
127
- };
128
- }
129
-
130
- /** Delta of `st` against `baseline`; `frame` is null when nothing changed. */
131
- export function deltaFrame(baseline, st) {
132
- const frame = { t: 'delta' };
133
- let dirty = false;
134
- if (st.items !== baseline.items) {
135
- Object.assign(frame, itemsDelta(baseline.items, st.items));
136
- dirty = true;
137
- }
138
- if (st.streamingTail !== baseline.tail) {
139
- Object.assign(frame, tailDelta(baseline.tail, st.streamingTail));
140
- dirty = true;
141
- }
142
- if (st.spinner !== baseline.spinner) {
143
- frame.spinner = st.spinner || null;
144
- dirty = true;
145
- }
146
- const live = liveStateOf(st);
147
- const liveSig = JSON.stringify(live);
148
- if (liveSig !== baseline.liveSig) {
149
- frame.live = live;
150
- dirty = true;
151
- }
152
- return { frame: dirty ? frame : null, baseline: baselineOf(st, liveSig) };
153
- }
@@ -1,106 +0,0 @@
1
- /**
2
- * src/tui/session/live-share/mirror.mjs - viewer-side application of owner
3
- * frames into the local session store.
4
- */
5
- const LIVE_LIMIT_KEYS = ['displayContextWindow', 'compactBoundaryTokens', 'autoCompactTokenLimit'];
6
-
7
- export function createMirror(viewerApply) {
8
- const upsertItem = (item) => {
9
- if (!item || item.id == null) return;
10
- const items = viewerApply.getState().items;
11
- const exists = Array.isArray(items) && items.some((it) => it?.id === item.id);
12
- if (exists) viewerApply.patchItem(item.id, item);
13
- else viewerApply.appendItems([item]);
14
- };
15
-
16
- // Mirror the owner's live-state subset into the viewer store. Context stats
17
- // merge over the local stats object so unmirrored accumulator fields keep
18
- // their last local values instead of vanishing.
19
- const applyLiveState = (live) => {
20
- if (!live || typeof live !== 'object') return;
21
- const patch = {
22
- busy: live.busy === true,
23
- commandBusy: live.commandBusy === true,
24
- queued: Array.isArray(live.queued) ? live.queued : [],
25
- activeToolSummary: live.activeToolSummary || null,
26
- activeTools: live.activeTools || null,
27
- agentWorkers: Array.isArray(live.agentWorkers) ? live.agentWorkers : [],
28
- agentJobs: Array.isArray(live.agentJobs) ? live.agentJobs : [],
29
- ownerClientHostPid: Number(live.ownerClientHostPid) || 0,
30
- };
31
- for (const key of LIVE_LIMIT_KEYS) {
32
- if (Number(live[key]) > 0) patch[key] = Number(live[key]);
33
- }
34
- if (live.stats && typeof live.stats === 'object' && Object.keys(live.stats).length > 0) {
35
- const current = viewerApply.getState().stats;
36
- patch.stats = { ...(current && typeof current === 'object' ? current : {}), ...live.stats };
37
- }
38
- viewerApply.set(patch);
39
- };
40
-
41
- // Owner gone (clean close, crash, or pipe drop): the mirrored activity is
42
- // no longer authoritative — clear it so the viewer never shows a frozen
43
- // spinner/queue while the promotion path takes over.
44
- const clearLiveState = () => {
45
- try {
46
- viewerApply?.set?.({
47
- busy: false,
48
- commandBusy: false,
49
- spinner: null,
50
- queued: [],
51
- activeToolSummary: null,
52
- activeTools: null,
53
- agentWorkers: [],
54
- agentJobs: [],
55
- ownerClientHostPid: 0,
56
- });
57
- } catch {
58
- /* viewer store already disposed */
59
- }
60
- };
61
-
62
- // Returns false when a tail suffix did not match the local base — this
63
- // mirror lost a frame and the caller must request a full resync.
64
- const applyTailAppend = (tailAppend) => {
65
- const current = viewerApply.getState().streamingTail;
66
- const base = Number(tailAppend.base) || 0;
67
- const matches =
68
- current && current.id === tailAppend.id && typeof current.text === 'string' && current.text.length === base;
69
- if (!matches) return false;
70
- viewerApply.updateStreamingTail(tailAppend.id, {
71
- ...(tailAppend.meta || {}),
72
- text: current.text + String(tailAppend.text || ''),
73
- });
74
- return true;
75
- };
76
-
77
- /** Apply one owner frame; false means the mirror is desynced. */
78
- const applyFrame = (frame) => {
79
- if (frame.t === 'full') {
80
- viewerApply.replaceItems(Array.isArray(frame.items) ? frame.items : []);
81
- if (frame.tail) viewerApply.updateStreamingTail(frame.tail.id, frame.tail, {}, { resetText: true });
82
- viewerApply.set({ spinner: frame.spinner || null });
83
- applyLiveState(frame.live);
84
- return true;
85
- }
86
- if (frame.t !== 'delta') return true;
87
- if (Array.isArray(frame.items)) {
88
- viewerApply.replaceItems(frame.items, { preserveStreamingTail: true });
89
- } else {
90
- for (const item of frame.changed || []) upsertItem(item);
91
- for (const item of frame.appended || []) upsertItem(item);
92
- }
93
- let synced = true;
94
- if (frame.tailAppend) {
95
- synced = applyTailAppend(frame.tailAppend);
96
- } else if ('tail' in frame) {
97
- if (frame.tail) viewerApply.updateStreamingTail(frame.tail.id, frame.tail, {}, { resetText: true });
98
- else viewerApply.clearStreamingTail();
99
- }
100
- if ('spinner' in frame) viewerApply.set({ spinner: frame.spinner || null });
101
- if ('live' in frame) applyLiveState(frame.live);
102
- return synced;
103
- };
104
-
105
- return { applyFrame, clearLiveState };
106
- }