mixdog 1.2.3 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (469) hide show
  1. package/package.json +1 -1
  2. package/scripts/gate-local.mjs +6 -4
  3. package/scripts/lib/gate-scheduler.mjs +29 -11
  4. package/scripts/mobile-release.mjs +5 -4
  5. package/scripts/probe-provider-catalog.mjs +31 -0
  6. package/scripts/provider-pingpong-live.mjs +128 -38
  7. package/scripts/session-sweep.mjs +5 -25
  8. package/src/agents/maintainer/AGENT.md +1 -1
  9. package/src/agents/maintainer/agent.json +1 -1
  10. package/src/agents/reviewer/AGENT.md +2 -4
  11. package/src/agents/security/AGENT.md +1 -2
  12. package/src/agents/writer/AGENT.md +2 -3
  13. package/src/defaults/shipped-history.json +7 -1
  14. package/src/defaults/skills/image/SKILL.md +21 -23
  15. package/src/lib/keychain-cjs.cjs +13 -11
  16. package/src/output-styles/common.md +2 -1
  17. package/src/rules/agent/AGENT.md +7 -5
  18. package/src/rules/lead/LEAD.md +13 -13
  19. package/src/rules/shared/45-destructive.md +4 -0
  20. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  21. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +28 -7
  22. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -11
  23. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +101 -23
  24. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +2 -0
  25. package/src/runtime/agent/orchestrator/providers/anthropic-api-key-fetch.mjs +36 -0
  26. package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +1 -1
  27. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -3
  28. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  29. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +26 -44
  30. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2 -5
  31. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +4 -0
  32. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +41 -12
  33. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +13 -1
  34. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +81 -10
  35. package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +109 -5
  36. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +2 -1
  37. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +107 -37
  38. package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +4 -1
  39. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +3 -1
  40. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  41. package/src/runtime/agent/orchestrator/providers/cursor-native-context.mjs +48 -0
  42. package/src/runtime/agent/orchestrator/providers/cursor-wire-exec.mjs +144 -34
  43. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +28 -4
  44. package/src/runtime/agent/orchestrator/providers/cursor-wire-request.mjs +8 -4
  45. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +41 -11
  46. package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +67 -5
  47. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +14 -4
  48. package/src/runtime/agent/orchestrator/providers/cursor.mjs +14 -1
  49. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +9 -6
  50. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -2
  51. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +26 -4
  52. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +12 -6
  53. package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +14 -6
  54. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +4 -4
  55. package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +1 -0
  56. package/src/runtime/agent/orchestrator/providers/gemini-rest-stream/watchdogs.mjs +16 -5
  57. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +6 -1
  58. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +22 -10
  59. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -2
  60. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +33 -7
  61. package/src/runtime/agent/orchestrator/providers/gemini.mjs +11 -2
  62. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  63. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +9 -2
  64. package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +9 -5
  65. package/src/runtime/agent/orchestrator/providers/lib/request-compression.mjs +86 -0
  66. package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +4 -2
  67. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -5
  68. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +7 -1
  69. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +60 -16
  70. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +11 -13
  71. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +30 -19
  72. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +5 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +42 -5
  75. package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +13 -9
  76. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +1 -3
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +18 -7
  78. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +36 -3
  79. package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +51 -3
  80. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +11 -1
  81. package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +64 -52
  82. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +3 -1
  83. package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +2 -1
  84. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +7 -1
  85. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +1 -4
  86. package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +0 -1
  87. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +7 -6
  88. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +13 -2
  89. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +4 -1
  90. package/src/runtime/agent/orchestrator/providers/openrouter.mjs +1 -2
  91. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +5 -4
  92. package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -1
  93. package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +2 -1
  94. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +11 -4
  95. package/src/runtime/agent/orchestrator/providers/wire-route.mjs +14 -4
  96. package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +15 -3
  97. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +6 -2
  98. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +8 -6
  99. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +4 -1
  100. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +30 -2
  101. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +3 -2
  102. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -3
  103. package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +3 -1
  104. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge-contract.mjs +6 -0
  105. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +10 -10
  106. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +3 -1
  107. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +46 -8
  108. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -8
  109. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -2
  110. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +24 -0
  111. package/src/runtime/agent/orchestrator/session/cache/tool-result-reuse.mjs +10 -2
  112. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -3
  113. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +3 -11
  114. package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +6 -22
  115. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -0
  116. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +16 -2
  117. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +28 -0
  118. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
  119. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +0 -6
  120. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +0 -6
  121. package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +1 -1
  122. package/src/runtime/agent/orchestrator/session/historical-session-closure.mjs +10 -0
  123. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +2 -5
  124. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +2 -4
  125. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +3 -3
  126. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +0 -27
  127. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +1 -1
  128. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -10
  129. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -9
  130. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +4 -1
  131. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +4 -1
  132. package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +1 -4
  133. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +76 -0
  134. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +5 -1
  135. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +8 -9
  136. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +6 -0
  137. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -2
  138. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +1 -4
  139. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -4
  140. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +33 -3
  141. package/src/runtime/agent/orchestrator/session/manager/ask-support.mjs +0 -4
  142. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +21 -1
  143. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +38 -13
  144. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +33 -0
  145. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +5 -0
  146. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +19 -1
  147. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +57 -13
  148. package/src/runtime/agent/orchestrator/session/manager/failed-turn-rewind.mjs +16 -0
  149. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +6 -120
  150. package/src/runtime/agent/orchestrator/session/manager/pending-persist-queue.mjs +1 -1
  151. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +29 -8
  152. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +42 -49
  153. package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +50 -0
  154. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +32 -14
  155. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +1 -1
  156. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +17 -33
  157. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +29 -13
  158. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -3
  159. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +45 -0
  160. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -9
  161. package/src/runtime/agent/orchestrator/session/send-instrumentation.mjs +2 -1
  162. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -2
  163. package/src/runtime/agent/orchestrator/session/side-question.mjs +12 -7
  164. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +5 -12
  165. package/src/runtime/agent/orchestrator/session/store/lifecycle-read.mjs +1 -1
  166. package/src/runtime/agent/orchestrator/session/store/listing.mjs +2 -6
  167. package/src/runtime/agent/orchestrator/session/store/live-cache-eviction.mjs +1 -1
  168. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +46 -37
  169. package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +1 -1
  170. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +1 -1
  171. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +5 -11
  172. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +59 -0
  173. package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +1 -1
  174. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +1 -1
  175. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +27 -32
  176. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +0 -8
  177. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +6 -18
  178. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +33 -106
  179. package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +1 -1
  180. package/src/runtime/agent/orchestrator/session/store-agent-worker-pool.mjs +5 -8
  181. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +160 -212
  182. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +50 -116
  183. package/src/runtime/agent/orchestrator/session/store-summary-locations.mjs +3 -29
  184. package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +1 -1
  185. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +7 -8
  186. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +9 -20
  187. package/src/runtime/agent/orchestrator/session/store.mjs +3 -16
  188. package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +11 -12
  189. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +37 -13
  190. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +15 -4
  191. package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +4 -2
  192. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +72 -15
  193. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +45 -0
  194. package/src/runtime/agent/orchestrator/stall-policy.mjs +50 -0
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +5 -1
  196. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +6 -2
  197. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +204 -10
  198. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +160 -39
  199. package/src/runtime/agent/orchestrator/tools/builtin/git-partial-stage.mjs +7 -5
  200. package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +14 -5
  201. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +4 -3
  202. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +2 -1
  203. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-path-fanout.mjs +48 -44
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +10 -3
  205. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +200 -17
  206. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +5 -4
  207. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +6 -1
  208. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +20 -0
  209. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +101 -2
  210. package/src/runtime/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +1 -1
  211. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +67 -0
  212. package/src/runtime/agent/orchestrator/tools/lib/process-table-fixture.mjs +50 -0
  213. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +303 -63
  214. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -0
  215. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +108 -18
  216. package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +77 -11
  217. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +81 -5
  218. package/src/runtime/attachments/store.d.mts +9 -0
  219. package/src/runtime/attachments/store.mjs +80 -9
  220. package/src/runtime/browser-bridge/browser-action-contract.d.mts +0 -1
  221. package/src/runtime/browser-bridge/browser-action-contract.mjs +0 -2
  222. package/src/runtime/computer-bridge/action-schema.mjs +178 -178
  223. package/src/runtime/computer-bridge/linux-readiness.d.mts +0 -2
  224. package/src/runtime/computer-bridge/linux-readiness.mjs +0 -16
  225. package/src/runtime/effort-judge/judge-client.mjs +21 -4
  226. package/src/runtime/effort-judge/judge-worker.mjs +4 -1
  227. package/src/runtime/github/tool.mjs +118 -17
  228. package/src/runtime/media/adapters/codex-image.mjs +140 -21
  229. package/src/runtime/media/catalog.mjs +4 -4
  230. package/src/runtime/media/chatgpt-usage.mjs +55 -0
  231. package/src/runtime/media/defaults.mjs +37 -0
  232. package/src/runtime/media/jobs.mjs +12 -2
  233. package/src/runtime/media/lanes.mjs +12 -0
  234. package/src/runtime/media/tool-defs.mjs +15 -4
  235. package/src/runtime/media/tool.mjs +41 -12
  236. package/src/runtime/media/upstream-error.mjs +72 -6
  237. package/src/runtime/memory/lib/ingest/transcript-rows.mjs +1 -0
  238. package/src/runtime/memory/lib/pg/process.mjs +5 -7
  239. package/src/runtime/memory/lib/pg/supervisor.mjs +4 -1
  240. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  241. package/src/runtime/office/authoring/html-browser.mjs +18 -8
  242. package/src/runtime/office/authoring/pdf-html-runner.mjs +1 -1
  243. package/src/runtime/office/authoring/pptx-html-measure.mjs +1 -1
  244. package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
  245. package/src/runtime/office/core/office-write-ledger.mjs +1 -5
  246. package/src/runtime/office/index.mjs +2 -3
  247. package/src/runtime/office/pdf/pdf-analysis.mjs +0 -68
  248. package/src/runtime/session-search/session-search-ingest.mjs +1 -1
  249. package/src/runtime/shared/agent-reap-state.mjs +13 -0
  250. package/src/runtime/shared/atomic-file.d.mts +1 -1
  251. package/src/runtime/shared/background-tasks.mjs +6 -1
  252. package/src/runtime/shared/bounded-line-diff.mjs +11 -2
  253. package/src/runtime/shared/browser-launch.mjs +15 -0
  254. package/src/runtime/shared/err-text.mjs +42 -4
  255. package/src/runtime/shared/file-lock.mjs +6 -5
  256. package/src/runtime/shared/llm/anthropic-betas.mjs +1 -2
  257. package/src/runtime/shared/llm/provider-model-identities.mjs +1 -0
  258. package/src/runtime/shared/model-route-chain.d.mts +8 -0
  259. package/src/runtime/shared/model-route-chain.mjs +48 -0
  260. package/src/runtime/shared/model-route-fallback.mjs +22 -0
  261. package/src/runtime/shared/pid-liveness.mjs +12 -0
  262. package/src/runtime/shared/provider-api-key.mjs +6 -0
  263. package/src/runtime/shared/provider-timeout-phase.mjs +17 -0
  264. package/src/runtime/shared/quiet-progress.d.mts +35 -0
  265. package/src/runtime/shared/quiet-progress.mjs +101 -0
  266. package/src/runtime/shared/quota-resume-store.mjs +32 -1
  267. package/src/runtime/shared/read-row-numbers.mjs +44 -0
  268. package/src/runtime/shared/remote-intent.mjs +2 -42
  269. package/src/runtime/shared/slow-span.mjs +8 -1
  270. package/src/runtime/shared/statusline/statusline-segments.mjs +24 -2
  271. package/src/runtime/shared/tool-card-model/card-header.mjs +2 -1
  272. package/src/runtime/shared/tool-output-budget.mjs +2 -0
  273. package/src/runtime/shared/tool-result-summary.mjs +16 -2
  274. package/src/runtime/shared/tool-status.mjs +3 -2
  275. package/src/runtime/shared/tool-surface.mjs +2 -3
  276. package/src/runtime/shared/tool-work-units.mjs +22 -15
  277. package/src/runtime/shared/transcript-metadata.mjs +49 -1
  278. package/src/runtime/shared/transcript-turn-keys.mjs +33 -0
  279. package/src/runtime/shared/transcript-writer/transcript-file.mjs +10 -1
  280. package/src/runtime/shared/transcript-writer.mjs +14 -4
  281. package/src/runtime/shared/turn-changes.mjs +2 -1
  282. package/src/runtime/shared/turn-snapshot.mjs +11 -3
  283. package/src/runtime/shared/worktrees/activity-gate.mjs +175 -0
  284. package/src/runtime/shared/worktrees/branch-management.mjs +179 -0
  285. package/src/runtime/shared/worktrees/carry.mjs +6 -4
  286. package/src/runtime/shared/worktrees/contract.mjs +27 -1
  287. package/src/runtime/shared/worktrees/dependencies.mjs +456 -0
  288. package/src/runtime/shared/worktrees/file-recovery.mjs +29 -13
  289. package/src/runtime/shared/worktrees/git-head.mjs +22 -13
  290. package/src/runtime/shared/worktrees/include.mjs +125 -7
  291. package/src/runtime/shared/worktrees/lock.mjs +1 -1
  292. package/src/runtime/shared/worktrees/maintenance.mjs +20 -2
  293. package/src/runtime/shared/worktrees/manager.mjs +378 -32
  294. package/src/runtime/shared/worktrees/owner.mjs +2 -1
  295. package/src/runtime/shared/worktrees/preparation-report.mjs +79 -0
  296. package/src/runtime/shared/worktrees/setup-commands.mjs +232 -0
  297. package/src/runtime/shared/worktrees/workspace-visibility.mjs +17 -0
  298. package/src/runtime/terminal-bridge/client.mjs +14 -10
  299. package/src/session-runtime/boot/apis.mjs +7 -1
  300. package/src/session-runtime/boot/config.mjs +2 -0
  301. package/src/session-runtime/boot/facade.mjs +3 -0
  302. package/src/session-runtime/boot/session.mjs +3 -2
  303. package/src/session-runtime/boot/tools.mjs +3 -0
  304. package/src/session-runtime/conversation-import/service.mjs +1 -1
  305. package/src/session-runtime/goal-facade-api.mjs +2 -2
  306. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +44 -18
  307. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +4 -1
  308. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +22 -8
  309. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  310. package/src/session-runtime/lifecycle/cold-heir.mjs +0 -1
  311. package/src/session-runtime/lifecycle/session-catalog.mjs +14 -16
  312. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +18 -53
  313. package/src/session-runtime/lifecycle/session-switch.mjs +1 -1
  314. package/src/session-runtime/lifecycle/shared.mjs +5 -6
  315. package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -5
  316. package/src/session-runtime/lifecycle/teardown.mjs +7 -16
  317. package/src/session-runtime/media-api.mjs +8 -0
  318. package/src/session-runtime/model-route/route-ownership.mjs +60 -0
  319. package/src/session-runtime/model-route/route-persist.mjs +3 -2
  320. package/src/session-runtime/model-route/set-route.mjs +114 -34
  321. package/src/session-runtime/model-route/web-search-route.mjs +7 -2
  322. package/src/session-runtime/model-route-api.mjs +4 -2
  323. package/src/session-runtime/native-web-search/routes.mjs +37 -24
  324. package/src/session-runtime/native-web-search.mjs +9 -8
  325. package/src/session-runtime/provider-auth/setup.mjs +4 -0
  326. package/src/session-runtime/provider-models/catalog-load.mjs +9 -0
  327. package/src/session-runtime/provider-models/web-search-catalog.mjs +23 -3
  328. package/src/session-runtime/provider-models.mjs +1 -0
  329. package/src/session-runtime/provider-usage.mjs +4 -0
  330. package/src/session-runtime/route-resolution.mjs +3 -1
  331. package/src/session-runtime/runtime-core.mjs +4 -0
  332. package/src/session-runtime/runtime-facade.mjs +6 -0
  333. package/src/session-runtime/services/agent-task-status.mjs +2 -0
  334. package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +0 -3
  335. package/src/session-runtime/services/agent-tool/close-flow.mjs +6 -7
  336. package/src/session-runtime/services/agent-tool/execute-send.mjs +2 -2
  337. package/src/session-runtime/services/agent-tool/execute-spawn.mjs +36 -3
  338. package/src/session-runtime/services/agent-tool/execute.mjs +9 -1
  339. package/src/session-runtime/services/agent-tool/helpers.mjs +30 -7
  340. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +7 -2
  341. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +6 -3
  342. package/src/session-runtime/services/agent-tool/lead-worker-index/lead-rows.mjs +3 -4
  343. package/src/session-runtime/services/agent-tool/lead-worker-index/reap-timers.mjs +9 -3
  344. package/src/session-runtime/services/agent-tool/lead-worker-index/row-settlement.mjs +7 -18
  345. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +9 -6
  346. package/src/session-runtime/services/agent-tool/model-select.mjs +82 -0
  347. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -6
  348. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -1
  349. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -5
  350. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -4
  351. package/src/session-runtime/services/agent-tool/spawn-flow.mjs +2 -1
  352. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  353. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +1 -3
  354. package/src/session-runtime/services/agent-tool/tag-registry/tag-refresh.mjs +1 -3
  355. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -9
  356. package/src/session-runtime/services/agent-tool/terminal-reaper/scan-admission.mjs +8 -41
  357. package/src/session-runtime/services/agent-tool/terminal-reaper/stale-rows.mjs +3 -3
  358. package/src/session-runtime/services/agent-tool/terminal-reaper.mjs +6 -23
  359. package/src/session-runtime/services/agent-tool/terminal-trace.mjs +0 -1
  360. package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
  361. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +32 -20
  362. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -2
  363. package/src/session-runtime/services/agent-tool/worker-index.mjs +28 -8
  364. package/src/session-runtime/services/agent-tool.mjs +4 -0
  365. package/src/session-runtime/services/agent-watchdog-registry.mjs +2 -0
  366. package/src/session-runtime/services/provider-admin.mjs +77 -0
  367. package/src/session-runtime/session-create/session-options.mjs +7 -5
  368. package/src/session-runtime/session-create/session-start-hook.mjs +2 -1
  369. package/src/session-runtime/session-transcript.mjs +4 -5
  370. package/src/session-runtime/session-turn-api.mjs +3 -9
  371. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -6
  372. package/src/session-runtime/setup-tool/executor.mjs +23 -5
  373. package/src/session-runtime/setup-tool/extended-actions.mjs +6 -6
  374. package/src/session-runtime/setup-tool/settings-contract.mjs +7 -2
  375. package/src/session-runtime/setup-tool/tool-defs.mjs +13 -1
  376. package/src/session-runtime/tool-policy-refresh.mjs +83 -32
  377. package/src/session-runtime/turn/agent-ops.mjs +49 -2
  378. package/src/session-runtime/turn/side-question-ops.mjs +1 -4
  379. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +2 -0
  380. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +4 -0
  381. package/src/session-runtime/turn/turn-run/turn-settle.mjs +8 -2
  382. package/src/session-runtime/turn/turn-run.mjs +1 -36
  383. package/src/session-runtime/usage-stats-api.mjs +4 -1
  384. package/src/session-runtime/workflow-agents-api/agent-route.mjs +16 -1
  385. package/src/session-runtime/workspace/admission-gate.mjs +44 -15
  386. package/src/session-runtime/workspace/project-branches.mjs +28 -36
  387. package/src/session-runtime/workspace/transition-steps.mjs +96 -95
  388. package/src/session-runtime/workspace/transitions.mjs +248 -68
  389. package/src/standalone/channel-transport.mjs +3 -4
  390. package/src/standalone/daemon-desktop-runtime.mjs +32 -1
  391. package/src/standalone/daemon-pg-stop.mjs +1 -3
  392. package/src/standalone/daemon-session-control.mjs +88 -0
  393. package/src/standalone/daemon-stored-session-views.mjs +23 -3
  394. package/src/standalone/daemon.mjs +2 -0
  395. package/src/standalone/desktop-service-registry.mjs +32 -5
  396. package/src/standalone/local-session-runtime.mjs +11 -12
  397. package/src/standalone/session-protocol.mjs +7 -0
  398. package/src/standalone/session-runtime-inline-host.mjs +2 -0
  399. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +91 -49
  400. package/src/standalone/session-service/agent-tree/agent-child.mjs +19 -1
  401. package/src/standalone/session-service/agent-tree/agent-registry.mjs +25 -0
  402. package/src/standalone/session-service/agent-tree/agent-turns.mjs +9 -1
  403. package/src/standalone/session-service/agent-tree.mjs +28 -2
  404. package/src/standalone/session-service/entries/session-loads.mjs +16 -5
  405. package/src/standalone/session-service/entries.mjs +1 -0
  406. package/src/standalone/session-service/projection/transcript-window.mjs +39 -0
  407. package/src/standalone/session-service/quota-resume.mjs +28 -13
  408. package/src/standalone/session-service/session-calls/session-turns.mjs +17 -6
  409. package/src/standalone/session-service/session-calls/session-views.mjs +6 -0
  410. package/src/standalone/session-tool-output.mjs +82 -0
  411. package/src/tui/app/app-view.jsx +2 -1
  412. package/src/tui/app/provider-setup/provider-items.mjs +8 -0
  413. package/src/tui/app/provider-setup-picker.mjs +15 -3
  414. package/src/tui/app/slash-commands.mjs +6 -0
  415. package/src/tui/app/slash-dispatch/session-commands.mjs +49 -0
  416. package/src/tui/components/Spinner.jsx +4 -0
  417. package/src/tui/components/SpinnerByline.jsx +21 -2
  418. package/src/tui/components/status-line/local-line.mjs +10 -2
  419. package/src/tui/dist/index.mjs +529 -270
  420. package/src/tui/session/active-tool-summary.mjs +1 -1
  421. package/src/tui/session/context-state.mjs +0 -3
  422. package/src/tui/session/goal-continuation/continuation-queue.mjs +2 -3
  423. package/src/tui/session/goal-continuation/deadline-delivery.mjs +4 -2
  424. package/src/tui/session/goal-continuation/session-boundary.mjs +21 -0
  425. package/src/tui/session/quota-resume.mjs +140 -61
  426. package/src/tui/session/session-api/commands.mjs +4 -10
  427. package/src/tui/session/session-api/controls.mjs +12 -0
  428. package/src/tui/session/session-api/lifecycle/dispose.mjs +2 -9
  429. package/src/tui/session/session-api/lifecycle/resume.mjs +2 -7
  430. package/src/tui/session/session-api/lifecycle.mjs +13 -11
  431. package/src/tui/session/session-api/media.mjs +2 -0
  432. package/src/tui/session/session-api/routes.mjs +81 -57
  433. package/src/tui/session/session-api/settings.mjs +3 -3
  434. package/src/tui/session/session-api/worktree.mjs +3 -2
  435. package/src/tui/session/session-flow/auto-clear.mjs +1 -3
  436. package/src/tui/session/session-flow/drain.mjs +6 -4
  437. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -0
  438. package/src/tui/session/session-flow/queue/take-entries.mjs +2 -1
  439. package/src/tui/session/session-flow/queue.mjs +1 -1
  440. package/src/tui/session/tool-approval.mjs +17 -8
  441. package/src/tui/session/transcript-store/streaming-tail.mjs +1 -1
  442. package/src/tui/session/tui-steering-persist.mjs +3 -5
  443. package/src/tui/session/turn-quiet.mjs +53 -0
  444. package/src/tui/session/turn-stream.mjs +5 -1
  445. package/src/tui/session/turn.mjs +38 -31
  446. package/src/tui/session/worktree-setup-notice.mjs +38 -0
  447. package/src/tui/spinner-meta.mjs +10 -0
  448. package/src/tui/spinner-verbs.mjs +3 -0
  449. package/src/ui/statusline.mjs +13 -3
  450. package/src/ui/streaming-markdown-heal.mjs +70 -18
  451. package/src/runtime/agent/orchestrator/providers/model-pricing-rates.mjs +0 -1
  452. package/src/runtime/agent/orchestrator/session/manager/foreign-pending-messages.mjs +0 -346
  453. package/src/runtime/agent/orchestrator/session/manager/session-owner-liveness.mjs +0 -117
  454. package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +0 -302
  455. package/src/session-runtime/services/agent-tool/terminal-reaper/reap-timers.mjs +0 -142
  456. package/src/session-runtime/turn/share-ops.mjs +0 -77
  457. package/src/tui/session/cross-surface-share.mjs +0 -406
  458. package/src/tui/session/live-share/delta.mjs +0 -153
  459. package/src/tui/session/live-share/mirror.mjs +0 -106
  460. package/src/tui/session/live-share/owner.mjs +0 -254
  461. package/src/tui/session/live-share/retry.mjs +0 -54
  462. package/src/tui/session/live-share/viewer/frame-router.mjs +0 -32
  463. package/src/tui/session/live-share/viewer/pipe-client.mjs +0 -108
  464. package/src/tui/session/live-share/viewer/submit-acks.mjs +0 -65
  465. package/src/tui/session/live-share/viewer/sync-waiters.mjs +0 -53
  466. package/src/tui/session/live-share/viewer.mjs +0 -99
  467. package/src/tui/session/live-share/wire.mjs +0 -44
  468. package/src/tui/session/live-share.mjs +0 -154
  469. package/src/tui/session/shared-dir-watch.mjs +0 -69
