mixdog 1.2.2 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (692) hide show
  1. package/README.md +18 -0
  2. package/package.json +2 -1
  3. package/scripts/gate-local.mjs +6 -4
  4. package/scripts/lib/gate-scheduler.mjs +29 -11
  5. package/scripts/probe-provider-catalog.mjs +31 -0
  6. package/scripts/provider-pingpong-live.mjs +599 -0
  7. package/scripts/session-sweep.mjs +5 -25
  8. package/src/agents/advisor/AGENT.md +1 -1
  9. package/src/agents/advisor/agent.json +1 -1
  10. package/src/agents/maintainer/AGENT.md +1 -1
  11. package/src/agents/maintainer/agent.json +1 -1
  12. package/src/agents/reviewer/AGENT.md +2 -4
  13. package/src/agents/security/AGENT.md +1 -2
  14. package/src/agents/writer/AGENT.md +2 -3
  15. package/src/defaults/shipped-history.json +11 -1
  16. package/src/defaults/skills/image/SKILL.md +21 -23
  17. package/src/defaults/skills/setup/SKILL.md +6 -1
  18. package/src/defaults/skills/setup/references/actions.md +44 -22
  19. package/src/defaults/skills/setup/references/surfaces.md +10 -8
  20. package/src/headless-exec.mjs +15 -8
  21. package/src/lib/keychain-cjs.cjs +20 -15
  22. package/src/output-styles/common.md +11 -10
  23. package/src/rules/agent/AGENT.md +6 -4
  24. package/src/rules/lead/LEAD.md +7 -9
  25. package/src/rules/shared/45-destructive.md +4 -0
  26. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  27. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +28 -7
  28. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -11
  29. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
  30. package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
  31. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
  32. package/src/runtime/agent/orchestrator/config.mjs +5 -0
  33. package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
  34. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
  35. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
  36. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +101 -23
  37. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +2 -0
  38. package/src/runtime/agent/orchestrator/providers/anthropic-api-key-fetch.mjs +36 -0
  39. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
  40. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +3 -1
  41. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +24 -17
  42. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +9 -9
  43. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  44. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +26 -44
  45. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +31 -15
  46. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
  47. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
  48. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
  49. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
  50. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
  51. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
  52. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
  53. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -0
  54. package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
  55. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +10 -0
  56. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +41 -12
  57. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +13 -1
  58. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +131 -9
  59. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +29 -10
  60. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +125 -8
  61. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +12 -62
  62. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +117 -41
  63. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  64. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +117 -72
  65. package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
  66. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +39 -5
  67. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  68. package/src/runtime/agent/orchestrator/providers/cursor-native-context.mjs +48 -0
  69. package/src/runtime/agent/orchestrator/providers/cursor-wire-exec.mjs +144 -34
  70. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +28 -4
  71. package/src/runtime/agent/orchestrator/providers/cursor-wire-request.mjs +8 -4
  72. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +42 -11
  73. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +109 -6
  74. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +17 -4
  75. package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -2
  76. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +73 -7
  77. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +75 -6
  78. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
  79. package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
  80. package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
  81. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +29 -5
  82. package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
  83. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +36 -13
  84. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +101 -11
  85. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
  86. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +1 -0
  87. package/src/runtime/agent/orchestrator/providers/gemini-rest-stream/watchdogs.mjs +16 -5
  88. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +19 -14
  89. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +371 -41
  90. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -2
  91. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +97 -49
  92. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +81 -10
  93. package/src/runtime/agent/orchestrator/providers/gemini.mjs +35 -8
  94. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  95. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +1 -0
  96. package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
  97. package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
  98. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +253 -42
  99. package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
  100. package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
  101. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +392 -0
  102. package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
  103. package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
  104. package/src/runtime/agent/orchestrator/providers/lib/request-compression.mjs +86 -0
  105. package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
  106. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
  107. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +50 -22
  108. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +133 -21
  109. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
  110. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +7 -1
  111. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
  112. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  113. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +92 -16
  114. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -13
  115. package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
  116. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +133 -62
  117. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
  118. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +5 -2
  119. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +39 -7
  120. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
  121. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +5 -0
  122. package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +1 -1
  123. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +84 -2
  124. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
  125. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
  126. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +155 -0
  127. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +40 -24
  128. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +63 -25
  129. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
  130. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +183 -0
  131. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +87 -6
  132. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +51 -3
  133. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -1
  134. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
  135. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +103 -26
  136. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +23 -4
  137. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +11 -6
  138. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +17 -2
  139. package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +15 -23
  140. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +64 -52
  141. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
  142. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +28 -5
  143. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
  144. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
  145. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +4 -0
  146. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +5 -0
  147. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
  148. package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
  149. package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +3 -1
  150. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +7 -0
  151. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +7 -1
  152. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +72 -24
  153. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
  154. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +50 -16
  155. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -19
  156. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
  157. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -36
  158. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
  159. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
  160. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
  161. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +18 -9
  162. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +181 -0
  163. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +78 -70
  164. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +74 -0
  165. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +150 -10
  166. package/src/runtime/agent/orchestrator/providers/registry.mjs +13 -2
  167. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +7 -1
  168. package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
  169. package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
  170. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +164 -0
  171. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +522 -0
  172. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
  173. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +195 -0
  174. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +104 -0
  175. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +8 -6
  176. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +24 -0
  177. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
  178. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +30 -2
  179. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +3 -2
  180. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -3
  181. package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
  182. package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
  183. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +16 -3
  184. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge-contract.mjs +6 -0
  185. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
  186. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  187. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
  188. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +178 -71
  189. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +102 -12
  190. package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
  191. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -8
  192. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -2
  193. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +24 -0
  194. package/src/runtime/agent/orchestrator/session/cache/tool-result-reuse.mjs +10 -2
  195. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -3
  196. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +5 -11
  197. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +6 -22
  198. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
  199. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +16 -93
  200. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +16 -2
  201. package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
  202. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +148 -0
  203. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  204. package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
  205. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
  206. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +0 -6
  207. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +0 -6
  208. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +3 -2
  209. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
  210. package/src/runtime/agent/orchestrator/session/historical-session-closure.mjs +10 -0
  211. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +2 -5
  212. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +89 -1
  213. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
  214. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
  215. package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
  216. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -27
  217. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +1 -1
  218. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -10
  219. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -9
  220. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +24 -10
  221. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +135 -0
  222. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +31 -4
  223. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +76 -0
  224. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +67 -20
  225. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +10 -10
  226. package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
  227. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +6 -0
  228. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
  229. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +29 -5
  230. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
  231. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +147 -0
  232. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +7 -5
  233. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +33 -3
  234. package/src/runtime/agent/orchestrator/session/manager/ask-support.mjs +0 -4
  235. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +23 -2
  236. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
  237. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +54 -13
  238. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +33 -0
  239. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
  240. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +11 -0
  241. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +22 -0
  242. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +57 -13
  243. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
  244. package/src/runtime/agent/orchestrator/session/manager/failed-turn-rewind.mjs +16 -0
  245. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +6 -120
  246. package/src/runtime/agent/orchestrator/session/manager/pending-persist-queue.mjs +1 -1
  247. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +231 -16
  248. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +42 -49
  249. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +50 -0
  250. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +47 -17
  251. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +26 -4
  252. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
  253. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +36 -35
  254. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +29 -13
  255. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +6 -3
  256. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
  257. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +45 -0
  258. package/src/runtime/agent/orchestrator/session/manager.mjs +4 -10
  259. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
  260. package/src/runtime/agent/orchestrator/session/send-instrumentation.mjs +2 -1
  261. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +17 -1
  262. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
  263. package/src/runtime/agent/orchestrator/session/side-question.mjs +197 -0
  264. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +22 -15
  265. package/src/runtime/agent/orchestrator/session/store/lifecycle-read.mjs +1 -1
  266. package/src/runtime/agent/orchestrator/session/store/listing.mjs +2 -6
  267. package/src/runtime/agent/orchestrator/session/store/live-cache-eviction.mjs +1 -1
  268. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
  269. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +46 -37
  270. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +1 -1
  271. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +1 -1
  272. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +44 -37
  273. package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
  274. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +59 -0
  275. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +1 -1
  276. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +1 -1
  277. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +27 -21
  278. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +0 -8
  279. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +6 -18
  280. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +33 -106
  281. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +4 -2
  282. package/src/runtime/agent/orchestrator/session/store-agent-worker-pool.mjs +5 -8
  283. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +136 -196
  284. package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
  285. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +53 -115
  286. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +8 -0
  287. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +10 -1
  288. package/src/runtime/agent/orchestrator/session/store-summary-locations.mjs +3 -29
  289. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +1 -1
  290. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +17 -10
  291. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +9 -20
  292. package/src/runtime/agent/orchestrator/session/store.mjs +22 -19
  293. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +12 -12
  294. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +38 -14
  295. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +15 -4
  296. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
  297. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
  298. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
  299. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +79 -0
  300. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +72 -15
  301. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +45 -0
  302. package/src/runtime/agent/orchestrator/stall-policy.mjs +50 -0
  303. package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
  304. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
  305. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +5 -1
  306. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +6 -2
  307. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
  308. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +218 -20
  309. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +160 -39
  310. package/src/runtime/agent/orchestrator/tools/builtin/git-partial-stage.mjs +7 -5
  311. package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +14 -5
  312. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +4 -3
  313. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +2 -1
  314. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-path-fanout.mjs +48 -44
  315. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +10 -3
  316. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +247 -49
  317. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +5 -4
  318. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +6 -1
  319. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
  320. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +20 -0
  321. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +101 -2
  322. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
  323. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
  324. package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
  325. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +67 -0
  326. package/src/runtime/agent/orchestrator/tools/lib/process-table-fixture.mjs +50 -0
  327. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +303 -63
  328. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -0
  329. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +108 -18
  330. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +77 -11
  331. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +81 -5
  332. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
  333. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
  334. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
  335. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
  336. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
  337. package/src/runtime/attachments/store.d.mts +9 -0
  338. package/src/runtime/attachments/store.mjs +80 -9
  339. package/src/runtime/browser-bridge/browser-action-contract.d.mts +0 -1
  340. package/src/runtime/browser-bridge/browser-action-contract.mjs +0 -2
  341. package/src/runtime/computer-bridge/action-schema.mjs +219 -196
  342. package/src/runtime/computer-bridge/linux-readiness.d.mts +0 -2
  343. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -16
  344. package/src/runtime/effort-judge/judge-client.mjs +21 -4
  345. package/src/runtime/effort-judge/judge-worker.mjs +4 -1
  346. package/src/runtime/github/tool.mjs +208 -17
  347. package/src/runtime/media/adapters/codex-image.mjs +140 -21
  348. package/src/runtime/media/catalog.mjs +4 -4
  349. package/src/runtime/media/chatgpt-usage.mjs +55 -0
  350. package/src/runtime/media/defaults.mjs +37 -0
  351. package/src/runtime/media/jobs.mjs +12 -2
  352. package/src/runtime/media/lanes.mjs +12 -0
  353. package/src/runtime/media/tool-defs.mjs +15 -4
  354. package/src/runtime/media/tool.mjs +41 -12
  355. package/src/runtime/media/upstream-error.mjs +72 -6
  356. package/src/runtime/memory/index.mjs +1 -0
  357. package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
  358. package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
  359. package/src/runtime/memory/lib/ingest/transcript-rows.mjs +1 -0
  360. package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
  361. package/src/runtime/memory/lib/pg/process.mjs +36 -33
  362. package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
  363. package/src/runtime/memory/lib/pg/supervisor.mjs +112 -4
  364. package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
  365. package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
  366. package/src/runtime/office/README.md +1 -1
  367. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  368. package/src/runtime/office/authoring/html-browser.mjs +18 -8
  369. package/src/runtime/office/authoring/html-document-author.mjs +2 -0
  370. package/src/runtime/office/authoring/pdf-html-runner.mjs +1 -1
  371. package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
  372. package/src/runtime/office/authoring/pptx-html-measure.mjs +3 -1
  373. package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
  374. package/src/runtime/office/authoring/xlsx-html-runner.mjs +3 -1
  375. package/src/runtime/office/core/office-actions-read.mjs +3 -0
  376. package/src/runtime/office/core/office-render-preview.mjs +2 -0
  377. package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
  378. package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
  379. package/src/runtime/office/core/office-sessions.mjs +5 -0
  380. package/src/runtime/office/core/office-transactions.mjs +3 -0
  381. package/src/runtime/office/core/office-write-ledger.mjs +94 -0
  382. package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
  383. package/src/runtime/office/index.mjs +29 -0
  384. package/src/runtime/office/pdf/pdf-analysis.mjs +0 -68
  385. package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
  386. package/src/runtime/office/pdf/pdf-render.mjs +23 -7
  387. package/src/runtime/office/pdf/pdf-security.mjs +2 -0
  388. package/src/runtime/office/portable/portable-opc.mjs +4 -1
  389. package/src/runtime/office/quality/visual-diff.mjs +2 -0
  390. package/src/runtime/session-search/session-search-ingest.mjs +1 -1
  391. package/src/runtime/shared/agent-reap-state.mjs +13 -0
  392. package/src/runtime/shared/atomic-file.d.mts +1 -1
  393. package/src/runtime/shared/background-tasks.mjs +6 -1
  394. package/src/runtime/shared/bounded-file-read.mjs +13 -0
  395. package/src/runtime/shared/bounded-line-diff.mjs +191 -0
  396. package/src/runtime/shared/browser-launch.mjs +15 -0
  397. package/src/runtime/shared/buffered-appender.mjs +18 -0
  398. package/src/runtime/shared/config.mjs +78 -18
  399. package/src/runtime/shared/err-text.mjs +48 -4
  400. package/src/runtime/shared/file-lock.mjs +6 -5
  401. package/src/runtime/shared/file-permissions.d.mts +6 -1
  402. package/src/runtime/shared/file-permissions.mjs +54 -6
  403. package/src/runtime/shared/llm/anthropic-betas.mjs +1 -2
  404. package/src/runtime/shared/llm/anthropic-effort.mjs +6 -0
  405. package/src/runtime/shared/llm/provider-model-identities.mjs +1 -0
  406. package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
  407. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
  408. package/src/runtime/shared/loopback-listener.mjs +9 -0
  409. package/src/runtime/shared/model-route-chain.d.mts +8 -0
  410. package/src/runtime/shared/model-route-chain.mjs +48 -0
  411. package/src/runtime/shared/model-route-fallback.mjs +22 -0
  412. package/src/runtime/shared/pid-liveness.mjs +12 -0
  413. package/src/runtime/shared/provider-api-key.mjs +8 -0
  414. package/src/runtime/shared/provider-timeout-phase.mjs +17 -0
  415. package/src/runtime/shared/quiet-progress.d.mts +35 -0
  416. package/src/runtime/shared/quiet-progress.mjs +101 -0
  417. package/src/runtime/shared/quota-resume-store.mjs +32 -1
  418. package/src/runtime/shared/read-row-numbers.mjs +44 -0
  419. package/src/runtime/shared/remote-intent.mjs +2 -42
  420. package/src/runtime/shared/review-diff.mjs +52 -0
  421. package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
  422. package/src/runtime/shared/session-sidebar-host.mjs +38 -0
  423. package/src/runtime/shared/slow-span.mjs +121 -0
  424. package/src/runtime/shared/statusline/statusline-segments.mjs +52 -6
  425. package/src/runtime/shared/tool-card-model/card-header.mjs +7 -1
  426. package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
  427. package/src/runtime/shared/tool-card-model.mjs +5 -2
  428. package/src/runtime/shared/tool-output-budget.mjs +2 -0
  429. package/src/runtime/shared/tool-output-limit.mjs +4 -0
  430. package/src/runtime/shared/tool-primitives.mjs +13 -0
  431. package/src/runtime/shared/tool-result-summary.mjs +22 -1
  432. package/src/runtime/shared/tool-status.mjs +3 -2
  433. package/src/runtime/shared/tool-surface.mjs +20 -6
  434. package/src/runtime/shared/tool-work-units.mjs +54 -11
  435. package/src/runtime/shared/transcript-metadata.mjs +49 -1
  436. package/src/runtime/shared/transcript-turn-keys.mjs +33 -0
  437. package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
  438. package/src/runtime/shared/transcript-writer/transcript-file.mjs +10 -1
  439. package/src/runtime/shared/transcript-writer.mjs +24 -6
  440. package/src/runtime/shared/turn-changes.mjs +269 -100
  441. package/src/runtime/shared/turn-review-reply.mjs +8 -39
  442. package/src/runtime/shared/turn-snapshot-store.mjs +19 -108
  443. package/src/runtime/shared/turn-snapshot.mjs +865 -683
  444. package/src/runtime/shared/turn-worktree-snapshot.mjs +183 -255
  445. package/src/runtime/shared/user-data-guard.mjs +262 -49
  446. package/src/runtime/shared/worktrees/activity-gate.mjs +175 -0
  447. package/src/runtime/shared/worktrees/branch-management.mjs +179 -0
  448. package/src/runtime/shared/worktrees/carry.mjs +533 -0
  449. package/src/runtime/shared/worktrees/contract.mjs +60 -0
  450. package/src/runtime/shared/worktrees/dependencies.mjs +456 -0
  451. package/src/runtime/shared/worktrees/file-recovery.mjs +84 -0
  452. package/src/runtime/shared/worktrees/git-head.mjs +214 -0
  453. package/src/runtime/shared/worktrees/git.mjs +8 -3
  454. package/src/runtime/shared/worktrees/include.mjs +125 -7
  455. package/src/runtime/shared/worktrees/lock.mjs +1 -1
  456. package/src/runtime/shared/worktrees/maintenance.mjs +20 -2
  457. package/src/runtime/shared/worktrees/manager.mjs +525 -31
  458. package/src/runtime/shared/worktrees/merge.mjs +31 -21
  459. package/src/runtime/shared/worktrees/owner.mjs +2 -1
  460. package/src/runtime/shared/worktrees/paths.d.mts +6 -0
  461. package/src/runtime/shared/worktrees/preparation-report.mjs +79 -0
  462. package/src/runtime/shared/worktrees/setup-commands.mjs +232 -0
  463. package/src/runtime/shared/worktrees/workspace-visibility.mjs +17 -0
  464. package/src/runtime/terminal-bridge/client.mjs +57 -20
  465. package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
  466. package/src/runtime/tidy/apply.mjs +47 -2
  467. package/src/runtime/tidy/run-engines.mjs +11 -5
  468. package/src/session-runtime/agent-tool-routing.mjs +19 -13
  469. package/src/session-runtime/boot/apis.mjs +20 -6
  470. package/src/session-runtime/boot/config.mjs +2 -0
  471. package/src/session-runtime/boot/facade.mjs +4 -0
  472. package/src/session-runtime/boot/infrastructure.mjs +6 -1
  473. package/src/session-runtime/boot/session.mjs +3 -3
  474. package/src/session-runtime/boot/tools.mjs +7 -1
  475. package/src/session-runtime/conversation-import/service.mjs +1 -1
  476. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
  477. package/src/session-runtime/goal-facade-api.mjs +2 -2
  478. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +91 -0
  479. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
  480. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +15 -5
  481. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +137 -26
  482. package/src/session-runtime/internal-tool-executor.mjs +8 -2
  483. package/src/session-runtime/lifecycle/cold-heir.mjs +187 -0
  484. package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
  485. package/src/session-runtime/lifecycle/session-catalog.mjs +25 -18
  486. package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
  487. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +36 -48
  488. package/src/session-runtime/lifecycle/session-switch.mjs +1 -1
  489. package/src/session-runtime/lifecycle/shared.mjs +5 -6
  490. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -5
  491. package/src/session-runtime/lifecycle/teardown.mjs +70 -14
  492. package/src/session-runtime/lifecycle-api.mjs +1 -0
  493. package/src/session-runtime/mcp-glue/connect.mjs +17 -5
  494. package/src/session-runtime/media-api.mjs +8 -0
  495. package/src/session-runtime/model-route/route-ownership.mjs +60 -0
  496. package/src/session-runtime/model-route/route-persist.mjs +3 -2
  497. package/src/session-runtime/model-route/set-route.mjs +116 -36
  498. package/src/session-runtime/model-route/web-search-route.mjs +7 -2
  499. package/src/session-runtime/model-route-api.mjs +4 -2
  500. package/src/session-runtime/native-web-search/routes.mjs +37 -24
  501. package/src/session-runtime/native-web-search-usage.mjs +51 -0
  502. package/src/session-runtime/native-web-search.mjs +19 -9
  503. package/src/session-runtime/new-session-config.mjs +4 -2
  504. package/src/session-runtime/provider-auth/login.mjs +4 -0
  505. package/src/session-runtime/provider-auth/setup.mjs +4 -0
  506. package/src/session-runtime/provider-models/catalog-load.mjs +9 -0
  507. package/src/session-runtime/provider-models/web-search-catalog.mjs +23 -3
  508. package/src/session-runtime/provider-models.mjs +1 -0
  509. package/src/session-runtime/provider-usage.mjs +4 -0
  510. package/src/session-runtime/resource-scope-decorate.mjs +10 -3
  511. package/src/session-runtime/route-resolution.mjs +3 -1
  512. package/src/session-runtime/runtime-core.mjs +4 -0
  513. package/src/session-runtime/runtime-facade.mjs +6 -0
  514. package/src/session-runtime/runtime-review-api.mjs +8 -2
  515. package/src/session-runtime/services/agent-task-status.mjs +2 -0
  516. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +0 -3
  517. package/src/session-runtime/services/agent-tool/close-flow.mjs +6 -7
  518. package/src/session-runtime/services/agent-tool/execute-send.mjs +2 -2
  519. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +36 -3
  520. package/src/session-runtime/services/agent-tool/execute.mjs +9 -1
  521. package/src/session-runtime/services/agent-tool/helpers.mjs +30 -7
  522. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
  523. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +7 -2
  524. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +6 -3
  525. package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
  526. package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
  527. package/src/session-runtime/services/agent-tool/lead-worker-index/lead-rows.mjs +3 -4
  528. package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +9 -3
  529. package/src/session-runtime/services/agent-tool/lead-worker-index/row-settlement.mjs +7 -18
  530. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +82 -13
  531. package/src/session-runtime/services/agent-tool/model-select.mjs +82 -0
  532. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -6
  533. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -1
  534. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -5
  535. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -4
  536. package/src/session-runtime/services/agent-tool/spawn-flow.mjs +2 -1
  537. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  538. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +1 -3
  539. package/src/session-runtime/services/agent-tool/tag-registry/tag-refresh.mjs +1 -3
  540. package/src/session-runtime/services/agent-tool/tag-registry.mjs +18 -10
  541. package/src/session-runtime/services/agent-tool/terminal-reaper/scan-admission.mjs +8 -41
  542. package/src/session-runtime/services/agent-tool/terminal-reaper/stale-rows.mjs +3 -3
  543. package/src/session-runtime/services/agent-tool/terminal-reaper.mjs +6 -23
  544. package/src/session-runtime/services/agent-tool/terminal-trace.mjs +0 -1
  545. package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
  546. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +32 -20
  547. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -2
  548. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
  549. package/src/session-runtime/services/agent-tool/worker-index.mjs +74 -15
  550. package/src/session-runtime/services/agent-tool.mjs +7 -0
  551. package/src/session-runtime/services/agent-watchdog-registry.mjs +2 -0
  552. package/src/session-runtime/services/channel-admin.mjs +19 -3
  553. package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
  554. package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
  555. package/src/session-runtime/services/provider-admin.mjs +158 -15
  556. package/src/session-runtime/session-create/session-options.mjs +7 -5
  557. package/src/session-runtime/session-create/session-start-hook.mjs +2 -1
  558. package/src/session-runtime/session-transcript-purge.mjs +32 -0
  559. package/src/session-runtime/session-transcript.mjs +4 -5
  560. package/src/session-runtime/session-turn-api.mjs +17 -14
  561. package/src/session-runtime/settings-builtin-tools-api.mjs +18 -6
  562. package/src/session-runtime/setup-tool/executor.mjs +57 -9
  563. package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
  564. package/src/session-runtime/setup-tool/settings-contract.mjs +18 -3
  565. package/src/session-runtime/setup-tool/tool-defs.mjs +25 -4
  566. package/src/session-runtime/skills-api.mjs +3 -5
  567. package/src/session-runtime/tool-policy-refresh.mjs +83 -32
  568. package/src/session-runtime/tool-surface.mjs +5 -1
  569. package/src/session-runtime/turn/agent-ops.mjs +49 -2
  570. package/src/session-runtime/turn/compaction-gate.mjs +25 -0
  571. package/src/session-runtime/turn/session-ops.mjs +7 -5
  572. package/src/session-runtime/turn/side-question-ops.mjs +19 -0
  573. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +7 -1
  574. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +12 -3
  575. package/src/session-runtime/turn/turn-run/turn-settle.mjs +18 -2
  576. package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
  577. package/src/session-runtime/turn/turn-run.mjs +26 -45
  578. package/src/session-runtime/usage-stats-api.mjs +46 -11
  579. package/src/session-runtime/workflow-agents-api/agent-route.mjs +16 -1
  580. package/src/session-runtime/workspace/admission-gate.mjs +44 -15
  581. package/src/session-runtime/workspace/project-branches.mjs +35 -41
  582. package/src/session-runtime/workspace/transition-steps.mjs +215 -116
  583. package/src/session-runtime/workspace/transitions.mjs +428 -73
  584. package/src/standalone/channel-transport.mjs +3 -4
  585. package/src/standalone/daemon-agent-control.mjs +9 -1
  586. package/src/standalone/daemon-desktop-runtime.mjs +32 -1
  587. package/src/standalone/daemon-local-session-bridge.mjs +14 -1
  588. package/src/standalone/daemon-owner.mjs +17 -4
  589. package/src/standalone/daemon-pg-stop.mjs +49 -0
  590. package/src/standalone/daemon-session-control.mjs +88 -0
  591. package/src/standalone/daemon-stop-budget.d.mts +2 -0
  592. package/src/standalone/daemon-stop-budget.mjs +18 -0
  593. package/src/standalone/daemon-stored-session-views.mjs +25 -3
  594. package/src/standalone/daemon-telemetry.mjs +19 -0
  595. package/src/standalone/daemon.mjs +63 -1
  596. package/src/standalone/desktop-service-registry.mjs +5 -0
  597. package/src/standalone/local-session-runtime.mjs +80 -30
  598. package/src/standalone/session-client.mjs +42 -0
  599. package/src/standalone/session-protocol.mjs +14 -0
  600. package/src/standalone/session-proxy/projection.mjs +41 -4
  601. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
  602. package/src/standalone/session-runtime-inline-host.mjs +3 -0
  603. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +91 -49
  604. package/src/standalone/session-service/agent-tree/agent-child.mjs +19 -1
  605. package/src/standalone/session-service/agent-tree/agent-registry.mjs +25 -0
  606. package/src/standalone/session-service/agent-tree/agent-turns.mjs +9 -1
  607. package/src/standalone/session-service/agent-tree.mjs +28 -2
  608. package/src/standalone/session-service/entries/session-loads.mjs +16 -5
  609. package/src/standalone/session-service/entries.mjs +1 -0
  610. package/src/standalone/session-service/projection/transcript-window.mjs +39 -0
  611. package/src/standalone/session-service/quota-resume.mjs +28 -13
  612. package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
  613. package/src/standalone/session-service/session-calls/session-turns.mjs +17 -6
  614. package/src/standalone/session-service/session-calls/session-views.mjs +6 -0
  615. package/src/standalone/session-service-api.mjs +6 -1
  616. package/src/standalone/session-state-patch.d.mts +2 -1
  617. package/src/standalone/session-state-patch.mjs +41 -1
  618. package/src/standalone/session-tool-output.mjs +82 -0
  619. package/src/tui/App.jsx +25 -0
  620. package/src/tui/app/app-view/floating-panel.jsx +26 -1
  621. package/src/tui/app/app-view.jsx +2 -1
  622. package/src/tui/app/btw-controller.mjs +118 -0
  623. package/src/tui/app/create-app-pickers.mjs +2 -0
  624. package/src/tui/app/provider-setup/provider-items.mjs +8 -0
  625. package/src/tui/app/provider-setup-picker.mjs +15 -3
  626. package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
  627. package/src/tui/app/shell-layout/surfaces.mjs +3 -1
  628. package/src/tui/app/slash-commands.mjs +19 -3
  629. package/src/tui/app/slash-dispatch/session-commands.mjs +68 -6
  630. package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
  631. package/src/tui/app/use-global-key-input.mjs +5 -12
  632. package/src/tui/app/use-prompt-handlers.mjs +11 -0
  633. package/src/tui/components/BtwPanel.jsx +53 -0
  634. package/src/tui/components/QuestionPanel.jsx +275 -0
  635. package/src/tui/components/Spinner.jsx +4 -0
  636. package/src/tui/components/SpinnerByline.jsx +21 -2
  637. package/src/tui/components/question-panel-model.mjs +156 -0
  638. package/src/tui/components/status-line/local-line.mjs +10 -2
  639. package/src/tui/dist/index.mjs +2897 -1722
  640. package/src/tui/session/active-tool-summary.mjs +1 -1
  641. package/src/tui/session/context-state.mjs +4 -5
  642. package/src/tui/session/goal-continuation/continuation-queue.mjs +2 -3
  643. package/src/tui/session/goal-continuation/deadline-delivery.mjs +4 -2
  644. package/src/tui/session/goal-continuation/session-boundary.mjs +21 -0
  645. package/src/tui/session/quota-resume.mjs +140 -61
  646. package/src/tui/session/session-api/commands.mjs +14 -10
  647. package/src/tui/session/session-api/controls.mjs +14 -2
  648. package/src/tui/session/session-api/integrations.mjs +9 -2
  649. package/src/tui/session/session-api/lifecycle/dispose.mjs +3 -9
  650. package/src/tui/session/session-api/lifecycle/resume.mjs +2 -7
  651. package/src/tui/session/session-api/lifecycle.mjs +14 -11
  652. package/src/tui/session/session-api/media.mjs +2 -0
  653. package/src/tui/session/session-api/routes.mjs +81 -57
  654. package/src/tui/session/session-api/settings.mjs +9 -3
  655. package/src/tui/session/session-api/worktree.mjs +3 -2
  656. package/src/tui/session/session-api.mjs +1 -0
  657. package/src/tui/session/session-flow/auto-clear.mjs +1 -3
  658. package/src/tui/session/session-flow/drain.mjs +6 -4
  659. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -0
  660. package/src/tui/session/session-flow/queue/take-entries.mjs +2 -1
  661. package/src/tui/session/session-flow/queue.mjs +1 -1
  662. package/src/tui/session/tool-approval.mjs +20 -8
  663. package/src/tui/session/transcript-spill.mjs +14 -7
  664. package/src/tui/session/transcript-store/streaming-tail.mjs +1 -1
  665. package/src/tui/session/tui-steering-persist.mjs +3 -5
  666. package/src/tui/session/turn-quiet.mjs +53 -0
  667. package/src/tui/session/turn-stream.mjs +179 -32
  668. package/src/tui/session/turn.mjs +50 -36
  669. package/src/tui/session/worktree-setup-notice.mjs +38 -0
  670. package/src/tui/spinner-meta.mjs +10 -0
  671. package/src/tui/spinner-verbs.mjs +3 -0
  672. package/src/ui/statusline.mjs +13 -3
  673. package/src/workflows/default/WORKFLOW.md +3 -1
  674. package/src/runtime/agent/orchestrator/providers/model-pricing-rates.mjs +0 -1
  675. package/src/runtime/agent/orchestrator/session/manager/foreign-pending-messages.mjs +0 -346
  676. package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +0 -117
  677. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +0 -246
  678. package/src/session-runtime/services/agent-tool/terminal-reaper/reap-timers.mjs +0 -142
  679. package/src/session-runtime/turn/share-ops.mjs +0 -77
  680. package/src/tui/session/cross-surface-share.mjs +0 -406
  681. package/src/tui/session/live-share/delta.mjs +0 -153
  682. package/src/tui/session/live-share/mirror.mjs +0 -106
  683. package/src/tui/session/live-share/owner.mjs +0 -254
  684. package/src/tui/session/live-share/retry.mjs +0 -54
  685. package/src/tui/session/live-share/viewer/frame-router.mjs +0 -32
  686. package/src/tui/session/live-share/viewer/pipe-client.mjs +0 -108
  687. package/src/tui/session/live-share/viewer/submit-acks.mjs +0 -65
  688. package/src/tui/session/live-share/viewer/sync-waiters.mjs +0 -53
  689. package/src/tui/session/live-share/viewer.mjs +0 -99
  690. package/src/tui/session/live-share/wire.mjs +0 -44
  691. package/src/tui/session/live-share.mjs +0 -154
  692. package/src/tui/session/shared-dir-watch.mjs +0 -69
