mixdog 1.2.3 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (469) hide show
  1. package/package.json +1 -1
  2. package/scripts/gate-local.mjs +6 -4
  3. package/scripts/lib/gate-scheduler.mjs +29 -11
  4. package/scripts/mobile-release.mjs +5 -4
  5. package/scripts/probe-provider-catalog.mjs +31 -0
  6. package/scripts/provider-pingpong-live.mjs +128 -38
  7. package/scripts/session-sweep.mjs +5 -25
  8. package/src/agents/maintainer/AGENT.md +1 -1
  9. package/src/agents/maintainer/agent.json +1 -1
  10. package/src/agents/reviewer/AGENT.md +2 -4
  11. package/src/agents/security/AGENT.md +1 -2
  12. package/src/agents/writer/AGENT.md +2 -3
  13. package/src/defaults/shipped-history.json +7 -1
  14. package/src/defaults/skills/image/SKILL.md +21 -23
  15. package/src/lib/keychain-cjs.cjs +13 -11
  16. package/src/output-styles/common.md +2 -1
  17. package/src/rules/agent/AGENT.md +7 -5
  18. package/src/rules/lead/LEAD.md +13 -13
  19. package/src/rules/shared/45-destructive.md +4 -0
  20. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  21. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +28 -7
  22. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -11
  23. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +101 -23
  24. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +2 -0
  25. package/src/runtime/agent/orchestrator/providers/anthropic-api-key-fetch.mjs +36 -0
  26. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +1 -1
  27. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -3
  28. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  29. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +26 -44
  30. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2 -5
  31. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +4 -0
  32. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +41 -12
  33. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +13 -1
  34. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +81 -10
  35. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +109 -5
  36. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +2 -1
  37. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +107 -37
  38. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +4 -1
  39. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +3 -1
  40. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  41. package/src/runtime/agent/orchestrator/providers/cursor-native-context.mjs +48 -0
  42. package/src/runtime/agent/orchestrator/providers/cursor-wire-exec.mjs +144 -34
  43. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +28 -4
  44. package/src/runtime/agent/orchestrator/providers/cursor-wire-request.mjs +8 -4
  45. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +41 -11
  46. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +67 -5
  47. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +14 -4
  48. package/src/runtime/agent/orchestrator/providers/cursor.mjs +14 -1
  49. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +9 -6
  50. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -2
  51. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +26 -4
  52. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +12 -6
  53. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +14 -6
  54. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +4 -4
  55. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +1 -0
  56. package/src/runtime/agent/orchestrator/providers/gemini-rest-stream/watchdogs.mjs +16 -5
  57. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +6 -1
  58. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +22 -10
  59. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -2
  60. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +33 -7
  61. package/src/runtime/agent/orchestrator/providers/gemini.mjs +11 -2
  62. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  63. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +9 -2
  64. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +9 -5
  65. package/src/runtime/agent/orchestrator/providers/lib/request-compression.mjs +86 -0
  66. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +4 -2
  67. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -5
  68. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +7 -1
  69. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +60 -16
  70. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +11 -13
  71. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +30 -19
  72. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +5 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +42 -5
  75. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +13 -9
  76. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +1 -3
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +18 -7
  78. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +36 -3
  79. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +51 -3
  80. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +11 -1
  81. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +64 -52
  82. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +3 -1
  83. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +2 -1
  84. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +7 -1
  85. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +1 -4
  86. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +0 -1
  87. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +7 -6
  88. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +13 -2
  89. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +4 -1
  90. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +1 -2
  91. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +5 -4
  92. package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -1
  93. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +2 -1
  94. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +11 -4
  95. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +14 -4
  96. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +15 -3
  97. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +6 -2
  98. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +8 -6
  99. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +4 -1
  100. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +30 -2
  101. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +3 -2
  102. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -3
  103. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +3 -1
  104. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge-contract.mjs +6 -0
  105. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +10 -10
  106. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +3 -1
  107. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +46 -8
  108. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -8
  109. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -2
  110. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +24 -0
  111. package/src/runtime/agent/orchestrator/session/cache/tool-result-reuse.mjs +10 -2
  112. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -3
  113. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -11
  114. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +6 -22
  115. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -0
  116. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +16 -2
  117. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +28 -0
  118. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  119. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +0 -6
  120. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +0 -6
  121. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +1 -1
  122. package/src/runtime/agent/orchestrator/session/historical-session-closure.mjs +10 -0
  123. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +2 -5
  124. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +2 -4
  125. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +3 -3
  126. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +0 -27
  127. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +1 -1
  128. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -10
  129. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -9
  130. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +4 -1
  131. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +4 -1
  132. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +1 -4
  133. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +76 -0
  134. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +5 -1
  135. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +8 -9
  136. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +6 -0
  137. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -2
  138. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +1 -4
  139. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -4
  140. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +33 -3
  141. package/src/runtime/agent/orchestrator/session/manager/ask-support.mjs +0 -4
  142. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +21 -1
  143. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +38 -13
  144. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +33 -0
  145. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +5 -0
  146. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +19 -1
  147. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +57 -13
  148. package/src/runtime/agent/orchestrator/session/manager/failed-turn-rewind.mjs +16 -0
  149. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +6 -120
  150. package/src/runtime/agent/orchestrator/session/manager/pending-persist-queue.mjs +1 -1
  151. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +29 -8
  152. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +42 -49
  153. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +50 -0
  154. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +32 -14
  155. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +1 -1
  156. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +17 -33
  157. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +29 -13
  158. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -3
  159. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +45 -0
  160. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -9
  161. package/src/runtime/agent/orchestrator/session/send-instrumentation.mjs +2 -1
  162. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -2
  163. package/src/runtime/agent/orchestrator/session/side-question.mjs +12 -7
  164. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +5 -12
  165. package/src/runtime/agent/orchestrator/session/store/lifecycle-read.mjs +1 -1
  166. package/src/runtime/agent/orchestrator/session/store/listing.mjs +2 -6
  167. package/src/runtime/agent/orchestrator/session/store/live-cache-eviction.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +46 -37
  169. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +1 -1
  170. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +1 -1
  171. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +5 -11
  172. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +59 -0
  173. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +1 -1
  174. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +1 -1
  175. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +27 -32
  176. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +0 -8
  177. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +6 -18
  178. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +33 -106
  179. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +1 -1
  180. package/src/runtime/agent/orchestrator/session/store-agent-worker-pool.mjs +5 -8
  181. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +160 -212
  182. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +50 -116
  183. package/src/runtime/agent/orchestrator/session/store-summary-locations.mjs +3 -29
  184. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +1 -1
  185. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +7 -8
  186. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +9 -20
  187. package/src/runtime/agent/orchestrator/session/store.mjs +3 -16
  188. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +11 -12
  189. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +37 -13
  190. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +15 -4
  191. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +4 -2
  192. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +72 -15
  193. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +45 -0
  194. package/src/runtime/agent/orchestrator/stall-policy.mjs +50 -0
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +5 -1
  196. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +6 -2
  197. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +204 -10
  198. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +160 -39
  199. package/src/runtime/agent/orchestrator/tools/builtin/git-partial-stage.mjs +7 -5
  200. package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +14 -5
  201. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +4 -3
  202. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +2 -1
  203. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-path-fanout.mjs +48 -44
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +10 -3
  205. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +200 -17
  206. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +5 -4
  207. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +6 -1
  208. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +20 -0
  209. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +101 -2
  210. package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
  211. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +67 -0
  212. package/src/runtime/agent/orchestrator/tools/lib/process-table-fixture.mjs +50 -0
  213. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +303 -63
  214. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -0
  215. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +108 -18
  216. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +77 -11
  217. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +81 -5
  218. package/src/runtime/attachments/store.d.mts +9 -0
  219. package/src/runtime/attachments/store.mjs +80 -9
  220. package/src/runtime/browser-bridge/browser-action-contract.d.mts +0 -1
  221. package/src/runtime/browser-bridge/browser-action-contract.mjs +0 -2
  222. package/src/runtime/computer-bridge/action-schema.mjs +178 -178
  223. package/src/runtime/computer-bridge/linux-readiness.d.mts +0 -2
  224. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -16
  225. package/src/runtime/effort-judge/judge-client.mjs +21 -4
  226. package/src/runtime/effort-judge/judge-worker.mjs +4 -1
  227. package/src/runtime/github/tool.mjs +118 -17
  228. package/src/runtime/media/adapters/codex-image.mjs +140 -21
  229. package/src/runtime/media/catalog.mjs +4 -4
  230. package/src/runtime/media/chatgpt-usage.mjs +55 -0
  231. package/src/runtime/media/defaults.mjs +37 -0
  232. package/src/runtime/media/jobs.mjs +12 -2
  233. package/src/runtime/media/lanes.mjs +12 -0
  234. package/src/runtime/media/tool-defs.mjs +15 -4
  235. package/src/runtime/media/tool.mjs +41 -12
  236. package/src/runtime/media/upstream-error.mjs +72 -6
  237. package/src/runtime/memory/lib/ingest/transcript-rows.mjs +1 -0
  238. package/src/runtime/memory/lib/pg/process.mjs +5 -7
  239. package/src/runtime/memory/lib/pg/supervisor.mjs +4 -1
  240. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  241. package/src/runtime/office/authoring/html-browser.mjs +18 -8
  242. package/src/runtime/office/authoring/pdf-html-runner.mjs +1 -1
  243. package/src/runtime/office/authoring/pptx-html-measure.mjs +1 -1
  244. package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
  245. package/src/runtime/office/core/office-write-ledger.mjs +1 -5
  246. package/src/runtime/office/index.mjs +2 -3
  247. package/src/runtime/office/pdf/pdf-analysis.mjs +0 -68
  248. package/src/runtime/session-search/session-search-ingest.mjs +1 -1
  249. package/src/runtime/shared/agent-reap-state.mjs +13 -0
  250. package/src/runtime/shared/atomic-file.d.mts +1 -1
  251. package/src/runtime/shared/background-tasks.mjs +6 -1
  252. package/src/runtime/shared/bounded-line-diff.mjs +11 -2
  253. package/src/runtime/shared/browser-launch.mjs +15 -0
  254. package/src/runtime/shared/err-text.mjs +42 -4
  255. package/src/runtime/shared/file-lock.mjs +6 -5
  256. package/src/runtime/shared/llm/anthropic-betas.mjs +1 -2
  257. package/src/runtime/shared/llm/provider-model-identities.mjs +1 -0
  258. package/src/runtime/shared/model-route-chain.d.mts +8 -0
  259. package/src/runtime/shared/model-route-chain.mjs +48 -0
  260. package/src/runtime/shared/model-route-fallback.mjs +22 -0
  261. package/src/runtime/shared/pid-liveness.mjs +12 -0
  262. package/src/runtime/shared/provider-api-key.mjs +6 -0
  263. package/src/runtime/shared/provider-timeout-phase.mjs +17 -0
  264. package/src/runtime/shared/quiet-progress.d.mts +35 -0
  265. package/src/runtime/shared/quiet-progress.mjs +101 -0
  266. package/src/runtime/shared/quota-resume-store.mjs +32 -1
  267. package/src/runtime/shared/read-row-numbers.mjs +44 -0
  268. package/src/runtime/shared/remote-intent.mjs +2 -42
  269. package/src/runtime/shared/slow-span.mjs +8 -1
  270. package/src/runtime/shared/statusline/statusline-segments.mjs +24 -2
  271. package/src/runtime/shared/tool-card-model/card-header.mjs +2 -1
  272. package/src/runtime/shared/tool-output-budget.mjs +2 -0
  273. package/src/runtime/shared/tool-result-summary.mjs +16 -2
  274. package/src/runtime/shared/tool-status.mjs +3 -2
  275. package/src/runtime/shared/tool-surface.mjs +2 -3
  276. package/src/runtime/shared/tool-work-units.mjs +22 -15
  277. package/src/runtime/shared/transcript-metadata.mjs +49 -1
  278. package/src/runtime/shared/transcript-turn-keys.mjs +33 -0
  279. package/src/runtime/shared/transcript-writer/transcript-file.mjs +10 -1
  280. package/src/runtime/shared/transcript-writer.mjs +14 -4
  281. package/src/runtime/shared/turn-changes.mjs +2 -1
  282. package/src/runtime/shared/turn-snapshot.mjs +11 -3
  283. package/src/runtime/shared/worktrees/activity-gate.mjs +175 -0
  284. package/src/runtime/shared/worktrees/branch-management.mjs +179 -0
  285. package/src/runtime/shared/worktrees/carry.mjs +6 -4
  286. package/src/runtime/shared/worktrees/contract.mjs +27 -1
  287. package/src/runtime/shared/worktrees/dependencies.mjs +456 -0
  288. package/src/runtime/shared/worktrees/file-recovery.mjs +29 -13
  289. package/src/runtime/shared/worktrees/git-head.mjs +22 -13
  290. package/src/runtime/shared/worktrees/include.mjs +125 -7
  291. package/src/runtime/shared/worktrees/lock.mjs +1 -1
  292. package/src/runtime/shared/worktrees/maintenance.mjs +20 -2
  293. package/src/runtime/shared/worktrees/manager.mjs +378 -32
  294. package/src/runtime/shared/worktrees/owner.mjs +2 -1
  295. package/src/runtime/shared/worktrees/preparation-report.mjs +79 -0
  296. package/src/runtime/shared/worktrees/setup-commands.mjs +232 -0
  297. package/src/runtime/shared/worktrees/workspace-visibility.mjs +17 -0
  298. package/src/runtime/terminal-bridge/client.mjs +14 -10
  299. package/src/session-runtime/boot/apis.mjs +7 -1
  300. package/src/session-runtime/boot/config.mjs +2 -0
  301. package/src/session-runtime/boot/facade.mjs +3 -0
  302. package/src/session-runtime/boot/session.mjs +3 -2
  303. package/src/session-runtime/boot/tools.mjs +3 -0
  304. package/src/session-runtime/conversation-import/service.mjs +1 -1
  305. package/src/session-runtime/goal-facade-api.mjs +2 -2
  306. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +44 -18
  307. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +4 -1
  308. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +22 -8
  309. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  310. package/src/session-runtime/lifecycle/cold-heir.mjs +0 -1
  311. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -16
  312. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +18 -53
  313. package/src/session-runtime/lifecycle/session-switch.mjs +1 -1
  314. package/src/session-runtime/lifecycle/shared.mjs +5 -6
  315. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -5
  316. package/src/session-runtime/lifecycle/teardown.mjs +7 -16
  317. package/src/session-runtime/media-api.mjs +8 -0
  318. package/src/session-runtime/model-route/route-ownership.mjs +60 -0
  319. package/src/session-runtime/model-route/route-persist.mjs +3 -2
  320. package/src/session-runtime/model-route/set-route.mjs +114 -34
  321. package/src/session-runtime/model-route/web-search-route.mjs +7 -2
  322. package/src/session-runtime/model-route-api.mjs +4 -2
  323. package/src/session-runtime/native-web-search/routes.mjs +37 -24
  324. package/src/session-runtime/native-web-search.mjs +9 -8
  325. package/src/session-runtime/provider-auth/setup.mjs +4 -0
  326. package/src/session-runtime/provider-models/catalog-load.mjs +9 -0
  327. package/src/session-runtime/provider-models/web-search-catalog.mjs +23 -3
  328. package/src/session-runtime/provider-models.mjs +1 -0
  329. package/src/session-runtime/provider-usage.mjs +4 -0
  330. package/src/session-runtime/route-resolution.mjs +3 -1
  331. package/src/session-runtime/runtime-core.mjs +4 -0
  332. package/src/session-runtime/runtime-facade.mjs +6 -0
  333. package/src/session-runtime/services/agent-task-status.mjs +2 -0
  334. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +0 -3
  335. package/src/session-runtime/services/agent-tool/close-flow.mjs +6 -7
  336. package/src/session-runtime/services/agent-tool/execute-send.mjs +2 -2
  337. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +36 -3
  338. package/src/session-runtime/services/agent-tool/execute.mjs +9 -1
  339. package/src/session-runtime/services/agent-tool/helpers.mjs +30 -7
  340. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +7 -2
  341. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +6 -3
  342. package/src/session-runtime/services/agent-tool/lead-worker-index/lead-rows.mjs +3 -4
  343. package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +9 -3
  344. package/src/session-runtime/services/agent-tool/lead-worker-index/row-settlement.mjs +7 -18
  345. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +9 -6
  346. package/src/session-runtime/services/agent-tool/model-select.mjs +82 -0
  347. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -6
  348. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -1
  349. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -5
  350. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -4
  351. package/src/session-runtime/services/agent-tool/spawn-flow.mjs +2 -1
  352. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  353. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +1 -3
  354. package/src/session-runtime/services/agent-tool/tag-registry/tag-refresh.mjs +1 -3
  355. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -9
  356. package/src/session-runtime/services/agent-tool/terminal-reaper/scan-admission.mjs +8 -41
  357. package/src/session-runtime/services/agent-tool/terminal-reaper/stale-rows.mjs +3 -3
  358. package/src/session-runtime/services/agent-tool/terminal-reaper.mjs +6 -23
  359. package/src/session-runtime/services/agent-tool/terminal-trace.mjs +0 -1
  360. package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
  361. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +32 -20
  362. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -2
  363. package/src/session-runtime/services/agent-tool/worker-index.mjs +28 -8
  364. package/src/session-runtime/services/agent-tool.mjs +4 -0
  365. package/src/session-runtime/services/agent-watchdog-registry.mjs +2 -0
  366. package/src/session-runtime/services/provider-admin.mjs +77 -0
  367. package/src/session-runtime/session-create/session-options.mjs +7 -5
  368. package/src/session-runtime/session-create/session-start-hook.mjs +2 -1
  369. package/src/session-runtime/session-transcript.mjs +4 -5
  370. package/src/session-runtime/session-turn-api.mjs +3 -9
  371. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -6
  372. package/src/session-runtime/setup-tool/executor.mjs +23 -5
  373. package/src/session-runtime/setup-tool/extended-actions.mjs +6 -6
  374. package/src/session-runtime/setup-tool/settings-contract.mjs +7 -2
  375. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -1
  376. package/src/session-runtime/tool-policy-refresh.mjs +83 -32
  377. package/src/session-runtime/turn/agent-ops.mjs +49 -2
  378. package/src/session-runtime/turn/side-question-ops.mjs +1 -4
  379. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +2 -0
  380. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +4 -0
  381. package/src/session-runtime/turn/turn-run/turn-settle.mjs +8 -2
  382. package/src/session-runtime/turn/turn-run.mjs +1 -36
  383. package/src/session-runtime/usage-stats-api.mjs +4 -1
  384. package/src/session-runtime/workflow-agents-api/agent-route.mjs +16 -1
  385. package/src/session-runtime/workspace/admission-gate.mjs +44 -15
  386. package/src/session-runtime/workspace/project-branches.mjs +28 -36
  387. package/src/session-runtime/workspace/transition-steps.mjs +96 -95
  388. package/src/session-runtime/workspace/transitions.mjs +248 -68
  389. package/src/standalone/channel-transport.mjs +3 -4
  390. package/src/standalone/daemon-desktop-runtime.mjs +32 -1
  391. package/src/standalone/daemon-pg-stop.mjs +1 -3
  392. package/src/standalone/daemon-session-control.mjs +88 -0
  393. package/src/standalone/daemon-stored-session-views.mjs +23 -3
  394. package/src/standalone/daemon.mjs +2 -0
  395. package/src/standalone/desktop-service-registry.mjs +32 -5
  396. package/src/standalone/local-session-runtime.mjs +11 -12
  397. package/src/standalone/session-protocol.mjs +7 -0
  398. package/src/standalone/session-runtime-inline-host.mjs +2 -0
  399. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +91 -49
  400. package/src/standalone/session-service/agent-tree/agent-child.mjs +19 -1
  401. package/src/standalone/session-service/agent-tree/agent-registry.mjs +25 -0
  402. package/src/standalone/session-service/agent-tree/agent-turns.mjs +9 -1
  403. package/src/standalone/session-service/agent-tree.mjs +28 -2
  404. package/src/standalone/session-service/entries/session-loads.mjs +16 -5
  405. package/src/standalone/session-service/entries.mjs +1 -0
  406. package/src/standalone/session-service/projection/transcript-window.mjs +39 -0
  407. package/src/standalone/session-service/quota-resume.mjs +28 -13
  408. package/src/standalone/session-service/session-calls/session-turns.mjs +17 -6
  409. package/src/standalone/session-service/session-calls/session-views.mjs +6 -0
  410. package/src/standalone/session-tool-output.mjs +82 -0
  411. package/src/tui/app/app-view.jsx +2 -1
  412. package/src/tui/app/provider-setup/provider-items.mjs +8 -0
  413. package/src/tui/app/provider-setup-picker.mjs +15 -3
  414. package/src/tui/app/slash-commands.mjs +6 -0
  415. package/src/tui/app/slash-dispatch/session-commands.mjs +49 -0
  416. package/src/tui/components/Spinner.jsx +4 -0
  417. package/src/tui/components/SpinnerByline.jsx +21 -2
  418. package/src/tui/components/status-line/local-line.mjs +10 -2
  419. package/src/tui/dist/index.mjs +529 -270
  420. package/src/tui/session/active-tool-summary.mjs +1 -1
  421. package/src/tui/session/context-state.mjs +0 -3
  422. package/src/tui/session/goal-continuation/continuation-queue.mjs +2 -3
  423. package/src/tui/session/goal-continuation/deadline-delivery.mjs +4 -2
  424. package/src/tui/session/goal-continuation/session-boundary.mjs +21 -0
  425. package/src/tui/session/quota-resume.mjs +140 -61
  426. package/src/tui/session/session-api/commands.mjs +4 -10
  427. package/src/tui/session/session-api/controls.mjs +12 -0
  428. package/src/tui/session/session-api/lifecycle/dispose.mjs +2 -9
  429. package/src/tui/session/session-api/lifecycle/resume.mjs +2 -7
  430. package/src/tui/session/session-api/lifecycle.mjs +13 -11
  431. package/src/tui/session/session-api/media.mjs +2 -0
  432. package/src/tui/session/session-api/routes.mjs +81 -57
  433. package/src/tui/session/session-api/settings.mjs +3 -3
  434. package/src/tui/session/session-api/worktree.mjs +3 -2
  435. package/src/tui/session/session-flow/auto-clear.mjs +1 -3
  436. package/src/tui/session/session-flow/drain.mjs +6 -4
  437. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -0
  438. package/src/tui/session/session-flow/queue/take-entries.mjs +2 -1
  439. package/src/tui/session/session-flow/queue.mjs +1 -1
  440. package/src/tui/session/tool-approval.mjs +17 -8
  441. package/src/tui/session/transcript-store/streaming-tail.mjs +1 -1
  442. package/src/tui/session/tui-steering-persist.mjs +3 -5
  443. package/src/tui/session/turn-quiet.mjs +53 -0
  444. package/src/tui/session/turn-stream.mjs +5 -1
  445. package/src/tui/session/turn.mjs +38 -31
  446. package/src/tui/session/worktree-setup-notice.mjs +38 -0
  447. package/src/tui/spinner-meta.mjs +10 -0
  448. package/src/tui/spinner-verbs.mjs +3 -0
  449. package/src/ui/statusline.mjs +13 -3
  450. package/src/ui/streaming-markdown-heal.mjs +70 -18
  451. package/src/runtime/agent/orchestrator/providers/model-pricing-rates.mjs +0 -1
  452. package/src/runtime/agent/orchestrator/session/manager/foreign-pending-messages.mjs +0 -346
  453. package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +0 -117
  454. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +0 -302
  455. package/src/session-runtime/services/agent-tool/terminal-reaper/reap-timers.mjs +0 -142
  456. package/src/session-runtime/turn/share-ops.mjs +0 -77
  457. package/src/tui/session/cross-surface-share.mjs +0 -406
  458. package/src/tui/session/live-share/delta.mjs +0 -153
  459. package/src/tui/session/live-share/mirror.mjs +0 -106
  460. package/src/tui/session/live-share/owner.mjs +0 -254
  461. package/src/tui/session/live-share/retry.mjs +0 -54
  462. package/src/tui/session/live-share/viewer/frame-router.mjs +0 -32
  463. package/src/tui/session/live-share/viewer/pipe-client.mjs +0 -108
  464. package/src/tui/session/live-share/viewer/submit-acks.mjs +0 -65
  465. package/src/tui/session/live-share/viewer/sync-waiters.mjs +0 -53
  466. package/src/tui/session/live-share/viewer.mjs +0 -99
  467. package/src/tui/session/live-share/wire.mjs +0 -44
  468. package/src/tui/session/live-share.mjs +0 -154
  469. package/src/tui/session/shared-dir-watch.mjs +0 -69
