mixdog 1.1.2 → 1.2.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 (288) hide show
  1. package/README.md +1 -0
  2. package/package.json +2 -1
  3. package/scripts/lib/run-node-tests.mjs +9 -0
  4. package/scripts/prune-desktop-runtime.mjs +3 -0
  5. package/scripts/test-direct.mjs +4 -2
  6. package/src/defaults/shipped-history.json +6 -0
  7. package/src/defaults/skills/setup/references/actions.md +5 -2
  8. package/src/defaults/skills/visualize/SKILL.md +157 -0
  9. package/src/defaults/skills/visualize/references/craft.md +88 -0
  10. package/src/headless-command.mjs +56 -3
  11. package/src/headless-exec.mjs +17 -1
  12. package/src/help.mjs +2 -0
  13. package/src/rules/shared/70-delivery.md +2 -2
  14. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  15. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +1 -0
  16. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +2 -0
  17. package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
  18. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +17 -11
  19. package/src/runtime/agent/orchestrator/config-storage.mjs +1 -0
  20. package/src/runtime/agent/orchestrator/config.mjs +9 -1
  21. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +47 -7
  22. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +51 -8
  23. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +25 -5
  24. package/src/runtime/agent/orchestrator/mcp/client.mjs +348 -122
  25. package/src/runtime/agent/orchestrator/mcp/reconnect-singleflight.mjs +4 -0
  26. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +3 -0
  27. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -1
  28. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +13 -1
  29. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -0
  30. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +2 -0
  31. package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +2 -1
  32. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +12 -4
  33. package/src/runtime/agent/orchestrator/providers/effort-rejection.mjs +244 -0
  34. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  35. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  36. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +8 -40
  37. package/src/runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs +2 -0
  38. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +51 -12
  39. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +37 -2
  40. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +67 -0
  41. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +521 -0
  42. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +251 -0
  43. package/src/runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs +2 -0
  44. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +69 -102
  45. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +3 -0
  46. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +6 -1
  47. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs +1 -1
  48. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +5 -2
  49. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +3 -0
  50. package/src/runtime/agent/orchestrator/providers/registry.mjs +15 -1
  51. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +10 -0
  52. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +36 -3
  53. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +12 -11
  54. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +16 -1
  55. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +11 -0
  56. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -3
  57. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -0
  58. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +9 -5
  59. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +18 -8
  60. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +10 -3
  61. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +18 -11
  62. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +13 -5
  63. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +362 -0
  64. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +253 -0
  65. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +1 -1
  66. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/diagnostic.mjs +1 -7
  67. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/refusal.mjs +1 -1
  68. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +3 -2
  69. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -1
  70. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +1 -0
  71. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +17 -7
  72. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +3 -0
  73. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +12 -2
  74. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -0
  75. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +5 -3
  76. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +5 -2
  77. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +37 -16
  78. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +4 -0
  79. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +90 -0
  80. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +22 -12
  81. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +32 -3
  82. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +27 -0
  83. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -1
  84. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -0
  85. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +2 -0
  86. package/src/runtime/agent/orchestrator/session/message-ids.mjs +123 -0
  87. package/src/runtime/agent/orchestrator/session/message-ids.test-support.mjs +29 -0
  88. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +29 -19
  89. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +3 -0
  90. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +10 -3
  91. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +11 -0
  92. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +29 -0
  93. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +5 -1
  94. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +23 -4
  95. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +20 -3
  96. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +28 -8
  97. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +140 -0
  98. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +52 -2
  99. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +32 -22
  100. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +10 -3
  101. package/src/runtime/agent/orchestrator/tools/builtin/read-cache-policy.mjs +8 -0
  102. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +31 -12
  103. package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +32 -35
  104. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +11 -12
  105. package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +9 -6
  106. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +80 -66
  107. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +8 -3
  108. package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +5 -1
  109. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +16 -7
  110. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +2 -1
  111. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +137 -0
  112. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +11 -10
  113. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +21 -11
  114. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +12 -1
  115. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +56 -13
  116. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +58 -0
  117. package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +25 -1
  118. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +78 -5
  119. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +2 -0
  120. package/src/runtime/attachments/store.mjs +38 -0
  121. package/src/runtime/shared/atomic-file.mjs +8 -2
  122. package/src/runtime/shared/best-effort-stderr.mjs +8 -0
  123. package/src/runtime/shared/code-graph-state.mjs +12 -0
  124. package/src/runtime/shared/defaults-separation.mjs +2 -0
  125. package/src/runtime/shared/git-runner-worker.mjs +3 -2
  126. package/src/runtime/shared/git-runner.mjs +4 -3
  127. package/src/runtime/shared/llm/default-context-window.mjs +6 -0
  128. package/src/runtime/shared/llm/model-catalog-projection.mjs +5 -4
  129. package/src/runtime/shared/llm/model-catalog.mjs +240 -118
  130. package/src/runtime/shared/llm/provider-catalog-cache.mjs +36 -28
  131. package/src/runtime/shared/llm/provider-catalog-registry.mjs +156 -0
  132. package/src/runtime/shared/llm/provider-seed-rosters.mjs +130 -0
  133. package/src/runtime/shared/model-proxy-mode.d.mts +3 -0
  134. package/src/runtime/shared/model-proxy-mode.mjs +19 -0
  135. package/src/runtime/shared/provider-accounts.mjs +2 -2
  136. package/src/runtime/shared/provider-api-key.mjs +21 -1
  137. package/src/runtime/shared/schedule-model-ref.mjs +11 -2
  138. package/src/runtime/shared/session-usage-totals.mjs +19 -0
  139. package/src/runtime/shared/sharp-electron-linux.mjs +25 -0
  140. package/src/runtime/shared/singleton-owner.mjs +36 -6
  141. package/src/runtime/shared/statusline/statusline-segments.mjs +68 -14
  142. package/src/runtime/shared/tool-surface.mjs +7 -0
  143. package/src/runtime/shared/tool-work-units.mjs +14 -0
  144. package/src/runtime/shared/transcript-metadata.mjs +17 -1
  145. package/src/runtime/shared/turn-changes.mjs +791 -0
  146. package/src/runtime/shared/turn-snapshot-store.mjs +346 -12
  147. package/src/runtime/shared/turn-snapshot.mjs +690 -81
  148. package/src/runtime/shared/turn-worktree-snapshot.mjs +161 -11
  149. package/src/runtime/shared/worktrees/cache-cleanups.mjs +52 -0
  150. package/src/runtime/shared/worktrees/contract.mjs +551 -0
  151. package/src/runtime/shared/worktrees/disk.mjs +57 -0
  152. package/src/runtime/shared/worktrees/git.mjs +247 -0
  153. package/src/runtime/shared/worktrees/include.mjs +480 -0
  154. package/src/runtime/shared/worktrees/lock.mjs +46 -0
  155. package/src/runtime/shared/worktrees/maintenance.mjs +96 -0
  156. package/src/runtime/shared/worktrees/manager.mjs +1215 -0
  157. package/src/runtime/shared/worktrees/merge.mjs +182 -0
  158. package/src/runtime/shared/worktrees/owner.mjs +46 -0
  159. package/src/runtime/shared/worktrees/paths.mjs +62 -0
  160. package/src/runtime/shared/worktrees/registry.mjs +110 -0
  161. package/src/runtime/shared/worktrees/settings.mjs +84 -0
  162. package/src/runtime/shared/worktrees/slug.mjs +62 -0
  163. package/src/runtime/shared/worktrees/test-support.mjs +96 -0
  164. package/src/runtime/visualize-bridge/client.mjs +181 -0
  165. package/src/runtime/visualize-bridge/tool-defs.mjs +97 -0
  166. package/src/session-runtime/boot/apis.mjs +35 -0
  167. package/src/session-runtime/boot/config.mjs +2 -0
  168. package/src/session-runtime/boot/facade.mjs +20 -0
  169. package/src/session-runtime/boot/infrastructure.mjs +1 -0
  170. package/src/session-runtime/boot/session.mjs +1 -0
  171. package/src/session-runtime/boot/tools.mjs +4 -0
  172. package/src/session-runtime/config-lifecycle.mjs +10 -1
  173. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +11 -1
  174. package/src/session-runtime/global-extensions.mjs +2 -2
  175. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +27 -2
  176. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +32 -1
  177. package/src/session-runtime/internal-tool-executor.mjs +9 -1
  178. package/src/session-runtime/lifecycle/session-catalog.mjs +8 -1
  179. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +5 -0
  180. package/src/session-runtime/lifecycle/session-switch/resume.mjs +21 -3
  181. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +16 -0
  182. package/src/session-runtime/mcp-glue/connect.mjs +11 -6
  183. package/src/session-runtime/mcp-glue/server-catalog.mjs +7 -3
  184. package/src/session-runtime/mcp-glue/server-input.mjs +29 -0
  185. package/src/session-runtime/model-route/route-persist.mjs +3 -0
  186. package/src/session-runtime/model-route/set-route.mjs +15 -2
  187. package/src/session-runtime/notification-bus.mjs +9 -1
  188. package/src/session-runtime/provider-models/row-hydration.mjs +2 -0
  189. package/src/session-runtime/resource-extension-sync.mjs +30 -7
  190. package/src/session-runtime/resource-mcp-api.mjs +20 -7
  191. package/src/session-runtime/route-resolution.mjs +10 -1
  192. package/src/session-runtime/route-state.mjs +16 -2
  193. package/src/session-runtime/runtime-core.mjs +5 -0
  194. package/src/session-runtime/runtime-facade.mjs +8 -0
  195. package/src/session-runtime/runtime-review-api.mjs +9 -0
  196. package/src/session-runtime/services/agent-tool/helpers.mjs +5 -0
  197. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +3 -0
  198. package/src/session-runtime/services/agent-tool/job-views/job-lookup.mjs +1 -0
  199. package/src/session-runtime/services/agent-tool/job-views/spawn-meta.mjs +1 -0
  200. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +15 -0
  201. package/src/session-runtime/services/agent-tool/send-flow.mjs +1 -0
  202. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +10 -2
  203. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -7
  204. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  205. package/src/session-runtime/services/agent-tool/tag-registry.mjs +2 -1
  206. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -0
  207. package/src/session-runtime/services/agent-tool/worker-rows.mjs +1 -0
  208. package/src/session-runtime/services/agent-tool.mjs +1 -0
  209. package/src/session-runtime/services/daemon-candidate.mjs +3 -2
  210. package/src/session-runtime/services/daemon-crash-capture/spawn-capture.mjs +55 -0
  211. package/src/session-runtime/session-create/session-options.mjs +10 -1
  212. package/src/session-runtime/session-turn-api.mjs +1 -0
  213. package/src/session-runtime/settings-api.mjs +4 -2
  214. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -2
  215. package/src/session-runtime/settings-worktree-api.mjs +17 -0
  216. package/src/session-runtime/setup-tool/executor.mjs +11 -4
  217. package/src/session-runtime/setup-tool/settings-contract.mjs +3 -1
  218. package/src/session-runtime/setup-tool/tool-defs.mjs +31 -3
  219. package/src/session-runtime/turn/agent-ops.mjs +12 -1
  220. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +13 -3
  221. package/src/session-runtime/turn/turn-run/snapshot-tracker.mjs +20 -15
  222. package/src/session-runtime/turn/turn-run/turn-open.mjs +4 -5
  223. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +29 -1
  224. package/src/session-runtime/turn/turn-run/turn-settle.mjs +6 -1
  225. package/src/session-runtime/turn/turn-run.mjs +6 -7
  226. package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -3
  227. package/src/session-runtime/workspace/admission-gate.mjs +197 -0
  228. package/src/session-runtime/workspace/project-branches.mjs +136 -0
  229. package/src/session-runtime/workspace/transition-steps.mjs +364 -0
  230. package/src/session-runtime/workspace/transitions.mjs +651 -0
  231. package/src/session-runtime/workspace/workspace-state.mjs +112 -0
  232. package/src/standalone/channel-transport/http-routes.mjs +17 -0
  233. package/src/standalone/channel-transport.mjs +13 -1
  234. package/src/standalone/daemon-desktop-runtime.mjs +1 -0
  235. package/src/standalone/daemon-owner.mjs +372 -0
  236. package/src/standalone/daemon-stored-session-views.mjs +4 -1
  237. package/src/standalone/daemon.mjs +139 -5
  238. package/src/standalone/desktop-service-registry.mjs +20 -0
  239. package/src/standalone/local-session-runtime.mjs +11 -0
  240. package/src/standalone/session-client/attachment-calls.mjs +3 -1
  241. package/src/standalone/session-client/daemon-unavailable.mjs +62 -0
  242. package/src/standalone/session-client/lease-heartbeat.mjs +47 -0
  243. package/src/standalone/session-client.mjs +104 -13
  244. package/src/standalone/session-protocol.mjs +16 -0
  245. package/src/standalone/session-proxy.mjs +3 -0
  246. package/src/standalone/session-service/agent-tree/agent-child.mjs +4 -0
  247. package/src/standalone/session-service/agent-tree/agent-rehydrate.mjs +1 -0
  248. package/src/standalone/session-service/entries/lifecycle.mjs +6 -0
  249. package/src/standalone/session-service/projection/revisions.mjs +2 -0
  250. package/src/standalone/session-service/projection/transcript-window.mjs +149 -19
  251. package/src/standalone/session-service/projection/workspace.mjs +14 -0
  252. package/src/standalone/session-service/session-calls/session-action.mjs +11 -3
  253. package/src/standalone/session-transport/call-route.mjs +13 -0
  254. package/src/standalone/session-transport/client-registry/client-grace.mjs +45 -3
  255. package/src/standalone/session-transport/client-registry/registration-replays.mjs +1 -0
  256. package/src/standalone/session-transport/client-registry.mjs +20 -3
  257. package/src/standalone/session-transport/routes.mjs +79 -2
  258. package/src/standalone/session-transport/stack.mjs +2 -0
  259. package/src/standalone/session-transport.mjs +24 -1
  260. package/src/tui/app/message-selector.mjs +2 -1
  261. package/src/tui/app/model-options.mjs +35 -5
  262. package/src/tui/app/model-picker/provider-models-list.mjs +2 -2
  263. package/src/tui/app/model-picker.mjs +4 -2
  264. package/src/tui/dist/index.mjs +332 -36
  265. package/src/tui/index.jsx +10 -2
  266. package/src/tui/session/compaction-view.mjs +147 -0
  267. package/src/tui/session/context-state.mjs +6 -0
  268. package/src/tui/session/initial-state.mjs +3 -0
  269. package/src/tui/session/quota-resume.mjs +2 -1
  270. package/src/tui/session/session-api/commands.mjs +10 -2
  271. package/src/tui/session/session-api/controls.mjs +4 -0
  272. package/src/tui/session/session-api/intake/rewind.mjs +2 -1
  273. package/src/tui/session/session-api/integrations.mjs +17 -0
  274. package/src/tui/session/session-api/lifecycle/dispose.mjs +6 -1
  275. package/src/tui/session/session-api/lifecycle/inheritance.mjs +2 -0
  276. package/src/tui/session/session-api/lifecycle/resume.mjs +3 -0
  277. package/src/tui/session/session-api/routes.mjs +10 -1
  278. package/src/tui/session/session-api/settings.mjs +2 -0
  279. package/src/tui/session/session-api/worktree.mjs +60 -0
  280. package/src/tui/session/session-api.mjs +2 -0
  281. package/src/tui/session/session-flow/auto-clear.mjs +31 -12
  282. package/src/tui/session/session-flow/drain.mjs +15 -1
  283. package/src/tui/session/session-flow/session-reset.mjs +4 -3
  284. package/src/tui/session/session-flow.mjs +2 -0
  285. package/src/tui/session/transcript-intake.mjs +14 -5
  286. package/src/tui/session/turn-stream.mjs +32 -4
  287. package/src/tui/session/turn-tool-cards.mjs +10 -2
  288. package/src/tui/session/turn.mjs +39 -10
