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
@@ -1,117 +0,0 @@
1
- // manager/session-owner-liveness.mjs
2
- // Is another live process driving this session right now?
3
- //
4
- // Attach-on-resume guard: resuming a session that another live process is
5
- // ACTIVELY driving right now must not create a second writer on the same
6
- // file — that split-brain silently freezes one side's transcript (generation
7
- // ownership drops the loser's saves). Such a resume ATTACHES instead: the
8
- // caller gets the live transcript flagged remoteAttached, its submits are
9
- // persisted into the shared pending spool (the owner's injection poller runs
10
- // them as normal user turns), and its view refreshes from disk. ONE writer,
11
- // ONE transcript, every surface talking into the same conversation. Idle
12
- // sessions keep the normal single-identity handoff.
13
- //
14
- // The answer comes from three durable signals — the in-process runtime entry,
15
- // the `.own` presence sidecar and the `.hb` heartbeat — each verified against
16
- // the pid the sidecar recorded so a force-killed owner can never look live.
17
- // The session file's own `lastHeartbeatAt`/`clientHostPid` are NOT liveness
18
- // evidence: the file outlives its writer, and its host pid can name an older
19
- // process (or a recycled pid), so a restart within the freshness window
20
- // reopened the session as a viewer whose prompts spooled to nobody.
21
- import {
22
- loadSession,
23
- saveSession,
24
- readSessionHeartbeatMtime,
25
- readSessionPresenceMtime,
26
- isSessionPresenceOwnerDead,
27
- deleteSessionPresence,
28
- isSessionHeartbeatOwnerDead,
29
- readSessionHeartbeatOwnerPid,
30
- deleteHeartbeat,
31
- } from '../store.mjs';
32
- import { _getRuntimeEntry } from './runtime-liveness.mjs';
33
- import { clearTurnCheckpoint, recoverTurnCheckpoint } from './turn-checkpoint.mjs';
34
-
35
- const ACTIVE_OWNER_HB_FRESH_MS = 2 * 60 * 1000; // heartbeat freshness window
36
-
37
- export function _isActivelyOwnedElsewhere(_session, sessionId) {
38
- // This process already owns the runtime for the id — switching back to
39
- // one of our own sessions (desktop tab switch, TUI /resume) never attaches.
40
- const entry = _getRuntimeEntry(sessionId);
41
- if (entry && entry.closed !== true) return false;
42
- // A FORCE-KILLED owner leaves its `.own` sidecar behind looking fresh.
43
- // The recorded pid is authoritative: when it no longer exists, the owner
44
- // is gone — clear the stale sidecar and resume with normal ownership
45
- // instead of viewer-attaching into a spool nobody drains.
46
- if (isSessionPresenceOwnerDead(sessionId)) {
47
- deleteSessionPresence(sessionId);
48
- return false;
49
- }
50
- const now = Date.now();
51
- // Presence (`.own`, pid-verified just above) covers the idle gaps between
52
- // turns: a live interactive surface keeps refreshing it (~20s) for its
53
- // CURRENT session, so cross-opening an idle-but-open session still
54
- // attaches as a viewer instead of splitting ownership into two writers
55
- // that clobber each other's saves.
56
- const presenceAt = Number(readSessionPresenceMtime(sessionId)) || 0;
57
- if (presenceAt > 0 && now - presenceAt <= ACTIVE_OWNER_HB_FRESH_MS) return true;
58
- // Heartbeats publish only while a turn is running (≤5s cadence) and the
59
- // sidecar is deleted on detach/close, so freshness here means another
60
- // process is mid-conversation on this session right now — PROVIDED that
61
- // process still exists. Without the pid check a force-killed owner (app
62
- // upgrade restart, crash) kept looking live for the whole freshness
63
- // window, so every cross-open attached as a viewer and the user's
64
- // messages spooled to a queue nobody drains (silently dropped 30m later).
65
- if (isSessionHeartbeatOwnerDead(sessionId)) {
66
- void deleteHeartbeat(sessionId);
67
- return false;
68
- }
69
- // Fresh sidecar whose recorded pid is alive: a real owner is driving this
70
- // session right now. Anything weaker (no sidecar, a pid-less legacy one)
71
- // proves no live owner, whatever the session file remembers.
72
- const sidecarAt = Number(readSessionHeartbeatMtime(sessionId)) || 0;
73
- return sidecarAt > 0 && now - sidecarAt <= ACTIVE_OWNER_HB_FRESH_MS && readSessionHeartbeatOwnerPid(sessionId) > 0;
74
- }
75
-
76
- // Viewer self-heal probe: true when a re-resume of this session would NO
77
- // LONGER attach (owner dead or every liveness signal stale). Attached
78
- // surfaces poll this so a dead owner promotes the viewer instead of leaving
79
- // it spooling messages to nobody. Single source of truth: the same guard
80
- // the resume path uses.
81
- export function isSessionOwnerGone(sessionId) {
82
- const session = loadSession(sessionId);
83
- if (!session) return false;
84
- return !_isActivelyOwnedElsewhere(session, sessionId);
85
- }
86
-
87
- export function _recoverTurnCheckpointDurably(session, sessionId) {
88
- const recovery = recoverTurnCheckpoint(session);
89
- if (!recovery.changed) return recovery;
90
- // Recovery is a durable reconnect boundary, not a renderer-only view.
91
- // Persist before removing the checkpoint so a second crash leaves at
92
- // least one complete copy of the interrupted turn.
93
- saveSession(session, {
94
- sync: true,
95
- expectedGeneration: session.generation,
96
- });
97
- if (recovery.turnToken) {
98
- clearTurnCheckpoint(sessionId, recovery.turnToken);
99
- }
100
- // A force-killed owner cannot clear its activity/presence sidecars. Once
101
- // its checkpoint is committed as interrupted, neither sidecar may keep a
102
- // restored pane busy or make a new prompt queue behind a dead process.
103
- deleteSessionPresence(sessionId);
104
- void deleteHeartbeat(sessionId);
105
- return recovery;
106
- }
107
-
108
- // Reconnect-safe historical read used by desktop pane peeks. Unlike a normal
109
- // read-only load, it resolves a dead owner's durable turn checkpoint before
110
- // returning the transcript. A genuinely live foreign owner remains untouched.
111
- export function recoverSessionAfterProcessRestart(sessionId) {
112
- const session = loadSession(sessionId);
113
- if (!session || session.closed === true) return session || null;
114
- if (_isActivelyOwnedElsewhere(session, sessionId)) return session;
115
- _recoverTurnCheckpointDurably(session, sessionId);
116
- return session;
117
- }
@@ -1,302 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync } from 'node:fs';
2
- import * as fsp from 'node:fs/promises';
3
- import { join } from 'node:path';
4
- import { getPluginData } from '../../config.mjs';
5
-
6
- // Session file paths are rebuilt on every load/save/sidecar probe. Memoize the
7
- // joined strings per data dir: a changed data dir (MIXDOG_DATA_DIR switch)
8
- // drops the whole memo, and the per-extension maps are bounded.
9
- const SESSION_PATH_MEMO_LIMIT = 4096;
10
- let _memoDataDir = null;
11
- let _memoStoreDir = null;
12
- const _memoFilePaths = new Map(); // extension → Map<id, path>
13
-
14
- function _storeDirPath() {
15
- const dataDir = getPluginData();
16
- if (dataDir !== _memoDataDir) {
17
- _memoDataDir = dataDir;
18
- _memoStoreDir = join(dataDir, 'sessions');
19
- _memoFilePaths.clear();
20
- }
21
- return _memoStoreDir;
22
- }
23
-
24
- function _memoFilePath(dir, id, extension) {
25
- let byId = _memoFilePaths.get(extension);
26
- if (!byId) {
27
- byId = new Map();
28
- _memoFilePaths.set(extension, byId);
29
- }
30
- let path = byId.get(id);
31
- if (path === undefined) {
32
- path = join(dir, _sessionFileName(id, extension));
33
- if (byId.size >= SESSION_PATH_MEMO_LIMIT) byId.clear();
34
- byId.set(id, path);
35
- }
36
- return path;
37
- }
38
- export function getStoreDir() {
39
- const dir = _storeDirPath();
40
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
41
- return dir;
42
- }
43
- function _sessionFileName(id, extension) {
44
- return `${id}${extension}`;
45
- }
46
- // Enforce minted session-id shape before using it in a path to prevent
47
- // `../` traversal. session IDs are generated by createSession as
48
- // `sess_<timestamp>_<hex>` — reject anything that doesn't match.
49
- function _assertSessionId(id) {
50
- if (!id || typeof id !== 'string' || !/^[A-Za-z0-9_-]+$/.test(id)) {
51
- throw new Error(`[session-store] invalid session id: ${JSON.stringify(id)}`);
52
- }
53
- }
54
- function _sessionFilePath(id, extension) {
55
- _assertSessionId(id);
56
- return _memoFilePath(getStoreDir(), id, extension);
57
- }
58
- export function sessionPath(id) {
59
- return _sessionFilePath(id, '.json');
60
- }
61
-
62
- // ── Sidecar owner-pid helpers ─────────────────────────────
63
- // Liveness sidecars record the publishing process id on their SECOND line so
64
- // a reader can tell a genuinely live owner from a force-killed one whose
65
- // timestamp still looks fresh. Legacy (pid-less) sidecars read back as 0.
66
- export function isProcessAlive(pid) {
67
- const target = Number(pid) || 0;
68
- if (target <= 0) return false;
69
- try {
70
- process.kill(target, 0);
71
- return true;
72
- } catch (error) {
73
- // ESRCH: no such process. EPERM means the pid exists (alive).
74
- return error?.code !== 'ESRCH';
75
- }
76
- }
77
-
78
- function _readSidecarOwnerPid(path) {
79
- try {
80
- return Number(String(readFileSync(path, 'utf8')).split('\n')[1]) || 0;
81
- } catch {
82
- return 0;
83
- }
84
- }
85
-
86
- /** True only when the sidecar recorded an owner pid that no longer exists
87
- * (pid-less legacy sidecars prove nothing and read false). */
88
- export function isSidecarOwnerDead(path) {
89
- const pid = _readSidecarOwnerPid(path);
90
- return pid > 0 && !isProcessAlive(pid);
91
- }
92
-
93
- // ── Heartbeat publish ─────────────────────────────────────
94
- // Lightweight per-session timestamp file (`<id>.hb`) consumed by the
95
- // status aggregator for fresh-session detection. Decoupled from the
96
- // full session JSON save so it can fire at a tight cadence (≤5s)
97
- // without serialising the whole payload. The .hb file holds
98
- // `<msTimestamp>\n<pid>\n` — readers that only need liveness use the file
99
- // mtime, while the attach-on-resume guard verifies the recorded pid.
100
- // Aggregator scans the same sessions/ directory and matches `<id>.hb` to
101
- // `<id>.json`.
102
- const _HEARTBEAT_THROTTLE_MS = 5_000;
103
- const _hbLastAt = new Map();
104
- const _hbOperations = new Map();
105
-
106
- function _queueHeartbeatOperation(id, operation) {
107
- const prior = _hbOperations.get(id) || Promise.resolve();
108
- const next = prior.then(operation, operation).catch(() => {});
109
- _hbOperations.set(id, next);
110
- void next.then(() => {
111
- if (_hbOperations.get(id) === next) _hbOperations.delete(id);
112
- });
113
- return next;
114
- }
115
-
116
- function _heartbeatPath(id) {
117
- return _sessionFilePath(id, '.hb');
118
- }
119
-
120
- export function publishHeartbeat(id, ts) {
121
- if (!id) return Promise.resolve();
122
- const now = ts || Date.now();
123
- const last = _hbLastAt.get(id) || 0;
124
- if (now - last < _HEARTBEAT_THROTTLE_MS) {
125
- return _hbOperations.get(id) || Promise.resolve();
126
- }
127
- const target = _heartbeatPath(id);
128
- _hbLastAt.set(id, now);
129
- return _queueHeartbeatOperation(id, () => fsp.writeFile(target, `${now}\n${process.pid}\n`, 'utf8'));
130
- }
131
-
132
- export function deleteHeartbeat(id) {
133
- if (!id) return Promise.resolve();
134
- // Deleting needs no directory: skip getStoreDir's synchronous probe.
135
- _assertSessionId(id);
136
- const target = _memoFilePath(_storeDirPath(), id, '.hb');
137
- // One ordered async delete behind any pending write for this id. It starts
138
- // on the next microtask when nothing is pending, so the marker still drops
139
- // at once, without a synchronous unlink on the turn-settle path. Queuing it
140
- // (rather than deleting beside the write) keeps a write started just before
141
- // turn completion from landing after the delete and resurrecting the
142
- // session's working badge for the full freshness window.
143
- _hbLastAt.delete(id);
144
- return _queueHeartbeatOperation(id, () => fsp.unlink(target).catch(() => {}));
145
- }
146
-
147
- // Batch reader for session catalogs. Scanning only the handful of `.hb`
148
- // sidecars avoids one failed stat per historical session while still exposing
149
- // cross-process turn activity to desktop/TUI resume lists.
150
- export function listSessionHeartbeatMtimes() {
151
- const result = new Map();
152
- try {
153
- const dir = getStoreDir();
154
- for (const filename of readdirSync(dir)) {
155
- if (!filename.endsWith('.hb')) continue;
156
- const id = filename.slice(0, -3);
157
- if (!/^[A-Za-z0-9_-]+$/.test(id)) continue;
158
- try {
159
- const mtime = statSync(join(dir, filename)).mtimeMs || 0;
160
- if (mtime > 0) result.set(id, mtime);
161
- } catch {
162
- /* sidecar disappeared after readdir */
163
- }
164
- }
165
- } catch {
166
- /* catalog activity is best-effort */
167
- }
168
- return result;
169
- }
170
-
171
- // Owner pid recorded in the `<id>.hb` sidecar (0 when absent or written by a
172
- // pre-pid build).
173
- export function readSessionHeartbeatOwnerPid(id) {
174
- if (!id) return 0;
175
- try {
176
- return _readSidecarOwnerPid(_heartbeatPath(id));
177
- } catch {
178
- return 0;
179
- }
180
- }
181
-
182
- // A killed owner never deletes its `.hb` sidecar, so bare mtime freshness
183
- // would keep the session "actively driven" for the whole freshness window and
184
- // every cross-open would attach as a viewer whose submits spool to nobody.
185
- // The recorded pid is authoritative proof; pid-less legacy sidecars return
186
- // false (unknown, not dead).
187
- export function isSessionHeartbeatOwnerDead(id) {
188
- const pid = readSessionHeartbeatOwnerPid(id);
189
- if (!pid) return false;
190
- return !isProcessAlive(pid);
191
- }
192
-
193
- // ── Interactive presence publish ──────────────────────────
194
- // `<id>.own` marks a live interactive surface (TUI/desktop engine) HOLDING
195
- // the session open — including idle time between turns. Kept separate from
196
- // `.hb` (turn-activity signal consumed by the status aggregator and deleted
197
- // at turn end) so idle presence never fakes a "running" badge. Consumed by
198
- // the attach-on-resume guard (_isActivelyOwnedElsewhere): fresh presence
199
- // means a cross-open must attach as a viewer instead of claiming a second
200
- // writer on the same session file (dual-writer last-save-wins clobbering).
201
- // Refreshed by the engine share tick (~3s call, throttled here) and cleared
202
- // on session switch/dispose; staleness covers crashes.
203
- //
204
- // Presence is a sidecar OF a session record and never outlives it: it is
205
- // only published while the record exists, and a publish that loses a race
206
- // with a deletion (this process or another one unlinked the record and its
207
- // sidecar while the write was in flight) removes what it just wrote.
208
- const _PRESENCE_THROTTLE_MS = 20_000;
209
- const _presenceLastAt = new Map();
210
- // id -> in-flight publish; deleteSessionPresence cancels it so the write that
211
- // lands after the unlink is removed again instead of resurrecting the file.
212
- const _presenceInFlight = new Map();
213
-
214
- function _presencePath(id) {
215
- return _sessionFilePath(id, '.own');
216
- }
217
-
218
- async function _sessionRecordExists(id) {
219
- try {
220
- await fsp.stat(sessionPath(id));
221
- return true;
222
- } catch (error) {
223
- // Only a proven absence stops the beacon; an unreadable stat keeps it.
224
- return error?.code !== 'ENOENT';
225
- }
226
- }
227
-
228
- async function _publishPresence(id, now, flight) {
229
- try {
230
- // A record that does not exist (never saved yet, or deleted) gets no
231
- // beacon; the throttle stays open so the next tick retries.
232
- if (!(await _sessionRecordExists(id)) || flight.cancelled) {
233
- if (_presenceLastAt.get(id) === now) _presenceLastAt.delete(id);
234
- return;
235
- }
236
- const target = _presencePath(id);
237
- await fsp.writeFile(target, `${now}\n${process.pid}\n`, 'utf8');
238
- if (flight.cancelled || !(await _sessionRecordExists(id))) {
239
- await fsp.unlink(target).catch(() => {});
240
- if (_presenceLastAt.get(id) === now) _presenceLastAt.delete(id);
241
- }
242
- } catch {
243
- /* best-effort beacon */
244
- } finally {
245
- if (_presenceInFlight.get(id) === flight) _presenceInFlight.delete(id);
246
- }
247
- }
248
-
249
- export function publishSessionPresence(id, ts) {
250
- if (!id) return;
251
- const now = ts || Date.now();
252
- const last = _presenceLastAt.get(id) || 0;
253
- if (now - last < _PRESENCE_THROTTLE_MS) return;
254
- if (_presenceInFlight.has(id)) return;
255
- _assertSessionId(id);
256
- _presenceLastAt.set(id, now);
257
- const flight = { cancelled: false, done: null };
258
- _presenceInFlight.set(id, flight);
259
- flight.done = _publishPresence(id, now, flight);
260
- }
261
-
262
- /** Test/drain seam: resolves once the id's in-flight presence publish settled. */
263
- export function settleSessionPresence(id) {
264
- return _presenceInFlight.get(id)?.done || Promise.resolve();
265
- }
266
-
267
- export function deleteSessionPresence(id) {
268
- if (!id) return;
269
- const flight = _presenceInFlight.get(id);
270
- if (flight) flight.cancelled = true;
271
- try {
272
- unlinkSync(_presencePath(id));
273
- } catch {
274
- /* ignore */
275
- }
276
- _presenceLastAt.delete(id);
277
- }
278
-
279
- export function readSessionPresenceMtime(id) {
280
- if (!id) return 0;
281
- try {
282
- return statSync(_presencePath(id)).mtimeMs || 0;
283
- } catch {
284
- return 0;
285
- }
286
- }
287
-
288
- // A force-killed owner never clears its presence sidecar, so bare mtime
289
- // freshness would lock every resume inside the window into viewer mode with
290
- // nobody draining the shared spool. The `.own` payload records the holder's
291
- // pid; a recorded-but-dead pid is authoritative proof the owner is gone.
292
- export function isSessionPresenceOwnerDead(id) {
293
- if (!id) return false;
294
- let pid = 0;
295
- try {
296
- pid = _readSidecarOwnerPid(_presencePath(id));
297
- } catch {
298
- return false;
299
- }
300
- if (!pid) return false;
301
- return !isProcessAlive(pid);
302
- }
@@ -1,142 +0,0 @@
1
- // Delayed reap timers: arm a terminal row's deadline, fire the reap when it
2
- // elapses, and rebuild the timers after a process restart.
3
- import { clean, clearAgentStatuslineRoute } from '../helpers.mjs';
4
- import { workerRowTime } from '../worker-rows.mjs';
5
- import { resolveAgentTerminalReapMs } from '../../../../runtime/agent/orchestrator/runtime-core/config-helpers.mjs';
6
- import { isTerminalRow } from './row-helpers.mjs';
7
-
8
- export function createReapTimers({ cfgMod, mgr, index, getLiveSession, tagForSession, tombstoneTerminalSession }) {
9
- const { readWorkerRows, writeWorkerRows, flushWorkerIndexMutations } = index;
10
- const reapTimers = new Map();
11
- // sessionId -> the reapAt a live timer was armed for. Lets a repeated session
12
- // scan recognise an already-armed deadline instead of re-arming (and thus
13
- // re-stamping) the same terminal lease on every list read.
14
- const scheduledReapAt = new Map();
15
-
16
- function isArmedFor(sessionId, reapAt) {
17
- return reapTimers.has(sessionId) && scheduledReapAt.get(sessionId) === reapAt;
18
- }
19
-
20
- /** closeAll() drops every timer wholesale; the armed-deadline bookkeeping
21
- * must go with them or a later scan would trust a timer that no longer runs. */
22
- function clearScheduledReaps() {
23
- scheduledReapAt.clear();
24
- }
25
-
26
- function cancelReap(sessionId) {
27
- const handle = reapTimers.get(sessionId);
28
- scheduledReapAt.delete(sessionId);
29
- if (!handle) return false;
30
- clearTimeout(handle);
31
- reapTimers.delete(sessionId);
32
- return true;
33
- }
34
-
35
- function reapTerminalRow(row) {
36
- const sessionId = clean(row?.sessionId);
37
- const reapAt = clean(row?.reapAt);
38
- const tag = clean(row?.tag) || tagForSession(sessionId);
39
- if (!sessionId || !reapAt || !tag) return false;
40
- const session = getLiveSession(sessionId);
41
- if (!tombstoneTerminalSession(tag, sessionId, session, reapAt)) return false;
42
- try {
43
- mgr.hideSessionFromList?.(sessionId);
44
- } catch {}
45
- clearAgentStatuslineRoute(sessionId);
46
- // Reaping expires only the reusable tag/runtime lease. The transcript is
47
- // user-visible from the parent task's agent tab, so terminal cleanup must
48
- // never tombstone it ahead of that parent.
49
- try {
50
- mgr.unloadSessionRuntime?.(sessionId, 'terminal-reap');
51
- } catch {}
52
- return true;
53
- }
54
-
55
- function schedulePersistedReap(row) {
56
- const sessionId = clean(row?.sessionId);
57
- const reapAt = clean(row?.reapAt);
58
- const deadline = Date.parse(reapAt) || 0;
59
- if (!sessionId || !deadline) return false;
60
- cancelReap(sessionId);
61
- const handle = setTimeout(
62
- () => {
63
- reapTimers.delete(sessionId);
64
- scheduledReapAt.delete(sessionId);
65
- reapTerminalRow(row);
66
- },
67
- Math.max(0, deadline - Date.now())
68
- );
69
- handle.unref?.();
70
- reapTimers.set(sessionId, handle);
71
- scheduledReapAt.set(sessionId, reapAt);
72
- return true;
73
- }
74
-
75
- function scheduleReap(sessionId, provider = null) {
76
- const id = clean(sessionId);
77
- if (!id) return false;
78
- cancelReap(id);
79
- // The terminal upsert is deferred to batch parallel fanout writes. Flush it
80
- // before stamping the deadline so reapAt and the terminal state land in one
81
- // durable lifecycle order.
82
- flushWorkerIndexMutations();
83
- const row = readWorkerRows().find((entry) => clean(entry.sessionId) === id);
84
- if (!row || !isTerminalRow(row)) return false;
85
- const reapProvider = clean(provider) || clean(row.provider) || clean(getLiveSession(id)?.provider) || null;
86
- const reapMs = resolveAgentTerminalReapMs(cfgMod.loadConfig(), reapProvider);
87
- const reapAt = reapMs == null ? null : new Date(Date.now() + reapMs).toISOString();
88
- let persisted = null;
89
- writeWorkerRows((byKey) => {
90
- for (const [key, current] of byKey.entries()) {
91
- if (clean(current.sessionId) !== id) continue;
92
- if (!isTerminalRow(current)) return;
93
- persisted = { ...current, reapAt };
94
- byKey.set(key, persisted);
95
- return;
96
- }
97
- });
98
- return persisted?.reapAt ? schedulePersistedReap(persisted) : false;
99
- }
100
-
101
- /** Rebuild child terminal timers after a process restart. Legacy rows have
102
- * no reapAt, so derive the original absolute deadline from their frozen
103
- * terminal stamp instead of granting a fresh full lease on every boot. */
104
- function recoverTerminalReaps() {
105
- flushWorkerIndexMutations();
106
- const now = Date.now();
107
- const recovered = [];
108
- writeWorkerRows((byKey) => {
109
- for (const [key, row] of byKey.entries()) {
110
- if (!isTerminalRow(row)) continue;
111
- let reapAt = clean(row.reapAt);
112
- if (!(Date.parse(reapAt) > 0)) {
113
- const reapMs = resolveAgentTerminalReapMs(cfgMod.loadConfig(), row.provider);
114
- if (reapMs == null) continue;
115
- const terminalAt = workerRowTime(row);
116
- // A timestamp-free legacy row cannot prove that its grace already
117
- // elapsed. Give it one normal window from recovery; timestamped rows
118
- // keep their original completion-based deadline.
119
- reapAt = new Date((terminalAt > 0 ? terminalAt : now) + reapMs).toISOString();
120
- }
121
- const next = { ...row, reapAt };
122
- byKey.set(key, next);
123
- recovered.push(next);
124
- }
125
- });
126
- for (const row of recovered) {
127
- if ((Date.parse(row.reapAt) || 0) <= now) reapTerminalRow(row);
128
- else schedulePersistedReap(row);
129
- }
130
- }
131
-
132
- return {
133
- reapTimers,
134
- isArmedFor,
135
- clearScheduledReaps,
136
- cancelReap,
137
- reapTerminalRow,
138
- schedulePersistedReap,
139
- scheduleReap,
140
- recoverTerminalReaps,
141
- };
142
- }
@@ -1,77 +0,0 @@
1
- /**
2
- * src/session-runtime/turn/share-ops.mjs - cross-surface session sharing on
3
- * the owner side: pending-spool intake, presence beacon, and the viewer's
4
- * owner-liveness probe.
5
- */
6
- export function createShareOps({ getSession, getActiveTurnCount, mgr, isSessionAdmissionOpen }) {
7
- // Owner-side injection intake: foreign user messages persisted into the
8
- // shared spool by an attached surface. Engine pollers call this while
9
- // idle and run each returned text through the normal submit queue.
10
- async function takeRemoteInjections() {
11
- const session = getSession();
12
- if (!session?.id || session.remoteAttached) return [];
13
- // Pending-spool intake is an admission route: a fenced/closed owner leaves
14
- // the spool untouched.
15
- if (isSessionAdmissionOpen && !isSessionAdmissionOpen()) return [];
16
- if (getActiveTurnCount() > 0) return [];
17
- try {
18
- return (await mgr.drainForeignUserInjections?.(session.id)) || [];
19
- } catch {
20
- return [];
21
- }
22
- }
23
-
24
- // Absolute path of THIS session's pending spool shard. Live-share owners
25
- // fs.watch it for instant cross-surface input pickup; empty string when
26
- // there is no session or the store is unavailable (callers fall back to the
27
- // poll tick).
28
- function pendingSpoolPath() {
29
- try {
30
- return mgr.pendingMessagesSpoolPath?.(getSession()?.id) || '';
31
- } catch {
32
- return '';
33
- }
34
- }
35
-
36
- // Interactive-presence beacon (engine share tick): mark the CURRENT
37
- // session as held open by this live surface — idle time included — so a
38
- // cross-open from another surface attaches as a viewer instead of
39
- // splitting ownership into two writers. No-op while THIS surface is the
40
- // viewer. Returns the held id so the caller can clear a previous
41
- // session's beacon after a switch.
42
- function publishSessionPresence() {
43
- const session = getSession();
44
- if (!session?.id || session.remoteAttached) return null;
45
- try {
46
- mgr.publishSessionPresence?.(session.id);
47
- } catch {
48
- /* best-effort */
49
- }
50
- return session.id;
51
- }
52
-
53
- function clearSessionPresence(id) {
54
- const target = id || getSession()?.id;
55
- if (!target) return;
56
- try {
57
- mgr.deleteSessionPresence?.(target);
58
- } catch {
59
- /* best-effort */
60
- }
61
- }
62
-
63
- // Live-owner liveness probe for the viewer self-heal tick: true when a
64
- // re-resume would no longer attach (owner pid dead or every liveness
65
- // signal stale) — i.e. nobody is draining this session's spool anymore.
66
- function sessionOwnerGone(id) {
67
- const target = id || getSession()?.id;
68
- if (!target) return false;
69
- try {
70
- return mgr.isSessionOwnerGone?.(target) === true;
71
- } catch {
72
- return false;
73
- }
74
- }
75
-
76
- return { takeRemoteInjections, pendingSpoolPath, publishSessionPresence, clearSessionPresence, sessionOwnerGone };
77
- }