@@ -0,0 +1,50 @@
1
+ // manager/runtime-state.mjs
2
+ // The process-global runtime liveness map and its turn-activity reads.
3
+ // runtime-liveness.mjs owns every entry and mutation; this leaf has no
4
+ // imports, so a cold reader (the daemon's session catalog) can ask which turns
5
+ // are in flight without loading the session manager graph. Every session runs
6
+ // inline in the daemon, so this map is the whole answer to "is this session's
7
+ // turn running".
8
+
9
+ export const runtimeState = new Map();
10
+
11
+ // Stages that still own live provider/tool work: compaction, idle cleanup and
12
+ // runtime unload all stay away from an entry in one of them.
13
+ export const IN_FLIGHT_STAGES = new Set(['connecting', 'requesting', 'streaming', 'tool_running', 'cancelling']);
14
+
15
+ /** Whether a runtime entry's turn (provider or tool work) is running now. */
16
+ export function isTurnInFlight(entry) {
17
+ if (!entry || entry.closed === true) return false;
18
+ if (entry.controller && !entry.controller.signal?.aborted) return true;
19
+ return IN_FLIGHT_STAGES.has(entry.stage);
20
+ }
21
+
22
+ const cleanLower = (value) =>
23
+ String(value || '')
24
+ .trim()
25
+ .toLowerCase();
26
+
27
+ /**
28
+ * Turn activity of every session this process runs: `working` holds the ids
29
+ * whose turn is in flight, `agentWorking` the root owner (Lead) ids of every
30
+ * in-flight Agent session.
31
+ */
32
+ export function inFlightSessionActivity() {
33
+ const working = new Set();
34
+ const agentWorking = new Set();
35
+ for (const [id, entry] of runtimeState) {
36
+ if (!isTurnInFlight(entry)) continue;
37
+ working.add(id);
38
+ const session = entry.session;
39
+ const ownerSessionId = String(session?.ownerSessionId || session?.parentSessionId || '').trim();
40
+ const agent = cleanLower(session?.agent);
41
+ if (
42
+ ownerSessionId &&
43
+ ownerSessionId !== id &&
44
+ (cleanLower(session?.owner) === 'agent' || (agent && agent !== 'lead'))
45
+ ) {
46
+ agentWorking.add(ownerSessionId);
47
+ }
48
+ }
49
+ return { working, agentWorking };
50
+ }
@@ -17,7 +17,8 @@ import { clearTurnCheckpoint } from './turn-checkpoint.mjs';
17
17
  import { forgetSessionSaveBaseline } from '../store/save-worker.mjs';
