mixdog 1.4.2 → 1.4.3

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 (417) hide show
  1. package/package.json +2 -2
  2. package/scripts/build-shipped-history.mjs +15 -5
  3. package/scripts/gate-local.mjs +65 -19
  4. package/scripts/graph-parity.mjs +8 -3
  5. package/scripts/lib/gate-scheduler.mjs +2 -1
  6. package/scripts/lib/run-node-tests.mjs +17 -5
  7. package/scripts/lib/test-failure-summary.mjs +1 -8
  8. package/scripts/lib/test-spawn-ledger.mjs +33 -2
  9. package/scripts/post-release-check.mjs +26 -16
  10. package/scripts/provider-pingpong-live.mjs +1 -1
  11. package/scripts/prune-embedding-runtime.mjs +3 -1
  12. package/scripts/release-paths.mjs +7 -1
  13. package/src/defaults/shipped-history.json +20 -0
  14. package/src/defaults/skills/setup/SKILL.md +2 -2
  15. package/src/defaults/skills/setup/references/actions.md +16 -3
  16. package/src/defaults/skills/setup/references/surfaces.md +3 -0
  17. package/src/defaults/skills/setup-guide/SKILL.md +6 -1
  18. package/src/lib/instruction-text.cjs +36 -0
  19. package/src/lib/rules-builder.cjs +34 -20
  20. package/src/orchestration/balanced.md +23 -0
  21. package/src/orchestration/focused.md +22 -0
  22. package/src/orchestration/none.md +5 -0
  23. package/src/orchestration/swarm.md +24 -0
  24. package/src/rules/agent-mode/AGENT_MODE.md +3 -1
  25. package/src/rules/agent-mode/MIXY.md +2 -2
  26. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +3 -3
  27. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +0 -1
  28. package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +4 -2
  29. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +0 -9
  30. package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +2 -2
  31. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +67 -0
  32. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +1 -0
  33. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +4 -4
  34. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -1
  35. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +199 -46
  36. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +3 -5
  37. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +9 -3
  38. package/src/runtime/agent/orchestrator/mcp/client.mjs +3 -5
  39. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +1 -1
  40. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +8 -2
  41. package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +1 -1
  42. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +14 -0
  43. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +1 -1
  44. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  45. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-stop.mjs +3 -3
  46. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
  47. package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +2 -2
  48. package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +4 -6
  49. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2784 -2872
  50. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +5 -8
  51. package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +288 -300
  52. package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +10 -1
  53. package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +10 -30
  54. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +30 -0
  55. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +0 -11
  56. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +8 -0
  57. package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +17 -3
  58. package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +47 -27
  59. package/src/runtime/agent/orchestrator/runtime-core/goal-deadlines.mjs +141 -10
  60. package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +26 -63
  61. package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +28 -3
  62. package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +36 -11
  63. package/src/runtime/agent/orchestrator/runtime-core/goal-state.mjs +88 -56
  64. package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +4 -1
  65. package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +51 -32
  66. package/src/runtime/agent/orchestrator/runtime-core/goal-text.mjs +45 -145
  67. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-defs.mjs +15 -98
  68. package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +32 -99
  69. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +23 -78
  70. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +69 -48
  71. package/src/runtime/agent/orchestrator/runtime-core/todo-list.mjs +367 -0
  72. package/src/runtime/agent/orchestrator/runtime-core/todo-tool-defs.mjs +47 -0
  73. package/src/runtime/agent/orchestrator/runtime-core/tool-availability.mjs +155 -0
  74. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +9 -0
  75. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +119 -35
  76. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +1 -1
  77. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
  78. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +28 -22
  79. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +30 -0
  80. package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +1 -1
  81. package/src/runtime/agent/orchestrator/session/cache-warm.mjs +2 -2
  82. package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +2 -2
  83. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +1 -1
  84. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -1
  85. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +3 -0
  86. package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +1 -1
  87. package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -12
  88. package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +1 -1
  89. package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +1 -1
  90. package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +1 -1
  91. package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +7 -3
  92. package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +1 -1
  93. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +1 -2
  94. package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +1 -1
  95. package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +1 -1
  96. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +11 -1
  97. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +1 -1
  98. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +8 -1
  99. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/todo-check.mjs +196 -0
  100. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +116 -50
  101. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +8 -1
  102. package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +1 -1
  103. package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +1 -1
  104. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -1
  105. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +5 -6
  106. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +6 -1
  107. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
  108. package/src/runtime/agent/orchestrator/session/loop/turn-report.mjs +35 -0
  109. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +1 -1
  110. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +57 -26
  111. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +9 -7
  112. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +21 -3
  113. package/src/runtime/agent/orchestrator/session/manager/ask-turn-failure.mjs +27 -11
  114. package/src/runtime/agent/orchestrator/session/manager/ask-turn-open.mjs +37 -34
  115. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +15 -0
  116. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +25 -15
  117. package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +79 -24
  118. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +3 -0
  119. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +12 -1
  120. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +1 -1
  121. package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +6 -1
  122. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +9 -1
  123. package/src/runtime/agent/orchestrator/session/manager/pending-spool-path.mjs +2 -2
  124. package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +1 -1
  125. package/src/runtime/agent/orchestrator/session/manager/prompt-settings.mjs +598 -0
  126. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +19 -0
  127. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +19 -10
  128. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +5 -0
  129. package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +1 -1
  130. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +31 -0
  131. package/src/runtime/agent/orchestrator/session/manager/session-lock.mjs +31 -0
  132. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +42 -6
  133. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +2 -0
  134. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +11 -1
  135. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +8 -9
  136. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +339 -88
  137. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-recovery.mjs +135 -11
  138. package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +377 -104
  139. package/src/runtime/agent/orchestrator/session/manager/turn-durability.mjs +144 -0
  140. package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +1 -1
  141. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +4 -0
  142. package/src/runtime/agent/orchestrator/session/manager.mjs +6 -0
  143. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +1 -1
  144. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +8 -1
  145. package/src/runtime/agent/orchestrator/session/save-session-worker.mjs +5 -1
  146. package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +1 -1
  147. package/src/runtime/agent/orchestrator/session/store/liveness-veto.mjs +2 -2
  148. package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +23 -2
  149. package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +3 -3
  150. package/src/runtime/agent/orchestrator/session/store/transcript-durability.mjs +88 -0
  151. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +5 -0
  152. package/src/runtime/agent/orchestrator/session/store-summary-log.mjs +1 -1
  153. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +14 -5
  154. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +2 -2
  155. package/src/runtime/agent/orchestrator/session/store.mjs +5 -0
  156. package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +7 -1
  157. package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +9 -1
  158. package/src/runtime/agent/orchestrator/session/transcript-restore/agent-envelope.mjs +1 -1
  159. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +3 -1
  160. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +2 -2
  161. package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -5
  162. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -1
  163. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +21 -3
  164. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
  165. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/worktree-add-guard.mjs +77 -0
  166. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +0 -1
  167. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +7 -3
  168. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +27 -9
  169. package/src/runtime/agent/orchestrator/tools/builtin/lib/search-input-helpers.mjs +2 -2
  170. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +1 -1
  171. package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +0 -1
  172. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +0 -10
  173. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +1 -2
  174. package/src/runtime/agent/orchestrator/tools/builtin.mjs +1 -24
  175. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary/child-kill.mjs +4 -3
  176. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +1 -2
  177. package/src/runtime/agent/orchestrator/tools/code-graph/modes/calls.mjs +1 -1
  178. package/src/runtime/agent/orchestrator/tools/code-graph/modes/symbols.mjs +2 -2
  179. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +4 -5
  180. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +3 -4
  181. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4 -22
  182. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +2 -2
  183. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +1 -1
  184. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +0 -4
  185. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +0 -1
  186. package/src/runtime/attachments/attachment-reference.mjs +1 -1
  187. package/src/runtime/attachments/pdf-extract.mjs +1 -1
  188. package/src/runtime/attachments/store.d.mts +1 -0
  189. package/src/runtime/attachments/store.mjs +2 -2
  190. package/src/runtime/channels/lib/config-reload-watch.mjs +42 -0
  191. package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +29 -9
  192. package/src/runtime/channels/lib/scheduler.mjs +33 -0
  193. package/src/runtime/channels/lib/schedules-db.mjs +11 -4
  194. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +4 -1
  195. package/src/runtime/channels/lib/webhooks-db.mjs +9 -3
  196. package/src/runtime/channels/lib/whisper-server.mjs +12 -12
  197. package/src/runtime/channels/lib/worker-main.mjs +9 -31
  198. package/src/runtime/computer-bridge/linux-readiness.mjs +10 -14
  199. package/src/runtime/connectors/connector-accounts-mcp.mjs +169 -33
  200. package/src/runtime/connectors/gmail-app-password.mjs +2 -2
  201. package/src/runtime/connectors/google-mcp.mjs +1 -1
  202. package/src/runtime/effort-judge/judge-client.mjs +2 -2
  203. package/src/runtime/effort-judge/judge-input.mjs +4 -4
  204. package/src/runtime/explore/explorer.mjs +0 -5
  205. package/src/runtime/explore/tool.mjs +3 -3
  206. package/src/runtime/local-provider/hardware.mjs +1 -1
  207. package/src/runtime/media/adapters/codex-image.mjs +3 -3
  208. package/src/runtime/media/adapters/gemini-video.mjs +1 -1
  209. package/src/runtime/media/media-usage.mjs +1 -1
  210. package/src/runtime/media/store.mjs +1 -1
  211. package/src/runtime/memory/index.mjs +11 -1
  212. package/src/runtime/memory/lib/embedding-reindex.mjs +27 -0
  213. package/src/runtime/memory/lib/memory-embed.mjs +83 -14
  214. package/src/runtime/memory/lib/memory-process-lock.mjs +159 -36
  215. package/src/runtime/memory/lib/memory-text-utils.mjs +6 -1
  216. package/src/runtime/memory/lib/memory.mjs +17 -0
  217. package/src/runtime/memory/lib/pg/process.mjs +1 -1
  218. package/src/runtime/memory/lib/pg/supervisor.mjs +16 -96
  219. package/src/runtime/memory/lib/recall-hybrid/hybrid-sql.mjs +12 -3
  220. package/src/runtime/office/authoring/docx-html-runner.mjs +1 -1
  221. package/src/runtime/office/authoring/pptx-author-action.mjs +1 -1
  222. package/src/runtime/office/authoring/xlsx-html-build.mjs +1 -1
  223. package/src/runtime/office/authoring/xlsx-html-runner.mjs +1 -1
  224. package/src/runtime/office/capabilities.mjs +1 -1
  225. package/src/runtime/office/core/office-core.mjs +1 -1
  226. package/src/runtime/office/design/content-model.mjs +3 -3
  227. package/src/runtime/office/design/docx/design-docx/section.mjs +6 -6
  228. package/src/runtime/office/design/xlsx/design-xlsx-components.mjs +1 -1
  229. package/src/runtime/office/design/xlsx/design-xlsx.mjs +1 -1
  230. package/src/runtime/office/pdf/ocr-engine.mjs +1 -1
  231. package/src/runtime/office/pdf/pdf-writer.mjs +4 -4
  232. package/src/runtime/office/portable/portable-docx-operations.mjs +2 -2
  233. package/src/runtime/office/portable/portable-soffice.mjs +8 -6
  234. package/src/runtime/office/portable/xlsx-contract.mjs +1 -1
  235. package/src/runtime/shared/atomic-file.d.mts +8 -0
  236. package/src/runtime/shared/background-tasks.mjs +22 -4
  237. package/src/runtime/shared/background-wait.mjs +66 -0
  238. package/src/runtime/shared/child-guardian.mjs +17 -7
  239. package/src/runtime/shared/config.mjs +313 -16
  240. package/src/runtime/shared/connector-catalog.d.mts +4 -5
  241. package/src/runtime/shared/connector-catalog.mjs +11 -1
  242. package/src/runtime/shared/file-lock.mjs +8 -3
  243. package/src/runtime/shared/git-runner.mjs +7 -2
  244. package/src/runtime/shared/idle-gc.mjs +30 -7
  245. package/src/runtime/shared/llm/http-agent.mjs +8 -5
  246. package/src/runtime/shared/llm/system-proxy.mjs +2 -1
  247. package/src/runtime/shared/llm/usage-ledger-quota.mjs +31 -12
  248. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +84 -8
  249. package/src/runtime/shared/llm/usage-ledger.mjs +3 -0
  250. package/src/runtime/shared/llm/usage-rollup.mjs +48 -0
  251. package/src/runtime/shared/maintenance-schedule.mjs +109 -0
  252. package/src/runtime/shared/process-runner.mjs +8 -4
  253. package/src/runtime/shared/routine-trigger.d.mts +13 -0
  254. package/src/runtime/shared/routine-trigger.mjs +34 -0
  255. package/src/runtime/shared/run-child.d.mts +2 -1
  256. package/src/runtime/shared/run-child.mjs +70 -18
  257. package/src/runtime/shared/session-scratch.mjs +14 -2
  258. package/src/runtime/shared/shipped-definitions.mjs +7 -1
  259. package/src/runtime/shared/tool-card-model.golden.json +3 -12
  260. package/src/runtime/shared/tool-execution-contract.mjs +2 -0
  261. package/src/runtime/shared/tool-work-units.mjs +31 -6
  262. package/src/runtime/shared/turn-snapshot.mjs +26 -4
  263. package/src/runtime/shared/turn-worktree-snapshot.mjs +6 -11
  264. package/src/runtime/shared/worker-requests.mjs +17 -3
  265. package/src/runtime/shared/worktrees/branch-management.mjs +1 -5
  266. package/src/runtime/shared/worktrees/contract.mjs +16 -6
  267. package/src/runtime/shared/worktrees/dependencies.mjs +127 -89
  268. package/src/runtime/shared/worktrees/disk.mjs +79 -2
  269. package/src/runtime/shared/worktrees/git.mjs +44 -11
  270. package/src/runtime/shared/worktrees/include.mjs +6 -4
  271. package/src/runtime/shared/worktrees/maintenance.mjs +422 -30
  272. package/src/runtime/shared/worktrees/manager.mjs +772 -75
  273. package/src/runtime/shared/worktrees/settings.mjs +33 -7
  274. package/src/runtime/shared/worktrees/test-support.mjs +5 -1
  275. package/src/runtime/shared/worktrees/worker-snapshots.mjs +82 -0
  276. package/src/runtime/tidy/process.mjs +2 -1
  277. package/src/runtime/web-search/index.mjs +3 -22
  278. package/src/runtime/web-search/lib/web-tools.mjs +2 -2
  279. package/src/runtime/web-search/tool-defs.mjs +17 -26
  280. package/src/session-runtime/agent-profile-changes.mjs +55 -4
  281. package/src/session-runtime/boot/apis.mjs +27 -4
  282. package/src/session-runtime/boot/begin.mjs +2 -0
  283. package/src/session-runtime/boot/config.mjs +10 -1
  284. package/src/session-runtime/boot/facade.mjs +1 -0
  285. package/src/session-runtime/boot/providers.mjs +70 -3
  286. package/src/session-runtime/boot/session.mjs +2 -0
  287. package/src/session-runtime/boot/tools.mjs +69 -25
  288. package/src/session-runtime/channel-config-api.mjs +1 -0
  289. package/src/session-runtime/config-change-effects.mjs +179 -0
  290. package/src/session-runtime/config-lifecycle/config-writers.mjs +1 -0
  291. package/src/session-runtime/config-lifecycle.mjs +160 -24
  292. package/src/session-runtime/conversation-import/discovery.mjs +86 -7
  293. package/src/session-runtime/conversation-import/service.mjs +3 -2
  294. package/src/session-runtime/goal-facade-api.mjs +49 -3
  295. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +3 -0
  296. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -2
  297. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +3 -11
  298. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +18 -4
  299. package/src/session-runtime/internal-tool-executor.mjs +12 -19
  300. package/src/session-runtime/lifecycle/cold-heir.mjs +7 -0
  301. package/src/session-runtime/lifecycle/memory-ingest.mjs +3 -3
  302. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +53 -5
  303. package/src/session-runtime/lifecycle/session-switch.mjs +13 -2
  304. package/src/session-runtime/lifecycle/teardown/session-close.mjs +4 -4
  305. package/src/session-runtime/lifecycle-api.mjs +1 -0
  306. package/src/session-runtime/mcp-glue/server-catalog.mjs +14 -3
  307. package/src/session-runtime/mcp-glue/server-connection.mjs +34 -8
  308. package/src/session-runtime/model-route/set-route.mjs +40 -7
  309. package/src/session-runtime/native-web-search/routes.mjs +3 -3
  310. package/src/session-runtime/provider-auth/refresh.mjs +6 -3
  311. package/src/session-runtime/provider-auth/setup.mjs +1 -1
  312. package/src/session-runtime/provider-readiness.mjs +53 -4
  313. package/src/session-runtime/resource-api.mjs +1 -1
  314. package/src/session-runtime/resource-extension-sync.mjs +4 -8
  315. package/src/session-runtime/resource-mcp-connector-accounts.mjs +5 -1
  316. package/src/session-runtime/resource-mcp-secrets.mjs +3 -3
  317. package/src/session-runtime/resource-plugins-api.mjs +4 -0
  318. package/src/session-runtime/routine-executor.mjs +152 -0
  319. package/src/session-runtime/routine-home-turn.mjs +46 -5
  320. package/src/session-runtime/runtime-facade.mjs +5 -0
  321. package/src/session-runtime/runtime-feature-gates.mjs +2 -11
  322. package/src/session-runtime/schedule-session-run.mjs +1 -0
  323. package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +6 -1
  324. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +7 -0
  325. package/src/session-runtime/services/agent-tool/send-flow.mjs +110 -6
  326. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +12 -0
  327. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +5 -0
  328. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +24 -6
  329. package/src/session-runtime/services/agent-tool.mjs +51 -1
  330. package/src/session-runtime/services/channel-admin.mjs +18 -0
  331. package/src/session-runtime/services/hook-bus/command-handler.mjs +7 -11
  332. package/src/session-runtime/services/plugin-admin.mjs +4 -0
  333. package/src/session-runtime/services/seeds.mjs +7 -0
  334. package/src/session-runtime/services/usage-stats-model.mjs +32 -11
  335. package/src/session-runtime/session-create/materialize.mjs +4 -2
  336. package/src/session-runtime/session-create/session-options.mjs +2 -0
  337. package/src/session-runtime/settings-builtin-tools-api.mjs +1 -9
  338. package/src/session-runtime/setup-tool/connector-widen-approval.mjs +1 -1
  339. package/src/session-runtime/setup-tool/executor.mjs +8 -1
  340. package/src/session-runtime/setup-tool/extended-actions.mjs +2 -0
  341. package/src/session-runtime/setup-tool/settings-contract.mjs +28 -0
  342. package/src/session-runtime/setup-tool/tool-defs.mjs +26 -1
  343. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +40 -43
  344. package/src/session-runtime/tool-policy/mode-switch.mjs +1 -1
  345. package/src/session-runtime/tool-policy/policy-stage.mjs +106 -8
  346. package/src/session-runtime/tool-policy/workflow-overlay.mjs +2 -1
  347. package/src/session-runtime/tool-policy-refresh.mjs +182 -5
  348. package/src/session-runtime/tool-surface.mjs +38 -1
  349. package/src/session-runtime/turn/agent-ops.mjs +10 -2
  350. package/src/session-runtime/turn/session-ops.mjs +2 -0
  351. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +5 -0
  352. package/src/session-runtime/turn/turn-run.mjs +1 -1
  353. package/src/session-runtime/webhook-session-run.mjs +2 -0
  354. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +1 -4
  355. package/src/session-runtime/workflow-agents-api/agent-route.mjs +3 -10
  356. package/src/session-runtime/workflow-agents-api/instruction-files.mjs +165 -0
  357. package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +5 -4
  358. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +2 -3
  359. package/src/session-runtime/workflow-agents-api.mjs +2 -0
  360. package/src/session-runtime/workspace/project-branches.mjs +1 -1
  361. package/src/session-runtime/workspace/session-view.mjs +1 -1
  362. package/src/session-runtime/workspace/transitions.mjs +20 -4
  363. package/src/session-runtime/workspace/worktree-maintenance.mjs +126 -6
  364. package/src/session-runtime/workspace/worktree-setup.mjs +13 -1
  365. package/src/session-runtime/workspace/worktree-tool.mjs +16 -0
  366. package/src/standalone/daemon-agent-control.mjs +25 -8
  367. package/src/standalone/daemon-desktop-runtime.mjs +6 -2
  368. package/src/standalone/daemon-lag-profiler.mjs +7 -7
  369. package/src/standalone/daemon.mjs +54 -2
  370. package/src/standalone/local-session-runtime.mjs +16 -0
  371. package/src/standalone/session-client/daemon-unavailable.mjs +1 -1
  372. package/src/standalone/session-protocol.mjs +11 -0
  373. package/src/standalone/session-service/agent-route-follow.mjs +23 -20
  374. package/src/standalone/session-service/agent-tree/agent-turns.mjs +18 -6
  375. package/src/standalone/session-service/quota-resume.mjs +9 -0
  376. package/src/standalone/session-service/session-calls/session-action.mjs +51 -1
  377. package/src/standalone/session-service/session-calls/session-turns.mjs +37 -18
  378. package/src/standalone/session-service/session-calls/turn-gate.mjs +34 -0
  379. package/src/standalone/session-service/session-calls.mjs +2 -1
  380. package/src/tui/App.jsx +8 -0
  381. package/src/tui/app/clipboard.mjs +1 -1
  382. package/src/tui/app/create-app-pickers.mjs +2 -0
  383. package/src/tui/app/doctor.mjs +2 -2
  384. package/src/tui/app/panel-signature.mjs +1 -1
  385. package/src/tui/app/settings-picker.mjs +53 -8
  386. package/src/tui/app/shell-layout/row-budgets.mjs +2 -2
  387. package/src/tui/app/slash-commands.mjs +1 -1
  388. package/src/tui/app/slash-dispatch/route-commands.mjs +1 -1
  389. package/src/tui/app/slash-dispatch/session-commands.mjs +1 -1
  390. package/src/tui/app/use-prompt-queue-history.mjs +2 -2
  391. package/src/tui/app/use-transcript-activity.mjs +1 -1
  392. package/src/tui/app/use-transcript-window/geometry.mjs +1 -1
  393. package/src/tui/components/prompt-input/escape-policy.d.mts +0 -1
  394. package/src/tui/components/prompt-input/escape-policy.mjs +1 -1
  395. package/src/tui/components/question-panel-model.mjs +4 -4
  396. package/src/tui/components/tool-execution/standard-card.jsx +3 -4
  397. package/src/tui/components/user-message-skills.mjs +1 -1
  398. package/src/tui/dist/index.mjs +309 -30
  399. package/src/tui/markdown/render-ansi.mjs +1 -1
  400. package/src/tui/session/agent-job-feed/notification-router.mjs +10 -0
  401. package/src/tui/session/agent-job-feed.mjs +2 -0
  402. package/src/tui/session/context-state.mjs +3 -0
  403. package/src/tui/session/quota-resume.mjs +1 -1
  404. package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
  405. package/src/tui/session/session-api/lifecycle/session-reset.mjs +7 -0
  406. package/src/tui/session/session-api/routes-agent-definitions.mjs +5 -0
  407. package/src/tui/session/session-api/worktree.mjs +13 -1
  408. package/src/tui/session/session-flow/drain.mjs +11 -14
  409. package/src/tui/session/tool-card-results/grouped-result.mjs +2 -2
  410. package/src/tui/session/turn-quiet.mjs +1 -1
  411. package/src/tui/session/turn.mjs +3 -0
  412. package/src/tui/session/worktree-setup-notice.mjs +1 -1
  413. package/src/tui/spinner-meta.mjs +3 -3
  414. package/src/tui/spinner-verbs.mjs +2 -2
  415. package/src/defaults/skills/goal-management/SKILL.md +0 -169
  416. package/src/runtime/agent/orchestrator/runtime-core/goal-tasks.mjs +0 -156
  417. package/src/session-runtime/goal-tasks.mjs +0 -1
