mixdog 1.1.1 → 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 (317) hide show
  1. package/README.md +1 -0
  2. package/package.json +2 -2
  3. package/scripts/lib/run-node-tests.mjs +9 -0
  4. package/scripts/prune-desktop-runtime.mjs +3 -0
  5. package/scripts/release-paths.mjs +39 -2
  6. package/scripts/test-direct.mjs +4 -2
  7. package/src/defaults/shipped-history.json +6 -0
  8. package/src/defaults/skills/setup/references/actions.md +5 -2
  9. package/src/defaults/skills/visualize/SKILL.md +157 -0
  10. package/src/defaults/skills/visualize/references/craft.md +88 -0
  11. package/src/headless-command.mjs +56 -3
  12. package/src/headless-exec.mjs +17 -1
  13. package/src/headless-role.mjs +2 -2
  14. package/src/help.mjs +2 -0
  15. package/src/lib/rules-builder.cjs +0 -23
  16. package/src/rules/lead/LEAD.md +2 -2
  17. package/src/rules/shared/70-delivery.md +2 -2
  18. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -0
  19. package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +1 -0
  20. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +2 -0
  21. package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
  22. package/src/runtime/agent/orchestrator/config-providers-merge.mjs +17 -11
  23. package/src/runtime/agent/orchestrator/config-storage.mjs +1 -0
  24. package/src/runtime/agent/orchestrator/config.mjs +9 -1
  25. package/src/runtime/agent/orchestrator/mcp/client-config.mjs +47 -7
  26. package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +51 -8
  27. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +25 -5
  28. package/src/runtime/agent/orchestrator/mcp/client.mjs +348 -122
  29. package/src/runtime/agent/orchestrator/mcp/reconnect-singleflight.mjs +4 -0
  30. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +3 -0
  31. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -1
  32. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +13 -1
  33. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -0
  34. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +2 -0
  35. package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +2 -1
  36. package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +12 -4
  37. package/src/runtime/agent/orchestrator/providers/effort-rejection.mjs +244 -0
  38. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  39. package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
  40. package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +8 -40
  41. package/src/runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs +2 -0
  42. package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +51 -12
  43. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +37 -2
  44. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +67 -0
  45. package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +521 -0
  46. package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +251 -0
  47. package/src/runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs +2 -0
  48. package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +69 -102
  49. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +3 -0
  50. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +6 -1
  51. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs +1 -1
  52. package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +5 -2
  53. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +3 -0
  54. package/src/runtime/agent/orchestrator/providers/registry.mjs +15 -1
  55. package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +10 -0
  56. package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +36 -3
  57. package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +12 -11
  58. package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +16 -1
  59. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +11 -0
  60. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +11 -8
  61. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +10 -0
  62. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +9 -5
  63. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +18 -8
  64. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +10 -3
  65. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +18 -11
  66. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +13 -5
  67. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +362 -0
  68. package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +253 -0
  69. package/src/runtime/agent/orchestrator/session/context-utils.mjs +12 -14
  70. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +1 -1
  71. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/diagnostic.mjs +1 -7
  72. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/refusal.mjs +1 -1
  73. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +3 -2
  74. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +2 -1
  75. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +1 -0
  76. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +17 -7
  77. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +3 -0
  78. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +12 -2
  79. package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -0
  80. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +5 -3
  81. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +5 -2
  82. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +37 -16
  83. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +4 -0
  84. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +90 -0
  85. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +22 -12
  86. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +32 -3
  87. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +27 -0
  88. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -1
  89. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +1 -0
  90. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +2 -0
  91. package/src/runtime/agent/orchestrator/session/manager.mjs +1 -5
  92. package/src/runtime/agent/orchestrator/session/message-ids.mjs +123 -0
  93. package/src/runtime/agent/orchestrator/session/message-ids.test-support.mjs +29 -0
  94. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +29 -19
  95. package/src/runtime/agent/orchestrator/session/read-dedup.mjs +0 -1
  96. package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +3 -0
  97. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +10 -3
  98. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +11 -0
  99. package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +29 -0
  100. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +5 -1
  101. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +23 -4
  102. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +20 -3
  103. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +28 -8
  104. package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +140 -0
  105. package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +52 -2
  106. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +32 -22
  107. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +10 -3
  108. package/src/runtime/agent/orchestrator/tools/builtin/read-cache-policy.mjs +8 -0
  109. package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +31 -12
  110. package/src/runtime/agent/orchestrator/tools/builtin/read-single-fast-paths.mjs +32 -35
  111. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +11 -12
  112. package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +9 -6
  113. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +80 -66
  114. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +8 -3
  115. package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +5 -1
  116. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +16 -7
  117. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +2 -1
  118. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +137 -0
  119. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +11 -10
  120. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +21 -11
  121. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +12 -1
  122. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +56 -13
  123. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +58 -0
  124. package/src/runtime/agent/orchestrator/tools/code-graph/trusted-roots.mjs +25 -1
  125. package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +78 -5
  126. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +2 -0
  127. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +0 -10
  128. package/src/runtime/attachments/store.mjs +38 -0
  129. package/src/runtime/channels/index.mjs +1 -5
  130. package/src/runtime/channels/lib/runtime-paths.mjs +8 -23
  131. package/src/runtime/channels/lib/tool-dispatch.mjs +1 -13
  132. package/src/runtime/channels/lib/worker-ipc.mjs +2 -2
  133. package/src/runtime/channels/lib/worker-main.mjs +4 -34
  134. package/src/runtime/shared/atomic-file.mjs +8 -2
  135. package/src/runtime/shared/best-effort-stderr.mjs +8 -0
  136. package/src/runtime/shared/code-graph-state.mjs +12 -0
  137. package/src/runtime/shared/defaults-separation.mjs +2 -0
  138. package/src/runtime/shared/git-runner-worker.mjs +3 -2
  139. package/src/runtime/shared/git-runner.mjs +4 -3
  140. package/src/runtime/shared/llm/default-context-window.mjs +6 -0
  141. package/src/runtime/shared/llm/model-catalog-projection.mjs +5 -4
  142. package/src/runtime/shared/llm/model-catalog.mjs +240 -118
  143. package/src/runtime/shared/llm/provider-catalog-cache.mjs +36 -28
  144. package/src/runtime/shared/llm/provider-catalog-registry.mjs +156 -0
  145. package/src/runtime/shared/llm/provider-seed-rosters.mjs +130 -0
  146. package/src/runtime/shared/model-proxy-mode.d.mts +3 -0
  147. package/src/runtime/shared/model-proxy-mode.mjs +19 -0
  148. package/src/runtime/shared/provider-accounts.mjs +2 -2
  149. package/src/runtime/shared/provider-api-key.mjs +21 -1
  150. package/src/runtime/shared/schedule-model-ref.mjs +11 -2
  151. package/src/runtime/shared/semver.d.mts +1 -0
  152. package/src/runtime/shared/semver.mjs +57 -0
  153. package/src/runtime/shared/session-usage-totals.mjs +19 -0
  154. package/src/runtime/shared/sharp-electron-linux.mjs +25 -0
  155. package/src/runtime/shared/singleton-owner.mjs +36 -6
  156. package/src/runtime/shared/statusline/statusline-segments.mjs +68 -14
  157. package/src/runtime/shared/tool-surface.mjs +9 -2
  158. package/src/runtime/shared/tool-work-units.mjs +14 -0
  159. package/src/runtime/shared/transcript-metadata.mjs +17 -1
  160. package/src/runtime/shared/turn-changes.mjs +791 -0
  161. package/src/runtime/shared/turn-snapshot-store.mjs +346 -12
  162. package/src/runtime/shared/turn-snapshot.mjs +690 -81
  163. package/src/runtime/shared/turn-worktree-snapshot.mjs +161 -11
  164. package/src/runtime/shared/update-checker.mjs +2 -31
  165. package/src/runtime/shared/worktrees/cache-cleanups.mjs +52 -0
  166. package/src/runtime/shared/worktrees/contract.mjs +551 -0
  167. package/src/runtime/shared/worktrees/disk.mjs +57 -0
  168. package/src/runtime/shared/worktrees/git.mjs +247 -0
  169. package/src/runtime/shared/worktrees/include.mjs +480 -0
  170. package/src/runtime/shared/worktrees/lock.mjs +46 -0
  171. package/src/runtime/shared/worktrees/maintenance.mjs +96 -0
  172. package/src/runtime/shared/worktrees/manager.mjs +1215 -0
  173. package/src/runtime/shared/worktrees/merge.mjs +182 -0
  174. package/src/runtime/shared/worktrees/owner.mjs +46 -0
  175. package/src/runtime/shared/worktrees/paths.mjs +62 -0
  176. package/src/runtime/shared/worktrees/registry.mjs +110 -0
  177. package/src/runtime/shared/worktrees/settings.mjs +84 -0
  178. package/src/runtime/shared/worktrees/slug.mjs +62 -0
  179. package/src/runtime/shared/worktrees/test-support.mjs +96 -0
  180. package/src/runtime/visualize-bridge/client.mjs +181 -0
  181. package/src/runtime/visualize-bridge/tool-defs.mjs +97 -0
  182. package/src/session-runtime/boot/apis.mjs +35 -0
  183. package/src/session-runtime/boot/begin.mjs +0 -2
  184. package/src/session-runtime/boot/config.mjs +2 -0
  185. package/src/session-runtime/boot/facade.mjs +20 -0
  186. package/src/session-runtime/boot/infrastructure.mjs +1 -0
  187. package/src/session-runtime/boot/session.mjs +1 -0
  188. package/src/session-runtime/boot/tools.mjs +9 -4
  189. package/src/session-runtime/config-lifecycle.mjs +10 -1
  190. package/src/session-runtime/cwd-plugins/cwd-apply.mjs +11 -1
  191. package/src/session-runtime/global-extensions.mjs +2 -2
  192. package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +27 -2
  193. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +32 -1
  194. package/src/session-runtime/internal-tool-executor.mjs +9 -1
  195. package/src/session-runtime/lifecycle/session-catalog.mjs +8 -1
  196. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +5 -0
  197. package/src/session-runtime/lifecycle/session-switch/resume.mjs +21 -3
  198. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +16 -0
  199. package/src/session-runtime/mcp-glue/connect.mjs +11 -6
  200. package/src/session-runtime/mcp-glue/server-catalog.mjs +7 -3
  201. package/src/session-runtime/mcp-glue/server-input.mjs +29 -0
  202. package/src/session-runtime/model-route/route-persist.mjs +3 -0
  203. package/src/session-runtime/model-route/set-route.mjs +15 -2
  204. package/src/session-runtime/notification-bus.mjs +9 -1
  205. package/src/session-runtime/provider-models/row-hydration.mjs +2 -0
  206. package/src/session-runtime/resource-extension-sync.mjs +30 -7
  207. package/src/session-runtime/resource-mcp-api.mjs +27 -10
  208. package/src/session-runtime/route-resolution.mjs +10 -1
  209. package/src/session-runtime/route-state.mjs +16 -2
  210. package/src/session-runtime/runtime-bootstrap.mjs +0 -4
  211. package/src/session-runtime/runtime-core.mjs +5 -0
  212. package/src/session-runtime/runtime-facade.mjs +8 -0
  213. package/src/session-runtime/runtime-paths.mjs +0 -1
  214. package/src/session-runtime/runtime-review-api.mjs +9 -0
  215. package/src/session-runtime/services/agent-tool/helpers.mjs +5 -0
  216. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +3 -0
  217. package/src/session-runtime/services/agent-tool/job-views/job-lookup.mjs +1 -0
  218. package/src/session-runtime/services/agent-tool/job-views/spawn-meta.mjs +1 -0
  219. package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +15 -0
  220. package/src/session-runtime/services/agent-tool/send-flow.mjs +1 -0
  221. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +10 -2
  222. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +19 -7
  223. package/src/session-runtime/services/agent-tool/spawn-preset.mjs +3 -0
  224. package/src/session-runtime/services/agent-tool/tag-registry.mjs +2 -1
  225. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +5 -0
  226. package/src/session-runtime/services/agent-tool/worker-rows.mjs +1 -0
  227. package/src/session-runtime/services/agent-tool.mjs +1 -0
  228. package/src/session-runtime/services/channel-worker.mjs +1 -1
  229. package/src/session-runtime/services/daemon-candidate.mjs +3 -2
  230. package/src/session-runtime/services/daemon-crash-capture/spawn-capture.mjs +55 -0
  231. package/src/session-runtime/session-create/session-options.mjs +10 -1
  232. package/src/session-runtime/session-turn-api.mjs +1 -0
  233. package/src/session-runtime/settings-api.mjs +4 -2
  234. package/src/session-runtime/settings-builtin-tools-api.mjs +9 -2
  235. package/src/session-runtime/settings-profile-api.mjs +27 -2
  236. package/src/session-runtime/settings-worktree-api.mjs +17 -0
  237. package/src/session-runtime/setup-tool/executor.mjs +11 -4
  238. package/src/session-runtime/setup-tool/settings-contract.mjs +3 -1
  239. package/src/session-runtime/setup-tool/tool-defs.mjs +31 -3
  240. package/src/session-runtime/starter-guide-state.mjs +62 -0
  241. package/src/session-runtime/turn/agent-ops.mjs +12 -1
  242. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +13 -3
  243. package/src/session-runtime/turn/turn-run/snapshot-tracker.mjs +20 -15
  244. package/src/session-runtime/turn/turn-run/turn-open.mjs +4 -5
  245. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +29 -1
  246. package/src/session-runtime/turn/turn-run/turn-settle.mjs +6 -1
  247. package/src/session-runtime/turn/turn-run.mjs +6 -7
  248. package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -3
  249. package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -2
  250. package/src/session-runtime/workspace/admission-gate.mjs +197 -0
  251. package/src/session-runtime/workspace/project-branches.mjs +136 -0
  252. package/src/session-runtime/workspace/transition-steps.mjs +364 -0
  253. package/src/session-runtime/workspace/transitions.mjs +651 -0
  254. package/src/session-runtime/workspace/workspace-state.mjs +112 -0
  255. package/src/standalone/channel-binding.mjs +1 -2
  256. package/src/standalone/channel-transport/call-dispatch.mjs +4 -10
  257. package/src/standalone/channel-transport/http-routes.mjs +17 -0
  258. package/src/standalone/channel-transport.mjs +13 -1
  259. package/src/standalone/daemon-channels-loader.mjs +2 -3
  260. package/src/standalone/daemon-desktop-runtime.mjs +1 -0
  261. package/src/standalone/daemon-owner.mjs +372 -0
  262. package/src/standalone/daemon-stored-session-views.mjs +4 -1
  263. package/src/standalone/daemon.mjs +139 -5
  264. package/src/standalone/desktop-service-registry.mjs +20 -0
  265. package/src/standalone/local-session-runtime.mjs +13 -78
  266. package/src/standalone/session-client/attachment-calls.mjs +3 -1
  267. package/src/standalone/session-client/daemon-unavailable.mjs +62 -0
  268. package/src/standalone/session-client/lease-heartbeat.mjs +47 -0
  269. package/src/standalone/session-client.mjs +104 -13
  270. package/src/standalone/session-protocol.mjs +17 -0
  271. package/src/standalone/session-proxy.mjs +3 -0
  272. package/src/standalone/session-service/agent-tree/agent-child.mjs +4 -0
  273. package/src/standalone/session-service/agent-tree/agent-rehydrate.mjs +1 -0
  274. package/src/standalone/session-service/entries/lifecycle.mjs +6 -0
  275. package/src/standalone/session-service/projection/revisions.mjs +2 -0
  276. package/src/standalone/session-service/projection/transcript-window.mjs +149 -19
  277. package/src/standalone/session-service/projection/workspace.mjs +14 -0
  278. package/src/standalone/session-service/session-calls/session-action.mjs +11 -3
  279. package/src/standalone/session-transport/call-route.mjs +13 -0
  280. package/src/standalone/session-transport/client-registry/client-grace.mjs +45 -3
  281. package/src/standalone/session-transport/client-registry/registration-replays.mjs +1 -0
  282. package/src/standalone/session-transport/client-registry.mjs +20 -3
  283. package/src/standalone/session-transport/routes.mjs +79 -2
  284. package/src/standalone/session-transport/stack.mjs +2 -0
  285. package/src/standalone/session-transport.mjs +24 -1
  286. package/src/tui/app/message-selector.mjs +2 -1
  287. package/src/tui/app/model-options.mjs +35 -5
  288. package/src/tui/app/model-picker/provider-models-list.mjs +2 -2
  289. package/src/tui/app/model-picker.mjs +4 -2
  290. package/src/tui/dist/index.mjs +332 -36
  291. package/src/tui/index.jsx +10 -2
  292. package/src/tui/session/compaction-view.mjs +147 -0
  293. package/src/tui/session/context-state.mjs +6 -0
  294. package/src/tui/session/initial-state.mjs +3 -0
  295. package/src/tui/session/quota-resume.mjs +2 -1
  296. package/src/tui/session/session-api/commands.mjs +10 -2
  297. package/src/tui/session/session-api/controls.mjs +4 -0
  298. package/src/tui/session/session-api/extensions.mjs +12 -8
  299. package/src/tui/session/session-api/intake/rewind.mjs +2 -1
  300. package/src/tui/session/session-api/integrations.mjs +18 -0
  301. package/src/tui/session/session-api/lifecycle/dispose.mjs +6 -1
  302. package/src/tui/session/session-api/lifecycle/inheritance.mjs +2 -0
  303. package/src/tui/session/session-api/lifecycle/resume.mjs +3 -0
  304. package/src/tui/session/session-api/routes.mjs +10 -1
  305. package/src/tui/session/session-api/settings.mjs +2 -0
  306. package/src/tui/session/session-api/shared.mjs +10 -6
  307. package/src/tui/session/session-api/worktree.mjs +60 -0
  308. package/src/tui/session/session-api.mjs +2 -0
  309. package/src/tui/session/session-flow/auto-clear.mjs +31 -12
  310. package/src/tui/session/session-flow/drain.mjs +15 -1
  311. package/src/tui/session/session-flow/session-reset.mjs +4 -3
  312. package/src/tui/session/session-flow.mjs +2 -0
  313. package/src/tui/session/transcript-intake.mjs +14 -5
  314. package/src/tui/session/turn-stream.mjs +32 -4
  315. package/src/tui/session/turn-tool-cards.mjs +10 -2
  316. package/src/tui/session/turn.mjs +39 -10
  317. package/src/runtime/channels/tool-defs.mjs +0 -17