@@ -3,6 +3,7 @@
3
3
  // progress, filtered by default to workers that can still do work.
4
4
  import { ACTIVE_STAGES } from '../tool-def.mjs';
5
5
  import { isTerminalWorkerStatus } from '../worker-rows.mjs';
6
+ import { sessionUsageTotals } from '../../../../runtime/shared/session-usage-totals.mjs';
6
7
 
7
8
  // Idle, closed, errored and reaped/unknown rows are history and stay reachable
8
9
  // through the task section (status/read keep their terminal result).
@@ -36,6 +37,7 @@ function agentRow({ tag, session, runtime, progress, now, indexRow = null }) {
36
37
  preset: session.presetName || null,
37
38
  effort: session.effort || null,
38
39
  fast: session.fast === true,
40
+ ...(session.autoEffort === false ? { autoEffort: false } : {}),
39
41
  // Additive: route model parameters (e.g. Daybreak Blue) when the route has any.
40
42
  ...(session.modelParameters && Object.keys(session.modelParameters).length
41
43
  ? { modelParameters: { ...session.modelParameters } }
@@ -51,6 +53,7 @@ function agentRow({ tag, session, runtime, progress, now, indexRow = null }) {
51
53
  clientHostPid: session.clientHostPid || null,
52
54
  lastStreamDeltaAt: runtime?.lastStreamDeltaAt ? new Date(runtime.lastStreamDeltaAt).toISOString() : null,
53
55
  staleSeconds: runtime?.lastStreamDeltaAt ? Math.floor((now - runtime.lastStreamDeltaAt) / 1000) : null,
56
+ ...sessionUsageTotals(session),
54
57
  windowTokens: Number(session.lastContextTokens ?? session.lastInputTokens) || 0,
55
58
  windowCap: Number(session.contextWindow) || null,
56
59
  permission: session.permission || null,
@@ -69,6 +69,7 @@ export function createJobLookup({ mgr, tags, refreshTagsFromSessions }) {
69
69
  model: session.model || null,
70
70
  effort: session.effort || null,
71
71
  fast: session.fast === true,
72
+ ...(session.autoEffort === false ? { autoEffort: false } : {}),
72
73
  },
73
74
  };
74
75
  }
@@ -16,6 +16,7 @@ export function preparedSpawnMeta(prepared, extras = {}) {
16
16
  model: prepared.preset.model,
17
17
  effort: prepared.preset.effort || null,
18
18
  fast: prepared.preset.fast === true,
19
+ ...(prepared.preset.autoEffort === false ? { autoEffort: false } : {}),
19
20
  });
