mixdog 0.9.151 → 0.9.152
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.
- package/README.md +110 -68
- package/package.json +3 -2
- package/scripts/tool-stress.mjs +0 -2
- package/src/defaults/skills/setup/SKILL.md +18 -27
- package/src/headless-exec.mjs +3 -10
- package/src/headless-exec.test.mjs +2 -7
- package/src/runtime/agent/orchestrator/config.mjs +6 -66
- package/src/runtime/agent/orchestrator/context/collect-skills.test.mjs +153 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +49 -45
- package/src/runtime/agent/orchestrator/mcp/client.mjs +242 -15
- package/src/runtime/agent/orchestrator/mcp/features.test.mjs +66 -0
- package/src/runtime/agent/orchestrator/mcp/security.test.mjs +36 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +54 -33
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +3 -8
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +10 -2
- package/src/runtime/agent/orchestrator/providers/lib/provider-replay.mjs +50 -0
- package/src/runtime/agent/orchestrator/providers/lib/sse-framing.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +3 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +25 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +35 -4
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +22 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +0 -2
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +4 -7
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/provider-replay.test.mjs +235 -0
- package/src/runtime/agent/orchestrator/providers/sse-framing.test.mjs +719 -0
- package/src/runtime/agent/orchestrator/providers/stream-json-pool.mjs +399 -39
- package/src/runtime/agent/orchestrator/providers/stream-json-worker.mjs +26 -0
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +14 -4
- package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +24 -1
- package/src/runtime/agent/orchestrator/session/compaction-read-reset.test.mjs +161 -0
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +14 -4
- package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +31 -18
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/message-sanitize.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +556 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.test.mjs +457 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +105 -186
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +115 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +23 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool-cwd-env.test.mjs +14 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -10
- package/src/runtime/agent/orchestrator/tools/builtin/find-search-budget.test.mjs +30 -14
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +15 -4
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +73 -15
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.test.mjs +76 -2
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +24 -683
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +64 -72
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-runner.mjs +2 -5
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-transport.mjs +75 -0
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-transport.test.mjs +24 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +24 -5
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.test.mjs +44 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +12 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +35 -21
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +28 -13
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.test.mjs +54 -0
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +11 -11
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +11 -11
- package/src/runtime/browser-bridge/client.mjs +103 -0
- package/src/runtime/browser-bridge/tool-defs.mjs +42 -0
- package/src/runtime/computer-bridge/client.mjs +101 -0
- package/src/runtime/computer-bridge/tool-defs.mjs +53 -0
- package/src/runtime/media/store.mjs +18 -8
- package/src/runtime/media/store.test.mjs +14 -0
- package/src/runtime/memory/index.mjs +1 -1
- package/src/runtime/memory/lib/transcript-ingest.mjs +8 -6
- package/src/runtime/memory/lib/transcript-ingest.test.mjs +52 -0
- package/src/runtime/shared/child-spawn-gate.mjs +17 -0
- package/src/runtime/shared/child-spawn-remote.mjs +69 -7
- package/src/runtime/shared/child-spawn-remote.test.mjs +124 -0
- package/src/runtime/shared/pristine-execution-contract.json +2 -1
- package/src/runtime/shared/provider-api-key.mjs +1 -0
- package/src/runtime/shared/session-runtime-health.mjs +91 -0
- package/src/runtime/shared/session-runtime-health.test.mjs +53 -0
- package/src/runtime/shared/skill-document.mjs +86 -0
- package/src/runtime/shared/skill-document.test.mjs +81 -0
- package/src/runtime/shared/tool-surface.mjs +18 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +1 -0
- package/src/runtime/shared/turn-snapshot.mjs +32 -9
- package/src/runtime/shared/user-cwd.mjs +33 -14
- package/src/runtime/shared/user-cwd.test.mjs +43 -0
- package/src/session-runtime/cwd-plugins.mjs +26 -26
- package/src/session-runtime/cwd-plugins.test.mjs +75 -0
- package/src/session-runtime/cwd-tool-routing.test.mjs +5 -0
- package/src/session-runtime/global-extensions.mjs +26 -0
- package/src/session-runtime/global-extensions.test.mjs +28 -0
- package/src/session-runtime/goal-runtime.mjs +721 -0
- package/src/session-runtime/goal-runtime.test.mjs +108 -0
- package/src/session-runtime/lifecycle-api.mjs +18 -4
- package/src/session-runtime/lifecycle-api.test.mjs +21 -0
- package/src/session-runtime/mcp-glue.mjs +49 -47
- package/src/session-runtime/plugin-mcp-standard.test.mjs +177 -0
- package/src/session-runtime/plugin-mcp.mjs +96 -22
- package/src/session-runtime/prewarm.mjs +1 -10
- package/src/session-runtime/resource-api-global.test.mjs +69 -0
- package/src/session-runtime/resource-api.mjs +173 -58
- package/src/session-runtime/runtime-core.mjs +148 -20
- package/src/session-runtime/runtime-tunables.mjs +6 -8
- package/src/session-runtime/session-turn-api.mjs +22 -11
- package/src/session-runtime/skills-api.mjs +79 -25
- package/src/session-runtime/skills-api.test.mjs +99 -0
- package/src/session-runtime/tool-catalog-schema.mjs +0 -5
- package/src/session-runtime/tool-catalog.mjs +4 -13
- package/src/session-runtime/tool-policy-surface.test.mjs +33 -11
- package/src/session-runtime/tool-surface.mjs +12 -0
- package/src/standalone/agent-dispatch-broker.mjs +5 -9
- package/src/standalone/agent-tool/notify.mjs +6 -8
- package/src/standalone/agent-tool/notify.test.mjs +37 -0
- package/src/standalone/daemon.mjs +31 -15
- package/src/standalone/hook-bus/config.mjs +1 -0
- package/src/standalone/plugin-admin.mjs +17 -0
- package/src/standalone/plugin-admin.test.mjs +7 -0
- package/src/standalone/provider-admin.mjs +1 -0
- package/src/standalone/session-protocol.mjs +5 -0
- package/src/standalone/session-runtime-agent-control-client.mjs +133 -0
- package/src/standalone/session-runtime-agent-control-client.test.mjs +71 -0
- package/src/standalone/session-runtime-dispatch-cancel.test.mjs +139 -0
- package/src/standalone/session-runtime-host-factory.mjs +17 -0
- package/src/standalone/session-runtime-host-factory.test.mjs +31 -0
- package/src/standalone/session-runtime-host-health.test.mjs +5 -0
- package/src/standalone/session-runtime-host.mjs +696 -58
- package/src/standalone/session-runtime-inline-host.mjs +351 -0
- package/src/standalone/session-runtime-inline-host.test.mjs +83 -0
- package/src/standalone/session-runtime-provider-cooldown.mjs +78 -0
- package/src/standalone/session-runtime-provider-cooldown.test.mjs +80 -0
- package/src/standalone/session-runtime-shard-host.test.mjs +569 -0
- package/src/standalone/session-runtime-shard-router.mjs +149 -0
- package/src/standalone/session-runtime-shard-router.test.mjs +101 -0
- package/src/standalone/session-runtime-worker.mjs +476 -18
- package/src/standalone/session-service.mjs +81 -6
- package/src/tui/app/app-view.jsx +1 -0
- package/src/tui/app/core-memory-picker.mjs +2 -0
- package/src/tui/app/extension-pickers.mjs +1 -1
- package/src/tui/app/maintenance-pickers.mjs +3 -3
- package/src/tui/app/model-options.mjs +2 -0
- package/src/tui/app/model-picker.mjs +14 -4
- package/src/tui/app/panel-handoff.test.mjs +311 -0
- package/src/tui/app/project-picker.mjs +1 -0
- package/src/tui/app/route-pickers.mjs +21 -6
- package/src/tui/app/settings-picker.mjs +26 -3
- package/src/tui/app/slash-commands.mjs +1 -0
- package/src/tui/app/slash-dispatch.mjs +73 -22
- package/src/tui/app/theme-effort-pickers.mjs +7 -2
- package/src/tui/components/Picker.jsx +10 -1
- package/src/tui/dist/index.mjs +163 -44
- package/src/tui/session/context-state.mjs +1 -0
- package/src/tui/session/goal-continuation.mjs +110 -0
- package/src/tui/session/goal-continuation.test.mjs +84 -0
- package/src/tui/session/queue-helpers.mjs +5 -2
- package/src/tui/session/session-action-surface.test.mjs +108 -0
- package/src/tui/session/session-api-ext.mjs +39 -8
- package/src/tui/session/session-api.mjs +58 -0
- package/src/tui/session/session-flow.mjs +6 -0
- package/src/tui/session/turn.mjs +1 -0
- package/src/tui/session-local.mjs +15 -1
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +0 -301
package/README.md
CHANGED
|
@@ -1,20 +1,35 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Mixdog
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/mixdog)
|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
## Better results. Less cost. More work.
|
|
8
|
+
|
|
9
|
+
Mixdog is an efficiency-first AI coding harness designed to deliver equal or
|
|
10
|
+
better performance with less context, time, and cost—so you can complete more
|
|
11
|
+
work within the same API budget or subscription quota.
|
|
12
|
+
|
|
13
|
+
With simple setup and an intuitive UX, Mixdog makes powerful orchestration,
|
|
14
|
+
parallel tasks, and seamless work across terminal, desktop, and web accessible
|
|
15
|
+
to everyone—from beginners to experts.
|
|
16
|
+
|
|
17
|
+
**The easiest way to get more out of every coding model.**
|
|
9
18
|
|
|
10
19
|
## Get started
|
|
11
20
|
|
|
12
|
-
###
|
|
21
|
+
### Desktop
|
|
13
22
|
|
|
14
|
-
|
|
23
|
+
| Platform | Download |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| Windows x64 | [Installer](https://github.com/tribgames/mixdog/releases/latest/download/mixdog-desktop-win-x64.exe) |
|
|
26
|
+
| macOS Apple silicon | [DMG](https://github.com/tribgames/mixdog/releases/latest/download/mixdog-desktop-mac-arm64.dmg) |
|
|
27
|
+
| macOS Intel | [DMG](https://github.com/tribgames/mixdog/releases/latest/download/mixdog-desktop-mac-x64.dmg) |
|
|
28
|
+
| Linux x86_64 | [AppImage](https://github.com/tribgames/mixdog/releases/latest/download/mixdog-desktop-linux-x86_64.AppImage) |
|
|
29
|
+
| Linux arm64 | [AppImage](https://github.com/tribgames/mixdog/releases/latest/download/mixdog-desktop-linux-arm64.AppImage) |
|
|
15
30
|
|
|
16
|
-
|
|
17
|
-
security warning
|
|
31
|
+
Desktop packages are currently unsigned, so Windows SmartScreen or macOS
|
|
32
|
+
Gatekeeper may show a security warning.
|
|
18
33
|
|
|
19
34
|
### CLI
|
|
20
35
|
|
|
@@ -28,28 +43,68 @@ mixdog
|
|
|
28
43
|
First run guides you through provider authentication, model selection, and
|
|
29
44
|
workflow setup.
|
|
30
45
|
|
|
46
|
+
## Benchmarks
|
|
47
|
+
|
|
48
|
+
Terminal-Bench 2.1 — same model, same 89 tasks, same official verifier, with
|
|
49
|
+
only the harness changed. Against the native CLI of each model family, Mixdog
|
|
50
|
+
scores higher while spending less to get there.
|
|
51
|
+
|
|
52
|
+
### GPT-5.6 Sol xhigh — Mixdog vs Codex CLI
|
|
53
|
+
|
|
54
|
+

|
|
55
|
+
|
|
56
|
+
- **86.5%** (385/445) vs Codex CLI's **84.3%** (75/89)
|
|
57
|
+
- **42%** lower priced cost — $0.641 vs $1.096 per trial
|
|
58
|
+
- **45%** smaller median final context — 18.5k vs 33.5k tokens
|
|
59
|
+
- **1.11×** faster — 339s vs 378s per trial
|
|
60
|
+
|
|
61
|
+
### Claude Opus 5 — Mixdog vs Claude Code
|
|
62
|
+
|
|
63
|
+

|
|
64
|
+
|
|
65
|
+
- **79/89** vs Claude Code's **77/89**
|
|
66
|
+
- **19%** lower priced cost — $104.29 vs $129.21 per run
|
|
67
|
+
- **28%** smaller median final context — 27.6k vs 38.2k tokens
|
|
68
|
+
- **1.15×** faster
|
|
69
|
+
|
|
70
|
+
Every run uses the official Harbor verifier, fast mode off, a 272k context
|
|
71
|
+
window, and zero retries. The Mixdog Sol run follows the protocol the official
|
|
72
|
+
Terminal-Bench leaderboard requires — all 89 tasks repeated five times (`k=5`,
|
|
73
|
+
445 trials); the Codex CLI baseline and both Opus-side runs are single passes
|
|
74
|
+
(`k=1`, 89 trials each).
|
|
75
|
+
|
|
76
|
+
The leaderboard is not accepting community submissions, so every run here ships
|
|
77
|
+
its raw artifacts instead — Harbor verdicts, official verifier output, pinned
|
|
78
|
+
task checksums, and the usage snapshots behind every cost figure — alongside
|
|
79
|
+
the harness, presets, and metric scripts that recompute each number above:
|
|
80
|
+
[`benchmarks/terminal-bench-2.1/`](benchmarks/terminal-bench-2.1/).
|
|
81
|
+
|
|
31
82
|
## Highlights
|
|
32
83
|
|
|
33
84
|
- **Multi-provider routing** — assign different providers and models by role.
|
|
85
|
+
- **Shared live sessions** — move between the TUI, desktop windows, and paired
|
|
86
|
+
browsers without starting a second copy of the session.
|
|
34
87
|
- **Efficient context** — cache-aware prompts, compaction, resumable sessions,
|
|
35
88
|
and focused repo-native tools.
|
|
36
89
|
- **Complete coding surface** — read, search, edit, test, review, web search,
|
|
37
90
|
MCP, skills, hooks, and plugins.
|
|
38
91
|
- **Local memory** — semantic and lexical recall with project-scoped context
|
|
39
92
|
and multilingual retrieval.
|
|
40
|
-
- **
|
|
41
|
-
|
|
42
|
-
- **
|
|
43
|
-
explorer, Studio, automation, and settings in one
|
|
93
|
+
- **Encrypted remote access** — pair the installable web app with Desktop and
|
|
94
|
+
use Mixdog from a browser or phone over authenticated E2EE.
|
|
95
|
+
- **Desktop coding app** — agent panes, Monaco editor, Git, terminals, file
|
|
96
|
+
explorer, Studio, automation, voice input, and settings in one app.
|
|
44
97
|
|
|
45
98
|
## Providers
|
|
46
99
|
|
|
47
100
|
Mixdog supports subscription OAuth and API-key routes, including:
|
|
48
101
|
|
|
49
|
-
- Anthropic and Claude
|
|
50
|
-
- OpenAI and ChatGPT/Codex
|
|
51
|
-
- Google Gemini
|
|
52
|
-
- xAI Grok
|
|
102
|
+
- Anthropic API keys and Claude account OAuth
|
|
103
|
+
- OpenAI API keys and ChatGPT/Codex account OAuth
|
|
104
|
+
- Google Gemini and Antigravity OAuth
|
|
105
|
+
- xAI API keys and Grok account OAuth
|
|
106
|
+
- OpenRouter API keys and its unified model catalog
|
|
107
|
+
- Experimental Cursor account OAuth
|
|
53
108
|
- DeepSeek and OpenCode Go
|
|
54
109
|
- OpenAI-compatible APIs
|
|
55
110
|
- Ollama and LM Studio
|
|
@@ -107,40 +162,57 @@ stdout; diagnostics remain on stderr.
|
|
|
107
162
|
## TUI commands
|
|
108
163
|
|
|
109
164
|
```text
|
|
110
|
-
/
|
|
111
|
-
/
|
|
112
|
-
/
|
|
113
|
-
/
|
|
114
|
-
/
|
|
115
|
-
/
|
|
116
|
-
/
|
|
117
|
-
/
|
|
118
|
-
/
|
|
119
|
-
/
|
|
120
|
-
/
|
|
121
|
-
/
|
|
122
|
-
/
|
|
123
|
-
/
|
|
165
|
+
/clear start a fresh chat
|
|
166
|
+
/project switch the current project
|
|
167
|
+
/resume resume a saved chat
|
|
168
|
+
/compact compact older conversation context
|
|
169
|
+
/autoclear manage idle-time context clearing
|
|
170
|
+
/context inspect the current context surface
|
|
171
|
+
/usage show provider quota and balance
|
|
172
|
+
/providers configure authentication and local endpoints
|
|
173
|
+
/model choose the main provider and model
|
|
174
|
+
/websearch choose the web search route
|
|
175
|
+
/workflow choose the active workflow
|
|
176
|
+
/agents inspect agents and model overrides
|
|
177
|
+
/effort set reasoning effort
|
|
178
|
+
/fast toggle supported model fast mode
|
|
179
|
+
/OutputStyle choose the Lead response style
|
|
180
|
+
/theme change the TUI color theme
|
|
181
|
+
/memory inspect and edit core memory
|
|
182
|
+
/mcp manage MCP servers and tools
|
|
183
|
+
/skills choose a skill for the next request
|
|
184
|
+
/plugins manage local plugin integrations
|
|
185
|
+
/hooks manage before-tool hooks and events
|
|
186
|
+
/setting open runtime settings
|
|
187
|
+
/profile set your title and response language
|
|
188
|
+
/update check for updates
|
|
189
|
+
/doctor diagnose installation health
|
|
190
|
+
/quit quit the TUI
|
|
124
191
|
```
|
|
125
192
|
|
|
126
193
|
Workflows and agents are Markdown definition packs (`WORKFLOW.md`, `AGENT.md`).
|
|
127
194
|
Built-in packs ship with Mixdog; custom packs live under the Mixdog data
|
|
128
195
|
directory.
|
|
129
196
|
|
|
130
|
-
##
|
|
197
|
+
## Desktop app
|
|
131
198
|
|
|
132
|
-
Mixdog Desktop runs the same agent runtime as the CLI
|
|
133
|
-
workbench:
|
|
199
|
+
Mixdog Desktop runs the same agent runtime as the CLI:
|
|
134
200
|
|
|
135
201
|
- Split panes for parallel, independently routed agent sessions
|
|
202
|
+
- Live session handoff between the TUI, desktop windows, and paired browsers
|
|
136
203
|
- Monaco editor, LSP integration, diffs, and turn-by-turn edit review
|
|
137
204
|
- Git staging, commits, branches, and generated commit messages
|
|
138
|
-
-
|
|
139
|
-
- Integrated
|
|
205
|
+
- File explorer with previews, thumbnails, search, and drag-and-drop
|
|
206
|
+
- Integrated terminal tabs using the local system shell
|
|
140
207
|
- Image and video generation Studio with a persistent local gallery
|
|
141
|
-
- Visual workflow, agent, and
|
|
208
|
+
- Visual workflow, agent, schedule, and webhook editors
|
|
209
|
+
- Voice dictation with an optional local transcription runtime
|
|
142
210
|
- Provider setup, usage, git identity, and remote pairing settings
|
|
143
211
|
|
|
212
|
+
The paired remote web app is installable on desktop and mobile browsers. It
|
|
213
|
+
uses an authenticated end-to-end encrypted connection before session state,
|
|
214
|
+
terminal data, files, or operation requests cross the relay.
|
|
215
|
+
|
|
144
216
|
For desktop development:
|
|
145
217
|
|
|
146
218
|
```bash
|
|
@@ -148,37 +220,6 @@ cd apps/desktop
|
|
|
148
220
|
npm run dev
|
|
149
221
|
```
|
|
150
222
|
|
|
151
|
-
## Terminal-Bench 2.1
|
|
152
|
-
|
|
153
|
-
Head-to-head runs against other agent CLIs on the same 89 tasks, holding the
|
|
154
|
-
model fixed and changing only the harness. Every run uses the official Harbor
|
|
155
|
-
verifier, fast mode off, a 272k context window, and zero retries.
|
|
156
|
-
|
|
157
|
-
**GPT-5.6 Sol xhigh — Mixdog vs Codex CLI**
|
|
158
|
-
|
|
159
|
-
- Score: **86.5%** (385/445) vs Codex CLI's **84.3%** (75/89)
|
|
160
|
-
- **1.11×** faster per trial (339s vs 378s)
|
|
161
|
-
- **42%** lower priced cost ($0.641 vs $1.096 per trial)
|
|
162
|
-
- **45%** smaller median final context (18.5k vs 33.5k tokens)
|
|
163
|
-
|
|
164
|
-
**Claude Opus 5 — Mixdog vs Claude Code**
|
|
165
|
-
|
|
166
|
-
- Score: **79/89** vs Claude Code's **77/89**
|
|
167
|
-
- **1.15×** faster and **19%** lower priced cost ($104.29 vs $129.21 per run)
|
|
168
|
-
- **28%** smaller median final context (27.6k vs 38.2k tokens)
|
|
169
|
-
|
|
170
|
-
Measurement: the Mixdog Sol run follows the same protocol the official
|
|
171
|
-
Terminal-Bench leaderboard requires — all 89 tasks repeated five times
|
|
172
|
-
(`k=5`, 445 trials), scored by the official Harbor verifier. The Codex CLI
|
|
173
|
-
baseline and both Opus-side runs are single passes (`k=1`, 89 trials each).
|
|
174
|
-
|
|
175
|
-
The official leaderboard is not accepting community submissions, so every run
|
|
176
|
-
here ships its raw artifacts instead — Harbor verdicts, official verifier
|
|
177
|
-
output, pinned task checksums, and the usage snapshots behind every cost
|
|
178
|
-
figure — alongside the harness, presets, and metric scripts that recompute
|
|
179
|
-
each number above:
|
|
180
|
-
[`benchmarks/terminal-bench-2.1/`](benchmarks/terminal-bench-2.1/).
|
|
181
|
-
|
|
182
223
|
## Data and configuration
|
|
183
224
|
|
|
184
225
|
Mixdog uses `~/.mixdog` as its home root and `~/.mixdog/data` for runtime data
|
|
@@ -213,10 +254,11 @@ Main directories:
|
|
|
213
254
|
|
|
214
255
|
```text
|
|
215
256
|
src/ CLI, TUI, runtime, workflows, agents, and rules
|
|
216
|
-
apps/desktop/
|
|
217
|
-
apps/relay/ remote web relay
|
|
257
|
+
apps/desktop/ cross-platform desktop app
|
|
258
|
+
apps/relay/ remote web app and relay
|
|
218
259
|
native/ native process, search, patch, and support binaries
|
|
219
260
|
scripts/ tests, diagnostics, benchmarks, and build scripts
|
|
261
|
+
benchmarks/ reproducible benchmark harnesses, results, and raw artifacts
|
|
220
262
|
vendor/ vendored runtime components
|
|
221
263
|
```
|
|
222
264
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mixdog",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.152",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Standalone mixdog coding-agent CLI/TUI workspace.",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"test:native-edit-wire": "node scripts/native-edit-wire-test.mjs",
|
|
67
67
|
"test:release-critical": "npm run test:release-assets && npm run smoke:patch && npm run test:providers",
|
|
68
68
|
"test:spec-advisory": "node scripts/advisory-spec-test.mjs && npm run test:spec-advisory --prefix apps/desktop",
|
|
69
|
-
"test:session-transport": "node --test scripts/session-transport-test.mjs scripts/daemon-bootstrap-test.mjs",
|
|
69
|
+
"test:session-transport": "node --test scripts/session-transport-test.mjs scripts/daemon-bootstrap-test.mjs src/runtime/shared/child-spawn-remote.test.mjs src/standalone/session-runtime-agent-control-client.test.mjs src/standalone/session-runtime-dispatch-cancel.test.mjs src/standalone/session-runtime-host-factory.test.mjs src/standalone/session-runtime-inline-host.test.mjs src/standalone/session-runtime-provider-cooldown.test.mjs src/standalone/session-runtime-shard-host.test.mjs src/standalone/session-runtime-shard-router.test.mjs",
|
|
70
70
|
"test:session": "node --test scripts/runtime-turn-contract-test.mjs scripts/session-save-fault-store-test.mjs scripts/turn-review-revert-test.mjs src/runtime/shared/tool-surface.test.mjs",
|
|
71
71
|
"test:media": "node --test src/runtime/media/store.test.mjs src/runtime/media/renditions.test.mjs src/runtime/media/adapters/codex-image.test.mjs",
|
|
72
72
|
"failures": "node scripts/tool-failures.mjs",
|
|
@@ -139,6 +139,7 @@
|
|
|
139
139
|
"undici": "^8.5.0",
|
|
140
140
|
"wrap-ansi": "^10.0.0",
|
|
141
141
|
"ws": "^8.21.0",
|
|
142
|
+
"yaml": "^2.9.0",
|
|
142
143
|
"zod": "^3.25.76"
|
|
143
144
|
},
|
|
144
145
|
"overrides": {
|
package/scripts/tool-stress.mjs
CHANGED
|
@@ -17,7 +17,6 @@ import { executePatchTool } from '../src/runtime/agent/orchestrator/tools/patch.
|
|
|
17
17
|
import { normalizeToolEnvelope } from '../src/runtime/agent/orchestrator/session/tool-envelope.mjs';
|
|
18
18
|
import { warmNativeSpawnServer } from '../src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs';
|
|
19
19
|
import { warmNativeSearchServer } from '../src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs';
|
|
20
|
-
import { prewarmFindEnumeration } from '../src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs';
|
|
21
20
|
|
|
22
21
|
if (!process.argv.includes('--unsafe-live')) {
|
|
23
22
|
console.error('Refusing high-impact tool stress without --unsafe-live; run `node scripts/tool-search-bench.mjs` for safe exploration diagnostics.');
|
|
@@ -66,7 +65,6 @@ try {
|
|
|
66
65
|
await Promise.all([
|
|
67
66
|
warmNativeSpawnServer(),
|
|
68
67
|
warmNativeSearchServer(),
|
|
69
|
-
prewarmFindEnumeration(root),
|
|
70
68
|
]);
|
|
71
69
|
prewarmMs = Date.now() - prewarmStarted;
|
|
72
70
|
// ── Phase A+C: concurrent multi-session waves (search/read/graph/shell +
|
|
@@ -15,7 +15,7 @@ description: Use this skill only to inspect or modify a Mixdog user's persisted
|
|
|
15
15
|
|
|
16
16
|
- `<mixdogData>` 해석 순서: `MIXDOG_DATA_DIR` → `<MIXDOG_HOME|~/.mixdog>/data` (`src/runtime/shared/plugin-paths.mjs`)
|
|
17
17
|
- 통합 config: `<mixdogData>/mixdog-config.json`
|
|
18
|
-
- 프로젝트 config: `<cwd>/.
|
|
18
|
+
- 프로젝트 config: `<cwd>/.mixdog/hooks.json`
|
|
19
19
|
- TUI 명령 목록: `src/tui/app/slash-commands.mjs`
|
|
20
20
|
- TUI 설정 허브: `/setting` (별칭 `/settings`, `/config`) → `src/tui/app/settings-picker.mjs`
|
|
21
21
|
- Desktop 설정: `Ctrl+,` → General / Context / Output style / Providers / Git / Skills / MCP / Plugins / Hooks / Connection / System / Shortcuts / About
|
|
@@ -111,7 +111,8 @@ API 키·토큰·OAuth 자격은 config에 쓰지 않는다.
|
|
|
111
111
|
1. **확인**: Desktop **Settings → General → Web search**, TUI `/setting → Web search`.
|
|
112
112
|
2. **변경**: toggle → `setWebSearchEnabled()`.
|
|
113
113
|
3. **저장**: `agent.modules.webSearch.enabled`.
|
|
114
|
-
4.
|
|
114
|
+
4. **검색 범위**: 전역 `<mixdogData>/skills/`와 활성 Plugin skill만 사용한다. Project `.mixdog/skills/`는 읽지 않는다.
|
|
115
|
+
5. **검증**: 열린 runtime과 다음 세션의 tool surface.
|
|
115
116
|
|
|
116
117
|
### reasoning effort / Fast
|
|
117
118
|
|
|
@@ -263,18 +264,15 @@ TUI·Desktop interval 편집 UI는 없다.
|
|
|
263
264
|
|
|
264
265
|
### MCP 추가
|
|
265
266
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
1. **확인**: `/mcp` 또는 Desktop **Settings → MCP**, `mcpStatus()`, `<cwd>/.mcp.json`.
|
|
267
|
+
1. **확인**: `/mcp` 또는 Desktop **Settings → MCP**, `mcpStatus()`, `agent.mcpServers`.
|
|
269
268
|
2. **변경**:
|
|
270
|
-
-
|
|
271
|
-
-
|
|
269
|
+
- Desktop: **Settings → MCP → Add**
|
|
270
|
+
- 디스크: `agent.mcpServers.<name>` 편집
|
|
272
271
|
- API 자동화: `addMcpServer()`, `removeMcpServer()`, `reconnectMcp()`
|
|
273
272
|
3. **transport**:
|
|
274
273
|
- stdio: `type`, `command`, `args`, `cwd`, `env`
|
|
275
274
|
- URL: `http`, `sse`, `ws`와 `url`, 선택 `headers`
|
|
276
|
-
4.
|
|
277
|
-
5. **검증**: `connected`, `toolCount`, `source`, `transport`, `error`.
|
|
275
|
+
4. **검증**: `connected`, `toolCount`, `transport`, `error`.
|
|
278
276
|
|
|
279
277
|
파일을 직접 편집했다면 mixdog 재시작이 기본 적용 경로다.
|
|
280
278
|
|
|
@@ -282,17 +280,15 @@ UI에는 서버 추가·삭제·전체 재연결 액션이 없다.
|
|
|
282
280
|
|
|
283
281
|
TUI `/mcp`와 Desktop MCP 모두 서버별 toggle을 지원하며 live connection과 세션 tool surface를 재동기화한다.
|
|
284
282
|
|
|
285
|
-
-
|
|
286
|
-
-
|
|
287
|
-
- 즉, 전역 config 서버를 toggle해도 전역 `agent.mcpServers.<name>.enabled`를 바꾸지 않는다.
|
|
283
|
+
- 서버 정의는 유지하고 `agent.mcpServers.<name>.enabled`를 전역으로 변경한다.
|
|
284
|
+
- Project `.mcp.json`과 Project별 override는 읽지 않는다.
|
|
288
285
|
- turn 실행 중 toggle은 turn 종료 경계에서 세션을 재생성한다.
|
|
289
286
|
|
|
290
287
|
### MCP 진단
|
|
291
288
|
|
|
292
|
-
1. `/mcp`의
|
|
293
|
-
2.
|
|
294
|
-
3.
|
|
295
|
-
4. `connected:true`와 기대 tool 노출로 검증한다.
|
|
289
|
+
1. `/mcp`의 transport/error를 먼저 읽는다.
|
|
290
|
+
2. stdio는 command·args·cwd·자식 env, URL transport는 scheme·endpoint·headers·방화벽을 확인한다.
|
|
291
|
+
3. `connected:true`와 기대 tool 노출로 검증한다.
|
|
296
292
|
|
|
297
293
|
### Skills enable / disable
|
|
298
294
|
|
|
@@ -317,11 +313,11 @@ UI 생성 액션은 없다.
|
|
|
317
313
|
|
|
318
314
|
1. **확인**: `/plugins` 또는 Desktop **Settings → Plugins**.
|
|
319
315
|
2. **추가**: Git URL, `owner/repo`, 기존 local path → `addPlugin()`.
|
|
320
|
-
3. **관리**: update/metadata refresh, plugin MCP enable/reconfigure, root/MCP name 복사, uninstall.
|
|
316
|
+
3. **관리**: 전역 enable/disable, update/metadata refresh, plugin MCP enable/reconfigure, root/MCP name 복사, uninstall.
|
|
321
317
|
4. **저장**: `<mixdogData>/plugins/registry.json`; managed Git checkout은 `<mixdogData>/plugins/installed/`.
|
|
322
318
|
5. **검증**: `pluginsStatus()`, plugin skill 수, MCP server 노출.
|
|
323
319
|
|
|
324
|
-
|
|
320
|
+
Plugin toggle은 해당 Plugin의 Skills와 MCP를 전역으로 함께 활성화/비활성화한다. 개별 MCP와 Skill은 각 화면에서도 관리할 수 있다.
|
|
325
321
|
|
|
326
322
|
### Hooks
|
|
327
323
|
|
|
@@ -380,8 +376,8 @@ Discord/Telegram messaging은 제거됐다. schedules/webhooks 자동화와 voic
|
|
|
380
376
|
|
|
381
377
|
1. **확인**: 상태줄 cwd, `/project`, Desktop rail **Projects**.
|
|
382
378
|
2. **변경**: `/project [path]` 또는 picker. TUI picker는 등록·생성·rename도 지원한다.
|
|
383
|
-
3. **적용**: cwd
|
|
384
|
-
4. **검증**: cwd
|
|
379
|
+
3. **적용**: cwd 변경은 실행 경로만 바꾸며 전역 Skills·Plugins·MCP 상태는 유지한다.
|
|
380
|
+
4. **검증**: cwd와 실행 경로.
|
|
385
381
|
|
|
386
382
|
### Git (Desktop 전용)
|
|
387
383
|
|
|
@@ -438,11 +434,6 @@ Desktop과 현재 runtime에서 소비되지 않는 아래 key는 사용자 옵
|
|
|
438
434
|
"cwd": "<project-subdir>",
|
|
439
435
|
"env": {}
|
|
440
436
|
}
|
|
441
|
-
},
|
|
442
|
-
"mcpProjectOverrides": {
|
|
443
|
-
"<normalized-cwd>": {
|
|
444
|
-
"<name>": { "enabled": false }
|
|
445
|
-
}
|
|
446
437
|
}
|
|
447
438
|
}
|
|
448
439
|
}
|
|
@@ -466,8 +457,8 @@ URL transport는 `type` + `url` + 선택 `headers`를 사용한다.
|
|
|
466
457
|
|
|
467
458
|
### 우선순위와 금지
|
|
468
459
|
|
|
469
|
-
- MCP
|
|
470
|
-
- Skill 이름 충돌:
|
|
460
|
+
- MCP는 전역 `agent.mcpServers`만 사용한다.
|
|
461
|
+
- Skill 이름 충돌: global > plugin
|
|
471
462
|
- `Mixdog.md` 자동 프롬프트 로드는 없다. skill/core memory를 사용한다.
|
|
472
463
|
- 확인되지 않은 key는 추측하지 말고 TODO로 남긴다.
|
|
473
464
|
- UI에 없는 runtime API를 사용자 UI처럼 설명하지 않는다.
|
package/src/headless-exec.mjs
CHANGED
|
@@ -23,17 +23,10 @@ function clean(value) {
|
|
|
23
23
|
|
|
24
24
|
export async function prewarmHeadlessSearch(cwd, {
|
|
25
25
|
loadNativeSearch = () => import('./runtime/agent/orchestrator/tools/builtin/native-search-client.mjs'),
|
|
26
|
-
loadListTool = () => import('./runtime/agent/orchestrator/tools/builtin/list-tool.mjs'),
|
|
27
26
|
} = {}) {
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
loadListTool(),
|
|
32
|
-
]);
|
|
33
|
-
await Promise.all([
|
|
34
|
-
nativeSearch.warmNativeSearchServer(),
|
|
35
|
-
listTool.prewarmFindEnumeration(root),
|
|
36
|
-
]);
|
|
27
|
+
void cwd;
|
|
28
|
+
const nativeSearch = await loadNativeSearch();
|
|
29
|
+
await nativeSearch.warmNativeSearchServer();
|
|
37
30
|
}
|
|
38
31
|
|
|
39
32
|
function nonNegativeNumber(value) {
|
|
@@ -9,7 +9,7 @@ import { prewarmHeadlessSearch, runHeadlessExec } from './headless-exec.mjs';
|
|
|
9
9
|
import { resolveCursorOAuthAccessToken } from './runtime/agent/orchestrator/providers/cursor-auth.mjs';
|
|
10
10
|
import { createPristineExecutionBoundary } from './runtime/shared/pristine-execution.mjs';
|
|
11
11
|
|
|
12
|
-
test('headless search prewarm starts the native server
|
|
12
|
+
test('headless search prewarm starts only the canonical native server', async () => {
|
|
13
13
|
const calls = [];
|
|
14
14
|
await prewarmHeadlessSearch('/app/project', {
|
|
15
15
|
loadNativeSearch: async () => ({
|
|
@@ -18,13 +18,8 @@ test('headless search prewarm starts the native server and Project inventory tog
|
|
|
18
18
|
return true;
|
|
19
19
|
},
|
|
20
20
|
}),
|
|
21
|
-
loadListTool: async () => ({
|
|
22
|
-
async prewarmFindEnumeration(root) {
|
|
23
|
-
calls.push(`index:${root}`);
|
|
24
|
-
},
|
|
25
|
-
}),
|
|
26
21
|
});
|
|
27
|
-
assert.deepEqual(calls
|
|
22
|
+
assert.deepEqual(calls, ['server']);
|
|
28
23
|
});
|
|
29
24
|
|
|
30
25
|
test('pristine headless execution binds Cursor OAuth credentials in process', async () => {
|
|
@@ -203,29 +203,6 @@ function hasKeys(value) {
|
|
|
203
203
|
return !!value && typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length > 0;
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
// Process-local write intent for project MCP overrides. A loaded config contains
|
|
207
|
-
// snapshots for every project, but only entries toggled by this process may
|
|
208
|
-
// override a newer value read from disk inside the save lock.
|
|
209
|
-
const dirtyMcpProjectOverrides = new Map();
|
|
210
|
-
let mcpProjectOverrideDirtySeq = 0;
|
|
211
|
-
function mcpProjectOverrideDirtyKey(projectKey, serverName) {
|
|
212
|
-
return `${String(projectKey)}\u0000${String(serverName)}`;
|
|
213
|
-
}
|
|
214
|
-
export function markMcpProjectOverrideDirty(projectKey, serverName, enabled) {
|
|
215
|
-
const pairKey = mcpProjectOverrideDirtyKey(projectKey, serverName);
|
|
216
|
-
dirtyMcpProjectOverrides.set(pairKey, {
|
|
217
|
-
enabled: enabled !== false,
|
|
218
|
-
seq: ++mcpProjectOverrideDirtySeq,
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
function clearDurablySavedMcpProjectOverrides(appliedDirty) {
|
|
222
|
-
for (const { pairKey, seq } of appliedDirty) {
|
|
223
|
-
if (dirtyMcpProjectOverrides.get(pairKey)?.seq === seq) {
|
|
224
|
-
dirtyMcpProjectOverrides.delete(pairKey);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
206
|
function normalizeWebSearchRoute(route) {
|
|
230
207
|
if (!route || typeof route !== 'object' || Array.isArray(route))
|
|
231
208
|
return null;
|
|
@@ -435,6 +412,7 @@ function canonicalizeLegacyAgentStorage(value = {}) {
|
|
|
435
412
|
delete next.capabilities;
|
|
436
413
|
delete next.defaultProvider;
|
|
437
414
|
delete next.guide;
|
|
415
|
+
delete next.mcpProjectOverrides;
|
|
438
416
|
return next;
|
|
439
417
|
}
|
|
440
418
|
|
|
@@ -451,6 +429,7 @@ function agentConfigStorageNeedsMigration(value = {}) {
|
|
|
451
429
|
|| Object.prototype.hasOwnProperty.call(value || {}, 'searchRoute')
|
|
452
430
|
|| Object.prototype.hasOwnProperty.call(value || {}, 'capabilities')
|
|
453
431
|
|| Object.prototype.hasOwnProperty.call(value || {}, 'defaultProvider')
|
|
432
|
+
|| Object.prototype.hasOwnProperty.call(value || {}, 'mcpProjectOverrides')
|
|
454
433
|
|| presets.some((preset) => !normalizePreset(preset))
|
|
455
434
|
|| (modules && typeof modules === 'object' && Object.prototype.hasOwnProperty.call(modules, 'memory'))
|
|
456
435
|
|| normalizedFields.some((key) => JSON.stringify(value?.[key]) !== JSON.stringify(canonical?.[key]));
|
|
@@ -560,9 +539,6 @@ export function loadConfig(options = {}) {
|
|
|
560
539
|
const loaded = canonicalizeAgentRouteStorage({
|
|
561
540
|
providers: mergedProviders,
|
|
562
541
|
mcpServers,
|
|
563
|
-
mcpProjectOverrides: raw.mcpProjectOverrides && typeof raw.mcpProjectOverrides === 'object' && !Array.isArray(raw.mcpProjectOverrides)
|
|
564
|
-
? raw.mcpProjectOverrides
|
|
565
|
-
: {},
|
|
566
542
|
presets: normalizedPresets,
|
|
567
543
|
default: raw.default || null,
|
|
568
544
|
maintenance: { ...DEFAULT_MAINTENANCE, ...normalizedMaint },
|
|
@@ -628,7 +604,6 @@ export function loadConfig(options = {}) {
|
|
|
628
604
|
return {
|
|
629
605
|
...defaults,
|
|
630
606
|
mcpServers: {},
|
|
631
|
-
mcpProjectOverrides: {},
|
|
632
607
|
presets: DEFAULT_PRESETS.map(p => ({ ...p })),
|
|
633
608
|
default: null,
|
|
634
609
|
maintenance: { ...DEFAULT_MAINTENANCE },
|
|
@@ -691,7 +666,7 @@ export async function patchSkillsDisabledAsync(disabledNames) {
|
|
|
691
666
|
return nextSkills;
|
|
692
667
|
}
|
|
693
668
|
|
|
694
|
-
function buildAgentSaveBuilder(config
|
|
669
|
+
function buildAgentSaveBuilder(config) {
|
|
695
670
|
const canonicalRoutes = canonicalizeLegacyAgentStorage(config);
|
|
696
671
|
// Strip ephemeral defaults from providers but preserve any unknown
|
|
697
672
|
// per-provider subkey so future schema additions round-trip through the
|
|
@@ -745,42 +720,10 @@ function buildAgentSaveBuilder(config, appliedDirty) {
|
|
|
745
720
|
// a concurrent instance survive the save (lost-update guard).
|
|
746
721
|
return (existingRaw) => {
|
|
747
722
|
const mcpServers = config.mcpServers || {};
|
|
748
|
-
const diskOverrides = existingRaw.mcpProjectOverrides && typeof existingRaw.mcpProjectOverrides === 'object'
|
|
749
|
-
? existingRaw.mcpProjectOverrides
|
|
750
|
-
: {};
|
|
751
|
-
const memoryOverrides = config.mcpProjectOverrides && typeof config.mcpProjectOverrides === 'object'
|
|
752
|
-
? config.mcpProjectOverrides
|
|
753
|
-
: {};
|
|
754
|
-
const mcpProjectOverrides = {};
|
|
755
|
-
for (const projectKey of new Set([...Object.keys(diskOverrides), ...Object.keys(memoryOverrides)])) {
|
|
756
|
-
const diskProject = diskOverrides[projectKey] && typeof diskOverrides[projectKey] === 'object'
|
|
757
|
-
? diskOverrides[projectKey]
|
|
758
|
-
: {};
|
|
759
|
-
const memoryProject = memoryOverrides[projectKey] && typeof memoryOverrides[projectKey] === 'object'
|
|
760
|
-
? memoryOverrides[projectKey]
|
|
761
|
-
: {};
|
|
762
|
-
// Disk wins for untouched snapshot entries. Only an override this
|
|
763
|
-
// process explicitly toggled may replace the in-lock disk value.
|
|
764
|
-
const mergedProject = { ...memoryProject, ...diskProject };
|
|
765
|
-
for (const serverName of Object.keys(memoryProject)) {
|
|
766
|
-
const pairKey = mcpProjectOverrideDirtyKey(projectKey, serverName);
|
|
767
|
-
const dirty = dirtyMcpProjectOverrides.get(pairKey);
|
|
768
|
-
if (dirty) {
|
|
769
|
-
const appliedValue = { enabled: dirty.enabled };
|
|
770
|
-
mergedProject[serverName] = appliedValue;
|
|
771
|
-
appliedDirty.push({ pairKey, seq: dirty.seq, appliedValue });
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
for (const serverName of Object.keys(mergedProject)) {
|
|
775
|
-
if (!Object.prototype.hasOwnProperty.call(mcpServers, serverName)) delete mergedProject[serverName];
|
|
776
|
-
}
|
|
777
|
-
if (Object.keys(mergedProject).length > 0) mcpProjectOverrides[projectKey] = mergedProject;
|
|
778
|
-
}
|
|
779
723
|
const next = {
|
|
780
724
|
...existingRaw,
|
|
781
725
|
providers: persistedProviders,
|
|
782
726
|
mcpServers,
|
|
783
|
-
mcpProjectOverrides,
|
|
784
727
|
presets,
|
|
785
728
|
default: config.default || null,
|
|
786
729
|
maintenance: canonicalRoutes.maintenance,
|
|
@@ -810,19 +753,16 @@ function buildAgentSaveBuilder(config, appliedDirty) {
|
|
|
810
753
|
delete next.capabilities;
|
|
811
754
|
delete next.defaultProvider;
|
|
812
755
|
delete next.guide;
|
|
756
|
+
delete next.mcpProjectOverrides;
|
|
813
757
|
return next;
|
|
814
758
|
};
|
|
815
759
|
}
|
|
816
760
|
export function saveConfig(config) {
|
|
817
|
-
|
|
818
|
-
persistAgentConfig(buildAgentSaveBuilder(config, appliedDirty));
|
|
819
|
-
clearDurablySavedMcpProjectOverrides(appliedDirty);
|
|
761
|
+
persistAgentConfig(buildAgentSaveBuilder(config));
|
|
820
762
|
}
|
|
821
763
|
// Async twin used by the debounced config-save flush timer.
|
|
822
764
|
export async function saveConfigAsync(config) {
|
|
823
|
-
|
|
824
|
-
await persistAgentConfigAsync(buildAgentSaveBuilder(config, appliedDirty));
|
|
825
|
-
clearDurablySavedMcpProjectOverrides(appliedDirty);
|
|
765
|
+
await persistAgentConfigAsync(buildAgentSaveBuilder(config));
|
|
826
766
|
}
|
|
827
767
|
// --- Preset helpers ---
|
|
828
768
|
// preset shape: { id, name, type: 'agent', provider, model, effort?, fast?, tools? }
|