package/README.md CHANGED
@@ -139,6 +139,7 @@ savings come from.
139
139
  - [Benchmarks](benchmarks/terminal-bench-2.1/)
140
140
  - [Code Tidy](docs/code-tidy.md)
141
141
  - [Git & GitHub](docs/git-github-integration.md)
142
+ - [SSH servers](docs/ssh-remote.md) (Korean, with an English summary)
142
143
  - [Language servers](docs/language-servers.md)
143
144
  - [Office runtime](src/runtime/office/README.md)
144
145
  - [Development, configuration, and testing](docs/development.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mixdog",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Open-source coding agent that matches Codex on Terminal-Bench 2.1 with 63% fewer tokens.",
@@ -156,6 +156,7 @@
156
156
  "@formulajs/formulajs": "^4.6.1",
157
157
  "@google/generative-ai": "^0.24.1",
158
158
  "@huggingface/transformers": "^4.2.0",
159
+ "@img/sharp-wasm32": "0.35.3",
159
160
  "@modelcontextprotocol/sdk": "^1.29.0",
160
161
  "@mozilla/readability": "^0.6.0",
161
162
  "@napi-rs/canvas": "^1.0.8",
@@ -203,7 +204,6 @@
203
204
  "eslint-scope": "^9.1.2",
204
205
  "lucide-static": "^1.41.0"
205
206
  },
