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
@@ -12,23 +12,235 @@
12
12
  // Once the shell has exited and been reaped, ANY remaining member
13
13
  // of that group is a descendant it left behind, and one signal to
14
14
  // the negative pgid reaches all of them.
15
- // win32 — there is no process group to signal, but the shell's stdout and
16
- // stderr pipes are INHERITED by its descendants: if they are still
17
- // held when the shell process itself has exited, something of this
18
- // command is alive. That observation gates a single batched
19
- // process-table read (shared with mcp/child-tree.mjs) which names
20
- // the survivors that are still linked to the shell pid.
21
- import { collectDescendantProcesses, killProcessTrees } from '../../mcp/child-tree.mjs';
22
- import { isPidAlive } from '../../../../shared/pid-liveness.mjs';
15
+ // win32 — inspect the process table after every root exit. Closed pipes
16
+ // cannot prove termination: descendants may redirect their stdio.
17
+ // The strict snapshot names survivors still linked to the root.
18
+ //
19
+ // Every process is tracked by IDENTITY — pid plus creation token from the
20
+ // same table read — never by pid alone: a recycled pid is a different process
21
+ // and neither keeps a tracked survivor "alive" nor becomes a kill target.
22
+ import { killProcessTrees, readProcessTable } from '../../mcp/child-tree.mjs';
23
23
 
24
24
  const isWin = process.platform === 'win32';
25
25
 