20
21
  }
21
22
 
@@ -72,6 +72,20 @@ export function createLeadWorkerIndex({ dataDir, cfgMod, workerRowFromSession })
72
72
  return true;
73
73
  }
74
74
 
75
+ /** A workspace transition moved the Lead: its existing row follows (status,
76
+ * reap deadline and liveness stamps unchanged). No row: nothing to write. */
77
+ function updateLeadWorkerCwd(sessionId, cwd) {
78
+ const id = clean(sessionId);
79
+ const next = clean(cwd);
80
+ if (!id || !next) return false;
81
+ index.write((byKey) => {
82
+ const current = byKey.get(id);
83
+ if (!current || current.cwd === next) return;
84
+ byKey.set(id, { ...current, cwd: next });
85
+ });
86
+ return true;
87
+ }
88
+
75
89
  /** Graceful-exit settlement: every turn this process still claims goes idle
76
90
  * before the runtime disappears. */
77
91
  function flushActiveLeadRows() {
@@ -147,6 +161,7 @@ export function createLeadWorkerIndex({ dataDir, cfgMod, workerRowFromSession })
147
161
  /** Resolves once every queued Lead index write is on disk. */
148
162
  flushLeadWorkerIndexWrites: index.flush,
149
163
  upsertLeadSession,
164
+ updateLeadWorkerCwd,
150
165
  removeLeadWorkerRow,
151
166
  flushActiveLeadRows,
152
167
  recoverStaleLeadRows,
@@ -180,6 +180,7 @@ export function createSendFlow({ mgr, defaultCwd, sessionSurface, canUseSessionS
180
180
  preset: session.presetName || null,
181
181
  effort: session.effort || null,
182
182
  fast: session.fast === true,
183
+ ...(session.autoEffort === false ? { autoEffort: false } : {}),
183
184
  },
184
185
  (job, ownerNotifyContext) => runSend(prepared, ownerNotifyContext, job),
185
186
  notifyContext
@@ -17,6 +17,7 @@ import { isAgentDisabled } from '../../../../runtime/shared/agent-route-config.m
17
17
  import { normalizeAgentPermission } from '../../../../runtime/shared/markdown-frontmatter.mjs';
18
18
  import { resolveAgentSpawnPreset } from '../spawn-preset.mjs';
19
19
  import { AGENT_OWNER } from '../../../../runtime/agent/orchestrator/agent-owner.mjs';
20
+ import { workspaceCwdLock } from '../../../workspace/admission-gate.mjs';
20
21
 
21
22
  export function createSpawnPlanner({
22
23
  cfgMod,
@@ -52,8 +53,15 @@ export function createSpawnPlanner({
52
53
  if (resolveTag(tag, context, { scanSessions: wantsSessionScan(args) })) {
53
54
  throw new Error(`agent spawn: tag "${tag}" already exists`);
54
55
  }
55
- const baseCwd = resolve(callerCwd || defaultCwd || process.cwd());
56
- const workerCwd = clean(args.cwd) ? resolve(baseCwd, args.cwd) : baseCwd;
56
+ // Workers share their Lead's execution root. While the Lead runs in its
57
+ // worktree, that root is locked: neither args.cwd nor an inherited
58
+ // (pre-transition) cwd can send a worker elsewhere.
59
+ const lockedCwd = workspaceCwdLock([
60
+ context?.ownerSessionId,
61
+ context?.callerSessionId || context?.sessionId,
62
+ ]);
63
+ const baseCwd = resolve(lockedCwd || callerCwd || defaultCwd || process.cwd());
64
+ const workerCwd = !lockedCwd && clean(args.cwd) ? resolve(baseCwd, args.cwd) : baseCwd;
57
65
  const prompt = await resolvePrompt(args, workerCwd);
58
66
  if (prepState?.timedOut) {
59
67
  throw new Error('agent spawn prep timed out before session bind');
@@ -10,6 +10,7 @@ import { prepareAgentSession } from '../../../../runtime/agent/orchestrator/agen
10
10
  import { getProvider } from '../../../../runtime/agent/orchestrator/providers/registry.mjs';
11
11
  import { resolveRouteContextState } from '../../../route-state.mjs';
12
12
  import { createSpawnPlanner } from './spawn-plan.mjs';
13
+ import { enterWorkerSpawn } from '../../../workspace/admission-gate.mjs';
13
14
 
14
15
  /** The route fields every worker-row and tag record carries. */
15
16
  export function presetDescriptor(agent, preset, presetName) {
@@ -20,6 +21,7 @@ export function presetDescriptor(agent, preset, presetName) {
20
21
  model: preset.model,
21
22
  effort: preset.effort || null,
22
23
  fast: preset.fast === true,
24
+ ...(preset.autoEffort === false ? { autoEffort: false } : {}),
23
25
  };
24
26
  }
25
27
 
@@ -84,9 +86,9 @@ export function createSpawnPreparer({
84
86
  // A sub-100 context share needs the window it selects; a percent alone
85
87
  // keeps the full served window.
86
88
  const sessionSpec = { ...spec };
87
- if (plan.preset.contextPercent) {
88
- const { contextPercent, selectedContextWindow } = resolveRouteContextState(plan.preset, null);
89
- Object.assign(sessionSpec, { contextPercent, selectedContextWindow });
89
+ if (plan.preset.contextPercent || plan.preset.contextTokens) {
90
+ const { contextPercent, selectedContextWindow, contextTokens } = resolveRouteContextState(plan.preset, null);
91
+ Object.assign(sessionSpec, { contextPercent, selectedContextWindow }, contextTokens ? { contextTokens } : {});
90
92
  }
91
93
  if (sessionSurface?.canonical === true && typeof sessionSurface.createChild === 'function') {
92
94
  return sessionSurface.createChild({ spec: sessionSpec, prompt: plan.prompt, tag: plan.tag });
@@ -99,10 +101,20 @@ export function createSpawnPreparer({
99
101
  }
100
102
 
101
103
  async function prepareSpawnInProcess(args, callerCwd = null, context = {}, prepState = null) {
102
- const plan = await resolveSpawnPlan(args, callerCwd, context, prepState);
103
- const spec = spawnSessionSpec(plan, args, context);
104
- const { session, effectiveCwd } = await createSpawnedSession(plan, spec, prepState);
105
- bindSpawnedSession(session, plan);
104
+ // Shared admission with Lead workspace transitions: no spawn is prepared
105
+ // while the Lead's workspace changes, no transition starts mid-spawn.
106
+ const leaveSpawn = enterWorkerSpawn([context?.ownerSessionId, context?.callerSessionId || context?.sessionId]);
107
+ let plan;
108
+ let session;
109
+ let effectiveCwd;
110
+ try {
111
+ plan = await resolveSpawnPlan(args, callerCwd, context, prepState);
112
+ const spec = spawnSessionSpec(plan, args, context);
113
+ ({ session, effectiveCwd } = await createSpawnedSession(plan, spec, prepState));
114
+ bindSpawnedSession(session, plan);
115
+ } finally {
116
+ leaveSpawn();
117
+ }
106
118
  if (sessionSurface?.canonical !== true) {
107
119
  maybePrewarmSpawnTransport(plan, session);
108
120
  }
@@ -20,6 +20,7 @@ export function resolveAgentSpawnPreset(config, args = {}) {
20
20
  model: clean(args.model),
21
21
  effort: clean(args.effort) || undefined,
22
22
  fast: args.fast === true,
23
+ ...(args.autoEffort === false ? { autoEffort: false } : {}),
23
24
  tools: 'full',
24
25
  },
25
26
  };
@@ -42,8 +43,10 @@ export function resolveAgentSpawnPreset(config, args = {}) {
42
43
  model: agentRoute.model,
43
44
  effort: agentRoute.effort,
44
45
  fast: agentRoute.fast === true,
46
+ ...(agentRoute.autoEffort === false ? { autoEffort: false } : {}),
45
47
  ...(agentRoute.modelParameters ? { modelParameters: agentRoute.modelParameters } : {}),
46
48
  ...(agentRoute.contextPercent ? { contextPercent: agentRoute.contextPercent } : {}),
49
+ ...(agentRoute.contextTokens ? { contextTokens: agentRoute.contextTokens } : {}),
47
50
  tools: 'full',
48
51
  },
49
52
  };
@@ -29,7 +29,7 @@ export function createTagRegistry({ dataDir, cfgMod, mgr }) {
29
29
  workerRowFromSession: index.workerRowFromSession,
30
30
  });
31
31
 
32
- const { upsertLeadSession } = leadIndex;
32
+ const { upsertLeadSession, updateLeadWorkerCwd } = leadIndex;
33
33
 
34
34
  function dispose(options) {
35
35
  try {
@@ -103,6 +103,7 @@ export function createTagRegistry({ dataDir, cfgMod, mgr }) {
103
103
  upsertWorkerSession: index.upsertWorkerSession,
104
104
  upsertWorkerSessionDeferred,
105
105
  upsertLeadSession,
106
+ updateLeadWorkerCwd,
106
107
  removeWorkerRow,
107
108
  refreshTagsFromIndex,
108
109
  tags,
@@ -38,6 +38,7 @@ export function normalizeWorkerRows(value) {
38
38
  preset: clean(row.preset) || null,
39
39
  effort: clean(row.effort) || null,
40
40
  fast: typeof row.fast === 'boolean' ? row.fast : null,
41
+ ...(row.autoEffort === false ? { autoEffort: false } : {}),
41
42
  status: clean(row.status) || 'idle',
42
43
  stage: clean(row.stage) || clean(row.status) || 'idle',
43
44
  createdAt: clean(row.createdAt) || null,
@@ -87,6 +88,10 @@ export function workerRowFromSession(session, fallbackTag = '', extra = {}, getS
87
88
  preset: clean(extra.preset) || clean(session?.presetName) || null,
88
89
  effort: clean(extra.effort) || clean(session?.effort) || null,
89
90
  fast: fastFlag(extra.fast, session?.fast),
91
+ // Absent means Auto effort is on; an explicit boolean wins over the session's.
92
+ ...((typeof extra.autoEffort === 'boolean' ? extra.autoEffort : session?.autoEffort) === false
93
+ ? { autoEffort: false }
94
+ : {}),
90
95
  status,
91
96
  stage,
92
97
  createdAt: clean(session?.createdAt) || clean(extra.createdAt) || nowIso,
@@ -133,6 +133,7 @@ export function workerRowToSession(row = {}) {
133
133
  presetName: row.preset || null,
134
134
  effort: row.effort || null,
135
135
  fast: row.fast === true,
136
+ ...(row.autoEffort === false ? { autoEffort: false } : {}),
136
137
  status: row.status || 'idle',
137
138
  stage: row.stage || row.status || 'idle',
138
139
  createdAt: row.createdAt || null,
@@ -146,6 +146,7 @@ export function createStandaloneAgent({
146
146
  getStatus,
147
147
  recoverWorkers,
148
148
  upsertLeadSession: registry.upsertLeadSession,
149
+ updateLeadWorkerCwd: registry.updateLeadWorkerCwd,
149
150
  closeAll: closeFlow.closeAll,
150
151
  dispose: (options) => registry.dispose(options),
151
152
  };
@@ -5,7 +5,8 @@
5
5
  // ready handoff so the daemon's code/signal is recorded against its pid, boot
6
6
  // time and ready state. Resolves once the candidate reported ready, exited,
7
7
  // failed to spawn, or the timeout elapsed; the caller then re-reads discovery
8
- // and attaches to whoever won.
8
+ // and attaches to whoever won. The resolved `summary()` describes this boot as
9
+ // observed when called, for a caller that has to give up.
9
10
  import { fork } from 'node:child_process';
10
11
  import { beginDaemonSpawnCapture } from './daemon-crash-capture.mjs';
11
12
 
@@ -34,7 +35,7 @@ export function forkDaemonCandidate({
34
35
  // Boot diagnostics written to fd 2 reach this log exactly once, even when
35
36
  // the candidate never reached ready.
36
37
  capture.mirror();
37
- resolve();
38
+ resolve({ summary: capture.summary });
38
39
  };
39
40
  let child;
40
41
  try {
@@ -20,6 +20,11 @@ const CAPTURE_ID_ATTEMPTS = 8;
20
20
  const MIRROR_MAX_BYTES = 16 * 1024;
21
21
  const MESSAGE_MAX_CHARS = 512;
22
22
  const HEAP_FLAG_RE = /^--max-(?:old-space|semi-space|heap)-size=/;
23
+ // Bytes of fd 2 a failure summary scans (the newest ones when larger).
24
+ const SUMMARY_SCAN_MAX_BYTES = 256 * 1024;
25
+ // Node's uncaught-error report (`TypeError: …`, `Error [ERR_…]: …`), V8's
26
+ // fatal abort and the daemon's own `fatal boot error` log line.
27
+ const STDERR_ERROR_LINE_RE = /\b[A-Z][A-Za-z]*Error\b(?: \[[A-Z0-9_]+\])?:|^Error\b|FATAL ERROR|(?<!non-)\bfatal\b/;
23
28
 
24
29
  function stamp(ms) {
25
30
  const iso = new Date(ms).toISOString();
@@ -256,6 +261,8 @@ function noteSpawnError(capture, error) {
256
261
  // this stream, so nothing here extends its lifetime.
257
262
  function drainStderrPipe(capture, stream) {
258
263
  const onData = (chunk) => {
264
+ // No capture file to read back: keep the newest bytes for summary().
265
+ capture.pipeText = `${capture.pipeText}${chunk}`.slice(-SUMMARY_SCAN_MAX_BYTES);
259
266
  mirrorText(capture.log, chunk);
260
267
  };
261
268
  stream.on('data', onData);
@@ -272,6 +279,52 @@ function drainStderrPipe(capture, stream) {
272
279
  });
273
280
  }
274
281
 
282
+ /** The candidate's fd 2 as text: the capture file (its newest bytes when
283
+ * large) or, when fd 2 fell back to a pipe, what that pipe delivered. */
284
+ function stderrText(capture) {
285
+ if (!capture.capturePath || capture.removed) return capture.pipeText;
286
+ try {
287
+ const handle = fs.openSync(capture.capturePath, 'r');
288
+ try {
289
+ const size = fs.fstatSync(handle).size;
290
+ const length = Math.min(size, SUMMARY_SCAN_MAX_BYTES);
291
+ const buffer = Buffer.allocUnsafe(length);
292
+ const bytesRead = fs.readSync(handle, buffer, 0, length, size - length);
293
+ return buffer.subarray(0, bytesRead).toString('utf8');
294
+ } finally {
295
+ fs.closeSync(handle);
296
+ }
297
+ } catch {
298
+ return capture.pipeText;
299
+ }
300
+ }
301
+
302
+ /** What a launcher that gave up on this boot needs to name its cause: the
303
+ * lifecycle as far as observed, the first error line on fd 2 (else its last
304
+ * line, where a stalled boot stopped) and where the full text is. */
305
+ function summarize(capture) {
306
+ const { record } = capture;
307
+ const lines = stderrText(capture)
308
+ .split(/\r?\n/)
309
+ .map((line) => line.trim())
310
+ .filter(Boolean);
311
+ const errorLine = lines.find((line) => STDERR_ERROR_LINE_RE.test(line));
312
+ return {
313
+ pid: record.pid,
314
+ ready: record.ready,
315
+ spawnedAt: record.spawnedAt,
316
+ exitedAt: record.exitedAt,
317
+ exitCode: record.exitCode,
318
+ exitSignal: record.exitSignal,
319
+ exitReason: record.exitReason ?? null,
320
+ uptimeMs: record.uptimeMs,
321
+ error: record.error,
322
+ stderrErrorLine: errorLine ? boundedMessage(errorLine) : null,
323
+ stderrLastLine: lines.length > 0 ? boundedMessage(lines.at(-1)) : null,
324
+ stderrPath: capture.removed ? null : capture.capturePath,
325
+ };
326
+ }
327
+
275
328
  /** Attach to the forked child: record its identity and keep a lifetime
276
329
  * listener that survives the ready handoff, so a later exit is still
277
330
  * correlated to this pid, boot time and ready state. */
@@ -347,6 +400,7 @@ export function beginDaemonSpawnCapture({
347
400
  readOffset: 0,
348
401
  removed: false,
349
402
  pipeDrained: null,
403
+ pipeText: '',
350
404
  stderrStdio: 'pipe',
351
405
  };
352
406
  openCapture(capture, { captureDir, prune, launcherPid, nonce });
@@ -377,5 +431,6 @@ export function beginDaemonSpawnCapture({
377
431
  * recording anything — the child, if any, keeps its duplicate. */
378
432
  release: () => closeWriteFd(capture),
379
433
  snapshot: () => ({ ...capture.record }),
434
+ summary: () => summarize(capture),
380
435
  };
381
436
  }
@@ -6,6 +6,7 @@ import { hasOwn } from '../../runtime/agent/orchestrator/runtime-core/session-te
6
6
  import { toolSpecForMode } from '../../runtime/agent/orchestrator/runtime-core/effort.mjs';
7
7
  import { pluginDataDir } from '../runtime-paths.mjs';
8
8
  import { LEAD_DISALLOWED_TOOLS } from '../../runtime/agent/orchestrator/runtime-core/tool-defs.mjs';
9
+ import { HEADLESS_TOOL_PROFILE } from '../../runtime/agent/orchestrator/runtime-core/tool-profile.mjs';
9
10
 
10
11
  // Ownership and permission fields an agent-owned session inherits from its profile.
11
12
  function agentOwnedSessionFields(sessionProfile) {
@@ -47,7 +48,13 @@ export function sessionOptions(deps, coreMemoryContext) {
47
48
  owner: agentOwned ? 'agent' : 'cli',
48
49
  agent: agentOwned ? sessionProfile?.agent || 'worker' : 'lead',
49
50
  lane: agentOwned ? 'agent' : 'cli',
50
- sourceType: agentOwned ? sessionProfile?.sourceType || 'agent' : 'lead',
51
+ // One-shot `mixdog exec` runs carry their own source so session catalogs
52
+ // can keep them out of the user's resumable list.
53
+ sourceType: agentOwned
54
+ ? sessionProfile?.sourceType || 'agent'
55
+ : rt.toolProfile === HEADLESS_TOOL_PROFILE
56
+ ? 'exec'
57
+ : 'lead',
51
58
  sourceName: agentOwned ? sessionProfile?.sourceName || sessionProfile?.agent || 'agent' : 'main',
52
59
  ...(rt.approvalMode ? { approvalMode: rt.approvalMode } : {}),
53
60
  clientHostPid: sessionProfile?.clientHostPid || process.pid,
@@ -64,8 +71,10 @@ export function sessionOptions(deps, coreMemoryContext) {
64
71
  workflowContext,
65
72
  orchestrationMode,
66
73
  fast: rt.route.fast === true,
74
+ autoEffort: rt.route.autoEffort !== false,
67
75
  modelParameters: rt.route.modelParameters || {},
68
76
  contextPercent: rt.route.contextPercent,
77
+ contextTokens: rt.route.contextTokens || null,
69
78
  selectedContextWindow: rt.route.selectedContextWindow || null,
70
79
  compaction:
71
80
  rt.config.compaction && typeof rt.config.compaction === 'object'
@@ -34,6 +34,7 @@ export function createSessionTurnApi(deps) {
34
34
  sessionOwnerGone: share.sessionOwnerGone,
35
35
  agentControl: agent.agentControl,
36
36
  taskControl: agent.taskControl,
37
+ stopShellJob: agent.stopShellJob,
37
38
  onNotification: agent.onNotification,
38
39
  toolsStatus: agent.toolsStatus,
39
40
  selectTools: agent.selectTools,
@@ -5,9 +5,9 @@
5
5
  // `this.*` resolve against the spread target, so cross-member calls (e.g.
6
6
  // setProfile -> this.getProfile) keep working when spread into the facade.
7
7
  //
8
- // The members live in five topic modules: profile/onboarding/skills,
8
+ // The members live in six topic modules: profile/onboarding/skills,
9
9
  // compaction/auto-clear, built-in tool modules, system (channels, shell,
10
- // updates) and developer options; the local provider's own methods come from
10
+ // updates), developer options and worktree defaults; the local provider's own methods come from
11
11
  // local-provider-settings.mjs.
12
12
  import { createLocalProviderSettings } from './local-provider-settings.mjs';
13
13
  import { createProfileSettings } from './settings-profile-api.mjs';
@@ -15,6 +15,7 @@ import { createCompactionSettings } from './settings-compaction-api.mjs';
15
15
  import { createBuiltinToolSettings } from './settings-builtin-tools-api.mjs';
16
16
  import { createSystemSettings } from './settings-system-api.mjs';
17
17
  import { createDeveloperSettings } from './settings-developer-api.mjs';
18
+ import { createWorktreeSettings } from './settings-worktree-api.mjs';
18
19
 
19
20
  export function createSettingsApi(deps) {
20
21
  // Optional: callers without a live local provider / gate fall back to the
@@ -38,5 +39,6 @@ export function createSettingsApi(deps) {
38
39
  ...createBuiltinToolSettings(shared, localSettings),
39
40
  ...createSystemSettings(shared),
40
41
  ...createDeveloperSettings(shared),
42
+ ...createWorktreeSettings(shared),
41
43
  };
42
44
  }
@@ -7,6 +7,7 @@ import {
7
7
  builtinInstalled,
8
8
  setBuiltinInstalledInConfig,
9
9
  } from '../runtime/agent/orchestrator/runtime-core/builtin-features.mjs';
10
+ import { featureEnvOverride, moduleEnabled } from '../runtime/agent/orchestrator/runtime-core/config-helpers.mjs';
10
11
  import { LOCAL_PROVIDER_ID } from '../runtime/local-provider/managed-runtime.mjs';
11
12
  import {
12
13
  INSTRUCTION_FILES_MODES,
@@ -23,7 +24,7 @@ import {
23
24
  shutdownEffortJudge,
24
25
  } from '../runtime/effort-judge/judge-client.mjs';
25
26
 
26
- const TOGGLEABLE_BUILTINS = ['git', 'office', 'tidy', 'localProvider', 'autoEffort'];
27
+ const TOGGLEABLE_BUILTINS = ['git', 'office', 'tidy', 'localProvider', 'autoEffort', 'visualize'];
27
28
 
28
29
  function setLocalProviderEnabledInConfig(configLike, enabled) {
29
30
  const next = { ...(configLike || {}) };
@@ -97,6 +98,12 @@ export function createBuiltinToolSettings(
97
98
  enabled: tidyToolEnabledFn ? tidyToolEnabledFn() : builtinFeatureActive(config, 'tidy'),
98
99
  installed: builtinInstalled(config, 'tidy'),
99
100
  },
101
+ // Ships with the runtime and needs no install; the toggle reflects the
102
+ // module flag, not live bridge presence.
103
+ visualize: {
104
+ enabled: featureEnvOverride('MIXDOG_FEATURE_VISUALIZE') ?? moduleEnabled(config, 'visualize', true),
105
+ installed: true,
106
+ },
100
107
  localProvider: {
101
108
  ...localProvider,
102
109
  ...localSettings.status(),
@@ -152,7 +159,7 @@ export function createBuiltinToolSettings(
152
159
  },
153
160
  async setBuiltinToolEnabled(name, enabled) {
154
161
  if (!TOGGLEABLE_BUILTINS.includes(name)) {
155
- throw new TypeError('Built-in tool must be git, office, tidy, localProvider, or autoEffort.');
162
+ throw new TypeError('Built-in tool must be git, office, tidy, localProvider, autoEffort, or visualize.');
156
163
  }
157
164
  if (name === 'autoEffort' && enabled !== false && !onnxRuntimeSupported()) {
158
165
  throw new Error(EFFORT_JUDGE_UNSUPPORTED);
@@ -0,0 +1,17 @@
1
+ // Settings → Worktrees: defaults for Lead-session git worktrees
2
+ // (runtime/shared/worktrees/settings.mjs). Values persist at agent config
3
+ // `worktree.<key>`; defaults are not stored.
4
+ import { applyWorktreeSettingsPatch, normalizeWorktreeSettings } from '../runtime/shared/worktrees/settings.mjs';
5
+
6
+ export function createWorktreeSettings({ getConfig, saveConfigAndAdopt }) {
7
+ return {
8
+ getWorktreeSettings() {
9
+ return normalizeWorktreeSettings(getConfig()?.worktree);
10
+ },
11
+ setWorktreeSettings(patch) {
12
+ const config = getConfig() || {};
13
+ saveConfigAndAdopt({ ...config, worktree: applyWorktreeSettingsPatch(config.worktree, patch) });
14
+ return this.getWorktreeSettings();
15
+ },
16
+ };
17
+ }
@@ -30,6 +30,7 @@ const PROFILE_VALUE_IDS = Object.freeze({
30
30
  const ACTION_APPLIES_TO = {
31
31
  set_recap_enabled: 'background Memory cycles; no restart required',
32
32
  set_auto_update: 'subsequent automatic update checks',
33
+ set_worktree_settings: 'new tasks and worktrees created afterwards; existing worktrees are unchanged',
33
34
  set_system_shell: 'subsequent shell calls',
34
35
  save_automation: 'the automation worker; scheduled runs follow the saved timing',
35
36
  delete_automation: 'future automation runs',
@@ -93,6 +94,7 @@ function routeInput(source) {
93
94
  if (typeof source.fast === 'boolean') next.fast = source.fast;
94
95
  if (Object.hasOwn(source, 'modelParameters')) next.modelParameters = { ...source.modelParameters };
95
96
  if (Object.hasOwn(source, 'contextPercent')) next.contextPercent = source.contextPercent;
97
+ if (Object.hasOwn(source, 'contextTokens')) next.contextTokens = source.contextTokens;
96
98
  if (Object.hasOwn(source, 'disabled')) next.disabled = source.disabled;
97
99
  return next;
98
100
  }
@@ -178,6 +180,7 @@ const mainRoute = (rt) => ({
178
180
  fastCapable: rt.fastCapable === true,
179
181
  modelParameters: rt.modelParameters || {},
180
182
  contextPercent: rt.contextPercent ?? null,
183
+ contextTokens: rt.contextTokens ?? null,
181
184
  });
182
185
 
183
186
  async function automationStatus(rt, { domain }) {
@@ -303,6 +306,7 @@ const SETUP_STATUS_READERS = {
303
306
  plugins: (rt) => rt.pluginsStatus?.() || {},
304
307
  update: (rt) => rt.getUpdateSettings?.() || {},
305
308
  onboarding: (rt) => rt.getOnboardingStatus?.() || {},
309
+ worktree: (rt) => rt.getWorktreeSettings(),
306
310
  schedules: automationStatus,
307
311
  webhooks: automationStatus,
308
312
  hooks: hookStatus,
@@ -328,11 +332,13 @@ function validateSetupInput(args) {
328
332
  if (action !== 'set_agent_route' && Object.hasOwn(args.route, 'disabled')) {
329
333
  throw new Error('route.disabled is only accepted by set_agent_route');
330
334
  }
331
- if (action !== 'set_route' && action !== 'set_agent_route' && Object.hasOwn(args.route, 'contextPercent')) {
332
- throw new Error('route.contextPercent is only accepted by set_route and set_agent_route');
335
+ for (const field of ['contextPercent', 'contextTokens']) {
336
+ if (action !== 'set_route' && action !== 'set_agent_route' && Object.hasOwn(args.route, field)) {
337
+ throw new Error(`route.${field} is only accepted by set_route and set_agent_route`);
338
+ }
333
339
  }
334
340
  }
335
- for (const field of ['desktop', 'appearance', 'webhook', 'compaction', 'providerAccount']) {
341
+ for (const field of ['desktop', 'appearance', 'webhook', 'compaction', 'providerAccount', 'worktree']) {
336
342
  if (args[field] && !Object.keys(args[field]).length) throw new Error(`${field} requires at least one setting`);
337
343
  }
338
344
  return action;
@@ -507,6 +513,7 @@ const SETUP_ACTION_HANDLERS = {
507
513
  rt.deleteLocalProviderModel(requireText(args.confirmationToken, 'confirmationToken')),
508
514
  set_system_shell: (rt, args) => rt.setSystemShell({ command: clean(args.command) }),
509
515
  set_auto_update: (rt, args) => rt.setAutoUpdate(requireBoolean(args.enabled)),
516
+ set_worktree_settings: (rt, args) => rt.setWorktreeSettings(args.worktree),
510
517
  forget_provider_auth: async (rt, args) => {
511
518
  const name = requireText(args.name, 'name');
512
519
  const setup = await rt.getProviderSetup({});
@@ -541,7 +548,7 @@ const SETUP_ACTION_HANDLERS = {
541
548
  set_mcp_enabled: async (rt, args) => ({
542
549
  mcp: mcpRows(await rt.setMcpServerEnabled(requireText(args.name, 'name'), requireBoolean(args.enabled))),
543
550
  }),
544
- reconnect_mcp: async (rt) => ({ mcp: mcpRows(await rt.reconnectMcp()) }),
551
+ reconnect_mcp: async (rt, args) => ({ mcp: mcpRows(await rt.reconnectMcp(clean(args.name) || undefined)) }),
545
552
  set_disabled_skills: (rt, args) => {
546
553
  if (!Array.isArray(args.skills)) throw new Error('skills (array of names) is required');
547
554
  return rt.setDisabledSkills(args.skills.map(clean).filter(Boolean));
@@ -108,6 +108,8 @@ export const SETUP_MCP_SCHEMA = object({
108
108
  additionalProperties: removableText,
109
109
  description: 'HTTP header names mapped to existing environment variable names.',
110
110
  },
111
+ startupTimeoutSec: { type: 'number', description: 'Connect/handshake timeout in seconds (>0, default 30).' },
112
+ toolTimeoutSec: { type: 'number', description: 'Per tool-call timeout in seconds (>0, default 120).' },
111
113
  });
112
114
 
113
115
  export const SETUP_EXTENDED_PROPERTIES = Object.freeze({
@@ -158,7 +160,7 @@ export const SETUP_EXTENDED_PROPERTIES = Object.freeze({
158
160
  model: {
159
161
  ...text,
160
162
  description:
161
- 'Required for new schedules; no default-model fallback. Use provider/model[@effort][+fast][?parameter=value] or an existing preset name. On overwrite, omission preserves the saved model, which must be non-empty.',
163
+ 'Required for new schedules; no default-model fallback. Use provider/model[@effort][+fast][+noauto][?parameter=value] (+noauto: Auto reasoning off; absent = on) or an existing preset name. On overwrite, omission preserves the saved model, which must be non-empty.',
162
164
  },
163
165
  cwd: text,
164
166
  workflow: text,