mixdog 0.9.0 → 0.9.2
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/package.json +10 -3
- package/scripts/_bench-cwc.json +20 -0
- package/scripts/agent-loop-policy-test.mjs +37 -0
- package/scripts/agent-parallel-smoke.mjs +54 -10
- package/scripts/background-task-meta-smoke.mjs +1 -1
- package/scripts/bench-run.mjs +262 -0
- package/scripts/compact-smoke.mjs +12 -0
- package/scripts/compact-trigger-migration-smoke.mjs +67 -1
- package/scripts/ingest-pure-conversation-smoke.mjs +148 -0
- package/scripts/internal-comms-bench.mjs +727 -0
- package/scripts/internal-comms-smoke.mjs +75 -0
- package/scripts/lead-workflow-smoke.mjs +4 -4
- package/scripts/live-worker-smoke.mjs +9 -9
- package/scripts/output-style-bench.mjs +285 -0
- package/scripts/output-style-smoke.mjs +13 -10
- package/scripts/patch-replay.mjs +90 -0
- package/scripts/provider-stream-stall-test.mjs +276 -0
- package/scripts/provider-toolcall-test.mjs +599 -1
- package/scripts/routing-corpus.mjs +281 -0
- package/scripts/session-bench.mjs +1526 -0
- package/scripts/session-diag.mjs +595 -0
- package/scripts/session-ingest-smoke.mjs +2 -2
- package/scripts/task-bench.mjs +207 -0
- package/scripts/tool-failures.mjs +6 -6
- package/scripts/tool-smoke.mjs +306 -66
- package/scripts/toolcall-args-test.mjs +81 -0
- package/src/agents/debugger/AGENT.md +4 -4
- package/src/agents/heavy-worker/AGENT.md +4 -2
- package/src/agents/reviewer/AGENT.md +4 -4
- package/src/agents/worker/AGENT.md +4 -2
- package/src/app.mjs +10 -6
- package/src/defaults/{hidden-roles.json → agents.json} +7 -7
- package/src/examples/schedules/SCHEDULE.example.md +32 -0
- package/src/examples/webhooks/WEBHOOK.example.md +40 -0
- package/src/headless-role.mjs +14 -14
- package/src/help.mjs +1 -0
- package/src/lib/mixdog-debug.cjs +0 -22
- package/src/lib/plugin-paths.cjs +1 -7
- package/src/lib/rules-builder.cjs +34 -56
- package/src/mixdog-session-runtime.mjs +710 -319
- package/src/output-styles/default.md +12 -7
- package/src/output-styles/minimal.md +25 -0
- package/src/output-styles/oneline.md +21 -0
- package/src/output-styles/simple.md +10 -9
- package/src/repl.mjs +12 -4
- package/src/rules/agent/00-common.md +7 -5
- package/src/rules/agent/30-explorer.md +7 -8
- package/src/rules/lead/01-general.md +3 -1
- package/src/rules/lead/lead-tool.md +7 -0
- package/src/rules/shared/01-tool.md +17 -12
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +90 -32
- package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +32 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +18 -6
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +23 -20
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +48 -14
- package/src/runtime/agent/orchestrator/agent-trace.mjs +87 -12
- package/src/runtime/agent/orchestrator/config.mjs +3 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +131 -67
- package/src/runtime/agent/orchestrator/{internal-roles.mjs → internal-agents.mjs} +72 -72
- package/src/runtime/agent/orchestrator/internal-tools.mjs +13 -26
- package/src/runtime/agent/orchestrator/mcp/client.mjs +94 -16
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +188 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-leaked-toolcall.mjs +444 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +359 -106
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +63 -51
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +27 -20
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +184 -17
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +8 -1
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +18 -8
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +210 -21
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +86 -30
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +254 -280
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +191 -50
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +18 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +11 -5
- package/src/runtime/agent/orchestrator/providers/registry.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +265 -1
- package/src/runtime/agent/orchestrator/session/compact.mjs +560 -51
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +250 -3
- package/src/runtime/agent/orchestrator/session/loop.mjs +394 -132
- package/src/runtime/agent/orchestrator/session/manager.mjs +217 -170
- package/src/runtime/agent/orchestrator/session/store.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/tool-envelope.mjs +61 -0
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +5 -0
- package/src/runtime/agent/orchestrator/stall-policy.mjs +63 -15
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +194 -32
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +143 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +1 -44
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +34 -18
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +0 -0
- package/src/runtime/agent/orchestrator/tools/builtin/list-formatting.mjs +10 -0
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +5 -4
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +15 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +9 -44
- package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +13 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +10 -17
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +18 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/builtin/tool-output-limit.mjs +10 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +59 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4076 -3985
- package/src/runtime/agent/orchestrator/tools/patch.mjs +116 -2
- package/src/runtime/channels/backends/discord.mjs +99 -9
- package/src/runtime/channels/backends/telegram.mjs +501 -0
- package/src/runtime/channels/index.mjs +441 -1254
- package/src/runtime/channels/lib/cli-worker-host.mjs +1 -8
- package/src/runtime/channels/lib/config.mjs +54 -3
- package/src/runtime/channels/lib/drop-trace.mjs +1 -1
- package/src/runtime/channels/lib/executor.mjs +0 -3
- package/src/runtime/channels/lib/format.mjs +4 -2
- package/src/runtime/channels/lib/memory-client.mjs +0 -38
- package/src/runtime/channels/lib/output-forwarder.mjs +77 -71
- package/src/runtime/channels/lib/runtime-paths.mjs +29 -6
- package/src/runtime/channels/lib/scheduler.mjs +1 -1
- package/src/runtime/channels/lib/session-discovery.mjs +0 -4
- package/src/runtime/channels/lib/telegram-format.mjs +283 -0
- package/src/runtime/channels/lib/tool-format.mjs +1 -2
- package/src/runtime/channels/lib/transcript-discovery.mjs +20 -11
- package/src/runtime/channels/lib/webhook.mjs +59 -31
- package/src/runtime/channels/tool-defs.mjs +1 -1
- package/src/runtime/lib/keychain-cjs.cjs +0 -1
- package/src/runtime/memory/data/runtime-manifest.json +6 -7
- package/src/runtime/memory/index.mjs +187 -43
- package/src/runtime/memory/lib/agent-ipc.mjs +2 -2
- package/src/runtime/memory/lib/core-memory-store.mjs +1 -1
- package/src/runtime/memory/lib/llm-worker-host.mjs +0 -4
- package/src/runtime/memory/lib/memory-cycle1.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2.mjs +9 -6
- package/src/runtime/memory/lib/memory-cycle3.mjs +1 -1
- package/src/runtime/memory/lib/memory-ops-policy.mjs +0 -1
- package/src/runtime/memory/lib/memory.mjs +101 -4
- package/src/runtime/memory/lib/pg/adapter.mjs +139 -15
- package/src/runtime/memory/lib/runtime-fetcher.mjs +43 -18
- package/src/runtime/memory/lib/session-ingest.mjs +116 -7
- package/src/runtime/memory/lib/trace-store.mjs +69 -22
- package/src/runtime/memory/tool-defs.mjs +6 -3
- package/src/runtime/search/index.mjs +2 -7
- package/src/runtime/search/lib/config.mjs +0 -4
- package/src/runtime/search/lib/state.mjs +1 -15
- package/src/runtime/search/lib/web-tools.mjs +0 -1
- package/src/runtime/shared/channel-notification-routing.mjs +12 -0
- package/src/runtime/shared/channel-notification-routing.test.mjs +45 -0
- package/src/runtime/shared/child-spawn-gate.mjs +0 -6
- package/src/runtime/shared/config.mjs +9 -0
- package/src/runtime/shared/llm/http-agent.mjs +12 -5
- package/src/runtime/shared/schedules-store.mjs +21 -19
- package/src/runtime/shared/tool-surface.mjs +98 -13
- package/src/runtime/shared/transcript-writer.mjs +129 -0
- package/src/runtime/shared/update-checker.mjs +214 -0
- package/src/standalone/agent-tool.mjs +255 -109
- package/src/standalone/channel-admin.mjs +133 -40
- package/src/standalone/channel-worker.mjs +8 -291
- package/src/standalone/explore-tool.mjs +2 -2
- package/src/standalone/memory-runtime-proxy.mjs +3 -1
- package/src/standalone/provider-admin.mjs +11 -0
- package/src/standalone/seeds.mjs +1 -11
- package/src/standalone/usage-dashboard.mjs +1 -1
- package/src/tui/App.jsx +2137 -750
- package/src/tui/components/ConfirmBar.jsx +47 -0
- package/src/tui/components/ContextPanel.jsx +5 -3
- package/src/tui/components/ItemRightHintOverprint.jsx +54 -0
- package/src/tui/components/Markdown.jsx +22 -98
- package/src/tui/components/Message.jsx +14 -35
- package/src/tui/components/Picker.jsx +87 -12
- package/src/tui/components/PromptInput.jsx +146 -9
- package/src/tui/components/QueuedCommands.jsx +1 -1
- package/src/tui/components/SlashCommandPalette.jsx +8 -5
- package/src/tui/components/Spinner.jsx +7 -7
- package/src/tui/components/StatusLine.jsx +40 -21
- package/src/tui/components/TextEntryPanel.jsx +51 -7
- package/src/tui/components/ToolExecution.jsx +177 -100
- package/src/tui/components/TurnDone.jsx +4 -4
- package/src/tui/components/UsagePanel.jsx +1 -1
- package/src/tui/components/tool-output-format.mjs +312 -40
- package/src/tui/components/tool-output-format.test.mjs +180 -1
- package/src/tui/display-width.mjs +69 -0
- package/src/tui/display-width.test.mjs +35 -0
- package/src/tui/dist/index.mjs +7324 -2393
- package/src/tui/engine.mjs +287 -126
- package/src/tui/index.jsx +117 -7
- package/src/tui/keyboard-protocol.mjs +42 -0
- package/src/tui/lib/voice-recorder.mjs +453 -0
- package/src/tui/markdown/format-token.mjs +354 -142
- package/src/tui/markdown/format-token.test.mjs +155 -17
- package/src/tui/markdown/measure-rendered-rows.mjs +85 -0
- package/src/tui/markdown/render-ansi.test.mjs +1 -1
- package/src/tui/markdown/streaming-markdown.mjs +167 -0
- package/src/tui/markdown/streaming-markdown.test.mjs +70 -0
- package/src/tui/markdown/table-layout.mjs +9 -9
- package/src/tui/paste-attachments.mjs +0 -11
- package/src/tui/prompt-history-store.mjs +129 -0
- package/src/tui/prompt-history-store.test.mjs +52 -0
- package/src/tui/statusline-ansi-bridge.test.mjs +3 -3
- package/src/tui/theme.mjs +41 -647
- package/src/tui/themes/base.mjs +86 -0
- package/src/tui/themes/basic.mjs +85 -0
- package/src/tui/themes/catppuccin.mjs +72 -0
- package/src/tui/themes/dracula.mjs +70 -0
- package/src/tui/themes/everforest.mjs +71 -0
- package/src/tui/themes/gruvbox.mjs +71 -0
- package/src/tui/themes/index.mjs +71 -0
- package/src/tui/themes/indigo.mjs +78 -0
- package/src/tui/themes/kanagawa.mjs +80 -0
- package/src/tui/themes/light.mjs +81 -0
- package/src/tui/themes/nord.mjs +72 -0
- package/src/tui/themes/onedark.mjs +16 -0
- package/src/tui/themes/rosepine.mjs +70 -0
- package/src/tui/themes/teal.mjs +81 -0
- package/src/tui/themes/tokyonight.mjs +79 -0
- package/src/tui/themes/utils.mjs +106 -0
- package/src/tui/themes/warm.mjs +79 -0
- package/src/tui/transcript-tool-failures.mjs +13 -2
- package/src/ui/markdown.mjs +1 -1
- package/src/ui/model-display.mjs +2 -2
- package/src/ui/statusline.mjs +26 -27
- package/src/vendor/statusline/bin/statusline-lib.mjs +0 -623
- package/src/vendor/statusline/bin/statusline-route.mjs +5 -12
- package/src/vendor/statusline/src/gateway/claude-current.mjs +3 -3
- package/src/vendor/statusline/src/gateway/route-meta.mjs +30 -16
- package/src/workflows/default/WORKFLOW.md +39 -12
- package/src/workflows/sequential/WORKFLOW.md +46 -0
- package/src/workflows/solo/WORKFLOW.md +7 -0
- package/vendor/ink/build/display-width.js +62 -0
- package/vendor/ink/build/ink.js +154 -20
- package/vendor/ink/build/measure-text.js +4 -1
- package/vendor/ink/build/output.js +115 -9
- package/vendor/ink/build/render-node-to-output.js +4 -1
- package/vendor/ink/build/render.js +4 -0
- package/src/hooks/lib/permission-rules.cjs +0 -170
- package/src/hooks/lib/settings-loader.cjs +0 -112
- package/src/lib/hook-pipe-path.cjs +0 -10
- package/src/output-styles/extreme-simple.md +0 -20
- package/src/rules/lead/04-workflow.md +0 -51
- package/src/runtime/channels/lib/hook-pipe-server.mjs +0 -671
- package/src/workflows/default/workflow.json +0 -13
- package/src/workflows/solo/workflow.json +0 -7
|
@@ -119,7 +119,7 @@ export function resolveClaudeModelAlias(model) {
|
|
|
119
119
|
if (!raw) return null;
|
|
120
120
|
const stripped = stripClaudeContextSuffix(raw);
|
|
121
121
|
if (/^claude-/i.test(stripped)) return stripped;
|
|
122
|
-
const family = stripped.match(/^(opus|sonnet|haiku)(?:[-_].*)?$/i)?.[1]?.toLowerCase();
|
|
122
|
+
const family = stripped.match(/^(opus|sonnet|haiku|fable)(?:[-_].*)?$/i)?.[1]?.toLowerCase();
|
|
123
123
|
if (family) return familyDefaultModel(family);
|
|
124
124
|
return null;
|
|
125
125
|
}
|
|
@@ -128,11 +128,11 @@ export function displayClaudeModel(model, raw = '', display = '') {
|
|
|
128
128
|
const explicit = cleanString(display);
|
|
129
129
|
if (explicit) return explicit;
|
|
130
130
|
const id = cleanString(model) || resolveClaudeModelAlias(raw) || cleanString(raw);
|
|
131
|
-
const m = id.match(/^claude-(opus|sonnet|haiku)-(\d+)
|
|
131
|
+
const m = id.match(/^claude-(opus|sonnet|haiku|fable)-(\d+)(?:-(\d+))?(?:-\d{8})?$/i);
|
|
132
132
|
if (m) {
|
|
133
133
|
const family = `${m[1][0].toUpperCase()}${m[1].slice(1).toLowerCase()}`;
|
|
134
134
|
const suffix = /\[1m\]/i.test(raw) || contextWindowFromRawModel(raw, id) === 1000000 ? ' (1M context)' : '';
|
|
135
|
-
return `${family} ${m[2]}
|
|
135
|
+
return `${family} ${m[2]}${m[3] ? `.${m[3]}` : ''}${suffix}`;
|
|
136
136
|
}
|
|
137
137
|
return id || raw || '';
|
|
138
138
|
}
|
|
@@ -254,8 +254,8 @@ function displayForModel(provider, model, info) {
|
|
|
254
254
|
const display = cleanString(info?.display) || cleanString(info?.displayName) || cleanString(info?.name);
|
|
255
255
|
if (display) return display;
|
|
256
256
|
if (provider === 'anthropic-oauth') {
|
|
257
|
-
const m = String(model || '').match(/^claude-(opus|sonnet|haiku)-(\d+)
|
|
258
|
-
if (m) return `${m[1][0].toUpperCase()}${m[1].slice(1).toLowerCase()} ${m[2]}
|
|
257
|
+
const m = String(model || '').match(/^claude-(opus|sonnet|haiku|fable)-(\d+)(?:-(\d+))?/i);
|
|
258
|
+
if (m) return `${m[1][0].toUpperCase()}${m[1].slice(1).toLowerCase()} ${m[2]}${m[3] ? `.${m[3]}` : ''}`;
|
|
259
259
|
}
|
|
260
260
|
return model || '';
|
|
261
261
|
}
|
|
@@ -343,25 +343,44 @@ export function readGatewayRouteInfo(seed = {}, providerObj = null) {
|
|
|
343
343
|
};
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
-
|
|
347
|
-
|
|
346
|
+
// Boundary denominator for status %, overflow checks, and gateway env window.
|
|
347
|
+
// Order: explicit boundary (routeInfo or compact) → contextWindow → budgetWindow
|
|
348
|
+
// → rawContextWindow. autoCompactTokenLimit / compactLimitTokens are triggers
|
|
349
|
+
// only and are never read here.
|
|
350
|
+
export function compactBoundaryDenominator(routeInfo = {}, compact = null) {
|
|
351
|
+
const fromRoute = num(
|
|
352
|
+
routeInfo?.compactBoundaryTokens
|
|
353
|
+
?? routeInfo?.compact_boundary_tokens
|
|
354
|
+
?? routeInfo?.boundaryTokens,
|
|
355
|
+
0,
|
|
356
|
+
);
|
|
357
|
+
const fromCompact = num(
|
|
358
|
+
compact?.boundaryTokens
|
|
359
|
+
?? compact?.compactBoundaryTokens
|
|
360
|
+
?? compact?.compact_boundary_tokens,
|
|
361
|
+
0,
|
|
362
|
+
);
|
|
363
|
+
const boundaryTokens = fromRoute > 0 ? fromRoute : fromCompact;
|
|
348
364
|
const contextWindow = num(routeInfo?.contextWindow ?? compact?.contextWindow, 0);
|
|
349
365
|
const budgetWindow = num(compact?.budgetWindow, 0);
|
|
350
366
|
const rawContextWindow = num(routeInfo?.rawContextWindow ?? compact?.rawContextWindow, 0);
|
|
351
|
-
if (
|
|
352
|
-
if (compactLimit > 0) return compactLimit;
|
|
353
|
-
if (budgetWindow > 0 && contextWindow > 0) return Math.min(budgetWindow, contextWindow);
|
|
354
|
-
if (budgetWindow > 0) return budgetWindow;
|
|
367
|
+
if (boundaryTokens > 0) return boundaryTokens;
|
|
355
368
|
if (contextWindow > 0) return contextWindow;
|
|
369
|
+
if (budgetWindow > 0) return budgetWindow;
|
|
356
370
|
return rawContextWindow > 0 ? rawContextWindow : 0;
|
|
357
371
|
}
|
|
358
372
|
|
|
373
|
+
function compactBoundaryForRoute(routeInfo = {}, compact = null) {
|
|
374
|
+
return compactBoundaryDenominator(routeInfo, compact);
|
|
375
|
+
}
|
|
376
|
+
|
|
359
377
|
// Single source of truth for the value synced to host env
|
|
360
378
|
// CLAUDE_CODE_AUTO_COMPACT_WINDOW. BOTH the --enable-time write
|
|
361
379
|
// (scripts/gateway-model.mjs) and the runtime sync (src/gateway/server.mjs)
|
|
362
380
|
// must derive the window the SAME way, or they disagree on the value written to
|
|
363
|
-
// settings.json.
|
|
364
|
-
//
|
|
381
|
+
// settings.json. Denominator order: compactBoundaryTokens / boundaryTokens (route
|
|
382
|
+
// or compact) → contextWindow → budgetWindow → rawContextWindow. Never
|
|
383
|
+
// autoCompactTokenLimit or compactLimitTokens (trigger-only). Returns a positive
|
|
365
384
|
// integer, or null when unknown.
|
|
366
385
|
export function autoCompactWindowForRoute(routeInfo) {
|
|
367
386
|
const n = compactBoundaryForRoute(routeInfo);
|
|
@@ -428,12 +447,7 @@ function usageCostUsd(routeInfo, usage) {
|
|
|
428
447
|
}
|
|
429
448
|
|
|
430
449
|
function contextUsageBoundary(routeInfo, compact = null) {
|
|
431
|
-
|
|
432
|
-
const budgetWindow = num(compact?.budgetWindow, 0);
|
|
433
|
-
const rawContextWindow = num(routeInfo?.rawContextWindow ?? compact?.rawContextWindow, 0);
|
|
434
|
-
if (contextWindow > 0) return contextWindow;
|
|
435
|
-
if (budgetWindow > 0) return budgetWindow;
|
|
436
|
-
return rawContextWindow > 0 ? rawContextWindow : compactBoundaryForRoute(routeInfo, compact);
|
|
450
|
+
return compactBoundaryDenominator(routeInfo, compact);
|
|
437
451
|
}
|
|
438
452
|
|
|
439
453
|
export function summarizeGatewayUsage(routeInfo, providerOut, compact = null, durationMs = null) {
|
|
@@ -1,14 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: default
|
|
3
|
+
name: Default
|
|
4
|
+
description: "Default agent workflow — fan-out parallel delegation across independent scopes."
|
|
5
|
+
agents: worker, heavy-worker, reviewer, debugger, maintainer
|
|
6
|
+
---
|
|
7
|
+
|
|
1
8
|
# Default Workflow
|
|
2
9
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
Lead supervises: delegates, coordinates, judges, decides. Route by complexity:
|
|
11
|
+
- Lead handles directly: simple 1–2 step work, plus coordination, pre-planning,
|
|
12
|
+
config changes, and final git deployment.
|
|
13
|
+
- Worker: implementation that takes several steps.
|
|
14
|
+
- Heavy Worker: high-complexity, multi-step implementation.
|
|
15
|
+
- Reviewer: verify implementation scopes (diff, regressions, missing checks).
|
|
16
|
+
- Debugger: deploy for very high complexity, or when root-causing has already
|
|
17
|
+
failed at least once.
|
|
18
|
+
|
|
19
|
+
1. Plan — discuss the request with the user, form a plan, and wait for approval.
|
|
20
|
+
2. Delegate — split into the maximum number of independent scopes.
|
|
21
|
+
- PARALLEL across independent scopes by default (implementation, analysis,
|
|
22
|
+
review, debugging split alike). Spawn every scope in the SAME turn. Shared
|
|
23
|
+
or cross-cutting code does NOT justify merging: split per path and verify
|
|
24
|
+
the shared parts yourself. The only single scope is a genuinely
|
|
25
|
+
inseparable dependency — then state it.
|
|
26
|
+
- SEQUENTIAL within a single complex scope — split it into ordered steps
|
|
27
|
+
rather than handing it off in one shot, with a build/test-green gate
|
|
28
|
+
between steps.
|
|
29
|
+
- Reuse the existing agent (same tag) for follow-up on the same scope; spawn
|
|
30
|
+
new only for a separate scope. Write briefs per the lead-tool brief
|
|
31
|
+
contract (token-optimized labeled fragments).
|
|
32
|
+
- After spawning async agent(s), END THE TURN — do not poll, guess, or start
|
|
33
|
+
dependent work until the completion notification resumes you (status/read
|
|
34
|
+
are manual recovery only). Then wait and continue automatically.
|
|
35
|
+
3. Review — pair one reviewer 1:1 with each implementation scope, spawned in the
|
|
36
|
+
same turn. Cross-check implementation and review results yourself before
|
|
37
|
+
acting on them. Send fixes back to the original scope and repeat until clean.
|
|
38
|
+
Skip review only for simple, low-risk tasks.
|
|
39
|
+
4. Report — deliver the final report: synthesize results (outcome + key
|
|
40
|
+
evidence; never forward raw agent output), state the final state, and ask the
|
|
41
|
+
user whether to ship/deploy when relevant.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: sequential
|
|
3
|
+
name: Sequential
|
|
4
|
+
description: "Sequential workflow — delegates 1:1 with no fan-out; one agent at a time."
|
|
5
|
+
agents: worker, heavy-worker, reviewer, debugger, maintainer
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Sequential Workflow
|
|
9
|
+
|
|
10
|
+
Unlike Default, which fans out independent scopes in parallel, this mode runs
|
|
11
|
+
with no fan-out: it delegates one scope at a time, 1:1, and only moves to the
|
|
12
|
+
next after the current one completes.
|
|
13
|
+
|
|
14
|
+
Lead supervises: delegates, coordinates, judges, decides. Route by complexity:
|
|
15
|
+
- Lead handles directly: simple 1–2 step work, plus coordination, pre-planning,
|
|
16
|
+
config changes, and final git deployment.
|
|
17
|
+
- Worker: implementation that takes several steps.
|
|
18
|
+
- Heavy Worker: high-complexity, multi-step implementation.
|
|
19
|
+
- Reviewer: verify implementation scopes (diff, regressions, missing checks).
|
|
20
|
+
- Debugger: deploy for very high complexity, or when root-causing has already
|
|
21
|
+
failed at least once.
|
|
22
|
+
|
|
23
|
+
1. Plan — discuss the request with the user, form a plan, and wait for approval.
|
|
24
|
+
2. Delegate — split into ordered scopes and hand them off ONE AT A TIME.
|
|
25
|
+
- NO PARALLEL, NO FAN-OUT. Even when scopes are independent, spawn exactly
|
|
26
|
+
one agent per turn; never spawn multiple agents in the same turn. Wait for
|
|
27
|
+
the current scope's completion notification before spawning the next scope
|
|
28
|
+
(1:1 sequential).
|
|
29
|
+
- SEQUENTIAL within a single complex scope — split it into ordered steps
|
|
30
|
+
rather than handing it off in one shot, with a build/test-green gate
|
|
31
|
+
between steps.
|
|
32
|
+
- Reuse the existing agent (same tag) for follow-up on the same scope; spawn
|
|
33
|
+
new only for a separate scope. Write briefs per the lead-tool brief
|
|
34
|
+
contract (token-optimized labeled fragments).
|
|
35
|
+
- After spawning an async agent, END THE TURN — do not poll, guess, or start
|
|
36
|
+
dependent or subsequent work until the completion notification resumes you
|
|
37
|
+
(status/read are manual recovery only). Then wait and continue
|
|
38
|
+
automatically.
|
|
39
|
+
3. Review — after each implementation scope completes, pair one reviewer 1:1
|
|
40
|
+
with that scope (spawned on its own turn, not batched). Cross-check
|
|
41
|
+
implementation and review results yourself before acting on them. Send fixes
|
|
42
|
+
back to the original scope and repeat until clean. Skip review only for
|
|
43
|
+
simple, low-risk tasks.
|
|
44
|
+
4. Report — deliver the final report: synthesize results (outcome + key
|
|
45
|
+
evidence; never forward raw agent output), state the final state, and ask the
|
|
46
|
+
user whether to ship/deploy when relevant.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* display-width.js — [mixdog fork] vendored copy of the shared display-width
|
|
3
|
+
* policy from src/tui/display-width.mjs.
|
|
4
|
+
*
|
|
5
|
+
* MUST STAY IN SYNC with src/tui/display-width.mjs. ink is aliased as an
|
|
6
|
+
* external bundle (see scripts/build-tui.mjs), so it cannot cleanly import from
|
|
7
|
+
* src; the small policy is replicated here verbatim instead. If the problem
|
|
8
|
+
* ranges or the WT_SESSION/MIXDOG_TUI_AMBIGUOUS_WIDE gate change there, change
|
|
9
|
+
* them here too — ink's MEASUREMENT must agree with OUR wrap/row math or the
|
|
10
|
+
* overlap gets worse, not better.
|
|
11
|
+
*
|
|
12
|
+
* Policy: widen ONLY U+2460–U+24FF (enclosed alphanumerics / circled digits)
|
|
13
|
+
* and U+2190–U+21FF (arrows) to 2 cells when ON. NEVER widen box-drawing
|
|
14
|
+
* (U+2500–U+257F), block elements, or other ambiguous glyphs. ON by default
|
|
15
|
+
* only under Windows Terminal (WT_SESSION); MIXDOG_TUI_AMBIGUOUS_WIDE='1'/'0'
|
|
16
|
+
* overrides and wins. OFF ⇒ identical to plain string-width.
|
|
17
|
+
*/
|
|
18
|
+
import stringWidth from 'string-width';
|
|
19
|
+
|
|
20
|
+
function isProblemCodePoint(cp) {
|
|
21
|
+
return (cp >= 0x2460 && cp <= 0x24ff) || (cp >= 0x2190 && cp <= 0x21ff);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function resolveAmbiguousWidePolicy(env = process.env) {
|
|
25
|
+
const override = env?.MIXDOG_TUI_AMBIGUOUS_WIDE;
|
|
26
|
+
if (override === '1')
|
|
27
|
+
return true;
|
|
28
|
+
if (override === '0')
|
|
29
|
+
return false;
|
|
30
|
+
return Boolean(env?.WT_SESSION);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Resolved once at module load (matches src/tui/display-width.mjs).
|
|
34
|
+
export const AMBIGUOUS_WIDE = resolveAmbiguousWidePolicy();
|
|
35
|
+
|
|
36
|
+
export function displayWidthWith(str, wide) {
|
|
37
|
+
const s = String(str ?? '');
|
|
38
|
+
const base = stringWidth(s);
|
|
39
|
+
if (!wide)
|
|
40
|
+
return base;
|
|
41
|
+
let extra = 0;
|
|
42
|
+
for (const ch of s) {
|
|
43
|
+
const cp = ch.codePointAt(0);
|
|
44
|
+
if (isProblemCodePoint(cp) && stringWidth(ch) === 1)
|
|
45
|
+
extra += 1;
|
|
46
|
+
}
|
|
47
|
+
return base + extra;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Visible display width under the resolved policy (ink-side stringWidth). */
|
|
51
|
+
export function displayStringWidth(str) {
|
|
52
|
+
return displayWidthWith(str, AMBIGUOUS_WIDE);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** widest-line equivalent under the policy. */
|
|
56
|
+
export function displayWidestLine(text) {
|
|
57
|
+
let lineWidth = 0;
|
|
58
|
+
for (const line of String(text ?? '').split('\n')) {
|
|
59
|
+
lineWidth = Math.max(lineWidth, displayStringWidth(line));
|
|
60
|
+
}
|
|
61
|
+
return lineWidth;
|
|
62
|
+
}
|
package/vendor/ink/build/ink.js
CHANGED
|
@@ -85,7 +85,7 @@ const stripKittyQueryResponsesAndTrailingPartial = (buffer) => {
|
|
|
85
85
|
// desynchronizes the incremental erase used for frames that exactly fill the
|
|
86
86
|
// viewport, leaving stale copies of previous frames behind (#969). Keep the
|
|
87
87
|
// pre-7.0 behavior of fully clearing between fullscreen frames there.
|
|
88
|
-
const isWindowsConsole = process.platform === 'win32';
|
|
88
|
+
const isWindowsConsole = process.platform === 'win32' || Boolean(process.env.WT_SESSION);
|
|
89
89
|
const shouldClearTerminalForFrame = ({ isTty, viewportRows, previousOutputHeight, nextOutputHeight, isUnmounting, }) => {
|
|
90
90
|
if (!isTty) {
|
|
91
91
|
return false;
|
|
@@ -181,6 +181,11 @@ export default class Ink {
|
|
|
181
181
|
// cells ({ x1, y1, x2, y2 } inclusive, normalized) or null. The App sets it
|
|
182
182
|
// via setSelection(); onRender forwards it to the renderer for highlighting.
|
|
183
183
|
selectionRect = null;
|
|
184
|
+
// [mixdog fork] Coalesce drag-selection repaints when a frame is pending.
|
|
185
|
+
isRendering = false;
|
|
186
|
+
selectionRepaintQueued = false;
|
|
187
|
+
selectionRepaintFlushPending = false;
|
|
188
|
+
selectionRepaintEpoch = 0;
|
|
184
189
|
// [mixdog fork] text under the current selection rect, refreshed every render
|
|
185
190
|
// from the output grid. Read back via getSelectionText() on drag-release.
|
|
186
191
|
selectedText = null;
|
|
@@ -318,9 +323,9 @@ export default class Ink {
|
|
|
318
323
|
this.log.setCursorPosition(position);
|
|
319
324
|
};
|
|
320
325
|
// [mixdog fork] Update the mouse drag-selection rectangle and repaint so the
|
|
321
|
-
// inverse highlight tracks the drag
|
|
326
|
+
// inverse highlight tracks the drag. Called by the App's mouse handler.
|
|
322
327
|
// A no-op-equal update is skipped to avoid redundant frames during motion.
|
|
323
|
-
setSelection = (rect) => {
|
|
328
|
+
setSelection = (rect, options = {}) => {
|
|
324
329
|
const a = this.selectionRect;
|
|
325
330
|
const same = a === rect ||
|
|
326
331
|
(a && rect &&
|
|
@@ -331,22 +336,68 @@ export default class Ink {
|
|
|
331
336
|
a.y2 === rect.y2 &&
|
|
332
337
|
a.clipY1 === rect.clipY1 &&
|
|
333
338
|
a.clipY2 === rect.clipY2 &&
|
|
334
|
-
a.captureText === rect.captureText
|
|
339
|
+
a.captureText === rect.captureText &&
|
|
340
|
+
a.selectionForeground === rect.selectionForeground &&
|
|
341
|
+
a.selectionBackground === rect.selectionBackground);
|
|
335
342
|
if (same) {
|
|
336
|
-
|
|
343
|
+
if (!options.immediate) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
this.selectionRect = rect ?? null;
|
|
337
349
|
}
|
|
338
|
-
this.selectionRect = rect ?? null;
|
|
339
350
|
if (!this.isUnmounted) {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
351
|
+
if (options.immediate) {
|
|
352
|
+
this.selectionRepaintEpoch++;
|
|
353
|
+
this.selectionRepaintFlushPending = false;
|
|
354
|
+
this.rootNode.onImmediateRender();
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
this.scheduleSelectionRepaint();
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
scheduleSelectionRepaint = () => {
|
|
361
|
+
if (this.hasPendingThrottledRender) {
|
|
362
|
+
return;
|
|
344
363
|
}
|
|
364
|
+
if (this.isRendering) {
|
|
365
|
+
this.selectionRepaintQueued = true;
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
if (this.selectionRepaintFlushPending) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
this.selectionRepaintFlushPending = true;
|
|
372
|
+
const epoch = ++this.selectionRepaintEpoch;
|
|
373
|
+
queueMicrotask(() => {
|
|
374
|
+
this.selectionRepaintFlushPending = false;
|
|
375
|
+
if (epoch !== this.selectionRepaintEpoch || this.isUnmounted) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
if (this.hasPendingThrottledRender) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
this.rootNode.onImmediateRender();
|
|
382
|
+
});
|
|
345
383
|
};
|
|
346
384
|
// [mixdog fork] Given a 0-based cell (x, y), return the inclusive rect of the
|
|
347
|
-
// word
|
|
348
|
-
//
|
|
349
|
-
//
|
|
385
|
+
// word at that cell on that single row, or null if the cell is whitespace/empty
|
|
386
|
+
// or out of range. Reuses the cached cell-value rows from the last render so it
|
|
387
|
+
// works without retaining the Output instance.
|
|
388
|
+
//
|
|
389
|
+
// Ported from claude-code's selection.ts charClass/wordBoundsAt (3-class word
|
|
390
|
+
// model) onto mixdog's rect(linear) infra. Instead of a naive "non-space run",
|
|
391
|
+
// expansion stops at a CHARACTER-CLASS change:
|
|
392
|
+
// class 1 = WORD_CHAR — letters (any script), digits, and the punctuation
|
|
393
|
+
// iTerm2 treats as word-part by default (/-+~_.\), so a path like
|
|
394
|
+
// `/usr/bin/bash` or `~/.claude/config.json` selects whole.
|
|
395
|
+
// class 2 = other punctuation — so `->` selects just `->`, not the words
|
|
396
|
+
// on either side.
|
|
397
|
+
// class 0 = space/empty. claude-code treats a space run as selectable
|
|
398
|
+
// (class 0), but mixdog intentionally returns null on empty/space
|
|
399
|
+
// so a double-click on blank does nothing (safer for our transcript
|
|
400
|
+
// where most alt-screen cells are padding).
|
|
350
401
|
getWordRectAt = (x, y) => {
|
|
351
402
|
const rows = this.lastPlainRows;
|
|
352
403
|
if (!rows)
|
|
@@ -354,16 +405,89 @@ export default class Ink {
|
|
|
354
405
|
const cells = rows[y];
|
|
355
406
|
if (!Array.isArray(cells))
|
|
356
407
|
return null;
|
|
357
|
-
|
|
358
|
-
|
|
408
|
+
// Unicode-aware word-char set (matches selection.ts WORD_CHAR).
|
|
409
|
+
const WORD_CHAR = /[\p{L}\p{N}_/.\-+~\\]/u;
|
|
410
|
+
const charClass = (v) => {
|
|
411
|
+
if (!v || v === ' ')
|
|
412
|
+
return 0;
|
|
413
|
+
return WORD_CHAR.test(v) ? 1 : 2;
|
|
414
|
+
};
|
|
415
|
+
// [mixdog fork] Wide/CJK glyphs occupy 2+ grid cells: the HEAD cell
|
|
416
|
+
// holds the glyph and each TRAILING cell is stored as '' (spacer tail)
|
|
417
|
+
// carrying the glyph's styles — see output.js ~L237-243 for how wide
|
|
418
|
+
// chars are laid into the grid. A '' cell is a wide-char TAIL only when
|
|
419
|
+
// it directly follows a non-empty non-space glyph (class !== 0); a ''
|
|
420
|
+
// after '' or after a space is genuine blank padding. This mirrors
|
|
421
|
+
// selection.ts wordBoundsAt's SpacerTail step-back (L172-178) and
|
|
422
|
+
// expansion step-over (L206-221) on mixdog's string-cell grid.
|
|
423
|
+
const isWideTail = (i) => i > 0 && cells[i] === '' && charClass(cells[i - 1]) !== 0;
|
|
424
|
+
// On entry: if the click landed on a spacer tail, step back to the head
|
|
425
|
+
// so charClass sees the actual glyph. Genuine blank padding is left
|
|
426
|
+
// alone, preserving the null-on-blank behavior below.
|
|
427
|
+
let sx = x;
|
|
428
|
+
if (isWideTail(sx))
|
|
429
|
+
sx = sx - 1;
|
|
430
|
+
const cls = charClass(cells[sx]);
|
|
431
|
+
// Preserve mixdog's null-on-space/empty behavior (class 0).
|
|
432
|
+
if (cls === 0)
|
|
359
433
|
return null;
|
|
360
|
-
let x1 =
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
434
|
+
let x1 = sx, x2 = sx;
|
|
435
|
+
// Expand left: step OVER a spacer tail to the wide-char head and include
|
|
436
|
+
// both columns when the head matches the class; otherwise stop at a
|
|
437
|
+
// class change.
|
|
438
|
+
while (x1 - 1 >= 0) {
|
|
439
|
+
const p = x1 - 1;
|
|
440
|
+
if (isWideTail(p)) {
|
|
441
|
+
if (p - 1 >= 0 && charClass(cells[p - 1]) === cls) {
|
|
442
|
+
x1 = p - 1;
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
if (charClass(cells[p]) === cls) {
|
|
448
|
+
x1 = p;
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
// Expand right: INCLUDE a spacer tail that follows an in-run glyph so x2
|
|
454
|
+
// covers the wide glyph's full width; otherwise stop at a class change.
|
|
455
|
+
while (x2 + 1 < cells.length) {
|
|
456
|
+
const n = x2 + 1;
|
|
457
|
+
if (isWideTail(n)) {
|
|
458
|
+
x2 = n;
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
if (charClass(cells[n]) === cls) {
|
|
462
|
+
x2 = n;
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
365
467
|
return { x1, y1: y, x2, y2: y };
|
|
366
468
|
};
|
|
469
|
+
// [mixdog fork] Given a 0-based row y, return the inclusive rect of the whole
|
|
470
|
+
// logical line at that row (mirrors claude-code's selectLineAt intent on
|
|
471
|
+
// mixdog's rect infra). x1 is always 0; x2 is the last non-space content cell
|
|
472
|
+
// so trailing padding isn't selected. Returns null for an empty/blank row.
|
|
473
|
+
// Exposed symmetrically to getWordRectAt (index.jsx wires it into the store).
|
|
474
|
+
getLineRectAt = (y) => {
|
|
475
|
+
const rows = this.lastPlainRows;
|
|
476
|
+
if (!rows)
|
|
477
|
+
return null;
|
|
478
|
+
const cells = rows[y];
|
|
479
|
+
if (!Array.isArray(cells))
|
|
480
|
+
return null;
|
|
481
|
+
let x2 = -1;
|
|
482
|
+
for (let x = 0; x < cells.length; x++) {
|
|
483
|
+
const v = cells[x];
|
|
484
|
+
if (v && !/^\s$/u.test(v))
|
|
485
|
+
x2 = x;
|
|
486
|
+
}
|
|
487
|
+
if (x2 < 0)
|
|
488
|
+
return null;
|
|
489
|
+
return { x1: 0, y1: y, x2, y2: y };
|
|
490
|
+
};
|
|
367
491
|
restoreLastOutput = () => {
|
|
368
492
|
if (!this.interactive) {
|
|
369
493
|
return;
|
|
@@ -401,6 +525,8 @@ export default class Ink {
|
|
|
401
525
|
this.nextRenderCommit.resolve();
|
|
402
526
|
this.nextRenderCommit = undefined;
|
|
403
527
|
}
|
|
528
|
+
this.isRendering = true;
|
|
529
|
+
try {
|
|
404
530
|
const startTime = performance.now();
|
|
405
531
|
const { output, outputHeight, staticOutput, cursor, selectedText, plainRows } = render(this.rootNode, this.isScreenReaderEnabled, this.selectionRect);
|
|
406
532
|
// [mixdog fork] Cache the text under the current selection rect so the App
|
|
@@ -488,6 +614,14 @@ export default class Ink {
|
|
|
488
614
|
this.fullStaticOutput += staticOutput;
|
|
489
615
|
}
|
|
490
616
|
this.renderInteractiveFrame(output, outputHeight, hasStaticOutput ? staticOutput : '');
|
|
617
|
+
}
|
|
618
|
+
finally {
|
|
619
|
+
this.isRendering = false;
|
|
620
|
+
if (this.selectionRepaintQueued) {
|
|
621
|
+
this.selectionRepaintQueued = false;
|
|
622
|
+
this.scheduleSelectionRepaint();
|
|
623
|
+
}
|
|
624
|
+
}
|
|
491
625
|
};
|
|
492
626
|
render(node) {
|
|
493
627
|
const tree = (React.createElement(AccessibilityContext.Provider, { value: { isScreenReaderEnabled: this.isScreenReaderEnabled } },
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
// [mixdog fork] use the shared display-width policy so ink's text measurement
|
|
2
|
+
// matches OUR wrap/row math for circled digits / arrows. Kept in sync with
|
|
3
|
+
// src/tui/display-width.mjs.
|
|
4
|
+
import { displayWidestLine as widestLine } from './display-width.js';
|
|
2
5
|
const cache = new Map();
|
|
3
6
|
const measureText = (text) => {
|
|
4
7
|
if (text.length === 0) {
|