26
- // The spawn server waits up to 2 s for the shell's stdio pumps to drain after
27
- // the root process exits and then reports the exit regardless (main.rs
28
- // run_spawn). A close that lands at/after this threshold therefore means the
29
- // pipes were STILL held by another process at that deadline, not that draining
30
- // was slow — a normal command closes within milliseconds of its exit.
31
- export const STDIO_HELD_AFTER_EXIT_MS = 1_500;
26
+ // Cadence of every termination re-check (unconfirmed kill, background job,
27
+ // survivors a finished command left behind).
28
+ export const TERMINATION_RECHECK_MS = 5_000;
29
+
30
+ // Upper bound on how long a kill waits for its pre-kill snapshot (one process-
31
+ // table read, ~1 s on Windows). The kill is sent at the bound regardless; the
32
+ // read is not abandoned — a snapshot that lands later is still absorbed.
33
+ export const PROCESS_TABLE_READ_BOUND_MS = 2_000;
34
+
35
+ /** Resolve `promise`'s value, or `onTimeout` once `ms` elapse first. The
36
+ * bound's timer is cleared whichever side wins. */
37
+ export function withinBound(promise, ms, onTimeout) {
38
+ let timer = null;
39
+ const bound = new Promise((resolve) => {
40
+ timer = setTimeout(() => resolve(onTimeout), ms);
41
+ timer.unref?.();
42
+ });
43
+ return Promise.race([promise, bound]).finally(() => clearTimeout(timer));
44
+ }
45
+
46
+ /** Every kill path: wait for the pre-kill `snapshot` (true, or a promise) at
47
+ * most PROCESS_TABLE_READ_BOUND_MS, then run `kill` whether it landed or not. */
48
+ export function killAfterSnapshot(snapshot, kill) {
49
+ return withinBound(Promise.resolve(snapshot), PROCESS_TABLE_READ_BOUND_MS, false).then(kill);
50
+ }
51
+
52
+ const identityKey = (entry) => `${entry.pid}:${entry.token ?? ''}`;
53
+
54
+ /** Tracks one command's process tree across its termination.
55
+ *
56
+ * `capture()` records the identities of the root and every descendant while
57
+ * the root is still alive — before a kill can break the parent chain (an
58
+ * exited Windows intermediate orphans its children; a POSIX descendant may
59
+ * leave the process group). `observe()` takes one strict table read and
60
+ * answers 'running', 'gone' or 'unknown':
61
+ * - the root is alive (same identity) → running
62
+ * - no complete pre-exit capture exists → unknown
63
+ * - a tracked identity, a descendant still linked to one,
64
+ * or (POSIX) a member of the command's group is alive → running
65
+ * - a tracked process without a creation token is present → unknown
66
+ * A failed table read rejects; callers treat it as unknown. */
67
+ export function createProcessTreeTracker({ pid, members = [], exitObserved = false } = {}) {
68
+ const rootPid = Number(pid) || 0;
69
+ let rootToken = null;
70
+ let complete = false;
71
+ const tracked = new Map();
72
+ let live = [];
73
+ for (const entry of members) tracked.set(identityKey(entry), { ...entry });
74
+ if (exitObserved) complete = rootPid > 0;
75
+
76
+ const present = (table, entry) => {
77
+ if (!table.tokenOf.has(entry.pid)) return false;
78
+ if (entry.token == null) return null;
79
+ return table.tokenOf.get(entry.pid) === entry.token;
80
+ };
81
+ const track = (table, child) => {
82
+ const entry = { pid: child, token: table.tokenOf.get(child) ?? null, name: table.nameOf.get(child) || '' };
83
+ const key = identityKey(entry);
84
+ if (tracked.has(key)) return false;
85
+ tracked.set(key, entry);
86
+ return true;
87
+ };
88
+ // The root's pid still names OUR root (or nothing): its dangling child links
89
+ // are ours. A different process under that pid is a reuse — not ours.
90
+ const rootPidIsOurs = (table, rootAlive) =>
91
+ rootAlive || !table.tokenOf.has(rootPid) || (rootToken != null && table.tokenOf.get(rootPid) === rootToken);
92
+
93
+ function absorb(table, rootAlive) {
94
+ const from = [];
95
+ if (rootPidIsOurs(table, rootAlive)) from.push(rootPid);
96
+ for (const entry of tracked.values()) if (present(table, entry) === true) from.push(entry.pid);
97
+ const seen = new Set(from);
98
+ while (from.length) {
99
+ const cur = from.pop();
100
+ for (const child of table.childrenOf.get(cur) ?? []) {
101
+ if (seen.has(child)) continue;
102
+ seen.add(child);
103
+ track(table, child);
104
+ from.push(child);
105
+ }
106
+ }
107
+ // POSIX: the command owns the group whose id is the root pid. While any
108
+ // member exists that id cannot be reused, so a live process holding the
109
+ // pid that is not our root means our group is gone.
110
+ if (!isWin && rootPidIsOurs(table, rootAlive)) {
111
+ for (const [member, pgid] of table.pgidOf ?? []) {
112
+ if (pgid === rootPid && member !== rootPid) track(table, member);
113
+ }
114
+ }
115
+ if (rootAlive) {
116
+ rootToken = rootToken ?? table.tokenOf.get(rootPid) ?? null;
117
+ complete = true;
118
+ }
119
+ }
120
+
121
+ function rootIsAlive(table, rootExited) {
122
+ if (rootExited || !table.tokenOf.has(rootPid)) return false;
123
+ return rootToken == null || table.tokenOf.get(rootPid) === rootToken;
124
+ }
125
+
126
+ return {
127
+ get complete() {
128
+ return complete;
129
+ },
130
+ /** Identities currently known alive after the last observation. */
131
+ get live() {
132
+ return live;
133
+ },
134
+ /** Pre-termination snapshot; call while the root still runs. */
135
+ async capture({ rootExited = false } = {}) {
136
+ if (rootPid <= 0) return false;
137
+ let table = await readProcessTable({ shared: true });
138
+ // A shared read may have begun before this root was spawned.
139
+ if (!table.tokenOf.has(rootPid)) table = await readProcessTable();
140
+ absorb(table, rootIsAlive(table, rootExited));
141
+ return complete;
142
+ },
143
+ /** For a root that exited ON ITS OWN (no kill in between): it is observed
144
+ * after exit exactly like a foreground command's settle. Callers never
145
+ * waive a missing pre-kill snapshot with it. */
146
+ acceptExitObservation() {
147
+ if (rootPid > 0) complete = true;
148
+ },
149
+ async observe({ rootExited = true } = {}) {
150
+ if (rootPid <= 0) return 'unknown';
151
+ const table = await readProcessTable();
152
+ const rootAlive = rootIsAlive(table, rootExited);
153
+ absorb(table, rootAlive);
154
+ live = [];
155
+ if (rootAlive) {
156
+ live = [{ pid: rootPid, token: rootToken, name: table.nameOf.get(rootPid) || '' }];
157
+ return 'running';
158
+ }
159
+ if (!complete) return 'unknown';
160
+ let unknown = false;
161
+ for (const entry of tracked.values()) {
162
+ const state = present(table, entry);
163
+ if (state === true) live.push(entry);
164
+ else if (state === null) unknown = true;
165
+ }
166
+ if (live.length > 0) return 'running';
167
+ return unknown ? 'unknown' : 'gone';
168
+ },
169
+ };
170
+ }
171
+
172
+ /** One observation loop: observe now, then every `intervalMs` until the tree
173
+ * is confirmed gone, then run `onTerminated` once. 'running', 'unknown', a
174
+ * failed or unanswered (by the next cadence tick) observation and a failing
175
+ * `onTerminated` all re-check on the same cadence; the first pass that is not
176
+ * 'gone' calls `onUnconfirmed` once. The returned stop() clears the pending
177
+ * timer; nothing else (listener, timer) outlives the loop. Nothing in it ever
178
+ * releases on time alone. */
179
+ export function watchTermination({
180
+ tracker,
181
+ rootExited = () => true,
182
+ onTerminated,
183
+ onUnconfirmed = null,
184
+ releaseRequested = null,
185
+ intervalMs = TERMINATION_RECHECK_MS,
186
+ }) {
187
+ let timer = null;
188
+ let stopped = false;
189
+ let reportedUnconfirmed = false;
190
+ const stop = () => {
191
+ stopped = true;
192
+ if (timer) clearTimeout(timer);
193
+ timer = null;
194
+ };
195
+ const pass = async () => {
196
+ timer = null;
197
+ if (stopped) return;
198
+ let state = 'unknown';
199
+ let observation = null;
200
+ // An explicit user force-release made from another process (the hold's
201
+ // workspace is visible there): released as if confirmed, never on time.
202
+ if (releaseRequested?.()) state = 'gone';
203
+ else
204
+ try {
205
+ observation = tracker.observe({ rootExited: rootExited() });
206
+ observation.catch(() => {});
207
+ // A pass that has not answered by the next cadence tick is unknown.
208
+ state = await withinBound(observation, intervalMs, 'unknown');
209
+ } catch {
210
+ state = 'unknown';
211
+ }
212
+ if (stopped) return;
213
+ if (state !== 'gone' && !reportedUnconfirmed) {
214
+ reportedUnconfirmed = true;
215
+ try {
216
+ onUnconfirmed?.();
217
+ } catch {
218
+ /* presentation only */
219
+ }
220
+ }
221
+ if (state === 'gone') {
222
+ try {
223
+ await onTerminated();
224
+ stop();
225
+ return;
226
+ } catch {
227
+ /* the release failed: the reservation stays and is re-checked */
228
+ }
229
+ }
230
+ // The next pass never starts beside this pass's enumerator: a table read
231
+ // always settles by its own deadline (killed on timeout).
232
+ if (observation)
233
+ await observation.then(
234
+ () => {},
235
+ () => {}
236
+ );
237
+ if (stopped) return;
238
+ timer = setTimeout(pass, intervalMs);
239
+ timer.unref?.();
240
+ };
241
+ void pass();
242
+ return stop;
243
+ }
32
244
 
