mixdog 0.9.92 → 0.9.94

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 (103) hide show
  1. package/README.md +147 -51
  2. package/package.json +6 -5
  3. package/scripts/code-graph-description-contract.mjs +6 -8
  4. package/scripts/tmp-cdp-errors.mjs +41 -0
  5. package/scripts/tmp-cdp-inspect.mjs +41 -0
  6. package/scripts/tui-transcript-jitter-harness.mjs +2 -18
  7. package/src/rules/agent/00-core.md +1 -2
  8. package/src/rules/agent/30-explorer.md +22 -16
  9. package/src/rules/lead/01-general.md +1 -0
  10. package/src/rules/shared/01-tool.md +27 -25
  11. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +16 -3
  12. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +22 -6
  13. package/src/runtime/agent/orchestrator/agent-trace.mjs +17 -0
  14. package/src/runtime/agent/orchestrator/context/collect.mjs +8 -3
  15. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +9 -1
  16. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +79 -21
  17. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +40 -19
  18. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +18 -1
  19. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +75 -15
  20. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +44 -8
  21. package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +3 -0
  22. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
  23. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +22 -5
  24. package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +42 -2
  25. package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +35 -29
  26. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +11 -2
  27. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +5 -6
  28. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +31 -2
  29. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +60 -0
  30. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +60 -31
  31. package/src/runtime/agent/orchestrator/session/manager.mjs +1 -1
  32. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +12 -3
  33. package/src/runtime/agent/orchestrator/session/store/listing.mjs +17 -0
  34. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +101 -0
  35. package/src/runtime/agent/orchestrator/session/store.mjs +30 -0
  36. package/src/runtime/agent/orchestrator/session/tool-batch.mjs +119 -109
  37. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +98 -3
  38. package/src/runtime/agent/orchestrator/stall-policy.mjs +31 -21
  39. package/src/runtime/agent/orchestrator/tools/bash-session.mjs +3 -3
  40. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +3 -3
  41. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +8 -2
  42. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +16 -10
  43. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +12 -3
  44. package/src/runtime/agent/orchestrator/tools/builtin/grep-formatting.mjs +22 -0
  45. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +491 -0
  46. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-output.mjs +91 -13
  47. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +90 -27
  48. package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +6 -1
  49. package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +1 -1
  50. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +19 -9
  51. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +7 -2
  52. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +32 -4
  53. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +16 -1
  54. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +543 -19
  55. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +5 -2
  56. package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +3 -3
  57. package/src/runtime/agent/orchestrator/tools/builtin/tool-output-limit.mjs +48 -0
  58. package/src/runtime/agent/orchestrator/tools/builtin.mjs +71 -1
  59. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +4 -2
  60. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +51 -2
  61. package/src/runtime/agent/orchestrator/tools/code-graph/search-references.mjs +6 -17
  62. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +2 -4
  63. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +4 -3
  64. package/src/runtime/agent/orchestrator/tools/lib/pwsh-standby-pool.mjs +47 -14
  65. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +3 -3
  66. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +3 -3
  67. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +100 -0
  68. package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +6 -5
  69. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +9 -0
  70. package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +1 -1
  71. package/src/runtime/agent/orchestrator/tools/shell-state.mjs +32 -2
  72. package/src/runtime/channels/backends/discord-gateway.mjs +6 -32
  73. package/src/runtime/channels/lib/inbound-handler.mjs +19 -3
  74. package/src/runtime/channels/lib/scheduler.mjs +51 -3
  75. package/src/runtime/channels/lib/worker-main.mjs +4 -0
  76. package/src/runtime/channels/tool-defs.mjs +4 -2
  77. package/src/runtime/memory/lib/query-handlers.mjs +11 -3
  78. package/src/runtime/memory/lib/tool-call-handler.mjs +16 -1
  79. package/src/runtime/memory/tool-defs.mjs +5 -5
  80. package/src/runtime/shared/background-tasks.mjs +10 -3
  81. package/src/runtime/shared/channel-notification-routing.mjs +8 -2
  82. package/src/runtime/shared/child-spawn-gate.mjs +50 -26
  83. package/src/runtime/shared/llm/http-agent.mjs +11 -0
  84. package/src/runtime/shared/task-notification-envelope.mjs +11 -2
  85. package/src/runtime/shared/tool-card-model.mjs +6 -2
  86. package/src/runtime/shared/tool-surface.mjs +7 -2
  87. package/src/session-runtime/lifecycle-api.mjs +26 -1
  88. package/src/session-runtime/provider-usage.mjs +26 -2
  89. package/src/session-runtime/tool-catalog-data.mjs +5 -2
  90. package/src/session-runtime/workflow.mjs +7 -5
  91. package/src/standalone/agent-tool/tag-registry.mjs +5 -1
  92. package/src/standalone/explore-tool.mjs +2 -2
  93. package/src/tui/app/use-transcript-window.mjs +7 -1
  94. package/src/tui/components/Spinner.jsx +18 -9
  95. package/src/tui/dist/index.mjs +179 -70
  96. package/src/tui/engine/agent-envelope.mjs +52 -3
  97. package/src/tui/engine/live-share.mjs +23 -3
  98. package/src/tui/engine/session-api.mjs +7 -0
  99. package/src/tui/engine/turn.mjs +85 -13
  100. package/src/tui/engine.mjs +32 -47
  101. package/src/tui/index.jsx +7 -0
  102. package/src/workflows/solo/WORKFLOW.md +0 -6
  103. package/src/workflows/solo-bench/WORKFLOW.md +17 -0