@@ -1,7 +1,10 @@
1
1
  // ── Runtime liveness map ──────────────────────────────────────────────
2
- // In-memory only. Tracks per-session stage + stream heartbeat so agent type=list
2
+ // In-memory only. Tracks per-session stage + stream progress so agent type=list
3
3
  // can surface whether a session is actually alive vs stuck. Never persisted —
4
- // heartbeats would otherwise churn the session JSON on every SSE delta.
4
+ // progress would otherwise churn the session JSON on every SSE delta. The Map
5
+ // itself lives in the import-free leaf runtime-state.mjs so cold readers can
6
+ // ask which turns are in flight (isSessionTurnInFlight /
7
+ // inFlightSessionActivity); every mutation stays here.
5
8
  //
6
9
  // The Map and its timer companion are
7
10
  // module-level singletons — preserving the baseline's single-process shape.
@@ -20,14 +23,16 @@
20
23
  // }
21
24
  import { createAbortController } from '../../../../shared/abort-controller.mjs';
22
25
  import { emitSessionApprovalWaitChange } from '../../../../shared/session-approval-wait.mjs';
23
- import { publishHeartbeat, deleteHeartbeat } from '../store.mjs';
24
26
  import { DEFAULT_ACTIVITY_HEARTBEAT_MS } from '../../stall-policy.mjs';
