mixdog 1.2.5 → 1.3.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 (493) hide show
  1. package/LICENSES/simple-icons-CC0-1.0.txt +30 -0
  2. package/NOTICE.md +19 -0
  3. package/package.json +4 -1
  4. package/scripts/check-model-recommendations.mjs +89 -0
  5. package/scripts/gate-local.mjs +7 -0
  6. package/scripts/lib/gate-scheduler.mjs +2 -2
  7. package/scripts/lib/isolated-test-env.mjs +16 -0
  8. package/scripts/lib/run-node-tests.mjs +5 -14
  9. package/scripts/provider-pingpong-live.mjs +9 -9
  10. package/src/agents/advisor/AGENT.md +4 -4
  11. package/src/agents/advisor/agent.json +1 -1
  12. package/src/agents/reviewer/AGENT.md +5 -4
  13. package/src/agents/reviewer/agent.json +1 -1
  14. package/src/defaults/shipped-history.json +17 -0
  15. package/src/defaults/skills/browser-use/SKILL.md +7 -1
  16. package/src/defaults/skills/computer-use/SKILL.md +3 -1
  17. package/src/defaults/skills/memory-management/SKILL.md +4 -1
  18. package/src/defaults/skills/setup/references/actions.md +11 -4
  19. package/src/defaults/skills/setup-guide/SKILL.md +175 -0
  20. package/src/defaults/skills/setup-guide/model-recommendations.json +333 -0
  21. package/src/defaults/skills/visualize/SKILL.md +3 -2
  22. package/src/lib/rules-builder.cjs +56 -7
  23. package/src/output-styles/common.md +22 -6
  24. package/src/output-styles/detailed.md +7 -5
  25. package/src/output-styles/minimal.md +7 -3
  26. package/src/output-styles/simple.md +2 -3
  27. package/src/rules/agent/AGENT.md +7 -1
  28. package/src/rules/agent-mode/AGENT_MODE.md +24 -0
  29. package/src/rules/agent-mode/MIXY.md +21 -0
  30. package/src/rules/agent-mode/ROUTINE.md +6 -0
  31. package/src/rules/lead/LEAD.md +9 -4
  32. package/src/rules/shared/10-tool-workflow.md +2 -1
  33. package/src/rules/shared/60-verification.md +4 -5
  34. package/src/rules/shared/70-delivery.md +3 -0
  35. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -1
  36. package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +86 -0
  37. package/src/runtime/agent/orchestrator/config.mjs +6 -0
  38. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +77 -14
  39. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +182 -13
  40. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +5 -3
  41. package/src/runtime/agent/orchestrator/internal-agents.mjs +10 -0
  42. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +215 -0
  43. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +58 -64
  44. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +10 -1
  45. package/src/runtime/agent/orchestrator/mcp/client.mjs +122 -15
  46. package/src/runtime/agent/orchestrator/mcp/oauth-account.mjs +97 -0
  47. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +2 -3
  48. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +49 -0
  49. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +59 -9
  50. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +32 -7
  51. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +45 -6
  52. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +195 -6
  53. package/src/runtime/agent/orchestrator/mcp/server-connectors.mjs +17 -0
  54. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +9 -2
  55. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  56. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +41 -19
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +3 -2
  58. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +4 -1
  59. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +2 -0
  60. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn.mjs +3 -0
  61. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -1
  62. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -1
  63. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +11 -5
  64. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +4 -0
  65. package/src/runtime/agent/orchestrator/providers/catalog-deadline.mjs +163 -0
  66. package/src/runtime/agent/orchestrator/providers/catalog-failures.mjs +34 -0
  67. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  68. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +38 -14
  69. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +100 -26
  70. package/src/runtime/agent/orchestrator/providers/lib/send-callbacks.mjs +24 -0
  71. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -0
  72. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +2 -1
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +4 -0
  75. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  76. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +49 -4
  78. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +0 -7
  79. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +7 -1
  80. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  81. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -0
  82. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  83. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +17 -12
  84. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +5 -1
  85. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +11 -2
  86. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +1 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +45 -16
  88. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -0
  89. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +1 -0
  90. package/src/runtime/agent/orchestrator/providers/openai-ws-connect.mjs +196 -0
  91. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +74 -9
  92. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +14 -1
  93. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
  94. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-login.mjs +194 -0
  95. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-tokens.mjs +353 -0
  96. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +293 -0
  97. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +33 -100
  98. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +23 -14
  99. package/src/runtime/agent/orchestrator/providers/registry.mjs +41 -27
  100. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +98 -4
  101. package/src/runtime/agent/orchestrator/runtime-core/context-status-shape.mjs +4 -0
  102. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +6 -4
  103. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +15 -8
  104. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -0
  105. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +12 -6
  106. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +32 -5
  107. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -4
  108. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +4 -1
  109. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +50 -20
  110. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +2 -0
  111. package/src/runtime/agent/orchestrator/session/agent-home.d.mts +4 -0
  112. package/src/runtime/agent/orchestrator/session/agent-home.mjs +33 -0
  113. package/src/runtime/agent/orchestrator/session/agent-mode.mjs +62 -0
  114. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +15 -3
  115. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +31 -0
  116. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +241 -0
  117. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +162 -0
  118. package/src/runtime/agent/orchestrator/session/agent-room.mjs +641 -0
  119. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +7 -1
  120. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +74 -13
  121. package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +102 -0
  122. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +8 -2
  123. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +16 -0
  124. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +2 -0
  125. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +6 -2
  126. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +165 -0
  127. package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +95 -0
  128. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +221 -0
  129. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +195 -0
  130. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +167 -0
  131. package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +9 -0
  132. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +3 -1
  133. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +39 -2
  134. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +10 -0
  135. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +16 -1
  136. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +82 -33
  137. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +11 -4
  138. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +5 -4
  139. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +13 -3
  140. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +7 -0
  141. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +1 -0
  142. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +6 -1
  143. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  144. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -0
  145. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +13 -5
  146. package/src/runtime/agent/orchestrator/session/manager/pending-lifecycle-epoch.mjs +0 -8
  147. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +10 -7
  148. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +62 -22
  149. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +44 -16
  150. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -5
  151. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +23 -1
  152. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +81 -34
  153. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +39 -4
  154. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -5
  155. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +55 -8
  156. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -0
  157. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -2
  158. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +6 -0
  159. package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +58 -0
  160. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -2
  161. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +24 -0
  162. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +32 -5
  163. package/src/runtime/agent/orchestrator/session/request-fork.mjs +47 -0
  164. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +70 -0
  165. package/src/runtime/agent/orchestrator/session/routine-result.mjs +277 -0
  166. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +16 -1
  167. package/src/runtime/agent/orchestrator/session/side-question.mjs +5 -43
  168. package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +10 -0
  169. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +73 -6
  170. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +40 -0
  171. package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +15 -0
  172. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +12 -0
  173. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +8 -0
  174. package/src/runtime/agent/orchestrator/session/store-agent-worker-header.mjs +36 -0
  175. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +258 -43
  176. package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +325 -0
  177. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +84 -21
  178. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -12
  179. package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +46 -0
  180. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +46 -30
  181. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +0 -4
  182. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +144 -45
  183. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +32 -13
  184. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +364 -38
  185. package/src/runtime/agent/orchestrator/session/store.mjs +9 -2
  186. package/src/runtime/agent/orchestrator/session/task-wait-control.mjs +43 -12
  187. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +23 -6
  188. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +44 -1
  189. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -6
  190. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +13 -7
  191. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +1 -1
  192. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/benign-exit.mjs +7 -1
  193. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +40 -7
  194. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +37 -34
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +1 -1
  196. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +0 -4
  197. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -0
  198. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +29 -27
  199. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +1 -1
  200. package/src/runtime/agent/orchestrator/tools/builtin/find-files-tool.mjs +28 -11
  201. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +12 -3
  202. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +203 -101
  203. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +90 -41
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +17 -1
  205. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-delivery.mjs +199 -0
  206. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +12 -0
  207. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +165 -39
  208. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +25 -13
  209. package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +113 -5
  210. package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +7 -6
  211. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +19 -4
  212. package/src/runtime/agent/orchestrator/tools/builtin/read-line-collector.mjs +5 -3
  213. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +25 -7
  214. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +2 -1
  215. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-render.mjs +3 -1
  216. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +12 -5
  217. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +61 -22
  218. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +32 -8
  219. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +193 -19
  220. package/src/runtime/agent/orchestrator/tools/builtin/shell-direct-exe.mjs +57 -7
  221. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +123 -32
  222. package/src/runtime/agent/orchestrator/tools/builtin/shell-lossless-compact.mjs +26 -1
  223. package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +13 -28
  224. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +90 -11
  225. package/src/runtime/agent/orchestrator/tools/builtin/wait-budgets.mjs +23 -0
  226. package/src/runtime/agent/orchestrator/tools/builtin.mjs +54 -10
  227. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +22 -28
  228. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +11 -7
  229. package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +126 -9
  230. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  231. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +15 -6
  232. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +64 -2
  233. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +10 -2
  234. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promotion-results.mjs +13 -3
  235. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +8 -0
  236. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -1
  237. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
  238. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +104 -55
  239. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +7 -2
  240. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +39 -23
  241. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +6 -2
  242. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  243. package/src/runtime/attachments/office-extract.mjs +11 -9
  244. package/src/runtime/browser-bridge/client.mjs +24 -0
  245. package/src/runtime/channels/lib/scheduler.mjs +40 -12
  246. package/src/runtime/channels/lib/schedules-db.mjs +71 -12
  247. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +36 -16
  248. package/src/runtime/channels/lib/webhook.mjs +0 -1
  249. package/src/runtime/channels/lib/webhooks-db.mjs +100 -10
  250. package/src/runtime/channels/lib/worker-main.mjs +17 -20
  251. package/src/runtime/computer-bridge/client.mjs +28 -1
  252. package/src/runtime/connectors/gmail-app-password.mjs +690 -0
  253. package/src/runtime/connectors/google-mcp.mjs +446 -0
  254. package/src/runtime/memory/lib/core-memory-access.mjs +69 -0
  255. package/src/runtime/memory/lib/core-memory-file.mjs +16 -8
  256. package/src/runtime/memory/lib/core-memory-index.mjs +15 -9
  257. package/src/runtime/memory/lib/core-memory-management.mjs +10 -4
  258. package/src/runtime/memory/lib/core-memory-store.mjs +53 -30
  259. package/src/runtime/memory/lib/core-memory-uniqueness.mjs +10 -6
  260. package/src/runtime/memory/lib/embedding-tokenizer.mjs +32 -18
  261. package/src/runtime/memory/lib/http-router/session-routes.mjs +3 -2
  262. package/src/runtime/memory/lib/memory-action-handlers/core-actions.mjs +44 -14
  263. package/src/runtime/memory/lib/memory-schema/core-and-meta.mjs +11 -0
  264. package/src/runtime/memory/lib/memory.mjs +7 -1
  265. package/src/runtime/memory/lib/query-core-recall.mjs +9 -1
  266. package/src/runtime/memory/lib/query-hybrid-search.mjs +2 -0
  267. package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -1
  268. package/src/runtime/memory/lib/tool-call-handler.mjs +9 -5
  269. package/src/runtime/memory/tool-defs.mjs +5 -0
  270. package/src/runtime/office/authoring/pptx-script-normalize.mjs +11 -8
  271. package/src/runtime/office/core/tabular.mjs +1 -1
  272. package/src/runtime/office/design/library/design-template-inspect.mjs +7 -4
  273. package/src/runtime/office/portable/docx-formatting.mjs +1 -1
  274. package/src/runtime/office/portable/docx-runs.mjs +1 -1
  275. package/src/runtime/office/portable/docx-tracked-edits.mjs +2 -2
  276. package/src/runtime/office/portable/portable-docx-edits.mjs +11 -10
  277. package/src/runtime/office/portable/portable-docx-operations.mjs +21 -17
  278. package/src/runtime/office/portable/portable-docx-parts.mjs +15 -9
  279. package/src/runtime/office/portable/portable-docx-styles.mjs +4 -1
  280. package/src/runtime/office/portable/portable-docx-xml.mjs +9 -9
  281. package/src/runtime/office/portable/portable-opc.mjs +27 -13
  282. package/src/runtime/office/portable/portable-pivot.mjs +3 -3
  283. package/src/runtime/office/portable/portable-pptx-chart.mjs +3 -3
  284. package/src/runtime/office/portable/portable-pptx-charts.mjs +24 -18
  285. package/src/runtime/office/portable/portable-pptx-core.mjs +5 -5
  286. package/src/runtime/office/portable/portable-pptx-deck.mjs +8 -4
  287. package/src/runtime/office/portable/portable-pptx-package.mjs +7 -4
  288. package/src/runtime/office/portable/portable-pptx-shapes.mjs +18 -9
  289. package/src/runtime/office/portable/portable-sheet-parts.mjs +9 -3
  290. package/src/runtime/office/portable/portable-sheet-xml.mjs +5 -5
  291. package/src/runtime/office/portable/portable-xlsx-charts.mjs +4 -1
  292. package/src/runtime/office/portable/portable-xlsx-drawings.mjs +10 -6
  293. package/src/runtime/office/portable/portable-xlsx-operations.mjs +8 -5
  294. package/src/runtime/office/portable/portable-xlsx-pivot-ops.mjs +1 -1
  295. package/src/runtime/office/portable/portable-xlsx-reference-shift.mjs +11 -7
  296. package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +6 -3
  297. package/src/runtime/office/portable/portable-xml.mjs +1 -1
  298. package/src/runtime/shared/agent-avatar-sprites.mjs +445 -0
  299. package/src/runtime/shared/agent-avatar.d.mts +64 -0
  300. package/src/runtime/shared/agent-avatar.mjs +320 -0
  301. package/src/runtime/shared/agent-route-config.d.mts +3 -0
  302. package/src/runtime/shared/agent-route-config.mjs +16 -0
  303. package/src/runtime/shared/atomic-file.mjs +36 -14
  304. package/src/runtime/shared/background-tasks.mjs +60 -20
  305. package/src/runtime/shared/child-spawn-gate.mjs +26 -16
  306. package/src/runtime/shared/config.mjs +8 -11
  307. package/src/runtime/shared/connector-accounts.mjs +15 -0
  308. package/src/runtime/shared/connector-catalog.d.mts +52 -0
  309. package/src/runtime/shared/connector-catalog.mjs +230 -0
  310. package/src/runtime/shared/connector-triggers.d.mts +3 -0
  311. package/src/runtime/shared/connector-triggers.mjs +43 -0
  312. package/src/runtime/shared/file-lock.mjs +7 -1
  313. package/src/runtime/shared/file-permissions-worker.mjs +38 -0
  314. package/src/runtime/shared/file-permissions.d.mts +19 -4
  315. package/src/runtime/shared/file-permissions.mjs +310 -4
  316. package/src/runtime/shared/git-runner-worker.mjs +6 -78
  317. package/src/runtime/shared/google-oauth-client.mjs +24 -0
  318. package/src/runtime/shared/held-request-host.d.mts +12 -0
  319. package/src/runtime/shared/held-request-host.mjs +71 -0
  320. package/src/runtime/shared/llm/http-agent.mjs +7 -3
  321. package/src/runtime/shared/llm/provider-catalog-registry.mjs +10 -0
  322. package/src/runtime/shared/llm/usage-accounting.mjs +2 -0
  323. package/src/runtime/shared/llm/usage-ledger-import.mjs +32 -3
  324. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +12 -5
  325. package/src/runtime/shared/llm/usage-ledger-worker.mjs +1 -1
  326. package/src/runtime/shared/llm/usage-ledger.mjs +20 -5
  327. package/src/runtime/shared/memory-snapshot.mjs +5 -1
  328. package/src/runtime/shared/notify-trace.mjs +8 -1
  329. package/src/runtime/shared/plain-preview.d.mts +1 -0
  330. package/src/runtime/shared/plain-preview.mjs +28 -0
  331. package/src/runtime/shared/pristine-execution-contract.json +5 -1
  332. package/src/runtime/shared/process-runner-worker.mjs +7 -0
  333. package/src/runtime/shared/process-runner.mjs +38 -0
  334. package/src/runtime/shared/provider-accounts.mjs +2 -1
  335. package/src/runtime/shared/provider-api-key.mjs +0 -1
  336. package/src/runtime/shared/read-row-numbers.mjs +1 -1
  337. package/src/runtime/shared/resource-admission.mjs +60 -18
  338. package/src/runtime/shared/routine-limits.d.mts +11 -0
  339. package/src/runtime/shared/routine-limits.mjs +21 -0
  340. package/src/runtime/shared/routine-trigger.d.mts +10 -0
  341. package/src/runtime/shared/routine-trigger.mjs +44 -0
  342. package/src/runtime/shared/run-child.mjs +84 -0
  343. package/src/runtime/shared/schedule-model-ref.mjs +9 -10
  344. package/src/runtime/shared/session-activity-signal.mjs +23 -0
  345. package/src/runtime/shared/shell-output-summary.mjs +23 -0
  346. package/src/runtime/shared/singleton-owner.mjs +126 -42
  347. package/src/runtime/shared/slow-span.mjs +4 -12
  348. package/src/runtime/shared/statusline/statusline-segments.mjs +13 -1
  349. package/src/runtime/shared/tool-output-limit.mjs +4 -2
  350. package/src/runtime/shared/tool-output-marker.mjs +58 -0
  351. package/src/runtime/shared/transcript-metadata.mjs +10 -0
  352. package/src/runtime/shared/turn-changes.mjs +0 -8
  353. package/src/runtime/shared/usage-readout-totals.mjs +56 -0
  354. package/src/runtime/shared/user-data-guard.mjs +131 -34
  355. package/src/runtime/shared/worktrees/activity-gate.mjs +33 -8
  356. package/src/runtime/shared/worktrees/git-head.mjs +20 -2
  357. package/src/runtime/shared/worktrees/lock.mjs +3 -2
  358. package/src/runtime/terminal-bridge/tool-defs.mjs +1 -1
  359. package/src/runtime/tidy/runners/biome.mjs +3 -1
  360. package/src/runtime/tidy/shadow.mjs +2 -1
  361. package/src/runtime/web-search/index.mjs +5 -7
  362. package/src/runtime/web-search/lib/formatter.mjs +42 -6
  363. package/src/runtime/web-search/tool-defs.mjs +6 -1
  364. package/src/session-runtime/agent-home-delivery.mjs +459 -0
  365. package/src/session-runtime/agent-profile-changes.mjs +21 -0
  366. package/src/session-runtime/agent-room-delivery.mjs +92 -0
  367. package/src/session-runtime/agent-task-sessions.mjs +200 -0
  368. package/src/session-runtime/boot/apis.mjs +50 -18
  369. package/src/session-runtime/boot/facade.mjs +5 -8
  370. package/src/session-runtime/boot/infrastructure.mjs +28 -17
  371. package/src/session-runtime/boot/tools.mjs +3 -0
  372. package/src/session-runtime/channel-config-api.mjs +53 -5
  373. package/src/session-runtime/cwd-plugins/core-memory-context.mjs +36 -20
  374. package/src/session-runtime/cwd-plugins/plugin-status.mjs +6 -1
  375. package/src/session-runtime/held-requests.mjs +228 -0
  376. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +121 -0
  377. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -1
  378. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +31 -2
  379. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +31 -2
  380. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  381. package/src/session-runtime/lifecycle/session-catalog.mjs +9 -0
  382. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +4 -3
  383. package/src/session-runtime/lifecycle/session-switch/resume.mjs +11 -4
  384. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +3 -3
  385. package/src/session-runtime/lifecycle/shared.mjs +25 -2
  386. package/src/session-runtime/lifecycle/teardown/session-close.mjs +2 -0
  387. package/src/session-runtime/lifecycle/teardown.mjs +5 -2
  388. package/src/session-runtime/lifecycle-api.mjs +3 -1
  389. package/src/session-runtime/mcp-glue/server-catalog.mjs +8 -0
  390. package/src/session-runtime/mcp-glue/server-input.mjs +3 -0
  391. package/src/session-runtime/mcp-oauth-login.mjs +112 -15
  392. package/src/session-runtime/model-route/set-route.mjs +14 -3
  393. package/src/session-runtime/owned-automation-run.mjs +229 -0
  394. package/src/session-runtime/provider-auth/login.mjs +10 -6
  395. package/src/session-runtime/provider-auth/setup.mjs +19 -2
  396. package/src/session-runtime/provider-catalog-cache.mjs +101 -25
  397. package/src/session-runtime/provider-models/catalog-load.mjs +14 -3
  398. package/src/session-runtime/provider-models/row-hydration.mjs +4 -0
  399. package/src/session-runtime/provider-models.mjs +76 -10
  400. package/src/session-runtime/provider-readiness.mjs +4 -0
  401. package/src/session-runtime/resource-api.mjs +5 -0
  402. package/src/session-runtime/resource-mcp-api.mjs +107 -13
  403. package/src/session-runtime/resource-skills-api.mjs +12 -0
  404. package/src/session-runtime/room-member-gate.mjs +48 -0
  405. package/src/session-runtime/routine-home-turn.mjs +156 -0
  406. package/src/session-runtime/routine-owner.mjs +48 -0
  407. package/src/session-runtime/schedule-session-run.mjs +30 -64
  408. package/src/session-runtime/services/agent-tool/close-flow.mjs +2 -1
  409. package/src/session-runtime/services/agent-tool/helpers.mjs +10 -0
  410. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +10 -2
  411. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +13 -4
  412. package/src/session-runtime/services/agent-tool/notify.mjs +15 -4
  413. package/src/session-runtime/services/agent-tool/restart-notify.mjs +134 -0
  414. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -1
  415. package/src/session-runtime/services/agent-tool/spawn-flow/deferred-spawn.mjs +2 -1
  416. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -3
  417. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +19 -4
  418. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +2 -0
  419. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -1
  420. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +8 -3
  421. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -0
  422. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +4 -0
  423. package/src/session-runtime/services/agent-tool/worker-index.mjs +44 -10
  424. package/src/session-runtime/services/agent-tool.mjs +20 -0
  425. package/src/session-runtime/services/channel-admin.mjs +93 -24
  426. package/src/session-runtime/services/memory-access.mjs +37 -0
  427. package/src/session-runtime/services/provider-admin.mjs +166 -59
  428. package/src/session-runtime/services/schedule-access.mjs +91 -0
  429. package/src/session-runtime/services/usage-dashboard-model.mjs +2 -2
  430. package/src/session-runtime/services/usage-dashboard.mjs +27 -69
  431. package/src/session-runtime/session-create/session-options.mjs +34 -7
  432. package/src/session-runtime/session-hooks.mjs +16 -8
  433. package/src/session-runtime/setup-tool/executor.mjs +68 -6
  434. package/src/session-runtime/setup-tool/extended-actions.mjs +72 -14
  435. package/src/session-runtime/setup-tool/settings-contract.mjs +8 -6
  436. package/src/session-runtime/setup-tool/tool-defs.mjs +8 -0
  437. package/src/session-runtime/skills-api.mjs +16 -1
  438. package/src/session-runtime/tool-policy-refresh.mjs +238 -29
  439. package/src/session-runtime/turn/session-ops.mjs +10 -3
  440. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +11 -2
  441. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +3 -0
  442. package/src/session-runtime/usage-stats-api.mjs +6 -1
  443. package/src/session-runtime/webhook-session-run.mjs +49 -67
  444. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +239 -0
  445. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +556 -22
  446. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +11 -1
  447. package/src/session-runtime/workflow-agents-api.mjs +4 -1
  448. package/src/standalone/channel-transport/http-routes.mjs +10 -9
  449. package/src/standalone/daemon-agent-control.mjs +1 -8
  450. package/src/standalone/daemon-desktop-runtime.mjs +20 -7
  451. package/src/standalone/daemon-owner.mjs +117 -25
  452. package/src/standalone/daemon-session-control.mjs +11 -2
  453. package/src/standalone/daemon.mjs +61 -17
  454. package/src/standalone/session-call-cache.mjs +6 -0
  455. package/src/standalone/session-protocol.mjs +28 -1
  456. package/src/standalone/session-service/retention/busy.mjs +7 -2
  457. package/src/standalone/session-service/session-calls/session-turns.mjs +9 -0
  458. package/src/standalone/session-service.mjs +19 -0
  459. package/src/standalone/session-transport/routes.mjs +7 -6
  460. package/src/tui/app/model-options.mjs +39 -2
  461. package/src/tui/app/model-picker.mjs +16 -2
  462. package/src/tui/app/provider-setup-picker.mjs +1 -2
  463. package/src/tui/app/slash-commands.mjs +20 -0
  464. package/src/tui/dist/index.mjs +487 -128
  465. package/src/tui/session/context-state.mjs +6 -1
  466. package/src/tui/session/notice-surface.mjs +35 -4
  467. package/src/tui/session/notice-text.mjs +0 -1
  468. package/src/tui/session/queue-helpers.mjs +2 -1
  469. package/src/tui/session/session-api/extensions.mjs +4 -0
  470. package/src/tui/session/session-api/intake/submission.mjs +12 -13
  471. package/src/tui/session/session-api/integrations.mjs +9 -5
  472. package/src/tui/session/session-api/lifecycle/session-reset.mjs +13 -3
  473. package/src/tui/session/session-api/lifecycle.mjs +17 -1
  474. package/src/tui/session/session-api/routes.mjs +48 -3
  475. package/src/tui/session/session-flow/drain.mjs +20 -3
  476. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -1
  477. package/src/tui/session/session-flow/queue/take-entries.mjs +3 -2
  478. package/src/tui/session/session-flow/steering.mjs +104 -24
  479. package/src/tui/session/session-flow.mjs +2 -0
  480. package/src/tui/session/tool-approval.mjs +26 -5
  481. package/src/tui/session/transcript-intake.mjs +6 -2
  482. package/src/tui/session/transcript-spill.mjs +5 -1
  483. package/src/tui/session/tui-steering-persist.mjs +65 -42
  484. package/src/tui/session/turn-live-call.mjs +56 -0
  485. package/src/tui/session/turn-stream.mjs +33 -0
  486. package/src/tui/session/turn.mjs +50 -7
  487. package/src/ui/statusline.mjs +1 -6
  488. package/src/ui/streaming-markdown-heal.mjs +24 -7
  489. package/src/vendor/statusline/bin/statusline-route.mjs +0 -1
  490. package/src/vendor/statusline/src/gateway/route-meta.mjs +0 -1
  491. package/src/workflows/default/WORKFLOW.md +9 -13
  492. package/src/session-runtime/automation-agents.mjs +0 -94
  493. package/src/session-runtime/automation-workflow.mjs +0 -59