33
245
  // Windows attaches a console host to the hidden console the shell runs in. It
34
246
  // is a real child of the shell and it lives exactly as long as console clients
@@ -44,7 +256,7 @@ function groupAlive(pgid) {
44
256
  process.kill(-pgid, 0);
45
257
  return true;
46
258
  } catch (error) {
47
- return error?.code === 'EPERM';
259
+ return error?.code !== 'ESRCH';
48
260
  }
49
261
  }
50
262
 
@@ -61,73 +273,101 @@ function delay(ms) {
61
273
  * reports a plain completion), or a handle describing the survivors:
62
274
  * groupPid POSIX process group that still has members
63
275
  * killPids pids a cancellation can signal directly
64
- * watchPids pids whose liveness answers "is this task still running?"
276
+ * watchPids pids of the observed survivors
277
+ * watch their identities ({ pid, token, name }); liveness and kills
278
+ * compare these, never the bare pid
65
279
  * reachable false when survivors are observable but no longer addressable
66
280
  * by pid (Windows re-parents nothing: a process whose parent
67
281
  * exited keeps a dangling parent id, so an intermediate that
68
- * already exited breaks the link). */
69
- export async function probeShellDescendants({ pid, stdioHeld = false } = {}) {
282
+ * already exited breaks the link).
283
+ * Rejects when the process table cannot be read completely. */
284
+ export async function probeShellDescendants({ pid } = {}) {
70
285
  const root = Number(pid) || 0;
71
286
  if (root <= 0) return null;
72
- if (!isWin) {
73
- if (!groupAlive(root)) return null;
74
- return { groupPid: root, killPids: [], watchPids: [], reachable: true };
75
- }
76
- if (!stdioHeld) return null;
77
- const found = await collectDescendantProcesses(root).catch(() => []);
78
- const live = found.filter((entry) => isPidAlive(entry.pid));
79
- if (live.length === 0) return null;
80
- const killPids = live.filter((entry) => !CONSOLE_HOST.test(entry.name)).map((entry) => entry.pid);
287
+ // POSIX fast path: no member of the command's group at all.
288
+ if (!isWin && !groupAlive(root)) return null;
289
+ const tracker = createProcessTreeTracker({ pid: root, exitObserved: true });
290
+ const state = await tracker.observe({ rootExited: true });
291
+ if (state === 'gone') return null;
292
+ if (state === 'unknown') throw new Error('Remaining child processes could not be verified.');
293
+ return survivorHandle(root, tracker.live);
294
+ }
295
+
296
+ function survivorHandle(rootPid, live) {
297
+ const watch = live.map(({ pid, token, name }) => ({ pid, token, name }));
298
+ const killPids = watch.filter((entry) => !CONSOLE_HOST.test(entry.name)).map((entry) => entry.pid);
81
299
  return {
82
- groupPid: null,
300
+ rootPid,
301
+ groupPid: isWin ? null : rootPid,
83
302
  killPids,
84
- watchPids: live.map((entry) => entry.pid),
85
- reachable: killPids.length > 0,
303
+ watchPids: watch.map((entry) => entry.pid),
304
+ watch,
305
+ reachable: !isWin || killPids.length > 0,
86
306
  };
87
307
  }
