mixdog 0.9.91 → 0.9.93
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 +147 -51
- package/package.json +6 -5
- package/scripts/code-graph-description-contract.mjs +6 -8
- package/scripts/tmp-cdp-errors.mjs +41 -0
- package/scripts/tmp-cdp-inspect.mjs +41 -0
- package/scripts/tool-overhead-microbench.mjs +60 -0
- package/scripts/tui-transcript-jitter-harness.mjs +2 -18
- package/src/agents/debugger/agent.json +1 -1
- package/src/agents/explore/agent.json +1 -1
- package/src/agents/heavy-worker/agent.json +1 -1
- package/src/agents/maintainer/agent.json +1 -1
- package/src/agents/reviewer/agent.json +1 -1
- package/src/agents/worker/agent.json +1 -1
- package/src/lib/rules-builder.cjs +5 -5
- package/src/output-styles/simple.md +1 -1
- package/src/rules/agent/00-core.md +1 -2
- package/src/rules/lead/01-general.md +1 -0
- package/src/rules/shared/01-tool.md +19 -21
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +16 -3
- package/src/runtime/agent/orchestrator/agent-trace.mjs +17 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +90 -22
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +54 -19
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +18 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +44 -8
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +35 -0
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +34 -5
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +35 -29
- package/src/runtime/agent/orchestrator/session/loop/stop-hooks.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +5 -6
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +31 -2
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +60 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +60 -31
- package/src/runtime/agent/orchestrator/session/manager.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/result-classification.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +71 -2
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +17 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +30 -0
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +19 -23
- package/src/runtime/agent/orchestrator/stall-policy.mjs +31 -21
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +12 -6
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +5 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/lib/pwsh-standby-pool.mjs +47 -14
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +100 -0
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +6 -5
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/shell-state.mjs +32 -2
- package/src/runtime/channels/backends/discord-gateway.mjs +6 -32
- package/src/runtime/channels/lib/inbound-handler.mjs +19 -3
- package/src/runtime/channels/lib/scheduler.mjs +51 -3
- package/src/runtime/channels/lib/worker-main.mjs +4 -0
- package/src/runtime/channels/tool-defs.mjs +4 -2
- package/src/runtime/memory/lib/query-handlers.mjs +11 -3
- package/src/runtime/memory/tool-defs.mjs +5 -5
- package/src/runtime/shared/channel-notification-routing.mjs +8 -2
- package/src/runtime/shared/llm/http-agent.mjs +11 -0
- package/src/session-runtime/lifecycle-api.mjs +26 -1
- package/src/session-runtime/output-styles.mjs +1 -4
- package/src/session-runtime/tool-catalog-data.mjs +5 -2
- package/src/session-runtime/workflow.mjs +25 -13
- package/src/standalone/agent-tool/tag-registry.mjs +5 -1
- package/src/standalone/explore-tool.mjs +1 -1
- package/src/tui/dist/index.mjs +100 -46
- package/src/tui/engine/agent-envelope.mjs +52 -3
- package/src/tui/engine/session-api.mjs +17 -0
- package/src/tui/engine/tui-steering-persist.mjs +24 -1
- package/src/tui/engine/turn.mjs +8 -9
- package/src/tui/engine.mjs +18 -41
- package/src/workflows/default/WORKFLOW.md +7 -18
- package/src/workflows/solo/WORKFLOW.md +0 -6
- package/src/workflows/solo-bench/WORKFLOW.md +17 -0
package/README.md
CHANGED
|
@@ -4,14 +4,17 @@
|
|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
Standalone coding
|
|
8
|
-
|
|
9
|
-
cost
|
|
7
|
+
Standalone coding agent that runs an orchestrated, multi-provider agent
|
|
8
|
+
workflow from one terminal — or from a full desktop workbench — built to
|
|
9
|
+
get the same quality out of the same models with less time, cost, and
|
|
10
|
+
context.
|
|
10
11
|
|
|
11
12
|
Mixdog combines an Ink-based terminal UI, per-role model routing across
|
|
12
13
|
providers, workflow agents, MCP/plugin/skill/hook support, lightweight
|
|
13
14
|
memory, web search, channel integrations, and repo-native tools for reading,
|
|
14
|
-
editing, testing, and reviewing code.
|
|
15
|
+
editing, testing, and reviewing code. Mixdog Desktop wraps the same runtime
|
|
16
|
+
in an Electron workbench with editor, git, terminal, file-explorer, media,
|
|
17
|
+
and automation surfaces.
|
|
15
18
|
|
|
16
19
|
## Quick start
|
|
17
20
|
|
|
@@ -25,34 +28,59 @@ mixdog
|
|
|
25
28
|
First run walks you through onboarding: provider auth, model pick, and
|
|
26
29
|
workflow setup.
|
|
27
30
|
|
|
28
|
-
## Terminal-Bench 2.1 —
|
|
31
|
+
## Terminal-Bench 2.1 — controlled full-run comparisons
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
**Same model, same quality — in a fraction of the time, context, and
|
|
34
|
+
cost.** On the same 89 tasks, mixdog scored on par with both native
|
|
35
|
+
harnesses — **78/89** vs Claude Code's **77/89** (within single-run noise)
|
|
36
|
+
and **75/89** matching Codex CLI — while finishing faster, ending leaner,
|
|
37
|
+
and costing less.
|
|
31
38
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
Each comparison matches the primary model and reasoning level on
|
|
40
|
+
both sides, comparing each product as shipped: mixdog routes scoped
|
|
41
|
+
read-only Explorer lookups to a smaller model, mirroring Claude Code's
|
|
42
|
+
built-in Explore subagent (Haiku 4.5 by default in the 2.1.x baseline).
|
|
43
|
+
Codex CLI ships no equivalent helper — the Sol-led mixdog run used GPT-5.6
|
|
44
|
+
Luna for that scoped Explorer work. Results are self-reported single runs
|
|
45
|
+
(`k=1`, 2026-08), not leaderboard submissions.
|
|
35
46
|
|
|
36
|
-
|
|
37
|
-
|---------------------|-----------------|-------------|
|
|
38
|
-
| Lead (orchestrator) | Claude Fable 5 | high |
|
|
39
|
-
| Explorer | Claude Haiku 4.5| default |
|
|
40
|
-
| Worker | Claude Opus 4.8 | medium |
|
|
41
|
-
| Heavy worker | Claude Opus 4.8 | high |
|
|
42
|
-
| Reviewer | GPT-5.5 | high (fast) |
|
|
47
|
+
#### Claude Opus 5 vs Claude Code
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
Sol Ultra (91.9%), ahead of GPT-5.6 Sol (88.8%) and Claude Mythos 5 (88%),
|
|
46
|
-
and well above the same primary model run standalone (Claude Fable 5,
|
|
47
|
-
84.3%). Measured once (k=1) due to cost, so treat it as indicative — a
|
|
48
|
-
max-effort k=5 run is planned and is expected to land higher. Per-task
|
|
49
|
-
results, raw Harbor jobs, and the harness adapter live in
|
|
50
|
-
`benchmarks/terminal-bench-2.1/`.
|
|
49
|
+