@@ -48,11 +48,21 @@ export function createWorkflowPacksApi(deps) {
48
48
  }));
49
49
  }
50
50
 
51
- async function setWorkflow(workflowId) {
51
+ // `{ scope: 'session' }` (the composer's selector in a session): a session
52
+ // with a conversation switches alone from its next turn
53
+ // (switchSessionWorkflow) and the configured workflow — the default for new
54
+ // sessions — stays as it is. Without a conversation, and without the
55
+ // scope, the choice becomes the configured workflow and an empty session
56
+ // picks it up in place, as before.
57
+ async function setWorkflow(workflowId, options = {}) {
52
58
  const requested = normalizeWorkflowId(workflowId, DEFAULT_WORKFLOW_ID);
53
59
  const id = requested === 'solo' ? DEFAULT_WORKFLOW_ID : requested;
54
60
  const pack = loadWorkflowPack(resolveDataDir(deps), id);
55
61
  if (!pack || pack.id !== id) throw new Error(`workflow "${workflowId}" not found`);
62
+ if (options?.scope === 'session') {
63
+ const switched = await deps.switchSessionWorkflow?.(id);
64
+ if (switched) return { ...switched.workflow, ...switched };
65
+ }
56
66
  saveActiveWorkflow(id);
57
67
  const applied = await deps.refreshEmptySessionToolPolicy?.();
58
68
  deps.invalidatePreSessionToolSurface?.();
@@ -1,5 +1,6 @@
1
1
  import { createOnboardingApi } from './workflow-agents-api/onboarding.mjs';
2
2
  import { createAgentEditorApi } from './workflow-agents-api/agent-editor.mjs';
3
+ import { createAgentConnectorsApi } from './workflow-agents-api/agent-connectors.mjs';
3
4
  import { createAgentRouteApi } from './workflow-agents-api/agent-route.mjs';
4
5
  import { createWorkflowPacksApi } from './workflow-agents-api/workflow-packs.mjs';
5
6
  import { createStyleAndModeApi } from './workflow-agents-api/style-and-mode.mjs';
@@ -11,9 +12,11 @@ import { createStyleAndModeApi } from './workflow-agents-api/style-and-mode.mjs'
11
12
  // getOnboardingStatus from the composed runtime API through `this`.
12
13
  export function createWorkflowAgentsApi(deps) {
13
14
  const routeApi = createAgentRouteApi(deps);
15
+ const editorApi = createAgentEditorApi({ ...deps, setAgentRoute: routeApi.setAgentRoute });
14
16
  return {
15
17
  ...createOnboardingApi(deps),
16
- ...createAgentEditorApi({ ...deps, setAgentRoute: routeApi.setAgentRoute }),
18
+ ...editorApi,
19
+ ...createAgentConnectorsApi(deps, editorApi),
17
20
  ...routeApi,
18
21
  ...createWorkflowPacksApi(deps),
19
22
  ...createStyleAndModeApi(deps),
@@ -31,9 +31,10 @@ export function createChannelRoutes({
31
31
  // Checked on every register/call/agent dispatch, first and again right
32
32
  // before the work is handed on (the lease may have been fenced while the
33
33
  // body was still arriving): a daemon that lost (or cannot re-verify) its
34
- // owner lease serves nothing.
35
- function refuseUnadmitted(res) {
36
- if (admitWork()) return false;
34
+ // owner lease serves nothing. `admitWork` may answer asynchronously (a
35
+ // request arriving during the lease's re-verification waits for it).
36
+ async function refuseUnadmitted(res) {
37
+ if (await admitWork()) return false;
37
38
  sendError(res, 'daemon owner lease is not held', 503);
38
39
  return true;
39
40
  }
@@ -54,10 +55,10 @@ export function createChannelRoutes({
54
55
  }
55
56
 
56
57
  async function register(req, res) {
57
- if (refuseUnadmitted(res)) return;
58
+ if (await refuseUnadmitted(res)) return;
58
59
  if (state.drainCommitted) return sendDraining(res);
59
60
  const body = await readChannelBody(req);
60
- if (refuseUnadmitted(res)) return;
61
+ if (await refuseUnadmitted(res)) return;
61
62
  const clientToken = registry.registerClient({
62
63
  leadPid: body.leadPid,
63
64
  cwd: body.cwd,
@@ -96,11 +97,11 @@ export function createChannelRoutes({
96
97
  // channels client registry alive. The broker itself owns a parallel fair
97
98
  // scheduler and per-call cancellation.
98
99
  async function agentDispatch(req, res) {
99
- if (refuseUnadmitted(res)) return;
100
+ if (await refuseUnadmitted(res)) return;
100
101
  if (state.drainCommitted) return sendDraining(res);
101
102
  if (!agentBroker?.dispatch) return sendError(res, 'agent broker unavailable', 503);
102
103
  const body = await readChannelBody(req);
103
- if (refuseUnadmitted(res)) return;
104
+ if (await refuseUnadmitted(res)) return;
104
105
  const callId = String(body.callId || '').trim();
105
106
  if (!callId) return sendError(res, 'callId required', 400);
106
107
  res.on('close', () => {
@@ -130,10 +131,10 @@ export function createChannelRoutes({
130
131
  }
131
132
 
132
133
  async function call(req, res) {
133
- if (refuseUnadmitted(res)) return;
134
+ if (await refuseUnadmitted(res)) return;
134
135
  if (state.drainCommitted) return sendDraining(res);
135
136
  const body = await readChannelBody(req);
136
- if (refuseUnadmitted(res)) return;
137
+ if (await refuseUnadmitted(res)) return;
137
138
  const clientToken = body.token || null;
138
139
  const c = clientToken ? clients.get(clientToken) : null;
139
140
  if (!c) return sendError(res, 'unknown client token', 404);
@@ -8,8 +8,6 @@
8
8
  // this control exists — the host takes `execute` as a constructor option), and
9
9
  // `cwd`. Output: { canonicalAgentTool, execute }.
10
10
 
11
- import { deliverAutomationCompletion } from '../session-runtime/automation-agents.mjs';
12
-
13
11
  export function createCanonicalAgentControl({ getSessionService, getSessionRuntimeHost, cwd }) {
14
12
  let canonicalAgentToolPromise = null;
15
13
 
@@ -34,12 +32,7 @@ export function createCanonicalAgentControl({ getSessionService, getSessionRunti
34
32
  isKeychainPrewarmReady: () => true,
35
33
  sessionSurface: sessionService.agentSurface,
36
34
  notifySessionCompletion(ownerSessionId, text, meta = {}) {
37
- // A schedule/webhook run owns no session runtime; its own
38
- // agent-result waiter takes the completions it is owed.
39
- return (
40
- getSessionRuntimeHost()?.notifySessionCompletion?.(ownerSessionId, text, meta) === true ||
41
- deliverAutomationCompletion(ownerSessionId, text, meta)
42
- );
35
+ return getSessionRuntimeHost()?.notifySessionCompletion?.(ownerSessionId, text, meta) === true;
43
36
  },
44
37
  });
45
38
  })
@@ -12,22 +12,33 @@
12
12
  * this daemon's in-memory turn activity (every session runs inline here, so
13
13
  * it is the single source of truth; worker index files only declare work). */
14
14
  async function loadSessionStoreWithRuntimeActivity() {
15
- const [store, runtime, progress] = await Promise.all([
15
+ const [store, runtime, progress, tasks] = await Promise.all([
16
16
  import('../runtime/agent/orchestrator/session/store-summary-reader.mjs'),
17
17
  // The import-free leaf holding the runtime map: no session manager graph.
18
18
  import('../runtime/agent/orchestrator/session/manager/runtime-state.mjs'),
19
19
  import('../runtime/agent/orchestrator/session/agent-pool-progress.mjs'),
20
+ import('../runtime/shared/background-tasks.mjs'),
20
21
  ]);
21
22
  return {
22
23
  ...store,
23
24
  // Running rows also carry their turn's progress stamp and stage (the
24
- // quiet-time cue), read from the same runtime map.
25
- listStoredAgentWorkers: () =>
26
- progress.withTurnProgress(
27
- store.listStoredAgentWorkers({ runningSessionIds: runtime.inFlightSessionActivity().working }),
25
+ // quiet-time cue), read from the same runtime map; an idle row whose
26
+ // agent handed off background shell work that still runs reads waiting.
27
+ // The handed-off shell work of every row comes from one task scan. The
28
+ // store is read with awaited I/O (a listing runs on every activity
29
+ // change); the running set is taken once those reads are done.
30
+ listStoredAgentWorkers: async () => {
31
+ const rows = await store.listStoredAgentWorkersAsync({
32
+ runningSessionIds: () => runtime.inFlightSessionActivity().working,
33
+ });
34
+ const awaiting = tasks.activeBackgroundTaskSessionIds({ surface: 'shell', awaitedOnly: true });
35
+ return progress.withTurnProgress(
36
+ rows,
28
37
  (sessionId) => runtime.runtimeState.get(sessionId),
29
- runtime.isTurnInFlight
30
- ),
38
+ runtime.isTurnInFlight,
39
+ (sessionId) => awaiting.has(sessionId)
40
+ );
41
+ },
31
42
  };
32
43
  }
33
44
 
@@ -53,6 +64,8 @@ export function createDesktopRuntime({ getLocalSessionBridge }) {
53
64
  loadStatuslineSegments: () => import('../runtime/shared/statusline/statusline-segments.mjs'),
54
65
  loadConfig: () => import('../runtime/shared/config.mjs'),
55
66
  loadDocumentPreview: () => import('../runtime/office/pdf/document-preview.mjs'),
67
+ // The desktop service's git children start on this worker, off the loop.
68
+ loadProcessRunner: () => import('../runtime/shared/process-runner.mjs'),
56
69
  async executeCodeGraphTool(name, args, cwd) {
57
70
  const graph = await import('../runtime/agent/orchestrator/tools/code-graph/dispatch.mjs');
58
71
  return graph.executeCodeGraphTool(name, args, cwd);
@@ -15,6 +15,14 @@
15
15
  // being renewed, and every register/call asks `admit()` first. After an
16
16
  // event-loop stall nothing is served until a refresh under the claim lock
17
17
  // proves the record still names it — a contender's claim takes that lock.
18
+ // A lease that ran out DURING such a stall (live when the loop stopped) is
19
+ // the one exception to the fence: the holder never had a turn to refresh
20
+ // or to fence, and a contender's reclaim is decided under the claim lock
21
+ // against the record's heartbeat there (daemonOwnerIsStale re-checks it),
22
+ // so a refresh that finds the record still naming this pid proves no
23
+ // contender took it and none can on its earlier proof. Without that, a sole
24
+ // daemon whose loop the machine starved past the lease killed itself and
25
+ // every running turn with no other daemon to take over.
18
26
  // - Holder's record names `livenessPort` from its very first claim: a tiny
19
27
  // loopback listener started BEFORE the claim (startOwnerLivenessListener)
20
28
  // answers /health with the pid, through boot and for the process lifetime.
@@ -32,8 +40,9 @@
32
40
  // daemon.json publishes, answering with that pid, proves them alive.
33
41
  import http from 'node:http';
34
42
  import { readFileSync } from 'node:fs';
43
+ import { readFile } from 'node:fs/promises';
35
44
  import { isPidAlive } from '../runtime/shared/pid-liveness.mjs';
36
- import { readSingletonOwner, refreshSingletonOwner } from '../runtime/shared/singleton-owner.mjs';
45
+ import { readSingletonOwner, refreshSingletonOwnerAsync } from '../runtime/shared/singleton-owner.mjs';
37
46
 
38
47
  export const DAEMON_OWNER_STALE_MS = 60_000;
39
48
  export const OWNER_PROBE_TIMEOUT_MS = 3_000;
@@ -58,11 +67,23 @@ export function daemonOwnerTimings(env = process.env) {
58
67
  }
59
68
 
60
69
  /** daemon.json's pid and session endpoint, or null when missing/unreadable. */
70
+ function discoveryOf(parsed) {
71
+ const session = parsed?.endpoints?.session;
72
+ return { pid: Number(parsed?.pid) || 0, port: Number(session?.port) || 0, token: session?.token || '' };
73
+ }
74
+
61
75
  export function readDiscovery(discoveryPath) {
62
76
  try {
63
- const parsed = JSON.parse(readFileSync(discoveryPath, 'utf8'));
64
- const session = parsed?.endpoints?.session;
65
- return { pid: Number(parsed?.pid) || 0, port: Number(session?.port) || 0, token: session?.token || '' };
77
+ return discoveryOf(JSON.parse(readFileSync(discoveryPath, 'utf8')));
78
+ } catch {
79
+ return null;
80
+ }
81
+ }
82
+
83
+ /** readDiscovery without blocking the event loop. */
84
+ export async function readDiscoveryAsync(discoveryPath) {
85
+ try {
86
+ return discoveryOf(JSON.parse(await readFile(discoveryPath, 'utf8')));
66
87
  } catch {
67
88
  return null;
68
89
  }
@@ -243,7 +264,10 @@ export function daemonOwnerIsStale(
243
264
  * `tickMs` it checks the lease, notices stalls, and every `heartbeatMs`
244
265
  * rewrites `owner` with a fresh wall-clock `heartbeatAt` under the claim lock
245
266
  * (recreating a deleted record), then calls `onBeat`.
246
- * - No successful refresh for `fenceMs`: fenced, never renewed (`onFenced`).
267
+ * - No successful refresh for `fenceMs`: fenced, never renewed (`onFenced`) —
268
+ * unless the lease ran out inside one stall (live when the loop stopped):
269
+ * then the refresh is retried every tick for `heartbeatMs` after the loop
270
+ * resumes, and fenced only if none succeeds by then.
247
271
  * - The record names another pid: `onSuperseded(record)`.
248
272
  * - A turn gap over `stallMs`: `admit()` refuses work until a refresh succeeds.
249
273
  * The gap is logged once, with `describeStall(fromMono, toMono)` appended.
@@ -258,7 +282,7 @@ export function createOwnerHeartbeat({
258
282
  stallMs,
259
283
  now = Date.now,
260
284
  monoNow = () => performance.now(),
261
- refresh = refreshSingletonOwner,
285
+ refresh = refreshSingletonOwnerAsync,
262
286
  log = () => {},
263
287
  describeStall = null,
264
288
  onBeat = () => {},
@@ -272,6 +296,13 @@ export function createOwnerHeartbeat({
272
296
  let lastBeatAt = leaseFrom;
273
297
  let lastTurnAt = leaseFrom;
274
298
  let needsVerify = false;
299
+ // Monotonic time the loop resumed from a stall that outlived the lease.
300
+ let stallResumedAt = null;
301
+ // The refresh in flight: a promise of its settled status, else null.
302
+ let pending = null;
303
+ // When the latest stall was noticed: only a refresh started after it can
304
+ // re-verify the record (an older one may have read it before the stall).
305
+ let stallNotedAt = Number.NEGATIVE_INFINITY;
275
306
  let timer = null;
276
307
 
277
308
  function halt(next) {
@@ -284,6 +315,12 @@ export function createOwnerHeartbeat({
284
315
  return t - leaseFrom >= fenceMs;
285
316
  }
286
317
 
318
+ // Expired and past re-verification: the refreshes failed while the loop
319
+ // ran, or no refresh landed within `heartbeatMs` of resuming from a stall.
320
+ function mustFence(t) {
321
+ return leaseExpired(t) && !(stallResumedAt !== null && t - stallResumedAt < heartbeatMs);
322
+ }
323
+
287
324
  function fence(t) {
288
325
  if (state !== 'active') return;
289
326
  halt('fenced');
@@ -298,6 +335,8 @@ export function createOwnerHeartbeat({
298
335
  lastTurnAt = t;
299
336
  if (t - from <= stallMs) return;
300
337
  needsVerify = true;
338
+ stallNotedAt = t;
339
+ if (state === 'active' && !leaseExpired(from) && leaseExpired(t)) stallResumedAt = t;
301
340
  let detail = '';
302
341
  try {
303
342
  detail = describeStall?.(from, t) || '';
@@ -310,13 +349,53 @@ export function createOwnerHeartbeat({
310
349
  );
311
350
  }
312
351
 
352
+ // A refresh's verdict, applied once it is known. Fenced, superseded or
353
+ // stopped while it ran: nothing is renewed. A renewal counts from the
354
+ // moment the refresh started (`t`), never from when it answered.
355
+ function settle(t, heartbeatAt, result) {
356
+ if (state !== 'active') return result.status;
357
+ if (result.status === 'refreshed') {
358
+ if (leaseExpired(t)) {
359
+ log(
360
+ `owner lease re-verified ${Math.round(t - leaseFrom)}ms after its last refresh (event-loop stall)` +
361
+ ' — the record still names this process; serving again'
362
+ );
363
+ }
364
+ leaseFrom = t;
365
+ lastRefreshAt = heartbeatAt;
366
+ if (t >= stallNotedAt) {
367
+ needsVerify = false;
368
+ stallResumedAt = null;
369
+ }
370
+ onBeat();
371
+ } else if (result.status === 'superseded') {
372
+ halt('superseded');
373
+ onSuperseded(result.owner);
374
+ } else if (result.status === 'busy') {
375
+ log('owner heartbeat skipped: claim lock busy');
376
+ }
377
+ return result.status;
378
+ }
379
+
380
+ function failedRefresh(error) {
381
+ log(`owner heartbeat failed: ${error?.message || error}`);
382
+ return { status: 'failed' };
383
+ }
384
+
385
+ // One refresh at a time. An asynchronous refresh (the default: its file
386
+ // work and lock retries never block the loop) answers 'pending' here and
387
+ // settles later; the lease and fence keep their monotonic deadlines while
388
+ // it runs — a refresh still unanswered at the fence does not hold it off.
313
389
  function beat() {
314
390
  if (state !== 'active') return null;
391
+ if (pending) return 'pending';
315
392
  const t = monoNow();
316
393
  lastBeatAt = t;
317
- // Checked before every renewal: an overdue beat after a stall must fence,
318
- // not extend a lease a contender may already have reclaimed.
319
- if (leaseExpired(t)) {
394
+ // Checked before every renewal: an overdue beat must fence, not extend a
395
+ // lease a contender may already have reclaimed — except right after a
396
+ // stall that outlived the lease, where the refresh itself (under the
397
+ // claim lock) answers whether one did.
398
+ if (mustFence(t)) {
320
399
  fence(t);
321
400
  return 'fenced';
322
401
  }
@@ -325,28 +404,26 @@ export function createOwnerHeartbeat({
325
404
  try {
326
405
  result = refresh(ownerPath, { ...record, heartbeatAt });
327
406
  } catch (error) {
328
- log(`owner heartbeat failed: ${error?.message || error}`);
329
- result = { status: 'failed' };
330
- }
331
- if (result.status === 'refreshed') {
332
- leaseFrom = t;
333
- lastRefreshAt = heartbeatAt;
334
- needsVerify = false;
335
- onBeat();
336
- } else if (result.status === 'superseded') {
337
- halt('superseded');
338
- onSuperseded(result.owner);
339
- } else if (result.status === 'busy') {
340
- log('owner heartbeat skipped: claim lock busy');
407
+ result = failedRefresh(error);
341
408
  }
342
- return result.status;
409
+ if (typeof result?.then !== 'function') return settle(t, heartbeatAt, result);
410
+ pending = result
411
+ .then(
412
+ (value) => value,
413
+ (error) => failedRefresh(error)
414
+ )
415
+ .then((value) => {
416
+ pending = null;
417
+ return settle(t, heartbeatAt, value);
418
+ });
419
+ return 'pending';
343
420
  }
344
421
 
345
422
  function tick() {
346
423
  if (state !== 'active') return;
347
424
  const t = monoNow();
348
425
  noteTurn(t);
349
- if (leaseExpired(t)) fence(t);
426
+ if (mustFence(t)) fence(t);
350
427
  else if (needsVerify ? t - lastBeatAt >= tickMs : t - lastBeatAt >= heartbeatMs) beat();
351
428
  }
352
429
 
@@ -363,7 +440,7 @@ export function createOwnerHeartbeat({
363
440
  // Shutting down: no ticks run to measure stalls; the lease still bounds it.
364
441
  if (state === 'stopped') return !leaseExpired(t);
365
442
  noteTurn(t);
366
- if (leaseExpired(t)) {
443
+ if (mustFence(t)) {
367
444
  fence(t);
368
445
  return false;
369
446
  }
@@ -372,8 +449,23 @@ export function createOwnerHeartbeat({
372
449
  if (needsVerify && t - lastBeatAt >= tickMs) beat();
373
450
  return state === 'active' && !needsVerify;
374
451
  },
452
+ /** admit(), but a request arriving while the lease is being re-verified
453
+ * waits for the verifying refresh instead of being refused outright: at
454
+ * most two refreshes (one started before the stall cannot verify). */
455
+ async admitAsync() {
456
+ for (let attempt = 0; attempt < 2; attempt += 1) {
457
+ if (this.admit()) return true;
458
+ if (!pending) return false;
459
+ await pending;
460
+ }
461
+ return this.admit();
462
+ },
375
463
  beat,
376
464
  tick,
465
+ /** Settles with the in-flight refresh's status (null when none runs). */
466
+ settled() {
467
+ return pending ?? Promise.resolve(null);
468
+ },
377
469
  /** Stop beating (shutdown). admit() keeps refusing once the lease runs out. */
378
470
  stop() {
379
471
  if (state === 'active') halt('stopped');
@@ -1,20 +1,26 @@
1
1
  import { SESSION_ID_PATTERN } from '../runtime/agent/orchestrator/runtime-core/session-id.mjs';
2
2
  import { sessionListOutput, sessionReadOutput, SESSION_TOOL_OUTPUT_BYTES } from './session-tool-output.mjs';
3
+ import { createAgentTaskSessions } from '../session-runtime/agent-task-sessions.mjs';
3
4
 
4
5
  const TARGET_ACTIONS = new Set(['status', 'read', 'send', 'cancel', 'delete']);
5
6
  const MUTATING_ACTIONS = new Set(['send', 'cancel', 'delete']);
6
7
 
7
8
  /** Model-facing session operations over the same service used by desktop and TUI. */
8
- export function createSessionControl({ getSessionService }) {
9
+ export function createSessionControl({
10
+ getSessionService,
11
+ agentTasks = createAgentTaskSessions({ getSessionService }),
12
+ }) {
9
13
  return async function executeSessionControl(args = {}, context = {}) {
10
14
  const action = args.action;
11
- if (action !== 'list' && !TARGET_ACTIONS.has(action)) {
15
+ if (action !== 'list' && action !== 'create' && !TARGET_ACTIONS.has(action)) {
12
16
  throw new Error(`session: unsupported remote action "${action}"`);
13
17
  }
14
18
  const caller = context.callerSessionId;
15
19
  if (typeof caller !== 'string' || !SESSION_ID_PATTERN.test(caller)) {
16
20
  throw new Error('session: caller session is required');
17
21
  }
22
+ // `callerAgentId`: set only for an attended agent conversation (workspace-tools.mjs).
23
+ if (action === 'create') return agentTasks.create(args, context);
18
24
  const sessionId = typeof args.session_id === 'string' ? args.session_id.trim() : '';
19
25
  if (TARGET_ACTIONS.has(action) && (typeof sessionId !== 'string' || !SESSION_ID_PATTERN.test(sessionId))) {
20
26
  throw new Error(`session: session_id is required for action=${action}`);
@@ -45,6 +51,9 @@ export function createSessionControl({ getSessionService }) {
45
51
  if (typeof args.prompt !== 'string' || !args.prompt.trim()) {
46
52
  throw new Error('session: prompt is required for action=send');
47
53
  }
54
+ // The agent's follow-up in a task session it created reports back too.
55
+ const origin = await agentTasks.originFor(sessionId, context.callerAgentId);
56
+ if (origin) return { sessionId, accepted: await agentTasks.send(sessionId, args.prompt, origin) };
48
57
  const result = await service.submitSession({
49
58
  sessionId,
50
59
  prompt: args.prompt,
@@ -35,7 +35,8 @@ import path from 'node:path';
35
35
  import { rmSync } from 'node:fs';
36
36
  import { fileURLToPath } from 'node:url';
37
37
  import { monitorEventLoopDelay, performance } from 'node:perf_hooks';
38
- import { writeJsonAtomicSync } from '../runtime/shared/atomic-file.mjs';
38
+ import { writeJsonAtomicAsync } from '../runtime/shared/atomic-file.mjs';
39
+ import { prewarmOwnerOnlyAclWin32 } from '../runtime/shared/file-permissions.mjs';
39
40
  import { ensurePrivateRuntimeRoot, resolveRuntimeRoot } from '../runtime/shared/runtime-root.mjs';
40
41
  import { ensureProcessListenerHeadroom } from '../runtime/shared/process-listener-headroom.mjs';
41
42
  import { listenerLeakWarningLine } from '../runtime/shared/listener-leak-warning.mjs';
@@ -46,6 +47,7 @@ import {
46
47
  daemonOwnerTimings,
47
48
  discoveryPid,
48
49
  proveDaemonOwnerRecord,
50
+ readDiscoveryAsync,
49
51
  startOwnerLivenessListener,
50
52
  } from './daemon-owner.mjs';
51
53
  import { remoteIntentPath } from '../runtime/shared/remote-intent.mjs';
@@ -75,6 +77,8 @@ import { createStoredSessionViews } from './daemon-stored-session-views.mjs';
75
77
  import * as quotaResumeStore from '../runtime/shared/quota-resume-store.mjs';
76
78
  import { registerWorktreeCacheCleanups } from '../runtime/shared/worktrees/cache-cleanups.mjs';
77
79
  import { createInlineSessionRuntimeHost } from './session-runtime-inline-host.mjs';
80
+ import { recoverScheduleResults, setAgentHomeLiveSurface } from '../session-runtime/agent-home-delivery.mjs';
81
+ import { recoverRoutineDeliveries } from '../session-runtime/owned-automation-run.mjs';
78
82
  import { getStandaloneMemoryRuntime } from '../session-runtime/services/memory-runtime-proxy.mjs';
79
83
  import { registerTranscriptPurgeHook } from '../session-runtime/session-transcript-purge.mjs';
80
84
  import { createBootPhaseProfiler } from './boot-phase-profiler.mjs';
@@ -93,7 +97,6 @@ import { createDesktopRuntime } from './daemon-desktop-runtime.mjs';
93
97
  import { createCanonicalAgentControl } from './daemon-agent-control.mjs';
94
98
  import { createSessionControl } from './daemon-session-control.mjs';
95
99
  import { flushAllIndexWrites } from '../session-runtime/services/agent-tool/index-write-queue.mjs';
96
- import { registerAutomationAgentTool } from '../session-runtime/automation-agents.mjs';
97
100
  import {
98
101
  compareRuntimeVersions,
99
102
  SESSION_CAPABILITY_FINGERPRINT,
@@ -607,11 +610,12 @@ function daemonStatusSnapshot() {
607
610
  }
608
611
 
609
612
  /** The file every attacher reads to find this daemon: wire identity plus both
610
- * loopback endpoints and their privileged tokens. */
613
+ * loopback endpoints and their privileged tokens. Written asynchronously
614
+ * (the secret file's owner-only ACL included), never on the event loop. */
611
615
  function publishDaemonDiscovery({ channel, session, modelProxy = null }) {
612
616
  // A re-publish keeps the first publication's startedAt.
613
617
  publishedEndpoints = { channel, session, modelProxy, startedAt: publishedEndpoints?.startedAt ?? Date.now() };
614
- writeJsonAtomicSync(
618
+ return writeJsonAtomicAsync(
615
619
  DAEMON_DISCOVERY_PATH,
616
620
  {
617
621
  protocol: SESSION_PROTOCOL,
@@ -658,6 +662,13 @@ function admitOwnerWork() {
658
662
  return ownerHeartbeat ? ownerHeartbeat.admit() : true;
659
663
  }
660
664
 
665
+ /** admitOwnerWork for the HTTP front doors: a request that arrives while the
666
+ * lease is being re-verified (the refresh is asynchronous) waits for that
667
+ * refresh instead of being refused. */
668
+ function admitOwnerWorkAsync() {
669
+ return ownerHeartbeat ? ownerHeartbeat.admitAsync() : true;
670
+ }
671
+
661
672
  /** This process no longer holds (or is about to lose) the owner lease: refuse
662
673
  * new work at once, unpublish its endpoint so launchers stop finding it, then
663
674
  * shut down within the shutdown budget — before a contender may reclaim. */
@@ -678,14 +689,31 @@ function fenceDaemon(reason) {
678
689
  /** Heartbeat follow-up while this process still owns the lock: a daemon.json
679
690
  * deleted (TEMP cleanup) or overwritten while it runs is written again, so
680
691
  * new clients keep finding the one daemon that serves this data dir. */
692
+ // Read and rewritten asynchronously, one check at a time: this runs after
693
+ // every heartbeat, and its synchronous read of daemon.json was measured
694
+ // blocking the loop for 5.9 s under disk contention.
695
+ let republishing = false;
681
696
  function republishMissingDiscovery() {
682
- if (!publishedEndpoints || shuttingDown || discoveryPid(DAEMON_DISCOVERY_PATH) === process.pid) return;
683
- try {
684
- publishDaemonDiscovery(publishedEndpoints);
685
- log('daemon.json was missing or named another pid — re-published');
686
- } catch (error) {
687
- log(`daemon.json re-publish failed: ${error?.message || error}`);
688
- }
697
+ if (!publishedEndpoints || shuttingDown || republishing) return;
698
+ republishing = true;
699
+ void (async () => {
700
+ try {
701
+ if ((await readDiscoveryAsync(DAEMON_DISCOVERY_PATH))?.pid === process.pid || shuttingDown) return;
702
+ await publishDaemonDiscovery(publishedEndpoints);
703
+ // Fenced while it was written: take it back down (fenceDaemon already ran).
704
+ if (shuttingDown) {
705
+ if ((await readDiscoveryAsync(DAEMON_DISCOVERY_PATH))?.pid === process.pid) {
706
+ rmSync(DAEMON_DISCOVERY_PATH, { force: true });
707
+ }
708
+ return;
709
+ }
710
+ log('daemon.json was missing or named another pid — re-published');
711
+ } catch (error) {
712
+ log(`daemon.json re-publish failed: ${error?.message || error}`);
713
+ } finally {
714
+ republishing = false;
715
+ }
716
+ })();
689
717
  }
690
718
 
691
719
  /** Ready handshake for the spawner, plus the log-sink handoff pinned to the
@@ -757,7 +785,7 @@ async function startChannelFrontDoor({ channelsRuntime, bootPhases }) {
757
785
  transport = createChannelTransport({
758
786
  handleCall: channelsRuntime.handleCall,
759
787
  agentBroker: agentDispatchBroker,
760
- admitWork: admitOwnerWork,
788
+ admitWork: admitOwnerWorkAsync,
761
789
  log,
762
790
  // The durable channel link lives in this file. Without it a restart loses
763
791
  // the pinned session (nothing to restore) and every catalog reports Remote
@@ -898,9 +926,6 @@ async function main() {
898
926
  cwd: CWD,
899
927
  });
900
928
  canonicalAgentControl = agentControl;
901
- // Schedules and webhooks run headless here; their sessions reach the same
902
- // canonical agent control through the automation tool scope.
903
- registerAutomationAgentTool(agentControl.execute);
904
929
  const requestedRuntimeMode = String(process.env.MIXDOG_SESSION_RUNTIME_MODE || '')
905
930
  .trim()
906
931
  .toLowerCase();
@@ -957,6 +982,22 @@ async function main() {
957
982
  },
958
983
  log,
959
984
  });
985
+ // Schedule results reach an open home thread at once (and wait out its turn).
986
+ setAgentHomeLiveSurface({
987
+ busy: (sessionId) => sessionService.liveSessionBusy(sessionId),
988
+ notice: (sessionId, notice) => sessionService.pushLiveSessionNotice(sessionId, notice),
989
+ // A task session's result (session create): the agent relays it in one turn.
990
+ wake: (sessionId, prompt) =>
991
+ sessionService.submitSession({ sessionId, prompt, options: { mode: 'prompt', kickoff: true } }),
992
+ // A routine fire: one queued turn in its bot's thread (routine-home-turn.mjs).
993
+ submit: async (sessionId, prompt, options) =>
994
+ (await sessionService.submitSession({ sessionId, prompt, options }))?.accepted === true,
995
+ abort: (sessionId) => sessionService.abortSession({ sessionId }),
996
+ });
997
+ // Results queued before a restart are posted now; results a finished run
998
+ // could not queue (kept on its routine's record) are queued again.
999
+ recoverScheduleResults().catch((error) => log(`routine results recovery failed: ${error?.message || error}`));
1000
+ recoverRoutineDeliveries().catch((error) => log(`routine delivery recovery failed: ${error?.message || error}`));
960
1001
  sessionTransport = createSessionTransport({
961
1002
  // ctx carries the CLIENT token: the session service refcounts views across
962
1003
  // processes with it, so a terminal exiting cannot destroy the session a
@@ -974,7 +1015,7 @@ async function main() {
974
1015
  } catch {}
975
1016
  },
976
1017
  onUpgradeRequested: requestDaemonReplacement,
977
- admitWork: admitOwnerWork,
1018
+ admitWork: admitOwnerWorkAsync,
978
1019
  });
979
1020
  const sessionEndpoint = await bootPhases.measure('session-transport-start', () => sessionTransport.start());
980
1021
  const modelProxyEndpoint = await startModelProxyBridge(bootPhases);
@@ -988,7 +1029,7 @@ async function main() {
988
1029
  exitRecorder.setReason(`owner claim superseded by pid=${ownerPid} before publish`, 0);
989
1030
  process.exit(0);
990
1031
  }
991
- publishDaemonDiscovery({ channel: { port, token }, session: sessionEndpoint, modelProxy: modelProxyEndpoint });
1032
+ await publishDaemonDiscovery({ channel: { port, token }, session: sessionEndpoint, modelProxy: modelProxyEndpoint });
992
1033
  bootPhases.mark('discovery-published');
993
1034
  log(`session front door on 127.0.0.1:${sessionEndpoint.port}`);
994
1035
 
@@ -1000,6 +1041,9 @@ async function main() {
1000
1041
  void sessionRuntimeHost?.warmLocalRuntime?.();
1001
1042
  });
1002
1043
  startPostgresInBackground();
1044
+ // Secret writes (token stores, config) find the ACL helpers already running
1045
+ // instead of starting one under their file lock.
1046
+ void prewarmOwnerOnlyAclWin32();
1003
1047
 
1004
1048
  // Automation may spawn the shared daemon; keep schedules/webhooks live.
1005
1049
  // A TUI-spawned daemon keeps the historical eager start (its channels client
@@ -85,6 +85,10 @@ export function createSessionCallCache({
85
85
  // Identity cannot be removed inside the promised retry TTL.
86
86
  for (const [key, record] of records) {
87
87
  if (records.size <= maxEntries && retainedBytes <= maxBytes) return;
88
+ // Insertion order is `at` order and settledAt >= at, so no later record
89
+ // can have left its TTL: stop instead of rescanning every live entry on
90
+ // each new call while a burst holds the cache above its budget.
91
+ if (at - record.at < ttlMs) break;
88
92
  if (!record.settled || !record.settledAt) continue;
89
93
  if (at - record.settledAt < ttlMs) continue;
90
94
  remove(key, record);
@@ -120,6 +124,8 @@ export function createSessionCallCache({
120
124
  bytes: 0,
121
125
  timer: null,
122
126
  };
127
+ // Re-insert at the tail so Map order stays `at` order (prune relies on it).
128
+ remove(key);
123
129
  records.set(key, record);
124
130
  prune();
125
131
  promise