package/README.md CHANGED
@@ -4,14 +4,17 @@
4
4
  ![node](https://img.shields.io/badge/node-%3E%3D22-brightgreen)
5
5
  ![license](https://img.shields.io/badge/license-MIT-blue)
6
6
 
7
- Standalone coding-agent CLI/TUI that runs an orchestrated, multi-provider
8
- agent workflow from one terminal — built for maximum performance at minimum
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 — 89.9% (self-reported)
31
+ ## Terminal-Bench 2.1 — controlled full-run comparisons
29
32
 
30
- ![Terminal-Bench 2.1 leaderboard with mixdog](https://raw.githubusercontent.com/tribgames/mixdog/main/benchmarks/terminal-bench-2.1/tb21-leaderboard.svg)
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
- Single-run score of **80/89 = 89.9%** (k=1) on
33
- `terminal-bench/terminal-bench-2-1`, using a cost-reduced per-role routing
34
- config:
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
- | Role | Model | Effort |
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
- Against published model scores this places second overall behind GPT-5.6
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
+ ![Terminal-Bench 2.1 comparison of mixdog with Claude Opus 5 and Claude Code](https://raw.githubusercontent.com/tribgames/mixdog/main/benchmarks/terminal-bench-2.1/tb21-opus-vs-claude-code.svg)
51
50
 
52
- Full transparency: 4 tasks refused by the primary model's safety layer were
53
- re-run routed to Claude Opus 4.8 (effort xhigh) and passed; timeouts and
54
- task resources were left unmodified. Raw Harbor `result.json`/`config.json`
55
- for every constituent run are included.
51
+ #### GPT-5.6 Sol xhigh vs Codex CLI
52
+
53
+ ![Terminal-Bench 2.1 comparison of mixdog with GPT-5.6 Sol xhigh and Codex CLI](https://raw.githubusercontent.com/tribgames/mixdog/main/benchmarks/terminal-bench-2.1/tb21-sol-vs-codex.svg)
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
- OAuth-backed providers, OpenAI-compatible APIs, Ollama, and LM Studio/local
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
- - Optional Discord/Telegram channels, webhook endpoints, cron schedules, and
85
- voice-message transcription for remote/event-driven workflows.
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
- - Lightweight memory restores prior work context across sessions.
90
- - Important memories are automatically promoted and demoted when stale.
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, and explorer roles.
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 package is limited by `package.json#files` to:
220
-
221
- ```text
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.92",
3
+ "version": "0.9.94",
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.27.0"
154
+ "undici": "6.28.0"
154
155
  },
155
156
  "@discordjs/rest": {
156
- "undici": "6.27.0"
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
- && hasModeClause(description, 'symbol modes', SYMBOL_MODES, 'symbols[]')
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', ...EXACT_MODES])
156
- && hasPositiveClause(symbolsDescription, ['keywords', ...KEYWORD_MODES])
157
- && hasPositiveClause(symbolsDescription, ['multiple exact symbols', 'one symbols[] call'])
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);
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { build } from 'esbuild';
3
- import { readFile, rm } from 'node:fs/promises';
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, growthProbe],
31
+ plugins: [inkAlias],
48
32
  banner: {
49
33
  js: "import { createRequire as __mixdogCreateRequire } from 'node:module';\nconst require = __mixdogCreateRequire(import.meta.url);",
50
34
  },
@@ -1,7 +1,6 @@
1
1
  # Agent Constraints
2
2
 
3
- - Agent communication is English. One turn is one batch; include every
4
- compatible read-only call.
3
+ - Agent communication is English.
5
4
  - Call tools immediately: no preamble/progress; text only in final handoff.
6
5
  - Final handoff is fragments: outcome, key `file:line`, verification
7
6
  command+result, material risk/blocker. Never repeat the brief, process,
@@ -9,22 +9,28 @@ kind: retrieval
9
9
  Return only WHERE (`path:line`), never WHY. You ARE `explore`; never call it.
10
10
  Use only grep/find/glob/code_graph; `read` and `list` are forbidden.
11
11
 
12
- Turn 1 (`turn 1/3`) is the whole search. Split broad/uncertain input into every
13
- known facet and send one batch under the shared one-route contract. Use
14
- `pattern[]` with 4–8 code-token variants for concept facets, `code_graph`
15
- `symbol_search` for symbol facets, and `find` `query[]` for unknown/broad
16
- targets or unverified path/name fragments. For a symptom/behavior query, add
17
- the upstream producer/derivation layer of the reported surface as extra facets
18
- in the SAME batch (more `pattern[]` variants or `code_graph` `symbol_search`),
19
- never as a later turn. Follow-up turns batch every unresolved facet in
20
- parallel; a single-tool turn is allowed only when exactly one
21
- pre-anchor/zero-hit facet remains.
22
-
23
- For broad grep use `output_mode:"files_with_matches"`. Use
24
- `content_with_context` with `head_limit` only on paths returned this session.
25
- Each pattern is one identifier, camel/snake variant, or concept synonym; never
26
- a prose phrase. Spaces and non-ASCII are allowed only in verbatim quoted
27
- error/log literals. Translate other non-English queries to English identifiers.
12
+ Turn 1 (`turn 1/3`) is the whole search and should already mint anchors. Split
13
+ broad/uncertain input into every known facet and send one batch under the
14
+ shared one-route contract. Route each facet to the cheapest anchor source:
15
+ `code_graph` `symbol_search` whenever the facet names a plausible
16
+ symbol/identifier; grep `content_with_context` with `pattern[]` of 4–8
17
+ code-token variants for concept facets its hits carry `path:line`, cite them
18
+ directly instead of re-mining; `find` `query[]` ONLY when the target is itself
19
+ a file/dir name or an unverified path fragment, never as a default extra
20
+ facet. For a symptom/behavior query, add the upstream producer/derivation
21
+ layer of the reported surface as extra facets in the SAME batch, never as a
22
+ later turn. Follow-up turns batch every unresolved facet in parallel; a
23
+ single-tool turn is allowed only when exactly one pre-anchor/zero-hit facet
24
+ remains.
25
+
26
+ Grep defaults to `output_mode:"content_with_context"` with `context:0`
27
+ (matches only the match line already carries its citable `path:line`) and a
28
+ tight `head_limit` (≤20); never request surrounding context lines. Use
29
+ `files_with_matches` only as a cheap existence probe when a facet must be
30
+ scoped before searching. Each pattern is one identifier, camel/snake variant,
31
+ or concept synonym; never a prose phrase. Spaces and non-ASCII are allowed
32
+ only in verbatim quoted error/log literals. Translate other non-English
33
+ queries to English identifiers.
28
34
 
29
35
  Scope is session cwd; `path` may be omitted. For unverified `src` paths, use
30
36
  `find` first; never guess or invent directories or pair `path:"."` with guessed
@@ -8,6 +8,7 @@
8
8
  validated target paths — never `~`, a root, or unresolved variables/globs;
9
9
  report material deletions with recoverability.
10
10
  - Act proactively; ask only for decisions.
11
+ - Build only what the task requires; trust internal and framework guarantees.
11
12
  - Mid-task input: a replacement supersedes current work, an addition folds
12
13
  into it, a status question gets a brief answer while work continues; after
13
14
  context compaction continue from the summary — never restart or redo