|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
#### GPT-5.6 Sol xhigh vs Codex CLI
|
|
52
|
+
|
|
53
|
+

|
|
54
|
+
|
|
55
|
+
- Speed: **1.43×** vs Claude Code, **1.27×** vs Codex CLI
|
|
56
|
+
(baseline elapsed agent time ÷ mixdog elapsed agent time)
|
|
57
|
+
- Final context: **40–47% smaller** at task end (median tokens, measured
|
|
58
|
+
from both harnesses' session logs)
|
|
59
|
+
- Priced cost: **29% lower** vs Claude Code, **at least 39.7% lower** vs
|
|
60
|
+
Codex CLI (mixdog $54.50–$58.84 vs Codex's recorded $97.54)
|
|
61
|
+
|
|
62
|
+
Both sides run their standard single-agent loop. Anthropic cost includes
|
|
63
|
+
measured cache writes; the archived OpenAI runs did not retain
|
|
64
|
+
`cache_write_tokens`, so the Codex cost delta is a lower bound. Raw
|
|
65
|
+
artifacts, the exact run commands, and the metric scripts that recompute
|
|
66
|
+
every number above live under `benchmarks/terminal-bench-2.1/`.
|
|
67
|
+
|
|
68
|
+
## Boot overhead — measured, not estimated
|
|
69
|
+
|
|
70
|
+
Fixed cost of the default system prompt + tool schemas, measured with a
|
|
71
|
+
minimal one-turn ping ("hi"). Every number below is what the provider's own
|
|
72
|
+
usage accounting reported for the first API call — same tokenizer on both
|
|
73
|
+
sides of each row, no offline estimates (2026-08).
|
|
74
|
+
|
|
75
|
+
| Tokenizer | Baseline harness | First-call prompt | mixdog Lead | mixdog worker agent |
|
|
76
|
+
|-----------|------------------|------------------:|------------:|--------------------:|
|
|
77
|
+
| Anthropic — pristine containers, TB2.1 harness | Claude Code 2.1.220 | 19,149 tok (median, n=89) | **7,295 (−62%)** | 4,856 (−75%) |
|
|
78
|
+
| OpenAI — same host, same model (`gpt-5.6-sol`) | Codex CLI 0.145.0 | 17,706 tok | **7,488 (−58%)** | 4,616 (−74%) |
|
|
79
|
+
|
|
80
|
+
The Lead surface carries the full default rule set, skills manifest, and
|
|
81
|
+
per-user profile; spawning a sub-agent costs a flat ~4.6–4.9k tokens. Low
|
|
82
|
+
boot overhead compounds: it is re-read on every request, so it is the
|
|
83
|
+
baseline of every cache write, compaction, and long-session turn.
|
|
56
84
|
|
|
57
85
|
## Why mixdog
|
|
58
86
|
|
|
@@ -68,9 +96,10 @@ for every constituent run are included.
|
|
|
68
96
|
|
|
69
97
|
**Any provider**
|
|
70
98
|
|
|
99
|
+
- Sign in with the subscriptions you already pay for: OAuth device flows for
|
|
100
|
+
Claude and ChatGPT/Codex accounts work alongside plain API keys.
|
|
71
101
|
- Anthropic, OpenAI, Google/Gemini, xAI/Grok, DeepSeek, OpenCode Go,
|
|
72
|
-
|
|
73
|
-
endpoints.
|
|
102
|
+
OpenAI-compatible APIs, Ollama, and LM Studio/local endpoints.
|
|
74
103
|
- Live model catalog from provider `/models` endpoints, enriched with
|
|
75
104
|
LiteLLM/models.dev metadata for context windows, output limits, pricing,
|
|
76
105
|
tool support, reasoning, and recency.
|
|
@@ -81,20 +110,34 @@ for every constituent run are included.
|
|
|
81
110
|
- Full-screen TUI with slash commands, provider setup, model/workflow
|
|
82
111
|
pickers, statusline integration, and detailed tool cards — plus headless
|
|
83
112
|
role mode for scripting.
|
|
84
|
-
-
|
|
85
|
-
|
|
113
|
+
- Mixdog Desktop: a full agent workbench for Windows/macOS/Linux (see
|
|
114
|
+
below).
|
|
115
|
+
- Web/mobile companion over relay pairing — scan a QR code to open your
|
|
116
|
+
running sessions in a phone browser and keep going from any network.
|
|
117
|
+
- Optional Discord/Telegram channels, webhook endpoints, and cron schedules
|
|
118
|
+
with quiet hours for remote/event-driven workflows; channel voice messages
|
|
119
|
+
are transcribed locally with a managed Whisper server.
|
|
120
|
+
- First-class Windows support: ConPTY terminals, PowerShell-aware shell
|
|
121
|
+
profiles, and a one-click desktop installer.
|
|
86
122
|
|
|
87
123
|
**Memory**
|
|
88
124
|
|
|
89
|
-
-
|
|
90
|
-
|
|
125
|
+
- Every session is ingested into a local memory store in the background, so
|
|
126
|
+
prior work, decisions, and fixes stay recallable across sessions via the
|
|
127
|
+
`recall` tool and `/memory`.
|
|
128
|
+
- Semantic + lexical recall with local embeddings, time-window queries, and
|
|
129
|
+
project-scoped pools — multilingual, including Korean morphology.
|
|
130
|
+
- A multi-pass consolidation cycle promotes important memories into a
|
|
131
|
+
compact core set — and demotes them when stale — so memory stays small
|
|
132
|
+
and current instead of growing without bound.
|
|
91
133
|
|
|
92
134
|
**Agent-ecosystem compatible**
|
|
93
135
|
|
|
94
136
|
- Skills, MCP servers, hooks, and plugins load through standard-compatible
|
|
95
137
|
interfaces.
|
|
96
138
|
- Workflow delegation through the `agent` tool and `/agents`: worker,
|
|
97
|
-
heavy-worker, reviewer, debugger, maintainer,
|
|
139
|
+
heavy-worker, reviewer, debugger, maintainer, explorer, and
|
|
140
|
+
web-researcher roles.
|
|
98
141
|
|
|
99
142
|
## Run
|
|
100
143
|
|
|
@@ -112,20 +155,31 @@ mixdog
|
|
|
112
155
|
# Start with an explicit route
|
|
113
156
|
mixdog --provider anthropic-oauth --model claude-haiku-4-5-20251001
|
|
114
157
|
|
|
158
|
+
# Start with a specific workflow active
|
|
159
|
+
mixdog --workflow solo
|
|
160
|
+
|
|
115
161
|
# Read-only tool surface
|
|
116
162
|
mixdog --readonly
|
|
117
163
|
|
|
118
164
|
# Enable remote/channel mode for this session
|
|
119
165
|
mixdog --remote
|
|
166
|
+
|
|
167
|
+
# Re-run the first-run setup wizard
|
|
168
|
+
mixdog --onboarding
|
|
120
169
|
```
|
|
121
170
|
|
|
122
|
-
Headless role mode is also supported
|
|
171
|
+
Headless role mode is also supported. It requires an explicit
|
|
172
|
+
provider/model pair and runs with ephemeral config — host behavioral config
|
|
173
|
+
and personal state are not loaded:
|
|
123
174
|
|
|
124
175
|
```bash
|
|
125
|
-
mixdog worker "fix the failing test"
|
|
126
|
-
mixdog reviewer "review the current diff"
|
|
176
|
+
mixdog --provider anthropic-oauth --model claude-opus-5 worker "fix the failing test"
|
|
177
|
+
mixdog --provider openai-oauth --model gpt-5.6-sol reviewer "review the current diff"
|
|
127
178
|
```
|
|
128
179
|
|
|
180
|
+
Roles: `explore`, `worker`, `heavy-worker`, `reviewer`, `debugger`,
|
|
181
|
+
`maintainer`, `web-researcher`.
|
|
182
|
+
|
|
129
183
|
## TUI basics
|
|
130
184
|
|
|
131
185
|
Common slash commands:
|
|
@@ -135,15 +189,26 @@ Common slash commands:
|
|
|
135
189
|
/model choose the main provider/model (/effort, /fast tune it)
|
|
136
190
|
/workflow choose the active workflow
|
|
137
191
|
/agents show workflow agents and per-agent model overrides
|
|
192
|
+
/project switch working directory (project)
|
|
193
|
+
/resume resume a saved chat
|
|
194
|
+
/usage show total provider quota / balance
|
|
195
|
+
/context show the current context surface
|
|
196
|
+
/memory list and edit core memories
|
|
138
197
|
/setting open the runtime settings hub
|
|
139
198
|
/mcp manage MCP servers and tools
|
|
140
199
|
/skills choose a skill for the next request
|
|
141
200
|
/channels manage Discord, Telegram, and voice
|
|
142
201
|
/compact compact older conversation context
|
|
202
|
+
/autoclear reduce cache-miss cost after long idle gaps
|
|
203
|
+
/theme change the TUI color theme
|
|
143
204
|
/clear reset the conversation and screen
|
|
144
205
|
/OutputStyle show or switch Lead output style
|
|
206
|
+
/update check version and update mixdog
|
|
207
|
+
/doctor diagnose installation health
|
|
145
208
|
```
|
|
146
209
|
|
|
210
|
+
Run `mixdog --help` for the full command and option reference.
|
|
211
|
+
|
|
147
212
|
Use `/providers` first if no model is configured, then `/model` to pick the
|
|
148
213
|
route. The model picker warms the provider catalog in the background and keeps
|
|
149
214
|
Claude families such as Opus, Sonnet, Haiku, and Fable separate when filtering
|
|
@@ -155,6 +220,44 @@ directory (`workflows/<id>/`, `agents/<id>/`) and are edited on the desktop
|
|
|
155
220
|
app's Workflows page. Schedules and webhooks are also managed in the desktop
|
|
156
221
|
app.
|
|
157
222
|
|
|
223
|
+
## Desktop app
|
|
224
|
+
|
|
225
|
+
Mixdog Desktop (Electron) runs the same runtime as the CLI inside a full
|
|
226
|
+
agent workbench. Installers are published on GitHub Releases (Windows
|
|
227
|
+
one-click NSIS, macOS dmg/zip, Linux AppImage), and a guided onboarding
|
|
228
|
+
wizard covers first-run setup. For development run `npm run dev` inside
|
|
229
|
+
`apps/desktop`.
|
|
230
|
+
|
|
231
|
+
- **Workbench shell** — VS Code-style activity rail and tab strip,
|
|
232
|
+
drag-and-drop tabs across pane groups, and unlimited splits that run
|
|
233
|
+
parallel agent sessions side by side — every pane hosts a live session
|
|
234
|
+
surface with its own draft and model controls — plus a command surface,
|
|
235
|
+
bottom panel, and problems view.
|
|
236
|
+
- **Sessions and projects** — project-scoped session lists, resumable
|
|
237
|
+
sessions with per-pane route restore, live agent-activity indicators, and
|
|
238
|
+
usage dashboards in the sidebar.
|
|
239
|
+
- **Editor and review** — Monaco editor pane with LSP integration, git and
|
|
240
|
+
inline diff viewers, and turn-by-turn review of agent edits with approval
|
|
241
|
+
cards.
|
|
242
|
+
- **Source control** — git dock for staging/commits/branches,
|
|
243
|
+
auto-generated commit messages, GitHub CLI integration, pull-request
|
|
244
|
+
browsing, and a dedicated review pane.
|
|
245
|
+
- **File explorer** — Windows-Explorer-grade folder pane: breadcrumbs and
|
|
246
|
+
path box, ribbon toolbar, places/drives/tree sidebar, grouped grid and
|
|
247
|
+
details views with shell icons and thumbnails, rubber-band selection,
|
|
248
|
+
clipboard and OS drag-and-drop, preview pane, and file properties.
|
|
249
|
+
- **Terminal** — integrated terminal tabs on the native shell (ConPTY on
|
|
250
|
+
Windows) with shell-profile detection, isolated in a worker process so a
|
|
251
|
+
runaway shell never takes the app down.
|
|
252
|
+
- **Studio** — media studio for image and video generation over
|
|
253
|
+
authenticated provider lanes, with a persistent local gallery, reference
|
|
254
|
+
images, and per-model resolution/aspect/duration controls.
|
|
255
|
+
- **Automation** — visual editors for workflow and agent packs, cron
|
|
256
|
+
schedules, webhooks, and channel integrations.
|
|
257
|
+
- **Settings hub** — provider auth, capability sweep, git identity, and
|
|
258
|
+
QR device pairing for the web/mobile companion, preloaded so every
|
|
259
|
+
category opens instantly.
|
|
260
|
+
|
|
158
261
|
## Scripts
|
|
159
262
|
|
|
160
263
|
```bash
|
|
@@ -206,6 +309,10 @@ src/
|
|
|
206
309
|
agents/ # workflow agent definitions
|
|
207
310
|
workflows/ # workflow definitions
|
|
208
311
|
rules/ # Lead and agent instructions
|
|
312
|
+
apps/
|
|
313
|
+
desktop/ # Mixdog Desktop — Electron workbench (main/preload/renderer)
|
|
314
|
+
mobile/ # mobile companion shell
|
|
315
|
+
relay/ # relay server for remote/web/mobile access
|
|
209
316
|
scripts/
|
|
210
317
|
smoke*.mjs # smoke checks
|
|
211
318
|
*test.mjs # focused node:test checks
|
|
@@ -216,20 +323,9 @@ vendor/
|
|
|
216
323
|
|
|
217
324
|
## Published package contents
|
|
218
325
|
|
|
219
|
-
The npm
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
README.md
|
|
223
|
-
scripts/
|
|
224
|
-
src/
|
|
225
|
-
vendor/
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
Test, smoke, and bench scripts are excluded from the tarball; they live in the
|
|
229
|
-
repository only.
|
|
230
|
-
|
|
231
|
-
`docs/` is not included in the published package unless `package.json#files` is
|
|
232
|
-
changed.
|
|
326
|
+
The npm tarball ships `README.md`, `src/`, `vendor/`, and runtime `scripts/`
|
|
327
|
+
only (`package.json#files`); tests, smokes, benches, and `docs/` stay in the
|
|
328
|
+
repository.
|
|
233
329
|
|
|
234
330
|
## License
|
|
235
331
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mixdog",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.93",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Standalone mixdog coding-agent CLI/TUI workspace.",
|
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
"test:agent-job-views": "node --test scripts/agent-job-terminal-view-test.mjs",
|
|
67
67
|
"test:agent-fanout": "node scripts/agent-parallel-smoke.mjs && node --test scripts/agent-route-batch-test.mjs scripts/execution-completion-dedup-test.mjs",
|
|
68
68
|
"test:toolcall": "node --test scripts/toolcall-args-test.mjs",
|
|
69
|
+
"test:tool-batching": "node --test scripts/eager-patch-shell-order-test.mjs scripts/session-bench-batching-test.mjs",
|
|
69
70
|
"test:shipmode": "node --test scripts/ship-mode-test.mjs",
|
|
70
71
|
"test:shellhardening": "node --test scripts/shell-hardening-test.mjs scripts/shell-failure-diagnostics-test.mjs scripts/windows-hide-spawn-options-test.mjs",
|
|
71
72
|
"test:placeholder": "node --test scripts/compacted-placeholder-scrub-test.mjs",
|
|
@@ -85,10 +86,10 @@
|
|
|
85
86
|
"test:code-graph-clean-cache": "node --test scripts/code-graph-dispatch-test.mjs",
|
|
86
87
|
"test:tui-queue": "node --test scripts/submit-commandbusy-race-test.mjs scripts/steering-drain-buckets-test.mjs scripts/abort-recovery-test.mjs scripts/execution-pending-resume-kick-test.mjs scripts/execution-resume-esc-integration-test.mjs scripts/pending-stale-injection-test.mjs",
|
|
87
88
|
"test:tui-input-render": "node --test scripts/prompt-immediate-render-test.mjs",
|
|
88
|
-
"test:tui-streaming-window": "node --test scripts/streaming-tail-window-test.mjs",
|
|
89
|
+
"test:tui-streaming-window": "node --test scripts/streaming-tail-window-test.mjs scripts/tui-store-frame-batch-test.mjs && node scripts/tui-transcript-jitter-harness.mjs",
|
|
89
90
|
"test:tui-ambiguous-width": "node --test scripts/tui-ambiguous-width-test.mjs",
|
|
90
91
|
"test:release-assets": "node --check scripts/verify-release-assets.mjs && node --check scripts/verify-release-assets-test.mjs && node --check scripts/deploy-workflow-test.mjs && node --test scripts/verify-release-assets-test.mjs scripts/deploy-workflow-test.mjs",
|
|
91
|
-
"test:release-focused": "npm run test:release-assets && npm run test:tool-contracts && npm run test:placeholder && npm run smoke:patch && npm run test:patch-binary-cache && npm run test:providers && npm run test:deferred-tools && npm run smoke:compact && npm run test:compact && npm run test:context && node --test scripts/code-graph-root-federation-test.mjs scripts/code-graph-aggregate-cwd-test.mjs && npm run test:code-graph-dispatch && node --test scripts/code-graph-disk-hit-test.mjs && npm run test:shellhardening && npm run test:project-registry && npm run test:session && npm run test:workflow-editor && npm run test:embedding-runtime && node --test scripts/tui-transcript-perf-test.mjs",
|
|
92
|
+
"test:release-focused": "npm run test:release-assets && npm run test:tool-contracts && npm run test:tool-batching && npm run test:placeholder && npm run smoke:patch && npm run test:patch-binary-cache && npm run test:providers && npm run test:deferred-tools && npm run smoke:compact && npm run test:compact && npm run test:context && node --test scripts/code-graph-root-federation-test.mjs scripts/code-graph-aggregate-cwd-test.mjs && npm run test:code-graph-dispatch && node --test scripts/code-graph-disk-hit-test.mjs && npm run test:shellhardening && npm run test:project-registry && npm run test:session && npm run test:workflow-editor && npm run test:embedding-runtime && node --test scripts/tui-transcript-perf-test.mjs",
|
|
92
93
|
"test:native-edit-wire": "node --test scripts/native-edit-wire-test.mjs",
|
|
93
94
|
"test:patch-binary-cache": "node --test scripts/patch-binary-cache-test.mjs",
|
|
94
95
|
"test:patch-parity": "node --test scripts/v4a-codex-parity-test.mjs",
|
|
@@ -150,10 +151,10 @@
|
|
|
150
151
|
},
|
|
151
152
|
"overrides": {
|
|
152
153
|
"discord.js": {
|
|
153
|
-
"undici": "6.
|
|
154
|
+
"undici": "6.28.0"
|
|
154
155
|
},
|
|
155
156
|
"@discordjs/rest": {
|
|
156
|
-
"undici": "6.
|
|
157
|
+
"undici": "6.28.0"
|
|
157
158
|
},
|
|
158
159
|
"onnxruntime-node": {
|
|
159
160
|
"global-agent": "^4.1.3"
|
|
@@ -85,7 +85,7 @@ const CODE_GRAPH_DESCRIPTION_MUTATION_CORPUS = [
|
|
|
85
85
|
allPositiveProbes: true,
|
|
86
86
|
mutate: (parts) => ({
|
|
87
87
|
...parts,
|
|
88
|
-
description: parts.description.replace(/keywords\s+(?:use|route through|select)/i, "keywords won't use"),
|
|
88
|
+
description: parts.description.replace(/keywords\s+(?:use|route through|select|via)/i, "keywords won't use"),
|
|
89
89
|
}),
|
|
90
90
|
},
|
|
91
91
|
{
|
|
@@ -101,7 +101,7 @@ const CODE_GRAPH_DESCRIPTION_MUTATION_CORPUS = [
|
|
|
101
101
|
allPositiveProbes: true,
|
|
102
102
|
mutate: (parts) => ({
|
|
103
103
|
...parts,
|
|
104
|
-
symbolsDescription: parts.symbolsDescription.replace(/one symbols\[\] call/i, 'one files[] call'),
|
|
104
|
+
symbolsDescription: parts.symbolsDescription.replace(/one symbols\[\] call|one symbols\[\]/i, 'one files[] call'),
|
|
105
105
|
}),
|
|
106
106
|
},
|
|
107
107
|
{
|
|
@@ -143,18 +143,16 @@ const CODE_GRAPH_DESCRIPTION_MUTATION_CORPUS = [
|
|
|
143
143
|
function hasCodeGraphDescriptionContract({ description, modeDescription, symbolsDescription }) {
|
|
144
144
|
return (
|
|
145
145
|
hasPositiveClause(description, ['file modes', 'files[]'])
|
|
146
|
-
&&
|
|
146
|
+
&& hasPositiveClause(description, ['symbol modes', 'symbols[]'])
|
|
147
147
|
&& hasPositiveClause(description, ['exact identifiers', ...EXACT_MODES])
|
|
148
148
|
&& hasPositiveClause(description, ['keywords', ...KEYWORD_MODES])
|
|
149
149
|
&& !hasContradictoryTargetAssignment(description)
|
|
150
150
|
&& hasModeClause(modeDescription, 'file modes', FILE_MODES)
|
|
151
151
|
&& hasPositiveClause(modeDescription, ['symbols with files', 'files[]', 'file outline'])
|
|
152
|
-
&& hasModeClause(modeDescription, 'symbol modes', SYMBOL_MODES)
|
|
153
|
-
&& hasPositiveClause(modeDescription, ['fileless symbols', 'symbol_search', 'keywords'])
|
|
154
152
|
&& !hasContradictoryTargetAssignment(modeDescription)
|
|
155
|
-
&& hasPositiveClause(symbolsDescription, ['exact identifiers'
|
|
156
|
-
&& hasPositiveClause(symbolsDescription, ['keywords'
|
|
157
|
-
&& hasPositiveClause(symbolsDescription, ['
|
|
153
|
+
&& hasPositiveClause(symbolsDescription, ['exact identifiers'])
|
|
154
|
+
&& hasPositiveClause(symbolsDescription, ['keywords'])
|
|
155
|
+
&& hasPositiveClause(symbolsDescription, ['symbols[]'])
|
|
158
156
|
&& !hasContradictoryTargetAssignment(symbolsDescription)
|
|
159
157
|
);
|
|
160
158
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import WebSocket from "ws";
|
|
2
|
+
|
|
3
|
+
const list = await fetch("http://127.0.0.1:9342/json/list").then((r) => r.json());
|
|
4
|
+
const page = list.find((t) => t.type === "page");
|
|
5
|
+
const ws = new WebSocket(page.webSocketDebuggerUrl);
|
|
6
|
+
let id = 0; const pending = new Map();
|
|
7
|
+
function send(method, params) {
|
|
8
|
+
return new Promise((res) => { const mid = ++id; pending.set(mid, res); ws.send(JSON.stringify({ id: mid, method, params })); });
|
|
9
|
+
}
|
|
10
|
+
const seen = new Map();
|
|
11
|
+
ws.on("message", (raw) => {
|
|
12
|
+
const msg = JSON.parse(raw);
|
|
13
|
+
if (msg.id && pending.has(msg.id)) { pending.get(msg.id)(msg.result); pending.delete(msg.id); return; }
|
|
14
|
+
if (msg.method === "Runtime.exceptionThrown") {
|
|
15
|
+
const d = msg.params.exceptionDetails;
|
|
16
|
+
const desc = d.exception?.description || d.text || "";
|
|
17
|
+
const key = desc.slice(0, 200);
|
|
18
|
+
seen.set(key, (seen.get(key) || 0) + 1);
|
|
19
|
+
} else if (msg.method === "Runtime.consoleAPICalled" && (msg.params.type === "error" || msg.params.type === "warning")) {
|
|
20
|
+
const text = msg.params.args.map((a) => a.value ?? a.description ?? "").join(" ");
|
|
21
|
+
const key = "[console." + msg.params.type + "] " + text.slice(0, 300);
|
|
22
|
+
seen.set(key, (seen.get(key) || 0) + 1);
|
|
23
|
+
} else if (msg.method === "Log.entryAdded") {
|
|
24
|
+
const e = msg.params.entry;
|
|
25
|
+
if (e.level === "error" || e.level === "warning") {
|
|
26
|
+
const key = "[log." + e.level + "] " + (e.text || "").slice(0, 300) + " @" + (e.url || "");
|
|
27
|
+
seen.set(key, (seen.get(key) || 0) + 1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
ws.on("open", async () => {
|
|
32
|
+
await send("Runtime.enable", {});
|
|
33
|
+
await send("Log.enable", {});
|
|
34
|
+
setTimeout(() => {
|
|
35
|
+
for (const [key, count] of [...seen.entries()].sort((a, b) => b[1] - a[1])) {
|
|
36
|
+
console.log(`x${count} ${key.replace(/\n/g, " | ")}`);
|
|
37
|
+
}
|
|
38
|
+
if (!seen.size) console.log("(no errors captured in window)");
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}, 12000);
|
|
41
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import WebSocket from "ws";
|
|
2
|
+
|
|
3
|
+
const list = await fetch("http://127.0.0.1:9342/json/list").then((r) => r.json());
|
|
4
|
+
const page = list.find((t) => t.type === "page");
|
|
5
|
+
if (!page) { console.error("no page target"); process.exit(1); }
|
|
6
|
+
const ws = new WebSocket(page.webSocketDebuggerUrl);
|
|
7
|
+
let id = 0; const pending = new Map();
|
|
8
|
+
function send(method, params) {
|
|
9
|
+
return new Promise((res) => { const mid = ++id; pending.set(mid, res); ws.send(JSON.stringify({ id: mid, method, params })); });
|
|
10
|
+
}
|
|
11
|
+
ws.on("message", (raw) => {
|
|
12
|
+
const msg = JSON.parse(raw);
|
|
13
|
+
if (msg.id && pending.has(msg.id)) { pending.get(msg.id)(msg.result); pending.delete(msg.id); }
|
|
14
|
+
});
|
|
15
|
+
ws.on("open", async () => {
|
|
16
|
+
const expr = `(() => {
|
|
17
|
+
const gate = document.querySelector('.desktop-boot-gate');
|
|
18
|
+
const covers = [...document.querySelectorAll('.pane-surface-cover, .desktop-boot-cover')].map(c => ({
|
|
19
|
+
cls: c.className,
|
|
20
|
+
rect: Math.round(c.getBoundingClientRect().width) + 'x' + Math.round(c.getBoundingClientRect().height),
|
|
21
|
+
parent: (c.parentElement?.className || '').slice(0, 90),
|
|
22
|
+
hasSpinner: !!c.querySelector('.desktop-loading-spinner'),
|
|
23
|
+
}));
|
|
24
|
+
const gates = [...document.querySelectorAll('.pane-surface-gate[data-ready="false"], .stable-surface-switch[data-ready="false"], .stable-content-swap[data-ready="false"]')]
|
|
25
|
+
.map(g => g.className + ' | parent=' + (g.parentElement?.className || '').slice(0, 70));
|
|
26
|
+
return JSON.stringify({
|
|
27
|
+
bootGate: gate ? { ready: gate.dataset.ready, pending: gate.dataset.pending, timeout: gate.dataset.timeout } : null,
|
|
28
|
+
revealed: window.__mixdogDesktopRevealed,
|
|
29
|
+
shown: window.__mixdogWindowShown,
|
|
30
|
+
covers, gates,
|
|
31
|
+
metrics: (window.__mixdogBootMetrics || []).slice(-30),
|
|
32
|
+
recovery: !!document.querySelector('.desktop-recovery-screen'),
|
|
33
|
+
rootKids: document.getElementById('root')?.childElementCount,
|
|
34
|
+
url: location.href,
|
|
35
|
+
}, null, 1);
|
|
36
|
+
})()`;
|
|
37
|
+
const r = await send("Runtime.evaluate", { expression: expr, returnByValue: true });
|
|
38
|
+
console.log(r?.result?.value ?? JSON.stringify(r));
|
|
39
|
+
process.exit(0);
|
|
40
|
+
});
|
|
41
|
+
setTimeout(() => { console.error("timeout"); process.exit(1); }, 8000);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Micro-bench: fixed per-call overhead of the shell tool path vs raw spawn.
|
|
2
|
+
// Usage: node scripts/tool-overhead-microbench.mjs [bash|powershell] [N]
|
|
3
|
+
// Prints per-call ms for executeBashTool('echo hi') and raw child spawn,
|
|
4
|
+
// so (tool - raw) isolates our tool-layer overhead (policy, wrappers, I/O).
|
|
5
|
+
import { spawn } from 'node:child_process';
|
|
6
|
+
import { executeBashTool } from '../src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs';
|
|
7
|
+
|
|
8
|
+
const shell = process.argv[2] || (process.platform === 'win32' ? 'powershell' : 'bash');
|
|
9
|
+
const N = Number(process.argv[3] || 15);
|
|
10
|
+
|
|
11
|
+
const stats = (arr) => {
|
|
12
|
+
const s = [...arr].sort((a, b) => a - b);
|
|
13
|
+
const sum = s.reduce((t, v) => t + v, 0);
|
|
14
|
+
return {
|
|
15
|
+
mean: (sum / s.length).toFixed(1),
|
|
16
|
+
p50: s[Math.floor(s.length / 2)].toFixed(1),
|
|
17
|
+
min: s[0].toFixed(1),
|
|
18
|
+
max: s[s.length - 1].toFixed(1),
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const rawOnce = () => new Promise((resolveDone, reject) => {
|
|
23
|
+
const child = shell === 'powershell'
|
|
24
|
+
? spawn('pwsh', ['-NoProfile', '-NonInteractive', '-Command', 'echo hi'])
|
|
25
|
+
: spawn('bash', ['-c', 'echo hi']);
|
|
26
|
+
let out = '';
|
|
27
|
+
child.stdout.on('data', (c) => { out += c; });
|
|
28
|
+
child.on('error', reject);
|
|
29
|
+
child.on('close', () => resolveDone(out));
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const toolOnce = async () => {
|
|
33
|
+
const out = await executeBashTool({ command: 'echo hi', shell }, process.cwd(), {});
|
|
34
|
+
return String(out);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Warm-up both paths (module init, shell resolution cache, standbys).
|
|
38
|
+
await toolOnce(); await toolOnce();
|
|
39
|
+
await rawOnce(); await rawOnce();
|
|
40
|
+
|
|
41
|
+
const toolMs = [];
|
|
42
|
+
for (let i = 0; i < N; i++) {
|
|
43
|
+
const t0 = performance.now();
|
|
44
|
+
await toolOnce();
|
|
45
|
+
toolMs.push(performance.now() - t0);
|
|
46
|
+
}
|
|
47
|
+
const rawMs = [];
|
|
48
|
+
for (let i = 0; i < N; i++) {
|
|
49
|
+
const t0 = performance.now();
|
|
50
|
+
await rawOnce();
|
|
51
|
+
rawMs.push(performance.now() - t0);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const t = stats(toolMs);
|
|
55
|
+
const r = stats(rawMs);
|
|
56
|
+
console.log(`shell=${shell} n=${N}`);
|
|
57
|
+
console.log(`tool mean=${t.mean}ms p50=${t.p50}ms min=${t.min}ms max=${t.max}ms`);
|
|
58
|
+
console.log(`raw mean=${r.mean}ms p50=${r.p50}ms min=${r.min}ms max=${r.max}ms`);
|
|
59
|
+
console.log(`overhead(mean tool-raw)=${(Number(t.mean) - Number(r.mean)).toFixed(1)}ms`);
|
|
60
|
+
process.exit(0);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { build } from 'esbuild';
|
|
3
|
-
import {
|
|
3
|
+
import { rm } from 'node:fs/promises';
|
|
4
4
|
import { dirname, join } from 'node:path';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
6
|
|
|
@@ -18,22 +18,6 @@ const inkAlias = {
|
|
|
18
18
|
},
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
// Build-only probe: records the exact delta seen by the production helper
|
|
22
|
-
// without adding another stateful estimator call from the harness.
|
|
23
|
-
const growthProbe = {
|
|
24
|
-
name: 'streaming-tail-growth-probe',
|
|
25
|
-
setup(ctx) {
|
|
26
|
-
ctx.onLoad({ filter: /transcript-window\.mjs$/ }, async (args) => {
|
|
27
|
-
let source = (await readFile(args.path, 'utf8')).replace(/\r\n/g, '\n');
|
|
28
|
-
const target = ' return { tailRows: idEntry.rows, delta };';
|
|
29
|
-
const replacement = ` globalThis.__mixdogTailGrowthProbe = { live, baseline, delta, tailRows: idEntry.rows };\n${target}`;
|
|
30
|
-
if (!source.includes(target)) return null;
|
|
31
|
-
source = source.replace(target, replacement);
|
|
32
|
-
return { contents: source, loader: 'js' };
|
|
33
|
-
});
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
|
|
37
21
|
try {
|
|
38
22
|
await build({
|
|
39
23
|
entryPoints: [entry],
|
|
@@ -44,7 +28,7 @@ try {
|
|
|
44
28
|
target: 'node22',
|
|
45
29
|
jsx: 'automatic',
|
|
46
30
|
packages: 'external',
|
|
47
|
-
plugins: [inkAlias
|
|
31
|
+
plugins: [inkAlias],
|
|
48
32
|
banner: {
|
|
49
33
|
js: "import { createRequire as __mixdogCreateRequire } from 'node:module';\nconst require = __mixdogCreateRequire(import.meta.url);",
|
|
50
34
|
},
|
|
@@ -156,8 +156,8 @@ function stripFrontmatter(markdown) {
|
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
function normalizeOutputStyleName(value) {
|
|
159
|
-
const name = String(value || '
|
|
160
|
-
return /^[A-Za-z0-9_.-]+$/.test(name) ? name : '
|
|
159
|
+
const name = String(value || 'simple').trim();
|
|
160
|
+
return /^[A-Za-z0-9_.-]+$/.test(name) ? name : 'simple';
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
function loadOutputStyle({ PLUGIN_ROOT, DATA_DIR }) {
|
|
@@ -172,10 +172,10 @@ function loadOutputStyle({ PLUGIN_ROOT, DATA_DIR }) {
|
|
|
172
172
|
const body = stripFrontmatter(readOptional(candidate));
|
|
173
173
|
if (body) return body;
|
|
174
174
|
}
|
|
175
|
-
if (styleName !== '
|
|
175
|
+
if (styleName !== 'simple') {
|
|
176
176
|
const fallback = [
|
|
177
|
-
path.join(DATA_DIR, 'output-styles', '
|
|
178
|
-
path.join(PLUGIN_ROOT, 'output-styles', '
|
|
177
|
+
path.join(DATA_DIR, 'output-styles', 'simple.md'),
|
|
178
|
+
path.join(PLUGIN_ROOT, 'output-styles', 'simple.md'),
|
|
179
179
|
];
|
|
180
180
|
for (const candidate of fallback) {
|
|
181
181
|
const body = stripFrontmatter(readOptional(candidate));
|