mixdog 1.0.12 → 1.1.1

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 (356) hide show
  1. package/README.md +83 -182
  2. package/package.json +4 -2
  3. package/scripts/build-shipped-history.mjs +131 -0
  4. package/scripts/latest-guard.mjs +63 -0
  5. package/scripts/lib/run-node-tests.mjs +330 -32
  6. package/scripts/lib/test-failure-records.mjs +5 -0
  7. package/scripts/lib/test-failure-summary.mjs +14 -3
  8. package/scripts/lib/test-spawn-ledger.mjs +19 -0
  9. package/scripts/merge-mac-update-feed.mjs +107 -0
  10. package/scripts/mobile-release.mjs +210 -0
  11. package/scripts/post-release-check.mjs +353 -0
  12. package/scripts/prune-embedding-runtime.mjs +9 -5
  13. package/scripts/publish-asset-release.mjs +43 -0
  14. package/scripts/release-guard.mjs +63 -0
  15. package/scripts/test-direct.mjs +16 -1
  16. package/scripts/test.mjs +29 -7
  17. package/src/agents/advisor/AGENT.md +38 -0
  18. package/src/agents/advisor/agent.json +6 -0
  19. package/src/agents/reviewer/AGENT.md +5 -2
  20. package/src/agents/reviewer/agent.json +1 -1
  21. package/src/defaults/shipped-history.json +383 -0
  22. package/src/defaults/skills/computer-use/SKILL.md +1 -1
  23. package/src/defaults/skills/goal-management/SKILL.md +11 -5
  24. package/src/defaults/skills/setup/SKILL.md +5 -8
  25. package/src/defaults/skills/setup/references/actions.md +62 -31
  26. package/src/defaults/skills/setup/references/surfaces.md +12 -10
  27. package/src/lib/keychain-cjs.cjs +582 -17
  28. package/src/lib/rules-builder.cjs +1 -1
  29. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +3 -1
  30. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +4 -0
  31. package/src/runtime/agent/orchestrator/config-presets.d.mts +1 -0
  32. package/src/runtime/agent/orchestrator/config-presets.mjs +44 -0
  33. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +9 -1
  34. package/src/runtime/agent/orchestrator/config-storage.mjs +32 -4
  35. package/src/runtime/agent/orchestrator/config.mjs +120 -21
  36. package/src/runtime/agent/orchestrator/context/instruction-files.mjs +130 -0
  37. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +4 -0
  38. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +77 -26
  39. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +44 -14
  40. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +2 -1
  41. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +11 -2
  42. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +2 -0
  43. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +3 -3
  44. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +388 -0
  45. package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +92 -109
  46. package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +107 -0
  47. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +51 -9
  48. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +2 -1
  49. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +11 -0
  50. package/src/runtime/agent/orchestrator/providers/lib/open-login-url.mjs +9 -0
  51. package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +254 -0
  52. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +218 -0
  53. package/src/runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs +239 -0
  54. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +233 -0
  55. package/src/runtime/agent/orchestrator/providers/muse-code-oauth-login.mjs +247 -0
  56. package/src/runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs +225 -0
  57. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +542 -0
  58. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +25 -0
  59. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +18 -10
  60. package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +13 -0
  61. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +51 -11
  62. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +6 -1
  63. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +7 -5
  64. package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +12 -0
  65. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +37 -9
  66. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +12 -2
  67. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +6 -1
  68. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs +99 -0
  69. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +4 -8
  70. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +3 -7
  71. package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +8 -0
  72. package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +70 -0
  73. package/src/runtime/agent/orchestrator/providers/registry.mjs +42 -3
  74. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +19 -35
  75. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +7 -0
  76. package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +0 -17
  77. package/src/runtime/agent/orchestrator/runtime-core/goal-state.mjs +0 -3
  78. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +0 -1
  79. package/src/runtime/agent/orchestrator/runtime-core/goal-text.mjs +1 -1
  80. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-defs.mjs +16 -2
  81. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -2
  82. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +18 -4
  83. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +7 -1
  84. package/src/runtime/agent/orchestrator/runtime-core/session-route-policy.mjs +16 -0
  85. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +2 -0
  86. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +2 -2
  87. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +7 -7
  88. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +6 -0
  89. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +11 -1
  90. package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +28 -3
  91. package/src/runtime/agent/orchestrator/session/loop/tool-call-ids.mjs +90 -0
  92. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +19 -11
  93. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +1 -0
  94. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +24 -11
  95. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +2 -6
  96. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +28 -0
  97. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +63 -3
  98. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +8 -0
  99. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
  100. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +4 -4
  101. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +3 -0
  102. package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +2 -0
  103. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +3 -0
  104. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +23 -0
  105. package/src/runtime/agent/orchestrator/session/turn-effort.mjs +18 -0
  106. package/src/runtime/agent/orchestrator/stall-policy.mjs +0 -1
  107. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +11 -8
  108. package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +27 -12
  109. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +245 -0
  110. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +13 -1
  111. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +3 -1
  112. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
  113. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +49 -0
  114. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +3 -3
  115. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +9 -7
  116. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +19 -20
  117. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +67 -19
  118. package/src/runtime/agent/orchestrator/tools/builtin/file-version-test-helpers.mjs +11 -0
  119. package/src/runtime/agent/orchestrator/tools/builtin/file-version.mjs +13 -0
  120. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +28 -3
  121. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-single-file-rescue.mjs +8 -5
  122. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +25 -12
  123. package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +73 -1
  124. package/src/runtime/agent/orchestrator/tools/builtin/raw-content-publication.mjs +17 -0
  125. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +136 -76
  126. package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +2 -2
  127. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +15 -17
  128. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +4 -2
  129. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +11 -10
  130. package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +5 -3
  131. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +30 -16
  132. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +3 -1
  133. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +17 -6
  134. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +23 -5
  135. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +93 -43
  136. package/src/runtime/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +4 -11
  137. package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +7 -3
  138. package/src/runtime/agent/orchestrator/tools/builtin/snapshot-validation.mjs +16 -19
  139. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +32 -6
  140. package/src/runtime/agent/orchestrator/tools/builtin.mjs +9 -2
  141. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +3 -1
  142. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  143. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +12 -15
  144. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background.mjs +6 -3
  145. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +14 -4
  146. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +4 -2
  147. package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +58 -8
  148. package/src/runtime/agent/orchestrator/tools/patch/content-guard.mjs +47 -0
  149. package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +155 -0
  150. package/src/runtime/agent/orchestrator/tools/patch/dispatch/native-proofs.mjs +6 -2
  151. package/src/runtime/agent/orchestrator/tools/patch/dispatch/native-snapshots.mjs +6 -2
  152. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +19 -16
  153. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +13 -44
  154. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +2 -2
  155. package/src/runtime/agent/orchestrator/tools/patch/post-patch-excerpts.mjs +5 -2
  156. package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +47 -7
  157. package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +72 -8
  158. package/src/runtime/agent/orchestrator/tools/patch/section-coalesce.mjs +3 -2
  159. package/src/runtime/agent/orchestrator/tools/patch/sequence/run.mjs +9 -1
  160. package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +9 -1
  161. package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +6 -6
  162. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +16 -4
  163. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +35 -14
  164. package/src/runtime/agent/orchestrator/tools/patch/wave.mjs +42 -4
  165. package/src/runtime/agent/orchestrator/tools/shell-codepage.mjs +296 -0
  166. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +124 -81
  167. package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +75 -24
  168. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +19 -4
  169. package/src/runtime/channels/lib/config.mjs +3 -8
  170. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +7 -3
  171. package/src/{tui → runtime/channels}/lib/voice-setup.mjs +38 -22
  172. package/src/runtime/channels/lib/webhook/request-handler.mjs +42 -8
  173. package/src/runtime/computer-bridge/actions.mjs +2 -0
  174. package/src/runtime/computer-bridge/client.mjs +25 -1
  175. package/src/runtime/computer-bridge/linux-action-capabilities.mjs +84 -0
  176. package/src/runtime/computer-bridge/linux-readiness.d.mts +52 -0
  177. package/src/runtime/computer-bridge/linux-readiness.mjs +411 -0
  178. package/src/runtime/computer-bridge/test-linux-display.mjs +5 -0
  179. package/src/runtime/effort-judge/compact-tokenizer.mjs +13 -8
  180. package/src/runtime/effort-judge/judge-client.mjs +12 -3
  181. package/src/runtime/effort-judge/judge-input.mjs +5 -2
  182. package/src/runtime/effort-judge/model-install.mjs +9 -3
  183. package/src/runtime/effort-judge/model-manifest.json +8 -8
  184. package/src/runtime/effort-judge/previous-human-request.mjs +162 -0
  185. package/src/runtime/effort-judge/verified-context-input.mjs +10 -0
  186. package/src/runtime/memory/lib/embedding-provider.mjs +12 -0
  187. package/src/runtime/memory/lib/embedding-worker.mjs +9 -3
  188. package/src/runtime/memory/lib/http-router/session-routes.mjs +2 -1
  189. package/src/runtime/memory/lib/memory-config-flags.mjs +3 -2
  190. package/src/runtime/memory/lib/memory-embed.mjs +5 -0
  191. package/src/runtime/memory/lib/pg/supervisor.mjs +3 -0
  192. package/src/runtime/shared/agent-route-config.mjs +50 -2
  193. package/src/runtime/shared/bounded-file-read.mjs +166 -0
  194. package/src/runtime/shared/builtin-grandfathering.mjs +37 -0
  195. package/src/runtime/shared/config.mjs +74 -6
  196. package/src/runtime/shared/defaults-separation.mjs +263 -0
  197. package/src/runtime/shared/developer-options.mjs +7 -0
  198. package/src/runtime/shared/instruction-files-mode.mjs +9 -0
  199. package/src/runtime/shared/llm/anthropic-effort.mjs +4 -0
  200. package/src/runtime/shared/llm/model-catalog.mjs +25 -1
  201. package/src/runtime/shared/llm/openai-daybreak.mjs +79 -0
  202. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +105 -1
  203. package/src/runtime/shared/llm/usage-ledger-worker.mjs +2 -1
  204. package/src/runtime/shared/llm/usage-ledger.mjs +72 -5
  205. package/src/runtime/shared/onnx-runtime-support.mjs +6 -0
  206. package/src/runtime/shared/orchestration.mjs +14 -6
  207. package/src/runtime/shared/pristine-execution-contract.json +9 -0
  208. package/src/runtime/shared/pristine-execution.mjs +1 -1
  209. package/src/runtime/shared/projects.mjs +65 -48
  210. package/src/runtime/shared/provider-accounts.mjs +49 -6
  211. package/src/runtime/shared/quota-resume-store.mjs +255 -0
  212. package/src/runtime/shared/resource-admission.mjs +10 -3
  213. package/src/runtime/shared/schedule-model-ref.mjs +11 -0
  214. package/src/runtime/shared/session-approval-wait.mjs +35 -0
  215. package/src/runtime/shared/shell-display.mjs +4 -2
  216. package/src/runtime/shared/shipped-definitions.mjs +275 -0
  217. package/src/runtime/shared/tool-card-model.golden.json +3 -3
  218. package/src/runtime/shared/tool-result-summary.mjs +86 -15
  219. package/src/runtime/shared/transcript-metadata.mjs +2 -0
  220. package/src/runtime/shared/turn-review-reply.mjs +2 -0
  221. package/src/runtime/shared/turn-snapshot.mjs +65 -6
  222. package/src/runtime/shared/turn-worktree-snapshot.mjs +208 -27
  223. package/src/session-runtime/boot/apis.mjs +24 -0
  224. package/src/session-runtime/boot/config.mjs +4 -0
  225. package/src/session-runtime/boot/facade.mjs +4 -1
  226. package/src/session-runtime/boot/infrastructure.mjs +21 -2
  227. package/src/session-runtime/boot/session.mjs +3 -0
  228. package/src/session-runtime/channel-config-api.mjs +5 -0
  229. package/src/session-runtime/config-lifecycle/config-writers.mjs +3 -0
  230. package/src/session-runtime/config-lifecycle.mjs +31 -6
  231. package/src/session-runtime/goal-facade-api.mjs +4 -0
  232. package/src/session-runtime/lifecycle/inheritance.mjs +28 -6
  233. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +3 -0
  234. package/src/session-runtime/lifecycle/session-switch/resume.mjs +7 -1
  235. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +6 -0
  236. package/src/session-runtime/lifecycle/teardown/session-close.mjs +14 -2
  237. package/src/session-runtime/media-api.mjs +32 -22
  238. package/src/session-runtime/model-recency.mjs +17 -0
  239. package/src/session-runtime/model-route/route-tuning.mjs +3 -5
  240. package/src/session-runtime/model-route/set-route.mjs +49 -21
  241. package/src/session-runtime/model-route-api.mjs +2 -1
  242. package/src/session-runtime/notification-bus.mjs +31 -6
  243. package/src/session-runtime/provider-auth/login.mjs +16 -10
  244. package/src/session-runtime/provider-auth/setup.mjs +22 -2
  245. package/src/session-runtime/provider-models/catalog-load.mjs +3 -1
  246. package/src/session-runtime/provider-models/row-hydration.mjs +26 -17
  247. package/src/session-runtime/provider-readiness.mjs +4 -0
  248. package/src/session-runtime/quick-model-rows/model-meta.mjs +26 -0
  249. package/src/session-runtime/quick-model-rows/provider-rows.mjs +40 -14
  250. package/src/session-runtime/resource-api.mjs +8 -1
  251. package/src/session-runtime/runtime-core.mjs +4 -0
  252. package/src/session-runtime/runtime-facade.mjs +25 -1
  253. package/src/session-runtime/runtime-review-api.mjs +12 -1
  254. package/src/session-runtime/schedule-session-run.mjs +3 -1
  255. package/src/session-runtime/services/agent-tool/helpers.mjs +4 -0
  256. package/src/session-runtime/services/agent-tool/index-write-queue.mjs +63 -27
  257. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +15 -3
  258. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +2 -0
  259. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +11 -3
  260. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +2 -0
  261. package/src/session-runtime/services/agent-tool/worker-index/approval-wait.mjs +97 -0
  262. package/src/session-runtime/services/agent-tool/worker-index/mutation-batch.mjs +4 -2
  263. package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -2
  264. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +3 -0
  265. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +58 -2
  266. package/src/session-runtime/services/agent-tool/worker-index.mjs +69 -15
  267. package/src/session-runtime/services/agent-tool/worker-rows.mjs +2 -0
  268. package/src/session-runtime/services/channel-admin.mjs +91 -15
  269. package/src/session-runtime/services/provider-admin.mjs +336 -80
  270. package/src/session-runtime/services/seeds.mjs +80 -152
  271. package/src/session-runtime/services/usage-dashboard-model.mjs +35 -0
  272. package/src/session-runtime/services/usage-dashboard.mjs +7 -0
  273. package/src/session-runtime/session-address.mjs +125 -0
  274. package/src/session-runtime/session-create.mjs +57 -2
  275. package/src/session-runtime/settings-builtin-tools-api.mjs +23 -0
  276. package/src/session-runtime/settings-compaction-api.mjs +13 -0
  277. package/src/session-runtime/setup-tool/executor.mjs +97 -40
  278. package/src/session-runtime/setup-tool/extended-actions.mjs +64 -5
  279. package/src/session-runtime/setup-tool/settings-contract.mjs +44 -1
  280. package/src/session-runtime/setup-tool/tool-defs.mjs +20 -7
  281. package/src/session-runtime/tool-policy-refresh.mjs +3 -0
  282. package/src/session-runtime/tool-surface.mjs +16 -9
  283. package/src/session-runtime/turn/session-ops.mjs +3 -0
  284. package/src/session-runtime/turn/share-ops.mjs +4 -1
  285. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +6 -0
  286. package/src/session-runtime/usage-stats-api.mjs +15 -0
  287. package/src/session-runtime/webhook-session-run.mjs +3 -1
  288. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +31 -5
  289. package/src/session-runtime/workflow-agents-api/agent-route.mjs +4 -0
  290. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +27 -7
  291. package/src/standalone/daemon-boot-coordinator.mjs +10 -0
  292. package/src/standalone/daemon-drain-policy.mjs +9 -0
  293. package/src/standalone/daemon-stored-session-views.mjs +7 -8
  294. package/src/standalone/daemon.mjs +21 -5
  295. package/src/standalone/local-session-runtime.mjs +11 -0
  296. package/src/standalone/session-client.mjs +52 -7
  297. package/src/standalone/session-protocol.mjs +9 -0
  298. package/src/standalone/session-service/agent-tree/agent-child.mjs +2 -0
  299. package/src/standalone/session-service/entries/lifecycle.mjs +2 -0
  300. package/src/standalone/session-service/entries/session-loads.mjs +9 -0
  301. package/src/standalone/session-service/projection/revisions.mjs +28 -4
  302. package/src/standalone/session-service/projection.mjs +1 -0
  303. package/src/standalone/session-service/quota-resume.mjs +140 -0
  304. package/src/standalone/session-service/session-calls/session-action.mjs +2 -2
  305. package/src/standalone/session-service/session-calls.mjs +10 -2
  306. package/src/standalone/session-service/stored-reader.mjs +26 -1
  307. package/src/standalone/session-service.mjs +21 -0
  308. package/src/standalone/session-transport/routes.mjs +2 -0
  309. package/src/tui/app/doctor.mjs +7 -11
  310. package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +3 -5
  311. package/src/tui/app/model-options.mjs +13 -1
  312. package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +10 -4
  313. package/src/tui/app/provider-setup/oauth-actions.mjs +5 -0
  314. package/src/tui/app/settings-picker/settings-rows.mjs +4 -6
  315. package/src/tui/app/settings-picker/settings-toggles/store-toggles.mjs +1 -1
  316. package/src/tui/app/slash-dispatch/route-commands.mjs +3 -2
  317. package/src/tui/components/ContextPanel.jsx +5 -1
  318. package/src/tui/components/Spinner.jsx +34 -319
  319. package/src/tui/components/SpinnerByline.jsx +256 -0
  320. package/src/tui/components/use-spinner-progress.mjs +113 -0
  321. package/src/tui/dist/index.mjs +15421 -14283
  322. package/src/tui/session/agent-job-feed/execution-delivery.mjs +13 -1
  323. package/src/tui/session/agent-job-feed/notification-router.mjs +3 -0
  324. package/src/tui/session/agent-job-feed/pending-resume.mjs +14 -1
  325. package/src/tui/session/agent-job-feed.mjs +4 -0
  326. package/src/tui/session/context-state.mjs +15 -1
  327. package/src/tui/session/initial-state.mjs +6 -0
  328. package/src/tui/session/live-share/owner.mjs +17 -0
  329. package/src/tui/session/oauth-flows.mjs +2 -0
  330. package/src/tui/session/quota-resume.mjs +263 -0
  331. package/src/tui/session/session-api/intake/abort.mjs +39 -35
  332. package/src/tui/session/session-api/intake/submission.mjs +13 -21
  333. package/src/tui/session/session-api/intake.mjs +3 -3
  334. package/src/tui/session/session-api/integrations.mjs +13 -9
  335. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  336. package/src/tui/session/session-api/lifecycle/inheritance.mjs +2 -2
  337. package/src/tui/session/session-api/lifecycle/session-reset.mjs +4 -0
  338. package/src/tui/session/session-api/lifecycle.mjs +71 -2
  339. package/src/tui/session/session-api/media.mjs +2 -2
  340. package/src/tui/session/session-api/quota-resume.mjs +21 -0
  341. package/src/tui/session/session-api/routes.mjs +4 -2
  342. package/src/tui/session/session-api/settings.mjs +2 -0
  343. package/src/tui/session/session-api.mjs +2 -0
  344. package/src/tui/session/session-flow/auto-clear.mjs +14 -6
  345. package/src/tui/session/session-flow/drain.mjs +52 -5
  346. package/src/tui/session/session-flow/queue/take-entries.mjs +2 -3
  347. package/src/tui/session/session-flow/queue.mjs +3 -0
  348. package/src/tui/session/session-flow/steering.mjs +11 -0
  349. package/src/tui/session/session-flow.mjs +1 -0
  350. package/src/tui/session/tool-approval.mjs +7 -2
  351. package/src/tui/session/tool-card-results/grouped-result.mjs +11 -2
  352. package/src/tui/session/transcript-intake.mjs +1 -0
  353. package/src/tui/session/transcript-spill/spill-dir.mjs +22 -6
  354. package/src/tui/session/turn.mjs +40 -3
  355. package/src/tui/spinner-meta.mjs +26 -10
  356. package/src/vendor/statusline/bin/statusline-route.mjs +3 -2