88
308
 
89
- /** True while the observed survivors are still running. */
90
- export function descendantsAlive(handle) {
91
- if (!handle) return false;
92
- if (handle.groupPid) return groupAlive(handle.groupPid);
93
- return handle.watchPids.some((pid) => isPidAlive(pid));
94
- }
309
+ const trackerFor = (handle) =>
310
+ createProcessTreeTracker({ pid: handle.rootPid, members: handle.watch, exitObserved: true });
95
311
 
96
- /** Resolve once every observed survivor has exited. Poll-based on purpose:
97
- * these processes are not our children any more, so there is no exit event to
98
- * subscribe to — only their liveness can be observed. */
99
- export async function waitForShellDescendants(handle, { pollMs = 1_000, signal = null } = {}) {
100
- while (descendantsAlive(handle)) {
101
- if (signal?.aborted) return false;
102
- await delay(pollMs);
103
- }
104
- return true;
312
+ /** Resolve once every observed survivor (by identity) has exited, or false
313
+ * once `signal` aborts. These processes are not our children any more, so
314
+ * there is no exit event to subscribe to; the shared observation loop
315
+ * re-checks them at the termination cadence. */
316
+ export function waitForShellDescendants(handle, { signal = null } = {}) {
317
+ if (!handle) return Promise.resolve(true);
318
+ return new Promise((resolve) => {
319
+ if (signal?.aborted) {
320
+ resolve(false);
321
+ return;
322
+ }
323
+ const onAbort = () => {
324
+ stop();
325
+ resolve(false);
326
+ };
327
+ const stop = watchTermination({
328
+ tracker: trackerFor(handle),
329
+ onTerminated: () => {
330
+ signal?.removeEventListener('abort', onAbort);
331
+ resolve(true);
332
+ },
333
+ });
334
+ signal?.addEventListener('abort', onAbort, { once: true });
335
+ });
105
336
  }
106
337
 
107
- /** Terminate the survivors. POSIX signals the whole process group, so the kill
108
- * is complete by construction; Windows kills every reachable tree and then
109
- * RE-OBSERVES, so the caller reports what actually died instead of what was
110
- * signalled. */
338
+ /** Terminate the survivors, signalling only processes whose identity still
339
+ * matches the observation, then RE-OBSERVE so the caller reports what
340
+ * actually died instead of what was signalled. Never rejects. */
111
341
  export async function killShellDescendants(handle) {
112
342
  if (!handle) return { terminated: true, survivors: [] };
113
- if (handle.groupPid) {
114
- try {
115
- process.kill(-handle.groupPid, 'SIGTERM');
116
- } catch {
117
- /* already gone */
118
- }
119
- await delay(200);
120
- if (groupAlive(handle.groupPid)) {
343
+ try {
344
+ const table = await readProcessTable();
345
+ // The group id is ours only while no other process holds the root pid.
346
+ if (handle.groupPid && !table.tokenOf.has(handle.groupPid)) {
121
347
  try {
122
- process.kill(-handle.groupPid, 'SIGKILL');
348
+ process.kill(-handle.groupPid, 'SIGTERM');
123
349
  } catch {
124
350
  /* already gone */
125
351
  }
126
- await delay(100);
352
+ await delay(200);
353
+ if (groupAlive(handle.groupPid)) {
354
+ try {
355
+ process.kill(-handle.groupPid, 'SIGKILL');
356
+ } catch {
357
+ /* already gone */
358
+ }
359
+ await delay(100);
360
+ }
127
361
  }
128
- return { terminated: !groupAlive(handle.groupPid), survivors: [] };
362
+ const targets = handle.watch
363
+ .filter((entry) => entry.token != null && table.tokenOf.get(entry.pid) === entry.token)
364
+ .filter((entry) => !CONSOLE_HOST.test(entry.name))
365
+ .map((entry) => entry.pid);
366
+ await killProcessTrees(targets).catch(() => {});
367
+ const tracker = trackerFor(handle);
368
+ const state = await tracker.observe({ rootExited: true });
369
+ return { terminated: state === 'gone', survivors: tracker.live.map((entry) => entry.pid) };
370
+ } catch {
371
+ return { terminated: false, survivors: [...handle.watchPids] };
129
372
  }
130
- await killProcessTrees(handle.killPids).catch(() => {});
131
- const survivors = handle.watchPids.filter((pid) => isPidAlive(pid));
132
- return { terminated: survivors.length === 0, survivors };
133
373
  }
@@ -84,4 +84,6 @@ export async function handOverLease(run) {
84
84
  const lease = run.resourceLease;
85
85
  run.resourceLease = null;
86
86
  await lease?.release();
87
+ run.workspaceAdmission?.();
88
+ run.workspaceAdmission = null;
87
89
  }
@@ -3,20 +3,65 @@
3
3
  // lease cleanup that a promoted or unconfirmed-kill child defers to its own
4
4
  // real exit.
5
5
  import { ExecResult, SHELL_OUTPUT_INLINE_CAP } from '../shell-exec-output.mjs';
6
- import { probeShellDescendants, STDIO_HELD_AFTER_EXIT_MS } from './shell-descendants.mjs';
6
+ import { createProcessTreeTracker, probeShellDescendants, watchTermination } from './shell-descendants.mjs';
7
+ import { unregisterOwnedShellTree } from './owned-shell-trees.mjs';
8
+ import {
9
+ adoptShellWorkspaceAdmission,
10
+ clearTerminationHold,
11
+ registerTerminationHold,
12
+ takeReleaseRequest,
13
+ } from '../builtin/lib/shell-job-records.mjs';
7
14
  import {
8
15
  clearForegroundRecord,
9
16
  clearForegroundTimers,
10
17
  detachAbortHandler,
18
+ keepTerminationUnconfirmedRecord,
11
19
  releaseResourceLease,
12
20
  } from './shell-run-state.mjs';
13
21
 
14
22
  // Unconfirmed-kill cleanup ceiling: the result is already reported, but the
15
- // tree may still be alive, so closing the capture and returning the
16
- // admission lease wait for the child's real exit — bounded so an unkillable
17
- // tree cannot pin the shell lane forever.
23
+ // tree may still be alive, so closing the capture and returning the resource
24
+ // lease wait for the child's real exit — bounded so an unkillable tree cannot
25
+ // pin the shell lane forever. The workspace admission is NOT bounded by it:
26
+ // it follows confirmed termination only (see below).
18
27
  const UNCONFIRMED_KILL_CLEANUP_CEILING_MS = 60_000;
19
28
 
29
+ /** Lifecycle completion of a run whose result is already reported: release
30
+ * `run.workspaceAdmission` and retire the live record only once the root AND
31
+ * every descendant identity captured before the kill are confirmed gone. One
32
+ * observation loop at the termination cadence; running, unknown (incomplete
33
+ * snapshot, failed table read) and a failing release all re-check, and no
34
+ * timer ever releases on its own. */
35
+ export function releaseAdmissionOnConfirmedTermination(run, { markNow = true } = {}) {
36
+ const { child } = run;
37
+ if (!child || run.stopTerminationWatch) return;
38
+ // Visible as "termination unconfirmed" until the lifecycle ends, with an
39
+ // explicit user force-release as the only other way out. An unconfirmed
40
+ // kill is marked at once; an owner-cancelled tree whose root is already
41
+ // gone only once its first observation is not 'gone'.
42
+ if (markNow) keepTerminationUnconfirmedRecord(run);
43
+ const release = () => {
44
+ run.workspaceAdmission?.();
45
+ run.workspaceAdmission = null;
46
+ run.stopTerminationWatch?.();
47
+ clearTerminationHold(run.foregroundRecordId);
48
+ clearForegroundRecord(run);
49
+ };
50
+ registerTerminationHold(run.foregroundRecordId, {
51
+ ownerSessionId: run.foregroundRecordInput?.ownerSessionId || null,
52
+ cwd: run.foregroundRecordInput?.cwd || null,
53
+ release,
54
+ });
55
+ run.terminationTracker = run.terminationTracker || createProcessTreeTracker({ pid: child.pid });
56
+ run.stopTerminationWatch = watchTermination({
57
+ tracker: run.terminationTracker,
58
+ rootExited: () => child.exitCode != null || child.signalCode != null,
59
+ onTerminated: release,
60
+ onUnconfirmed: markNow ? null : () => keepTerminationUnconfirmedRecord(run),
61
+ releaseRequested: () => takeReleaseRequest(run.foregroundRecordId),
62
+ });
63
+ }
64
+
20
65
  // Promotion resolves the call and hands the child's lifecycle to the
21
66
  // shell-jobs registry, but the spill FDs stay owned by THIS runner and
22
67
  // nothing else would ever close them — one leaked descriptor pair per
@@ -49,9 +94,17 @@ export function createPromotedCaptureRelease(run) {
49
94
 
50
95
  function deferCleanupToChildExit(run) {
51
96
  let done = false;
97
+ let ceiling = null;
52
98
  const cleanup = () => {
53
99
  if (done) return;
54
100
  done = true;
101
+ clearTimeout(ceiling);
102
+ try {
103
+ run.child.removeListener('close', cleanup);
104
+ run.child.removeListener('exit', cleanup);
105
+ } catch {
106
+ /* not an emitter */
107
+ }
55
108
  try {
56
109
  run.taskOutput.closeFds();
57
110
  } catch {
@@ -65,8 +118,9 @@ function deferCleanupToChildExit(run) {
65
118
  } catch {
66
119
  /* child may already be gone */
67
120
  }
68
- const ceiling = setTimeout(cleanup, UNCONFIRMED_KILL_CLEANUP_CEILING_MS);
121
+ ceiling = setTimeout(cleanup, UNCONFIRMED_KILL_CLEANUP_CEILING_MS);
69
122
  if (ceiling.unref) ceiling.unref();
123
+ releaseAdmissionOnConfirmedTermination(run);
70
124
  }
71
125
 
72
126
  // getStdout/getStderr can throw on a spilled-file read failure (EBADF after
@@ -96,21 +150,17 @@ export async function readCapturedOutput(taskOutput, final = false) {
96
150
  // instead of a clean finish; null means nothing survived.
97
151
  async function probeSurvivingDescendants(run) {
98
152
  if (run.killed || run.timedOut || !run.child?.pid) return null;
99
- try {
100
- const descendants = await probeShellDescendants({
101
- pid: run.child.pid,
102
- stdioHeld: run.rootExitAtMs > 0 && Date.now() - run.rootExitAtMs >= STDIO_HELD_AFTER_EXIT_MS,
103
- });
104
- if (descendants) descendants.taskId = run.foregroundRecordId;
105
- return descendants;
106
- } catch {
107
- return null;
108
- }
153
+ const descendants = await probeShellDescendants({
154
+ pid: run.child.pid,
155
+ });
156
+ if (descendants) descendants.taskId = run.foregroundRecordId;
157
+ return descendants;
109
158
  }
110
159
 
111
160
  export function createSettle(run, releasePromotedCapture) {
112
161
  return async (exitCode, signal) => {
113
162
  if (run.settled) return;
163
+ if (run.ownedTree) unregisterOwnedShellTree(run.foregroundRecordId, run.ownedTree);
114
164
  if (run.autoBackgrounded) {
115
165
  releasePromotedCapture();
116
166
  return;
@@ -119,7 +169,15 @@ export function createSettle(run, releasePromotedCapture) {
119
169
  const { taskOutput } = run;
120
170
  // Off the readouts the instant the command is over, before any awaited
121
171
  // output capture — a finished command must never linger as "running".
122
- clearForegroundRecord(run);
172
+ // An unconfirmed kill is NOT over: its record stays, marked unconfirmed
173
+ // (releaseAdmissionOnConfirmedTermination), until every process is
174
+ // confirmed gone or the user releases it.
175
+ // Every other killed run (timeout, abort, session close) completes the
176
+ // same way: its pre-kill snapshot, not the root's exit, decides when it
177
+ // is over — a captured descendant can outlive the root it was killed with.
178
+ const confirmKill = run.killed === true && !run.killUnconfirmed && Boolean(run.child?.pid);
179
+ const lifecycleHeld = run.killUnconfirmed || confirmKill;
180
+ if (!lifecycleHeld) clearForegroundRecord(run);
123
181
  clearForegroundTimers(run);
124
182
  detachAbortHandler(run);
125
183
  const stdoutTail = run.stdoutDecoder.end();
@@ -139,7 +197,8 @@ export function createSettle(run, releasePromotedCapture) {
139
197
  if (run.killUnconfirmed) {
140
198
  // Never confirmed dead: deleting the capture files or handing back the
141
199
  // lease now would release resources a live process still owns. The
142
- // spilled paths therefore survive and travel with the result below.
200
+ // spilled paths therefore survive and travel with the result below, and
201
+ // the workspace admission stays held until termination is confirmed.
143
202
  deferCleanupToChildExit(run);
144
203
  } else if (taskOutput.spilled && taskOutput.totalDiskBytes() <= SHELL_OUTPUT_INLINE_CAP) {
145
204
  taskOutput.deleteFiles();
@@ -148,7 +207,38 @@ export function createSettle(run, releasePromotedCapture) {
148
207
  taskOutput.closeFds();
149
208
  void releaseResourceLease(run);
150
209
  }
151
- const descendants = await probeSurvivingDescendants(run);
210
+ let descendants = null;
211
+ let descendantsUnknown = false;
212
+ try {
213
+ descendants = await probeSurvivingDescendants(run);
214
+ } catch (error) {
215
+ descendantsUnknown = true;
216
+ taskOutput.writeError = taskOutput.writeError || error;
217
+ exitCode = exitCode || 1;
218
+ run.failureReason = 'Remaining child processes could not be verified; workspace cleanup is blocked.';
219
+ // The root exited on its own, so it is observed after exit like any
220
+ // settle; the held admission joins the termination watch and the
221
+ // explicit force-release, and the record is kept, marked unconfirmed.
222
+ // (The probe runs only for an unkilled root, so the lifecycle is not
223
+ // already held here.)
224
+ run.terminationTracker = run.terminationTracker || createProcessTreeTracker({ pid: run.child.pid });
225
+ run.terminationTracker.acceptExitObservation();
226
+ releaseAdmissionOnConfirmedTermination(run);
227
+ }
228
+ // Marked unconfirmed (with its force-release) only once an observation
229
+ // finds a captured identity still alive or cannot tell.
230
+ if (confirmKill) releaseAdmissionOnConfirmedTermination(run, { markNow: false });
231
+ if (!lifecycleHeld && !descendantsUnknown && run.workspaceAdmission) {
232
+ try {
233
+ if (descendants) adoptShellWorkspaceAdmission(run.foregroundRecordId, run.workspaceAdmission);
234
+ else run.workspaceAdmission();
235
+ run.workspaceAdmission = null;
236
+ } catch (error) {
237
+ taskOutput.writeError = taskOutput.writeError || error;
238
+ exitCode = exitCode || 1;
239
+ run.failureReason = 'workspace admission cleanup failed';
240
+ }
241
+ }
152
242
  run.resolveResult(
153
243
  new ExecResult({
154
244
  stdout,