206
- "main": "index.js",
207
207
  "directories": {
208
208
  "doc": "docs"
209
209
  },
@@ -132,6 +132,15 @@ export function testIsolationEnv(scratchDir) {
132
132
  export const DEFAULT_TEST_TIMEOUT_MS = 120_000;
133
133
  export const LONG_TEST_TIMEOUT_MS = 600_000;
134
134
 
135
+ /** Per-file timeout default for explicitly named files: a `.slow`/`.live`/
136
+ * `.electron` test file keeps its lane's long bound (scripts/test.mjs laneOf)
137
+ * even when run outside the lane runner. */
138
+ export function explicitFilesTimeoutMs(fileArgs) {
139
+ return fileArgs.some((arg) => /\.(slow|live|electron)\.test\.mjs$/.test(String(arg)))
140
+ ? LONG_TEST_TIMEOUT_MS
141
+ : DEFAULT_TEST_TIMEOUT_MS;
142
+ }
143
+
135
144
  // A batch that has not exited by then is killed with its process tree and
136
145
  // fails the run; MIXDOG_TEST_BATCH_TIMEOUT_MS overrides the default.
137
146
  const DEFAULT_BATCH_TIMEOUT_MS = 60 * 60 * 1000;
@@ -190,6 +190,9 @@ async function prunePdfRuntime(nodeModules) {
190
190
  }
191
191
 
192
192
  async function pruneSharpWasmFallback(nodeModules, target) {
193
+ // The Linux daemon runs on Electron, whose system GLib breaks the native
194
+ // addon; src/runtime/shared/sharp-electron-linux.mjs routes it to wasm.
195
+ if (target.platform === 'linux') return false;
193
196
  const imgRoot = join(nodeModules, '@img');
194
197
  let packages;
195
198
  try {
@@ -2,7 +2,7 @@
2
2
  // Single source of truth for CI/CD path selection.
3
3
  //
4
4
  // Consumers:
5
- // - .github/workflows/release-gate.yml → `node scripts/release-paths.mjs desktop-regex|runtime-regex`
5
+ // - .github/workflows/release-gate.yml → `node scripts/release-paths.mjs desktop-regex|runtime-regex|patch-regex|history-regex|mobile-regex`
6
6
  // (grep -E patterns selecting which incremental gates a change requires)
7
7
  // - .github/workflows/deploy.yml → `import { RELEASE_CRITICAL_PATHS }`
8
8
  // (git diff paths whose change invalidates the previous release's
@@ -47,6 +47,24 @@ const PATCH_GATE_FILES = [
47
47
  ...GATE_SELECTION_SOURCES,
48
48
  ];
49
49
 
50
+ // The shipped-definition history is generated from git history of the agent,
51
+ // workflow, output-style and bundled-skill trees (scripts/build-shipped-history.mjs)
52
+ // and committed under src/defaults/. Release re-checks it, so the gate checks
53
+ // it first instead of letting a stale file fail the deploy late.
54
+ const HISTORY_GATE_PREFIXES = ['src/agents/', 'src/workflows/', 'src/output-styles/', 'src/defaults/'];
55
+ const HISTORY_GATE_FILES = [
56
+ 'scripts/build-shipped-history.mjs',
57
+ 'src/runtime/shared/shipped-definitions.mjs',
58
+ '.github/workflows/release-gate.yml',
59
+ ...GATE_SELECTION_SOURCES,
60
+ ];
61
+
62
+ // The mobile release scripts (Python) carry unittest suites that no Node lane
63
+ // discovers; they run when those scripts or the mobile workflows change.
64
+ const MOBILE_GATE_PREFIXES = ['apps/mobile/scripts/'];
65
+ const MOBILE_WORKFLOW_PATTERN = '\\.github/workflows/mobile-[^/]*\\.yml$';
66
+ const MOBILE_GATE_FILES = ['.github/workflows/release-gate.yml', ...GATE_SELECTION_SOURCES];
67
+
50
68
  // deploy.yml plan: paths whose change since the published release tag marks
51
69
  // the default lane as unverified.
52
70
  export const RELEASE_CRITICAL_PATHS = ['native', 'scripts', 'src', ...PACKAGE_MANIFESTS];
@@ -77,14 +95,33 @@ export function patchGateRegex() {
77
95
  ].join('|')})`;
78
96
  }
79
97
 
98
+ export function historyGateRegex() {
99
+ return `^(${[
100
+ ...HISTORY_GATE_PREFIXES.map(escapeRegex),
101
+ ...HISTORY_GATE_FILES.map((file) => `${escapeRegex(file)}$`),
102
+ ].join('|')})`;
103
+ }
104
+
105
+ export function mobileGateRegex() {
106
+ return `^(${[
107
+ ...MOBILE_GATE_PREFIXES.map(escapeRegex),
108
+ ...MOBILE_GATE_FILES.map((file) => `${escapeRegex(file)}$`),
109
+ MOBILE_WORKFLOW_PATTERN,
110
+ ].join('|')})`;
111
+ }
112
+
80
113
  const mode = process.argv[2];
81
114
  if (mode) {
82
115
  if (mode === 'desktop-regex') process.stdout.write(`${desktopGateRegex()}\n`);
83
116
  else if (mode === 'runtime-regex') process.stdout.write(`${runtimeGateRegex()}\n`);
84
117
  else if (mode === 'patch-regex') process.stdout.write(`${patchGateRegex()}\n`);
118
+ else if (mode === 'history-regex') process.stdout.write(`${historyGateRegex()}\n`);
119
+ else if (mode === 'mobile-regex') process.stdout.write(`${mobileGateRegex()}\n`);
85
120
  else if (mode === 'critical-paths') process.stdout.write(`${RELEASE_CRITICAL_PATHS.join('\n')}\n`);
86
121
  else {
87
- process.stderr.write(`unknown mode: ${mode} (expected desktop-regex|runtime-regex|patch-regex|critical-paths)\n`);
122
+ process.stderr.write(
123
+ `unknown mode: ${mode} (expected desktop-regex|runtime-regex|patch-regex|history-regex|mobile-regex|critical-paths)\n`
124
+ );
88
125
  process.exit(1);
89
126
  }
90
127
  }
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // Explicit Node test options and file paths, without discovery or lane filters.
3
- import { runNodeTests } from './lib/run-node-tests.mjs';
3
+ import { explicitFilesTimeoutMs, runNodeTests } from './lib/run-node-tests.mjs';
4
4
 
5
5
  const argv = process.argv.slice(2);
6
6
  // The same defaults as scripts/test.mjs: `mock.module` is still flag-gated on
@@ -17,5 +17,7 @@ await runNodeTests(
17
17
  '--test',
18
18
  ...unlessGiven('--test-force-exit'),
19
19
  ],
20
- argv
20
+ argv,
21
+ // A named slow-lane file keeps the slow lane's per-file bound.
22
+ { testTimeoutMs: explicitFilesTimeoutMs(argv) }
21
23
  );
@@ -321,9 +321,11 @@
321
321
  "0f14ba0a3d8b3896b717dc144bbe49a4",
322
322
  "1c317db86e1ff80a5c4102e09e36f5fb",
323
323
  "242f11864abdef90fa0cc9cb4599a579",
324
+ "29a347c4d3a2f773fa92c627260301ba",
324
325
  "336ced846a9e4f774cbb109417856c3b",
325
326
  "3f72247651ad9d777b6754bfd46732aa",
326
327
  "50bdf35d06913236855080fdea6b50dc",
328
+ "5b4586a44104b26ae7dd45da101079bf",
327
329
  "6101786127a1e68778eafcd2bf2c9ce0",
328
330
  "6711dbc9d84023b8eabfa928b8d33d18",
329
331
  "6f9e9338f560fa9acd839a67b5e2d1cc",
@@ -339,6 +341,7 @@
339
341
  "e04e6abe9a54e7d07b37f8fc32b5ad30",
340
342
  "e38d606df69865a9cf1cc48386535e8b",
341
343
  "e5ac8ea16905815e36e88d883195a617",
344
+ "e9b89f9193bd9d9c80ba6cf4419e58ff",
342
345
  "feabe973080344c4d52787a96043ab68",
343
346
  "ff18ac1a9f5961925aec27ffb870bae0"
344
347
  ],
@@ -360,6 +363,9 @@
360
363
  "f209e75b6ea0360929516a713474ad71",
361
364
  "fe0512acbb2fc8f80c5961b9f44aa5e2"
362
365
  ],
366
+ "visualize": [
367
+ "f65924f0691284ad31000469a9855b62"
368
+ ],
363
369
  "xlsx": [
364
370
  "0deebbdd009b0a0941ca4b0833dbe7f6",
365
371
  "10778ab8e1e2f7929895c034fef9ac41",
@@ -6,7 +6,7 @@ Read this when choosing a `setup` mutation.
6
6
 
7
7
  - `status` reads one domain: summary, model, agents, workflow, websearch,
8
8
  output-style, profile, autoclear, compaction, memory, features, local-provider, shell,
9
- providers, mcp, skills, plugins, update, onboarding, capabilities, developer,
9
+ providers, mcp, skills, plugins, update, onboarding, worktree, capabilities, developer,
10
10
  desktop, appearance, projects, connection, schedules, webhooks, hooks, or
11
11
  media.
12
12
  - `open` navigates to a supported UI surface. Read `surfaces.md` for targets and
@@ -42,6 +42,7 @@ Read this when choosing a `setup` mutation.
42
42
  | Permanently delete confirmed, unchanged, unused model files | `delete_local_model` |
43
43
  | TUI system shell | `set_system_shell` |
44
44
  | Automatic updates | `set_auto_update` |
45
+ | Worktree defaults: new tasks on the current branch or a new worktree, branch prefix, large-repository warning size, automatic cleanup | `set_worktree_settings` |
45
46
  | Remove stored provider authentication (one OAuth account at a time) | `forget_provider_auth` |
46
47
  | Select, rename, reorder, or auto-switch OAuth accounts, or allow paid credits | `set_provider_account` |
47
48
  | Developer options such as risk-gated OAuth providers | `set_developer_option` |
@@ -85,7 +86,9 @@ Read this when choosing a `setup` mutation.
85
86
  Inspect `status model`, `status agents`, `status websearch`, or `status
86
87
  workflow` before changing the corresponding domain.
87
88
 
88
- - Main and agent routes also accept `modelParameters` and `contextPercent`; agent routes accept `disabled`.
89
+ - Main and agent routes also accept `modelParameters`, `contextPercent`, and
90
+ `contextTokens` (an exact window in tokens that overrides `contextPercent`);
91
+ agent routes accept `disabled`.
89
92
  Use the model catalog for actual available options, not remembered model ids.
90
93
  - A Web Search route must support native web search; tool exposure is changed
91
94
  separately.
@@ -0,0 +1,157 @@
1
+ ---
2
+ name: visualize
3
+ description: Show mockups, design options, diagrams, and finished artifacts beside the chat with the visualize tool.
4
+ when_to_use: 'Mockups before UI work, design options, visual explanations, or showing a produced artifact; not production code alone.'
5
+ metadata:
6
+ requires: visualize
7
+ dependencies:
8
+ tools:
9
+ - type: tool
10
+ value: visualize
11
+ ---
12
+
13
+ # Visualize (visualize tool)
14
+
15
+ The side panel is where the user sees the work instead of reading about it.
16
+ This file owns when to draw, how a mockup is built and iterated, and how results
17
+ are shown. The schema owns action fields. `references/craft.md` owns the design
18
+ bar every mockup is held to; read it before the first mockup of a session.
19
+
20
+ ## 1. Which job
21
+ **Hard rule — seeing beats reading, or it is not this skill**: draw when the
22
+ answer is a layout, a state, a flow, a spatial relation, or a look. Scope,
23
+ tradeoffs, and wording decisions stay in chat even when the topic is UI.
24
+ - *Show* — any artifact you produced or changed (HTML, deck, document, sheet,
25
+ PDF, image, video, a local dev page): `open` it once when it is ready. Edits
26
+ reload the tab by themselves; never reopen to refresh.
27
+ - *Mockup* — a UI change before implementation, or the user asks for a
28
+ 시안/mockup/preview. §2.
29
+ - *Options* — the direction is genuinely open (the user is unsure, or two
30
+ readings of the request lead to different layouts). §3.
31
+ - *Explain* — a flow, state machine, architecture, or data path the user needs
32
+ to grasp: one HTML diagram page, no option machinery.
33
+ **Hard rule — not this tool**: authoring Office files, images, or video belongs
34
+ to their own skills; this skill only shows their output. Clicking, typing, and
35
+ testing a page belong to `browser`.
36
+
37
+ ## 2. Mockup loop
38
+ 1. **Ground in the real product.** Read the files that define the touched
39
+ surface — tokens, theme, the component and its neighbours — before drawing.
40
+ For an existing app screen, prefer the real screen (a capture of the running
41
+ app) with only the changed parts drawn over it; invented chrome hides what
42
+ actually changes. Done when you can name the exact component and values the
43
+ change touches.
44
+ 2. **Split the change into states.** Every state the user will meet gets its
45
+ own labelled frame: A default, B the interaction, C the result, D failure or
46
+ empty where they exist. One frame per state, captioned with what changed and
47
+ why in one sentence.
48
+ 3. **Write** `design/mockups/<topic>/index.html` (self-contained: inline CSS
49
+ and JS, no network). Sample data is realistic and marked as sample once in
50
+ the lead line; never fake metrics or filler sections.
51
+ 4. **Show**: `open` the page, then `annotate` each changed element with a short
52
+ label. Marks live on the panel, not in the file.
53
+ 5. **Look before you report.** Run `visualize check` on the tab and fix every
54
+ reported page problem (uncaught errors, CSP violations, console errors,
55
+ missing assets, blocked network requests: the page must be self-contained)
56
+ in the file, then `check` again until it reports none; a
57
+ "Page problems" section on any `open`, `annotate`, or `capture` result counts
58
+ the same. Then run `visualize inspect` on the tab: once at the panel's
59
+ width and, when the design is responsive, again with `viewport`
60
+ `{width: 375, height: 812}`; fix every finding it lists (overflow, clipped
61
+ text, tiny or overlapping targets, low contrast, missing alt or labels) in
62
+ the file before reporting. Then `capture` the tab (or read it through
63
+ `browser`) and check it against `references/craft.md` §5; fix what fails
64
+ before the user sees the report.
65
+ 6. **Report** in chat: path, the states shown, what to confirm, and the open
66
+ questions. Then stop — implementation waits for approval.
67
+ 7. **Iterate in place.** Feedback edits the same file; the tab reloads and the
68
+ panel keeps each saved state as a version (v1…vN) the user can step back
69
+ to, compare side by side, or restore, so never copy the file to keep an
70
+ old version. The user can also point at the page: their message then carries a
71
+ `<visualize_feedback>` block of numbered pins (`pin N` = the "📌 N" they
72
+ saw), each with the note, tab and project-relative file, and for an HTML
73
+ element its selector, label, trimmed HTML, key styles and box (a PDF or
74
+ image pin gives a region instead), plus the crop image "visualize pin N"
75
+ when there is one. Answer pin by pin by number and act on the element
76
+ the selector names; secret values arrive as `[redacted]`, so never restore
77
+ them from the crop or guess them.
78
+ 8. **After approval**: implement from the approved mockup; its values are the
79
+ spec. When the work needs a record, `export` the approved tab to PNG or PDF
80
+ beside the page (`export` with `format` and a project-relative `output`,
81
+ e.g. `design/mockups/login/login-approved.png`; `version` for a kept
82
+ version). A single HTML page renders whole in a hidden window, so the tab need
83
+ not be on screen; the result lists the written path, size, and any page
84
+ problems. Remove any temporary data or records you created to stage
85
+ the mockup, and say so.
86
+
87
+ ## 3. Options
88
+ **Default — one strong mockup.** Options only when the direction is open.
89
+ **Hard rule — options differ in stance, not in pixels**: pick one axis that
90
+ matters for this decision (density, layout model, emphasis, interaction model)
91
+ and pull the 2–3 options apart on it. Two options that differ by accent colour
92
+ or radius are one option.
93
+ - Name each by its stance ("1 · one menu", "2 · inline chips") and give its
94
+ cost in one line.
95
+ - `open` 2–3 targets in one call to show them side by side.
96
+ - Make the options pickable: put `data-choice="<id>"` on each option's root
97
+ (and `data-choice-group="<decision>"` when one page asks more than one
98
+ question; ungrouped choices form one group). A click selects one per group
99
+ and adds `data-choice-selected` to it; the panel's default outline uses
100
+ `:where()`, so style `[data-choice][data-choice-selected]` to match the
101
+ mockup. `data-choice-label` names it when its text does not. Picks reach
102
+ you with the user's next message under `choices:` in the
103
+ `<visualize_feedback>` block as tab, file, group, choice id and label.
104
+ - When the user picks, consolidate into one mockup and close the others; a
105
+ pile of options is not a result.
106
+
107
+ ## 4. Showing results
108
+ - Open a result once, when it is ready to look at, not at every intermediate
109
+ write. Long multi-step work shows the first reviewable state, then lets
110
+ reloads carry the rest.
111
+ - Decks and documents: the panel shows the converted pages; still run the
112
+ owning skill's own render review — the panel is for the user, not your QC.
113
+ - Close tabs that no longer match the conversation (a resolved choice, a
114
+ replaced draft) so the user is never looking at stale work.
115
+ - A web URL is opened alone, never mixed with files; marking, capturing, or
116
+ closing a web page belongs to `browser`.
117
+ - `annotate` and `capture` need the tab on screen (`export` of an HTML page does not). When they report the panel
118
+ is hidden, tell the user to open it rather than retrying.
119
+ - When `visualize` is unavailable, give the file path; never start your own
120
+ server or pretend it was shown.
121
+
122
+ ### Inline content or a file
123
+ - **Inline** (`open` with `input.content` — `mermaid`, `svg`, `chart` (an
124
+ ECharts option as JSON), `html`, `markdown`): diagrams, charts, quick
125
+ sketches and notes you will not edit again. No file is written. `mermaid`,
126
+ `svg` and `markdown` are static, sanitized output (no scripts). `chart` is
127
+ interactive (tooltips, zoom) and `html` runs its scripts, as in-memory pages
128
+ held to the same rules as an HTML file: outside network is blocked, so an
129
+ `html` sketch must be self-contained, and its page problems come back in the
130
+ result. Re-opening with the same `title` adds a version.
131
+ - **File** (`targets`): a real mockup that needs iteration, scripts, assets,
132
+ versioning on disk, annotate/Comment feedback, or a deliverable the user keeps.
133
+ - A render error comes back as a page problem (Mermaid parse error, bad chart
134
+ JSON): fix the source and open again; never report it as shown.
135
+
136
+ ### Tweaks
137
+ Offer tweaks when the open decision is a value, not a layout: colour, density,
138
+ spacing, type scale, radius. The page declares them in
139
+ `<script type="application/json" id="mx-tweaks">` (HTML files and inline
140
+ `html`/`chart`): `[{"id":"accent","label":"Accent","type":"color","var":"--accent","default":"#3b82f6"}]`.
141
+ Types: `color` (hex/rgb), `range` (`min`,`max`,`step`,`unit`),
142
+ `select` (`options`), `toggle`; each sets a `--css-var` or a
143
+ `data-*` attribute on the root, which your CSS reads. Keep it to 6 or fewer
144
+ meaningful controls (16 is the hard cap) and give every one a real default.
145
+ The panel adds a Tweaks button; when the user sends their values you get them
146
+ under `tweaks:` in `<visualize_feedback>` (`accent (--accent): #2f6fed (was
147
+ #3b82f6)`): bake them into the file as the new defaults — both the CSS value
148
+ and the control's `default`. A malformed block is a `tweaks: <reason>` page
149
+ problem.
150
+
151
+ ## 5. Reporting
152
+ Short: what is on screen, the path, the decision you need. Do not narrate the
153
+ HTML. Uncertain or unverified rendering is stated, not glossed.
154
+ The panel and the chat card already show the content: never repeat its source
155
+ (Mermaid text, chart JSON, SVG, HTML) or re-render its data as a chat table or
156
+ text chart. Name the tab and give one or two lines on what it shows or what to
157
+ look at.
@@ -0,0 +1,88 @@
1
+ # Craft bar for mockups and visual pages
2
+
3
+ The bar is "a designer on this product drew it", not "a page was generated".
4
+ Most generated-looking design is wrong composition, not wrong colour; fix the
5
+ cause in the order below.
6
+
7
+ ## 1. Source before taste
8
+ - An existing product wins over every rule here. Lift its real tokens,
9
+ spacing, radii, type, copy tone, and density from source files; do not
10
+ approximate from memory or a screenshot when the code is readable.
11
+ - A new surface with no system: define a small one first (4–6 named colours,
12
+ one or two type families with roles, a spacing step, one radius scale) and
13
+ write it as CSS variables at the top of the page.
14
+ - A brief's explicit direction wins, including when it asks for a look this
15
+ file warns against.
16
+
17
+ ## 2. Name the surface, then compose
18
+ Before any colour or component, decide in one line what the user does here;
19
+ the composition follows from it:
20
+
21
+ | Surface | User is… | Composition carries |
22
+ |---|---|---|
23
+ | Watch | following changing state | density, glanceable hierarchy, no marketing framing |
24
+ | Act | working through items | selection, row actions, clear current item |
25
+ | Compare | weighing options | aligned columns, equal structure, one differentiator |
26
+ | Set up | configuring | grouped fields, save/validation states, little decoration |
27
+ | Persuade / teach | being convinced or taught | one idea per section; the only place a hero belongs |
28
+ | Browse | exploring a space | filters, results, peek/zoom |
29
+ | Drive / inspect | commanding or drilling into one object | keyboard paths, focus, detail panes |
30
+
31
+ A screen spanning two picks a primary one; never average them.
32
+
33
+ ## 3. Hierarchy with type and space first
34
+ - Scale, weight, and spacing carry hierarchy before boxes, borders, icons, or
35
+ colour. Add a container only when it groups something the user acts on.
36
+ - Line length under ~80 characters; numbers in tables tabular and aligned.
37
+ - Structural marks (numbers, dividers, labels) only when they encode real
38
+ information — numbered steps only for a real sequence.
39
+ - One memorable element per page; everything around it stays quiet.
40
+
41
+ ## 4. Words are interface
42
+ - Name things by what the user understands, not how the system is built.
43
+ - Buttons say what happens ("Save changes"); the same action keeps the same
44
+ name through the flow ("Publish" → "Published").
45
+ - Errors say what happened and what to do, without apology. Empty states
46
+ invite the next action.
47
+ - Sentence case, plain verbs, no filler or invented claims. Draft copy is
48
+ marked as draft.
49
+
50
+ ## 5. Self-review before showing
51
+ Look at the capture, list which of these fire, then repair by cause:
52
+
53
+ Composition (re-layout; recolouring will not fix these):
54
+ 1. Wrong surface — e.g. a hero on a dashboard.
55
+ 2. Everything centred because no layout was chosen.
56
+ 3. Equal-weight tile grids (icon + heading + sentence ×3) where one thing
57
+ should lead.
58
+
59
+ Decoration (remove; replace with scale, weight, or spacing):
60
+ 4. Coloured side rails on cards.
61
+ 5. Blur or glass with no elevation system behind it.
62
+ 6. Oversized stat numbers filling space meant for content.
63
+ 7. A rounded icon above every heading; icons that do not aid scanning.
64
+ 8. Identical cards, one radius and one soft shadow on everything.
65
+
66
+ Defaults (recolour / re-typeset only if the brief left them free):
67
+ 9. Indigo/violet accent or glossy gradient chosen by habit.
68
+ 10. Default font used without a reason; ALL-CAPS eyebrow labels over every
69
+ heading; one word accented in a headline; "→" on every link.
70
+
71
+ Re-check after repairing. Do not show while 1–3 still fire.
72
+
73
+ ## 6. Quality floor (always, without announcing it)
74
+ `visualize inspect` reports most floor failures (overflow, clipped text,
75
+ small or overlapping targets, low contrast, missing alt or labels); a page is
76
+ not shown while it lists any.
77
+ - Visible keyboard focus, real hover and disabled states where shown.
78
+ - Readable contrast for text and controls; hit targets ≥ 44px on touch frames.
79
+ - Motion only when it shows what changed; respect `prefers-reduced-motion`.
80
+ - Fits the panel width without horizontal scroll; frames wider than the panel
81
+ scale down rather than clip.
82
+ - Self-contained: no CDN, web font, API or other network request. The panel
83
+ blocks outside network unless the user allows it (a blocked request is a
84
+ `blocked-network` page problem), so inline or bundle every asset in the
85
+ project. No fake data passed off as real, or stock imagery.
86
+ - A value the user may want to tune (accent, density, spacing) is a CSS variable
87
+ on the root plus a control in `<script type="application/json" id="mx-tweaks">
88
+ [{"id":"accent","type":"color","var":"--accent","default":"#3b82f6"}]`.
@@ -1,5 +1,12 @@
1
+ import { worktreeNameError } from './runtime/shared/worktrees/contract.mjs';
2
+
1
3
  const VALUE_OPTIONS = new Set(['--provider', '--model', '--effort', '--workflow']);
4
+ // `--worktree [name]` takes an optional value; `--worktree=<name>` is the
5
+ // unambiguous spelling.
6
+ const WORKTREE_OPTION = '--worktree';
7
+ const NO_WORKTREE_OPTION = '--no-worktree';
2
8
  const FLAG_OPTIONS = new Set([
9
+ NO_WORKTREE_OPTION,
3
10
  '--readonly',
4
11
  '--help',
5
12
  '-h',
@@ -12,7 +19,7 @@ const FLAG_OPTIONS = new Set([
12
19
  '--memory',
13
20
  '--json',
14
21
  ]);
15
- const EXEC_UNSUPPORTED_FLAGS = new Set(['--readonly', '--remote', '--onboarding', '--memory']);
22
+ const EXEC_UNSUPPORTED_FLAGS = new Set(['--readonly', '--remote', '--onboarding', '--memory', NO_WORKTREE_OPTION]);
16
23
  const HEADLESS_WORKFLOW_ERROR = 'option --workflow is not supported for mixdog exec';
17
24
 
18
25
  function roleKey(value) {
@@ -22,6 +29,16 @@ function roleKey(value) {
22
29
  .replace(/[\s_]+/g, '-');
23
30
  }
24
31
 
32
+ const isWorktreeOption = (arg) => arg === WORKTREE_OPTION || arg.startsWith(`${WORKTREE_OPTION}=`);
33
+
34
+ /** The token after a bare `--worktree` is its name unless it is an option or the exec verb. */
35
+ function worktreeNameToken(value) {
36
+ if (value === undefined || value === null) return null;
37
+ const text = String(value);
38
+ if (!text || text.startsWith('-') || roleKey(text) === 'exec') return null;
39
+ return text;
40
+ }
41
+
25
42
  function argvIndicatesExec(argv) {
26
43
  for (let index = 0; index < argv.length; index += 1) {
27
44
  const arg = String(argv[index] ?? '');
@@ -29,6 +46,11 @@ function argvIndicatesExec(argv) {
29
46
  index += 1;
30
47
  continue;
31
48
  }
49
+ if (arg === WORKTREE_OPTION) {
50
+ if (worktreeNameToken(argv[index + 1]) !== null) index += 1;
51
+ continue;
52
+ }
53
+ if (isWorktreeOption(arg)) continue;
32
54
  if (arg === '--') continue;
33
55
  if (FLAG_OPTIONS.has(arg) || arg.startsWith('-')) continue;
34
56
  return roleKey(arg) === 'exec';
@@ -39,9 +61,23 @@ function argvIndicatesExec(argv) {
39
61
  function parseTokens(argv, { strictValues = true } = {}) {
40
62
  const positional = [];
41
63
  const values = {};
64
+ let worktree;
42
65
  const allowHeadlessIntent = strictValues && !argv.includes('--react');
43
66
  for (let index = 0; index < argv.length; index += 1) {
44
67
  const arg = String(argv[index] ?? '');
68
+ if (isWorktreeOption(arg)) {
69
+ let name = arg === WORKTREE_OPTION ? null : arg.slice(WORKTREE_OPTION.length + 1);
70
+ if (name === null) {
71
+ name = worktreeNameToken(argv[index + 1]);
72
+ if (name !== null) index += 1;
73
+ }
74
+ const nameError = name === null ? null : worktreeNameError(name);
75
+ if (nameError && strictValues) {
76
+ return { error: `option --worktree name ${JSON.stringify(name)} is invalid: ${nameError}` };
77
+ }
78
+ worktree = { mode: 'worktree', name: nameError ? null : name };
79
+ continue;
80
+ }
45
81
  if (VALUE_OPTIONS.has(arg)) {
46
82
  const value = argv[index + 1];
47
83
  if (value === undefined || value === '' || String(value).startsWith('-')) {
@@ -87,7 +123,19 @@ function parseTokens(argv, { strictValues = true } = {}) {
87
123
  }
88
124
  positional.push(arg);
89
125
  }
90
- return { positional, values };
126
+ return { positional, values, worktree };
127
+ }
128
+
129
+ /**
130
+ * Session creation intent from `--worktree [name]` / `--no-worktree`:
131
+ * undefined follows the worktree settings default.
132
+ * @returns {{ worktree?: { mode: 'worktree', name: string|null } | { mode: 'branch' } } | { error: string }}
133
+ */
134
+ function worktreeIntent(argv, parsed) {
135
+ const disabled = argv.includes(NO_WORKTREE_OPTION);
136
+ if (disabled && parsed.worktree) return { error: 'options --worktree and --no-worktree are mutually exclusive' };
137
+ if (disabled) return { worktree: { mode: 'branch' } };
138
+ return parsed.worktree ? { worktree: parsed.worktree } : {};
91
139
  }
92
140
 
93
141
  function execFromPositional(positional) {
@@ -103,7 +151,10 @@ export function classifyCliInvocation(argv = []) {
103
151
  const hasPlain = argv.includes('--plain');
104
152
  const parsed = parseTokens(argv, { strictValues: !hasHelp && !hasPlain });
105
153
  if (parsed.error) return { kind: 'error', ...parsed };
154
+ const intent = worktreeIntent(argv, parsed);
155
+ if (intent.error && !hasHelp && !hasPlain) return { kind: 'error', error: intent.error };
106
156
  const options = {
157
+ ...(intent.worktree ? { worktree: intent.worktree } : {}),
107
158
  provider: parsed.values['--provider'],
108
159
  model: parsed.values['--model'],
109
160
  effort: parsed.values['--effort'],
@@ -129,7 +180,9 @@ export function classifyCliInvocation(argv = []) {
129
180
  skipHostPrelude: true,
130
181
  };
131
182
  }
132
- const unsupported = [...EXEC_UNSUPPORTED_FLAGS].find((flag) => argv.includes(flag));
183
+ const unsupported =
184
+ [...EXEC_UNSUPPORTED_FLAGS].find((flag) => argv.includes(flag)) ||
185
+ (parsed.worktree ? WORKTREE_OPTION : undefined);
133
186
  if (unsupported) {
134
187
  return {
135
188
  kind: 'error',
@@ -75,6 +75,7 @@ export async function runHeadlessExec({
75
75
  memoryRuntimeCleanup = stopStandaloneMemoryRuntimesForProcess,
76
76
  daemonRuntimeCleanup = shutdownDaemonForRuntimeRoot,
77
77
  usageLedgerCleanup = closeUsageLedgers,
78
+ sessionStoreDrain = drainHeadlessSessionStore,
78
79
  hasActiveTasks = hasActiveBackgroundTasks,
79
80
  installSignalCleanupFn = installProcessSignalCleanup,
80
81
  } = {}) {
@@ -122,6 +123,7 @@ export async function runHeadlessExec({
122
123
  memoryRuntimeCleanup,
123
124
  daemonRuntimeCleanup,
124
125
  usageLedgerCleanup,
126
+ sessionStoreDrain,
125
127
  hasActiveTasks,
126
128
  installSignalCleanupFn,
127
129
  });
@@ -155,6 +157,7 @@ async function executeHeadlessPrompt(
155
157
  memoryRuntimeCleanup,
156
158
  daemonRuntimeCleanup,
157
159
  usageLedgerCleanup,
160
+ sessionStoreDrain,
158
161
  hasActiveTasks,
159
162
  installSignalCleanupFn,
160
163
  }
@@ -172,6 +175,7 @@ async function executeHeadlessPrompt(
172
175
  writeErr,
173
176
  hasActiveTasks,
174
177
  usageLedgerCleanup,
178
+ sessionStoreDrain,
175
179
  daemonRuntimeCleanup,
176
180
  memoryRuntimeCleanup,
177
181
  });
@@ -266,7 +270,7 @@ function taskScopeFor(session) {
266
270
  // pristine root.
267
271
  function headlessCleanup(
268
272
  run,
269
- { writeErr, hasActiveTasks, usageLedgerCleanup, daemonRuntimeCleanup, memoryRuntimeCleanup }
273
+ { writeErr, hasActiveTasks, usageLedgerCleanup, sessionStoreDrain, daemonRuntimeCleanup, memoryRuntimeCleanup }
270
274
  ) {
271
275
  let cleanupPromise = null;
272
276
  const shutdown = async (reason) => {
@@ -289,6 +293,13 @@ function headlessCleanup(
289
293
  await drainAgentTrace();
290
294
  }
291
295
  });
296
+ // The session store's process-exit hook flushes any save still pending
297
+ // at exit to the data dir resolved AT THAT MOMENT — by then the boundary
298
+ // has restored the host environment, so a late write would land in the
299
+ // host's session catalog. Flush while the pristine data dir is current.
300
+ await attemptShutdownStep(errors, async () => {
301
+ if (boundary) await sessionStoreDrain();
302
+ });
292
303
  // The usage ledger lives inside the pristine root. Its open SQLite
293
304
  // handle blocks the root removal below on Windows (EBUSY) for the whole
294
305
  // rmSync retry budget, so release it once the last usage row is in.
@@ -316,6 +327,11 @@ function headlessCleanup(
316
327
  };
317
328
  }
318
329
 
330
+ async function drainHeadlessSessionStore() {
331
+ const { drainSessionStore } = await import('./runtime/agent/orchestrator/session/store.mjs');
332
+ drainSessionStore();
333
+ }
334
+
319
335
  // Runs one shutdown step, collecting its failure so the remaining steps still
320
336
  // run; true when the step succeeded.
321
337
  async function attemptShutdownStep(errors, step) {
@@ -140,8 +140,8 @@ export async function runHeadlessRole({
140
140
  } = {}) {
141
141
  const cleanAgent = clean(agent);
142
142
  const cleanMessage = clean(message);
143
- // Classic headless surface: web search and memory tools start OFF
144
- // and opt back in per run (--web-search / --memory). An explicit
143
+ // Web search and memory start OFF. This call can pass webSearch or memory;
144
+ // exec accepts --web-search and rejects --memory. An explicit
145
145
  // MIXDOG_FEATURE_* value from the caller environment always wins.
146
146
  for (const [key, enabled] of [
147
147
  ['MIXDOG_FEATURE_WEB_SEARCH', webSearch],
package/src/help.mjs CHANGED
@@ -17,6 +17,8 @@ const HELP_LINES = [
17
17
  ' --web-search enable web search and page retrieval for headless exec',
18
18
  ' --json emit headless exec events as JSONL',
19
19
  ' --workflow <name> start with the given workflow active',
20
+ ' --worktree [name] run this session in a new git worktree (optionally named)',
21
+ ' --no-worktree run this session on the current branch in the project folder',
20
22
  ' --readonly read-only tool surface',
21
23
  ' --remote enable remote/channel mode for this session',
22
24
  ' --onboarding re-run the first-run setup wizard',