18
18
  import { forgetSessionLoadCache } from '../store/load-cache.mjs';
19
19
  import { releaseReadSnapshotScope } from '../../tools/builtin/snapshot-store.mjs';
20
- import { cancelNativeTasks } from '../../tools/lib/native-spawn-client.mjs';
20
+ import { cancelOwnedShellTrees } from '../../tools/lib/owned-shell-trees.mjs';
21
+ import { noteShellOwnerSessionClosed } from '../../tools/builtin/lib/shell-job-records.mjs';
21
22
  import { forgetSideQuestion } from '../side-question-store.mjs';
22
23
 
23
24
  /**
@@ -47,15 +48,17 @@ export function closeSession(id, reason = 'manual', opts = {}) {
47
48
  const entry = _getRuntimeEntry(id);
48
49
  // askSession owns the interruption tracker that can merge committed
49
50
  // iterations, the current partial response, and observed tool results into
50
- // one canonical transcript. Finalize that in-memory snapshot synchronously
51
+ // one canonical transcript. Stage that in-memory snapshot synchronously
51
52
  // BEFORE the lifecycle generation changes; once generation is bumped, the
52
- // normal cancellation cleanup save is intentionally rejected as stale.
53
+ // normal cancellation cleanup save is intentionally rejected as stale. It
54
+ // is only staged: a refused barrier rolls it back so the turn keeps running
55
+ // and checkpointing as if no close had been attempted.
56
+ let closeSnapshot = null;
53
57
  try {
54
- entry?.prepareCloseSnapshot?.(reason);
58
+ closeSnapshot = entry?.prepareCloseSnapshot?.tentative?.(reason) ?? null;
55
59
  } catch {
56
60
  /* best-effort */