@@ -61,8 +61,20 @@ export function createWorktreeSetup({ backend, newTxId, planWorktreeSetup, runWo
61
61
  }
62
62
  }
63
63
  };
64
+ if (claimed.blocked?.length) {
65
+ report.notes.push(
66
+ `Dependencies were not installed: ${claimed.blocked.join(', ')} ${claimed.blocked.length > 1 ? 'are links' : 'is a link'}, and any install here could empty the folder it points at (such as the main checkout's) through it. Remove the link (never its target); the next turn installs.`
67
+ );
68
+ session.pendingSetupNotice = { revision: Date.now(), content: worktreePreparationNote(report) };
69
+ return;
70
+ }
64
71
  try {
65
- const plan = await planWorktreeSetup({ worktreeDir: here.cwd, mainDir: here.projectPath, signal });
72
+ const plan = await planWorktreeSetup({
73
+ worktreeDir: here.cwd,
74
+ mainDir: here.projectPath,
75
+ shared: claimed.shared ?? [],
76
+ signal,
77
+ });
66
78
  report.dependencyNotes = plan.notes;
67
79
  if (plan.commands.length) {
68
80
  report.installs = await runWorktreeSetup({ commands: plan.commands, signal, onProgress: emit });
@@ -147,6 +147,11 @@ export function createWorktreeToolHost({ getSession, getWorkspaceApi, executeSes
147
147
  }
148
148
  const lane = laneFor(entry.ownerSessionId, callerSessionId, scope);
149
149
  const menu = await lane.menu();
150
+ // This session's worktree that it does not work in: removed where it is,
151
+ // without entering it (its own running workers elsewhere never block that).
152
+ if (lane.own && menu.workspace?.worktreeId !== entry.id) {
153
+ return workspaceApi().removeOwnedWorktree({ entryId: entry.id, force: request.force === true });
154
+ }
150
155
  if (menu.retainedWorktree?.id !== entry.id) {
151
156
  throw new Error(
152
157
  `git worktree remove: ${entry.path} is not the current worktree of session ${entry.ownerSessionId}; enter it (worktree_action enter, branch ${entry.branch}) first, then remove it`
@@ -174,6 +179,17 @@ export function createWorktreeToolHost({ getSession, getWorkspaceApi, executeSes
174
179
  return merge(lane());
175
180
  case 'remove': {
176
181
  const force = request.force === true;
182
+ if (request.branch) {
183
+ // By branch: the managed worktree of that branch this session owns.
184
+ const rows = await workspaceApi().listWorktrees();
185
+ const row = rows.find((item) => item.branch === request.branch && item.ownerSessionId === callerSessionId);
186
+ if (!row) {
187
+ throw new Error(
188
+ `git worktree remove: this session owns no managed worktree of branch ${request.branch}; git worktree list shows them`
189
+ );
190
+ }
191
+ return removePath({ path: row.path, force }, callerSessionId, scope);
192
+ }
177
193
  if (request.sessionId && request.sessionId !== callerSessionId) {
178
194
  const gone = await orphan((row) => row.ownerSessionId === request.sessionId);
179
195
  if (gone) return workspaceApi().removeOrphanWorktree({ entryId: gone.id, force });
@@ -6,7 +6,7 @@
6
6
  //
7
7
  // Inputs: `getSessionService` / `getSessionRuntimeHost` (both are wired after
8
8
  // this control exists — the host takes `execute` as a constructor option), and
9
- // `cwd`. Output: { canonicalAgentTool, execute }.
9
+ // `cwd`. Output: { canonicalAgentTool, execute, runForeground, dispose }.
10
10
 
11
11
  export function createCanonicalAgentControl({ getSessionService, getSessionRuntimeHost, cwd }) {
12
12
  let canonicalAgentToolPromise = null;
@@ -43,16 +43,33 @@ export function createCanonicalAgentControl({ getSessionService, getSessionRunti
43
43
  return canonicalAgentToolPromise;
44
44
  }
45
45
 
46
- async function execute(args = {}, context = {}) {
47
- const tool = await canonicalAgentTool();
46
+ /** `context` rooted at its caller session (agent-tool: the owner is the caller's root). */
47
+ async function scopeContext(context) {
48
48
  const sessionService = getSessionService();
49
49
  const parentSessionId = String(context?.callerSessionId || '').trim();
50
50
  await sessionService.rehydrateAgentSessions();
51
- const scopedContext = {
52
- ...context,
53
- callerSessionId: parentSessionId || null,
54
- ownerSessionId: sessionService.rootOwnerSessionId(parentSessionId),
51
+ return {
52
+ parentSessionId,
53
+ sessionService,
54
+ scopedContext: {
55
+ ...context,
56
+ callerSessionId: parentSessionId || null,
57
+ ownerSessionId: sessionService.rootOwnerSessionId(parentSessionId),
58
+ },
55
59
  };
60
+ }
61
+
62
+ /** One agent run to its end for a caller with no session to hand it to
63
+ * (routine-executor.mjs): resolves `{ sessionId, content }`. */
64
+ async function runForeground(args = {}, context = {}, options = {}) {
65
+ const tool = await canonicalAgentTool();
66
+ const { scopedContext } = await scopeContext(context);
67
+ return await tool.runToCompletion(args, scopedContext, options);
68
+ }
69
+
70
+ async function execute(args = {}, context = {}) {
71
+ const tool = await canonicalAgentTool();
72
+ const { parentSessionId, sessionService, scopedContext } = await scopeContext(context);
56
73
  if (String(args?.type || '') === '__close_all') {
57
74
  await tool.closeAll?.(String(args?.reason || 'agent owner closed'), {
58
75
  callerSessionId: parentSessionId || null,
@@ -72,5 +89,5 @@ export function createCanonicalAgentControl({ getSessionService, getSessionRunti
72
89
  await tool?.disposeAsync?.({ settle: true });
73
90
  }
74
91
 
75
- return { canonicalAgentTool, execute, dispose };
92
+ return { canonicalAgentTool, execute, runForeground, dispose };
76
93
  }
@@ -12,12 +12,13 @@
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, tasks] = await Promise.all([
15
+ const [store, runtime, progress, tasks, liveState] = 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
20
  import('../runtime/shared/background-tasks.mjs'),
21
+ import('../runtime/agent/orchestrator/session/store/live-state.mjs'),
21
22
  ]);
22
23
  return {
23
24
  ...store,
@@ -33,7 +34,10 @@ async function loadSessionStoreWithRuntimeActivity() {
33
34
  });
34
35
  const awaiting = tasks.activeBackgroundTaskSessionIds({ surface: 'shell', awaitedOnly: true });
35
36
  return progress.withTurnProgress(
36
- rows,
37
+ progress.withLiveUsage(
38
+ progress.withLiveTodo(rows, (sessionId) => liveState._liveSessions.get(sessionId)),
39
+ (sessionId) => liveState._liveSessions.get(sessionId)
40
+ ),
37
41
  (sessionId) => runtime.runtimeState.get(sessionId),
38
42
  runtime.isTurnInFlight,
39
43
  (sessionId) => awaiting.has(sessionId)
@@ -15,14 +15,14 @@ import path from 'node:path';
15
15
  import { fileURLToPath } from 'node:url';
16
16
 
17
17
  export const LAG_PROFILE_FLAG_FILE = 'lag-profile.on';
18
- export const LAG_PROFILE_DIR_NAME = 'profiles';
19
- export const LAG_PROFILE_KEEP = 10;
20
- export const LAG_PROFILE_TOP = 15;
18
+ const LAG_PROFILE_DIR_NAME = 'profiles';
19
+ const LAG_PROFILE_KEEP = 10;
20
+ const LAG_PROFILE_TOP = 15;
21
21
  export const LAG_PROFILE_SAMPLING_US = 1000;
22
- export const LAG_P99_THRESHOLD_MS = 1000;
22
+ const LAG_P99_THRESHOLD_MS = 1000;
23
23
  // The owner lease's stall threshold: any window holding one logged
24
24
  // `event loop stalled` line is kept.
25
- export const LAG_MAX_THRESHOLD_MS = 1000;
25
+ const LAG_MAX_THRESHOLD_MS = 1000;
26
26
 
27
27
  const PROFILE_FILE_RE = /^daemon-lag-.+\.cpuprofile$/;
28
28
  const SRC_ROOT = fileURLToPath(new URL('..', import.meta.url));
@@ -90,12 +90,12 @@ export function summarizeCpuProfile(profile, { limit = LAG_PROFILE_TOP, srcRoot
90
90
  .slice(0, limit);
91
91
  }
92
92
 
93
- export function formatTopEntries(entries) {
93
+ function formatTopEntries(entries) {
94
94
  return entries.map((entry) => `${entry.label}=${Math.round(entry.ms)}ms`).join(',');
95
95
  }
96
96
 
97
97
  /** Keep only the `keep` newest daemon-lag profiles (names sort by timestamp). */
98
- export async function pruneProfiles(dir, keep = LAG_PROFILE_KEEP) {
98
+ async function pruneProfiles(dir, keep = LAG_PROFILE_KEEP) {
99
99
  const names = (await fsp.readdir(dir)).filter((name) => PROFILE_FILE_RE.test(name)).sort();
100
100
  const stale = names.slice(0, Math.max(0, names.length - keep));
101
101
  for (const name of stale) await fsp.rm(path.join(dir, name), { force: true });
@@ -841,6 +841,50 @@ async function startChannelFrontDoor({ channelsRuntime, bootPhases }) {
841
841
  return bootPhases.measure('channel-transport-start', () => transport.start());
842
842
  }
843
843
 
844
+ async function startDaemonMaintenance() {
845
+ const [schedule, liveness, { IN_FLIGHT_STAGES }] = await Promise.all([
846
+ import('../runtime/shared/maintenance-schedule.mjs'),
847
+ import('../runtime/agent/orchestrator/session/manager/runtime-liveness.mjs'),
848
+ import('../runtime/agent/orchestrator/session/manager/runtime-state.mjs'),
849
+ ]);
850
+ const entries = () => [...liveness._runtimeEntries()];
851
+ schedule.registerMaintenanceIdleProbe(
852
+ () =>
853
+ !entries().some(
854
+ ([, entry]) => (entry?.controller && !entry.controller.signal?.aborted) || IN_FLIGHT_STAGES.has(entry?.stage)
855
+ )
856
+ );
857
+ schedule.registerMaintenanceTask(
858
+ 'worktree-cleanup',
859
+ async () => {
860
+ const maintenance = await import('../runtime/shared/worktrees/maintenance.mjs');
861
+ // Every session with an open runtime entry here counts as live, read
862
+ // again right before each removal (one that opened meanwhile keeps its folder).
863
+ const liveSessionIds = () =>
864
+ entries()
865
+ .filter(([, entry]) => entry && entry.closed !== true)
866
+ .map(([id]) => id);
867
+ const report = await maintenance.runWorktreeCleanup({
868
+ liveSessionIds: liveSessionIds(),
869
+ currentLiveSessionIds: liveSessionIds,
870
+ });
871
+ const incomplete = report.kept.filter((item) => item.reason === 'incomplete');
872
+ if (report.removed.length || report.errors.length || incomplete.length) {
873
+ log(
874
+ `worktree cleanup: removed ${report.removed.length}, incomplete ${incomplete.length}` +
875
+ `${incomplete.length ? ` (${incomplete.map((item) => item.id).join(', ')})` : ''}, errors ${report.errors.length}`
876
+ );
877
+ }
878
+ },
879
+ {
880
+ intervalMs: 60 * 60_000,
881
+ initialDelayMs: 3 * 60_000,
882
+ onError: (error) => log(`worktree cleanup failed: ${error?.message || error}`),
883
+ }
884
+ );
885
+ schedule.startMaintenanceSchedule();
886
+ }
887
+
844
888
  async function main() {
845
889
  const startedAt = performance.now();
846
890
  const bootPhases = createBootPhaseProfiler({ log, startedAt });
@@ -865,14 +909,19 @@ async function main() {
865
909
  .then((maintenance) => maintenance.reconcileWorktreesAtStartup())
866
910
  .then((report) => {
867
911
  const changed = report.removed.length + report.recovered.length + report.pruned.length;
868
- if (changed || report.errors.length) {
912
+ const incomplete = report.kept.filter((item) => item.reason === 'incomplete').length;
913
+ if (changed || incomplete || report.errors.length) {
869
914
  log(
870
915
  `worktree reconcile: removed ${report.removed.length}, recovered ${report.recovered.length}, ` +
871
- `pruned ${report.pruned.length}, errors ${report.errors.length}`
916
+ `pruned ${report.pruned.length}, incomplete ${incomplete}, errors ${report.errors.length}`
872
917
  );
873
918
  }
874
919
  })
875
920
  .catch((error) => log(`worktree reconcile failed: ${error?.message || error}`));
921
+ // Idle-time housekeeping (shared/maintenance-schedule.mjs): the worktree
922
+ // cleanup's count/age limits and archive rules once the desktop (favorites)
923
+ // is attached, then hourly while no session is mid-turn.
924
+ void startDaemonMaintenance().catch((error) => log(`maintenance schedule failed: ${error?.message || error}`));
876
925
  // The daemon owns prompt attachments; its census runs off the boot path
877
926
  // (first attempt after the store's start delay, then per its interval).
878
927
  void import('../runtime/attachments/store.mjs').then((store) => store.startAttachmentGc()).catch(() => {});
@@ -1043,6 +1092,9 @@ async function main() {
1043
1092
  submit: async (sessionId, prompt, options) =>
1044
1093
  (await sessionService.submitSession({ sessionId, prompt, options }))?.accepted === true,
1045
1094
  abort: (sessionId) => sessionService.abortSession({ sessionId }),
1095
+ // A routine's executor sub-agent, run to its end before its bot is woken
1096
+ // (routine-executor.mjs); resolves `{ sessionId, content }`.
1097
+ runAgent: (args, context, options) => agentControl.runForeground(args, context, options),
1046
1098
  });
1047
1099
  // A bot's next turn, whatever starts it, first reads the progress updates
1048
1100
  // queued for its thread (they wake nobody on their own).
@@ -17,6 +17,7 @@ import { createToolCardResults } from '../tui/session/tool-card-results.mjs';
17
17
  import { createAgentJobFeed } from '../tui/session/agent-job-feed.mjs';
18
18
  import { createWorktreeSetupNotices } from '../tui/session/worktree-setup-notice.mjs';
19
19
  import { createContextState } from '../tui/session/context-state.mjs';
20
+ import { onTodoChange, todoSnapshot } from '../runtime/agent/orchestrator/runtime-core/todo-list.mjs';
20
21
  import { createSessionFlow } from '../tui/session/session-flow.mjs';
21
22
  import { createRunTurn } from '../tui/session/turn.mjs';
22
23
  import { createQuotaResumeLane } from '../tui/session/quota-resume.mjs';
@@ -147,6 +148,9 @@ export function createRuntimePulse({
147
148
  const pulse = () => {
148
149
  if (flags.disposed) return;
149
150
  if (flags.pendingSessionReset) return;
151
+ // A closed conversation has no session to read: republishing would blank
152
+ // its last todo and Goal for anyone still viewing it.
153
+ if (flags.admission === 'terminal') return;
150
154
  syncContextStats({ allowEstimated: true });
151
155
  publishChanged({
152
156
  ...routeState(),
@@ -385,6 +389,12 @@ export async function createLocalSessionRuntime({
385
389
  displayedExecutionNotificationKeys,
386
390
  pushNotice,
387
391
  itemIndexById,
392
+ // The status line's context gauge after an empty session's settings reconcile.
393
+ refreshContextStats: () => {
394
+ if (flags.disposed || flags.pendingSessionReset) return;
395
+ syncContextStats({ allowEstimated: true });
396
+ set({ stats: { ...getState().stats } });
397
+ },
388
398
  });
389
399
  lifecycle.unsubscribeRuntimeNotifications = subscribeRuntimeNotifications();
390
400
  if (typeof runtime.onWorktreeSetup === 'function') {
@@ -400,6 +410,12 @@ export async function createLocalSessionRuntime({
400
410
  });
401
411
  }
402
412
 
413
+ // A todo call republishes the list at once, not on the next 2s pulse.
414
+ lifecycle.unsubscribeTodo = onTodoChange(({ sessionId }) => {
415
+ if (flags.disposed || flags.pendingSessionReset || !sessionId || sessionId !== runtime.id) return;
416
+ set({ todo: todoSnapshot(runtime.session) });
417
+ });
418
+
403
419
  const { patchToolCardResult, flushToolResults } = createToolCardResults({
404
420
  getState,
405
421
  set,
@@ -4,7 +4,7 @@
4
4
  // owner that never published, the newest candidate's exit and first stderr
5
5
  // error — so the desktop error card's details name the cause, not only the
6
6
  // symptom.
7
- export const DAEMON_UNAVAILABLE_MESSAGE = 'daemon session endpoint is unavailable';
7
+ const DAEMON_UNAVAILABLE_MESSAGE = 'daemon session endpoint is unavailable';
8
8
 
9
9
  function exitCodeText(code) {
10
10
  // Windows reports NTSTATUS crash codes as large unsigned values.
@@ -12,6 +12,8 @@ export const SESSION_READ_ACTIONS = Object.freeze([
12
12
  'agentDefinitionPresence',
13
13
  'archivedAgentIdentities',
14
14
  'getAgentDefinition',
15
+ 'listInstructionFiles',
16
+ 'getInstructionFile',
15
17
  'getAgentAvatarImage',
16
18
  'getAgentConnectors',
17
19
  'getProjectConnectors',
@@ -82,6 +84,8 @@ export const SESSION_READ_ACTIONS = Object.freeze([
82
84
  'getBranchMenu',
83
85
  'getProjectBranchMenu',
84
86
  'listWorktrees',
87
+ 'previewWorktreeCleanup',
88
+ 'getSessionWorktreeWork',
85
89
  'hooksStatus',
86
90
  'inheritancePreflight',
87
91
  'listAgents',
@@ -136,6 +140,8 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
136
140
  'deleteAgentDefinition',
137
141
  'restoreAgentDefinition',
138
142
  'purgeAgentDefinition',
143
+ 'saveInstructionFile',
144
+ 'resetInstructionFile',
139
145
  'deleteHookRule',
140
146
  'deleteMediaAsset',
141
147
  'deleteMediaAssets',
@@ -149,6 +155,9 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
149
155
  'checkCustomProviderKeyEnv',
150
156
  'discoverCustomProviderModels',
151
157
  'deleteSession',
158
+ // The desktop's auto-delete: configureSession routes it through the turn
159
+ // gate (session-action.mjs deleteIdleSession), never the generic lane.
160
+ 'deleteSessionIfIdle',
152
161
  'deleteWebhook',
153
162
  'deleteWorkflow',
154
163
  'enablePluginMcp',
@@ -293,6 +302,8 @@ export const SESSION_CONFIGURE_ACTIONS = Object.freeze([
293
302
  'mergeWorkspace',
294
303
  'removeWorktree',
295
304
  'pruneWorktrees',
305
+ 'deleteWorktree',
306
+ 'setArchivedSessionWorktrees',
296
307
  ]);
297
308
 
298
309
  export const SESSION_READ_ACTION_SET = new Set(SESSION_READ_ACTIONS);
@@ -4,21 +4,13 @@
4
4
  // on the model it started on). The latest saved route wins. A thread no
5
5
  // runtime hosts keeps its model until it is opened (the desktop refreshes it
6
6
  // then, agent-home-sessions.ts).
7
- import { subscribeAgentRouteChanges } from '../../session-runtime/agent-profile-changes.mjs';
7
+ import {
8
+ AGENT_ROUTE_KEYS as ROUTE_KEYS,
9
+ subscribeAgentRouteChanges,
10
+ } from '../../session-runtime/agent-profile-changes.mjs';
8
11
  import { agentHomeSessionId } from '../../runtime/agent/orchestrator/session/agent-home.mjs';
9
12
  import { roomMemberOfSession } from '../../runtime/agent/orchestrator/session/agent-room.mjs';
10
13
 
11
- const ROUTE_KEYS = [
12
- 'provider',
13
- 'model',
14
- 'effort',
15
- 'fast',
16
- 'autoEffort',
17
- 'modelParameters',
18
- 'contextPercent',
19
- 'contextTokens',
20
- ];
21
-
22
14
  /** The pick the session route API takes for a saved route. */
23
15
  function sessionRoutePick(route) {
24
16
  const pick = { sessionOnly: true };
@@ -41,29 +33,40 @@ export function createAgentRouteFollow({ sessionsById, sessionOwner, advance, pu
41
33
  if (step.changed) publishStep(entry, step);
42
34
  })
43
35
  .catch((error) => {
44
- // A route the runtime refuses (provider signed out) leaves the chat on its model.
36
+ // A route the runtime refuses (provider signed out) leaves the chat on
37
+ // its model; the publication fails, so a retrying publisher sends it again.
45
38
  log(`agent route change not applied to ${sessionId}: ${error?.message || error}`);
39
+ throw error;
46
40
  });
47
41
  }
48
42
 
49
43
  function enqueue(sessionId, pick) {
50
44
  const queued = (tails.get(sessionId) || Promise.resolve()).then(() => apply(sessionId, pick));
51
- tails.set(sessionId, queued);
52
- queued.then(() => {
53
- if (tails.get(sessionId) === queued) tails.delete(sessionId);
45
+ // A refused update never holds back the chat's later ones.
46
+ const tail = queued.catch(() => {});
47
+ tails.set(sessionId, tail);
48
+ tail.then(() => {
49
+ if (tails.get(sessionId) === tail) tails.delete(sessionId);
54
50
  });
55
51
  return queued;
56
52
  }
57
53
 
58
- // Every matching chat is queued before the first await: publications queue in order.
59
- function follow(agentId, route) {
54
+ // Every matching chat is queued before the first await: publications queue
55
+ // in order. Rejects once every chat settled when any refused the route.
56
+ async function follow(agentId, route) {
60
57
  const home = agentHomeSessionId(agentId);
61
- if (!home || !route?.provider || !route?.model) return Promise.resolve();
58
+ if (!home || !route?.provider || !route?.model) return;
62
59
  const pick = sessionRoutePick(route);
63
60
  const queued = [...sessionsById.keys()]
64
61
  .filter((sessionId) => sessionId === home || roomMemberOfSession(sessionId)?.agentId === agentId)
65
62
  .map((sessionId) => enqueue(sessionId, pick));
66
- return Promise.all(queued);
63
+ const failures = (await Promise.allSettled(queued)).filter((one) => one.status === 'rejected');
64
+ if (failures.length) {
65
+ throw new AggregateError(
66
+ failures.map((one) => one.reason),
67
+ `${failures.length} chat(s) of ${agentId} did not take the route`
68
+ );
69
+ }
67
70
  }
68
71
  return subscribeAgentRouteChanges(follow);
69
72
  }
@@ -6,6 +6,7 @@ import { createAgentChildFactory } from './agent-child.mjs';
6
6
  import { partialHandoffTextFromSession } from '../../../runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs';
7
7
  import { attachmentsForIntake } from '../../../runtime/attachments/store.mjs';
8
8
  import { producedFileLines } from '../../../runtime/shared/handoff-artifacts.mjs';
9
+ import { carryReportOnError, turnReportText } from '../../../runtime/agent/orchestrator/session/loop/turn-report.mjs';
9
10
  import {
10
11
  collectUnreportedWrites,
11
12
  handoffContent,
@@ -79,7 +80,16 @@ export function createAgentTurns({
79
80
  return error;
80
81
  }
81
82
 
82
- async function runAgentTurn({ session, prompt, context = null, onToolResult, onTerminalResult } = {}) {
83
+ async function runAgentTurn({
84
+ session,
85
+ prompt,
86
+ context = null,
87
+ onToolResult,
88
+ onTerminalResult,
89
+ // The trusted skill-selection text of the turn (a routine executor's
90
+ // instructions); absent selects from the whole prompt, as any turn does.
91
+ skillSelection,
92
+ } = {}) {
83
93
  await rehydrateAgentSessions();
84
94
  const sessionId = String(session?.id || session || '').trim();
85
95
  const cancelEpoch = registry.assertAdmission(sessionId);
@@ -116,11 +126,12 @@ export function createAgentTurns({
116
126
  priority: 'next',
117
127
  context,
118
128
  transcriptMeta: agentTurnTranscriptMeta(content),
129
+ ...(typeof skillSelection === 'string' ? { skillSelection } : {}),
119
130
  ...(entry.runtime.isWireSafe === true || typeof onToolResult !== 'function' ? {} : { onToolResult }),
120
131
  };
121
132
  const detail = await target.call(entry.runtime, content, options);
122
133
  if (detail?.status === 'failed') {
123
- throw new Error(String(detail.error || 'agent session turn failed'));
134
+ throw carryReportOnError(new Error(String(detail.error || 'agent session turn failed')), detail.carriedReport);
124
135
  }
125
136
  if (detail?.status === 'cancelled') {
126
137
  const stop = takeWatchdogStop(sessionId) || new Error('agent session turn cancelled');
@@ -134,11 +145,12 @@ export function createAgentTurns({
134
145
  const reason = String(detail?.reason || detail?.error || '').trim();
135
146
  throw new Error(`agent turn ${status}${reason ? `: ${reason}` : ''}`);
136
147
  }
137
- let result = detail?.result || { content: '' };
138
- // The files the turn produced reach the owner with its handoff.
139
- const report = String(result.content || '');
148
+ const { reportContent, ...settled } = detail?.result || { content: '' };
149
+ // The owner gets the turn's whole report (turn-report.mjs), with the
150
+ // files the turn produced.
151
+ const report = turnReportText({ ...settled, reportContent });
140
152
  const files = await turnArtifactLines(entry.runtime, messageStart, descriptor, report);
141
- if (files.length) result = { ...result, content: [report, files.join('\n')].join('\n\n') };
153
+ const result = { ...settled, content: files.length ? [report, files.join('\n')].join('\n\n') : report };
142
154
  descriptor.status = 'idle';
143
155
  descriptor.stage = 'idle';
144
156
  descriptor.lastHandoff = typeof result?.content === 'string' ? result.content : '';
@@ -124,6 +124,15 @@ export function createQuotaResumeScheduler({
124
124
  function tick() {
125
125
  if (running) return running;
126
126
  running = (async () => {
127
+ // The setting turned off anywhere (another process, a hand edit), not
128
+ // only through setQuotaAutoResumeEnabled here: nothing pending resumes.
129
+ if (store.quotaAutoResumeEnabled?.() === false) {
130
+ if (store.listQuotaResumeEntries().length) {
131
+ store.cancelAllQuotaResumeEntries();
132
+ log('quota resume off: pending resumes cancelled');
133
+ }
134
+ return;
135
+ }
127
136
  for (const entry of store.listQuotaResumeEntries()) {
128
137
  if (isClosed()) return;
129
138
  if (entry.resetAt > now() || !isCurrent(store, entry)) continue;
@@ -5,6 +5,7 @@ import { SESSION_CONFIGURE_ACTION_SET, SESSION_READ_ACTION_SET } from '../../ses
5
5
  import { annotateSpan, markPhase } from '../../../runtime/shared/slow-span.mjs';
6
6
  import { sanitizeForWire } from '../../session-wire-values.mjs';
7
7
  import { botWorkBySession } from '../../../runtime/shared/bot-owned-work.mjs';
8
+ import { createSessionTurnGate } from './turn-gate.mjs';
8
9
 
9
10
  /** Reads a session without a live runtime answers from disk (readStoredReview). */
10
11
  const STORED_REVIEW_ACTIONS = new Set([
@@ -43,6 +44,9 @@ export function createSessionActionCalls(ctx) {
43
44
  const { bodyForClient } = ctx.projection;
44
45
  const { retainUnwatched, awaitingApprovalSessionKinds, roomHandoffQuestions } = ctx.retention;
45
46
  const { assertAvailable, hostedEntryForSession, entryForSession } = ctx.entries;
47
+ const { stateBusy } = ctx.retention;
48
+ const sessionOwner = ctx.projection?.sessionOwner;
49
+ const turnGate = ctx.turnGate ?? createSessionTurnGate();
46
50
 
47
51
  /** A cold session's review, read from its durable turn record (the same
48
52
  * source a runtime loaded only to answer it would read). Bodiless: the
@@ -82,7 +86,12 @@ export function createSessionActionCalls(ctx) {
82
86
  if (storedReview && !hosted) return storedReviewResult(id, name, args, baseRevision);
83
87
  const entry = hosted || (await entryForSession(id, openHints || {}));
84
88
  assertAvailable(entry);
85
- const target = entry.runtime[name];
89
+ // A remote read of the context status waits for an empty session's
90
+ // settings reconcile; the local accessor stays synchronous.
91
+ const target =
92
+ name === 'contextStatus' && typeof entry.runtime.contextStatusSettled === 'function'
93
+ ? entry.runtime.contextStatusSettled
94
+ : entry.runtime[name];
86
95
  if (typeof target !== 'function') throw new TypeError(`session action ${name} is unavailable`);
87
96
  markPhase('load');
88
97
  const value = await target.apply(entry.runtime, Array.isArray(args) ? args : []);
@@ -162,9 +171,50 @@ export function createSessionActionCalls(ctx) {
162
171
  };
163
172
  }
164
173
 
174
+ /** The desktop's auto-delete through the control session (`sessionId`):
175
+ * `args` = [target id, { lastUsedAt }]. The target is closed to service
176
+ * turn starts while the runtime's idle-only delete checks and acts
177
+ * (session-delete.mjs deleteSessionIfIdle); one being admitted refuses it. */
178
+ async function deleteIdleSession({ sessionId, args = [], open: openHints = {}, baseRevision = null } = {}) {
179
+ assertAvailable();
180
+ const controlId = String(sessionId || '');
181
+ if (!controlId) throw new TypeError('sessionId is required');
182
+ const [target, expected] = Array.isArray(args) ? args : [];
183
+ const id = String(target || '');
184
+ const entry = await entryForSession(controlId, openHints || {});
185
+ assertAvailable(entry);
186
+ if (typeof entry.runtime.deleteSessionIfIdle !== 'function') {
187
+ throw new TypeError('session action deleteSessionIfIdle is unavailable');
188
+ }
189
+ let value;
190
+ const reopen = id ? turnGate.fence(id) : null;
191
+ if (!reopen) value = { deleted: false, reason: id ? 'turn-starting' : 'invalid' };
192
+ else {
193
+ try {
194
+ value = await entry.runtime.deleteSessionIfIdle(id, expected ?? {}, {
195
+ isHostedBusy: (sessionIdToCheck) => {
196
+ const owner = sessionOwner?.(sessionIdToCheck);
197
+ return Boolean(owner) && stateBusy(owner.runtime?.getState?.());
198
+ },
199
+ });
200
+ } finally {
201
+ reopen();
202
+ }
203
+ }
204
+ log(`session action deleteSessionIfIdle session=${id} result=${resultSummary(value?.deleted ?? value)}`);
205
+ const step = advanceForCaller(entry);
206
+ retainUnwatched(entry);
207
+ return {
208
+ value: sanitizeForWire(value) ?? null,
209
+ sessionId: responseSessionId(entry, controlId),
210
+ ...bodyForClient(step, Number.isInteger(baseRevision) ? baseRevision : null),
211
+ };
212
+ }
213
+
165
214
  async function configureSession(params = {}, callCtx = null) {
166
215
  const revision = Math.max(0, Number(callCtx?.revision) || 0);
167
216
  const action = params?.action;
217
+ if (action === 'deleteSessionIfIdle') return deleteIdleSession(params);
168
218
  // Revision 0 desktop adapters routed some reads through configure because
169
219
  // their local read list lagged the session surface. A newer daemon accepts
170
220
  // those reads without weakening the current revision's finite lanes.