mixdog 1.3.4 → 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 (472) hide show
  1. package/LICENSES/oh-my-pi-MIT.txt +23 -0
  2. package/NOTICE.md +17 -2
  3. package/README.md +11 -0
  4. package/package.json +3 -11
  5. package/scripts/daemon-stub.mjs +1 -1
  6. package/scripts/embed-google-oauth-client.mjs +49 -0
  7. package/scripts/gate-local.mjs +4 -2
  8. package/scripts/lib/test-spawn-ledger.mjs +46 -1
  9. package/scripts/native-release-status.mjs +2 -2
  10. package/scripts/recall-history-cases.json +1 -1
  11. package/scripts/suite-health.mjs +10 -1
  12. package/scripts/test.mjs +12 -11
  13. package/src/agents/reviewer/AGENT.md +7 -11
  14. package/src/agents/reviewer/agent.json +1 -1
  15. package/src/defaults/shipped-history.json +25 -1
  16. package/src/defaults/skills/browser-use/SKILL.md +77 -17
  17. package/src/defaults/skills/code-tidy/SKILL.md +142 -270
  18. package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
  19. package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
  20. package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
  21. package/src/defaults/skills/computer-use/SKILL.md +33 -9
  22. package/src/defaults/skills/setup/SKILL.md +29 -2
  23. package/src/defaults/skills/setup/references/actions.md +117 -28
  24. package/src/defaults/skills/setup/references/surfaces.md +77 -35
  25. package/src/defaults/skills/setup-guide/SKILL.md +3 -3
  26. package/src/defaults/skills/visualize/SKILL.md +2 -1
  27. package/src/lib/keychain-cjs.cjs +359 -29
  28. package/src/lib/rules-builder.cjs +10 -8
  29. package/src/rules/agent/AGENT.md +6 -6
  30. package/src/rules/agent-mode/AGENT_MODE.md +10 -2
  31. package/src/rules/agent-mode/MIXY.md +12 -0
  32. package/src/rules/lead/LEAD.md +18 -20
  33. package/src/rules/shared/05-tool-calls.md +5 -6
  34. package/src/rules/shared/10-tool-workflow.md +2 -0
  35. package/src/rules/shared/60-verification.md +7 -5
  36. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
  37. package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +193 -0
  38. package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
  39. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
  40. package/src/runtime/agent/orchestrator/config.mjs +34 -0
  41. package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
  42. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +72 -67
  43. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +54 -1
  44. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
  45. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +177 -73
  46. package/src/runtime/agent/orchestrator/mcp/client.mjs +25 -2
  47. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +31 -2
  48. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +16 -3
  49. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +42 -7
  50. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +21 -2
  51. package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +23 -0
  52. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +11 -1
  53. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +230 -137
  54. package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +64 -7
  55. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +18 -5
  56. package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  58. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
  59. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
  60. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +160 -69
  61. package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
  62. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +64 -33
  63. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
  64. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +52 -8
  65. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +10 -1
  66. package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +22 -6
  67. package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +15 -4
  68. package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +17 -2
  69. package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +142 -104
  70. package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
  71. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  72. package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +10 -4
  73. package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +10 -217
  74. package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
  75. package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -6
  76. package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +409 -0
  77. package/src/runtime/agent/orchestrator/providers/devin-wire-families.mjs +187 -0
  78. package/src/runtime/agent/orchestrator/providers/devin-wire-identity.mjs +342 -0
  79. package/src/runtime/agent/orchestrator/providers/devin-wire-models.mjs +541 -0
  80. package/src/runtime/agent/orchestrator/providers/devin-wire-protobuf.mjs +305 -0
  81. package/src/runtime/agent/orchestrator/providers/devin-wire-request.mjs +558 -0
  82. package/src/runtime/agent/orchestrator/providers/devin-wire-schema.mjs +880 -0
  83. package/src/runtime/agent/orchestrator/providers/devin-wire-session.mjs +190 -0
  84. package/src/runtime/agent/orchestrator/providers/devin-wire-tool-args.mjs +351 -0
  85. package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +560 -0
  86. package/src/runtime/agent/orchestrator/providers/devin.mjs +491 -0
  87. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -0
  88. package/src/runtime/agent/orchestrator/providers/gemini-output-limit.mjs +46 -0
  89. package/src/runtime/agent/orchestrator/providers/gemini-reasoning-relay.mjs +30 -0
  90. package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +7 -11
  91. package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +61 -22
  92. package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -0
  93. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -4
  94. package/src/runtime/agent/orchestrator/providers/gemini.mjs +25 -2
  95. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  96. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +96 -5
  97. package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
  98. package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +23 -5
  99. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
  100. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
  101. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
  102. package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
  103. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +19 -1
  104. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +39 -3
  105. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  106. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
  107. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +6 -1
  108. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
  109. package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
  110. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
  111. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
  112. package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
  113. package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +1 -0
  114. package/src/runtime/agent/orchestrator/providers/provider-availability.mjs +19 -0
  115. package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
  116. package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
  117. package/src/runtime/agent/orchestrator/providers/registry.mjs +43 -3
  118. package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
  119. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
  120. package/src/runtime/agent/orchestrator/providers/wire-protobuf-codec.mjs +368 -0
  121. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +12 -7
  122. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
  123. package/src/runtime/agent/orchestrator/runtime-core/compaction-config-keys.mjs +62 -0
  124. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +37 -16
  125. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +100 -23
  126. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +1 -1
  127. package/src/runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs +133 -0
  128. package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -0
  129. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
  130. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
  131. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
  132. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +23 -5
  133. package/src/runtime/agent/orchestrator/runtime-core/tool-profile.mjs +35 -10
  134. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +57 -10
  135. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +9 -6
  136. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -1
  137. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +18 -0
  138. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +0 -3
  139. package/src/runtime/agent/orchestrator/session/agent-room.mjs +10 -4
  140. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +792 -0
  141. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +148 -25
  142. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
  143. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
  144. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +8 -0
  145. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +47 -9
  146. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +6 -2
  147. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
  148. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +14 -2
  149. package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +8 -0
  150. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +18 -22
  151. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +32 -3
  152. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +11 -2
  153. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -1
  154. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +51 -3
  155. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +17 -3
  156. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -2
  157. package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
  158. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +14 -4
  159. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
  160. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
  161. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +10 -0
  162. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
  163. package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +23 -5
  164. package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +60 -0
  165. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
  166. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
  167. package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +2 -0
  168. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
  169. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +14 -0
  170. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -1
  171. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
  172. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
  173. package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +23 -13
  174. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
  175. package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
  176. package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +129 -0
  177. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +20 -2
  178. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
  179. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +8 -0
  180. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
  181. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +13 -0
  182. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +7 -2
  183. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
  184. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +18 -5
  185. package/src/runtime/agent/orchestrator/session/message-ids.mjs +5 -3
  186. package/src/runtime/agent/orchestrator/session/message-reactions.mjs +89 -0
  187. package/src/runtime/agent/orchestrator/session/message-reactions.test-support.mjs +75 -0
  188. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +19 -8
  189. package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
  190. package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +127 -0
  191. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +0 -2
  192. package/src/runtime/agent/orchestrator/session/routine-result.mjs +47 -11
  193. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +20 -2
  194. package/src/runtime/agent/orchestrator/session/sensitive-projection.mjs +100 -0
  195. package/src/runtime/agent/orchestrator/session/sensitive-values.mjs +257 -0
  196. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +20 -7
  197. package/src/runtime/agent/orchestrator/session/side-question.mjs +18 -0
  198. package/src/runtime/agent/orchestrator/session/skill-update-notice.mjs +60 -0
  199. package/src/runtime/agent/orchestrator/session/store/live-state.mjs +6 -3
  200. package/src/runtime/agent/orchestrator/session/store/save-delta.mjs +9 -5
  201. package/src/runtime/agent/orchestrator/session/store/serialize.mjs +9 -8
  202. package/src/runtime/agent/orchestrator/session/store/session-persistence-events.mjs +29 -0
  203. package/src/runtime/agent/orchestrator/session/store-agent-worker-header-cache.mjs +85 -0
  204. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +133 -18
  205. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +12 -2
  206. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -14
  207. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +84 -3
  208. package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
  209. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +11 -5
  210. package/src/runtime/agent/orchestrator/session/thinking-binding.mjs +108 -0
  211. package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +2 -2
  212. package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +2 -1
  213. package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +4 -0
  214. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +5 -0
  215. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +25 -2
  216. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
  217. package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
  218. package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
  219. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
  220. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
  221. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +240 -0
  222. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
  223. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/shell-cwd.mjs +38 -0
  224. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +25 -5
  225. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +65 -7
  226. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
  227. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
  228. package/src/runtime/browser-bridge/action-schema.mjs +13 -2
  229. package/src/runtime/browser-bridge/client.mjs +73 -8
  230. package/src/runtime/browser-bridge/input-fields.mjs +8 -9
  231. package/src/runtime/browser-bridge/mail-links.mjs +107 -0
  232. package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
  233. package/src/runtime/channels/lib/config.mjs +6 -61
  234. package/src/runtime/channels/lib/crash-log.mjs +1 -1
  235. package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
  236. package/src/runtime/channels/lib/event-queue.mjs +3 -18
  237. package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
  238. package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
  239. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
  240. package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
  241. package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
  242. package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
  243. package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
  244. package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
  245. package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
  246. package/src/runtime/channels/lib/schedule-errors.mjs +51 -0
  247. package/src/runtime/channels/lib/scheduler.mjs +135 -154
  248. package/src/runtime/channels/lib/schedules-db.mjs +83 -11
  249. package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
  250. package/src/runtime/channels/lib/tool-dispatch.mjs +14 -2
  251. package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
  252. package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
  253. package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
  254. package/src/runtime/channels/lib/worker-main.mjs +19 -34
  255. package/src/runtime/computer-bridge/action-schema.mjs +42 -1
  256. package/src/runtime/computer-bridge/actions.mjs +9 -1
  257. package/src/runtime/computer-bridge/client.mjs +180 -8
  258. package/src/runtime/computer-bridge/core-actions.mjs +2 -2
  259. package/src/runtime/computer-bridge/error-recovery.mjs +27 -2
  260. package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
  261. package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
  262. package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
  263. package/src/runtime/connectors/gmail-app-password.mjs +172 -39
  264. package/src/runtime/connectors/google-mcp.mjs +10 -12
  265. package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
  266. package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
  267. package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
  268. package/src/runtime/office/com/com-adapter.mjs +17 -1
  269. package/src/runtime/office/com/office-com-host.ps1 +51 -1
  270. package/src/runtime/office/pdf/cfb-fixture.mjs +328 -0
  271. package/src/runtime/office/pdf/cfb-protection.mjs +311 -0
  272. package/src/runtime/office/pdf/document-preview.mjs +326 -8
  273. package/src/runtime/office/pdf/ooxml-crypto.mjs +469 -0
  274. package/src/runtime/office/pdf/ooxml-key-worker.mjs +14 -0
  275. package/src/runtime/office/portable/portable-soffice.mjs +45 -5
  276. package/src/runtime/session-search/session-search-db.mjs +73 -9
  277. package/src/runtime/session-search/session-search-ingest.mjs +110 -20
  278. package/src/runtime/shared/abort-race.mjs +89 -0
  279. package/src/runtime/shared/agent-avatar.d.mts +0 -1
  280. package/src/runtime/shared/agent-kind.mjs +4 -3
  281. package/src/runtime/shared/bot-hops.mjs +62 -2
  282. package/src/runtime/shared/bounded-download.mjs +8 -3
  283. package/src/runtime/shared/config.mjs +51 -35
  284. package/src/runtime/shared/connector-accounts.mjs +20 -10
  285. package/src/runtime/shared/connector-catalog.d.mts +33 -2
  286. package/src/runtime/shared/connector-catalog.mjs +166 -8
  287. package/src/runtime/shared/connector-triggers.mjs +22 -19
  288. package/src/runtime/shared/defaults-separation.mjs +2 -14
  289. package/src/runtime/shared/delegated-approval-host.mjs +103 -11
  290. package/src/runtime/shared/developer-options.mjs +32 -1
  291. package/src/runtime/shared/err-text.mjs +24 -15
  292. package/src/runtime/shared/file-permissions.d.mts +0 -8
  293. package/src/runtime/shared/file-permissions.mjs +0 -11
  294. package/src/runtime/shared/git-direct.test-support.mjs +19 -0
  295. package/src/runtime/shared/google-oauth-client.generated.json +4 -0
  296. package/src/runtime/shared/google-oauth-client.mjs +34 -9
  297. package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
  298. package/src/runtime/shared/heartbeat-interval.mjs +19 -0
  299. package/src/runtime/shared/idle-auto-clear-gate.mjs +104 -0
  300. package/src/runtime/shared/llm/anthropic-betas.mjs +7 -0
  301. package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +12 -0
  302. package/src/runtime/shared/llm/provider-catalog-registry.mjs +1 -0
  303. package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
  304. package/src/runtime/shared/llm/well-formed.mjs +66 -0
  305. package/src/runtime/shared/mixy-presence.mjs +22 -0
  306. package/src/runtime/shared/orchestration.d.mts +2 -0
  307. package/src/runtime/shared/pg-schema-db.mjs +27 -16
  308. package/src/runtime/shared/profile-config.cjs +1 -1
  309. package/src/runtime/shared/prompt-origin.d.mts +4 -0
  310. package/src/runtime/shared/prompt-origin.mjs +21 -0
  311. package/src/runtime/shared/provider-accounts.mjs +231 -59
  312. package/src/runtime/shared/provider-api-key.mjs +19 -8
  313. package/src/runtime/shared/provider-display-name.mjs +29 -0
  314. package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
  315. package/src/runtime/shared/routine-trigger.d.mts +2 -0
  316. package/src/runtime/shared/routine-trigger.mjs +52 -0
  317. package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
  318. package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
  319. package/src/runtime/shared/session-activity-signal.mjs +34 -1
  320. package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
  321. package/src/runtime/shared/session-sidebar-host.mjs +7 -3
  322. package/src/runtime/shared/session-turn-prelude.mjs +18 -0
  323. package/src/runtime/shared/tool-execution-contract.mjs +2 -0
  324. package/src/runtime/shared/tool-result-summary.mjs +1 -14
  325. package/src/runtime/shared/transcript-metadata.mjs +38 -0
  326. package/src/runtime/shared/user-data-guard.mjs +30 -2
  327. package/src/runtime/shared/worktrees/activity-gate.mjs +12 -5
  328. package/src/runtime/shared/worktrees/test-support.mjs +9 -4
  329. package/src/runtime/terminal-bridge/client.mjs +10 -1
  330. package/src/runtime/visualize-bridge/client.mjs +27 -8
  331. package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
  332. package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
  333. package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
  334. package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
  335. package/src/session-runtime/agent-home-delivery.mjs +486 -179
  336. package/src/session-runtime/agent-room-delivery.mjs +28 -1
  337. package/src/session-runtime/agent-task-sessions.mjs +561 -199
  338. package/src/session-runtime/boot/apis.mjs +9 -0
  339. package/src/session-runtime/boot/begin.mjs +3 -2
  340. package/src/session-runtime/boot/infrastructure.mjs +4 -0
  341. package/src/session-runtime/boot/providers.mjs +3 -0
  342. package/src/session-runtime/boot/tools.mjs +8 -1
  343. package/src/session-runtime/bot-chain.mjs +32 -0
  344. package/src/session-runtime/bot-status.mjs +7 -4
  345. package/src/session-runtime/channel-config-api.mjs +63 -17
  346. package/src/session-runtime/config-lifecycle.mjs +6 -0
  347. package/src/session-runtime/connector-merge-migration.mjs +305 -0
  348. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +132 -28
  349. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +2 -0
  350. package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +45 -0
  351. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +72 -5
  352. package/src/session-runtime/internal-tool-executor.mjs +4 -0
  353. package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
  354. package/src/session-runtime/lifecycle/session-catalog.mjs +3 -1
  355. package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
  356. package/src/session-runtime/lifecycle/teardown.mjs +23 -5
  357. package/src/session-runtime/mcp-glue/server-catalog.mjs +61 -3
  358. package/src/session-runtime/mcp-oauth-login.mjs +5 -3
  359. package/src/session-runtime/mixy-heartbeat.mjs +927 -0
  360. package/src/session-runtime/model-route/route-tuning.mjs +10 -6
  361. package/src/session-runtime/notification-bus.mjs +31 -117
  362. package/src/session-runtime/notification-completion-queue.mjs +54 -0
  363. package/src/session-runtime/notification-listeners.mjs +76 -0
  364. package/src/session-runtime/owned-automation-run.mjs +35 -13
  365. package/src/session-runtime/prewarm/channel-start.mjs +3 -7
  366. package/src/session-runtime/provider-auth/login.mjs +7 -0
  367. package/src/session-runtime/provider-models/row-hydration.mjs +13 -2
  368. package/src/session-runtime/resource-mcp-api.mjs +143 -224
  369. package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
  370. package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
  371. package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
  372. package/src/session-runtime/resource-mcp-servers.mjs +78 -0
  373. package/src/session-runtime/resource-mcp-store.mjs +49 -0
  374. package/src/session-runtime/routine-home-turn.mjs +33 -6
  375. package/src/session-runtime/routine-owner.mjs +40 -9
  376. package/src/session-runtime/schedule-session-run.mjs +7 -3
  377. package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
  378. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +8 -12
  379. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +7 -2
  380. package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
  381. package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
  382. package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
  383. package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
  384. package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
  385. package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
  386. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
  387. package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
  388. package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
  389. package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
  390. package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
  391. package/src/session-runtime/services/channel-admin.mjs +73 -31
  392. package/src/session-runtime/services/channel-session-router.mjs +4 -2
  393. package/src/session-runtime/services/channel-worker.mjs +1 -1
  394. package/src/session-runtime/services/provider-admin.mjs +128 -25
  395. package/src/session-runtime/services/schedule-access.mjs +14 -0
  396. package/src/session-runtime/services/seeds.mjs +0 -28
  397. package/src/session-runtime/services/usage-dashboard-model.mjs +1 -0
  398. package/src/session-runtime/session-compaction-sync.mjs +27 -0
  399. package/src/session-runtime/session-create/session-options.mjs +8 -4
  400. package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
  401. package/src/session-runtime/settings-compaction-api.mjs +2 -40
  402. package/src/session-runtime/settings-system-api.mjs +28 -1
  403. package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
  404. package/src/session-runtime/setup-tool/executor.mjs +187 -29
  405. package/src/session-runtime/setup-tool/extended-actions.mjs +33 -2
  406. package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
  407. package/src/session-runtime/setup-tool/settings-contract.mjs +68 -6
  408. package/src/session-runtime/setup-tool/tool-defs.mjs +92 -6
  409. package/src/session-runtime/task-session-route.mjs +99 -0
  410. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
  411. package/src/session-runtime/tool-policy/policy-stage.mjs +21 -4
  412. package/src/session-runtime/tool-policy/surface-helpers.mjs +2 -3
  413. package/src/session-runtime/tool-surface.mjs +4 -0
  414. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
  415. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +98 -21
  416. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
  417. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -1
  418. package/src/session-runtime/workspace/transitions.mjs +10 -2
  419. package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
  420. package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
  421. package/src/standalone/channel-transport/client-registry.mjs +24 -163
  422. package/src/standalone/channel-transport.mjs +1 -1
  423. package/src/standalone/daemon-channels-loader.mjs +10 -8
  424. package/src/standalone/daemon-session-control/list-page.mjs +72 -0
  425. package/src/standalone/daemon-session-control/request.mjs +51 -0
  426. package/src/standalone/daemon-session-control/room-host.mjs +57 -0
  427. package/src/standalone/daemon-session-control/route-control.mjs +48 -0
  428. package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
  429. package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
  430. package/src/standalone/daemon-session-control.mjs +161 -157
  431. package/src/standalone/daemon.mjs +33 -2
  432. package/src/standalone/session-client.mjs +7 -3
  433. package/src/standalone/session-protocol.mjs +10 -0
  434. package/src/standalone/session-service/agent-tree/agent-cancel.mjs +6 -2
  435. package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
  436. package/src/standalone/session-service/quota-resume.mjs +3 -0
  437. package/src/standalone/session-service/retention/busy.mjs +65 -1
  438. package/src/standalone/session-service/session-calls/session-action.mjs +23 -2
  439. package/src/standalone/session-service/session-calls/session-turns.mjs +6 -0
  440. package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
  441. package/src/standalone/session-service.mjs +13 -0
  442. package/src/standalone/session-tool-output.mjs +21 -10
  443. package/src/tui/app/model-options.mjs +4 -27
  444. package/src/tui/dist/index.mjs +81 -65
  445. package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
  446. package/src/tui/session/initial-state.mjs +3 -0
  447. package/src/tui/session/notice-surface.mjs +23 -1
  448. package/src/tui/session/queue-helpers.mjs +3 -42
  449. package/src/tui/session/session-api/integrations.mjs +1 -0
  450. package/src/tui/session/session-api/lifecycle.mjs +8 -0
  451. package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
  452. package/src/tui/session/session-api/routes-write.mjs +5 -1
  453. package/src/tui/session/session-api/routes.mjs +1 -0
  454. package/src/tui/session/session-api/settings.mjs +30 -2
  455. package/src/tui/session/session-flow/auto-clear.mjs +4 -33
  456. package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
  457. package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
  458. package/src/tui/session/session-flow/drain-retry.mjs +35 -0
  459. package/src/tui/session/session-flow/drain.mjs +118 -149
  460. package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
  461. package/src/tui/session/session-flow/queue/take-entries.mjs +5 -2
  462. package/src/tui/session/tool-approval-delegation.mjs +64 -0
  463. package/src/tui/session/tool-approval-request.mjs +39 -0
  464. package/src/tui/session/tool-approval-settle.mjs +62 -0
  465. package/src/tui/session/tool-approval.mjs +69 -115
  466. package/src/tui/session/tui-steering-persist.mjs +8 -1
  467. package/src/tui/session/turn-stream.mjs +36 -3
  468. package/src/tui/session/turn.mjs +23 -2
  469. package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
  470. package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
  471. package/scripts/code-graph-description-contract.mjs +0 -188
  472. package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