27
+ import { MODEL_THINKING_STAGE, awaitingModelResponse, lastProgressAt } from '../../../../shared/quiet-progress.mjs';
25
28
  import { finishBrowserTurn } from '../../../../browser-bridge/client.mjs';
26
29
  import { configureUsageMetricsRuntime, dropMetricSeenState, bumpUsageMetricsTurnId } from './usage-metrics.mjs';
30
+ import { runtimeState as _runtimeState, isTurnInFlight } from './runtime-state.mjs';
31
+
32
+ export { IN_FLIGHT_STAGES, inFlightSessionActivity } from './runtime-state.mjs';
27
33
 
28
34
  const HEARTBEAT_THROTTLE_MS = 60_000; // 60s
29
35
 
30
- const _runtimeState = new Map();
31
36
  const _toolActivityHeartbeats = new Map();
32
37
  const VALID_STAGES = new Set([
33
38
  'connecting',
@@ -99,7 +104,6 @@ function _touchSessionActivityProgress(id) {
99
104
  const now = Date.now();
100
105
  entry.lastProgressAt = now;
101
106
  entry.updatedAt = now;
102
- publishHeartbeat(id, now);
103
107
  }
104
108
 
105
109
  function _startToolActivityHeartbeat(id) {
@@ -111,11 +115,17 @@ function _startToolActivityHeartbeat(id) {
111
115
  }
112
116
 
113
117
  export function updateSessionStage(id, stage) {
118
+ if (stage === MODEL_THINKING_STAGE) {
119
+ markSessionRequestSent(id);
120
+ return;
121
+ }
114
122
  if (!id || !VALID_STAGES.has(stage)) return;
115
123
  const entry = _touchRuntime(id);
116
124
  const now = Date.now();
117
125
  const priorStage = entry.stage;
118
126
  entry.stage = stage;
127
+ // A new stage (a retried attempt included) has not sent its request yet.
128
+ entry.requestSentAt = null;
119
129
  if (stage === 'requesting' && priorStage !== 'requesting') {
120
130
  entry.modelRequestStartedAt = now;
121
131
  }
@@ -148,6 +158,7 @@ export function markSessionAskStart(id) {
148
158
  entry.lastToolProtocolAt = null;
149
159
  entry.lastSemanticKind = null;
150
160
  entry.transportTrackingEnabled = false;
161
+ entry.requestSentAt = null;
151
162
  entry.lastToolCall = null;
152
163
  entry.toolStartedAt = null;
153
164
  entry.toolOutputTail = null;
@@ -166,14 +177,18 @@ export function markSessionAskStart(id) {
166
177
  entry.modelRequestStartedAt = null;
167
178
  entry.lastProgressAt = now;
168
179
  entry.updatedAt = now;
169
- // Publish heartbeat immediately so the status aggregator picks the
170
- // session up in the connecting / requesting window. Without this the
171
- // .hb file only landed on the first stream chunk — producing a 3–10s
172
- // (xhigh: 30s+) invisible gap where agent sessions ran but the
173
- // statusline showed no maintenance/agent badge. STREAM_FRESH_MS (5 min)
174
- // still drops a session whose provider truly never returns a chunk;
175
- // markSessionStreamDelta keeps refreshing once chunks arrive.
176
- return publishHeartbeat(id, now);
180
+ }
181
+ /** The provider put the request on the wire; its response headers are
182
+ * pending. The turn stays `requesting` (every stage set and the watchdog
183
+ * clock are unchanged); the send time lets surfaces show "model thinking"
184
+ * until transport arrives. Not progress: lastProgressAt is untouched. */
185
+ export function markSessionRequestSent(id) {
186
+ if (!id) return;
187
+ const entry = _runtimeState.get(id);
188
+ if (!entry || entry.closed || entry.controller?.signal?.aborted || entry.stage !== 'requesting') return;
189
+ const now = Date.now();
190
+ entry.requestSentAt = now;
191
+ entry.updatedAt = now;
177
192
  }
178
193
  export function enableSessionTransportTracking(id) {
179
194
  if (!id) return;
@@ -194,7 +209,6 @@ export function markSessionTransportActivity(id) {
194
209
  const now = Date.now();
195
210
  entry.lastTransportAt = now;
196
211
  entry.updatedAt = now;
197
- publishHeartbeat(id, now);
198
212
  }
199
213
  function _normalizeModelProgressKind(kind) {
200
214
  let value = 'semantic';
@@ -211,10 +225,10 @@ export async function markSessionStreamDelta(id, kind = 'semantic') {
211
225
  // creates it before streaming begins). _touchRuntime would instead resurrect a
212
226
  // blank entry — and closeSession()/idle-sweep clear _runtimeState on a deferred
213
227
  // tick while a detached provider stream may still be trickling deltas. A delta
214
- // arriving after that clear must NOT re-create an entry or it would republish the
215
- // .hb heartbeat that markSessionClosed deleted, orphaning a dead session's
216
- // heartbeat indefinitely (the disk tombstone blocks ask resumption but not this
217
- // path). Skip a missing, tombstoned, or aborted entry — never refresh liveness.
228
+ // arriving after that clear must NOT re-create an entry or it would revive a
229
+ // dead session's runtime state (the disk tombstone blocks ask resumption but
230
+ // not this path). Skip a missing, tombstoned, or aborted entry — never refresh
231
+ // liveness.
218
232
  const entry = _runtimeState.get(id);
219
233
  if (!entry || entry.closed || entry.controller?.signal?.aborted || TERMINAL_STAGES.has(entry.stage)) return;
220
234
  const progressKind = _normalizeModelProgressKind(kind);
@@ -240,11 +254,7 @@ export async function markSessionStreamDelta(id, kind = 'semantic') {
240
254
  if (entry.stage === 'connecting' || entry.stage === 'requesting') {
241
255
  entry.stage = 'streaming';
242
256
  }
243
- // Lightweight heartbeat (≤5s self-throttled) for the status aggregator.
244
- // Disk-side session.lastHeartbeatAt below is the heavy 60s zombie-reaper
245
- // signal; the .hb file is the fast fresh-session signal consumed by the
246
- // status line.
247
- publishHeartbeat(id, now);
257
+ // Disk-side session.lastHeartbeatAt is the 60s zombie-reaper signal.
248
258
  const session = entry.session;
249
259
  if (session && now - (session.lastHeartbeatAt || 0) > HEARTBEAT_THROTTLE_MS) {
250
260
  session.lastHeartbeatAt = now;
@@ -271,9 +281,7 @@ export function markSessionToolCall(id, toolName) {
271
281
  entry.lastToolProtocolAt = entry.toolStartedAt;
272
282
  entry.lastProgressAt = entry.toolStartedAt;
273
283
  entry.updatedAt = entry.toolStartedAt;
274
- const heartbeat = publishHeartbeat(id, entry.toolStartedAt);
275
284
  _startToolActivityHeartbeat(id);
276
- return heartbeat;
277
285
  }
278
286
  // Live shell-output tail for the CURRENT running tool. Written by the shell
279
287
  // tool's onOutputTail timer (~1 s cadence), read by engine transcript
@@ -341,10 +349,6 @@ export function markSessionDone(id, { empty = false } = {}) {
341
349
  entry.emptyFinal = false;
342
350
  entry.emptyFinalAt = null;
343
351
  }
344
- // Terminal stage — drop the heartbeat so the status badge releases
345
- // immediately. A subsequent ask on the same session re-publishes via
346
- // markSessionStreamDelta on the first chunk.
347
- return deleteHeartbeat(id);
348
352
  }
349
353
  // Tag a session as having completed with empty final synthesis (no
350
354
  // content/reasoning). Distinct from `markSessionDone`: still a success
@@ -368,9 +372,7 @@ export function markSessionError(id, msg) {
368
372
  // silent empty final). Clear the flag so the next ask starts clean.
369
373
  entry.emptyFinal = false;
370
374
  entry.emptyFinalAt = null;
371
- const heartbeatDeleted = deleteHeartbeat(id);
372
375
  _unlinkParentAbortListener(entry);
373
- return heartbeatDeleted;
374
376
  }
375
377
  export function markSessionCancelled(id) {
376
378
  if (!id) return;
@@ -380,24 +382,19 @@ export function markSessionCancelled(id) {
380
382
  _settleTerminalEntry(entry, 'done', null);
381
383
  entry.emptyFinal = false;
382
384
  entry.emptyFinalAt = null;
383
- const heartbeatDeleted = deleteHeartbeat(id);
384
385
  _unlinkParentAbortListener(entry);
385
- return heartbeatDeleted;
386
386
  }
387
387
  export function getSessionRuntime(id) {
388
388
  return id ? _runtimeState.get(id) || null : null;
389
389
  }
390
390
 
391
- // Stages that still own live provider/tool work: compaction, idle cleanup and
392
- // runtime unload all stay away from an entry in one of them.
393
- export const IN_FLIGHT_STAGES = new Set(['connecting', 'requesting', 'streaming', 'tool_running', 'cancelling']);
391
+ /** Whether this session's turn (provider or tool work) is running now. */
392
+ export function isSessionTurnInFlight(sessionId) {
393
+ return Boolean(sessionId) && isTurnInFlight(_runtimeState.get(sessionId));
394
+ }
394
395
 
395
396
  export function isSessionCompactionBlocked(sessionId) {
396
- if (!sessionId) return false;
397
- const entry = _runtimeState.get(sessionId);
398
- if (!entry || entry.closed === true) return false;
399
- if (entry.controller && !entry.controller.signal?.aborted) return true;
400
- return IN_FLIGHT_STAGES.has(entry.stage);
397
+ return isSessionTurnInFlight(sessionId);
401
398
  }
402
399
 
403
400
  export function getSessionProgressSnapshot(sessionId) {
@@ -418,6 +415,9 @@ export function getSessionProgressSnapshot(sessionId) {
418
415
  firstActivityAt,
419
416
  firstSemanticAt,
420
417
  lastTransportAt: entry.lastTransportAt || 0,
418
+ requestSentAt: entry.requestSentAt || 0,
419
+ // Request on the wire, headers pending: the model is queued or thinking.
420
+ awaitingModelResponse: awaitingModelResponse(entry),
421
421
  lastSemanticAt: entry.lastSemanticAt || 0,
422
422
  lastSemanticKind: entry.lastSemanticKind || null,
423
423
  lastReasoningAt: entry.lastReasoningAt || 0,
@@ -482,14 +482,7 @@ export function getSessionAbortSignal(sessionId) {
482
482
  * either skip the watchdog or treat 0 as "no progress yet".
483
483
  */
484
484
  export function getSessionLastProgressAt(sessionId) {
485
- const entry = _runtimeState.get(sessionId);
486
- if (!entry) return 0;
487
- return Math.max(
488
- entry.lastProgressAt || 0,
489
- entry.lastStreamDeltaAt || 0,
490
- entry.toolStartedAt || 0,
491
- entry.askStartedAt || 0
492
- );
485
+ return lastProgressAt(_runtimeState.get(sessionId));
493
486
  }
494
487
 
495
488
  /**
@@ -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,9 @@ 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';
22
+ import { forgetSideQuestion } from '../side-question-store.mjs';
21
23
 
22
24
  /**
23
25
  * Close a session. Plants a `closed=true` tombstone on disk with a bumped
@@ -46,15 +48,17 @@ export function closeSession(id, reason = 'manual', opts = {}) {
46
48
  const entry = _getRuntimeEntry(id);
47
49
  // askSession owns the interruption tracker that can merge committed
48
50
  // iterations, the current partial response, and observed tool results into
49
- // one canonical transcript. Finalize that in-memory snapshot synchronously
51
+ // one canonical transcript. Stage that in-memory snapshot synchronously
50
52
  // BEFORE the lifecycle generation changes; once generation is bumped, the
51
- // 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;
52
57
  try {
53
- entry?.prepareCloseSnapshot?.(reason);
58
+ closeSnapshot = entry?.prepareCloseSnapshot?.tentative?.(reason) ?? null;
54
59
  } catch {
55
60
  /* best-effort */
56
61
  }
57
- _stopToolActivityHeartbeat(id);
58
62
  // 1. Tombstone first — this wins the race against saveSession().
59
63
  // Skipped when tombstone=false: no closed:true marker is planted, so
60
64
  // the session file stays intact and resumeSession() will accept it.
@@ -66,7 +70,10 @@ export function closeSession(id, reason = 'manual', opts = {}) {
66
70
  // it once disk generation moves past that. Without this bump the late
67
71
  // write could silently overwrite the session after the user resumes
68
72
  // it back (BL: burned-session late-save clobber).
69
- const newGen = tombstone ? markSessionClosed(id, reason) : bumpSessionGeneration(id, reason);
73
+ const outcome = { absent: false };
74
+ const newGen = tombstone
75
+ ? markSessionClosed(id, reason, { outcome })
76
+ : bumpSessionGeneration(id, reason, { outcome });
70
77
  // Durable lifecycle barrier check. ANY nonnumeric result means the barrier
71
78
  // is not on disk — a write failure, a liveness/ownership veto, a contended
72
79
  // commit lock, or a missing record. Only a failed write publishes a
@@ -76,13 +83,23 @@ export function closeSession(id, reason = 'manual', opts = {}) {
76
83
  // crash checkpoint while the session stays open and resumable on disk — the
77
84
  // way a failed close silently destroys a turn. Leave every runtime
78
85
  // structure intact, surface the cause, and report failure to the caller.
79
- if (typeof newGen !== 'number') {
86
+ //
87
+ // The one exception is a record that was legitimately already gone (never
88
+ // saved, or deleted): the barrier cancelled its pending writes under the
89
+ // commit lock and found no copy on disk or in memory, so there is nothing
90
+ // a late save could clobber and nothing left open to resume. That close
91
+ // succeeds and tears the runtime down normally.
92
+ if (typeof newGen !== 'number' && outcome.absent !== true) {
93
+ closeSnapshot?.rollback();
80
94
  reportCloseBarrierFailure({ id, reason, tombstone, entry });
81
95
  return false;
82
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);
83
102
  cancelOwnedShellProcesses({ id, reason, tombstone });
84
- // prepareCloseSnapshot was folded into the synchronous generation write
85
- // above. Only now is it safe to remove the crash fallback.
86
103
  clearTurnCheckpoint(id);
87
104
  teardownSessionRuntime({ id, entry, reason, tombstone, newGen });
88
105
  return true;
@@ -95,7 +112,7 @@ export function closeSession(id, reason = 'manual', opts = {}) {
95
112
  */
96
113
  function reportCloseBarrierFailure({ id, reason, tombstone, entry }) {
97
114
  const commitError = getSessionLifecycleCommitError(id);
98
- let detail = 'no durable barrier written (veto, contended commit, or missing record)';
115
+ let detail = 'no durable barrier written (veto or contended commit)';
99
116
  if (commitError) {
100
117
  const code = commitError.code ? ` (${commitError.code})` : '';
101
118
  detail = `${commitError.message}${code}`;
@@ -128,16 +145,27 @@ function reportCloseBarrierFailure({ id, reason, tombstone, entry }) {
128
145
  * with the unconfirmed outcome. The re-stamp is idempotent: markSessionClosed
129
146
  * keeps the original close time and generation and only upgrades the cancel
130
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.
131
154
  */
132
155
  function cancelOwnedShellProcesses({ id, reason, tombstone }) {
133
- 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 });
134
161
  try {
135
- 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);
136
165
  } catch {
137
- // A cancel that threw proved nothing either.
138
- cancelConfirmed = false;
166
+ unconfirmed();
139
167
  }
140
- if (tombstone && !cancelConfirmed) markSessionClosed(id, reason, { cancelStatus: 'cancel-unconfirmed' });
168
+ noteShellOwnerSessionClosed(id);
141
169
  }
142
170
 
143
171
  /**
@@ -163,6 +191,7 @@ function teardownSessionRuntime({ id, entry, reason, tombstone, newGen }) {
163
191
  /* ignore */
164
192
  }
165
193
  }
194
+ forgetSideQuestion(id, { cancel: true });
166
195
  closeProviderConnections(id, `session-close:${reason}`);
167
196
  // Diagnostic: one-line stderr so operators can distinguish the four close
168
197
  // pathways (request-abort / manual / idle-sweep / runner-crash). iterCount
@@ -264,8 +293,8 @@ export function abortSessionTurn(id, reason = 'turn-abort') {
264
293
  * what a settled turn left behind;
265
294
  * - offload sidecars, the turn checkpoint and persisted pending messages
266
295
  * are left intact — they are the follow-up turn's context, not runtime.
267
- * Terminal ownership stays with the caller's own reap path (agent-tool
268
- * scheduleReap → closeSession('terminal-reap')).
296
+ * A terminal session is never closed here; it stays open until it is
297
+ * explicitly cancelled or deleted.
269
298
  *
270
299
  * Returns false (changing nothing) when the session is still in flight.
271
300
  */
@@ -288,6 +317,7 @@ export function unloadSessionRuntime(id, reason = 'runtime-unload') {
288
317
  if (IN_FLIGHT_STAGES.has(entry.stage)) return false;
289
318
  }
290
319
  _stopToolActivityHeartbeat(id);
320
+ forgetSideQuestion(id, { cancel: true });
291
321
  closeProviderConnections(id, `runtime-unload:${reason}`);
292
322
  releaseSessionReadCaches(id);
293
323
  _clearSessionRuntime(id);
@@ -27,8 +27,9 @@ import { isSessionCompactionBlocked, getSessionAbortSignal, _runtimeEntries } fr
27
27
  import { mintSessionId } from './session-id.mjs';
28
28
  import { hideCompactionArchive } from '../compaction-archive-capture.mjs';
29
29
  import { writeStderrBestEffort } from '../../../../shared/best-effort-stderr.mjs';
30
+ import { forgetSideQuestion } from '../side-question-store.mjs';
30
31
 
31
- /** Force-flush session metrics to disk. Used by watchdog terminal-reap (fix B). */
32
+ /** Force-flush session metrics to disk. */
32
33
  export async function flushSessionMetrics(sessionId) {
33
34
  if (!sessionId) return;
34
35
  const session = loadSession(sessionId);
@@ -91,13 +92,30 @@ export async function updateSessionManualTitle(id, title) {
91
92
  if (!session || session.closed === true) return false;
92
93
  const normalized = normalizeSessionTitle(title);
93
94
  if (!normalized) return false;
94
- if (session.title === normalized && session.titleLocked === true) return false;
95
+ if (session.title === normalized && session.titleLocked === true && session.titleSource === 'user') return false;
95
96
  session.title = normalized;
96
97
  session.titleLocked = true;
98
+ session.titleSource = 'user';
97
99
  session.titleUpdatedAt = Date.now();
98
100
  await saveSessionAsync(session, { expectedGeneration: session.generation });
99
101
  return true;
100
102
  }
103
+ // A title the model chose (session tool). Never overwrites a user title; a
104
+ // legacy locked session without titleSource counts as user-titled. It locks
105
+ // the title against auto-generated ones but stays replaceable by the model.
106
+ export async function updateSessionAiTitle(id, title) {
107
+ const session = loadSession(id);
108
+ if (!session || session.closed === true) return { ok: false, reason: 'not-found' };
109
+ const normalized = normalizeSessionTitle(title);
110
+ if (!normalized) return { ok: false, reason: 'empty-title' };
111
+ if (session.titleLocked === true && session.titleSource !== 'ai') return { ok: false, reason: 'user-title' };
112
+ session.title = normalized;
113
+ session.titleLocked = true;
114
+ session.titleSource = 'ai';
115
+ session.titleUpdatedAt = Date.now();
116
+ await saveSessionAsync(session, { expectedGeneration: session.generation });
117
+ return { ok: true, title: normalized };
118
+ }
101
119
  // --- Clear messages (keep system prompt + provider/model/cwd) ---
102
120
  // Token/provider accounting a cleared transcript starts from; shared by the
103
121
  // live session and the cold fork of its outgoing transcript.
@@ -262,8 +280,10 @@ export async function clearSessionMessages(sessionId, options = {}) {
262
280
 
263
281
  session.messages = keep;
264
282
  // Clear truncates the transcript wholesale; drop the provider prefix
265
- // snapshot so the next send re-baselines instead of history_shrink.
283
+ // snapshot so the next send re-baselines instead of history_shrink, and
284
+ // the request a /btw side question would fork.
266
285
  delete session._providerPrefixGuardState;
286
+ forgetSideQuestion(sessionId);
267
287
  resetSessionBp3Environment(session);
268
288
  Object.assign(session, clearedTokenAccounting(now));
269
289
  session.compaction = {
@@ -372,9 +392,11 @@ export async function rewindSessionMessagesTo(sessionId, options = {}) {
372
392
  const removed = messages.length - start;
373
393
  session.messages = messages.slice(0, start);
374
394
  // The provider cache is keyed on the exact prefix we just truncated;
375
- // the prefix-guard snapshot describes it too and must go with it.
395
+ // the prefix-guard snapshot and the /btw fork request describe it too and
396
+ // must go with it.
376
397
  session.providerState = undefined;
377
398
  delete session._providerPrefixGuardState;
399
+ forgetSideQuestion(sessionId);
378
400
  session.updatedAt = Date.now();
379
401
  session.lastUsedAt = Date.now();
380
402
  await saveSessionAsync(session, { expectedGeneration: session.generation });
@@ -0,0 +1,82 @@
1
+ // manager/session-fallback-title.mjs
2
+ // Durable, transcript-independent fallback title: the first usable
3
+ // user-authored prompt, stored on `session.title` so the conversation keeps a
4
+ // name after compaction replaces the transcript. Leaf module (no session-crud
5
+ // import) so ask-turn-execute, compaction-runner and pre-send-compact can share it.
6
+ import { compactSessionTitle } from '../../runtime-core/session-title.mjs';
7
+ import { cleanSessionPreview, isSessionPreviewNoise, sessionMessageText } from '../../runtime-core/session-text.mjs';
8
+ import { IMPORTED_MESSAGE_SOURCE } from '../imported-message.mjs';
9
+ import { isActualUserInstructionMessage } from '../compact/messages.mjs';
10
+
11
+ const UNTITLED_PLACEHOLDER = /^untitled(?:\s+session)?$/i;
12
+ const MEDIA_PLACEHOLDER = /^\[(?:image|video|file)\]$/i;
13
+ // Attachment envelopes carry payloads, not prose: closed blocks, then a block
14
+ // that lost its closing tag (the rest of the text is payload), then bare
15
+ // self-closing tags. Stripped before truncation so a large payload cannot
16
+ // crowd the prompt out of the bounded source.
17
+ const ATTACHMENT_TAGS = 'file|attachment|document|image|video|pdf';
18
+ const ATTACHMENT_BLOCK = new RegExp(`<(${ATTACHMENT_TAGS})\\b[^>]*>[\\s\\S]*?<\\/\\1\\s*>`, 'gi');
19
+ const ATTACHMENT_UNTERMINATED = new RegExp(`<(?:${ATTACHMENT_TAGS})\\b[^>]*>[\\s\\S]*$`, 'i');
20
+ const ATTACHMENT_SELF_CLOSING = new RegExp(`<(?:${ATTACHMENT_TAGS})\\b[^>]*\\/>`, 'gi');
21
+ const MEDIA_MARKER = /\[(?:Image|Video|File)(?:\s*#?\d+)?(?::[^\]\r\n]*)?\]/gi;
22
+
23
+ function stripAttachmentEnvelopes(text) {
24
+ return text
25
+ .replace(ATTACHMENT_BLOCK, ' ')
26
+ .replace(ATTACHMENT_SELF_CLOSING, ' ')
27
+ .replace(ATTACHMENT_UNTERMINATED, ' ')
28
+ .replace(MEDIA_MARKER, ' ');
29
+ }
30
+
31
+ function isUsableTitle(title) {
32
+ const text = String(title || '').trim();
33
+ return !!text && !UNTITLED_PLACEHOLDER.test(text);
34
+ }
35
+
36
+ /** Bounded single-line title from user-authored text; '' when nothing usable. */
37
+ export function fallbackTitleFromText(content) {
38
+ const raw = sessionMessageText(content);
39
+ if (!raw || /^\s*reference files:/i.test(raw)) return '';
40
+ const prose = stripAttachmentEnvelopes(raw);
41
+ if (isSessionPreviewNoise(prose)) return '';
42
+ const title = compactSessionTitle(cleanSessionPreview(prose, 4_000));
43
+ return isUsableTitle(title) && !MEDIA_PLACEHOLDER.test(title) ? title : '';
44
+ }
45
+
46
+ /** A turn the human typed: provenance lives in `meta` (`source` of an injected
47
+ * goal/notification/compaction turn, `synthetic`), never on the message root. */
48
+ function isHumanAuthoredTurn(message) {
49
+ if (message?.role !== 'user' || message.internal === true || message.synthetic === true) return false;
50
+ const meta = message.meta;
51
+ if (meta && typeof meta === 'object') {
52
+ if (meta.synthetic === true) return false;
53
+ if (meta.source && meta.source !== IMPORTED_MESSAGE_SOURCE) return false;
54
+ }
55
+ return isActualUserInstructionMessage(message);
56
+ }
57
+
58
+ /** Title from the first usable human user message of a transcript. */
59
+ export function fallbackTitleFromMessages(messages) {
60
+ for (const message of Array.isArray(messages) ? messages : []) {
61
+ if (!isHumanAuthoredTurn(message)) continue;
62
+ const title = fallbackTitleFromText(message.content);
63
+ if (title) return title;
64
+ }
65
+ return '';
66
+ }
67
+
68
+ /** Fills `session.title` only when missing. Never touches a locked (manual/AI)
69
+ * or generated title, and leaves generatedTitleStage unset so
70
+ * updateSessionGeneratedTitle can still upgrade it. The caller persists. */
71
+ export function applyFallbackSessionTitle(session, title) {
72
+ if (!session || !isUsableTitle(title) || isUsableTitle(session.title)) return false;
73
+ if (session.titleLocked === true || session.generatedTitleStage) return false;
74
+ session.title = title;
75
+ session.titleUpdatedAt = Date.now();
76
+ return true;
77
+ }
78
+
79
+ export function backfillFallbackSessionTitle(session, messages) {
80
+ if (!session || isUsableTitle(session.title)) return false;
81
+ return applyFallbackSessionTitle(session, fallbackTitleFromMessages(messages));
82
+ }