mixdog 1.3.5 → 1.4.0

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 (341) hide show
  1. package/NOTICE.md +2 -2
  2. package/README.md +2 -2
  3. package/package.json +2 -11
  4. package/scripts/daemon-stub.mjs +1 -1
  5. package/scripts/gate-local.mjs +4 -2
  6. package/scripts/native-release-status.mjs +2 -2
  7. package/scripts/recall-history-cases.json +1 -1
  8. package/scripts/suite-health.mjs +10 -1
  9. package/scripts/test.mjs +7 -11
  10. package/src/agents/reviewer/AGENT.md +7 -11
  11. package/src/agents/reviewer/agent.json +1 -1
  12. package/src/defaults/shipped-history.json +17 -1
  13. package/src/defaults/skills/browser-use/SKILL.md +59 -11
  14. package/src/defaults/skills/code-tidy/SKILL.md +142 -270
  15. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
  16. package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
  17. package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
  18. package/src/defaults/skills/computer-use/SKILL.md +33 -9
  19. package/src/defaults/skills/setup/SKILL.md +22 -0
  20. package/src/defaults/skills/setup/references/actions.md +39 -5
  21. package/src/defaults/skills/setup/references/surfaces.md +11 -2
  22. package/src/defaults/skills/visualize/SKILL.md +2 -1
  23. package/src/lib/rules-builder.cjs +10 -8
  24. package/src/rules/agent/AGENT.md +6 -6
  25. package/src/rules/lead/LEAD.md +18 -20
  26. package/src/rules/shared/05-tool-calls.md +5 -6
  27. package/src/rules/shared/10-tool-workflow.md +2 -0
  28. package/src/rules/shared/60-verification.md +7 -5
  29. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
  30. package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
  31. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
  32. package/src/runtime/agent/orchestrator/config.mjs +17 -1
  33. package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
  34. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +72 -67
  35. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +54 -1
  36. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
  37. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +176 -72
  38. package/src/runtime/agent/orchestrator/mcp/client.mjs +19 -0
  39. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +181 -133
  40. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +42 -6
  41. package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
  42. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  43. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
  44. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
  45. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +145 -66
  46. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
  47. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +64 -33
  48. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
  49. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +123 -102
  50. package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
  51. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
  52. package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -13
  53. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
  54. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
  55. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
  56. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  57. package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
  58. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -1
  59. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
  60. package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
  61. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
  62. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
  63. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
  64. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
  65. package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
  66. package/src/runtime/agent/orchestrator/providers/registry.mjs +26 -0
  67. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
  68. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
  69. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +12 -7
  70. package/src/runtime/agent/orchestrator/runtime-core/compaction-config-keys.mjs +62 -0
  71. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +37 -16
  72. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +100 -23
  73. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -0
  74. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
  75. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
  76. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +792 -0
  77. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +133 -22
  78. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
  79. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
  80. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -1
  81. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +11 -5
  82. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +0 -2
  83. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
  84. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +1 -1
  85. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +18 -22
  86. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +32 -3
  87. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +3 -1
  88. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +1 -1
  89. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +17 -3
  90. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -2
  91. package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
  92. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +3 -2
  93. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
  94. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
  95. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +10 -0
  96. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
  97. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +12 -3
  98. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
  99. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
  100. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
  101. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
  102. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
  103. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +23 -13
  104. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
  105. package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
  106. package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +129 -0
  107. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +20 -2
  108. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
  109. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +8 -0
  110. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
  111. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +7 -2
  112. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
  113. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +18 -5
  114. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +19 -8
  115. package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
  116. package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +127 -0
  117. package/src/runtime/agent/orchestrator/session/routine-result.mjs +36 -9
  118. package/src/runtime/agent/orchestrator/session/sensitive-projection.mjs +100 -0
  119. package/src/runtime/agent/orchestrator/session/sensitive-values.mjs +257 -0
  120. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +20 -7
  121. package/src/runtime/agent/orchestrator/session/side-question.mjs +18 -0
  122. package/src/runtime/agent/orchestrator/session/skill-update-notice.mjs +60 -0
  123. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +6 -3
  124. package/src/runtime/agent/orchestrator/session/store/save-delta.mjs +9 -5
  125. package/src/runtime/agent/orchestrator/session/store/serialize.mjs +9 -8
  126. package/src/runtime/agent/orchestrator/session/store/session-persistence-events.mjs +29 -0
  127. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +8 -6
  128. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +12 -2
  129. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -14
  130. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +84 -3
  131. package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
  132. package/src/runtime/agent/orchestrator/session/thinking-binding.mjs +108 -0
  133. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +2 -2
  134. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +2 -1
  135. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +18 -1
  136. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
  137. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
  138. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
  139. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
  140. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
  141. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +240 -0
  142. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
  143. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/shell-cwd.mjs +38 -0
  144. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +25 -5
  145. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +65 -7
  146. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
  147. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
  148. package/src/runtime/browser-bridge/action-schema.mjs +13 -2
  149. package/src/runtime/browser-bridge/client.mjs +73 -8
  150. package/src/runtime/browser-bridge/input-fields.mjs +8 -9
  151. package/src/runtime/browser-bridge/mail-links.mjs +107 -0
  152. package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
  153. package/src/runtime/channels/lib/config.mjs +6 -61
  154. package/src/runtime/channels/lib/crash-log.mjs +1 -1
  155. package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
  156. package/src/runtime/channels/lib/event-queue.mjs +3 -18
  157. package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
  158. package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
  159. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
  160. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
  161. package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
  162. package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
  163. package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
  164. package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
  165. package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
  166. package/src/runtime/channels/lib/scheduler.mjs +33 -147
  167. package/src/runtime/channels/lib/schedules-db.mjs +34 -11
  168. package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
  169. package/src/runtime/channels/lib/tool-dispatch.mjs +1 -2
  170. package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
  171. package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
  172. package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
  173. package/src/runtime/channels/lib/worker-main.mjs +10 -34
  174. package/src/runtime/computer-bridge/action-schema.mjs +42 -1
  175. package/src/runtime/computer-bridge/actions.mjs +9 -1
  176. package/src/runtime/computer-bridge/client.mjs +180 -8
  177. package/src/runtime/computer-bridge/core-actions.mjs +2 -2
  178. package/src/runtime/computer-bridge/error-recovery.mjs +27 -2
  179. package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
  180. package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
  181. package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
  182. package/src/runtime/connectors/gmail-app-password.mjs +172 -39
  183. package/src/runtime/connectors/google-mcp.mjs +10 -12
  184. package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
  185. package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
  186. package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
  187. package/src/runtime/session-search/session-search-db.mjs +73 -9
  188. package/src/runtime/session-search/session-search-ingest.mjs +110 -20
  189. package/src/runtime/shared/abort-race.mjs +89 -0
  190. package/src/runtime/shared/agent-avatar.d.mts +0 -1
  191. package/src/runtime/shared/agent-kind.mjs +4 -3
  192. package/src/runtime/shared/bounded-download.mjs +8 -3
  193. package/src/runtime/shared/config.mjs +2 -13
  194. package/src/runtime/shared/connector-accounts.mjs +20 -10
  195. package/src/runtime/shared/connector-catalog.d.mts +29 -0
  196. package/src/runtime/shared/connector-catalog.mjs +150 -0
  197. package/src/runtime/shared/connector-triggers.mjs +22 -19
  198. package/src/runtime/shared/defaults-separation.mjs +2 -14
  199. package/src/runtime/shared/delegated-approval-host.mjs +103 -11
  200. package/src/runtime/shared/err-text.mjs +24 -15
  201. package/src/runtime/shared/file-permissions.d.mts +0 -8
  202. package/src/runtime/shared/file-permissions.mjs +0 -11
  203. package/src/runtime/shared/git-direct.test-support.mjs +19 -0
  204. package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
  205. package/src/runtime/shared/heartbeat-interval.mjs +19 -0
  206. package/src/runtime/shared/idle-auto-clear-gate.mjs +104 -0
  207. package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
  208. package/src/runtime/shared/mixy-presence.mjs +22 -0
  209. package/src/runtime/shared/orchestration.d.mts +2 -0
  210. package/src/runtime/shared/pg-schema-db.mjs +27 -16
  211. package/src/runtime/shared/profile-config.cjs +1 -1
  212. package/src/runtime/shared/prompt-origin.d.mts +4 -0
  213. package/src/runtime/shared/prompt-origin.mjs +21 -0
  214. package/src/runtime/shared/provider-accounts.mjs +7 -1
  215. package/src/runtime/shared/provider-display-name.mjs +29 -0
  216. package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
  217. package/src/runtime/shared/routine-trigger.d.mts +2 -0
  218. package/src/runtime/shared/routine-trigger.mjs +10 -0
  219. package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
  220. package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
  221. package/src/runtime/shared/session-activity-signal.mjs +34 -1
  222. package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
  223. package/src/runtime/shared/session-sidebar-host.mjs +7 -3
  224. package/src/runtime/shared/session-turn-prelude.mjs +18 -0
  225. package/src/runtime/shared/tool-result-summary.mjs +1 -14
  226. package/src/runtime/shared/worktrees/test-support.mjs +9 -4
  227. package/src/runtime/terminal-bridge/client.mjs +10 -1
  228. package/src/runtime/visualize-bridge/client.mjs +27 -8
  229. package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
  230. package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
  231. package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
  232. package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
  233. package/src/session-runtime/agent-home-delivery.mjs +448 -185
  234. package/src/session-runtime/agent-task-sessions.mjs +329 -180
  235. package/src/session-runtime/boot/apis.mjs +9 -0
  236. package/src/session-runtime/boot/infrastructure.mjs +4 -0
  237. package/src/session-runtime/boot/providers.mjs +3 -0
  238. package/src/session-runtime/boot/tools.mjs +6 -1
  239. package/src/session-runtime/config-lifecycle.mjs +6 -0
  240. package/src/session-runtime/connector-merge-migration.mjs +305 -0
  241. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +132 -28
  242. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +2 -0
  243. package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
  244. package/src/session-runtime/lifecycle/session-catalog.mjs +3 -1
  245. package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
  246. package/src/session-runtime/lifecycle/teardown.mjs +23 -5
  247. package/src/session-runtime/mcp-glue/server-catalog.mjs +55 -3
  248. package/src/session-runtime/mcp-oauth-login.mjs +5 -3
  249. package/src/session-runtime/mixy-heartbeat.mjs +153 -33
  250. package/src/session-runtime/notification-bus.mjs +31 -117
  251. package/src/session-runtime/notification-completion-queue.mjs +54 -0
  252. package/src/session-runtime/notification-listeners.mjs +76 -0
  253. package/src/session-runtime/owned-automation-run.mjs +2 -1
  254. package/src/session-runtime/prewarm/channel-start.mjs +3 -7
  255. package/src/session-runtime/resource-mcp-api.mjs +143 -224
  256. package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
  257. package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
  258. package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
  259. package/src/session-runtime/resource-mcp-servers.mjs +78 -0
  260. package/src/session-runtime/resource-mcp-store.mjs +49 -0
  261. package/src/session-runtime/routine-owner.mjs +40 -9
  262. package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
  263. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +7 -2
  264. package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
  265. package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
  266. package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
  267. package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
  268. package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
  269. package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
  270. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
  271. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
  272. package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
  273. package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
  274. package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
  275. package/src/session-runtime/services/channel-admin.mjs +7 -13
  276. package/src/session-runtime/services/channel-session-router.mjs +4 -2
  277. package/src/session-runtime/services/seeds.mjs +0 -28
  278. package/src/session-runtime/session-compaction-sync.mjs +27 -0
  279. package/src/session-runtime/session-create/session-options.mjs +1 -0
  280. package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
  281. package/src/session-runtime/settings-compaction-api.mjs +2 -40
  282. package/src/session-runtime/settings-system-api.mjs +13 -1
  283. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
  284. package/src/session-runtime/setup-tool/executor.mjs +145 -22
  285. package/src/session-runtime/setup-tool/extended-actions.mjs +8 -3
  286. package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
  287. package/src/session-runtime/setup-tool/settings-contract.mjs +4 -3
  288. package/src/session-runtime/setup-tool/tool-defs.mjs +64 -5
  289. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
  290. package/src/session-runtime/tool-policy/policy-stage.mjs +16 -2
  291. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  292. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
  293. package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
  294. package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
  295. package/src/standalone/channel-transport/client-registry.mjs +24 -163
  296. package/src/standalone/channel-transport.mjs +1 -1
  297. package/src/standalone/daemon-channels-loader.mjs +10 -8
  298. package/src/standalone/daemon-session-control/list-page.mjs +72 -0
  299. package/src/standalone/daemon-session-control/request.mjs +51 -0
  300. package/src/standalone/daemon-session-control/room-host.mjs +57 -0
  301. package/src/standalone/daemon-session-control/route-control.mjs +48 -0
  302. package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
  303. package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
  304. package/src/standalone/daemon-session-control.mjs +124 -188
  305. package/src/standalone/daemon.mjs +26 -3
  306. package/src/standalone/session-client.mjs +7 -3
  307. package/src/standalone/session-protocol.mjs +5 -0
  308. package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
  309. package/src/standalone/session-service/quota-resume.mjs +3 -0
  310. package/src/standalone/session-service/retention/busy.mjs +65 -1
  311. package/src/standalone/session-service/session-calls/session-action.mjs +23 -2
  312. package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
  313. package/src/standalone/session-tool-output.mjs +15 -7
  314. package/src/tui/app/model-options.mjs +3 -28
  315. package/src/tui/dist/index.mjs +58 -64
  316. package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
  317. package/src/tui/session/initial-state.mjs +3 -0
  318. package/src/tui/session/notice-surface.mjs +7 -1
  319. package/src/tui/session/queue-helpers.mjs +3 -42
  320. package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
  321. package/src/tui/session/session-api/routes-write.mjs +5 -1
  322. package/src/tui/session/session-api/routes.mjs +1 -0
  323. package/src/tui/session/session-api/settings.mjs +17 -1
  324. package/src/tui/session/session-flow/auto-clear.mjs +4 -33
  325. package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
  326. package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
  327. package/src/tui/session/session-flow/drain-retry.mjs +35 -0
  328. package/src/tui/session/session-flow/drain.mjs +118 -149
  329. package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
  330. package/src/tui/session/session-flow/queue/take-entries.mjs +5 -2
  331. package/src/tui/session/tool-approval-delegation.mjs +64 -0
  332. package/src/tui/session/tool-approval-request.mjs +39 -0
  333. package/src/tui/session/tool-approval-settle.mjs +62 -0
  334. package/src/tui/session/tool-approval.mjs +69 -115
  335. package/src/tui/session/tui-steering-persist.mjs +8 -1
  336. package/src/tui/session/turn-stream.mjs +19 -2
  337. package/src/tui/session/turn.mjs +1 -0
  338. package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
  339. package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
  340. package/scripts/code-graph-description-contract.mjs +0 -188
  341. package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