@@ -25,6 +25,7 @@ export const SESSION_READ_ACTIONS = Object.freeze([
25
25
  'getProfile',
26
26
  'getProviderSetup',
27
27
  'getProviderAccounts',
28
+ 'getQuotaAutoResume',
28
29
  'getQuotaHistory',
29
30
  'getRecapSettings',
30
31
  'getWebSearchRoute',
@@ -95,6 +96,7 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
95
96
  'deleteSchedule',
96
97
  'saveCustomProvider',
97
98
  'removeCustomProvider',
99
+ 'updateCustomProviderModel',
98
100
  'testCustomProvider',
99
101
  'discoverCustomProviderModels',
100
102
  'deleteSession',
@@ -115,6 +117,11 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
115
117
  'reloadSkills',
116
118
  'rememberPromptHistory',
117
119
  'removeMcpServer',
120
+ 'continueSessionInModel',
121
+ 'scheduleQuotaResume',
122
+ 'cancelQuotaResume',
123
+ 'retryFailedTurn',
124
+ 'setQuotaAutoResume',
118
125
  'removeNotice',
119
126
  'removePlugin',
120
127
  'renameSessionTitle',
@@ -177,6 +184,7 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
177
184
  'setTheme',
178
185
  'setToolMode',
179
186
  'setWebSearchEnabled',
187
+ 'setInstructionFiles',
180
188
  'setWebhookConfig',
181
189
  'setWebhookEnabled',
182
190
  'setWorkflow',
@@ -185,6 +193,7 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
185
193
  'startMediaJob',
186
194
  'switchContext',
187
195
  'taskControl',
196
+ 'testWebhook',
188
197
  'toggleFast',
189
198
  'toggleVoice',
190
199
  'claimSetupRequest',
@@ -37,6 +37,8 @@ export function createAgentChildFactory({ registry, rehydrateAgentSessions, crea
37
37
  effort: preset.effort,
38
38
  fast: preset.fast === true,
39
39
  modelParameters: preset.modelParameters,
40
+ contextPercent: spec.contextPercent,
41
+ selectedContextWindow: spec.selectedContextWindow,
40
42
  toolMode: 'full',
41
43
  sessionProfile,
42
44
  });
@@ -47,6 +47,8 @@ export function createEntryLifecycle({
47
47
  effort: params.effort,
48
48
  fast: params.fast,
49
49
  modelParameters: params.modelParameters,
50
+ contextPercent: params.contextPercent,
51
+ selectedContextWindow: params.selectedContextWindow,
50
52
  toolMode: params.toolMode || 'full',
51
53
  remote: params.remote === true,
52
54
  desktopSession: params.desktopSession ?? null,
@@ -61,6 +61,15 @@ export function createSessionLoads({
61
61
  await destroy(entry, 'session load mismatch');
62
62
  throw new Error(`session ${sessionId} could not be resumed`);
63
63
  }
64
+ // The loaded conversation is this entry's durable address from now on:
65
+ // an evicted/unloaded/crashed-restored runtime may resume it again but
66
+ // never mint another id under this entry.
67
+ try {
68
+ await entry.runtime.bindSessionAddress?.(loaded);
69
+ } catch (err) {
70
+ await destroy(entry, 'session address bind failed');
71
+ throw err;
72
+ }
64
73
  // Publish/index the resumed identity before sessionLoads releases its
65
74
  // single-flight promise. A second pane arriving in the next microtask must
66
75
  // find this owner in O(1), not create a duplicate runtime.
@@ -34,6 +34,7 @@ export function frameBody(step, prepend = false) {
34
34
 
35
35
  /** Response body for the CALLER, which announced the revision it holds. */
36
36
  export function bodyForClient(step, baseRevision, prepend = false) {
37
+ if (step.unavailable) return { revision: step.revision, unavailable: true };
37
38
  if (!step.changed && baseRevision === step.revision) return { revision: step.revision };
38
39
  if (step.patch && baseRevision === step.previousRevision) return frameBody(step, prepend);
39
40
  return { revision: step.revision, full: step.snapshot };
@@ -49,7 +50,7 @@ function headGrowthPatch(previous, snapshot) {
49
50
  return patch?.itemsPrepend ? patch : null;
50
51
  }
51
52
 
52
- export function createRevisionSteps({ revisionEpoch, index, updateEntryBusy }) {
53
+ export function createRevisionSteps({ revisionEpoch, index, updateEntryBusy, log = () => {} }) {
53
54
  // One clock owns every snapshot served by this daemon, including stored
54
55
  // views and replacement runtimes. Per-entry counters restarted after idle
55
56
  // eviction, so clients retaining the old baseline discarded new turns.
@@ -97,12 +98,35 @@ export function createRevisionSteps({ revisionEpoch, index, updateEntryBusy }) {
97
98
  function advance(entry) {
98
99
  // Deltas are computed against the WINDOWED snapshot, so a tail-only
99
100
  // baseline keeps receiving ordinary suffix patches.
100
- const snapshot = windowTranscriptSnapshot(entry, snapshotOf(entry));
101
- const projectedSessionId = String(snapshot?.sessionId || '');
101
+ const current = windowTranscriptSnapshot(entry, snapshotOf(entry));
102
+ const projectedSessionId = String(current?.sessionId || '');
102
103
  const addressedSessionId = String(entry.addressedSessionId || '');
103
104
  if (addressedSessionId && projectedSessionId && projectedSessionId !== addressedSessionId) {
104
- throw new Error(`session ${addressedSessionId} changed its durable address to ${projectedSessionId}`);
105
+ // The runtime now reports another conversation. Throwing here failed
106
+ // every read of this entry (view sync, getSnapshot, push watcher), so
107
+ // keep serving what this address last published and say so once.
108
+ if (entry.addressMismatchLogged !== projectedSessionId) {
109
+ entry.addressMismatchLogged = projectedSessionId;
110
+ log(
111
+ `session ${addressedSessionId} changed its durable address to ${projectedSessionId}; serving last snapshot`
112
+ );
113
+ }
114
+ // `current` belongs to ANOTHER conversation and is never served for this
115
+ // address; with no published snapshot left (retention cleared it) the
116
+ // step says so and callers answer without a body.
117
+ const stale = entry.publishedSnapshot ?? null;
118
+ const staleRevision = entry.revision || 0;
119
+ return {
120
+ changed: false,
121
+ ...(stale ? {} : { unavailable: true }),
122
+ snapshot: stale,
123
+ revision: staleRevision,
124
+ previousRevision: staleRevision,
125
+ patch: null,
126
+ prependPatch: null,
127
+ };
105
128
  }
129
+ const snapshot = current;
106
130
  if (!addressedSessionId && projectedSessionId) {
107
131
  entry.addressedSessionId = projectedSessionId;
108
132
  }
@@ -33,6 +33,7 @@ export function createSessionProjection({
33
33
  revisionEpoch,
34
34
  index,
35
35
  updateEntryBusy,
36
+ log,
36
37
  });
37
38
  const frames = createFramePublisher({
38
39
  index,
@@ -0,0 +1,140 @@
1
+ // session-service/quota-resume.mjs
2
+ // The daemon's clock for quota auto-resume. Waiting lives in the durable
3
+ // store (runtime/shared/quota-resume-store.mjs), never in a session runtime,
4
+ // so an evicted or not-yet-loaded session waits exactly like a live one. One
5
+ // timer is armed for the earliest due entry; when it fires, the addressed
6
+ // session is materialized under daemon ownership (the Goal-recovery pattern),
7
+ // a fresh usage reading decides whether its provider can serve the model
8
+ // again, and the session's own lane runs the retry under the entry's
9
+ // generation. Overdue entries run as soon as the scheduler starts.
10
+
11
+ /** A still-exhausted reading is re-taken once, this much later. */
12
+ export const QUOTA_RESUME_RETRY_MS = 5 * 60_000;
13
+ /** A busy session is re-checked this much later, without spending an attempt. */
14
+ export const QUOTA_RESUME_BUSY_RECHECK_MS = 30_000;
15
+ const MAX_TIMER_MS = 2 ** 31 - 1;
16
+
17
+ const isCurrent = (store, entry) => store.quotaResumeEntry(entry.sessionId)?.generation === entry.generation;
18
+
19
+ /** One due entry: load its session, take the fresh reading, then fire,
20
+ * re-check later, or clear it. Returns the outcome for the log. */
21
+ async function resumeDueEntry(entry, { store, materializeSession, readQuotaUsable, log, isClosed, now }) {
22
+ const { sessionId, generation } = entry;
23
+ let runtime;
24
+ try {
25
+ runtime = await materializeSession(sessionId);
26
+ } catch (error) {
27
+ if (isClosed()) return 'closed';
28
+ log(`quota resume could not load session=${sessionId}: ${error?.message || error}`);
29
+ store.cancelQuotaResumeEntry(sessionId, { generation });
30
+ return 'unavailable';
31
+ }
32
+ if (!isCurrent(store, entry)) return 'cancelled';
33
+ let usable = false;
34
+ try {
35
+ usable = await readQuotaUsable(entry.provider, entry.model);
36
+ } catch (error) {
37
+ log(`quota resume usage reading failed provider=${entry.provider}: ${error?.message || error}`);
38
+ }
39
+ if (!isCurrent(store, entry)) return 'cancelled';
40
+ if (!usable) {
41
+ // One more reading five minutes on; after that the session falls back
42
+ // to the user's own choice.
43
+ if (entry.attempts < 1) {
44
+ store.deferQuotaResumeEntry(sessionId, generation, {
45
+ resetAt: now() + QUOTA_RESUME_RETRY_MS,
46
+ attempts: entry.attempts + 1,
47
+ });
48
+ return 'exhausted-retry';
49
+ }
50
+ store.cancelQuotaResumeEntry(sessionId, { generation });
51
+ return 'exhausted';
52
+ }
53
+ const outcome =
54
+ typeof runtime?.fireQuotaResume === 'function' ? runtime.fireQuotaResume({ generation }) : 'unsupported';
55
+ if (outcome === 'busy') {
56
+ store.deferQuotaResumeEntry(sessionId, generation, {
57
+ resetAt: now() + QUOTA_RESUME_BUSY_RECHECK_MS,
58
+ attempts: entry.attempts,
59
+ });
60
+ } else if (isCurrent(store, entry)) {
61
+ // Every other outcome settles the entry; one the session could not
62
+ // address (it now holds another session id) must not stay due forever.
63
+ store.cancelQuotaResumeEntry(sessionId, { generation });
64
+ }
65
+ return outcome;
66
+ }
67
+
68
+ export function createQuotaResumeScheduler({
69
+ store,
70
+ materializeSession,
71
+ readQuotaUsable,
72
+ log = () => {},
73
+ isClosed = () => false,
74
+ now = () => Date.now(),
75
+ setTimer = (task, ms) => setTimeout(task, ms),
76
+ clearTimer = (timer) => clearTimeout(timer),
77
+ }) {
78
+ let started = false;
79
+ let timer = null;
80
+ let running = null;
81
+ let unsubscribe = null;
82
+ const deps = { store, materializeSession, readQuotaUsable, log, isClosed, now };
83
+
84
+ function arm() {
85
+ if (timer) clearTimer(timer);
86
+ timer = null;
87
+ if (!started || isClosed() || running) return;
88
+ const entries = store.listQuotaResumeEntries();
89
+ if (entries.length === 0) return;
90
+ const due = Math.min(...entries.map((entry) => entry.resetAt));
91
+ timer = setTimer(
92
+ () => {
93
+ timer = null;
94
+ void tick();
95
+ },
96
+ Math.min(MAX_TIMER_MS, Math.max(0, due - now()))
97
+ );
98
+ timer?.unref?.();
99
+ }
100
+
101
+ function tick() {
102
+ if (running) return running;
103
+ running = (async () => {
104
+ for (const entry of store.listQuotaResumeEntries()) {
105
+ if (isClosed()) return;
106
+ if (entry.resetAt > now() || !isCurrent(store, entry)) continue;
107
+ try {
108
+ const outcome = await resumeDueEntry(entry, deps);
109
+ log(`quota resume session=${entry.sessionId} outcome=${outcome}`);
110
+ } catch (error) {
111
+ log(`quota resume failed session=${entry.sessionId}: ${error?.message || error}`);
112
+ store.cancelQuotaResumeEntry(entry.sessionId, { generation: entry.generation });
113
+ }
114
+ }
115
+ })().finally(() => {
116
+ running = null;
117
+ arm();
118
+ });
119
+ return running;
120
+ }
121
+
122
+ return {
123
+ /** Start the clock; entries already due run right away. */
124
+ start() {
125
+ if (started || isClosed()) return;
126
+ started = true;
127
+ unsubscribe = store.subscribeQuotaResume(() => arm());
128
+ arm();
129
+ },
130
+ /** Run every due entry now (the timer's own callback). */
131
+ tick,
132
+ stop() {
133
+ started = false;
134
+ unsubscribe?.();
135
+ unsubscribe = null;
136
+ if (timer) clearTimer(timer);
137
+ timer = null;
138
+ },
139
+ };
140
+ }
@@ -22,7 +22,7 @@ function requireSessionAction(action, allowed) {
22
22
  }
23
23
 
24
24
  export function createSessionActionCalls(ctx) {
25
- const { isClosed, log, listSessions, getRemoteSessionState, loadProjectStore, advanceForCaller, readStoredReview } =
25
+ const { isClosed, log, listSessions, getRemoteSessionState, loadProjectStore, advanceForCaller, readStoredReview, responseSessionId } =
26
26
  ctx;
27
27
  const { bodyForClient } = ctx.projection;
28
28
  const { retainUnwatched } = ctx.retention;
@@ -83,7 +83,7 @@ export function createSessionActionCalls(ctx) {
83
83
  retainUnwatched(entry);
84
84
  return {
85
85
  value: sanitizeForWire(value) ?? null,
86
- sessionId: String(entry.runtime.getState?.()?.sessionId || id),
86
+ sessionId: responseSessionId(entry, id),
87
87
  ...bodyForClient(step, Number.isInteger(baseRevision) ? baseRevision : null),
88
88
  };
89
89
  }
@@ -23,10 +23,18 @@ import { createSessionViewCalls } from './session-calls/session-views.mjs';
23
23
  export function createSessionCalls(deps) {
24
24
  const { advance, currentSessionId, publishStep, bodyForClient } = deps.projection;
25
25
 
26
+ /** The id a response reports: the entry's immutable addressed id (what the
27
+ * served snapshot describes), never a runtime id that drifted away from it.
28
+ * Before the first advance there is no address yet, so the runtime id (a
29
+ * fresh create/resume) is the identity. */
30
+ function responseSessionId(entry, fallback = '') {
31
+ return String(entry.addressedSessionId || currentSessionId(entry) || fallback);
32
+ }
33
+
26
34
  /** `prepend`: the caller announced transcriptPrepend (see frameBody). */
27
35
  function sessionResult(entry, step, baseRevision = null, extra = {}, { prepend = false } = {}) {
28
36
  return {
29
- sessionId: currentSessionId(entry),
37
+ sessionId: responseSessionId(entry),
30
38
  reservedOnly: entry.reservedOnly === true,
31
39
  ...extra,
32
40
  ...bodyForClient(step, Number.isInteger(baseRevision) ? baseRevision : null, prepend),
@@ -46,7 +54,7 @@ export function createSessionCalls(deps) {
46
54
  return step;
47
55
  }
48
56
 
49
- const ctx = { ...deps, sessionResult, advanceForCaller };
57
+ const ctx = { ...deps, sessionResult, responseSessionId, advanceForCaller };
50
58
  const actions = createSessionActionCalls(ctx);
51
59
  const views = createSessionViewCalls({ ...ctx, runSessionAction: actions.runSessionAction });
52
60
  const turns = createSessionTurnCalls(ctx);
@@ -10,9 +10,27 @@ export function createStoredSessionReader({
10
10
  statStoredSession = null,
11
11
  forgetStoredSession = null,
12
12
  releaseStoredSession = null,
13
+ readQuotaResume = null,
13
14
  sessionOwner,
14
15
  log,
15
16
  }) {
17
+ /** The cold session's queued quota resume (snapshot shape) or null. */
18
+ const quotaResumeOf = (sessionId) => {
19
+ if (typeof readQuotaResume !== 'function') return null;
20
+ try {
21
+ return readQuotaResume(sessionId) ?? null;
22
+ } catch (err) {
23
+ log(`stored quota resume projection failed session=${sessionId}: ${err?.message || err}`);
24
+ return null;
25
+ }
26
+ };
27
+ // The resume is projected beside the transcript, so its identity is part
28
+ // of the stamp a cold view is served by: a scheduled, deferred or cleared
29
+ // resume refreshes the view even while the transcript files are unchanged.
30
+ const quotaResumeStamp = (sessionId) => {
31
+ const resume = quotaResumeOf(sessionId);
32
+ return resume ? `${resume.turnKey}:${resume.resetAt}:${resume.attempts}` : '';
33
+ };
16
34
  // `${sessionId}|${window}` -> { projectionStamp, fileStamp }: the settled
17
35
  // file identity each served projection was built from. The 1s cold-view
18
36
  // refresh asks again with the stamp it holds; while the files still carry
@@ -78,11 +96,15 @@ export function createStoredSessionReader({
78
96
 
79
97
  async function fileStampOf(sessionId) {
80
98
  if (typeof statStoredSession !== 'function') return null;
99
+ let stamp;
81
100
  try {
82
- return (await statStoredSession(sessionId)) || null;
101
+ stamp = (await statStoredSession(sessionId)) || null;
83
102
  } catch {
84
103
  return null;
85
104
  }
105
+ if (stamp === null) return null;
106
+ const resume = quotaResumeStamp(sessionId);
107
+ return resume ? `${stamp}|quota-resume:${resume}` : stamp;
86
108
  }
87
109
 
88
110
  /** Whether the projection a caller holds (`projectionStamp`, read through
@@ -145,6 +167,9 @@ export function createStoredSessionReader({
145
167
  ...wire,
146
168
  sessionId,
147
169
  ...(typeof readStoredGoal === 'function' ? { goal: sanitizeForWire(goal, 1) ?? null } : {}),
170
+ ...(typeof readQuotaResume === 'function'
171
+ ? { quotaResume: sanitizeForWire(quotaResumeOf(sessionId)) ?? null }
172
+ : {}),
148
173
  queued: Array.isArray(snapshot.queued) ? wire.queued : [],
149
174
  };
150
175
  }
@@ -22,6 +22,7 @@ import { createSessionRetention } from './session-service/retention.mjs';
22
22
  import { createViewerRegistry } from './session-service/viewers.mjs';
23
23
  import { createSessionEntries } from './session-service/entries.mjs';
24
24
  import { createSessionCalls } from './session-service/session-calls.mjs';
25
+ import { createQuotaResumeScheduler } from './session-service/quota-resume.mjs';
25
26
 
26
27
  const EXTERNAL_SESSION_ACTIONS = new Set([
27
28
  ...SESSION_READ_ACTION_SET,
@@ -56,6 +57,10 @@ export function createSessionService({
56
57
  onDesktopReady = () => {},
57
58
  idleEvictMs = null,
58
59
  evictSweepMs = null,
60
+ // Quota auto-resume: the durable queue module and the fresh usage reading
61
+ // (provider, model) => Promise<boolean>. Without a store nothing is scheduled.
62
+ quotaResumeStore = null,
63
+ readQuotaUsable = null,
59
64
  } = {}) {
60
65
  const createRuntime = createSessionRuntime;
61
66
  if (typeof createRuntime !== 'function') throw new Error('createSessionRuntime is required');
@@ -165,6 +170,9 @@ export function createSessionService({
165
170
  statStoredSession,
166
171
  forgetStoredSession,
167
172
  releaseStoredSession,
173
+ readQuotaResume: quotaResumeStore
174
+ ? (sessionId) => quotaResumeStore.publicQuotaResume(quotaResumeStore.quotaResumeEntry(sessionId))
175
+ : null,
168
176
  sessionOwner: projection.sessionOwner,
169
177
  log,
170
178
  });
@@ -197,10 +205,21 @@ export function createSessionService({
197
205
  retainUnwatched: retention.retainUnwatched,
198
206
  createSession: calls.createSession,
199
207
  });
208
+ const quotaUsableReader = typeof readQuotaUsable === 'function' ? readQuotaUsable : async () => false;
209
+ const quotaResume = quotaResumeStore
210
+ ? createQuotaResumeScheduler({
211
+ store: quotaResumeStore,
212
+ materializeSession: calls.materializeSession,
213
+ readQuotaUsable: quotaUsableReader,
214
+ log,
215
+ isClosed,
216
+ })
217
+ : null;
200
218
 
201
219
  function stop(reason = 'service stop') {
202
220
  if (stopPromise) return stopPromise;
203
221
  closed = true;
222
+ quotaResume?.stop();
204
223
  stopPromise = Promise.resolve().then(async () => {
205
224
  try {
206
225
  unsubscribeExternalSessionStates();
@@ -264,6 +283,8 @@ export function createSessionService({
264
283
  methods: {
265
284
  ...calls,
266
285
  stop,
286
+ startQuotaResume: () => quotaResume?.start(),
287
+ runDueQuotaResumes: () => quotaResume?.tick() ?? Promise.resolve(),
267
288
  releaseClient: viewers.releaseClient,
268
289
  agentSurface: agentTree.agentSurface,
269
290
  agentManager: agentTree.agentManager,
@@ -114,6 +114,7 @@ export function createTransportRoutes({
114
114
  const requestedProtocol = Number(body.protocol);
115
115
  const requestedRevision = Math.max(0, Number(body.revision) || 0);
116
116
  const requestedVersion = String(body.version || '0.0.0');
117
+ const force = body.force === true;
117
118
  const revisionOrder = requestedRevision - SESSION_REVISION;
118
119
  const versionOrder = compareRuntimeVersions(requestedVersion, runtimeVersion());
119
120
  const newerBuild =
@@ -140,6 +141,7 @@ export function createTransportRoutes({
140
141
  protocol: SESSION_PROTOCOL,
141
142
  revision: requestedRevision,
142
143
  version: requestedVersion,
144
+ force,
143
145
  });
144
146
  } catch {}
145
147
  });
@@ -115,6 +115,7 @@ function reportNode({ version, engines }, row) {
115
115
  }
116
116
 
117
117
  function providerUnusableReason(entry) {
118
+ if (entry.configError) return `has an invalid configuration (${entry.configError})`;
118
119
  if (entry.reauthRequired) return 'requires sign-in again';
119
120
  if (entry.enabled === false) return 'is disabled';
120
121
  if (entry.type === 'local' && !entry.detected) return 'has no installed runtime/model';
@@ -240,9 +241,7 @@ function reportRegistry(label) {
240
241
  const broken = active.filter(
241
242
  (entry) => entry.broken || entry.error || entry.invalid || entry.dependencyIssues?.length
242
243
  );
243
- const missing = Array.isArray(status.missing)
244
- ? status.missing.filter((entry) => entry.enabled !== false)
245
- : [];
244
+ const missing = Array.isArray(status.missing) ? status.missing.filter((entry) => entry.enabled !== false) : [];
246
245
  let detail = `${active.length}/${entries.length} active${scopeDetail}`;
247
246
  const issues = [...broken, ...(label === 'plugins' ? missing : [])];
248
247
  if (!issues.length) {
@@ -340,7 +339,8 @@ async function readDataFolder(dataDir) {
340
339
 
341
340
  function reportDataFolder({ dataDir, writable, missing }, row) {
342
341
  if (writable) row('ok', `writable · ${dataDir}`);
343
- else if (missing) row('fail', `not found · ${dataDir}`, { hint: 'create the folder or point MIXDOG_DATA_DIR at an existing one' });
342
+ else if (missing)
343
+ row('fail', `not found · ${dataDir}`, { hint: 'create the folder or point MIXDOG_DATA_DIR at an existing one' });
344
344
  else row('fail', `not writable · ${dataDir}`, { hint: 'check the folder permissions' });
345
345
  }
346
346
 
@@ -398,15 +398,11 @@ export async function runDoctorChecks(runtime = {}, getState = () => ({}), optio
398
398
  [
399
399
  'voice',
400
400
  'voice',
401
- async () => (runtime.getVoiceStatus || (await import('../lib/voice-setup.mjs')).getVoiceStatus)(),
401
+ async () =>
402
+ (runtime.getVoiceStatus || (await import('../../runtime/channels/lib/voice-setup.mjs')).getVoiceStatus)(),
402
403
  reportVoice,
403
404
  ],
404
- [
405
- 'automation',
406
- 'automation',
407
- () => runtime.getChannelSettings?.({ includeStatus: true }),
408
- reportChannels(runtime),
409
- ],
405
+ ['automation', 'automation', () => runtime.getChannelSettings?.({ includeStatus: true }), reportChannels(runtime)],
410
406
  ['skills', 'skills', () => runtime.skillsStatus?.(), reportRegistry('skills')],
411
407
  ['plugins', 'plugins', () => runtime.pluginsStatus?.(), reportRegistry('plugins')],
412
408
  ['hooks', 'hooks', () => runtime.hooksStatus?.(), reportHooks],
@@ -110,11 +110,9 @@ export function createAutoClearPicker({
110
110
  const enabled = current?.enabled !== false;
111
111
  const idleMs = Number(current?.idleMs || HOUR_MS);
112
112
  const cacheTtlLabel = !enabled || idleMs >= HOUR_MS ? '1h' : '5m';
113
- const sourceLabel = current?.providerCustom
114
- ? `${current.provider} override`
115
- : current?.custom
116
- ? 'global'
117
- : `${current?.provider || 'default'} default`;
113
+ let sourceLabel = `${current?.provider || 'default'} default`;
114
+ if (current?.providerCustom) sourceLabel = `${current.provider} override`;
115
+ else if (current?.custom) sourceLabel = 'global';
118
116
  const items = [
119
117
  {
120
118
  value: 'toggle',
@@ -8,6 +8,7 @@
8
8
  import { theme } from '../theme.mjs';
9
9
  import { displayModelName } from '../../runtime/shared/model-display.mjs';
10
10
  import { isRollingModelAlias } from '../../runtime/shared/model-alias.mjs';
11
+ import { DAYBREAK_PROVIDER, daybreakBlueOn } from '../../runtime/shared/llm/openai-daybreak.mjs';
11
12
 
12
13
  export const parsedModelVersion = (id) => {
13
14
  const text = String(id || '').toLowerCase();
@@ -167,6 +168,8 @@ const PROVIDER_DISPLAY_NAMES = new Map([
167
168
  ['openai-oauth', 'OpenAI OAuth'],
168
169
  ['anthropic-oauth', 'Anthropic OAuth'],
169
170
  ['grok-oauth', 'Grok OAuth'],
171
+ ['muse-code-oauth', 'Muse Code'],
172
+ ['mimo-oauth', 'MiMo'],
170
173
  ['cursor-oauth', 'Cursor OAuth'],
171
174
  ['antigravity-oauth', 'Antigravity OAuth'],
172
175
  ['openai', 'OpenAI API'],
@@ -193,6 +196,8 @@ const PROVIDER_DISPLAY_RANKS = {
193
196
  'openai-oauth': 10,
194
197
  'anthropic-oauth': 20,
195
198
  'grok-oauth': 30,
199
+ 'muse-code-oauth': 33,
200
+ 'mimo-oauth': 34,
196
201
  'antigravity-oauth': 31,
197
202
  'cursor-oauth': 32,
198
203
  'opencode-go': 35,
@@ -233,7 +238,14 @@ export const modelDescription = (m) =>
233
238
 
234
239
  const modelRecordDisplayName = (model) => displayModelName(model?.id, model?.provider, model?.display || model?.name);
235
240
 
236
- const routeModelDisplayName = (route) => displayModelName(route?.model, route?.provider, route?.modelDisplay || '');
241
+ // Daybreak Blue reads as part of the model ("GPT-6 Sol Blue"), ahead of effort.
242
+ const routeModelDisplayName = (route) =>
243
+ [
244
+ displayModelName(route?.model, route?.provider, route?.modelDisplay || ''),
245
+ route?.provider === DAYBREAK_PROVIDER && daybreakBlueOn(route?.modelParameters) ? 'Blue' : '',
246
+ ]
247
+ .filter(Boolean)
248
+ .join(' ');
237
249
 
238
250
  const groupModelsByProvider = (models) => {
239
251
  const providers = new Map();
@@ -4,6 +4,9 @@
4
4
  // selected parameters (and the selected effort), and cycling `thinking` can
5
5
  // invalidate a Fast selection that the new parameter combination rules out.
6
6
  import { modelKey } from './model-key.mjs';
7
+ import { DAYBREAK_PARAMETER_ID } from '../../../../runtime/shared/llm/openai-daybreak.mjs';
8
+
9
+ const TOGGLE_PARAMETER_IDS = new Set(['thinking', DAYBREAK_PARAMETER_ID]);
7
10
 
8
11
  export function createFastParameterSelection({ state, currentRoute, isCurrentRoute, isStateRoute, getSelectedEffort }) {
9
12
  const selectedFast = new Map();
@@ -82,12 +85,15 @@ export function createFastParameterSelection({ state, currentRoute, isCurrentRou
82
85
  return true;
83
86
  };
84
87
 
85
- /** Cycles the 'thinking' parameter to its next option; false when the model
86
- * has none. Fast is dropped when the new parameters rule it out. */
88
+ /** Cycles the model's toggle parameter ('thinking', or Daybreak Blue's
89
+ * on/off) to its next option; false when the model has none. Fast is
90
+ * dropped when the new parameters rule it out. */
87
91
  const cycleThinking = (model) => {
88
- const wanted = 'thinking';
89
- const definition = (model.modelParameterOptions || []).find((parameter) => parameter.id === wanted);
92
+ const definition = (model.modelParameterOptions || []).find((parameter) =>
93
+ TOGGLE_PARAMETER_IDS.has(parameter.id)
94
+ );
90
95
  if (!definition?.options?.length) return false;
96
+ const wanted = definition.id;
91
97
  const parameters = modelParametersFor(model);
92
98
  const current = Math.max(
93
99
  0,
@@ -127,6 +127,11 @@ function beginInteractiveOAuthLogin(flow, providerItem, login) {
127
127
  `browser opened for ${providerName}; paste code/redirect here if callback does not finish`,
128
128
  'info'
129
129
  );
130
+ } else if (started?.userCode) {
131
+ flow.store.pushNotice(
132
+ `${providerName}: enter code ${started.userCode} in the browser to finish signing in`,
133
+ 'info'
134
+ );
130
135
  } else {
131
136
  flow.store.pushNotice(`browser opened for ${providerName}; finish signing in there`, 'info');
132
137
  }
@@ -3,7 +3,7 @@
3
3
  // concern — routing/model first, then session behavior, integrations, voice,
4
4
  // system — and must stay in sync with desktop SETTINGS_ITEMS (tui-parity
5
5
  // test, minus system-shell).
6
- import { isVoiceEnabled } from '../../lib/voice-setup.mjs';
6
+ import { isVoiceEnabled } from '../../../runtime/channels/lib/voice-setup.mjs';
7
7
 
8
8
  const boolLabel = (enabled) => (enabled ? 'On' : 'Off');
9
9
 
@@ -66,11 +66,9 @@ export function buildSettingsItems({
66
66
  const { workflow, mcp, plugins, skills } = view;
67
67
  const outputStyleLabel =
68
68
  outputStyle?.current?.label || outputStyle?.current?.id || outputStyle?.configured || 'Default';
69
- const autoClearSource = autoClear.providerCustom
70
- ? ` (${autoClear.provider} override)`
71
- : autoClear.custom
72
- ? ' (global)'
73
- : ` (${autoClear.provider || 'default'} default)`;
69
+ let autoClearSource = ` (${autoClear.provider || 'default'} default)`;
70
+ if (autoClear.providerCustom) autoClearSource = ` (${autoClear.provider} override)`;
71
+ else if (autoClear.custom) autoClearSource = ' (global)';
74
72
  return [
75
73
  {
76
74
  value: 'model',
@@ -2,7 +2,7 @@
2
2
  // The boolean rows of Settings: each write goes through the store, reports the
3
3
  // outcome as a notice, and refreshes Settings through the deferred refresh
4
4
  // bound to the keypress that started it.
5
- import { toggleVoice, isVoiceInstallBusy } from '../../../lib/voice-setup.mjs';
5
+ import { toggleVoice, isVoiceInstallBusy } from '../../../../runtime/channels/lib/voice-setup.mjs';
6
6
 
7
7
  export function createStoreToggles({ store, view, formatDuration, deferredSettingsRefresh }) {
8
8
  const applyAutoClear = (patch = {}) => {