@@ -7,6 +7,17 @@
7
7
  * turn. The eviction sweep that consumes this lives in ../retention.mjs.
8
8
  */
9
9
  import { activeBackgroundTaskSessionIds, hasActiveBackgroundTasks } from '../../../runtime/shared/background-tasks.mjs';
10
+ import { emitSessionApprovalCardChange } from '../../../runtime/shared/session-activity-signal.mjs';
11
+ import { roomMemberOfSession } from '../../../runtime/agent/orchestrator/session/agent-room.mjs';
12
+
13
+ /** A room member session's copies of the questions of sessions it handed work
14
+ * to (tui/session/tool-approval.mjs `handoffQuestions`); empty for any other
15
+ * session. The room shows them from the member's catalog row (agent-rooms.ts),
16
+ * as no view watches a member session. */
17
+ function roomHandoffQuestionsOf(sessionId, state) {
18
+ if (!roomMemberOfSession(sessionId)) return [];
19
+ return Array.isArray(state?.handoffQuestions) ? state.handoffQuestions : [];
20
+ }
10
21
 
11
22
  export function createBusyTracker({ sessions, currentSessionId }) {
12
23
  function stateBusy(state) {
@@ -18,9 +29,54 @@ export function createBusyTracker({ sessions, currentSessionId }) {
18
29
  function updateEntryBusy(entry, state) {
19
30
  const next = stateBusy(state);
20
31
  entry.busy = next;
32
+ // Every runtime state change passes here, watched or headless: a session
33
+ // that starts or stops showing an approval card (any kind, a sub-agent's
34
+ // delegated copy included) announces it, so the session catalog — the one
35
+ // status source every list row has, open pane or not — re-reads it.
36
+ const awaitingApproval = Boolean(state?.toolApproval);
37
+ const awaitingQuestion = state?.toolApproval?.kind === 'question';
38
+ // A room member's handed-off questions coming and going re-read it too.
39
+ const sessionId = currentSessionId(entry) || '';
40
+ const handoffQuestions = roomHandoffQuestionsOf(sessionId, state)
41
+ .map((question) => String(question?.id ?? ''))
42
+ .join('\n');
43
+ if (
44
+ awaitingApproval !== (entry.awaitingApproval === true) ||
45
+ awaitingQuestion !== (entry.awaitingQuestion === true) ||
46
+ handoffQuestions !== (entry.handoffQuestions ?? '')
47
+ ) {
48
+ entry.awaitingApproval = awaitingApproval;
49
+ entry.awaitingQuestion = awaitingQuestion;
50
+ entry.handoffQuestions = handoffQuestions;
51
+ emitSessionApprovalCardChange(sessionId);
52
+ }
21
53
  return next;
22
54
  }
23
55
 
56
+ /** Room member session id -> its pending handed-off question copies, for
57
+ * every live member runtime holding one. */
58
+ function roomHandoffQuestions() {
59
+ const byMember = new Map();
60
+ for (const entry of sessions) {
61
+ const sessionId = currentSessionId(entry);
62
+ const questions = sessionId ? roomHandoffQuestionsOf(sessionId, entry.runtime?.getState?.()) : [];
63
+ if (questions.length) byMember.set(sessionId, questions);
64
+ }
65
+ return byMember;
66
+ }
67
+
68
+ /** Session id -> the kind of its pending card ('approval' | 'question') for
69
+ * every session whose live runtime shows one waiting on the user. */
70
+ function awaitingApprovalSessionKinds() {
71
+ const kinds = new Map();
72
+ for (const entry of sessions) {
73
+ const sessionId = currentSessionId(entry);
74
+ const pending = sessionId ? entry.runtime?.getState?.()?.toolApproval : null;
75
+ if (pending) kinds.set(sessionId, pending.kind === 'question' ? 'question' : 'approval');
76
+ }
77
+ return kinds;
78
+ }
79
+
24
80
  function sessionBusy(entry) {
25
81
  const sessionId = currentSessionId(entry);
26
82
  // Detached views do not make their background commands disposable. Keep
@@ -65,5 +121,13 @@ export function createBusyTracker({ sessions, currentSessionId }) {
65
121
  return count;
66
122
  }
67
123
 
68
- return { stateBusy, updateEntryBusy, sessionBusy, liveBusyCount, liveTurnBusyCount };
124
+ return {
125
+ stateBusy,
126
+ updateEntryBusy,
127
+ awaitingApprovalSessionKinds,
128
+ roomHandoffQuestions,
129
+ sessionBusy,
130
+ liveBusyCount,
131
+ liveTurnBusyCount,
132
+ };
69
133
  }
@@ -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 {
@@ -128,6 +128,12 @@ export function createSessionTurnCalls(ctx) {
128
128
  const accepted = await Promise.resolve(target.call(entry.runtime, intake.prompt, submissionOptions));
129
129
  if (accepted === true) {
130
130
  entry.reservedOnly = false;
131
+ if (isUserTurn(submissionOptions)) {
132
+ // The user is active: Mixy's due heartbeat check waits for quiet.
133
+ void import('../../../session-runtime/mixy-heartbeat.mjs')
134
+ .then(({ noteUserTurn }) => noteUserTurn())
135
+ .catch((error) => log(`heartbeat activity note failed: ${error?.message || error}`));
136
+ }
131
137
  if (isAgentHomeSessionId(id) && isUserTurn(submissionOptions)) {
132
138
  // The user spoke in this agent's home: its round trips with other
133
139
  // sessions count from zero again, so a capped thread wakes again.
@@ -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) {
@@ -274,6 +274,18 @@ export function createSessionService({
274
274
  return true;
275
275
  }
276
276
 
277
+ /** Show the reactions now on message `messageId` in the hosted runtime of
278
+ * `sessionId` and publish them to its views; false when no runtime hosts
279
+ * it or its live rows do not hold that message. */
280
+ function setLiveMessageReactions(sessionId, messageId, reactions) {
281
+ const owner = projection.sessionOwner(sessionId);
282
+ if (typeof owner?.runtime?.setMessageReactions !== 'function') return false;
283
+ if (!owner.runtime.setMessageReactions(messageId, reactions)) return false;
284
+ const step = projection.advance(owner);
285
+ if (step.changed) projection.publishStep(owner, step);
286
+ return true;
287
+ }
288
+
277
289
  function getStatus() {
278
290
  const busy = retention.liveBusyCount();
279
291
  let watched = 0;
@@ -322,6 +334,7 @@ export function createSessionService({
322
334
  liveSessionBusy,
323
335
  liveSessionAwaitingApproval,
324
336
  pushLiveSessionNotice,
337
+ setLiveMessageReactions,
325
338
  stop,
326
339
  startQuotaResume: () => quotaResume?.start(),
327
340
  runDueQuotaResumes: () => quotaResume?.tick() ?? Promise.resolve(),
@@ -7,29 +7,40 @@ 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');
13
15
 
14
16
  /** Keep catalog paging authoritative even when the output budget shortens a page.
15
17
  * `rich` adds the owning bot, last activity, latest line and working state
16
- * (never for a background caller: bot-status.mjs scopedBot). */
17
- export function sessionListOutput(page, limit, { rich = true } = {}) {
18
+ * (never for a background caller: bot-status.mjs scopedBot). `rich` may be a
19
+ * per-row predicate: a bot gets them only for its own sessions. */
20
+ export function sessionListOutput(page, limit, { rich = true, cursorOf = encodeCatalogCursor } = {}) {
18
21
  const raw = page.sessions;
19
22
  const sessions = raw.slice(0, limit).map((row) => {
23
+ // Decided first: a session that is not the caller's carries its real
24
+ // title only, never a preview standing in for it.
25
+ const own = typeof rich === 'function' ? rich(row) : rich;
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 } : {};
20
32
  const base = {
21
33
  id: row.id,
22
- ...(row.title || row.preview
23
- ? { title: escapeHarnessTags(truncateToolText(row.title || row.preview, 160)) }
24
- : {}),
25
- ...(row.status ? { status: row.status } : {}),
34
+ ...(title ? { title: escapeHarnessTags(truncateToolText(title, SESSION_TITLE_LIMIT)) } : {}),
35
+ ...(status ? { status } : {}),
26
36
  ...(row.cwd ? { cwd: row.cwd } : {}),
27
37
  ...(row.archived === true ? { archived: true } : {}),
28
38
  };
29
- if (!rich) return base;
39
+ if (!own) return { ...base, ...working };
30
40
  // The bot it belongs to: its chat, room seat or the task's creator.
31
41
  const bot = sessionBotOf(row);
32
- 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);
33
44
  const preview = String(row.lastMessagePreview || '').replace(/\s+/g, ' ');
34
45
  return {
35
46
  ...base,
@@ -37,7 +48,7 @@ export function sessionListOutput(page, limit, { rich = true } = {}) {
37
48
  ...(lastUsedAt ? { lastUsedAt: new Date(lastUsedAt).toISOString() } : {}),
38
49
  // The latest user or assistant line, quoted data.
39
50
  ...(preview.trim() ? { preview: escapeHarnessTags(truncateToolText(preview, LIST_PREVIEW_LIMIT)) } : {}),
40
- ...(row.working === true || row.agentWorking === true ? { working: true } : {}),
51
+ ...working,
41
52
  };
42
53
  });
43
54
  const result = {
@@ -47,7 +58,7 @@ export function sessionListOutput(page, limit, { rich = true } = {}) {
47
58
  };
48
59
  for (;;) {
49
60
  if (sessions.length < raw.length && sessions.length) {
50
- result.nextCursor = encodeCatalogCursor(raw[sessions.length - 1]);
61
+ result.nextCursor = cursorOf(raw[sessions.length - 1]);
51
62
  }
52
63
  if (outputBytes(result) <= TOOL_OUTPUT_PAGE_BYTES) return result;
53
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,33 +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
- ['antigravity-oauth', 'Antigravity OAuth'],
177
- ['openai', 'OpenAI API'],
178
- ['openai-api', 'OpenAI API'],
179
- ['anthropic', 'Anthropic API'],
180
- ['anthropic-api', 'Anthropic API'],
181
- ['gemini', 'Gemini API'],
182
- ['gemini-api', 'Gemini API'],
183
- ['xai', 'xAI API'],
184
- ['xai-api', 'xAI API'],
185
- ['deepseek', 'DeepSeek API'],
186
- ['deepseek-api', 'DeepSeek API'],
187
- ['opencode-go-oauth', 'OpenCode Go OAuth'],
188
- ['openrouter', 'OpenRouter'],
189
- ['mixdog-local', 'Local Provider'],
190
- ['default', 'Default'],
191
- ]);
192
-
193
- export const providerDisplayName = (provider) =>
194
- 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 };
195
171
 
196
172
  export const resolveProviderDisplayName = (provider, providerNames = null) =>
197
173
  (String(provider || '')
@@ -279,6 +255,7 @@ const PROVIDER_DISPLAY_RANKS = {
279
255
  'mimo-oauth': 34,
280
256
  'antigravity-oauth': 31,
281
257
  'cursor-oauth': 32,
258
+ 'devin-oauth': 32.5,
282
259
  'opencode-go-oauth': 34.5,
283
260
  openai: 40,
284
261
  'openai-api': 40,
@@ -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.";
@@ -51347,6 +51346,7 @@ var PROVIDER_CATALOGS = Object.freeze({
51347
51346
  rosterLimitsAuthoritative: true
51348
51347
  },
51349
51348
  "cursor-oauth": { relay: true },
51349
+ "devin-oauth": { relay: true },
51350
51350
  "cursor-api": { relay: true },
51351
51351
  // The models.dev listing id of the Go gateway: a relay catalog, not a
51352
51352
  // selectable provider (the model lookup needs it flagged as a relay).
@@ -59515,6 +59515,34 @@ function isRollingModelAlias(id) {
59515
59515
  return /-latest$/i.test(String(id || "").trim());
59516
59516
  }
59517
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
+
59518
59546
  // src/runtime/shared/llm/openai-daybreak.mjs
59519
59547
  var DAYBREAK_PROVIDER = "openai-oauth";
59520
59548
  var DAYBREAK_PARAMETER_ID = "daybreak";
@@ -59662,31 +59690,6 @@ var normalizeModelOptions = (models) => {
59662
59690
  }
59663
59691
  return normalized;
59664
59692
  };
59665
- var PROVIDER_DISPLAY_NAMES = /* @__PURE__ */ new Map([
59666
- ["openai-oauth", "OpenAI OAuth"],
59667
- ["anthropic-oauth", "Anthropic OAuth"],
59668
- ["grok-oauth", "Grok OAuth"],
59669
- ["muse-code-oauth", "Muse Code"],
59670
- ["command-code-oauth", "Command Code"],
59671
- ["mimo-oauth", "MiMo"],
59672
- ["cursor-oauth", "Cursor OAuth"],
59673
- ["antigravity-oauth", "Antigravity OAuth"],
59674
- ["openai", "OpenAI API"],
59675
- ["openai-api", "OpenAI API"],
59676
- ["anthropic", "Anthropic API"],
59677
- ["anthropic-api", "Anthropic API"],
59678
- ["gemini", "Gemini API"],
59679
- ["gemini-api", "Gemini API"],
59680
- ["xai", "xAI API"],
59681
- ["xai-api", "xAI API"],
59682
- ["deepseek", "DeepSeek API"],
59683
- ["deepseek-api", "DeepSeek API"],
59684
- ["opencode-go-oauth", "OpenCode Go OAuth"],
59685
- ["openrouter", "OpenRouter"],
59686
- ["mixdog-local", "Local Provider"],
59687
- ["default", "Default"]
59688
- ]);
59689
- var providerDisplayName = (provider) => PROVIDER_DISPLAY_NAMES.get(String(provider || "").toLowerCase()) ?? (provider || "Provider");
59690
59693
  var resolveProviderDisplayName = (provider, providerNames = null) => String(provider || "").trim().startsWith("custom-") && providerNames?.[String(provider).trim()] || providerDisplayName(provider);
59691
59694
  var loadProviderDisplayNames = async (store) => {
59692
59695
  let setup = null;
@@ -59754,6 +59757,7 @@ var PROVIDER_DISPLAY_RANKS = {
59754
59757
  "mimo-oauth": 34,
59755
59758
  "antigravity-oauth": 31,
59756
59759
  "cursor-oauth": 32,
59760
+ "devin-oauth": 32.5,
59757
59761
  "opencode-go-oauth": 34.5,
59758
59762
  openai: 40,
59759
59763
  "openai-api": 40,
@@ -62131,12 +62135,30 @@ function markUserDataInitialized(dataDir2) {
62131
62135
  }
62132
62136
  var ensuredDataDirs = /* @__PURE__ */ new Set();
62133
62137
  function ensureUserDataInitialized(dataDir2) {
62134
- if (!dataDir2) return;
62138
+ if (!dataDir2 || skipBackups()) return;
62135
62139
  const key = normalizeDataDir(dataDir2);
62136
62140
  if (ensuredDataDirs.has(key)) return;
62137
- if (!hasUserDataInitMarker(dataDir2)) backupUserData(dataDir2, "initial-snapshot");
62141
+ if (!hasPublishedBackup(dataDir2)) {
62142
+ backupUserData(dataDir2, "initial-snapshot");
62143
+ if (!hasPublishedBackup(dataDir2)) return;
62144
+ }
62138
62145
  ensuredDataDirs.add(key);
62139
62146
  }
62147
+ function hasPublishedBackup(dataDir2) {
62148
+ const instanceId = readInitInstanceId(dataDir2);
62149
+ if (!instanceId) return false;
62150
+ const key = normalizeDataDir(dataDir2);
62151
+ const scopeDir = scopeDirFor(dataDir2);
62152
+ return listBackupDirsNewestFirst(scopeDir).some((name) => {
62153
+ try {
62154
+ const manifest = JSON.parse(readFileSync10(manifestPath(scopeDir, name), "utf8"));
62155
+ return typeof manifest?.dataDir === "string" && normalizeDataDir(manifest.dataDir) === key && manifest.instanceId === instanceId;
62156
+ } catch (error) {
62157
+ if (isAbsentBackupError(error)) return false;
62158
+ throw error;
62159
+ }
62160
+ });
62161
+ }
62140
62162
  function skipBackups() {
62141
62163
  return process.env.MIXDOG_SKIP_USER_DATA_BACKUP === "1" || process.env.MIXDOG_SKIP_USER_DATA_BACKUP === "true";
62142
62164
  }
@@ -62270,6 +62292,7 @@ var {
62270
62292
  setSecret: _setSecret,
62271
62293
  deleteSecret: _deleteSecret,
62272
62294
  hasSecret: _hasSecret,
62295
+ hasFallbackSecret: _hasFallbackSecret,
62273
62296
  setSecretAsync: _setSecretAsyncImpl,
62274
62297
  deleteSecretAsync: _deleteSecretAsyncImpl,
62275
62298
  keychainStatus: _keychainStatus,
@@ -62346,13 +62369,6 @@ function canonicalizeStoredChannelsConfig(value = {}) {
62346
62369
  const next = isPlainObject(value) ? { ...value } : {};
62347
62370
  delete next.promptInjection;
62348
62371
  delete next.schedules;
62349
- delete next.nonInteractive;
62350
- delete next.interactive;
62351
- delete next.backend;
62352
- delete next.provider;
62353
- delete next.discord;
62354
- delete next.telegram;
62355
- delete next.channel;
62356
62372
  return next;
62357
62373
  }
62358
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,
@@ -35,10 +35,29 @@ export function createNoticeSurface({ getState, set, isDisposed, pushItem, repla
35
35
  // A routine result is a finished sentence, never a raw error to polish;
36
36
  // a group-room row is someone's words, kept verbatim (a pass has none).
37
37
  const value =
38
- options.routine || options.room || options.heldRequest ? String(text ?? '').trim() : polishNoticeText(text);
38
+ options.routine || options.room || options.heldRequest || options.assistant
39
+ ? String(text ?? '').trim()
40
+ : polishNoticeText(text);
39
41
  if (!value && !options.room) return null;
40
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;
41
45
  if (!forceTranscript) return pushToast(value, tone, options.ttlMs, options);
46
+ // The agent's own message posted outside a turn (agent-home-delivery.mjs):
47
+ // its reply row, as the stored message restores.
48
+ if (options.assistant) {
49
+ const id = options.messageId || nextId();
50
+ pushItem({
51
+ kind: 'assistant',
52
+ id,
53
+ text: value,
54
+ streaming: false,
55
+ at: storedAt ?? Date.now(),
56
+ ...(options.messageId ? { messageId: options.messageId } : {}),
57
+ ...(options.posted ? { posted: true } : {}),
58
+ });
59
+ return id;
60
+ }
42
61
  const userRow = options.room?.kind === 'user';
43
62
  // A room user row keeps its message id (the sender's submission id), as a
44
63
  // turn's own prompt row keeps its submission id.
@@ -69,6 +88,9 @@ export function createNoticeSurface({ getState, set, isDisposed, pushItem, repla
69
88
  // A held request of an unattended run (human-gate/held-message.mjs).
70
89
  ...(options.heldRequest ? { heldRequest: options.heldRequest } : {}),
71
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 } : {}),
72
94
  });
73
95
  return id;
74
96
  };