@@ -40,7 +40,7 @@ export function createSessionActionCalls(ctx) {
40
40
  responseSessionId,
41
41
  } = ctx;
42
42
  const { bodyForClient } = ctx.projection;
43
- const { retainUnwatched } = ctx.retention;
43
+ const { retainUnwatched, awaitingApprovalSessionKinds, roomHandoffQuestions } = ctx.retention;
44
44
  const { assertAvailable, hostedEntryForSession, entryForSession } = ctx.entries;
45
45
 
46
46
  /** A cold session's review, read from its durable turn record (the same
@@ -111,6 +111,27 @@ export function createSessionActionCalls(ctx) {
111
111
  return result;
112
112
  }
113
113
 
114
+ /** Rows with `awaitingApproval` on every session whose live runtime shows an
115
+ * approval card: a list row reads "needs you" from it whether or not any
116
+ * pane receives that session's lane. A room member's row also carries the
117
+ * handed-off questions it holds (`handoffQuestions`), which its room shows. */
118
+ function withApprovalWaits(rows) {
119
+ if (!Array.isArray(rows)) return rows;
120
+ const waiting = awaitingApprovalSessionKinds();
121
+ const questions = roomHandoffQuestions();
122
+ if (!waiting.size && !questions.size) return rows;
123
+ return rows.map((row) => {
124
+ const kind = waiting.get(row?.id);
125
+ const asked = questions.get(row?.id);
126
+ if (!kind && !asked) return row;
127
+ return {
128
+ ...row,
129
+ ...(kind ? { awaitingApproval: true, ...(kind === 'question' ? { awaitingQuestion: true } : {}) } : {}),
130
+ ...(asked ? { handoffQuestions: asked } : {}),
131
+ };
132
+ });
133
+ }
134
+
114
135
  async function listSessionCatalog(options = {}) {
115
136
  if (isClosed()) throw new Error('session service is closed');
116
137
  if (typeof listSessions !== 'function') {
@@ -124,7 +145,7 @@ export function createSessionActionCalls(ctx) {
124
145
  });
125
146
  // A `page: { limit, cursor }` request answers one page: { sessions, nextCursor }.
126
147
  const page = listed && !Array.isArray(listed) && Array.isArray(listed.sessions) ? listed : null;
127
- const sessions = page ? page.sessions : listed;
148
+ const sessions = withApprovalWaits(page ? page.sessions : listed);
128
149
  const remoteSession = typeof getRemoteSessionState === 'function' ? await getRemoteSessionState() : null;
129
150
  const nextCursor = typeof page?.nextCursor === 'string' ? page.nextCursor : null;
130
151
  return {
@@ -131,6 +131,14 @@ export function createSessionViewCalls(ctx) {
131
131
  notePrependViewer(viewer, params);
132
132
  const id = String(sessionId || '');
133
133
  if (!id) throw new TypeError('sessionId is required');
134
+ if (params.attachmentHistory === true) {
135
+ // Apart from every window: nothing here reads, fills or replaces a
136
+ // transcript projection.
137
+ const stored =
138
+ typeof readStoredSession === 'function' ? await readStoredSession(id, { attachmentHistory: true }) : null;
139
+ assertAvailable();
140
+ return { history: stored ? { items: stored.items } : null };
141
+ }
134
142
  const live = await liveEntryFor(id);
135
143
  assertAvailable(live);
136
144
  if (params.transcriptRange) {
@@ -7,6 +7,8 @@ import { summarizeToolResult } from '../runtime/shared/tool-result-summary.mjs';
7
7
  import { TOOL_OUTPUT_PAGE_BYTES, TOOL_OUTPUT_TAIL_BYTES } from '../runtime/shared/tool-output-budget.mjs';
8
8
 
9
9
  export const SESSION_TOOL_OUTPUT_BYTES = TOOL_OUTPUT_TAIL_BYTES;
10
+ // A session title as the session tool quotes it, listed or read.
11
+ export const SESSION_TITLE_LIMIT = 160;
10
12
  const MESSAGE_TEXT_LIMIT = 2000;
11
13
  const LIST_PREVIEW_LIMIT = 100;
12
14
  const outputBytes = (value) => Buffer.byteLength(JSON.stringify(value), 'utf8');
@@ -15,24 +17,30 @@ const outputBytes = (value) => Buffer.byteLength(JSON.stringify(value), 'utf8');
15
17
  * `rich` adds the owning bot, last activity, latest line and working state
16
18
  * (never for a background caller: bot-status.mjs scopedBot). `rich` may be a
17
19
  * per-row predicate: a bot gets them only for its own sessions. */
18
- export function sessionListOutput(page, limit, { rich = true } = {}) {
20
+ export function sessionListOutput(page, limit, { rich = true, cursorOf = encodeCatalogCursor } = {}) {
19
21
  const raw = page.sessions;
20
22
  const sessions = raw.slice(0, limit).map((row) => {
21
23
  // Decided first: a session that is not the caller's carries its real
22
24
  // title only, never a preview standing in for it.
23
25
  const own = typeof rich === 'function' ? rich(row) : rich;
24
26
  const title = own ? row.title || row.preview : row.title;
27
+ // Live work, for every caller: its own turn or pool row (`working`)
28
+ // reads `running` whatever the settled catalog status; an Agent session
29
+ // working for it (`agentWorking`) marks it working too.
30
+ const status = row.working === true ? 'running' : row.status;
31
+ const working = row.working === true || row.agentWorking === true ? { working: true } : {};
25
32
  const base = {
26
33
  id: row.id,
27
- ...(title ? { title: escapeHarnessTags(truncateToolText(title, 160)) } : {}),
28
- ...(row.status ? { status: row.status } : {}),
34
+ ...(title ? { title: escapeHarnessTags(truncateToolText(title, SESSION_TITLE_LIMIT)) } : {}),
35
+ ...(status ? { status } : {}),
29
36
  ...(row.cwd ? { cwd: row.cwd } : {}),
30
37
  ...(row.archived === true ? { archived: true } : {}),
31
38
  };
32
- if (!own) return base;
39
+ if (!own) return { ...base, ...working };
33
40
  // The bot it belongs to: its chat, room seat or the task's creator.
34
41
  const bot = sessionBotOf(row);
35
- const lastUsedAt = Number(row.lastUsedAt) || 0;
42
+ // A live row's latest sign of work (`liveAt`) is newer than its last settled turn.
43
+ const lastUsedAt = Math.max(Number(row.lastUsedAt) || 0, Number(row.liveAt) || 0);
36
44
  const preview = String(row.lastMessagePreview || '').replace(/\s+/g, ' ');
37
45
  return {
38
46
  ...base,
@@ -40,7 +48,7 @@ export function sessionListOutput(page, limit, { rich = true } = {}) {
40
48
  ...(lastUsedAt ? { lastUsedAt: new Date(lastUsedAt).toISOString() } : {}),
41
49
  // The latest user or assistant line, quoted data.
42
50
  ...(preview.trim() ? { preview: escapeHarnessTags(truncateToolText(preview, LIST_PREVIEW_LIMIT)) } : {}),
43
- ...(row.working === true || row.agentWorking === true ? { working: true } : {}),
51
+ ...working,
44
52
  };
45
53
  });
46
54
  const result = {
@@ -50,7 +58,7 @@ export function sessionListOutput(page, limit, { rich = true } = {}) {
50
58
  };
51
59
  for (;;) {
52
60
  if (sessions.length < raw.length && sessions.length) {
53
- result.nextCursor = encodeCatalogCursor(raw[sessions.length - 1]);
61
+ result.nextCursor = cursorOf(raw[sessions.length - 1]);
54
62
  }
55
63
  if (outputBytes(result) <= TOOL_OUTPUT_PAGE_BYTES) return result;
56
64
  if (sessions.length <= 1) throw new Error('session: one catalog row exceeds the output budget');
@@ -9,6 +9,7 @@ import { theme } from '../theme.mjs';
9
9
  import { displayModelName, effortDisplayLabel } from '../../runtime/shared/model-display.mjs';
10
10
  import { isRollingModelAlias } from '../../runtime/shared/model-alias.mjs';
11
11
  import { describeError } from '../../runtime/shared/error-presentation.mjs';
12
+ import { providerDisplayName } from '../../runtime/shared/provider-display-name.mjs';
12
13
  import { DAYBREAK_PROVIDER, daybreakBlueOn } from '../../runtime/shared/llm/openai-daybreak.mjs';
13
14
 
14
15
  export const parsedModelVersion = (id) => {
@@ -165,34 +166,8 @@ export const normalizeModelOptions = (models) => {
165
166
  return normalized;
166
167
  };
167
168
 
168
- const PROVIDER_DISPLAY_NAMES = new Map([
169
- ['openai-oauth', 'OpenAI OAuth'],
170
- ['anthropic-oauth', 'Anthropic OAuth'],
171
- ['grok-oauth', 'Grok OAuth'],
172
- ['muse-code-oauth', 'Muse Code'],
173
- ['command-code-oauth', 'Command Code'],
174
- ['mimo-oauth', 'MiMo'],
175
- ['cursor-oauth', 'Cursor OAuth'],
176
- ['devin-oauth', 'Devin'],
177
- ['antigravity-oauth', 'Antigravity OAuth'],
178
- ['openai', 'OpenAI API'],
179
- ['openai-api', 'OpenAI API'],
180
- ['anthropic', 'Anthropic API'],
181
- ['anthropic-api', 'Anthropic API'],
182
- ['gemini', 'Gemini API'],
183
- ['gemini-api', 'Gemini API'],
184
- ['xai', 'xAI API'],
185
- ['xai-api', 'xAI API'],
186
- ['deepseek', 'DeepSeek API'],
187
- ['deepseek-api', 'DeepSeek API'],
188
- ['opencode-go-oauth', 'OpenCode Go OAuth'],
189
- ['openrouter', 'OpenRouter'],
190
- ['mixdog-local', 'Local Provider'],
191
- ['default', 'Default'],
192
- ]);
193
-
194
- export const providerDisplayName = (provider) =>
195
- PROVIDER_DISPLAY_NAMES.get(String(provider || '').toLowerCase()) ?? (provider || 'Provider');
169
+ // Provider display names live in runtime/shared so error text can name the provider too.
170
+ export { providerDisplayName };
196
171
 
197
172
  export const resolveProviderDisplayName = (provider, providerNames = null) =>
198
173
  (String(provider || '')
@@ -24385,6 +24385,12 @@ var init_file_has_data = __esm({
24385
24385
  }
24386
24386
  });
24387
24387
 
24388
+ // src/runtime/shared/abort-race.mjs
24389
+ var init_abort_race = __esm({
24390
+ "src/runtime/shared/abort-race.mjs"() {
24391
+ }
24392
+ });
24393
+
24388
24394
  // src/runtime/shared/bounded-download.mjs
24389
24395
  import { createWriteStream, rmSync as rmSync2 } from "node:fs";
24390
24396
  import { Transform as Transform2 } from "node:stream";
@@ -24458,7 +24464,7 @@ async function streamResponseToFile(response, destPath, { maxBytes, expectedByte
24458
24464
  var MAX_NATIVE_BINARY_DOWNLOAD_BYTES;
24459
24465
  var init_bounded_download = __esm({
24460
24466
  "src/runtime/shared/bounded-download.mjs"() {
24461
- init_sleep();
24467
+ init_abort_race();
24462
24468
  MAX_NATIVE_BINARY_DOWNLOAD_BYTES = 256 * 1024 * 1024;
24463
24469
  }
24464
24470
  });
@@ -40971,16 +40977,7 @@ function summarizeCodeGraphResult({ text, translate }) {
40971
40977
  if (looksLikeZeroResultText(text)) return translate("No results", "No results");
40972
40978
  return null;
40973
40979
  }
40974
- function summarizeFetchResult({ text, trimmed, args, normalized, translate }) {
40975
- if (normalized === "fetch") {
40976
- const a = parseToolArgs(args);
40977
- const isChannelFetch = !firstText(a.url, a.uri) && Boolean(firstText(a.channel, a.channelId, a.chatId, a.messageId) || a.limit != null);
40978
- if (isChannelFetch) {
40979
- const n = countNonEmptyLines(text);
40980
- if (trimmed && looksLineOriented(text) && n > 0) return countLabel(translate, n, "message");
40981
- return summarizeGenericResult(text, translate);
40982
- }
40983
- }
40980
+ function summarizeFetchResult({ text }) {
40984
40981
  const status = /(?:HTTP[\s/]*\d?\.?\d?\s*|status[:\s]+)([1-5]\d{2})\b/i.exec(text) || /\b([1-5]\d{2})\s+(?:OK|Not\s+Found|Forbidden|Moved|Found|Created|No\s+Content|Bad\s+Request|Unauthorized|Internal)/.exec(
40985
40982
  text
40986
40983
  );
@@ -42494,6 +42491,22 @@ function transportErrorText(error) {
42494
42491
  return `${TRANSPORT_SENTENCES[verdict.kind]}${detail ? ` (${detail})` : ""}.`;
42495
42492
  }
42496
42493
 
42494
+ // src/runtime/shared/provider-timeout-phase.mjs
42495
+ var TIMEOUT_PHASE = Object.freeze({
42496
+ // The response headers did not arrive in the first-byte window.
42497
+ HEADERS: "headers",
42498
+ // The headers arrived, the first chunk did not.
42499
+ FIRST_CHUNK: "first-chunk",
42500
+ // A stream that already produced output went silent.
42501
+ IDLE: "idle",
42502
+ // A sign-in token refresh did not answer: an auth problem, not a slow model.
42503
+ AUTH: "auth"
42504
+ });
42505
+ function isFirstByteTimeout(err) {
42506
+ const phase = err?.timeoutPhase;
42507
+ return phase === TIMEOUT_PHASE.HEADERS || phase === TIMEOUT_PHASE.FIRST_CHUNK;
42508
+ }
42509
+
42497
42510
  // src/runtime/agent/orchestrator/providers/provider-error-kind.mjs
42498
42511
  var PROVIDER_ERROR_KINDS = Object.freeze([
42499
42512
  "overloaded",
@@ -43341,20 +43354,6 @@ function describeError(value) {
43341
43354
  };
43342
43355
  }
43343
43356
 
43344
- // src/runtime/shared/provider-timeout-phase.mjs
43345
- var TIMEOUT_PHASE = Object.freeze({
43346
- // The response headers did not arrive in the first-byte window.
43347
- HEADERS: "headers",
43348
- // The headers arrived, the first chunk did not.
43349
- FIRST_CHUNK: "first-chunk",
43350
- // A stream that already produced output went silent.
43351
- IDLE: "idle"
43352
- });
43353
- function isFirstByteTimeout(err) {
43354
- const phase = err?.timeoutPhase;
43355
- return phase === TIMEOUT_PHASE.HEADERS || phase === TIMEOUT_PHASE.FIRST_CHUNK;
43356
- }
43357
-
43358
43357
  // src/runtime/shared/err-text.mjs
43359
43358
  function errorHttpStatus(err) {
43360
43359
  return Number(err?.httpStatus || err?.status || err?.response?.status || 0) || 0;
@@ -43512,16 +43511,16 @@ function hasTypedEvidence(error) {
43512
43511
  if (!error || typeof error !== "object") return false;
43513
43512
  return Boolean(error.errorKind?.kind) || errorHttpStatus(error) > 0 || Boolean(error.code) || Boolean(error.retryAfterMs);
43514
43513
  }
43515
- var timedOutMs = (text) => Number(/timed out after (\d+)ms/i.exec(text)?.[1]) || 0;
43516
- function stillThinkingText(error, text) {
43514
+ var timedOutMs = (text) => Number(/(?:timed out after|within) (\d+)ms/i.exec(text)?.[1]) || 0;
43515
+ function stillThinkingText(error, text, providerLabel) {
43517
43516
  const ms = Number(error.waitedMs) || timedOutMs(text);
43518
- const provider = typeof error.providerLabel === "string" && error.providerLabel ? error.providerLabel : "the provider";
43517
+ const provider = typeof providerLabel === "string" && providerLabel ? providerLabel : "the provider";
43519
43518
  const attempts = Number(error.attempts) > 0 ? `; attempts: ${Math.floor(Number(error.attempts))}` : "";
43520
43519
  return `Model still thinking: no output in ${formatDurationMs(ms)}; ${provider} sent nothing yet${attempts}.`;
43521
43520
  }
43522
- function typedStreamFailureText(error, text) {
43521
+ function typedStreamFailureText(error, text, providerLabel) {
43523
43522
  if (!error || typeof error !== "object") return null;
43524
- if (isFirstByteTimeout(error)) return stillThinkingText(error, text);
43523
+ if (isFirstByteTimeout(error)) return stillThinkingText(error, text, providerLabel);
43525
43524
  if (error.timeoutPhase === TIMEOUT_PHASE.IDLE) {
43526
43525
  const ms = timedOutMs(text);
43527
43526
  return ms > 0 ? `No progress ${formatDurationMs(ms)}.` : "No progress.";
@@ -43558,7 +43557,7 @@ function presentErrorText(error, options = {}) {
43558
43557
  if (embeddedError) text = embeddedError;
43559
43558
  text = oneLine(stripErrorPrefix(text));
43560
43559
  if (!text) return "Unknown error";
43561
- const streamFailure = typedStreamFailureText(error, text);
43560
+ const streamFailure = typedStreamFailureText(error, text, options.providerLabel);
43562
43561
  if (streamFailure) return streamFailure;
43563
43562
  if (code === "PROVIDER_PREFIX_MUTATION" || name === "ProviderPrefixMutationError") {
43564
43563
  return "Session state changed unexpectedly.";
@@ -59516,6 +59515,34 @@ function isRollingModelAlias(id) {
59516
59515
  return /-latest$/i.test(String(id || "").trim());
59517
59516
  }
59518
59517
 
59518
+ // src/runtime/shared/provider-display-name.mjs
59519
+ var PROVIDER_DISPLAY_NAMES = /* @__PURE__ */ new Map([
59520
+ ["openai-oauth", "OpenAI OAuth"],
59521
+ ["anthropic-oauth", "Anthropic OAuth"],
59522
+ ["grok-oauth", "Grok OAuth"],
59523
+ ["muse-code-oauth", "Muse Code"],
59524
+ ["command-code-oauth", "Command Code"],
59525
+ ["mimo-oauth", "MiMo"],
59526
+ ["cursor-oauth", "Cursor OAuth"],
59527
+ ["devin-oauth", "Devin"],
59528
+ ["antigravity-oauth", "Antigravity OAuth"],
59529
+ ["openai", "OpenAI API"],
59530
+ ["openai-api", "OpenAI API"],
59531
+ ["anthropic", "Anthropic API"],
59532
+ ["anthropic-api", "Anthropic API"],
59533
+ ["gemini", "Gemini API"],
59534
+ ["gemini-api", "Gemini API"],
59535
+ ["xai", "xAI API"],
59536
+ ["xai-api", "xAI API"],
59537
+ ["deepseek", "DeepSeek API"],
59538
+ ["deepseek-api", "DeepSeek API"],
59539
+ ["opencode-go-oauth", "OpenCode Go OAuth"],
59540
+ ["openrouter", "OpenRouter"],
59541
+ ["mixdog-local", "Local Provider"],
59542
+ ["default", "Default"]
59543
+ ]);
59544
+ var providerDisplayName = (provider) => PROVIDER_DISPLAY_NAMES.get(String(provider || "").toLowerCase()) ?? (provider || "Provider");
59545
+
59519
59546
  // src/runtime/shared/llm/openai-daybreak.mjs
59520
59547
  var DAYBREAK_PROVIDER = "openai-oauth";
59521
59548
  var DAYBREAK_PARAMETER_ID = "daybreak";
@@ -59663,32 +59690,6 @@ var normalizeModelOptions = (models) => {
59663
59690
  }
59664
59691
  return normalized;
59665
59692
  };
59666
- var PROVIDER_DISPLAY_NAMES = /* @__PURE__ */ new Map([
59667
- ["openai-oauth", "OpenAI OAuth"],
59668
- ["anthropic-oauth", "Anthropic OAuth"],
59669
- ["grok-oauth", "Grok OAuth"],
59670
- ["muse-code-oauth", "Muse Code"],
59671
- ["command-code-oauth", "Command Code"],
59672
- ["mimo-oauth", "MiMo"],
59673
- ["cursor-oauth", "Cursor OAuth"],
59674
- ["devin-oauth", "Devin"],
59675
- ["antigravity-oauth", "Antigravity OAuth"],
59676
- ["openai", "OpenAI API"],
59677
- ["openai-api", "OpenAI API"],
59678
- ["anthropic", "Anthropic API"],
59679
- ["anthropic-api", "Anthropic API"],
59680
- ["gemini", "Gemini API"],
59681
- ["gemini-api", "Gemini API"],
59682
- ["xai", "xAI API"],
59683
- ["xai-api", "xAI API"],
59684
- ["deepseek", "DeepSeek API"],
59685
- ["deepseek-api", "DeepSeek API"],
59686
- ["opencode-go-oauth", "OpenCode Go OAuth"],
59687
- ["openrouter", "OpenRouter"],
59688
- ["mixdog-local", "Local Provider"],
59689
- ["default", "Default"]
59690
- ]);
59691
- var providerDisplayName = (provider) => PROVIDER_DISPLAY_NAMES.get(String(provider || "").toLowerCase()) ?? (provider || "Provider");
59692
59693
  var resolveProviderDisplayName = (provider, providerNames = null) => String(provider || "").trim().startsWith("custom-") && providerNames?.[String(provider).trim()] || providerDisplayName(provider);
59693
59694
  var loadProviderDisplayNames = async (store) => {
59694
59695
  let setup = null;
@@ -62368,13 +62369,6 @@ function canonicalizeStoredChannelsConfig(value = {}) {
62368
62369
  const next = isPlainObject(value) ? { ...value } : {};
62369
62370
  delete next.promptInjection;
62370
62371
  delete next.schedules;
62371
- delete next.nonInteractive;
62372
- delete next.interactive;
62373
- delete next.backend;
62374
- delete next.provider;
62375
- delete next.discord;
62376
- delete next.telegram;
62377
- delete next.channel;
62378
62372
  return next;
62379
62373
  }
62380
62374
  function canonicalizeUnifiedConfig(value = {}) {
@@ -1,4 +1,5 @@
1
1
  import { readImageAttachmentFromPath } from '../../paste-attachments.mjs';
2
+ import { PROMPT_ORIGIN_CHANNEL } from '../../../runtime/agent/orchestrator/session/manager/pending-message-entry.mjs';
2
3
 
3
4
  // Channel inbound images arrive as a JSON-array-of-paths meta value (stringified
4
5
  // across the notify IPC boundary). Parse defensively; a malformed value simply
@@ -44,6 +45,8 @@ export function createModelNotificationEnqueue({ chain, enqueue, getState, getDi
44
45
  priority: 'later',
45
46
  key: notificationKey || undefined,
46
47
  displayText: delivery.displayText || text,
48
+ // Its provenance (an inbound channel message) rides beside the mode.
49
+ ...(event?.origin === PROMPT_ORIGIN_CHANNEL ? { origin: PROMPT_ORIGIN_CHANNEL } : {}),
47
50
  };
48
51
  // Image load failed or overran its budget: still deliver the text body so
49
52
  // the notification is never silently lost.
@@ -26,6 +26,9 @@ export function createInitialSessionState({ runtime, runtimeCwd, baseRouteState
26
26
  queued: [],
27
27
  thinking: null,
28
28
  toolApproval: null,
29
+ // Approvals waiting behind the shown one (its own, and copies of sessions
30
+ // it delegated or handed work to): the dock's "1/N".
31
+ toolApprovalsWaiting: 0,
29
32
  // How the last approval ended and from which device, so every device can
30
33
  // say who answered ({ id, approved, device, at }).
31
34
  toolApprovalResult: null,
@@ -40,6 +40,8 @@ export function createNoticeSurface({ getState, set, isDisposed, pushItem, repla
40
40
  : polishNoticeText(text);
41
41
  if (!value && !options.room) return null;
42
42
  const forceTranscript = options.transcript === true;
43
+ // A message posted from the stored record keeps its stored time.
44
+ const storedAt = Number.isFinite(options.at) ? options.at : null;
43
45
  if (!forceTranscript) return pushToast(value, tone, options.ttlMs, options);
44
46
  // The agent's own message posted outside a turn (agent-home-delivery.mjs):
45
47
  // its reply row, as the stored message restores.
@@ -50,8 +52,9 @@ export function createNoticeSurface({ getState, set, isDisposed, pushItem, repla
50
52
  id,
51
53
  text: value,
52
54
  streaming: false,
53
- at: Date.now(),
55
+ at: storedAt ?? Date.now(),
54
56
  ...(options.messageId ? { messageId: options.messageId } : {}),
57
+ ...(options.posted ? { posted: true } : {}),
55
58
  });
56
59
  return id;
57
60
  }
@@ -85,6 +88,9 @@ export function createNoticeSurface({ getState, set, isDisposed, pushItem, repla
85
88
  // A held request of an unattended run (human-gate/held-message.mjs).
86
89
  ...(options.heldRequest ? { heldRequest: options.heldRequest } : {}),
87
90
  ...(options.messageId ? { messageId: options.messageId } : {}),
91
+ ...(storedAt !== null ? { at: storedAt } : {}),
92
+ // Posted outside any turn: its own turn key (transcript-turn-keys.mjs).
93
+ ...(options.posted ? { posted: true } : {}),
88
94
  });
89
95
  return id;
90
96
  };
@@ -4,7 +4,8 @@
4
4
  * flattening, session activity timestamps, and batch merging.
5
5
  */
6
6
  import { agentJobResultText, parseAgentJob, parseSyntheticAgentMessage } from './agent-envelope.mjs';
7
- import { attachmentTextForPart, isAttachmentReference } from '../../runtime/attachments/store.mjs';
7
+ import { isAttachmentReference } from '../../runtime/attachments/store.mjs';
8
+ import { promptContentText, sessionActivityTimestamp } from '../../runtime/shared/idle-auto-clear-gate.mjs';
8
9
  import { recognisedSlashToken } from '../app/slash-commands.mjs';
9
10
 
10
11
  const QUEUE_PRIORITY = { now: 0, next: 1, later: 2 };
@@ -82,47 +83,7 @@ export function notificationDisplayText(text) {
82
83
  return firstQueueLine(synthetic?.result || result || text) || 'agent notification';
83
84
  }
84
85
 
85
- export function promptContentText(content) {
86
- if (typeof content === 'string') return content;
87
- if (Array.isArray(content)) {
88
- return content
89
- .map((part) => {
90
- if (typeof part === 'string') return part;
91
- if (part?.type === 'text') return isAttachmentReference(part) ? attachmentTextForPart(part) : part.text || '';
92
- if (part?.type === 'image') return '[Image]';
93
- if (part?.type === 'file') return '[File]';
94
- return part?.text || '';
95
- })
96
- .filter(Boolean)
97
- .join('\n');
98
- }
99
- return String(content ?? '');
100
- }
101
-
102
- function timestampMs(value) {
103
- if (value == null || value === '') return 0;
104
- const n = Number(value);
105
- if (Number.isFinite(n) && n > 0) return n;
106
- const parsed = Date.parse(String(value));
107
- return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
108
- }
109
-
110
- function hasModelVisibleConversation(session) {
111
- const messages = Array.isArray(session?.messages) ? session.messages : [];
112
- return messages.some((message) => {
113
- const role = message?.role;
114
- if (role !== 'user' && role !== 'assistant' && role !== 'tool') return false;
115
- const text = promptContentText(message.content).trim();
116
- if (role === 'user' && text.startsWith('<system-reminder>')) return false;
117
- if (role === 'assistant' && text === '.' && !Array.isArray(message.toolCalls)) return false;
118
- return !!text || role === 'assistant' || role === 'tool';
119
- });
120
- }
121
-
122
- export function sessionActivityTimestamp(session, fallback = 0) {
123
- if (!hasModelVisibleConversation(session)) return 0;
124
- return timestampMs(session?.lastUsedAt) || timestampMs(session?.updatedAt) || timestampMs(fallback);
125
- }
86
+ export { promptContentText, sessionActivityTimestamp };
126
87
 
127
88
  export function promptDisplayText(content, options = {}) {
128
89
  if (typeof options.displayText === 'string' && options.displayText.trim()) return options.displayText;
@@ -2,6 +2,16 @@
2
2
  * routes-agent-definitions.mjs — the session route surface's passthroughs to
3
3
  * the runtime's agent, workflow-pack, connector and lead-identity services.
4
4
  */
5
+
6
+ /** Mixy's status with `exists`, the one rule (mixy-presence.mjs) the desktop
7
+ * answers from (main/mixy-first.ts). null when her routines cannot be read:
8
+ * the status still serves readers of her name. */
9
+ async function withMixyExists(status) {
10
+ if (!status || typeof status !== 'object') return status;
11
+ const { readMixyExists } = await import('../../../session-runtime/routine-owner.mjs');
12
+ return { ...status, exists: await readMixyExists(status).catch(() => null) };
13
+ }
14
+
5
15
  export function createAgentDefinitionApi(runtime) {
6
16
  return {
7
17
  listAgents: () => {
@@ -53,8 +63,10 @@ export function createAgentDefinitionApi(runtime) {
53
63
  saveLeadPersona: async (text) => runtime.saveLeadPersona?.(text) ?? '',
54
64
  getLeadAgentBody: () => runtime.getLeadAgentBody?.() ?? '',
55
65
  saveLeadAgentBody: async (text) => runtime.saveLeadAgentBody?.(text) ?? '',
56
- getLeadStatus: () =>
57
- runtime.getLeadStatus?.() ?? { created: null, name: '', avatar: null, homeChatted: false, route: null },
66
+ getLeadStatus: async () =>
67
+ withMixyExists(
68
+ runtime.getLeadStatus?.() ?? { created: null, name: '', avatar: null, homeChatted: false, route: null }
69
+ ),
58
70
  getLeadHomeRoute: () => runtime.getLeadHomeRoute?.() ?? null,
59
71
  saveLeadIdentity: async (payload) => runtime.saveLeadIdentity?.(payload) ?? null,
60
72
  setLeadCreated: async (created, description) => runtime.setLeadCreated?.(created, description) ?? null,
@@ -54,14 +54,18 @@ const SESSION_ONLY_KEYS = new Set(['provider', 'model', 'effort', 'fast', 'autoE
54
54
  * the tuning, or both. Completed here, inside the serialized route write,
55
55
  * against the latest selected route — so a Fast-only change keeps the effort a
56
56
  * previous write selected. `unchanged` when it asks for nothing the selected
57
- * route does not already have.
57
+ * route does not already have and the session itself already runs that model
58
+ * (a fallback hop moves the session, not the selected route).
58
59
  */
59
60
  function completeSessionOnlyRequest(request, selected) {
60
61
  const named = Boolean(request.provider || request.model);
61
62
  const target = named ? request : { ...request, provider: selected.provider, model: selected.model };
62
63
  const sameModel = target.provider === selected.provider && target.model === selected.model;
63
64
  if (!sameModel) return { request: target, unchanged: false };
65
+ const sessionOnTarget =
66
+ !selected.sessionModel || (selected.sessionProvider === target.provider && selected.sessionModel === target.model);
64
67
  const unchanged =
68
+ sessionOnTarget &&
65
69
  Object.keys(request).every((key) => SESSION_ONLY_KEYS.has(key)) &&
66
70
  (request.effort === undefined || request.effort === selected.effort) &&
67
71
  (request.fast === undefined || request.fast === (selected.fast === true)) &&
@@ -128,6 +128,7 @@ export function createSessionRouteApi(bag) {
128
128
  return result;
129
129
  }),
130
130
  getOrchestrationMode: () => runtime.getOrchestrationMode(),
131
+ getConfiguredOrchestrationMode: () => runtime.getConfiguredOrchestrationMode(),
131
132
  setOrchestrationMode: withCommandLock(async (mode, options) => {
132
133
  const result = await runtime.setOrchestrationMode(mode, options);
133
134
  publishSessionSwitches(bag, { orchestrationModeSwitch: result?.orchestrationModeSwitch });
@@ -112,12 +112,28 @@ export function createSessionSettingsApi(bag) {
112
112
  setAiSessionTitles: withCommandLock(async (enabled) => {
113
113
  return await runtime.setAiSessionTitles?.(enabled);
114
114
  }),
115
+ getCacheWarmingSettings: () => {
116
+ return runtime.getCacheWarmingSettings?.() || { enabled: true };
117
+ },
118
+ setCacheWarmingEnabled: withCommandLock(async (enabled) => {
119
+ return await runtime.setCacheWarmingEnabled?.(enabled);
120
+ }),
115
121
  getHeartbeatSettings: () => {
116
- return runtime.getHeartbeatSettings?.() || { heartbeat: true };
122
+ return runtime.getHeartbeatSettings?.() || { heartbeat: true, intervalMinutes: 60 };
117
123
  },
118
124
  setHeartbeatEnabled: withCommandLock(async (enabled) => {
119
125
  return await runtime.setHeartbeatEnabled?.(enabled);
120
126
  }),
127
+ setHeartbeatInterval: withCommandLock(async (minutes) => {
128
+ return await runtime.setHeartbeatInterval?.(minutes);
129
+ }),
130
+ // The desktop app reports the user's latest in-app input time: Mixy's
131
+ // heartbeat waits for 30 quiet minutes (mixy-heartbeat.mjs noteUserInput).
132
+ noteUserInput: async (at) => {
133
+ const { noteUserInput } = await import('../../../session-runtime/mixy-heartbeat.mjs');
134
+ noteUserInput(at);
135
+ return { ok: true };
136
+ },
121
137
  getReactionSettings: () => {
122
138
  return runtime.getReactionSettings?.() || { reactions: true };
123
139
  },
@@ -4,7 +4,7 @@
4
4
  * cleared-session UI once the active turn settles.
5
5
  */
6
6
  import { presentErrorText } from '../../../runtime/shared/err-text.mjs';
7
- import { sessionActivityTimestamp } from '../queue-helpers.mjs';
7
+ import { idleAutoClearDue, sessionActivityTimestamp } from '../../../runtime/shared/idle-auto-clear-gate.mjs';
8
8
  import { archiveItemsForCompaction, compactionArchivedRows } from '../compaction-view.mjs';
9
9
 
10
10
  // Upper bound on the awaited idle compaction. Without a bound a stalled
@@ -17,29 +17,6 @@ import { archiveItemsForCompaction, compactionArchivedRows } from '../compaction
17
17
  const AUTO_CLEAR_COMPACT_TIMEOUT_MS = 60_000;
18
18
  const LATE_COMPLETION_NOTICE = 'auto-clear completed late; compacted conversation retained';
19
19
 
20
- // A zero is often an unavailable/stale meter field, not an authoritative
21
- // measurement. Do not let it mask the sibling live estimate.
22
- function contextUsageBelowThreshold(runtime, minContextPercent) {
23
- if (!(minContextPercent > 0)) return false;
24
- const status = runtime.contextStatus?.() || null;
25
- const usedTokens = Math.max(
26
- 0,
27
- Number(status?.usedTokens) || 0,
28
- Number(status?.currentEstimatedTokens) || 0,
29
- Number(status?.compaction?.currentEstimatedTokens) || 0
30
- );
31
- const triggerTokens = Number(
32
- status?.compaction?.triggerTokens ||
33
- status?.compaction?.autoCompactTokenLimit ||
34
- runtime.session?.autoCompactTokenLimit ||
35
- 0
36
- );
37
- if (!Number.isFinite(usedTokens) || !Number.isFinite(triggerTokens) || !(usedTokens > 0 && triggerTokens > 0)) {
38
- return true;
39
- }
40
- return (usedTokens / triggerTokens) * 100 < minContextPercent;
41
- }
42
-
43
20
  export function createAutoClearOps(bag, { reset, kickDrain }) {
44
21
  const {
45
22
  runtime,
@@ -140,15 +117,9 @@ export function createAutoClearOps(bag, { reset, kickDrain }) {
140
117
  const cfg = autoClearState();
141
118
  const now = Date.now();
142
119
  const activityAt = sessionActivityTimestamp(runtime.session, flags.lastUserActivityAt);
143
- const idleMs = activityAt ? now - activityAt : 0;
144
- const notIdle =
145
- !cfg.enabled ||
146
- getState().busy ||
147
- (!ignorePending && pending.length > 0) ||
148
- flags.autoClearRunning ||
149
- flags.autoClearInFlight ||
150
- idleMs < cfg.idleMs;
151
- if (notIdle || contextUsageBelowThreshold(runtime, Number(cfg.minContextPercent ?? 10))) {
120
+ const blocked =
121
+ getState().busy || (!ignorePending && pending.length > 0) || flags.autoClearRunning || flags.autoClearInFlight;
122
+ if (blocked || !idleAutoClearDue({ cfg, activityAt, at: now, runtime })) {
152
123
  if (!activityAt) flags.lastUserActivityAt = now;
153
124
  return false;
154
125
  }