57
61
  }
58
- _stopToolActivityHeartbeat(id);
59
62
  // 1. Tombstone first — this wins the race against saveSession().
60
63
  // Skipped when tombstone=false: no closed:true marker is planted, so
61
64
  // the session file stays intact and resumeSession() will accept it.
@@ -87,12 +90,16 @@ export function closeSession(id, reason = 'manual', opts = {}) {
87
90
  // a late save could clobber and nothing left open to resume. That close
88
91
  // succeeds and tears the runtime down normally.
89
92
  if (typeof newGen !== 'number' && outcome.absent !== true) {
93
+ closeSnapshot?.rollback();
90
94
  reportCloseBarrierFailure({ id, reason, tombstone, entry });
91
95
  return false;
92
96
  }
97
+ // The staged snapshot was folded into the synchronous generation write
98
+ // above; committing it stops the turn's checkpoint writer. Only now is it
99
+ // safe to remove the crash fallback.
100
+ closeSnapshot?.commit();
101
+ _stopToolActivityHeartbeat(id);
93
102
  cancelOwnedShellProcesses({ id, reason, tombstone });
94
- // prepareCloseSnapshot was folded into the synchronous generation write
95
- // above. Only now is it safe to remove the crash fallback.
96
103
  clearTurnCheckpoint(id);
97
104
  teardownSessionRuntime({ id, entry, reason, tombstone, newGen });
98
105
  return true;
@@ -138,16 +145,27 @@ function reportCloseBarrierFailure({ id, reason, tombstone, entry }) {
138
145
  * with the unconfirmed outcome. The re-stamp is idempotent: markSessionClosed
139
146
  * keeps the original close time and generation and only upgrades the cancel
140
147
  * scalars (unconfirmed never downgrades back to cancelled).
148
+ *
149
+ * Every tree records its process identities before the kill (the kill may
150
+ * break the parent chain). When a snapshot is still pending the cancel is
151
+ * sent once it lands or after PROCESS_TABLE_READ_BOUND_MS, whichever first;
152
+ * the close itself does not wait. Holds this session leaves behind become
153
+ * releasable from any session that sees their workspace.
141
154
  */
142
155
  function cancelOwnedShellProcesses({ id, reason, tombstone }) {
143
- let cancelConfirmed = true;
156
+ const record = (result) => {
157
+ if (tombstone && result?.confirmed === false) markSessionClosed(id, reason, { cancelStatus: 'cancel-unconfirmed' });
158
+ };
159
+ // A cancel that threw proved nothing either.
160
+ const unconfirmed = () => record({ confirmed: false });
144
161
  try {
145
- cancelConfirmed = cancelNativeTasks({ ownerSessionId: id })?.confirmed !== false;
162
+ const result = cancelOwnedShellTrees(id);
163
+ if (typeof result?.then === 'function') result.then(record, unconfirmed);
164
+ else record(result);
146
165
  } catch {
147
- // A cancel that threw proved nothing either.
148
- cancelConfirmed = false;
166
+ unconfirmed();
149
167
  }
150
- if (tombstone && !cancelConfirmed) markSessionClosed(id, reason, { cancelStatus: 'cancel-unconfirmed' });
168
+ noteShellOwnerSessionClosed(id);
151
169
  }
152
170
 
153
171
  /**
@@ -275,8 +293,8 @@ export function abortSessionTurn(id, reason = 'turn-abort') {
275
293
  * what a settled turn left behind;
276
294
  * - offload sidecars, the turn checkpoint and persisted pending messages
277
295
  * are left intact — they are the follow-up turn's context, not runtime.
278
- * Terminal ownership stays with the caller's own reap path (agent-tool
279
- * scheduleReap → closeSession('terminal-reap')).
296
+ * A terminal session is never closed here; it stays open until it is
297
+ * explicitly cancelled or deleted.
280
298
  *
281
299
  * Returns false (changing nothing) when the session is still in flight.
282
300
  */
@@ -29,7 +29,7 @@ import { hideCompactionArchive } from '../compaction-archive-capture.mjs';
29
29
  import { writeStderrBestEffort } from '../../../../shared/best-effort-stderr.mjs';
30
30
  import { forgetSideQuestion } from '../side-question-store.mjs';
31
31
 
32
- /** Force-flush session metrics to disk. Used by watchdog terminal-reap (fix B). */
32
+ /** Force-flush session metrics to disk. */
33
33
  export async function flushSessionMetrics(sessionId) {
34
34
  if (!sessionId) return;
35
35
  const session = loadSession(sessionId);
@@ -7,7 +7,7 @@ import { getProvider } from '../../providers/registry.mjs';
7
7
  import { invalidateContextUsageSnapshot, invalidateProviderContextBaseline } from '../loop/compact-policy.mjs';
8
8
  import { saveSession, saveSessionAsync, saveSessionAsyncDeferred, loadSession, setLiveSession } from '../store.mjs';
9
9
  import { _liveSessions } from '../store/live-state.mjs';
10
- import { _isActivelyOwnedElsewhere, _recoverTurnCheckpointDurably } from './session-owner-liveness.mjs';
10
+ import { _recoverTurnCheckpointDurably } from './turn-checkpoint-recovery.mjs';
11
11
  import { isAgentOwner } from '../../agent-owner.mjs';
12
12
  import { getHiddenAgent } from '../../internal-agents.mjs';
13
13
  import { loadConfig } from '../../config.mjs';
@@ -37,14 +37,15 @@ import { getAgentRuntimeSync, warnAgentRuntimeResolveFailureOnce } from './agent
37
37
  import { ensureCodexWireSessionId, mintSessionId } from './session-id.mjs';
38
38
  import { providerCacheKey } from './provider-cache-key.mjs';
39
39
  import { buildSessionRecord, normalizeDesktopSessionMetadata, sessionOriginFields } from './session-record.mjs';
40
+ import { normalizeWorkflowRoute } from '../../runtime-core/workflow.mjs';
40
41
  import { applyPendingWorkspaceReroot, refreshSessionBp3Environment } from './prompt-utils.mjs';
41
42
  import { isWorktreeBound } from '../../../../shared/worktrees/contract.mjs';
42
43
  import { applyAgentToolExposure } from '../loop/tool-exposure-migration.mjs';
44
+ import { prewarmSessionAutoEffort } from './ask-turn-auto-effort.mjs';
43
45
 
44
- // Owner liveness (attach-on-resume guard) and the durable turn-checkpoint
45
- // recovery it gates; re-exported so prior importers of this module stay
46
- // unchanged.
47
- export { isSessionOwnerGone, recoverSessionAfterProcessRestart } from './session-owner-liveness.mjs';
46
+ // Durable turn-checkpoint recovery; re-exported so prior importers of this
47
+ // module stay unchanged.
48
+ export { recoverSessionAfterProcessRestart } from './turn-checkpoint-recovery.mjs';
48
49
  // Prepared-surface cache warmers (desktop hover prefetch, pane projection);
49
50
  // re-exported so prior importers of this module stay unchanged.
50
51
  export { prefetchSession, prepareSessionProjection } from './prepared-resume-cache.mjs';
@@ -211,6 +212,11 @@ export function createSession(opts) {
211
212
  const { profile } = resolved;
212
213
  const route = resolveSessionRoute(opts, presetObj, profile);
213
214
  const { providerName, modelName, provider, toolPreset, id } = route;
215
+ const routeFallbacks = normalizeWorkflowRoute({
216
+ provider: providerName,
217
+ model: modelName,
218
+ fallbacks: Object.hasOwn(opts, 'routeFallbacks') ? opts.routeFallbacks : presetObj?.fallbacks,
219
+ })?.fallbacks;
214
220
  // Provider cache strategy — agentRuntime.resolveSync() above is a
215
221
  // best-effort injection point (setAgentRuntime() has no live caller
216
222
  // today, so that branch never fires); build it directly here so every
@@ -218,11 +224,7 @@ export function createSession(opts) {
218
224
  // 'lead', or no agent at all — raw/CLI callers) get their BP4 message
219
225
  // tail TTL linked to the user's autoClear idle-sweep config; hidden and
220
226
  // public agents keep the flat 5m default (see cache-strategy.mjs docs).
221
- // Scoped to explicit-breakpoint (Anthropic-family) providers only — the
222
- // non-Anthropic branches of buildProviderCacheOpts (e.g. the 'openai'
223
- // cacheRetention:'24h' shape) were never exercised by createSession
224
- // before this change, and are left untouched to avoid altering live
225
- // OpenAI/other-provider request shape as a side effect of this fix.
227
+ // Scoped to explicit-breakpoint (Anthropic-family) providers only.
226
228
  const providerCacheOpts = resolved.providerCacheOpts || buildSessionProviderCacheOpts(providerName, id, opts.agent);
227
229
  const surface = resolveSessionToolSurface(opts, { profile, toolPreset, modelName });
228
230
  const prompt = composeSessionSystem(opts, { profile, providerName, modelName, surface });
@@ -244,6 +246,7 @@ export function createSession(opts) {
244
246
  origin: sessionOriginFields(opts, { profile, presetObj, providerCacheOpts, surface }),
245
247
  });
246
248
  session.providerCacheOptsOverride = Boolean(resolved.providerCacheOpts);
249
+ if (routeFallbacks?.length) session.routeFallbacks = routeFallbacks;
247
250
  // A non-native agent sends core + bridge, built from its filtered tools.
248
251
  applyAgentToolExposure(session);
249
252
  refreshSessionBp3Environment(session, opts.cwd);
@@ -251,6 +254,7 @@ export function createSession(opts) {
251
254
  // reads live memory; disk flush is for cross-process / restart durability.
252
255
  setLiveSession(session);
253
256
  saveSession(session);
257
+ prewarmSessionAutoEffort(session, provider);
254
258
  return session;
255
259
  }
256
260
 
@@ -460,9 +464,8 @@ export function updateSessionRoute(id, route = {}, options = {}) {
460
464
  }
461
465
 
462
466
  // --- resume (reload tools for a stored session) ---
463
- // Whether another live process is driving the session (and therefore whether
464
- // this resume attaches as a viewer) is decided by session-owner-liveness.mjs;
465
- // the prepared tool surface it consumes is cached in prepared-resume-cache.mjs.
467
+ // Interrupted-turn recovery lives in turn-checkpoint-recovery.mjs; the
468
+ // prepared tool surface it consumes is cached in prepared-resume-cache.mjs.
466
469
 
467
470
  // Desktop callers pass their selected durable classification as a
468
471
  // capability check. Refuse a stale/tampered cross-class resume before any
@@ -496,25 +499,6 @@ function _applyDesktopResumeScope(session, options) {
496
499
  return true;
497
500
  }
498
501
 
499
- // ATTACH (viewer mode, zero ownership): hand back the live transcript
500
- // under the SAME id, flagged remoteAttached. No tool refresh, no save,
501
- // no generation claim — the session file remains exclusively the
502
- // owner's. session-turn-api routes this surface's submits into the
503
- // shared pending spool instead of running a local turn.
504
- function _attachViewerSession(session, sessionId) {
505
- const attached = { ...session, remoteAttached: true };
506
- delete attached.liveTurnMessages;
507
- delete attached.toolApprovalHook;
508
- if (process.env.MIXDOG_DEBUG_SESSION_LOG) {
509
- try {
510
- process.stderr.write(`[session] attach-on-resume: ${sessionId} is live elsewhere → viewer attach\n`);
511
- } catch {
512
- /* best-effort */
513
- }
514
- }
515
- return attached;
516
- }
517
-
518
502
  // Refreshes the session's tool surface from the prepared resume when it still
519
503
  // matches, warning about tools the preset no longer offers.
520
504
  function _refreshResumedTools(session, sessionId, preset) {
@@ -551,7 +535,6 @@ export async function resumeSession(sessionId, preset, options = {}) {
551
535
  if (Object.hasOwn(options, 'mcpScopeId')) {
552
536
  session.mcpScopeId = String(options.mcpScopeId || '').trim() || null;
553
537
  }
554
- if (_isActivelyOwnedElsewhere(session, sessionId)) return _attachViewerSession(session, sessionId);
555
538
  _recoverTurnCheckpointDurably(session, sessionId);
556
539
  _refreshResumedTools(session, sessionId, preset);
557
540
  refreshSessionProviderCacheOpts(session);
@@ -563,5 +546,6 @@ export async function resumeSession(sessionId, preset, options = {}) {
563
546
  process.stderr.write(`[session] resume save failed: ${err?.message || err}\n`);
564
547
  } catch {}
565
548
  });
549
+ prewarmSessionAutoEffort(session, session.provider ? getProvider(session.provider) : null);
566
550
  return session;
567
551
  }
@@ -18,6 +18,7 @@ import {
18
18
  } from '../../tools/builtin/runtime-capabilities.mjs';
19
19
  import { captureOriginalUserCwd } from '../../../../shared/user-cwd.mjs';
20
20
  import { delegationDisabled } from './session-tool-surface.mjs';
21
+ import { contextAckMessage } from '../compact/user-message-kind.mjs';
21
22
 
22
23
  // Preserve the exact pre-layout environment payload: Lead carried the
23
24
  // shell preference in Profile Preferences, while any routing surface with
@@ -89,6 +90,23 @@ export function buildWorkspacePromptContext(session, cwd) {
89
90
 
90
91
  // BP1/BP2/BP3 rule blocks plus the volatile environment, composed into the
91
92
  // four system blocks; environmentTailContext is the persisted env tail.
93
+ export function sessionRolePromptFields(identity, { ownerIsAgent, toolFreeRole, delegationFree }) {
94
+ const skipRules = identity.skipAgentRules || toolFreeRole;
95
+ let roleRules = '';
96
+ if (!skipRules) {
97
+ roleRules = ownerIsAgent
98
+ ? _buildAgentRules(identity.agentRulesProfile)
99
+ : _buildLeadRules({ includeLeadBrief: !delegationFree });
100
+ }
101
+ return {
102
+ roleRules,
103
+ userPrompt: identity.systemPrompt,
104
+ skipRoleCatalog: !ownerIsAgent,
105
+ agent: identity.agent,
106
+ profile: { skip: identity.profileSkip },
107
+ };
108
+ }
109
+
92
110
  export function composeSessionSystem(opts, { profile, providerName, modelName, surface }) {
93
111
  const { ownerIsAgent, resolvedAgent, skills } = surface;
94
112
  // A tool-free hidden role (a one-shot classifier or title writer) carries
@@ -105,12 +123,14 @@ export function composeSessionSystem(opts, { profile, providerName, modelName, s
105
123
  model: modelName,
106
124
  });
107
125
  const delegationFree = delegationDisabled(opts, ownerIsAgent);
108
- let roleRules = '';
109
- if (!skipAgentRules) {
110
- roleRules = ownerIsAgent
111
- ? _buildAgentRules(surface.agentRulesProfile)
112
- : _buildLeadRules({ includeLeadBrief: !delegationFree });
113
- }
126
+ const promptIdentity = {
127
+ systemPrompt: opts.systemPrompt || '',
128
+ skipAgentRules: opts.skipAgentRules === true,
129
+ profileSkip: { ...profile?.skip },
130
+ agent: resolvedAgent,
131
+ agentRulesProfile: surface.agentRulesProfile,
132
+ };
133
+ const roleFields = sessionRolePromptFields(promptIdentity, { ownerIsAgent, toolFreeRole, delegationFree });
114
134
  const leadOnly = !skipAgentRules && !ownerIsAgent;
115
135
  const metaContext = leadOnly ? _buildLeadMetaContext() : '';
116
136
  // Lead-only response language; closes the environment block so no English
@@ -132,14 +152,10 @@ export function composeSessionSystem(opts, { profile, providerName, modelName, s
132
152
  ? ''
133
153
  : loadInstructionFilesContext({ mode: configuredInstructionFilesMode(), cwd: opts.cwd });
134
154
  const composed = composeSystemPrompt({
135
- userPrompt: opts.systemPrompt,
155
+ ...roleFields,
136
156
  agentRules: injectedRules || undefined,
137
- roleRules: roleRules || undefined,
138
157
  metaContext: metaContext || undefined,
139
158
  languageContext: languageContext || undefined,
140
- skipRoleCatalog: !ownerIsAgent,
141
- profile: profile || undefined,
142
- agent: resolvedAgent,
143
159
  workflowContext: opts.workflowContext || null,
144
160
  coreMemoryContext: opts.coreMemoryContext || null,
145
161
  instructionFilesContext: instructionFilesContext || null,
@@ -147,7 +163,7 @@ export function composeSessionSystem(opts, { profile, providerName, modelName, s
147
163
  environmentContext: shellEnvironmentContext,
148
164
  provider: providerName || null,
149
165
  });
150
- return { ...composed, environmentTailContext };
166
+ return { ...composed, environmentTailContext, promptIdentity };
151
167
  }
152
168
 
153
169
  // 4-BP layout (see composeSystemPrompt docs):
@@ -188,7 +204,7 @@ export function seedSessionMessages({ baseRules, stableSystemContext, sessionMar
188
204
  if (files?.length) {
189
205
  const fileContext = files.map((f) => `### ${f.path}\n\`\`\`\n${f.content}\n\`\`\``).join('\n\n');
190
206
  messages.push({ role: 'user', content: `Reference files:\n\n${fileContext}` });
191
- messages.push({ role: 'assistant', content: '.' });
207
+ messages.push(contextAckMessage());
192
208
  }
193
209
  return messages;
194
210
  }
@@ -138,6 +138,8 @@ export function buildSessionRecord({ opts, route, presetObj, surface, prompt, me
138
138
  agent: opts.agent,
139
139
  owner: opts.owner || 'user',
140
140
  bp3CoreContext: prompt.sessionMarkerCore,
141
+ promptIdentity: prompt.promptIdentity,
142
+ callerDisallowedTools: [...(opts.callerDisallowedTools ?? opts.disallowedTools ?? [])],
141
143
  bp3EnvironmentContext: prompt.environmentTailContext,
142
144
  // BP3 core and the volatile environment live in SEPARATE system
143
145
  // blocks (cacheTier 'tier3' vs 'env'). Legacy persisted sessions
@@ -162,9 +164,7 @@ export function buildSessionRecord({ opts, route, presetObj, surface, prompt, me
162
164
  totalInputTokens: 0,
163
165
  totalOutputTokens: 0,
164
166
  totalToolCalls: 0,
165
- // Refreshed on each completed ask() — surfaced by agent type=list for
166
- // debugging + consumed by store.mjs's idle-sweep to reclaim stalled
167
- // agent sessions past RUNNING_STALL_MS.
167
+ // Refreshed on each completed ask() — surfaced by agent type=list.
168
168
  lastUsedAt: Date.now(),
169
169
  tokensCumulative: 0,
170
170
  ...origin,
@@ -0,0 +1,45 @@
1
+ // manager/turn-checkpoint-recovery.mjs
2
+ // Durable recovery of a turn interrupted by a process restart: an interrupted
3
+ // turn checkpoint is committed as interrupted on resume. Every session runs in
4
+ // the daemon, so a turn is live while this process runs it or while another
5
+ // live process owns the daemon; reads never recover a live turn.
6
+ import { join } from 'node:path';
7
+ import { readSingletonOwner } from '../../../../shared/singleton-owner.mjs';
8
+ import { loadSession, saveSession } from '../store.mjs';
9
+ import { dataDir } from '../store-summary-locations.mjs';
10
+ import { runtimeState, isTurnInFlight } from './runtime-state.mjs';
11
+ import { clearTurnCheckpoint, recoverTurnCheckpoint } from './turn-checkpoint.mjs';
12
+
13
+ /** Whether this session's turn may still be running: in flight in this
14
+ * process, or owned by another live process holding the daemon record. */
15
+ export function isSessionTurnLive(sessionId) {
16
+ if (isTurnInFlight(runtimeState.get(sessionId))) return true;
17
+ const { owner, alive } = readSingletonOwner(join(dataDir(), 'daemon-owner.json'));
18
+ return alive && Number(owner.pid) !== process.pid;
19
+ }
20
+
21
+ export function _recoverTurnCheckpointDurably(session, sessionId) {
22
+ const recovery = recoverTurnCheckpoint(session);
23
+ if (!recovery.changed) return recovery;
24
+ // Recovery is a durable reconnect boundary, not a renderer-only view.
25
+ // Persist before removing the checkpoint so a second crash leaves at
26
+ // least one complete copy of the interrupted turn.
27
+ saveSession(session, {
28
+ sync: true,
29
+ expectedGeneration: session.generation,
30
+ });
31
+ if (recovery.turnToken) {
32
+ clearTurnCheckpoint(sessionId, recovery.turnToken);
33
+ }
34
+ return recovery;
35
+ }
36
+
37
+ // Reconnect-safe historical read used by desktop pane peeks. Unlike a normal
38
+ // read-only load, it resolves a dead owner's durable turn checkpoint before
39
+ // returning the transcript; a live turn is returned untouched.
40
+ export function recoverSessionAfterProcessRestart(sessionId) {
41
+ const session = loadSession(sessionId);
42
+ if (!session || session.closed === true || isSessionTurnLive(sessionId)) return session || null;
43
+ _recoverTurnCheckpointDurably(session, sessionId);
44
+ return session;
45
+ }
@@ -2,7 +2,7 @@
2
2
  // Thin facade over the split session-manager modules in ./manager/.
3
3
  //
4
4
  // Module map:
5
- // manager/runtime-liveness.mjs — in-memory stage/heartbeat + accessors
5
+ // manager/runtime-liveness.mjs — in-memory stage/progress + accessors
6
6
  // manager/tool-resolution.mjs — tool policy resolution/narrowing
7
7
  // manager/context-meta.mjs — context-window / compact-trigger meta
8
8
  // manager/prompt-utils.mjs — prompt content shaping helpers
@@ -45,6 +45,7 @@ export {
45
45
  markSessionError,
46
46
  markSessionCancelled,
47
47
  getSessionRuntime,
48
+ isSessionTurnInFlight,
48
49
  isSessionCompactionBlocked,
49
50
  getSessionProgressSnapshot,
50
51
  forEachSessionRuntime,
@@ -59,19 +60,12 @@ export { previewSessionTools } from './manager/tool-resolution.mjs';
59
60
  export {
60
61
  _mergePendingMessageEntries,
61
62
  enqueuePendingMessage,
62
- enqueueRemotePendingMessage,
63
- drainForeignUserInjections,
64
63
  drainPendingMessages,
65
64
  // Shutdown drain so buffered/in-flight spool writes are never abandoned.
66
65
  settlePendingMessageWrites,
67
66
  markCompletionEntry,
68
67
  COMPLETION_NOTIFICATION_KIND,
69
- pendingMessagesSpoolPath,
70
68
  } from './manager/pending-messages.mjs';
71
- // Interactive-presence sidecar (idle-open ownership signal for the
72
- // attach-on-resume guard) — resolved through the manager facade so the
73
- // session-runtime turn API reaches it as mgr.publishSessionPresence.
74
- export { publishSessionPresence, deleteSessionPresence } from './store.mjs';
75
69
 
76
70
  // ── Usage-metrics surface — re-exported unchanged so loop.mjs / smoke scripts
77
71
  // keep resolving these through the facade. ────────────────────────────────
@@ -105,7 +99,6 @@ export {
105
99
  prefetchSession,
106
100
  prepareSessionProjection,
107
101
  resumeSession,
108
- isSessionOwnerGone,
109
102
  recoverSessionAfterProcessRestart,
110
103
  } from './manager/session-lifecycle.mjs';
111
104
  export { askSession, _api_call_with_interrupt } from './manager/ask-session.mjs';
@@ -3,6 +3,7 @@
3
3
  // wrappers are installed on the caller's opts in place for ONE send, and the
4
4
  // returned restore unwinds only our own wrappers.
5
5
  import { isVisibleStreamProgress } from '../../../shared/stream-progress.mjs';
6
+ import { MODEL_THINKING_STAGE } from '../../../shared/quiet-progress.mjs';
6
7
 
7
8
  // Bench-only turn timing (MIXDOG_TURN_TIMING=1): one stderr line per
8
9
  // provider request — TTFT (first visible model progress) and total stream
@@ -61,7 +62,7 @@ function retryVisibilityWrappers(opts, timedOpts, retryAttemptNumber, retryMaxFo
61
62
  if (!(retryAttemptNumber > 0 && prevOnStageChange)) return wrappers;
62
63
  let progressObserved = false;
63
64
  wrappers.onStageChange = (stage, detail) => {
64
- if (!progressObserved && (stage === 'requesting' || stage === 'streaming')) {
65
+ if (!progressObserved && (stage === 'requesting' || stage === 'streaming' || stage === MODEL_THINKING_STAGE)) {
65
66
  return prevOnStageChange('reconnecting', {
66
67
  ...(detail && typeof detail === 'object' ? detail : {}),
67
68
  attempt: retryAttemptNumber,
@@ -37,7 +37,7 @@ import {
37
37
  isThinkingReplayRejection,
38
38
  repairThinkingReplayInPlace,
39
39
  } from './thinking-replay-recovery.mjs';
40
- import { readStreamOutcome } from '../providers/lib/stream-outcome.mjs';
40
+ import { readStreamOutcome, stampStreamOutcome } from '../providers/lib/stream-outcome.mjs';
41
41
  import { cloneProviderReplay } from '../providers/lib/provider-replay.mjs';
42
42
  import { resolveWorkerCompactPolicy } from './loop/compact-policy.mjs';
43
43
  import { agentContextOverflowError } from './loop/context-overflow.mjs';
@@ -260,6 +260,7 @@ export async function sendWithRecovery(ctx) {
260
260
  hooks.logTurnTiming('ok');
261
261
  } catch (sendErr) {
262
262
  hooks.logTurnTiming(`err:${sendErr?.code || sendErr?.name || 'unknown'}`);
263
+ stampStreamOutcome(sendErr, hooks.relayWitness);
263
264
  return await recoverFromSendError(sendErr, { ...ctx, relayWitness: hooks.relayWitness });
264
265
  }
265
266
  return { action: 'proceed', response };
@@ -454,7 +455,9 @@ async function recoverFromSendError(sendErr, state) {
454
455
  if (toolSchemaDropUsed !== true) {
455
456
  const exclusion = rejectedToolSchema(sendErr, state);
456
457
  if (exclusion) {
457
- logLoop(`[loop] provider rejected tool schema "${exclusion.name}" (${loopTag(state)}); dropping it and replaying once`);
458
+ logLoop(
459
+ `[loop] provider rejected tool schema "${exclusion.name}" (${loopTag(state)}); dropping it and replaying once`
460
+ );
458
461
  traceLoop(state, 'tool_schema_drop', { tool: exclusion.name });
459
462
  return { action: 'retry_tool_schema_drop', exclusion };
460
463
  }
@@ -54,7 +54,7 @@ function sideQuestionPrompt(question) {
54
54
  function replyMessages(response) {
55
55
  if (!response) return [];
56
56
  const reply = response.toolCalls?.length
57
- ? buildToolCallAssistantMessage(response, { calls: response.toolCalls, suppressMidTurnText: false, opts: {} })
57
+ ? buildToolCallAssistantMessage(response, { calls: response.toolCalls, opts: {} })
58
58
  : buildIntermediateAssistantMessage(response, {});
59
59
  if (!reply) return [];
60
60
  const stubs = collectAssistantToolCallIds(reply).map((id) => ({
@@ -165,12 +165,17 @@ export async function askSideQuestion(sessionId, question) {
165
165
  const { messages, opts } = buildSideQuestionRequest(request, text);
166
166
  let response;
167
167
  try {
168
- response = await request.provider.send(messages, request.model, request.tools.length ? request.tools : undefined, {
169
- ...opts,
170
- transportScope,
171
- admissionOwner: sessionId,
172
- signal: run.signal,
173
- });
168
+ response = await request.provider.send(
169
+ messages,
170
+ request.model,
171
+ request.tools.length ? request.tools : undefined,
172
+ {
173
+ ...opts,
174
+ transportScope,
175
+ admissionOwner: sessionId,
176
+ signal: run.signal,
177
+ }
178
+ );
174
179
  } catch (error) {
175
180
  throw run.signal.aborted ? run.signal.reason : error;
176
181
  }
@@ -11,7 +11,7 @@ import { join } from 'node:path';
11
11
  import { getPluginData } from '../../config.mjs';
12
12
  import { PLUGIN_LOG_MAX_BYTES, PLUGIN_LOG_KEEP_BYTES } from '../../../../../lib/mixdog-debug.cjs';
13
13
  import { createAsyncLogAppender } from '../../../../shared/async-log-appender.mjs';
14
- import { sessionPath, deleteHeartbeat } from './paths-heartbeat.mjs';
14
+ import { sessionPath } from './session-paths.mjs';
15
15
  import {
16
16
  readCanonicalSessionRecord as _readCanonicalRecord,
17
17
  CANONICAL_RECORD_UNREADABLE as LIFECYCLE_AMBIGUOUS,
@@ -36,7 +36,7 @@ import {
36
36
  } from './live-state.mjs';
37
37
  import { _uncacheSessionSummary, _queueSessionSummaryUpsert } from './summary-cache.mjs';
38
38
  import { _savePending, _clearDebounce } from './pending-saves.mjs';
39
- import { _runtimeLivenessVeto, _heartbeatLivenessVeto, _deleteHeartbeatUnlessNewer } from './liveness-veto.mjs';
39
+ import { _runtimeLivenessVeto } from './liveness-veto.mjs';
40
40
  import { loadSession } from './load-session.mjs';
41
41
 
42
42
  // Cancellation truth, single rule: an UNCONFIRMED stop outranks a confirmed
@@ -185,15 +185,11 @@ export function markSessionClosed(id, reason = 'manual', options = {}) {
185
185
  // Caller-provided probes may re-enter the store, so evaluate them before
186
186
  // taking the non-reentrant Atomics commit lock. A veto must also precede
187
187
  // pending-save cancellation so debounce durability remains intact.
188
- if (_runtimeLivenessVeto(id, options) || _heartbeatLivenessVeto(id, options)) return null;
188
+ if (_runtimeLivenessVeto(id, options)) return null;
189
189
  const closeGuard = _guardedSaveOptions(id);
190
190
  const commitControl = _acquireWriteCommit(closeGuard);
191
191
  if (commitControl === false) return null;
192
192
  try {
193
- // Cross-process heartbeat revival after full-TTL silence is accepted as a
194
- // best-effort race: the tombstone resurrection guard is the authoritative
195
- // post-race arbiter. Re-stat here, but never invoke caller code under lock.
196
- if (_heartbeatLivenessVeto(id, options)) return null;
197
193
  const authority = _readLifecycleAuthority(id, reason, 'close');
198
194
  if (authority === LIFECYCLE_AMBIGUOUS) return null;
199
195
  // Only a committed close may disrupt pending persistence.
@@ -230,7 +226,7 @@ export function markSessionClosed(id, reason = 'manual', options = {}) {
230
226
  const tombstone = {
231
227
  ...base,
232
228
  closed: true,
233
- closedReason: alreadyClosed ? base.closedReason || reason : reason,
229
+ closedReason: alreadyClosed && reason !== 'desktop-session-delete' ? base.closedReason || reason : reason,
234
230
  status: 'closed',
235
231
  generation: newGen,
236
232
  updatedAt: closeTime,
@@ -240,8 +236,6 @@ export function markSessionClosed(id, reason = 'manual', options = {}) {
240
236
  _savePending.delete(id);
241
237
  clearSessionSaveError(id);
242
238
  _clearLiveSession(id);
243
- // Preserve a sidecar published strictly after the sweep's scan snapshot.
244
- _deleteHeartbeatUnlessNewer(id, options);
245
239
  _queueSessionSummaryUpsert(tombstone);
246
240
  _droppedSaveIds.delete(id);
247
241
  // Emit the close metric only on the FIRST close — a re-close of an
@@ -257,7 +251,7 @@ export function markSessionClosed(id, reason = 'manual', options = {}) {
257
251
  /**
258
252
  * Bump a session's generation WITHOUT planting a closed:true tombstone.
259
253
  * Used by closeSession(id, reason, { tombstone: false }) — the runtime side
260
- * (heartbeat, bash shells, controller, in-memory entry) is detached, but the
254
+ * (bash shells, controller, in-memory entry) is detached, but the
261
255
  * session file itself stays valid/resumable. The generation bump alone is
262
256
  * what protects it from a late save race: any saveSession() still in flight
263
257
  * from the detached turn was issued with the OLD generation as its
@@ -299,7 +293,6 @@ export function bumpSessionGeneration(id, reason = 'detach', options = {}) {
299
293
  _savePending.delete(id);
300
294
  clearSessionSaveError(id);
301
295
  _clearLiveSession(id);
302
- deleteHeartbeat(id);
303
296
  _queueSessionSummaryUpsert(detached);
304
297
  _droppedSaveIds.delete(id);
305
298
  return newGen;
@@ -6,7 +6,7 @@
6
6
  * path and of the in-memory snapshot caches.
7
7
  */
8
8
  import { readCanonicalSessionRecord, CANONICAL_RECORD_UNREADABLE } from './canonical-reader.mjs';
9
- import { sessionPath } from './paths-heartbeat.mjs';
9
+ import { sessionPath } from './session-paths.mjs';
10
10
 
11
11
  /**
12
12
  * Cheap authoritative lifecycle read straight from disk (no live/pending