@@ -1825,8 +1825,8 @@ var require_react_reconciler_production = __commonJS({
1825
1825
  currentEntangledActionThenable = {
1826
1826
  status: "pending",
1827
1827
  value: void 0,
1828
- then: function(resolve4) {
1829
- entangledListeners.push(resolve4);
1828
+ then: function(resolve6) {
1829
+ entangledListeners.push(resolve6);
1830
1830
  }
1831
1831
  };
1832
1832
  }
@@ -1849,8 +1849,8 @@ var require_react_reconciler_production = __commonJS({
1849
1849
  status: "pending",
1850
1850
  value: null,
1851
1851
  reason: null,
1852
- then: function(resolve4) {
1853
- listeners.push(resolve4);
1852
+ then: function(resolve6) {
1853
+ listeners.push(resolve6);
1854
1854
  }
1855
1855
  };
1856
1856
  thenable.then(
@@ -11449,8 +11449,8 @@ var require_react_reconciler_development = __commonJS({
11449
11449
  currentEntangledActionThenable = {
11450
11450
  status: "pending",
11451
11451
  value: void 0,
11452
- then: function(resolve4) {
11453
- entangledListeners.push(resolve4);
11452
+ then: function(resolve6) {
11453
+ entangledListeners.push(resolve6);
11454
11454
  }
11455
11455
  };
11456
11456
  }
@@ -11473,8 +11473,8 @@ var require_react_reconciler_development = __commonJS({
11473
11473
  status: "pending",
11474
11474
  value: null,
11475
11475
  reason: null,
11476
- then: function(resolve4) {
11477
- listeners.push(resolve4);
11476
+ then: function(resolve6) {
11477
+ listeners.push(resolve6);
11478
11478
  }
11479
11479
  };
11480
11480
  thenable.then(
@@ -23274,7 +23274,7 @@ var init_keyed_serial_queue = __esm({
23274
23274
 
23275
23275
  // src/runtime/shared/sleep.mjs
23276
23276
  function sleep(ms) {
23277
- return new Promise((resolve4) => setTimeout(resolve4, ms));
23277
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
23278
23278
  }
23279
23279
  function sleepSync(ms) {
23280
23280
  const buffer = new SharedArrayBuffer(4);
@@ -23485,11 +23485,12 @@ function* releaseReclaimGuard(reclaim) {
23485
23485
  } catch {
23486
23486
  }
23487
23487
  }
23488
- function lockReclaimable(owner, stat2, staleMs) {
23488
+ function lockReclaimable(owner, stat2, staleMs, strictOwner = false) {
23489
23489
  if (owner.pid !== null) return !ownerIsLive(owner);
23490
+ if (strictOwner) return false;
23490
23491
  return Date.now() - (Number(stat2.mtimeMs) || 0) >= Math.max(0, staleMs);
23491
23492
  }
23492
- function* tryReclaimStaleLock(lockPath, staleMs) {
23493
+ function* tryReclaimStaleLock(lockPath, staleMs, strictOwner = false) {
23493
23494
  let initial;
23494
23495
  try {
23495
23496
  initial = yield ["stat", lockPath];
@@ -23497,7 +23498,7 @@ function* tryReclaimStaleLock(lockPath, staleMs) {
23497
23498
  return false;
23498
23499
  }
23499
23500
  const owner = yield* readLockOwner(lockPath);
23500
- if (!lockReclaimable(owner, initial, staleMs)) return false;
23501
+ if (!lockReclaimable(owner, initial, staleMs, strictOwner)) return false;
23501
23502
  const reclaim = yield* tryAcquireReclaimGuard(lockPath);
23502
23503
  if (reclaim === null) return false;
23503
23504
  try {
@@ -23509,7 +23510,7 @@ function* tryReclaimStaleLock(lockPath, staleMs) {
23509
23510
  }
23510
23511
  const currentOwner = yield* readLockOwner(lockPath);
23511
23512
  if (currentOwner.pid !== owner.pid || currentOwner.token !== owner.token) return false;
23512
- if (lockReclaimable(currentOwner, current, staleMs)) {
23513
+ if (lockReclaimable(currentOwner, current, staleMs, strictOwner)) {
23513
23514
  try {
23514
23515
  yield ["unlink", lockPath];
23515
23516
  return true;
@@ -23609,7 +23610,7 @@ function* acquireLock(lockPath, opts, mode, markHeld, timing = null) {
23609
23610
  lastError = error;
23610
23611
  if (!LOCK_WAIT_CODES.has(error?.code)) throw error;
23611
23612
  try {
23612
- if (runSync(tryReclaimStaleLock(lockPath, staleMs))) continue;
23613
+ if (runSync(tryReclaimStaleLock(lockPath, staleMs, opts.strictOwner === true))) continue;
23613
23614
  } catch {
23614
23615
  }
23615
23616
  if (timeoutMs <= 0) throw contentionError(lockPath, error, yield* describeLockHolder(lockPath));
@@ -23764,8 +23765,8 @@ function _drainAdaptiveFileIo() {
23764
23765
  }
23765
23766
  }
23766
23767
  function _runAdaptiveFileIo(run) {
23767
- return new Promise((resolve4, reject) => {
23768
- _ioQueue.push({ run, resolve: resolve4, reject });
23768
+ return new Promise((resolve6, reject) => {
23769
+ _ioQueue.push({ run, resolve: resolve6, reject });
23769
23770
  _drainAdaptiveFileIo();
23770
23771
  });
23771
23772
  }
@@ -24076,14 +24077,14 @@ import { createHash as createHash5 } from "node:crypto";
24076
24077
  import {
24077
24078
  chmodSync as chmodSync2,
24078
24079
  createReadStream,
24079
- existsSync as existsSync11,
24080
+ existsSync as existsSync12,
24080
24081
  mkdirSync as mkdirSync6,
24081
- readFileSync as readFileSync12,
24082
+ readFileSync as readFileSync13,
24082
24083
  readdirSync as readdirSync3,
24083
24084
  renameSync as renameSync4,
24084
24085
  rmSync as rmSync3
24085
24086
  } from "node:fs";
24086
- import { join as join12 } from "node:path";
24087
+ import { join as join13 } from "node:path";
24087
24088
  function platformKeyCandidates(platform2 = process.platform, arch = process.arch) {
24088
24089
  const native = `${platform2}-${arch}`;
24089
24090
  return platform2 === "win32" && arch === "arm64" ? [native, "win32-x64"] : [native];
@@ -24148,17 +24149,17 @@ import {
24148
24149
  closeSync as closeSync2,
24149
24150
  createReadStream as createReadStream2,
24150
24151
  createWriteStream as createWriteStream2,
24151
- existsSync as existsSync12,
24152
+ existsSync as existsSync13,
24152
24153
  mkdirSync as mkdirSync7,
24153
24154
  openSync as openSync2,
24154
- readFileSync as readFileSync13,
24155
+ readFileSync as readFileSync14,
24155
24156
  readdirSync as readdirSync4,
24156
24157
  rmSync as rmSync4,
24157
- statSync as statSync4,
24158
+ statSync as statSync5,
24158
24159
  writeFileSync as writeFileSync5
24159
24160
  } from "node:fs";
24160
24161
  import { setTimeout as sleep2 } from "node:timers/promises";
24161
- import { join as join13, dirname as dirname9 } from "node:path";
24162
+ import { join as join14, dirname as dirname11 } from "node:path";
24162
24163
  import { fileURLToPath as fileURLToPath3 } from "node:url";
24163
24164
  import { pipeline as pipeline2 } from "node:stream/promises";
24164
24165
  import { spawnSync } from "node:child_process";
@@ -24176,7 +24177,7 @@ function lockAgeMs(holderTs, waitSince) {
24176
24177
  }
24177
24178
  function _readInstallLockToken(lockPath) {
24178
24179
  try {
24179
- const raw = readFileSync13(lockPath, "utf8").trim();
24180
+ const raw = readFileSync14(lockPath, "utf8").trim();
24180
24181
  if (!raw) return null;
24181
24182
  const [pidLine, tsLine = ""] = raw.split(/\r?\n/);
24182
24183
  const pid = Number(pidLine);
@@ -24194,15 +24195,15 @@ function _installLockTokenMatches(lockPath, expectedPid, expectedTs, expectedTok
24194
24195
  }
24195
24196
  function chmodExtractedBinariesPosix(rootDir, executable) {
24196
24197
  if (process.platform === "win32") return;
24197
- const execDir = join13(rootDir, dirname9(executable));
24198
+ const execDir = join14(rootDir, dirname11(executable));
24198
24199
  const targets = /* @__PURE__ */ new Set([
24199
- join13(rootDir, executable),
24200
- join13(execDir, "whisper-cli"),
24201
- join13(execDir, "whisper-server"),
24202
- join13(execDir, "ffmpeg")
24200
+ join14(rootDir, executable),
24201
+ join14(execDir, "whisper-cli"),
24202
+ join14(execDir, "whisper-server"),
24203
+ join14(execDir, "ffmpeg")
24203
24204
  ]);
24204
24205
  for (const p of targets) {
24205
- if (existsSync12(p)) {
24206
+ if (existsSync13(p)) {
24206
24207
  try {
24207
24208
  chmodSync3(p, 493);
24208
24209
  } catch {
@@ -24212,7 +24213,7 @@ function chmodExtractedBinariesPosix(rootDir, executable) {
24212
24213
  }
24213
24214
  async function _withInstallLock(rootDir, lockName, fn, { pollMs = 250 } = {}) {
24214
24215
  mkdirSync7(rootDir, { recursive: true });
24215
- const lockPath = join13(rootDir, `.${lockName}.lock`);
24216
+ const lockPath = join14(rootDir, `.${lockName}.lock`);
24216
24217
  let fd = null;
24217
24218
  let foreignWaitSince = 0;
24218
24219
  let samePidWaitSince = 0;
@@ -24298,28 +24299,28 @@ ${Date.now()}`);
24298
24299
  }
24299
24300
  }
24300
24301
  function readBundledManifest() {
24301
- return JSON.parse(readFileSync13(BUNDLED_MANIFEST_PATH, "utf8"));
24302
+ return JSON.parse(readFileSync14(BUNDLED_MANIFEST_PATH, "utf8"));
24302
24303
  }
24303
24304
  function readActiveName(rootDir) {
24304
- const activeFile = join13(rootDir, "active-version");
24305
- if (!existsSync12(activeFile)) return "";
24306
- return readFileSync13(activeFile, "utf8").trim();
24305
+ const activeFile = join14(rootDir, "active-version");
24306
+ if (!existsSync13(activeFile)) return "";
24307
+ return readFileSync14(activeFile, "utf8").trim();
24307
24308
  }
24308
24309
  async function loadManifest(dataDir2) {
24309
- if (existsSync12(BUNDLED_MANIFEST_PATH)) {
24310
+ if (existsSync13(BUNDLED_MANIFEST_PATH)) {
24310
24311
  return readBundledManifest();
24311
24312
  }
24312
- const cachedPath = join13(dataDir2, "voice-runtime", "manifest.json");
24313
- if (existsSync12(cachedPath)) {
24313
+ const cachedPath = join14(dataDir2, "voice-runtime", "manifest.json");
24314
+ if (existsSync13(cachedPath)) {
24314
24315
  try {
24315
- return JSON.parse(readFileSync13(cachedPath, "utf8"));
24316
+ return JSON.parse(readFileSync14(cachedPath, "utf8"));
24316
24317
  } catch {
24317
24318
  }
24318
24319
  }
24319
24320
  const res = await fetch(MANIFEST_URL, { signal: AbortSignal.timeout(3e4) });
24320
24321
  if (!res.ok) throw new Error(`[voice-runtime] manifest fetch failed: ${res.status} ${res.statusText}`);
24321
24322
  const manifest = await res.json();
24322
- mkdirSync7(join13(dataDir2, "voice-runtime"), { recursive: true });
24323
+ mkdirSync7(join14(dataDir2, "voice-runtime"), { recursive: true });
24323
24324
  writeFileSync5(cachedPath, JSON.stringify(manifest, null, 2));
24324
24325
  return manifest;
24325
24326
  }
@@ -24332,20 +24333,20 @@ function detectCudaMajorsWin32() {
24332
24333
  const envKeys = Object.keys(process.env).filter((k) => k === "CUDA_PATH" || /^CUDA_PATH_V\d+_\d+$/i.test(k));
24333
24334
  for (const k of envKeys) {
24334
24335
  const p = process.env[k];
24335
- if (p) dirs.push(join13(p, "bin"));
24336
+ if (p) dirs.push(join14(p, "bin"));
24336
24337
  }
24337
24338
  for (const root of windowsProgramRoots()) {
24338
- const standardRoot = join13(root, "NVIDIA GPU Computing Toolkit", "CUDA");
24339
- if (!existsSync12(standardRoot)) continue;
24339
+ const standardRoot = join14(root, "NVIDIA GPU Computing Toolkit", "CUDA");
24340
+ if (!existsSync13(standardRoot)) continue;
24340
24341
  try {
24341
24342
  for (const e of readdirSync4(standardRoot)) {
24342
- if (/^v\d+\.\d+/.test(e)) dirs.push(join13(standardRoot, e, "bin"));
24343
+ if (/^v\d+\.\d+/.test(e)) dirs.push(join14(standardRoot, e, "bin"));
24343
24344
  }
24344
24345
  } catch {
24345
24346
  }
24346
24347
  }
24347
24348
  for (const d of dirs) {
24348
- if (!existsSync12(d)) continue;
24349
+ if (!existsSync13(d)) continue;
24349
24350
  try {
24350
24351
  for (const f of readdirSync4(d)) {
24351
24352
  const m = /^cublas64_(\d+)\.dll$/i.exec(f);
@@ -24367,7 +24368,7 @@ function detectCudaMajorsLinux() {
24367
24368
  const cudaPath = process.env.CUDA_PATH;
24368
24369
  if (cudaPath) dirs.push(`${cudaPath}/lib64`);
24369
24370
  for (const d of dirs) {
24370
- if (!existsSync12(d)) continue;
24371
+ if (!existsSync13(d)) continue;
24371
24372
  try {
24372
24373
  for (const f of readdirSync4(d)) {
24373
24374
  const m = /^libcublas\.so\.(\d+)$/.exec(f);
@@ -24390,7 +24391,7 @@ function hasNvidiaDriver() {
24390
24391
  const sys = windowsSystemRoot();
24391
24392
  if (!sys) return false;
24392
24393
  for (const f of ["System32\\nvidia-smi.exe", "System32\\nvml.dll"]) {
24393
- if (existsSync12(join13(sys, f))) return true;
24394
+ if (existsSync13(join14(sys, f))) return true;
24394
24395
  }
24395
24396
  return false;
24396
24397
  }
@@ -24413,7 +24414,7 @@ async function processExtras(extras, stagingDir, onProgress) {
24413
24414
  if (!Array.isArray(extras) || extras.length === 0) return;
24414
24415
  for (const extra of extras) {
24415
24416
  const tag = createHash6("sha256").update(extra.url).digest("hex").slice(0, 8);
24416
- const archivePath = join13(stagingDir, `extra-${tag}.${extra.format}`);
24417
+ const archivePath = join14(stagingDir, `extra-${tag}.${extra.format}`);
24417
24418
  process.stderr.write(`[voice-runtime] fetching extra ${tag} (${(extra.size / 1024 / 1024).toFixed(0)} MB) ...
24418
24419
  `);
24419
24420
  await downloadFile(extra.url, archivePath, {
@@ -24422,16 +24423,16 @@ async function processExtras(extras, stagingDir, onProgress) {
24422
24423
  });
24423
24424
  if (!extra.sha256) throw new Error(`[voice-runtime] manifest extra entry missing required sha256: ${extra.url}`);
24424
24425
  await verifySha256(archivePath, extra.sha256);
24425
- const extractDir = join13(stagingDir, `.extra-${tag}`);
24426
+ const extractDir = join14(stagingDir, `.extra-${tag}`);
24426
24427
  mkdirSync7(extractDir, { recursive: true });
24427
24428
  extractZip(archivePath, extractDir);
24428
24429
  for (const f of extra.files) {
24429
- const src = join13(extractDir, f.from);
24430
- const dst = join13(stagingDir, f.to);
24431
- if (!existsSync12(src)) {
24430
+ const src = join14(extractDir, f.from);
24431
+ const dst = join14(stagingDir, f.to);
24432
+ if (!existsSync13(src)) {
24432
24433
  throw new Error(`[voice-runtime] extra ${tag}: expected file ${f.from} not present after extract`);
24433
24434
  }
24434
- mkdirSync7(dirname9(dst), { recursive: true });
24435
+ mkdirSync7(dirname11(dst), { recursive: true });
24435
24436
  renameWithRetrySync(src, dst);
24436
24437
  }
24437
24438
  try {
@@ -24445,12 +24446,12 @@ async function processExtras(extras, stagingDir, onProgress) {
24445
24446
  }
24446
24447
  }
24447
24448
  function gcStaleVersions(rootDir, activeName, prefix) {
24448
- if (!existsSync12(rootDir)) return;
24449
+ if (!existsSync13(rootDir)) return;
24449
24450
  for (const entry of readdirSync4(rootDir)) {
24450
24451
  if (entry === activeName || entry === "active-version" || entry === "manifest.json") continue;
24451
24452
  if (!entry.startsWith(prefix) && !entry.startsWith("staging-")) continue;
24452
24453
  try {
24453
- rmSync4(join13(rootDir, entry), { recursive: true, force: true });
24454
+ rmSync4(join14(rootDir, entry), { recursive: true, force: true });
24454
24455
  } catch {
24455
24456
  }
24456
24457
  }
@@ -24458,7 +24459,7 @@ function gcStaleVersions(rootDir, activeName, prefix) {
24458
24459
  function gcPublishedRuntimeSiblings(rootDir, prefix) {
24459
24460
  try {
24460
24461
  const activeName = readActiveName(rootDir);
24461
- if (!activeName.startsWith(prefix) || !existsSync12(join13(rootDir, activeName))) return;
24462
+ if (!activeName.startsWith(prefix) || !existsSync13(join14(rootDir, activeName))) return;
24462
24463
  gcStaleVersions(rootDir, activeName, prefix);
24463
24464
  } catch {
24464
24465
  }
@@ -24467,12 +24468,12 @@ async function extractGz(gzPath, destPath) {
24467
24468
  await pipeline2(createReadStream2(gzPath), createGunzip(), createWriteStream2(destPath));
24468
24469
  }
24469
24470
  function gcStagingPartials(dir) {
24470
- if (!existsSync12(dir)) return;
24471
+ if (!existsSync13(dir)) return;
24471
24472
  try {
24472
24473
  for (const entry of readdirSync4(dir)) {
24473
24474
  if (!entry.startsWith(".staging-")) continue;
24474
24475
  try {
24475
- rmSync4(join13(dir, entry), { force: true });
24476
+ rmSync4(join14(dir, entry), { force: true });
24476
24477
  } catch {
24477
24478
  }
24478
24479
  }
@@ -24543,24 +24544,24 @@ async function ensureWhisperRuntime(dataDir2, onProgress = null) {
24543
24544
  );
24544
24545
  }
24545
24546
  const ver = manifest.version;
24546
- const rootDir = join13(dataDir2, "voice-runtime");
24547
+ const rootDir = join14(dataDir2, "voice-runtime");
24547
24548
  const activeName = `whisper-${ver}-${variant.id}`;
24548
- const activeDir = join13(rootDir, activeName);
24549
- const whisperCmd = join13(activeDir, variant.executable);
24550
- if (existsSync12(whisperCmd)) {
24549
+ const activeDir = join14(rootDir, activeName);
24550
+ const whisperCmd = join14(activeDir, variant.executable);
24551
+ if (existsSync13(whisperCmd)) {
24551
24552
  gcStaleVersions(rootDir, activeName, "whisper-");
24552
24553
  return { whisperCmd, version: ver, variantId: variant.id };
24553
24554
  }
24554
24555
  return _withInstallLock(rootDir, "install", async () => {
24555
- if (existsSync12(whisperCmd)) {
24556
+ if (existsSync13(whisperCmd)) {
24556
24557
  gcStaleVersions(rootDir, activeName, "whisper-");
24557
24558
  return { whisperCmd, version: ver, variantId: variant.id };
24558
24559
  }
24559
24560
  gcStagingPartials(rootDir);
24560
- const stagingDir = join13(rootDir, `staging-${process.pid}-${Date.now()}`);
24561
+ const stagingDir = join14(rootDir, `staging-${process.pid}-${Date.now()}`);
24561
24562
  mkdirSync7(stagingDir, { recursive: true });
24562
24563
  try {
24563
- const archivePath = join13(stagingDir, `whisper.${variant.format}`);
24564
+ const archivePath = join14(stagingDir, `whisper.${variant.format}`);
24564
24565
  process.stderr.write(
24565
24566
  `[voice-runtime] fetching whisper-${ver} variant=${variant.id} for ${key} (${(variant.size / 1024 / 1024).toFixed(0)} MB; cuda=${[...env4.cudaMajors].join(",") || "none"} nvidiaDriver=${env4.hasNvidiaDriver}) ...
24566
24567
  `
@@ -24575,13 +24576,13 @@ async function ensureWhisperRuntime(dataDir2, onProgress = null) {
24575
24576
  extractZip(archivePath, stagingDir);
24576
24577
  rmSync4(archivePath, { force: true });
24577
24578
  chmodExtractedBinariesPosix(stagingDir, variant.executable);
24578
- const stagedExec = join13(stagingDir, variant.executable);
24579
- if (!existsSync12(stagedExec)) {
24579
+ const stagedExec = join14(stagingDir, variant.executable);
24580
+ if (!existsSync13(stagedExec)) {
24580
24581
  throw new Error(`[voice-runtime] expected executable ${variant.executable} not present after extract`);
24581
24582
  }
24582
24583
  await processExtras(variant.extras, stagingDir, onProgress);
24583
24584
  renameWithRetrySync(stagingDir, activeDir);
24584
- writeFileAtomicSync(join13(rootDir, "active-version"), activeName, { fsyncDir: true });
24585
+ writeFileAtomicSync(join14(rootDir, "active-version"), activeName, { fsyncDir: true });
24585
24586
  process.stderr.write(`[voice-runtime] whisper-${ver} variant=${variant.id} ready at ${activeDir}
24586
24587
  `);
24587
24588
  gcStaleVersions(rootDir, activeName, "whisper-");
@@ -24596,9 +24597,9 @@ async function ensureWhisperRuntime(dataDir2, onProgress = null) {
24596
24597
  });
24597
24598
  }
24598
24599
  function isManagedWhisperStale(dataDir2) {
24599
- const activeName = readActiveName(join13(dataDir2, "voice-runtime"));
24600
+ const activeName = readActiveName(join14(dataDir2, "voice-runtime"));
24600
24601
  if (!activeName) return false;
24601
- if (!existsSync12(BUNDLED_MANIFEST_PATH)) return false;
24602
+ if (!existsSync13(BUNDLED_MANIFEST_PATH)) return false;
24602
24603
  try {
24603
24604
  const manifest = readBundledManifest();
24604
24605
  if (!manifest?.version) return false;
@@ -24608,10 +24609,10 @@ function isManagedWhisperStale(dataDir2) {
24608
24609
  }
24609
24610
  }
24610
24611
  function resolveManagedWhisperCmd(dataDir2) {
24611
- const activeName = readActiveName(join13(dataDir2, "voice-runtime"));
24612
+ const activeName = readActiveName(join14(dataDir2, "voice-runtime"));
24612
24613
  if (!activeName) return null;
24613
- const activeDir = join13(dataDir2, "voice-runtime", activeName);
24614
- if (existsSync12(BUNDLED_MANIFEST_PATH)) {
24614
+ const activeDir = join14(dataDir2, "voice-runtime", activeName);
24615
+ if (existsSync13(BUNDLED_MANIFEST_PATH)) {
24615
24616
  try {
24616
24617
  const manifest = readBundledManifest();
24617
24618
  const key = platformEntryKey(manifest.platforms);
@@ -24621,26 +24622,26 @@ function resolveManagedWhisperCmd(dataDir2) {
24621
24622
  const variantId = activeName.startsWith(prefix) ? activeName.slice(prefix.length) : "";
24622
24623
  const variant = variants.find((v) => v.id === variantId);
24623
24624
  if (variant?.executable) {
24624
- const p = join13(activeDir, variant.executable);
24625
- if (existsSync12(p)) return p;
24625
+ const p = join14(activeDir, variant.executable);
24626
+ if (existsSync13(p)) return p;
24626
24627
  }
24627
24628
  }
24628
24629
  } catch {
24629
24630
  }
24630
24631
  }
24631
24632
  for (const c of ["Release/whisper-cli.exe", "Release/whisper-cli"]) {
24632
- const p = join13(activeDir, c);
24633
- if (existsSync12(p)) return p;
24633
+ const p = join14(activeDir, c);
24634
+ if (existsSync13(p)) return p;
24634
24635
  }
24635
24636
  return null;
24636
24637
  }
24637
24638
  function resolveManagedWhisperModelById(dataDir2, modelId = "standard") {
24638
- if (!existsSync12(BUNDLED_MANIFEST_PATH)) return null;
24639
+ if (!existsSync13(BUNDLED_MANIFEST_PATH)) return null;
24639
24640
  const entry = manifestModelEntry(readBundledManifest(), modelId);
24640
24641
  if (!entry?.filename) return null;
24641
- const modelDir = join13(dataDir2, "voice", "models");
24642
- const p = join13(modelDir, entry.filename);
24643
- return existsSync12(p) ? p : null;
24642
+ const modelDir = join14(dataDir2, "voice", "models");
24643
+ const p = join14(modelDir, entry.filename);
24644
+ return existsSync13(p) ? p : null;
24644
24645
  }
24645
24646
  function gcUnknownModelFiles(manifest, modelDir) {
24646
24647
  const keep = /* @__PURE__ */ new Set();
@@ -24657,7 +24658,7 @@ function gcUnknownModelFiles(manifest, modelDir) {
24657
24658
  for (const name of names) {
24658
24659
  if (!name.endsWith(".bin") || keep.has(name)) continue;
24659
24660
  try {
24660
- rmSync4(join13(modelDir, name), { force: true });
24661
+ rmSync4(join14(modelDir, name), { force: true });
24661
24662
  process.stderr.write(`[voice-runtime] removed stale model file ${name}
24662
24663
  `);
24663
24664
  } catch {
@@ -24675,24 +24676,24 @@ async function ensureFfmpegRuntime(dataDir2, onProgress = null) {
24675
24676
  throw new VoiceRuntimeUnsupportedError(key);
24676
24677
  }
24677
24678
  const ver = manifest.ffmpeg.version;
24678
- const rootDir = join13(dataDir2, "ffmpeg-runtime");
24679
+ const rootDir = join14(dataDir2, "ffmpeg-runtime");
24679
24680
  const activeName = `ffmpeg-${ver}`;
24680
- const activeDir = join13(rootDir, activeName);
24681
- const ffmpegPath = join13(activeDir, platformEntry.executable);
24682
- if (existsSync12(ffmpegPath)) {
24681
+ const activeDir = join14(rootDir, activeName);
24682
+ const ffmpegPath = join14(activeDir, platformEntry.executable);
24683
+ if (existsSync13(ffmpegPath)) {
24683
24684
  gcStaleVersions(rootDir, activeName, "ffmpeg-");
24684
24685
  return { ffmpegPath, version: ver };
24685
24686
  }
24686
24687
  return _withInstallLock(rootDir, "install", async () => {
24687
- if (existsSync12(ffmpegPath)) {
24688
+ if (existsSync13(ffmpegPath)) {
24688
24689
  gcStaleVersions(rootDir, activeName, "ffmpeg-");
24689
24690
  return { ffmpegPath, version: ver };
24690
24691
  }
24691
24692
  gcStagingPartials(rootDir);
24692
- const stagingDir = join13(rootDir, `staging-${process.pid}-${Date.now()}`);
24693
+ const stagingDir = join14(rootDir, `staging-${process.pid}-${Date.now()}`);
24693
24694
  mkdirSync7(stagingDir, { recursive: true });
24694
24695
  try {
24695
- const archivePath = join13(stagingDir, `ffmpeg.${platformEntry.format}`);
24696
+ const archivePath = join14(stagingDir, `ffmpeg.${platformEntry.format}`);
24696
24697
  process.stderr.write(
24697
24698
  `[voice-runtime] fetching ffmpeg-${ver} for ${key} (${(platformEntry.size / 1024 / 1024).toFixed(0)} MB) ...
24698
24699
  `
@@ -24704,7 +24705,7 @@ async function ensureFfmpegRuntime(dataDir2, onProgress = null) {
24704
24705
  if (!platformEntry.sha256)
24705
24706
  throw new Error(`[voice-runtime] manifest ffmpeg entry for ${key} missing required sha256`);
24706
24707
  await verifySha256(archivePath, platformEntry.sha256);
24707
- const stagedExec = join13(stagingDir, platformEntry.executable);
24708
+ const stagedExec = join14(stagingDir, platformEntry.executable);
24708
24709
  if (platformEntry.format === "gz") {
24709
24710
  await extractGz(archivePath, stagedExec);
24710
24711
  } else if (platformEntry.format === "zip") {
@@ -24713,7 +24714,7 @@ async function ensureFfmpegRuntime(dataDir2, onProgress = null) {
24713
24714
  throw new Error(`[voice-runtime] ffmpeg manifest format must be "gz" or "zip", got "${platformEntry.format}"`);
24714
24715
  }
24715
24716
  rmSync4(archivePath, { force: true });
24716
- if (!existsSync12(stagedExec)) {
24717
+ if (!existsSync13(stagedExec)) {
24717
24718
  throw new Error(
24718
24719
  `[voice-runtime] expected ffmpeg executable ${platformEntry.executable} not present after extract`
24719
24720
  );
@@ -24722,7 +24723,7 @@ async function ensureFfmpegRuntime(dataDir2, onProgress = null) {
24722
24723
  chmodSync3(stagedExec, 493);
24723
24724
  }
24724
24725
  renameWithRetrySync(stagingDir, activeDir);
24725
- writeFileAtomicSync(join13(rootDir, "active-version"), activeName, { fsyncDir: true });
24726
+ writeFileAtomicSync(join14(rootDir, "active-version"), activeName, { fsyncDir: true });
24726
24727
  process.stderr.write(`[voice-runtime] ffmpeg-${ver} ready at ${activeDir}
24727
24728
  `);
24728
24729
  gcStaleVersions(rootDir, activeName, "ffmpeg-");
@@ -24737,24 +24738,24 @@ async function ensureFfmpegRuntime(dataDir2, onProgress = null) {
24737
24738
  });
24738
24739
  }
24739
24740
  function resolveManagedFfmpegPath(dataDir2) {
24740
- const activeName = readActiveName(join13(dataDir2, "ffmpeg-runtime"));
24741
+ const activeName = readActiveName(join14(dataDir2, "ffmpeg-runtime"));
24741
24742
  if (!activeName) return null;
24742
- const activeDir = join13(dataDir2, "ffmpeg-runtime", activeName);
24743
- if (existsSync12(BUNDLED_MANIFEST_PATH)) {
24743
+ const activeDir = join14(dataDir2, "ffmpeg-runtime", activeName);
24744
+ if (existsSync13(BUNDLED_MANIFEST_PATH)) {
24744
24745
  try {
24745
24746
  const manifest = readBundledManifest();
24746
24747
  const key = platformEntryKey(manifest.ffmpeg?.platforms);
24747
24748
  const platformEntry = manifest.ffmpeg?.platforms?.[key];
24748
24749
  if (platformEntry?.executable) {
24749
- const p = join13(activeDir, platformEntry.executable);
24750
- if (existsSync12(p)) return p;
24750
+ const p = join14(activeDir, platformEntry.executable);
24751
+ if (existsSync13(p)) return p;
24751
24752
  }
24752
24753
  } catch {
24753
24754
  }
24754
24755
  }
24755
24756
  for (const c of ["ffmpeg.exe", "ffmpeg"]) {
24756
- const p = join13(activeDir, c);
24757
- if (existsSync12(p)) return p;
24757
+ const p = join14(activeDir, c);
24758
+ if (existsSync13(p)) return p;
24758
24759
  }
24759
24760
  return null;
24760
24761
  }
@@ -24769,7 +24770,7 @@ function voiceRuntimeInfo(runtime) {
24769
24770
  let modelBytes = model?.size || 0;
24770
24771
  if (runtime.modelPath) {
24771
24772
  try {
24772
- modelBytes = statSync4(runtime.modelPath).size;
24773
+ modelBytes = statSync5(runtime.modelPath).size;
24773
24774
  } catch {
24774
24775
  modelBytes = 0;
24775
24776
  }
@@ -24785,15 +24786,15 @@ function voiceRuntimeInfo(runtime) {
24785
24786
  }
24786
24787
  function resolveVoiceRuntime(dataDir2, { modelId = "standard", cleanup = true } = {}) {
24787
24788
  if (cleanup) {
24788
- gcPublishedRuntimeSiblings(join13(dataDir2, "voice-runtime"), "whisper-");
24789
- gcPublishedRuntimeSiblings(join13(dataDir2, "ffmpeg-runtime"), "ffmpeg-");
24789
+ gcPublishedRuntimeSiblings(join14(dataDir2, "voice-runtime"), "whisper-");
24790
+ gcPublishedRuntimeSiblings(join14(dataDir2, "ffmpeg-runtime"), "ffmpeg-");
24790
24791
  }
24791
24792
  const managedWhisperCmd = resolveManagedWhisperCmd(dataDir2);
24792
24793
  const managedModelPath = resolveManagedWhisperModelById(dataDir2, modelId);
24793
24794
  const managedFfmpegPath = resolveManagedFfmpegPath(dataDir2);
24794
24795
  const ext = process.platform === "win32" ? ".exe" : "";
24795
- const managedServerCmd = managedWhisperCmd ? join13(dirname9(managedWhisperCmd), `whisper-server${ext}`) : null;
24796
- const serverCmd = managedServerCmd && existsSync12(managedServerCmd) ? managedServerCmd : null;
24796
+ const managedServerCmd = managedWhisperCmd ? join14(dirname11(managedWhisperCmd), `whisper-server${ext}`) : null;
24797
+ const serverCmd = managedServerCmd && existsSync13(managedServerCmd) ? managedServerCmd : null;
24797
24798
  return {
24798
24799
  kind: "managed-whisper.cpp",
24799
24800
  label: "whisper.cpp",
@@ -24818,9 +24819,9 @@ async function ensureWhisperModel(dataDir2, onProgress = null, modelId = "standa
24818
24819
  if (!model) {
24819
24820
  throw new Error("[voice-runtime] manifest is missing the `model` section \u2014 cannot resolve whisper model");
24820
24821
  }
24821
- const modelDir = join13(dataDir2, "voice", "models");
24822
- const modelPath = join13(modelDir, model.filename);
24823
- if (existsSync12(modelPath)) {
24822
+ const modelDir = join14(dataDir2, "voice", "models");
24823
+ const modelPath = join14(modelDir, model.filename);
24824
+ if (existsSync13(modelPath)) {
24824
24825
  const actual = await sha256File(modelPath);
24825
24826
  if (actual === model.sha256) {
24826
24827
  return { modelPath, modelId: model.id, size: model.size };
@@ -24835,7 +24836,7 @@ async function ensureWhisperModel(dataDir2, onProgress = null, modelId = "standa
24835
24836
  }
24836
24837
  }
24837
24838
  return _withInstallLock(modelDir, "install", async () => {
24838
- if (existsSync12(modelPath)) {
24839
+ if (existsSync13(modelPath)) {
24839
24840
  const actual = await sha256File(modelPath);
24840
24841
  if (actual === model.sha256) {
24841
24842
  gcUnknownModelFiles(manifest, modelDir);
@@ -24847,7 +24848,7 @@ async function ensureWhisperModel(dataDir2, onProgress = null, modelId = "standa
24847
24848
  }
24848
24849
  }
24849
24850
  gcStagingPartials(modelDir);
24850
- const stagingPath = join13(modelDir, `.staging-${process.pid}-${Date.now()}-${model.filename}`);
24851
+ const stagingPath = join14(modelDir, `.staging-${process.pid}-${Date.now()}-${model.filename}`);
24851
24852
  try {
24852
24853
  process.stderr.write(
24853
24854
  `[voice-runtime] fetching model ${model.id} (${(model.size / 1024 / 1024).toFixed(0)} MB) from ${model.url} ...
@@ -33875,8 +33876,8 @@ var App_default = App;
33875
33876
  var noop = () => {
33876
33877
  };
33877
33878
  var textEncoder = new TextEncoder();
33878
- var yieldImmediate = async () => new Promise((resolve4) => {
33879
- setImmediate(resolve4);
33879
+ var yieldImmediate = async () => new Promise((resolve6) => {
33880
+ setImmediate(resolve6);
33880
33881
  });
33881
33882
  var kittyQueryEscapeByte = 27;
33882
33883
  var kittyQueryOpenBracketByte = 91;
@@ -34131,8 +34132,8 @@ var Ink = class {
34131
34132
  };
34132
34133
  }
34133
34134
  this.initKittyKeyboard();
34134
- this.exitPromise = new Promise((resolve4, reject) => {
34135
- this.resolveExitPromise = resolve4;
34135
+ this.exitPromise = new Promise((resolve6, reject) => {
34136
+ this.resolveExitPromise = resolve6;
34136
34137
  this.rejectExitPromise = reject;
34137
34138
  });
34138
34139
  void this.exitPromise.catch(noop);
@@ -34572,9 +34573,9 @@ var Ink = class {
34572
34573
  settleThrottle(this.throttledOnRender, canWriteToStdout);
34573
34574
  settleThrottle(this.throttledLog, canWriteToStdout);
34574
34575
  if (canWriteToStdout && hasWritableState) {
34575
- await new Promise((resolve4) => {
34576
+ await new Promise((resolve6) => {
34576
34577
  this.options.stdout.write("", () => {
34577
- resolve4();
34578
+ resolve6();
34578
34579
  });
34579
34580
  });
34580
34581
  return;
@@ -34660,8 +34661,8 @@ var Ink = class {
34660
34661
  async awaitNextRender() {
34661
34662
  if (!this.nextRenderCommit) {
34662
34663
  let resolveRender;
34663
- const promise = new Promise((resolve4) => {
34664
- resolveRender = resolve4;
34664
+ const promise = new Promise((resolve6) => {
34665
+ resolveRender = resolve6;
34665
34666
  });
34666
34667
  this.nextRenderCommit = { promise, resolve: resolveRender };
34667
34668
  }
@@ -35114,7 +35115,7 @@ import { useState as useState5, useEffect as useEffect6, useCallback as useCallb
35114
35115
  // src/tui/index.jsx
35115
35116
  import { closeSync as closeSync3, constants as fsConstants, createWriteStream as createWriteStream3, mkdirSync as mkdirSync8, openSync as openSync3, readSync } from "node:fs";
35116
35117
  import { tmpdir as tmpdir3 } from "node:os";
35117
- import { dirname as dirname10, join as join16 } from "node:path";
35118
+ import { dirname as dirname12, join as join17 } from "node:path";
35118
35119
  import { performance as performance2 } from "node:perf_hooks";
35119
35120
  import { format } from "node:util";
35120
35121
 
@@ -35132,12 +35133,12 @@ import { spawn } from "node:child_process";
35132
35133
  import path from "node:path";
35133
35134
  var DIALOG_TIMEOUT_MS = 5 * 60 * 1e3;
35134
35135
  function runCapture(cmd, args, { timeoutMs = DIALOG_TIMEOUT_MS } = {}) {
35135
- return new Promise((resolve4) => {
35136
+ return new Promise((resolve6) => {
35136
35137
  let child;
35137
35138
  try {
35138
35139
  child = spawn(cmd, args, { stdio: ["ignore", "pipe", "ignore"], windowsHide: true });
35139
35140
  } catch (error) {
35140
- resolve4({ ok: false, code: -1, stdout: "", error });
35141
+ resolve6({ ok: false, code: -1, stdout: "", error });
35141
35142
  return;
35142
35143
  }
35143
35144
  let stdout2 = "";
@@ -35149,7 +35150,7 @@ function runCapture(cmd, args, { timeoutMs = DIALOG_TIMEOUT_MS } = {}) {
35149
35150
  child.kill();
35150
35151
  } catch {
35151
35152
  }
35152
- resolve4({ ok: false, code: -1, stdout: "", error: new Error("dialog timed out") });
35153
+ resolve6({ ok: false, code: -1, stdout: "", error: new Error("dialog timed out") });
35153
35154
  }, timeoutMs);
35154
35155
  timer2.unref?.();
35155
35156
  child.stdout.on("data", (chunk) => {
@@ -35159,13 +35160,13 @@ function runCapture(cmd, args, { timeoutMs = DIALOG_TIMEOUT_MS } = {}) {
35159
35160
  if (settled) return;
35160
35161
  settled = true;
35161
35162
  clearTimeout(timer2);
35162
- resolve4({ ok: false, code: -1, stdout: "", error });
35163
+ resolve6({ ok: false, code: -1, stdout: "", error });
35163
35164
  });
35164
35165
  child.on("close", (code) => {
35165
35166
  if (settled) return;
35166
35167
  settled = true;
35167
35168
  clearTimeout(timer2);
35168
- resolve4({ ok: code === 0, code, stdout: stdout2 });
35169
+ resolve6({ ok: code === 0, code, stdout: stdout2 });
35169
35170
  });
35170
35171
  });
35171
35172
  }
@@ -35173,10 +35174,10 @@ function spawnFailed(result) {
35173
35174
  return !!result && result.code === -1;
35174
35175
  }
35175
35176
  function commandExists(cmd) {
35176
- return new Promise((resolve4) => {
35177
+ return new Promise((resolve6) => {
35177
35178
  const probe = process.platform === "win32" ? spawn("where", [cmd], { stdio: "ignore", windowsHide: true }) : spawn("which", [cmd], { stdio: "ignore" });
35178
- probe.on("error", () => resolve4(false));
35179
- probe.on("close", (code) => resolve4(code === 0));
35179
+ probe.on("error", () => resolve6(false));
35180
+ probe.on("close", (code) => resolve6(code === 0));
35180
35181
  });
35181
35182
  }
35182
35183
  function psSingleQuoted(value) {
@@ -35445,6 +35446,12 @@ var SLASH_COMMANDS = [
35445
35446
  },
35446
35447
  { name: "resume", usage: "/resume", params: "[id]", description: "Resume a saved chat" },
35447
35448
  { name: "context", usage: "/context", description: "Show current context surface" },
35449
+ {
35450
+ name: "shells",
35451
+ usage: "/shells",
35452
+ params: "[release <task_id> [--confirm]]",
35453
+ description: "List shells; release one whose termination is unconfirmed"
35454
+ },
35448
35455
  {
35449
35456
  name: "fork",
35450
35457
  usage: "/fork",
@@ -37526,7 +37533,7 @@ var DIFF_STAT_SUMMARY_RE = /^\s*\d+\s+files?\s+changed\b/;
37526
37533
  function colorizeDiffStatLine(line, c) {
37527
37534
  const m = DIFF_STAT_FILE_RE.exec(line);
37528
37535
  if (m) {
37529
- const [, indent, path2, sep, tail] = m;
37536
+ const [, indent, path2, sep2, tail] = m;
37530
37537
  const countMatch = /^(\d+)(\s*)([+-]*)\s*$/.exec(tail);
37531
37538
  let coloredTail;
37532
37539
  if (countMatch) {
@@ -37537,7 +37544,7 @@ function colorizeDiffStatLine(line, c) {
37537
37544
  } else {
37538
37545
  coloredTail = c.diffContext(tail);
37539
37546
  }
37540
- return `${indent}${c.diffContext(path2)}${c.diffContext(sep)}${coloredTail}`;
37547
+ return `${indent}${c.diffContext(path2)}${c.diffContext(sep2)}${coloredTail}`;
37541
37548
  }
37542
37549
  return c.diffContext(line);
37543
37550
  }
@@ -38481,19 +38488,34 @@ var HEALABLE_MARKDOWN_SYNTAX = /[`*_~[]/;
38481
38488
  function openFence(text) {
38482
38489
  let marker = "";
38483
38490
  let length = 0;
38491
+ let start = 0;
38492
+ let lineStart2 = 0;
38484
38493
  for (const rawLine of String(text ?? "").split("\n")) {
38485
38494
  const fence = FENCE_LINE.exec(rawLine.replace(/\r$/, ""));
38486
- if (!fence) continue;
38487
- const marks = fence[1];
38488
- if (!marker) {
38489
- marker = marks[0];
38490
- length = marks.length;
38491
- } else if (marks[0] === marker && marks.length >= length && !fence[2].trim()) {
38492
- marker = "";
38493
- length = 0;
38495
+ if (fence) {
38496
+ const marks = fence[1];
38497
+ if (!marker) {
38498
+ marker = marks[0];
38499
+ length = marks.length;
38500
+ start = lineStart2;
38501
+ } else if (marks[0] === marker && marks.length >= length && !fence[2].trim()) {
38502
+ marker = "";
38503
+ length = 0;
38504
+ }
38494
38505
  }
38506
+ lineStart2 += rawLine.length + 1;
38495
38507
  }
38496
- return marker ? { marker, length } : null;
38508
+ return marker ? { marker, length, start } : null;
38509
+ }
38510
+ function trimPartialOpeningFence(text, fence) {
38511
+ const lineEnd2 = text.indexOf("\n", fence.start);
38512
+ return lineEnd2 >= 0 && /\S/.test(text.slice(lineEnd2 + 1)) ? text : text.slice(0, fence.start);
38513
+ }
38514
+ var PENDING_BLOCK_MARKER_LINE = /(?:^|\n)[ \t]*(?:[-+*=_#>~`]+|\d{1,9}[.)]?)[ \t]*$/;
38515
+ function trimPendingBlockMarker(text) {
38516
+ const pending = PENDING_BLOCK_MARKER_LINE.exec(text);
38517
+ if (!pending) return text;
38518
+ return text.slice(0, pending.index + (pending[0].startsWith("\n") ? 1 : 0));
38497
38519
  }
38498
38520
  function trimPartialClosingFence(text, fence) {
38499
38521
  const partial = /(?:^|\r?\n) {0,3}([`~]+)$/.exec(text);
@@ -38524,7 +38546,7 @@ function closeInlineCode(text, isPendingLocalPath) {
38524
38546
  } else if (run === open) open = 0;
38525
38547
  index = end;
38526
38548
  }
38527
- if (open && isPendingLocalPath?.(text.slice(openIndex + open))) {
38549
+ if (open && (!text.slice(openIndex + open) || isPendingLocalPath?.(text.slice(openIndex + open)))) {
38528
38550
  return text.slice(0, openIndex);
38529
38551
  }
38530
38552
  return open > 0 ? `${text}${"`".repeat(open)}` : text;
@@ -38554,6 +38576,7 @@ function scanEmphasisRuns(masked) {
38554
38576
  let end = index + 1;
38555
38577
  while (masked[end] === marker) end += 1;
38556
38578
  const length = end - index;
38579
+ const at = index;
38557
38580
  const before = index > 0 ? masked[index - 1] : "";
38558
38581
  const after = end < masked.length ? masked[end] : "";
38559
38582
  const beforeSpace = isMarkdownSpace(before);
@@ -38563,16 +38586,25 @@ function scanEmphasisRuns(masked) {
38563
38586
  const left = !afterSpace && (!afterPunctuation || beforeSpace || beforePunctuation);
38564
38587
  const right = !beforeSpace && (!beforePunctuation || afterSpace || afterPunctuation);
38565
38588
  if (marker === "~") {
38566
- if (length >= 2) runs.push({ marker, length: 2, canOpen: left, canClose: right });
38589
+ runs.push({
38590
+ marker,
38591
+ length: Math.min(length, 2),
38592
+ canOpen: left && length >= 2,
38593
+ canClose: right && length >= 2,
38594
+ at,
38595
+ end
38596
+ });
38567
38597
  } else if (marker === "_") {
38568
38598
  runs.push({
38569
38599
  marker,
38570
38600
  length,
38571
38601
  canOpen: left && (!right || beforePunctuation),
38572
- canClose: right && (!left || afterPunctuation)
38602
+ canClose: right && (!left || afterPunctuation),
38603
+ at,
38604
+ end
38573
38605
  });
38574
38606
  } else {
38575
- runs.push({ marker, length, canOpen: left, canClose: right });
38607
+ runs.push({ marker, length, canOpen: left, canClose: right, at, end });
38576
38608
  }
38577
38609
  index = end;
38578
38610
  }
@@ -38580,7 +38612,9 @@ function scanEmphasisRuns(masked) {
38580
38612
  }
38581
38613
  function closeEmphasis(text) {
38582
38614
  const open = [];
38583
- for (const run of scanEmphasisRuns(maskCode(text))) {
38615
+ const runs = scanEmphasisRuns(maskCode(text));
38616
+ const last = runs[runs.length - 1];
38617
+ for (const run of runs) {
38584
38618
  let length = run.length;
38585
38619
  while (run.canClose && length > 0) {
38586
38620
  let match = -1;
@@ -38597,13 +38631,17 @@ function closeEmphasis(text) {
38597
38631
  length -= used;
38598
38632
  open.length = opener.length > 0 ? match + 1 : match;
38599
38633
  }
38634
+ if (run === last && run.end === text.length && length === run.length) {
38635
+ return closeEmphasis(text.slice(0, run.at));
38636
+ }
38600
38637
  if (length > 0 && run.canOpen) open.push({ marker: run.marker, length });
38601
38638
  }
38602
- let healed = text;
38639
+ const body = text.trimEnd();
38640
+ let closers = "";
38603
38641
  for (let index = open.length - 1; index >= 0; index -= 1) {
38604
- healed += open[index].marker.repeat(Math.min(open[index].length, 3));
38642
+ closers += open[index].marker.repeat(Math.min(open[index].length, 3));
38605
38643
  }
38606
- return healed;
38644
+ return closers ? `${body}${closers}${text.slice(body.length)}` : text;
38607
38645
  }
38608
38646
  function linkDestinationEnd(text, start) {
38609
38647
  let depth = 1;
@@ -38687,8 +38725,9 @@ function trimPendingTableHead(text) {
38687
38725
  function healStreamingMarkdownTail(text, isPendingLocalPath) {
38688
38726
  const source = String(text ?? "");
38689
38727
  const fence = source.includes("`") || source.includes("~") ? openFence(source) : null;
38690
- if (fence) return trimPartialClosingFence(source, fence);
38691
- const value = source.includes("|") ? trimPendingTableHead(source) : source;
38728
+ if (fence) return trimPartialOpeningFence(trimPartialClosingFence(source, fence), fence);
38729
+ const unmarked = trimPendingBlockMarker(source);
38730
+ const value = unmarked.includes("|") ? trimPendingTableHead(unmarked) : unmarked;
38692
38731
  const hasSyntax = HEALABLE_MARKDOWN_SYNTAX.test(value);
38693
38732
  if (!value || !hasSyntax && !isPendingLocalPath) return value;
38694
38733
  const healed = hasSyntax ? closeEmphasis(healIncompleteLink(closeInlineCode(value, isPendingLocalPath), isPendingLocalPath)) : value;
@@ -39936,7 +39975,7 @@ function isUserControlCancellation(text) {
39936
39975
  return USER_CONTROL_CANCELLATION_RE.test(String(text || "").trimStart());
39937
39976
  }
39938
39977
  function hasBenignExitOutcome(text) {
39939
- return /^\[outcome:\s*(?:no-match|no-change)\]\s*$/im.test(String(text || ""));
39978
+ return /^\[outcome:\s*(?:no-match|no-change|conflicts)\]\s*$/im.test(String(text || ""));
39940
39979
  }
39941
39980
  var ENVELOPE_TAG_HEAD_RE = /^<(?:task-notification|task-id|tool-use-id|output-file|status)[\s>]/i;
39942
39981
  function toolResultEnvelopeStatus(text) {
@@ -40108,10 +40147,10 @@ function splitPathAndDelta(value, explicitDelta = "") {
40108
40147
  let path2 = String(value ?? "").trim();
40109
40148
  let delta = String(explicitDelta ?? "").trim();
40110
40149
  if (!delta) {
40111
- const sep = path2.lastIndexOf(" \u2014 ");
40112
- if (sep !== -1) {
40113
- delta = path2.slice(sep + 3).trim();
40114
- path2 = path2.slice(0, sep).trim();
40150
+ const sep2 = path2.lastIndexOf(" \u2014 ");
40151
+ if (sep2 !== -1) {
40152
+ delta = path2.slice(sep2 + 3).trim();
40153
+ path2 = path2.slice(0, sep2).trim();
40115
40154
  }
40116
40155
  }
40117
40156
  return { path: path2, delta };
@@ -40480,8 +40519,20 @@ function summarizeAgentResult({ text, trimmed, translate }) {
40480
40519
  return null;
40481
40520
  }
40482
40521
  var summarizeGeneric = ({ text, translate }) => summarizeGenericResult(text, translate);
40483
- var summarizeAskUserResult = ({ text }) => {
40484
- const answers = /^User has answered your questions:\s*(.*?)(?:\s*You can now continue with these answers in mind\.)?$/s.exec(String(text ?? "").trim());
40522
+ var summarizeAskUserResult = ({ text, translate }) => {
40523
+ const replied = /^User replied in chat: ("(?:[^"\\]|\\.)*")\. /s.exec(String(text ?? "").trim());
40524
+ if (replied) {
40525
+ let reply = "";
40526
+ try {
40527
+ reply = String(JSON.parse(replied[1]));
40528
+ } catch {
40529
+ }
40530
+ const label = translate("Answered in chat", "Answered in chat", {});
40531
+ return truncateSingleLine(reply ? `${label}: ${reply}` : label, AGENT_SURFACE_BRIEF_MAX);
40532
+ }
40533
+ const answers = /^User has answered your questions:\s*(.*?)(?:\s*You can now continue with these answers in mind\.)?$/s.exec(
40534
+ String(text ?? "").trim()
40535
+ );
40485
40536
  return truncateSingleLine(answers ? answers[1] : String(text ?? "").trim(), AGENT_SURFACE_BRIEF_MAX) || null;
40486
40537
  };
40487
40538
  var TOOL_RESULT_SUMMARIZERS = new Map(
@@ -40876,12 +40927,18 @@ function officeUnit(a) {
40876
40927
  }
40877
40928
  function visualizeUnit(a) {
40878
40929
  const action = String(a.action || "").toLowerCase();
40879
- if (action === "capture") return unitDescriptor("Visualize", { count: 1, active: "Capturing", done: "Captured", noun: "screenshot" });
40880
- if (action === "export") return unitDescriptor("Visualize", { count: 1, active: "Exporting", done: "Exported", noun: "file" });
40881
- if (action === "annotate") return unitDescriptor("Visualize", { count: 1, active: "Marking", done: "Marked", noun: "annotation" });
40882
- if (action === "check") return unitDescriptor("Visualize", { count: 1, active: "Checking", done: "Checked", noun: "page" });
40883
- if (action === "inspect") return unitDescriptor("Visualize", { count: 1, active: "Inspecting", done: "Inspected", noun: "page" });
40884
- if (action === "close") return unitDescriptor("Visualize", { count: 1, active: "Closing", done: "Closed", noun: "tab" });
40930
+ if (action === "capture")
40931
+ return unitDescriptor("Visualize", { count: 1, active: "Capturing", done: "Captured", noun: "screenshot" });
40932
+ if (action === "export")
40933
+ return unitDescriptor("Visualize", { count: 1, active: "Exporting", done: "Exported", noun: "file" });
40934
+ if (action === "annotate")
40935
+ return unitDescriptor("Visualize", { count: 1, active: "Marking", done: "Marked", noun: "annotation" });
40936
+ if (action === "check")
40937
+ return unitDescriptor("Visualize", { count: 1, active: "Checking", done: "Checked", noun: "page" });
40938
+ if (action === "inspect")
40939
+ return unitDescriptor("Visualize", { count: 1, active: "Inspecting", done: "Inspected", noun: "page" });
40940
+ if (action === "close")
40941
+ return unitDescriptor("Visualize", { count: 1, active: "Closing", done: "Closed", noun: "tab" });
40885
40942
  return unitDescriptor("Visualize", { count: 1, active: "Showing", done: "Showed", noun: "artifact" });
40886
40943
  }
40887
40944
  function terminalUnit(a) {
@@ -41095,7 +41152,10 @@ function cwdUnit(a) {
41095
41152
  }
41096
41153
  if (action === "favorite" || action === "archive") {
41097
41154
  const off = a.value === false;
41098
- const [active, done] = action === "favorite" ? off ? ["Unfavoriting", "Unfavorited"] : ["Favoriting", "Favorited"] : off ? ["Unarchiving", "Unarchived"] : ["Archiving", "Archived"];
41155
+ let words;
41156
+ if (action === "favorite") words = off ? ["Unfavoriting", "Unfavorited"] : ["Favoriting", "Favorited"];
41157
+ else words = off ? ["Unarchiving", "Unarchived"] : ["Archiving", "Archived"];
41158
+ const [active, done] = words;
41099
41159
  return unitDescriptor("Setup", { active, done, noun: "session", effect: true });
41100
41160
  }
41101
41161
  if (action.endsWith("-worktree") || action.endsWith("-worktrees")) {
@@ -41109,7 +41169,12 @@ function cwdUnit(a) {
41109
41169
  if (action === "status") {
41110
41170
  return unitDescriptor("Setup", { active: "Checking", done: "Checked", noun: "session" });
41111
41171
  }
41112
- return unitDescriptor("Setup", { active: "Checking", done: "Checked", noun: "working directory", pluralNoun: "working directories" });
41172
+ return unitDescriptor("Setup", {
41173
+ active: "Checking",
41174
+ done: "Checked",
41175
+ noun: "working directory",
41176
+ pluralNoun: "working directories"
41177
+ });
41113
41178
  }
41114
41179
  var TOOL_UNITS = /* @__PURE__ */ new Map([
41115
41180
  [
@@ -41589,7 +41654,8 @@ function summarizeGithub(a, max) {
41589
41654
  const id = a.number ?? a.id;
41590
41655
  const hasId = id != null && String(id).trim() !== "";
41591
41656
  const title = truncateToolText(firstText(a.title, a.workflow, a.tag), Math.min(max, 60));
41592
- return hasId ? compactParts([`${phrase} ${String(id).trim()}`, repo, title]) : compactParts([repo ? `${phrase} ${repo}` : phrase, title]);
41657
+ if (hasId) return compactParts([`${phrase} ${String(id).trim()}`, repo, title]);
41658
+ return compactParts([repo ? `${phrase} ${repo}` : phrase, title]);
41593
41659
  }
41594
41660
  function formatToolSurface(name, args, opts = {}) {
41595
41661
  const parsed = parseToolArgs(args);
@@ -42308,7 +42374,10 @@ var IN_FLIGHT_BUDGET_MAX_WAIT_MS = 6e4;
42308
42374
  function inFlightAdviceMs(err) {
42309
42375
  const advised = retryAfterMsFromError(err);
42310
42376
  if (advised != null) return advised;
42311
- for (const [name, unitMs] of [["retry-after-ms", 1], ["retry-after", 1e3]]) {
42377
+ for (const [name, unitMs] of [
42378
+ ["retry-after-ms", 1],
42379
+ ["retry-after", 1e3]
42380
+ ]) {
42312
42381
  const value = errorHeaderValue(err, name);
42313
42382
  const n = Number(value);
42314
42383
  if (value != null && String(value).trim() !== "" && Number.isFinite(n) && n >= 0) return n * unitMs;
@@ -42664,6 +42733,20 @@ function describeError(value) {
42664
42733
  };
42665
42734
  }
42666
42735
 
42736
+ // src/runtime/shared/provider-timeout-phase.mjs
42737
+ var TIMEOUT_PHASE = Object.freeze({
42738
+ // The response headers did not arrive in the first-byte window.
42739
+ HEADERS: "headers",
42740
+ // The headers arrived, the first chunk did not.
42741
+ FIRST_CHUNK: "first-chunk",
42742
+ // A stream that already produced output went silent.
42743
+ IDLE: "idle"
42744
+ });
42745
+ function isFirstByteTimeout(err) {
42746
+ const phase = err?.timeoutPhase;
42747
+ return phase === TIMEOUT_PHASE.HEADERS || phase === TIMEOUT_PHASE.FIRST_CHUNK;
42748
+ }
42749
+
42667
42750
  // src/runtime/shared/err-text.mjs
42668
42751
  function errorHttpStatus(err) {
42669
42752
  return Number(err?.httpStatus || err?.status || err?.response?.status || 0) || 0;
@@ -42821,6 +42904,25 @@ function hasTypedEvidence(error) {
42821
42904
  if (!error || typeof error !== "object") return false;
42822
42905
  return Boolean(error.errorKind?.kind) || errorHttpStatus(error) > 0 || Boolean(error.code) || Boolean(error.retryAfterMs);
42823
42906
  }
42907
+ var timedOutMs = (text) => Number(/timed out after (\d+)ms/i.exec(text)?.[1]) || 0;
42908
+ function stillThinkingText(error, text) {
42909
+ const ms = Number(error.waitedMs) || timedOutMs(text);
42910
+ const provider = typeof error.providerLabel === "string" && error.providerLabel ? error.providerLabel : "the provider";
42911
+ const attempts = Number(error.attempts) > 0 ? `; attempts: ${Math.floor(Number(error.attempts))}` : "";
42912
+ return `Model still thinking: no output in ${formatDurationMs(ms)}; ${provider} sent nothing yet${attempts}.`;
42913
+ }
42914
+ function typedStreamFailureText(error, text) {
42915
+ if (!error || typeof error !== "object") return null;
42916
+ if (isFirstByteTimeout(error)) return stillThinkingText(error, text);
42917
+ if (error.timeoutPhase === TIMEOUT_PHASE.IDLE) {
42918
+ const ms = timedOutMs(text);
42919
+ return ms > 0 ? `No progress ${formatDurationMs(ms)}.` : "No progress.";
42920
+ }
42921
+ if (error.code === "TRUNCATED_STREAM" && error.streamCorruption !== true) {
42922
+ return "Connection to the provider was lost (TRUNCATED_STREAM).";
42923
+ }
42924
+ return null;
42925
+ }
42824
42926
  function presentErrorText(error, options = {}) {
42825
42927
  const presentation = describeError(error);
42826
42928
  if (["image-size", "payload-size", "request"].includes(presentation.kind)) return presentation.summary;
@@ -42844,6 +42946,8 @@ function presentErrorText(error, options = {}) {
42844
42946
  if (embeddedError) text = embeddedError;
42845
42947
  text = oneLine(stripErrorPrefix(text));
42846
42948
  if (!text) return "Unknown error";
42949
+ const streamFailure = typedStreamFailureText(error, text);
42950
+ if (streamFailure) return streamFailure;
42847
42951
  if (code === "PROVIDER_PREFIX_MUTATION" || name === "ProviderPrefixMutationError") {
42848
42952
  return "Session state changed unexpectedly.";
42849
42953
  }
@@ -42883,7 +42987,7 @@ function presentErrorText(error, options = {}) {
42883
42987
  }
42884
42988
  const firstTransport = /first (?:transport|semantic response) stale\s*\((\d+)ms\)/i.exec(text);
42885
42989
  if (firstTransport) {
42886
- return `No first response ${formatDurationMs(firstTransport[1])}.`;
42990
+ return `Agent watchdog stopped the run: no model response in ${formatDurationMs(firstTransport[1])}.`;
42887
42991
  }
42888
42992
  const firstResponse = /(?:agent\s+)?first response stale\s*\((\d+)ms\)/i.exec(text);
42889
42993
  if (firstResponse) {
@@ -42918,7 +43022,7 @@ function backgroundTaskFailureStatusLabel(status, error, options = {}) {
42918
43022
  const watchdog = watchdogMsFromRawError(raw);
42919
43023
  let head = "Failed";
42920
43024
  if (/^(cancelled|canceled)$/i.test(statusNorm)) head = "Cancelled";
42921
- else if (/^timeout$/i.test(statusNorm) || watchdog?.kind === "timeout" || /first response stale/i.test(raw) || /no first response from/i.test(presented))
43025
+ else if (/^timeout$/i.test(statusNorm) || watchdog?.kind === "timeout" || /first response stale/i.test(raw) || /no first response from/i.test(presented) || /^(?:Model still thinking|Agent watchdog stopped the run):/.test(presented))
42922
43026
  head = "Timeout";
42923
43027
  else if (watchdog?.kind === "stale" || /(?:agent )?(?:task|tool running) stale|went stale without/i.test(raw) || /went stale after/i.test(presented))
42924
43028
  head = "Stale";
@@ -43811,7 +43915,8 @@ function headerLabel(base, surface, display, status, detail) {
43811
43915
  if (display.isBackgroundMetadataResult) return backgroundTaskActionTitle(normalizedName, display.backgroundMeta);
43812
43916
  if (isShellSurface) return shellHeader(status.shellStatus, groupCount, parsedArgs?.verifyShell === true);
43813
43917
  const described = normalizedName === "load_tool" && !headerPending ? bridgeDescribedToolNames(display.displayedResultText) : null;
43814
- if (described) return described.length ? `Described ${described.map(displayToolSearchTarget).join(", ")}` : "Described";
43918
+ if (described)
43919
+ return described.length ? `Described ${described.map(displayToolSearchTarget).join(", ")}` : "Described";
43815
43920
  return (isAgentTool(normalizedName) ? agentActionTitle(parsedArgs, display.displayedResultText) : "") || formatToolActionHeader(name, args, {
43816
43921
  pending: headerPending,
43817
43922
  count: groupCount,
@@ -45869,8 +45974,8 @@ var notifyRenderFrame = (seq) => {
45869
45974
  for (const ack of acks) ack(seq);
45870
45975
  };
45871
45976
  var yieldToRenderer = ({ frames = 1 } = {}) => {
45872
- if (!hasRenderFrameSource()) return new Promise((resolve4) => setImmediate(resolve4));
45873
- return new Promise((resolve4) => {
45977
+ if (!hasRenderFrameSource()) return new Promise((resolve6) => setImmediate(resolve6));
45978
+ return new Promise((resolve6) => {
45874
45979
  const minSeq = renderAckSeq;
45875
45980
  let remainingFrames = Math.max(1, Math.floor(Number(frames) || 1));
45876
45981
  let settled = false;
@@ -45885,7 +45990,7 @@ var yieldToRenderer = ({ frames = 1 } = {}) => {
45885
45990
  releaseClosedListener();
45886
45991
  const idx = pendingRenderAcks.indexOf(onFrame);
45887
45992
  if (idx !== -1) pendingRenderAcks.splice(idx, 1);
45888
- resolve4();
45993
+ resolve6();
45889
45994
  };
45890
45995
  releaseClosedListener = onRenderFrameSourcesClosed(finish);
45891
45996
  const onTimeout = () => {
@@ -46685,13 +46790,13 @@ function nativeClipboardCommand(text) {
46685
46790
  function copyToClipboard(text) {
46686
46791
  const value = String(text ?? "");
46687
46792
  const wroteOsc52 = writeOsc52Clipboard(value);
46688
- return new Promise((resolve4, reject) => {
46793
+ return new Promise((resolve6, reject) => {
46689
46794
  const { cmd, args, input } = nativeClipboardCommand(value);
46690
46795
  let child;
46691
46796
  try {
46692
46797
  child = spawn2(cmd, args, { stdio: ["pipe", "ignore", "ignore"], windowsHide: true });
46693
46798
  } catch (e) {
46694
- if (wroteOsc52) resolve4();
46799
+ if (wroteOsc52) resolve6();
46695
46800
  else reject(clipboardHelperError(cmd, e));
46696
46801
  return;
46697
46802
  }
@@ -46700,7 +46805,7 @@ function copyToClipboard(text) {
46700
46805
  });
46701
46806
  if (!wroteOsc52) {
46702
46807
  child.on("close", (code) => {
46703
- if (code === 0) resolve4();
46808
+ if (code === 0) resolve6();
46704
46809
  else reject(new Error(`${cmd} exited with code ${code}`));
46705
46810
  });
46706
46811
  }
@@ -46709,7 +46814,7 @@ function copyToClipboard(text) {
46709
46814
  child.stdin.end(input);
46710
46815
  if (wroteOsc52) {
46711
46816
  child.unref?.();
46712
- resolve4();
46817
+ resolve6();
46713
46818
  }
46714
46819
  });
46715
46820
  }
@@ -47013,7 +47118,7 @@ function mimeForPath(path2) {
47013
47118
  return IMAGE_MIME[extname(String(path2 || "")).toLowerCase()] || null;
47014
47119
  }
47015
47120
  function execFileBuffer(cmd, args, options = {}) {
47016
- return new Promise((resolve4) => {
47121
+ return new Promise((resolve6) => {
47017
47122
  execFile(
47018
47123
  cmd,
47019
47124
  args,
@@ -47025,7 +47130,7 @@ function execFileBuffer(cmd, args, options = {}) {
47025
47130
  ...options
47026
47131
  },
47027
47132
  (error, stdout2, stderr) => {
47028
- resolve4({ ok: !error, code: error?.code ?? 0, stdout: stdout2, stderr, error });
47133
+ resolve6({ ok: !error, code: error?.code ?? 0, stdout: stdout2, stderr, error });
47029
47134
  }
47030
47135
  );
47031
47136
  });
@@ -47518,7 +47623,10 @@ var SPINNER_MODE_OVERRIDE_VERBS = {
47518
47623
  compacting: "Compacting conversation",
47519
47624
  "auto-clear": "Auto-clearing conversation",
47520
47625
  resuming: "Resuming conversation",
47521
- "task-wait": "\uC791\uC5C5 \uB300\uAE30 \uC911"
47626
+ "task-wait": "\uC791\uC5C5 \uB300\uAE30 \uC911",
47627
+ // The request is sent and its response headers are pending: the model is
47628
+ // queued or thinking server-side.
47629
+ "model-thinking": "Model thinking"
47522
47630
  };
47523
47631
  function spinnerVerbFor(startedAt = 0, now = 0, pool = SPINNER_VERBS) {
47524
47632
  const list = Array.isArray(pool) && pool.length ? pool : SPINNER_VERBS;
@@ -48418,7 +48526,7 @@ function completeOAuthCode(ctx, target, commandText) {
48418
48526
  }
48419
48527
  oauthSubmitRef.current = true;
48420
48528
  setProviderPrompt((prompt) => prompt === target ? { ...prompt, submitting: true } : prompt);
48421
- const completion = typeof target.login?.completeCode === "function" ? new Promise((resolve4) => resolve4(target.login.completeCode(commandText))) : Promise.reject(new Error("OAuth login is no longer active"));
48529
+ const completion = typeof target.login?.completeCode === "function" ? new Promise((resolve6) => resolve6(target.login.completeCode(commandText))) : Promise.reject(new Error("OAuth login is no longer active"));
48422
48530
  void completion.then(() => {
48423
48531
  const successReturn = target.successReturn;
48424
48532
  const afterSave = target.afterSave;
@@ -49738,6 +49846,44 @@ function useSharedTick(intervalMs, isActive = true, onTick2 = null) {
49738
49846
  }, [intervalMs, isActive]);
49739
49847
  }
49740
49848
 
49849
+ // src/runtime/shared/quiet-progress.mjs
49850
+ var QUIET_PROGRESS_CUE_MS = 12e4;
49851
+ var MODEL_THINKING_STAGE = "model_thinking";
49852
+ var WAIT_BY_STAGE = {
49853
+ connecting: "provider",
49854
+ requesting: "provider",
49855
+ [MODEL_THINKING_STAGE]: "thinking",
49856
+ streaming: "model",
49857
+ tool_running: "tool",
49858
+ resource_wait: "slot",
49859
+ cancelling: "cancel"
49860
+ };
49861
+ function quietProgressParts(quiet, now, warnMs = 0) {
49862
+ const since = Number(quiet?.since) || 0;
49863
+ if (!since) return null;
49864
+ const quietMs = Math.max(0, now - since);
49865
+ if (quietMs < QUIET_PROGRESS_CUE_MS) return null;
49866
+ return {
49867
+ quietMs,
49868
+ minutes: Math.floor(quietMs / 6e4),
49869
+ wait: String(quiet.wait || ""),
49870
+ tool: typeof quiet.tool === "string" ? quiet.tool : "",
49871
+ escalated: Number(warnMs) > 0 && quietMs >= Number(warnMs)
49872
+ };
49873
+ }
49874
+ var WAIT_TEXT = {
49875
+ provider: "waiting on provider",
49876
+ thinking: "model thinking",
49877
+ model: "waiting on model",
49878
+ slot: "waiting for a slot",
49879
+ cancel: "stopping"
49880
+ };
49881
+ function quietProgressLabel(parts) {
49882
+ if (!parts) return "";
49883
+ const wait = parts.wait === "tool" ? `running ${parts.tool || "a tool"}` : WAIT_TEXT[parts.wait] || "";
49884
+ return [`quiet for ${parts.minutes}m`, wait].filter(Boolean).join(" \xB7 ");
49885
+ }
49886
+
49741
49887
  // src/tui/spinner-meta.mjs
49742
49888
  var compactNumberFormatter = new Intl.NumberFormat("en-US", {
49743
49889
  notation: "compact",
@@ -49773,9 +49919,13 @@ function buildSpinnerMeta({
49773
49919
  thinkingSince = 0,
49774
49920
  thinkingMs = 0,
49775
49921
  effort = "",
49922
+ // The turn's published quiet state (`spinner.quiet`) and the clock it is read at.
49923
+ quiet = null,
49924
+ now = Date.now(),
49776
49925
  verbose: _verbose = false
49777
49926
  } = {}) {
49778
49927
  const tokens = Math.max(0, Number(outputTokens) || 0);
49928
+ const quietParts = quietProgressParts(quiet, now, quiet?.warnMs);
49779
49929
  const thinkingParts = spinnerThinkingParts({ thinking, thinkingSince, thinkingMs, effort });
49780
49930
  const thinkingText = spinnerThinkingLabel({ thinking, thinkingSince, thinkingMs, effort });
49781
49931
  return {
@@ -49788,7 +49938,11 @@ function buildSpinnerMeta({
49788
49938
  // mid-turn for no reason the reader could see; now both arrive together.
49789
49939
  showTokens: tokens > 0,
49790
49940
  thinkingText,
49791
- thinkingActive: Boolean(thinking || Number(thinkingSince) > 0)
49941
+ thinkingActive: Boolean(thinking || Number(thinkingSince) > 0),
49942
+ // Quiet-time cue: structured for the desktop's i18n, English for the TUI;
49943
+ // `escalated` once the silence reaches the stall watchdog's warn point.
49944
+ quietParts,
49945
+ quietText: quietProgressLabel(quietParts)
49792
49946
  };
49793
49947
  }
49794
49948
  function isReducedMotion(env4) {
@@ -49803,6 +49957,7 @@ var INTERRUPT_HINT = "esc to interrupt";
49803
49957
  var THINKING_DELAY_MS = 3e3;
49804
49958
  var GLIMMER_SPEED_MS = {
49805
49959
  requesting: 70,
49960
+ "model-thinking": 70,
49806
49961
  reconnecting: 70,
49807
49962
  compacting: 120,
49808
49963
  "auto-clear": 120,
@@ -49846,7 +50001,9 @@ function tokenModeGlyph(mode) {
49846
50001
  case "responding":
49847
50002
  case "thinking":
49848
50003
  return DOWN_ARROW;
50004
+ // The request is sent and nothing has come back yet.
49849
50005
  case "requesting":
50006
+ case "model-thinking":
49850
50007
  return UP_ARROW;
49851
50008
  default:
49852
50009
  return "";
@@ -49862,6 +50019,8 @@ function SpinnerByline({
49862
50019
  thinkingActiveSince,
49863
50020
  thinkingMs,
49864
50021
  effort,
50022
+ quiet = null,
50023
+ now = Date.now(),
49865
50024
  interruptible,
49866
50025
  columns,
49867
50026
  reducedMotion,
@@ -49895,7 +50054,9 @@ function SpinnerByline({
49895
50054
  thinking,
49896
50055
  thinkingSince: thinkingActiveSince,
49897
50056
  thinkingMs,
49898
- effort
50057
+ effort,
50058
+ quiet,
50059
+ now
49899
50060
  });
49900
50061
  const tokenGlyph = tokenModeGlyph(mode);
49901
50062
  let tokenText = "";
@@ -49914,8 +50075,11 @@ function SpinnerByline({
49914
50075
  const interruptW = interruptText.length;
49915
50076
  const showInterrupt = Boolean(interruptText) && avail > interruptW;
49916
50077
  const usedAfterInterrupt = showInterrupt ? interruptW + SEP_WIDTH : 0;
49917
- const showThinkingStatus = Boolean(thinkingStatusText) && avail > usedAfterInterrupt + thinkingStatusW;
49918
- const usedAfterThinking = usedAfterInterrupt + (showThinkingStatus ? thinkingStatusW + SEP_WIDTH : 0);
50078
+ const quietText = meta.quietText;
50079
+ const showQuiet = Boolean(quietText) && avail > usedAfterInterrupt + quietText.length;
50080
+ const usedAfterQuiet = usedAfterInterrupt + (showQuiet ? quietText.length + SEP_WIDTH : 0);
50081
+ const showThinkingStatus = Boolean(thinkingStatusText) && avail > usedAfterQuiet + thinkingStatusW;
50082
+ const usedAfterThinking = usedAfterQuiet + (showThinkingStatus ? thinkingStatusW + SEP_WIDTH : 0);
49919
50083
  const showTimer = Boolean(timerLabel) && avail > usedAfterThinking + timerW;
49920
50084
  const usedAfterTimer = usedAfterThinking + (showTimer ? timerW + SEP_WIDTH : 0);
49921
50085
  const showTokens = wantsTokens && tokenText && avail > usedAfterTimer + tokenW;
@@ -49946,6 +50110,11 @@ function SpinnerByline({
49946
50110
  ) }, "thinking-status") : /* @__PURE__ */ jsx2(Text, { color: theme.statusSubtle, children: thinkingStatusText }, "thinking-status")
49947
50111
  );
49948
50112
  }
50113
+ if (showQuiet) {
50114
+ segments.push(
50115
+ /* @__PURE__ */ jsx2(Text, { color: meta.quietParts?.escalated ? theme.warning : theme.statusSubtle, children: quietText }, "quiet")
50116
+ );
50117
+ }
49949
50118
  if (showInterrupt) {
49950
50119
  segments.push(
49951
50120
  /* @__PURE__ */ jsx2(Text, { color: theme.statusSubtle, children: interruptText }, "interrupt")
@@ -50083,6 +50252,8 @@ function Spinner({
50083
50252
  thinkingActiveSince = 0,
50084
50253
  thinkingMs = 0,
50085
50254
  effort = "",
50255
+ // The turn's quiet state (`spinner.quiet`), shown as the quiet-time cue.
50256
+ quiet = null,
50086
50257
  hasActiveTools = false,
50087
50258
  paused = false,
50088
50259
  interruptible = false,
@@ -50125,6 +50296,8 @@ function Spinner({
50125
50296
  thinkingActiveSince,
50126
50297
  thinkingMs,
50127
50298
  effort,
50299
+ quiet,
50300
+ now,
50128
50301
  interruptible,
50129
50302
  columns,
50130
50303
  reducedMotion,
@@ -50322,7 +50495,7 @@ function normalizeStatuslineAnsi(text, colors, { reset = RESET2 } = {}) {
50322
50495
  // src/runtime/shared/statusline/statusline-segments.mjs
50323
50496
  import { readdir, readFile, stat } from "node:fs/promises";
50324
50497
  import { homedir as homedir2 } from "node:os";
50325
- import { join as join9 } from "node:path";
50498
+ import { join as join10 } from "node:path";
50326
50499
 
50327
50500
  // src/runtime/shared/llm/model-catalog.mjs
50328
50501
  import { existsSync as existsSync8, readFileSync as readFileSync8 } from "node:fs";
@@ -50361,6 +50534,7 @@ var ANTIGRAVITY_MODELS = Object.freeze([
50361
50534
  low: "gemini-3.1-pro-low",
50362
50535
  high: "gemini-3.1-pro-high"
50363
50536
  }),
50537
+ fallbackModel("gemini-4-argon", "Gemini 4 Argon", "gemini-pro", 1048576, "gemini-4-argon", ["low", "medium", "high"]),
50364
50538
  fallbackModel("claude-opus-4-6-thinking", "Claude Opus 4.6 (Thinking)", null, 25e4, "claude-opus-4-6-thinking", [
50365
50539
  "low",
50366
50540
  "medium",
@@ -50914,9 +51088,17 @@ function isPidAlive(value) {
50914
51088
  }
50915
51089
  }
50916
51090
 
51091
+ // src/runtime/shared/worktrees/git-head.mjs
51092
+ import { readFileSync as readFileSync9, statSync as statSync2, watch } from "node:fs";
51093
+ import { dirname as dirname8, resolve as resolve4 } from "node:path";
51094
+
51095
+ // src/runtime/shared/worktrees/paths.mjs
51096
+ import { existsSync as existsSync9, realpathSync as realpathSync2 } from "node:fs";
51097
+ import { dirname as dirname7, isAbsolute as isAbsolute2, join as join9, relative, resolve as resolve3, sep } from "node:path";
51098
+
50917
51099
  // src/runtime/shared/statusline/statusline-segments.mjs
50918
- var DEFAULT_MIXDOG_HOME = process.env.MIXDOG_HOME || join9(homedir2(), ".mixdog");
50919
- var DEFAULT_STANDALONE_DATA_DIR = join9(DEFAULT_MIXDOG_HOME, "data");
51100
+ var DEFAULT_MIXDOG_HOME = process.env.MIXDOG_HOME || join10(homedir2(), ".mixdog");
51101
+ var DEFAULT_STANDALONE_DATA_DIR = join10(DEFAULT_MIXDOG_HOME, "data");
50920
51102
  var SHELL_JOBS_SEGMENT_CACHE_MS = 1e3;
50921
51103
  var FINISHED_SHELL_JOB_TTL_MS = 30 * 60 * 1e3;
50922
51104
  var EMPTY_SHELL_JOBS_SESSION = Object.freeze({
@@ -50963,6 +51145,10 @@ function shellJobsStatus({ clientHostPid, sessionId } = {}) {
50963
51145
  if (!scoped) return sessions === own.sessions ? own : { ...own, sessions };
50964
51146
  return scope && sessions?.[scope] || EMPTY_SHELL_JOBS_SESSION;
50965
51147
  }
51148
+ function unconfirmedShellCount(status) {
51149
+ const jobs = Array.isArray(status?.jobs) ? status.jobs : [];
51150
+ return jobs.filter((job) => job?.terminationUnconfirmed === true).length;
51151
+ }
50966
51152
  function freshestShellJobsSessions() {
50967
51153
  let freshest = null;
50968
51154
  for (const entry of _shellJobsSegmentCache.values()) {
@@ -50973,7 +51159,7 @@ function freshestShellJobsSessions() {
50973
51159
  async function refreshShellJobsStatus(ownerPid) {
50974
51160
  let value = EMPTY_SHELL_JOBS;
50975
51161
  try {
50976
- const dir = join9(dataDir(), "shell-jobs");
51162
+ const dir = join10(dataDir(), "shell-jobs");
50977
51163
  let names;
50978
51164
  try {
50979
51165
  names = await readdir(dir);
@@ -50985,17 +51171,19 @@ async function refreshShellJobsStatus(ownerPid) {
50985
51171
  let count = 0;
50986
51172
  let oldestMs = Infinity;
50987
51173
  const jobs = [];
51174
+ const orphaned = [];
50988
51175
  const bySession = /* @__PURE__ */ new Map();
50989
51176
  for (const id of ids) {
50990
- const p = join9(dir, `${id}.json`);
51177
+ const p = join10(dir, `${id}.json`);
50991
51178
  let detail;
50992
51179
  try {
50993
51180
  detail = JSON.parse(await readFile(p, "utf-8"));
50994
51181
  } catch {
50995
51182
  continue;
50996
51183
  }
50997
- if (!await isShellJobAlive(detail, p, dir, id)) continue;
50998
- if (detail?.foreground === true) continue;
51184
+ const unconfirmed = detail?.terminationUnconfirmed === true;
51185
+ if (unconfirmed ? !isPidAlive(ownerByJob.get(id) || 0) : !await isShellJobAlive(detail, p, dir, id)) continue;
51186
+ if (detail?.foreground === true && !unconfirmed) continue;
50999
51187
  const ownedByThisHost = ownerByJob.get(id) === ownerPid;
51000
51188
  if (ownedByThisHost) count++;
51001
51189
  let jobMs = Infinity;
@@ -51010,9 +51198,11 @@ async function refreshShellJobsStatus(ownerPid) {
51010
51198
  taskId: id,
51011
51199
  command: String(detail?.command || "").trim(),
51012
51200
  cwd: String(detail?.cwd || "").trim(),
51013
- startedAt: detail?.startedAt || (Number.isFinite(jobMs) ? jobMs : null)
51201
+ startedAt: detail?.startedAt || (Number.isFinite(jobMs) ? jobMs : null),
51202
+ ...unconfirmed ? { terminationUnconfirmed: true } : {}
51014
51203
  };
51015
51204
  if (ownedByThisHost) jobs.push(job);
51205
+ if (unconfirmed && detail?.ownerSessionClosed === true) orphaned.push(job);
51016
51206
  if (!owner) continue;
51017
51207
  const bucket = bySession.get(owner) || { count: 0, oldestMs: Infinity, jobs: [], finished: [] };
51018
51208
  bucket.count += 1;
@@ -51024,7 +51214,7 @@ async function refreshShellJobsStatus(ownerPid) {
51024
51214
  for (const id of doneIds) {
51025
51215
  let detail;
51026
51216
  try {
51027
- detail = JSON.parse(await readFile(join9(dir, `${id}.json`), "utf-8"));
51217
+ detail = JSON.parse(await readFile(join10(dir, `${id}.json`), "utf-8"));
51028
51218
  } catch {
51029
51219
  continue;
51030
51220
  }
@@ -51046,6 +51236,7 @@ async function refreshShellJobsStatus(ownerPid) {
51046
51236
  bySession.set(owner, bucket);
51047
51237
  }
51048
51238
  if (count || bySession.size) value = summarizeShellJobs({ count, oldestMs, jobs, bySession });
51239
+ if (orphaned.length) value = { ...value, orphaned };
51049
51240
  } catch {
51050
51241
  value = EMPTY_SHELL_JOBS;
51051
51242
  }
@@ -51086,7 +51277,7 @@ async function isShellJobAlive(detail, detailPath, dir, id) {
51086
51277
  try {
51087
51278
  const st = await stat(detailPath);
51088
51279
  const timeoutMs = Number(detail?.timeoutMs);
51089
- const enforced = detail?.timeoutEnforced === true || await stat(join9(dir, `${id}.enforced`)).then(
51280
+ const enforced = detail?.timeoutEnforced === true || await stat(join10(dir, `${id}.enforced`)).then(
51090
51281
  () => true,
51091
51282
  () => false
51092
51283
  );
@@ -51270,11 +51461,17 @@ function localStatusLineL2({ agentWorkers = [], agentJobs = [], activeTools = nu
51270
51461
  }
51271
51462
  const shellScope = String(sessionId ?? "").trim();
51272
51463
  const shellStatus = shellScope ? shellJobsStatus({ clientHostPid, sessionId: shellScope }) : shellJobsStatus({ clientHostPid });
51273
- const shellCount = Number(shellStatus?.count) || 0;
51464
+ const unconfirmed = unconfirmedShellCount(shellStatus);
51465
+ const shellCount = (Number(shellStatus?.count) || 0) - unconfirmed;
51274
51466
  if (shellCount > 0) {
51275
51467
  const label = `Running ${shellCount} Shell${shellCount === 1 ? "" : "s"}`;
51276
51468
  l2Parts.push(`${spin} ${STATUS}${label}${RESET3}${elapsedSuffix(shellStatus.elapsedLabel || "")}`);
51277
51469
  }
51470
+ if (unconfirmed > 0) {
51471
+ const { WARNING } = statusColors();
51472
+ const label = `\u26A0 ${unconfirmed} Shell${unconfirmed === 1 ? "" : "s"} termination unconfirmed`;
51473
+ l2Parts.push(`${WARNING}${label}${RESET3} ${SUBTLE}\xB7${RESET3} /shells`);
51474
+ }
51278
51475
  const tools = activeTools && typeof activeTools === "object" ? activeTools : {};
51279
51476
  const searchInfo = tools.web_search || null;
51280
51477
  if (searchInfo && num(searchInfo.count) > 0) {
@@ -55442,7 +55639,7 @@ function renderToolApproval({ toolApproval, store, frameColumns, expandedOptionP
55442
55639
  toolApproval.id
55443
55640
  );
55444
55641
  }
55445
- const resolve4 = (approved) => {
55642
+ const resolve6 = (approved) => {
55446
55643
  store.resolveToolApproval?.(toolApproval.id, {
55447
55644
  approved,
55448
55645
  reason: approved ? "approved by user" : "denied by user"
@@ -55467,12 +55664,12 @@ function renderToolApproval({ toolApproval, store, frameColumns, expandedOptionP
55467
55664
  description: "run this tool call"
55468
55665
  }
55469
55666
  ],
55470
- onSelect: (value) => resolve4(value === "approve"),
55471
- onCancel: () => resolve4(false),
55667
+ onSelect: (value) => resolve6(value === "approve"),
55668
+ onCancel: () => resolve6(false),
55472
55669
  onKey: (input) => {
55473
55670
  const value = String(input || "").trim().toLowerCase();
55474
- if (value === "a" || value === "y") resolve4(true);
55475
- else if (value === "d" || value === "n") resolve4(false);
55671
+ if (value === "a" || value === "y") resolve6(true);
55672
+ else if (value === "d" || value === "n") resolve6(false);
55476
55673
  },
55477
55674
  title: "Tool approval",
55478
55675
  description: toolApprovalDescription(toolApproval),
@@ -56646,6 +56843,7 @@ function renderAppView(ctx) {
56646
56843
  thinkingActiveSince: liveSpinner?.thinkingSegmentStartedAt ?? 0,
56647
56844
  thinkingMs: liveSpinner?.thinkingAccumulatedMs ?? 0,
56648
56845
  effort: state.effort || "",
56846
+ quiet: liveSpinner?.quiet ?? null,
56649
56847
  hasActiveTools: !!activeTools?.web_search?.count,
56650
56848
  paused: !!toolApproval,
56651
56849
  interruptible: !!(state.busy && state.spinner?.active),
@@ -56729,7 +56927,7 @@ function renderAppView(ctx) {
56729
56927
  StatusLine,
56730
56928
  {
56731
56929
  sessionId: state.sessionId,
56732
- clientHostPid: state.ownerClientHostPid || state.clientHostPid,
56930
+ clientHostPid: state.clientHostPid,
56733
56931
  provider: state.provider,
56734
56932
  model: state.model,
56735
56933
  effort: state.effort,
@@ -59356,7 +59554,7 @@ function createOnboardingSteps({
59356
59554
  import { spawn as spawn3 } from "node:child_process";
59357
59555
 
59358
59556
  // src/runtime/shared/wsl.mjs
59359
- import { readFileSync as readFileSync9 } from "node:fs";
59557
+ import { readFileSync as readFileSync10 } from "node:fs";
59360
59558
  var _isWSL;
59361
59559
  function isWSL() {
59362
59560
  if (_isWSL !== void 0) return _isWSL;
@@ -59369,7 +59567,7 @@ function isWSL() {
59369
59567
  return _isWSL;
59370
59568
  }
59371
59569
  try {
59372
- const v = readFileSync9("/proc/version", "utf8").toLowerCase();
59570
+ const v = readFileSync10("/proc/version", "utf8").toLowerCase();
59373
59571
  _isWSL = v.includes("microsoft") || v.includes("wsl");
59374
59572
  } catch {
59375
59573
  _isWSL = false;
@@ -59476,6 +59674,20 @@ function buildProviderItems(setup) {
59476
59674
  _authenticated: p.authenticated
59477
59675
  });
59478
59676
  }
59677
+ if (setup.managedByClient === true) {
59678
+ for (const p of setup.local || []) {
59679
+ providerItems.push({
59680
+ value: `local:${p.id}`,
59681
+ label: p.name,
59682
+ meta: providerStatusLabel(p),
59683
+ description: "",
59684
+ _type: "local",
59685
+ _providerId: p.id,
59686
+ _providerName: p.name,
59687
+ _provider: p
59688
+ });
59689
+ }
59690
+ }
59479
59691
  providerItems.sort((a, b) => {
59480
59692
  const rank = providerItemRank(a) - providerItemRank(b);
59481
59693
  if (rank !== 0) return rank;
@@ -59801,8 +60013,8 @@ function createProviderSetupPicker({
59801
60013
  }
59802
60014
  });
59803
60015
  try {
59804
- await new Promise((resolve4) => setTimeout(resolve4, 0));
59805
- return await store.getProviderSetup();
60016
+ await new Promise((resolve6) => setTimeout(resolve6, 0));
60017
+ return await store.getProviderSetup(options.forceRefresh ? { force: true } : void 0);
59806
60018
  } catch (e) {
59807
60019
  store.pushNotice(`providers failed: ${e?.message || e}`, "error");
59808
60020
  return null;
@@ -59833,6 +60045,9 @@ function createProviderSetupPicker({
59833
60045
  });
59834
60046
  }
59835
60047
  items.push(...buildProviderItems(setup));
60048
+ if (setup.managedByClient === true) {
60049
+ items.push({ value: "refresh-client-providers", label: "Refresh", _type: "refresh-client-providers" });
60050
+ }
59836
60051
  const flow = {
59837
60052
  store,
59838
60053
  setProviderPrompt,
@@ -59858,10 +60073,10 @@ function createProviderSetupPicker({
59858
60073
  };
59859
60074
  flow.paint({
59860
60075
  title: options.title || "Providers",
59861
- description: options.description || "Choose a provider. Enter opens provider actions.",
60076
+ description: setup.managedByClient === true ? "Manage provider sign-ins and accounts in the local desktop window. Refresh to update availability." : options.description || "Choose a provider. Enter opens provider actions.",
59862
60077
  footer: providerFooter,
59863
60078
  footerGapRows: 1,
59864
- help: options.confirmBar ? void 0 : "\u2191/\u2193 Select \xB7 Enter Open \xB7 Esc Back",
60079
+ help: options.confirmBar ? void 0 : setup.managedByClient === true ? "\u2191/\u2193 Select \xB7 Enter Refresh \xB7 Esc Back" : "\u2191/\u2193 Select \xB7 Enter Open \xB7 Esc Back",
59865
60080
  indexMode: "always",
59866
60081
  labelWidth: 18,
59867
60082
  metaWidth: 12,
@@ -59873,6 +60088,12 @@ function createProviderSetupPicker({
59873
60088
  if (item?._providerId) flow.rememberProviderSelection(item);
59874
60089
  },
59875
60090
  onSelect: (_value, item) => {
60091
+ if (setup.managedByClient === true && item._type !== "continue") {
60092
+ if (item._type === "refresh-client-providers") {
60093
+ void openProviderSetupPicker({ ...options, preloadedSetup: null, forceRefresh: true });
60094
+ }
60095
+ return;
60096
+ }
59876
60097
  flow.releaseSurface();
59877
60098
  if (item._type === "continue") {
59878
60099
  onContinue?.();
@@ -59914,7 +60135,7 @@ function createModelCatalog({ store, providerModelsCacheRef, webSearchModelsCach
59914
60135
  let renderedQuickModels = false;
59915
60136
  if (!providerModels.length || options.refreshModels === true) {
59916
60137
  paintLoading();
59917
- await new Promise((resolve4) => setTimeout(resolve4, 0));
60138
+ await new Promise((resolve6) => setTimeout(resolve6, 0));
59918
60139
  try {
59919
60140
  if (options.refreshModels !== true && options.cacheRef !== "webSearch") {
59920
60141
  refreshModelsPromise = Promise.resolve(loadModels({ force: false }));
@@ -60915,8 +61136,8 @@ function createSettingsNavigation({ openers, openSettingsPicker, setSettingsProm
60915
61136
  }
60916
61137
 
60917
61138
  // src/runtime/shared/config.mjs
60918
- import { readFileSync as readFileSync11, statSync as statSync3, mkdirSync as mkdirSync5, existsSync as existsSync10, watch as fsWatch } from "node:fs";
60919
- import { join as join11, dirname as dirname8 } from "node:path";
61139
+ import { readFileSync as readFileSync12, statSync as statSync4, mkdirSync as mkdirSync5, existsSync as existsSync11, watch as fsWatch } from "node:fs";
61140
+ import { join as join12, dirname as dirname10 } from "node:path";
60920
61141
  import { createRequire as createRequire3 } from "node:module";
60921
61142
 
60922
61143
  // src/runtime/shared/object.mjs
@@ -60933,12 +61154,12 @@ init_atomic_file();
60933
61154
  // src/runtime/shared/user-data-guard.mjs
60934
61155
  import {
60935
61156
  copyFileSync,
60936
- existsSync as existsSync9,
61157
+ existsSync as existsSync10,
60937
61158
  mkdirSync as mkdirSync4,
60938
61159
  readdirSync as readdirSync2,
60939
- readFileSync as readFileSync10,
61160
+ readFileSync as readFileSync11,
60940
61161
  rmSync,
60941
- statSync as statSync2,
61162
+ statSync as statSync3,
60942
61163
  writeFileSync as writeFileSync4
60943
61164
  } from "node:fs";
60944
61165
  import {
@@ -60948,11 +61169,11 @@ import {
60948
61169
  rm as rmP,
60949
61170
  stat as statP
60950
61171
  } from "node:fs/promises";
60951
- import { basename as basename5, dirname as dirname7, join as join10, resolve as resolve3 } from "node:path";
61172
+ import { basename as basename5, dirname as dirname9, join as join11, resolve as resolve5 } from "node:path";
60952
61173
  import { homedir as homedir3 } from "node:os";
60953
61174
  import { createHash as createHash4, randomUUID } from "node:crypto";
60954
61175
  function getBackupRoot() {
60955
- return process.env.MIXDOG_USER_DATA_BACKUP_ROOT || join10(process.env.MIXDOG_HOME || process.env.MIXDOG_CONFIG_DIR || mixdogHome(), "backups", "user-data");
61176
+ return process.env.MIXDOG_USER_DATA_BACKUP_ROOT || join11(process.env.MIXDOG_HOME || process.env.MIXDOG_CONFIG_DIR || mixdogHome(), "backups", "user-data");
60956
61177
  }
60957
61178
  var USER_DATA_FILES = ["mixdog-config.json"];
60958
61179
  var USER_DATA_DIRS = ["schedules", "webhooks", "workflows"];
@@ -60960,12 +61181,12 @@ var BACKUP_MANIFEST = "backup.json";
60960
61181
  var INIT_MARKER = ".mixdog-user-data.json";
60961
61182
  var SCOPE_PREFIX = "scope-";
60962
61183
  function normalizeDataDir(dataDir2) {
60963
- const full = resolve3(String(dataDir2));
61184
+ const full = resolve5(String(dataDir2));
60964
61185
  return process.platform === "win32" ? full.toLowerCase() : full;
60965
61186
  }
60966
61187
  function scopeDirFor(dataDir2) {
60967
61188
  const id = createHash4("sha256").update(normalizeDataDir(dataDir2)).digest("hex").slice(0, 16);
60968
- return join10(getBackupRoot(), `${SCOPE_PREFIX}${id}`);
61189
+ return join11(getBackupRoot(), `${SCOPE_PREFIX}${id}`);
60969
61190
  }
60970
61191
  function stamp() {
60971
61192
  return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
@@ -60976,7 +61197,7 @@ function safeReason(reason) {
60976
61197
  function readInitInstanceId(dataDir2) {
60977
61198
  if (!dataDir2) return null;
60978
61199
  try {
60979
- const marker = JSON.parse(readFileSync10(join10(dataDir2, INIT_MARKER), "utf8"));
61200
+ const marker = JSON.parse(readFileSync11(join11(dataDir2, INIT_MARKER), "utf8"));
60980
61201
  return typeof marker?.instanceId === "string" && marker.instanceId ? marker.instanceId : null;
60981
61202
  } catch {
60982
61203
  return null;
@@ -60986,13 +61207,13 @@ function hasUserDataInitMarker(dataDir2) {
60986
61207
  return readInitInstanceId(dataDir2) != null;
60987
61208
  }
60988
61209
  function legacyBackupRoots() {
60989
- const legacy = process.env.MIXDOG_USER_DATA_BACKUP_ROOT || join10(process.env.MIXDOG_CONFIG_DIR || join10(homedir3(), ".mixdog"), "backups", "user-data");
61210
+ const legacy = process.env.MIXDOG_USER_DATA_BACKUP_ROOT || join11(process.env.MIXDOG_CONFIG_DIR || join11(homedir3(), ".mixdog"), "backups", "user-data");
60990
61211
  const current = getBackupRoot();
60991
61212
  return normalizeDataDir(legacy) === normalizeDataDir(current) ? [current] : [current, legacy];
60992
61213
  }
60993
61214
  function manifestDataDirMatches(backupDir, dataDirKey) {
60994
61215
  try {
60995
- const manifest = JSON.parse(readFileSync10(join10(backupDir, BACKUP_MANIFEST), "utf8"));
61216
+ const manifest = JSON.parse(readFileSync11(join11(backupDir, BACKUP_MANIFEST), "utf8"));
60996
61217
  return typeof manifest?.dataDir === "string" && normalizeDataDir(manifest.dataDir) === dataDirKey;
60997
61218
  } catch {
60998
61219
  return false;
@@ -61000,7 +61221,7 @@ function manifestDataDirMatches(backupDir, dataDirKey) {
61000
61221
  }
61001
61222
  function legacyMarkersFor(root, dataDir2, dataDirKey) {
61002
61223
  const hashed = new Set(
61003
- [String(dataDir2), resolve3(String(dataDir2))].map(
61224
+ [String(dataDir2), resolve5(String(dataDir2))].map(
61004
61225
  (value) => `.initialized-${createHash4("sha256").update(value).digest("hex").slice(0, 16)}.json`
61005
61226
  )
61006
61227
  );
@@ -61013,12 +61234,12 @@ function legacyMarkersFor(root, dataDir2, dataDirKey) {
61013
61234
  return names.filter((name) => {
61014
61235
  if (hashed.has(name)) return true;
61015
61236
  try {
61016
- const marker = JSON.parse(readFileSync10(join10(root, name), "utf8"));
61237
+ const marker = JSON.parse(readFileSync11(join11(root, name), "utf8"));
61017
61238
  return typeof marker?.dataDir === "string" && normalizeDataDir(marker.dataDir) === dataDirKey;
61018
61239
  } catch {
61019
61240
  return false;
61020
61241
  }
61021
- }).map((name) => join10(root, name));
61242
+ }).map((name) => join11(root, name));
61022
61243
  }
61023
61244
  function findLegacyUserDataEvidence(dataDir2, { fresh = false } = {}) {
61024
61245
  if (!dataDir2 || hasUserDataInitMarker(dataDir2)) return null;
@@ -61039,7 +61260,7 @@ function scanLegacyUserDataEvidence(dataDir2, key) {
61039
61260
  markers.push(...legacyMarkersFor(root, dataDir2, key));
61040
61261
  for (const name of backupDirsNewestFirst(root)) {
61041
61262
  if (name.startsWith(SCOPE_PREFIX)) continue;
61042
- if (manifestDataDirMatches(join10(root, name), key)) backups.push(join10(root, name));
61263
+ if (manifestDataDirMatches(join11(root, name), key)) backups.push(join11(root, name));
61043
61264
  }
61044
61265
  }
61045
61266
  backups.sort((x, y) => basename5(y).localeCompare(basename5(x)));
@@ -61063,10 +61284,10 @@ function backupDirsNewestFirst(dir) {
61063
61284
  }
61064
61285
  function readRestorableConfig(backupDir, dataDirKey, instanceId) {
61065
61286
  try {
61066
- const manifest = JSON.parse(readFileSync10(join10(backupDir, BACKUP_MANIFEST), "utf8"));
61287
+ const manifest = JSON.parse(readFileSync11(join11(backupDir, BACKUP_MANIFEST), "utf8"));
61067
61288
  if (typeof manifest?.dataDir !== "string" || normalizeDataDir(manifest.dataDir) !== dataDirKey) return null;
61068
61289
  if (manifest.instanceId !== instanceId) return null;
61069
- const parsed = JSON.parse(readFileSync10(join10(backupDir, "mixdog-config.json"), "utf8"));
61290
+ const parsed = JSON.parse(readFileSync11(join11(backupDir, "mixdog-config.json"), "utf8"));
61070
61291
  return isStructurallyCompleteMixdogConfigBackup(parsed) ? parsed : null;
61071
61292
  } catch {
61072
61293
  return null;
@@ -61076,13 +61297,13 @@ function findRestorableConfig(dataDir2, instanceId) {
61076
61297
  const key = normalizeDataDir(dataDir2);
61077
61298
  const scopeDir = scopeDirFor(dataDir2);
61078
61299
  for (const name of backupDirsNewestFirst(scopeDir)) {
61079
- const parsed = readRestorableConfig(join10(scopeDir, name), key, instanceId);
61300
+ const parsed = readRestorableConfig(join11(scopeDir, name), key, instanceId);
61080
61301
  if (parsed) return parsed;
61081
61302
  }
61082
61303
  const root = getBackupRoot();
61083
61304
  for (const name of backupDirsNewestFirst(root)) {
61084
61305
  if (name.startsWith(SCOPE_PREFIX)) continue;
61085
- const parsed = readRestorableConfig(join10(root, name), key, instanceId);
61306
+ const parsed = readRestorableConfig(join11(root, name), key, instanceId);
61086
61307
  if (parsed) return parsed;
61087
61308
  }
61088
61309
  return null;
@@ -61104,7 +61325,7 @@ function loadLegacyMixdogConfigFromBackup(dataDir2, options) {
61104
61325
  const evidence = findLegacyUserDataEvidence(dataDir2, options);
61105
61326
  for (const backupDir of evidence?.backups || []) {
61106
61327
  try {
61107
- const parsed = JSON.parse(readFileSync10(join10(backupDir, "mixdog-config.json"), "utf8"));
61328
+ const parsed = JSON.parse(readFileSync11(join11(backupDir, "mixdog-config.json"), "utf8"));
61108
61329
  if (isStructurallyCompleteMixdogConfigBackup(parsed)) return parsed;
61109
61330
  } catch {
61110
61331
  }
@@ -61112,40 +61333,40 @@ function loadLegacyMixdogConfigFromBackup(dataDir2, options) {
61112
61333
  return null;
61113
61334
  }
61114
61335
  function copyTree(src, dst, copied) {
61115
- const st = statSync2(src);
61336
+ const st = statSync3(src);
61116
61337
  if (st.isDirectory()) {
61117
61338
  for (const name of readdirSync2(src)) {
61118
- copyTree(join10(src, name), join10(dst, name), copied);
61339
+ copyTree(join11(src, name), join11(dst, name), copied);
61119
61340
  }
61120
61341
  return;
61121
61342
  }
61122
61343
  if (!st.isFile()) return;
61123
- mkdirSync4(dirname7(dst), { recursive: true });
61344
+ mkdirSync4(dirname9(dst), { recursive: true });
61124
61345
  copyFileSync(src, dst);
61125
61346
  copied.push(dst);
61126
61347
  }
61127
61348
  function pruneBackups(scopeDir, keep = 40) {
61128
61349
  for (const name of backupDirsNewestFirst(scopeDir).slice(keep)) {
61129
61350
  try {
61130
- rmSync(join10(scopeDir, name), { recursive: true, force: true });
61351
+ rmSync(join11(scopeDir, name), { recursive: true, force: true });
61131
61352
  } catch {
61132
61353
  }
61133
61354
  }
61134
61355
  }
61135
61356
  function markUserDataInitialized(dataDir2) {
61136
61357
  const existing = readInitInstanceId(dataDir2);
61137
- if (existing || !dataDir2 || !existsSync9(dataDir2)) return existing;
61358
+ if (existing || !dataDir2 || !existsSync10(dataDir2)) return existing;
61138
61359
  try {
61139
61360
  writeFileSync4(
61140
- join10(dataDir2, INIT_MARKER),
61361
+ join11(dataDir2, INIT_MARKER),
61141
61362
  `${JSON.stringify(
61142
- { instanceId: randomUUID(), dataDir: resolve3(dataDir2), createdAt: (/* @__PURE__ */ new Date()).toISOString() },
61363
+ { instanceId: randomUUID(), dataDir: resolve5(dataDir2), createdAt: (/* @__PURE__ */ new Date()).toISOString() },
61143
61364
  null,
61144
61365
  2
61145
61366
  )}
61146
61367
  `,
61147
61368
  // An unreadable marker is replaced; a concurrent creator's valid one wins.
61148
- { encoding: "utf8", flag: existsSync9(join10(dataDir2, INIT_MARKER)) ? "w" : "wx" }
61369
+ { encoding: "utf8", flag: existsSync10(join11(dataDir2, INIT_MARKER)) ? "w" : "wx" }
61149
61370
  );
61150
61371
  } catch {
61151
61372
  }
@@ -61164,14 +61385,14 @@ function skipBackups() {
61164
61385
  }
61165
61386
  function backupTarget(dataDir2, reason) {
61166
61387
  const scopeDir = scopeDirFor(dataDir2);
61167
- return { scopeDir, backupDir: join10(scopeDir, `${stamp()}-${safeReason(reason)}`) };
61388
+ return { scopeDir, backupDir: join11(scopeDir, `${stamp()}-${safeReason(reason)}`) };
61168
61389
  }
61169
61390
  function finishBackup(dataDir2, backupDir, reason) {
61170
61391
  const instanceId = markUserDataInitialized(dataDir2);
61171
61392
  writeFileSync4(
61172
- join10(backupDir, BACKUP_MANIFEST),
61393
+ join11(backupDir, BACKUP_MANIFEST),
61173
61394
  `${JSON.stringify(
61174
- { dataDir: resolve3(dataDir2), instanceId, reason, createdAt: (/* @__PURE__ */ new Date()).toISOString() },
61395
+ { dataDir: resolve5(dataDir2), instanceId, reason, createdAt: (/* @__PURE__ */ new Date()).toISOString() },
61175
61396
  null,
61176
61397
  2
61177
61398
  )}
@@ -61183,16 +61404,16 @@ function finishBackup(dataDir2, backupDir, reason) {
61183
61404
  }
61184
61405
  function backupUserData(dataDir2, reason = "snapshot") {
61185
61406
  if (skipBackups()) return { dir: null, copied: [] };
61186
- if (!dataDir2 || !existsSync9(dataDir2)) return { dir: null, copied: [] };
61407
+ if (!dataDir2 || !existsSync10(dataDir2)) return { dir: null, copied: [] };
61187
61408
  const { scopeDir, backupDir } = backupTarget(dataDir2, reason);
61188
61409
  const copied = [];
61189
61410
  for (const rel of USER_DATA_FILES) {
61190
- const src = join10(dataDir2, rel);
61191
- if (existsSync9(src)) copyTree(src, join10(backupDir, rel), copied);
61411
+ const src = join11(dataDir2, rel);
61412
+ if (existsSync10(src)) copyTree(src, join11(backupDir, rel), copied);
61192
61413
  }
61193
61414
  for (const rel of USER_DATA_DIRS) {
61194
- const src = join10(dataDir2, rel);
61195
- if (existsSync9(src)) copyTree(src, join10(backupDir, rel), copied);
61415
+ const src = join11(dataDir2, rel);
61416
+ if (existsSync10(src)) copyTree(src, join11(backupDir, rel), copied);
61196
61417
  }
61197
61418
  if (copied.length > 0) {
61198
61419
  finishBackup(dataDir2, backupDir, reason);
@@ -61208,12 +61429,12 @@ async function copyTreeAsync(src, dst, copied) {
61208
61429
  const st = await statP(src);
61209
61430
  if (st.isDirectory()) {
61210
61431
  for (const name of await readdirP(src)) {
61211
- await copyTreeAsync(join10(src, name), join10(dst, name), copied);
61432
+ await copyTreeAsync(join11(src, name), join11(dst, name), copied);
61212
61433
  }
61213
61434
  return;
61214
61435
  }
61215
61436
  if (!st.isFile()) return;
61216
- await mkdirP(dirname7(dst), { recursive: true });
61437
+ await mkdirP(dirname9(dst), { recursive: true });
61217
61438
  await copyFileP(src, dst);
61218
61439
  copied.push(dst);
61219
61440
  }
@@ -61226,23 +61447,23 @@ async function pruneBackupsAsync(scopeDir, keep = 40) {
61226
61447
  }
61227
61448
  for (const name of entries.slice(keep)) {
61228
61449
  try {
61229
- await rmP(join10(scopeDir, name), { recursive: true, force: true });
61450
+ await rmP(join11(scopeDir, name), { recursive: true, force: true });
61230
61451
  } catch {
61231
61452
  }
61232
61453
  }
61233
61454
  }
61234
61455
  async function backupUserDataAsync(dataDir2, reason = "snapshot") {
61235
61456
  if (skipBackups()) return { dir: null, copied: [] };
61236
- if (!dataDir2 || !existsSync9(dataDir2)) return { dir: null, copied: [] };
61457
+ if (!dataDir2 || !existsSync10(dataDir2)) return { dir: null, copied: [] };
61237
61458
  const { scopeDir, backupDir } = backupTarget(dataDir2, reason);
61238
61459
  const copied = [];
61239
61460
  for (const rel of USER_DATA_FILES) {
61240
- const src = join10(dataDir2, rel);
61241
- if (existsSync9(src)) await copyTreeAsync(src, join10(backupDir, rel), copied);
61461
+ const src = join11(dataDir2, rel);
61462
+ if (existsSync10(src)) await copyTreeAsync(src, join11(backupDir, rel), copied);
61242
61463
  }
61243
61464
  for (const rel of USER_DATA_DIRS) {
61244
- const src = join10(dataDir2, rel);
61245
- if (existsSync9(src)) await copyTreeAsync(src, join10(backupDir, rel), copied);
61465
+ const src = join11(dataDir2, rel);
61466
+ if (existsSync10(src)) await copyTreeAsync(src, join11(backupDir, rel), copied);
61246
61467
  }
61247
61468
  if (copied.length > 0) {
61248
61469
  finishBackup(dataDir2, backupDir, reason);
@@ -61287,7 +61508,7 @@ var {
61287
61508
  onKeychainRecovered: _onKeychainRecovered
61288
61509
  } = _require("../../lib/keychain-cjs.cjs");
61289
61510
  function configPath() {
61290
- return join11(resolvePluginData(), "mixdog-config.json");
61511
+ return join12(resolvePluginData(), "mixdog-config.json");
61291
61512
  }
61292
61513
  var GENERATED_KEY = "_generated";
61293
61514
  var DEFAULTS_VERSION = 2;
@@ -61316,7 +61537,7 @@ function readConfigRawCached() {
61316
61537
  return _configReadCache.raw;
61317
61538
  }
61318
61539
  try {
61319
- const st2 = statSync3(configPath());
61540
+ const st2 = statSync4(configPath());
61320
61541
  if (st2.mtimeMs === _configReadCache.mtimeMs && st2.size === _configReadCache.size) {
61321
61542
  _configReadCache.atMs = now;
61322
61543
  return _configReadCache.raw;
@@ -61326,7 +61547,7 @@ function readConfigRawCached() {
61326
61547
  }
61327
61548
  let st = null;
61328
61549
  try {
61329
- st = statSync3(configPath());
61550
+ st = statSync4(configPath());
61330
61551
  } catch (err) {
61331
61552
  if (err.code === "ENOENT") {
61332
61553
  _configReadCache = null;
@@ -61338,7 +61559,7 @@ function readConfigRawCached() {
61338
61559
  }
61339
61560
  let raw;
61340
61561
  try {
61341
- raw = readFileSync11(configPath(), "utf8");
61562
+ raw = readFileSync12(configPath(), "utf8");
61342
61563
  } catch (err) {
61343
61564
  if (err.code === "ENOENT") {
61344
61565
  _configReadCache = null;
@@ -61413,7 +61634,7 @@ function readConfigFile() {
61413
61634
  }
61414
61635
  }
61415
61636
  function writeConfigFile(data, postBackupReason = "post-config-write") {
61416
- mkdirSync5(dirname8(configPath()), { recursive: true, mode: 448 });
61637
+ mkdirSync5(dirname10(configPath()), { recursive: true, mode: 448 });
61417
61638
  try {
61418
61639
  backupUserData(resolvePluginData(), "pre-config-write");
61419
61640
  } catch {
@@ -61437,7 +61658,7 @@ function persistRestoredConfig(restored) {
61437
61658
  const wrote = withFileLockSync(
61438
61659
  `${path2}.lock`,
61439
61660
  () => {
61440
- if (existsSync10(path2)) return false;
61661
+ if (existsSync11(path2)) return false;
61441
61662
  writeAll(restored, "post-restore");
61442
61663
  return true;
61443
61664
  },
@@ -61479,7 +61700,7 @@ function readAll() {
61479
61700
  function quarantineMalformedConfig(parseErr) {
61480
61701
  const corrupt = `${configPath()}.corrupt-${Date.now()}`;
61481
61702
  try {
61482
- if (existsSync10(configPath())) renameWithRetrySync(configPath(), corrupt);
61703
+ if (existsSync11(configPath())) renameWithRetrySync(configPath(), corrupt);
61483
61704
  } catch {
61484
61705
  }
61485
61706
  process.stderr.write(
@@ -61509,7 +61730,7 @@ function restoreAllForRmWOrThrow(reason) {
61509
61730
  function readAllForRmW() {
61510
61731
  let raw;
61511
61732
  try {
61512
- raw = readFileSync11(configPath(), "utf8");
61733
+ raw = readFileSync12(configPath(), "utf8");
61513
61734
  } catch (err) {
61514
61735
  if (err.code === "ENOENT") {
61515
61736
  if (isUserDataRecoveryExpected(resolvePluginData(), { fresh: true })) {
@@ -61556,7 +61777,7 @@ function readSection(section) {
61556
61777
  return stripGeneratedMarker(readAll()[section] ?? null) ?? {};
61557
61778
  }
61558
61779
  async function writeConfigFileAsync(data) {
61559
- mkdirSync5(dirname8(configPath()), { recursive: true, mode: 448 });
61780
+ mkdirSync5(dirname10(configPath()), { recursive: true, mode: 448 });
61560
61781
  try {
61561
61782
  await backupUserDataAsync(resolvePluginData(), "pre-config-write");
61562
61783
  } catch {
@@ -62550,6 +62771,44 @@ var sessionCommands = {
62550
62771
  }).catch((e) => store.pushNotice(`fork failed: ${e?.message || e}`, "error"));
62551
62772
  return true;
62552
62773
  },
62774
+ // /shells — this session's shells, each marked running or "termination
62775
+ // unconfirmed". `/shells release <id>` explains what releasing means and
62776
+ // asks for `--confirm`; only then is the workspace hold dropped.
62777
+ shells(ctx, arg) {
62778
+ const { store } = ctx;
62779
+ const [action, taskId, flag] = String(arg || "").trim().split(/\s+/).filter(Boolean);
62780
+ if (!action) {
62781
+ void Promise.resolve(store.listShellJobs?.()).then((result) => {
62782
+ const jobs = Array.isArray(result?.jobs) ? result.jobs : [];
62783
+ if (!jobs.length) {
62784
+ store.pushNotice("No shells are running.", "info");
62785
+ return;
62786
+ }
62787
+ const lines = jobs.map(
62788
+ (job) => `${job.taskId} ${job.terminationUnconfirmed ? "termination unconfirmed" : "running"} ${job.command}`
62789
+ );
62790
+ const held = jobs.some((job) => job.terminationUnconfirmed);
62791
+ if (held) lines.push("Release a held shell with /shells release <task_id>.");
62792
+ store.pushNotice(lines.join("\n"), held ? "warn" : "info");
62793
+ }).catch((error) => store.pushNotice(`Couldn\u2019t list shells: ${error?.message || error}`, "error"));
62794
+ return true;
62795
+ }
62796
+ if (action !== "release" || !taskId) {
62797
+ store.pushNotice("usage: /shells [release <task_id> [--confirm]]", "warn");
62798
+ return true;
62799
+ }
62800
+ if (flag !== "--confirm") {
62801
+ store.pushNotice(
62802
+ `Releasing ${taskId} unlocks its folder although its processes may still be running. To proceed, run /shells release ${taskId} --confirm`,
62803
+ "warn"
62804
+ );
62805
+ return true;
62806
+ }
62807
+ void Promise.resolve(store.releaseShellJob?.(taskId)).then(
62808
+ (result) => result?.released ? store.pushNotice(`Released ${taskId}.`, "info") : store.pushNotice(`Couldn\u2019t release ${taskId}: ${result?.error || "unavailable"}`, "warn")
62809
+ ).catch((error) => store.pushNotice(`Couldn\u2019t release ${taskId}: ${error?.message || error}`, "error"));
62810
+ return true;
62811
+ },
62553
62812
  doctor(ctx) {
62554
62813
  const { state, store, deps } = ctx;
62555
62814
  if (state.commandBusy) {
@@ -63023,8 +63282,8 @@ function usePromptQueueHistory({
63023
63282
  let timer2 = null;
63024
63283
  Promise.race([
63025
63284
  Promise.resolve(store.dispose?.("cli-react-exit", { detach: true })),
63026
- new Promise((resolve4) => {
63027
- timer2 = setTimeout(resolve4, 350);
63285
+ new Promise((resolve6) => {
63286
+ timer2 = setTimeout(resolve6, 350);
63028
63287
  })
63029
63288
  ]).finally(() => {
63030
63289
  if (timer2) clearTimeout(timer2);
@@ -63229,15 +63488,15 @@ function useTerminalChrome({ stdout: stdout2, isRawModeSupported, setResizeState
63229
63488
  import { useCallback as useCallback21, useEffect as useEffect27, useLayoutEffect as useLayoutEffect8 } from "react";
63230
63489
 
63231
63490
  // src/tui/session/transcript-spill.mjs
63232
- import { readFileSync as readFileSync15 } from "node:fs";
63233
- import { join as join15 } from "node:path";
63491
+ import { readFileSync as readFileSync16 } from "node:fs";
63492
+ import { join as join16 } from "node:path";
63234
63493
  import { Worker } from "node:worker_threads";
63235
63494
 
63236
63495
  // src/tui/session/transcript-spill/spill-dir.mjs
63237
63496
  import { randomUUID as randomUUID2 } from "node:crypto";
63238
- import { mkdtempSync, readdirSync as readdirSync5, readFileSync as readFileSync14, rmSync as rmSync5, statSync as statSync5, writeFileSync as writeFileSync6 } from "node:fs";
63497
+ import { mkdtempSync, readdirSync as readdirSync5, readFileSync as readFileSync15, rmSync as rmSync5, statSync as statSync6, writeFileSync as writeFileSync6 } from "node:fs";
63239
63498
  import { tmpdir as tmpdir2 } from "node:os";
63240
- import { join as join14 } from "node:path";
63499
+ import { join as join15 } from "node:path";
63241
63500
  var STALE_MS = 24 * 60 * 60 * 1e3;
63242
63501
  var PROCESS_NONCE = randomUUID2();
63243
63502
 
@@ -65611,8 +65870,8 @@ function waitWithTimeout(promise, ms) {
65611
65870
  let timer2 = null;
65612
65871
  return Promise.race([
65613
65872
  Promise.resolve(promise).then(() => true),
65614
- new Promise((resolve4) => {
65615
- timer2 = setTimeout(() => resolve4(false), ms);
65873
+ new Promise((resolve6) => {
65874
+ timer2 = setTimeout(() => resolve6(false), ms);
65616
65875
  })
65617
65876
  ]).finally(() => {
65618
65877
  if (timer2) clearTimeout(timer2);
@@ -65631,7 +65890,7 @@ function scheduleHardExit(code = 0) {
65631
65890
  timer2.unref?.();
65632
65891
  }
65633
65892
  function resolveTuiStderrLogPath() {
65634
- return process.env.MIXDOG_TUI_STDERR_LOG || join16(process.env.MIXDOG_RUNTIME_ROOT || join16(tmpdir3(), "mixdog"), "mixdog-tui.stderr.log");
65893
+ return process.env.MIXDOG_TUI_STDERR_LOG || join17(process.env.MIXDOG_RUNTIME_ROOT || join17(tmpdir3(), "mixdog"), "mixdog-tui.stderr.log");
65635
65894
  }
65636
65895
  function ansiFg(rgb2) {
65637
65896
  const m = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/.exec(String(rgb2 || ""));
@@ -65712,7 +65971,7 @@ function installTuiStderrGuard() {
65712
65971
  const originalWrite = process.stderr.write.bind(process.stderr);
65713
65972
  const logPath = resolveTuiStderrLogPath();
65714
65973
  try {
65715
- mkdirSync8(dirname10(logPath), { recursive: true });
65974
+ mkdirSync8(dirname12(logPath), { recursive: true });
65716
65975
  } catch {
65717
65976
  }
65718
65977
  (0, import_mixdog_debug.rotateBoundedLog)(logPath, import_mixdog_debug.PLUGIN_LOG_MAX_BYTES, import_mixdog_debug.PLUGIN_LOG_KEEP_BYTES);