mixdog 0.9.1 → 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 +8 -1
- 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/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/rules-builder.cjs +32 -54
- package/src/mixdog-session-runtime.mjs +710 -318
- 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 -2
- 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 +332 -57
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +59 -32
- 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 +78 -3
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +202 -98
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +183 -20
- 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 +15 -9
- 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/builtin/arg-guard.mjs +194 -24
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +143 -0
- 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 -1224
- package/src/runtime/channels/lib/config.mjs +54 -2
- package/src/runtime/channels/lib/format.mjs +4 -2
- package/src/runtime/channels/lib/output-forwarder.mjs +80 -67
- package/src/runtime/channels/lib/runtime-paths.mjs +29 -0
- package/src/runtime/channels/lib/scheduler.mjs +1 -1
- package/src/runtime/channels/lib/telegram-format.mjs +283 -0
- package/src/runtime/channels/lib/tool-format.mjs +1 -1
- package/src/runtime/channels/lib/transcript-discovery.mjs +19 -1
- package/src/runtime/channels/lib/webhook.mjs +59 -31
- package/src/runtime/channels/tool-defs.mjs +1 -1
- package/src/runtime/memory/index.mjs +184 -19
- 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/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.mjs +101 -4
- package/src/runtime/memory/lib/pg/adapter.mjs +139 -15
- package/src/runtime/memory/lib/session-ingest.mjs +107 -0
- package/src/runtime/memory/lib/trace-store.mjs +69 -22
- package/src/runtime/memory/tool-defs.mjs +6 -3
- 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/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/usage-dashboard.mjs +1 -1
- package/src/tui/App.jsx +2096 -732
- 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 +83 -7
- 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 +170 -98
- package/src/tui/components/TurnDone.jsx +4 -4
- package/src/tui/components/UsagePanel.jsx +1 -1
- package/src/tui/components/tool-output-format.mjs +159 -21
- package/src/tui/components/tool-output-format.test.mjs +87 -0
- package/src/tui/display-width.mjs +69 -0
- package/src/tui/display-width.test.mjs +35 -0
- package/src/tui/dist/index.mjs +6965 -2391
- 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 +129 -76
- package/src/tui/markdown/format-token.test.mjs +61 -19
- 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 -657
- 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-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 +100 -12
- 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/output-styles/extreme-simple.md +0 -20
- package/src/rules/lead/04-workflow.md +0 -51
- package/src/workflows/default/workflow.json +0 -13
- package/src/workflows/solo/workflow.json +0 -7
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;
|
|
@@ -336,7 +336,9 @@ export default class Ink {
|
|
|
336
336
|
a.y2 === rect.y2 &&
|
|
337
337
|
a.clipY1 === rect.clipY1 &&
|
|
338
338
|
a.clipY2 === rect.clipY2 &&
|
|
339
|
-
a.captureText === rect.captureText
|
|
339
|
+
a.captureText === rect.captureText &&
|
|
340
|
+
a.selectionForeground === rect.selectionForeground &&
|
|
341
|
+
a.selectionBackground === rect.selectionBackground);
|
|
340
342
|
if (same) {
|
|
341
343
|
if (!options.immediate) {
|
|
342
344
|
return;
|
|
@@ -380,9 +382,22 @@ export default class Ink {
|
|
|
380
382
|
});
|
|
381
383
|
};
|
|
382
384
|
// [mixdog fork] Given a 0-based cell (x, y), return the inclusive rect of the
|
|
383
|
-
// word
|
|
384
|
-
//
|
|
385
|
-
//
|
|
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).
|
|
386
401
|
getWordRectAt = (x, y) => {
|
|
387
402
|
const rows = this.lastPlainRows;
|
|
388
403
|
if (!rows)
|
|
@@ -390,16 +405,89 @@ export default class Ink {
|
|
|
390
405
|
const cells = rows[y];
|
|
391
406
|
if (!Array.isArray(cells))
|
|
392
407
|
return null;
|
|
393
|
-
|
|
394
|
-
|
|
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)
|
|
395
433
|
return null;
|
|
396
|
-
let x1 =
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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
|
+
}
|
|
401
467
|
return { x1, y1: y, x2, y2: y };
|
|
402
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
|
+
};
|
|
403
491
|
restoreLastOutput = () => {
|
|
404
492
|
if (!this.interactive) {
|
|
405
493
|
return;
|
|
@@ -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) {
|
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
import sliceAnsi from 'slice-ansi';
|
|
2
|
-
import stringWidth from 'string-width';
|
|
3
2
|
import { styledCharsFromTokens, styledCharsToString, tokenize, } from '@alcalzone/ansi-tokenize';
|
|
3
|
+
// [mixdog fork] use the shared display-width policy so ink's per-character
|
|
4
|
+
// advance + width cache treat circled digits / arrows as 2 cells under Windows
|
|
5
|
+
// Terminal, matching OUR wrap/row math. See display-width.js (kept in sync with
|
|
6
|
+
// src/tui/display-width.mjs).
|
|
7
|
+
import { displayStringWidth as stringWidth } from './display-width.js';
|
|
8
|
+
const RGB_COLOR_RE = /^rgb\(\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\s*\)$/;
|
|
9
|
+
const rgbStyle = (value, type, fallback) => {
|
|
10
|
+
const match = RGB_COLOR_RE.exec(String(value || ''));
|
|
11
|
+
const parts = match
|
|
12
|
+
? match.slice(1, 4).map(part => Math.max(0, Math.min(255, Number(part) || 0)))
|
|
13
|
+
: fallback;
|
|
14
|
+
const sgr = type === 'foreground' ? 38 : 48;
|
|
15
|
+
const reset = type === 'foreground' ? '\x1b[39m' : '\x1b[49m';
|
|
16
|
+
return { code: `\x1b[${sgr};2;${parts[0]};${parts[1]};${parts[2]}m`, endCode: reset };
|
|
17
|
+
};
|
|
18
|
+
const intersectClips = (clips) => {
|
|
19
|
+
if (clips.length === 0) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
const out = {};
|
|
23
|
+
for (const clip of clips) {
|
|
24
|
+
if (typeof clip?.x1 === 'number') {
|
|
25
|
+
out.x1 = typeof out.x1 === 'number' ? Math.max(out.x1, clip.x1) : clip.x1;
|
|
26
|
+
}
|
|
27
|
+
if (typeof clip?.x2 === 'number') {
|
|
28
|
+
out.x2 = typeof out.x2 === 'number' ? Math.min(out.x2, clip.x2) : clip.x2;
|
|
29
|
+
}
|
|
30
|
+
if (typeof clip?.y1 === 'number') {
|
|
31
|
+
out.y1 = typeof out.y1 === 'number' ? Math.max(out.y1, clip.y1) : clip.y1;
|
|
32
|
+
}
|
|
33
|
+
if (typeof clip?.y2 === 'number') {
|
|
34
|
+
out.y2 = typeof out.y2 === 'number' ? Math.min(out.y2, clip.y2) : clip.y2;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
};
|
|
4
39
|
class OutputCaches {
|
|
5
40
|
widths = new Map();
|
|
6
41
|
blockWidths = new Map();
|
|
@@ -112,10 +147,19 @@ export default class Output {
|
|
|
112
147
|
const { text, transformers } = operation;
|
|
113
148
|
let { x, y } = operation;
|
|
114
149
|
let lines = text.split('\n');
|
|
115
|
-
|
|
150
|
+
// [mixdog fork] Nested overflow:hidden boxes must be clipped to
|
|
151
|
+
// the INTERSECTION of every active ancestor clip. Using only the
|
|
152
|
+
// innermost clip lets child components such as ToolExecution /
|
|
153
|
+
// TurnDone (which have their own overflow hidden rows) escape the
|
|
154
|
+
// transcript viewport and paint over command/prompt/status rows.
|
|
155
|
+
const clip = intersectClips(clips);
|
|
116
156
|
if (clip) {
|
|
117
157
|
const clipHorizontally = typeof clip?.x1 === 'number' && typeof clip?.x2 === 'number';
|
|
118
158
|
const clipVertically = typeof clip?.y1 === 'number' && typeof clip?.y2 === 'number';
|
|
159
|
+
if ((clipHorizontally && clip.x2 <= clip.x1) ||
|
|
160
|
+
(clipVertically && clip.y2 <= clip.y1)) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
119
163
|
// If text is positioned outside of clipping area altogether,
|
|
120
164
|
// skip to the next operation to avoid unnecessary calculations
|
|
121
165
|
if (clipHorizontally) {
|
|
@@ -218,15 +262,34 @@ export default class Output {
|
|
|
218
262
|
// dim text, and status colors do not bleed through.
|
|
219
263
|
const sel = this.selection;
|
|
220
264
|
let selectedText = null;
|
|
265
|
+
// [mixdog fork] noSelect exclusion (claude-code skips gutter / line-number
|
|
266
|
+
// / diff-sigil cells from both highlight and copy via screen.noSelect):
|
|
267
|
+
// mixdog's cell model has NO noSelect marker — the Output grid stores only
|
|
268
|
+
// {value, styles} per cell, with no flag distinguishing gutter cells from
|
|
269
|
+
// content. Inferring gutters from position/content would be a fragile
|
|
270
|
+
// heuristic (line numbers, diff +/- sigils, and real content are
|
|
271
|
+
// indistinguishable at the cell level), so this is deliberately NOT
|
|
272
|
+
// implemented. It needs a noSelect bit threaded through the render
|
|
273
|
+
// pipeline before it can be done cleanly.
|
|
221
274
|
if (sel) {
|
|
222
275
|
const captureSelectedText = sel.captureText !== false;
|
|
223
276
|
if (!captureSelectedText) {
|
|
224
277
|
selectedText = undefined;
|
|
225
278
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
279
|
+
// [mixdog fork] Port applySelectionOverlay's fg-preserving principle
|
|
280
|
+
// from claude-code's selection.ts: REPLACE only the background and
|
|
281
|
+
// PRESERVE each cell's own foreground/attribute styles, so syntax
|
|
282
|
+
// highlighting, OSC-8 links, and dim text stay readable under the
|
|
283
|
+
// selection. The old code forced a black fg + light bg, flattening
|
|
284
|
+
// every colored glyph to one color. selectionForeground is now
|
|
285
|
+
// intentionally unused (kept in the setter API for compatibility).
|
|
286
|
+
const selectionBg = rgbStyle(sel.selectionBackground, 'background', [245, 245, 245]);
|
|
287
|
+
// A style entry sets the background when its opening SGR code begins
|
|
288
|
+
// with a background parameter: 40-47 (basic), 48 (256/truecolor),
|
|
289
|
+
// 49 (default), or 100-107 (bright). ansi-tokenize emits one entry
|
|
290
|
+
// per SGR attribute, so a prefix test on `.code` cleanly isolates the
|
|
291
|
+
// bg-only entries we want to drop before appending the selection bg.
|
|
292
|
+
const isBackgroundStyle = (s) => typeof s?.code === 'string' && /^\x1b\[(?:4[0-9]|10[0-7])[;m]/.test(s.code);
|
|
230
293
|
const linear = sel.mode === 'linear';
|
|
231
294
|
const start = linear && (sel.y1 > sel.y2 || (sel.y1 === sel.y2 && sel.x1 > sel.x2))
|
|
232
295
|
? { x: sel.x2, y: sel.y2 }
|
|
@@ -281,9 +344,16 @@ export default class Output {
|
|
|
281
344
|
if (contentStart === -1 || x < contentStart || x > contentEnd) {
|
|
282
345
|
continue;
|
|
283
346
|
}
|
|
347
|
+
// [mixdog fork] fg-preserving highlight: keep the cell's own
|
|
348
|
+
// style entries (foreground color, bold/dim/underline, link
|
|
349
|
+
// attrs) and swap ONLY the background. Drop any existing
|
|
350
|
+
// background entry so the two bgs don't fight, then append the
|
|
351
|
+
// selection bg last so it wins for this cell.
|
|
352
|
+
const baseStyles = Array.isArray(cell.styles) ? cell.styles : [];
|
|
353
|
+
const preserved = baseStyles.filter(style => !isBackgroundStyle(style));
|
|
284
354
|
row[x] = {
|
|
285
355
|
...cell,
|
|
286
|
-
styles:
|
|
356
|
+
styles: [...preserved, selectionBg],
|
|
287
357
|
};
|
|
288
358
|
}
|
|
289
359
|
// Trailing spaces in a selected row are padding, not content.
|
|
@@ -302,6 +372,20 @@ export default class Output {
|
|
|
302
372
|
while (selRows.length > 0 && selRows[selRows.length - 1].trim() === '') {
|
|
303
373
|
selRows.pop();
|
|
304
374
|
}
|
|
375
|
+
// [mixdog fork] SOFT-WRAP JOIN (claude-code getSelectedText):
|
|
376
|
+
// claude-code rejoins word-wrapped continuation rows into one
|
|
377
|
+
// logical line using screen.softWrap, a per-row bitmap set at
|
|
378
|
+
// wrap time marking a row as a continuation of the one above.
|
|
379
|
+
// mixdog's rect(linear) render model carries NO softWrap metadata
|
|
380
|
+
// — the Output grid is a flat array of visual rows with no record
|
|
381
|
+
// of which line breaks were inserted by wrapping vs. present in
|
|
382
|
+
// the source. Detecting "this row filled to content width AND the
|
|
383
|
+
// next continues the same logical block" from cell values alone is
|
|
384
|
+
// a guess (a source line that legitimately fills the width would be
|
|
385
|
+
// wrongly glued to the next). Per the correctness-over-cleverness
|
|
386
|
+
// rule we keep the honest per-visual-row '\n' join rather than
|
|
387
|
+
// fabricate wrap boundaries. Revisit if the render pipeline starts
|
|
388
|
+
// emitting a softWrap bit per row.
|
|
305
389
|
selectedText = selRows.join('\n');
|
|
306
390
|
}
|
|
307
391
|
}
|
|
@@ -317,8 +401,30 @@ export default class Output {
|
|
|
317
401
|
const generatedOutput = output
|
|
318
402
|
.map(line => {
|
|
319
403
|
// See https://github.com/vadimdemedes/ink/pull/564#issuecomment-1637022742
|
|
320
|
-
|
|
321
|
-
|
|
404
|
+
// [mixdog fork] Keep the serialized row inside Output.width as a
|
|
405
|
+
// final invariant. Component-level width budgeting can miss
|
|
406
|
+
// background fills, resize races, or wide-char edge cases; if the
|
|
407
|
+
// terminal receives a row wider than its modeled width it may
|
|
408
|
+
// soft-wrap/scroll outside Ink's cursor-origin model.
|
|
409
|
+
const lineWithinWidth = [];
|
|
410
|
+
let usedWidth = 0;
|
|
411
|
+
for (const item of line) {
|
|
412
|
+
if (item === undefined) {
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
const value = item.value ?? '';
|
|
416
|
+
if (value === '') {
|
|
417
|
+
lineWithinWidth.push(item);
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
const itemWidth = Math.max(1, this.caches.getStringWidth(value));
|
|
421
|
+
if (usedWidth + itemWidth > this.width) {
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
lineWithinWidth.push(item);
|
|
425
|
+
usedWidth += itemWidth;
|
|
426
|
+
}
|
|
427
|
+
return styledCharsToString(lineWithinWidth).trimEnd();
|
|
322
428
|
})
|
|
323
429
|
.join('\n');
|
|
324
430
|
return {
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
// [mixdog fork] use the shared display-width policy so the wrap decision here
|
|
2
|
+
// agrees with measure-text.js and output.js. Kept in sync with
|
|
3
|
+
// src/tui/display-width.mjs.
|
|
4
|
+
import { displayWidestLine as widestLine } from './display-width.js';
|
|
2
5
|
import indentString from 'indent-string';
|
|
3
6
|
import Yoga from 'yoga-layout';
|
|
4
7
|
import wrapText from './wrap-text.js';
|
|
@@ -41,6 +41,10 @@ const render = (node, options) => {
|
|
|
41
41
|
getSelectionText: () => instance.selectedText,
|
|
42
42
|
// [mixdog fork] resolve the word rect at a cell for double-click select.
|
|
43
43
|
getWordRectAt: (x, y) => instance.getWordRectAt(x, y),
|
|
44
|
+
// [mixdog fork] resolve the whole-line rect at a row for triple-click /
|
|
45
|
+
// line select. Symmetric to getWordRectAt; index.jsx wires it into the
|
|
46
|
+
// store as store.getLineRectAt.
|
|
47
|
+
getLineRectAt: (y) => instance.getLineRectAt(y),
|
|
44
48
|
};
|
|
45
49
|
};
|
|
46
50
|
export default render;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: extreme-simple
|
|
3
|
-
title: Extreme Simple
|
|
4
|
-
description: Ultra-short completion sentence
|
|
5
|
-
aliases: extreme, extreme simple
|
|
6
|
-
keep-coding-instructions: true
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Output Style
|
|
10
|
-
|
|
11
|
-
Extreme — one ultra-short completion sentence. The most minimal of the styles.
|
|
12
|
-
|
|
13
|
-
- Reply with a single completion sentence whenever possible.
|
|
14
|
-
- Preferred pattern: `<target> 변경되었습니다. <verification> 통과 완료입니다.`
|
|
15
|
-
- If verification was not run, use one short sentence saying the change is done
|
|
16
|
-
and verification was not run.
|
|
17
|
-
- No headings, bullets, labels, explanations, tool traces, or metadata unless
|
|
18
|
-
the user explicitly asks.
|
|
19
|
-
- Preserve only the single decisive path, command, symbol, API name, code, or
|
|
20
|
-
error verbatim.
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Workflow
|
|
2
|
-
|
|
3
|
-
Priority:
|
|
4
|
-
- When an `# Active Workflow` block is present, it is the binding session
|
|
5
|
-
workflow and takes precedence over all other workflow guidance.
|
|
6
|
-
|
|
7
|
-
Delegation:
|
|
8
|
-
- Lead is the supervisor of agents, responsible for task delegation,
|
|
9
|
-
coordination, judgment, and final decisions.
|
|
10
|
-
- As supervisor, prefer delegating implementation work to an agent; keep direct
|
|
11
|
-
work limited to coordination and User Workflow exceptions such as
|
|
12
|
-
one-or-two-step edits, pre-planning, config changes, and final git deployment.
|
|
13
|
-
- Implementation edits to product/runtime/TUI code MUST be delegated to a
|
|
14
|
-
Worker/Heavy Worker, even when small. Lead may directly edit only rules, docs,
|
|
15
|
-
config, and final deployment/git steps, unless the user explicitly asks Lead
|
|
16
|
-
to patch directly.
|
|
17
|
-
- Delegation split: different code paths / entry points / file groups are
|
|
18
|
-
separate scopes — implementation AND analysis, review, debugging split the
|
|
19
|
-
same way. With 2+ independent scopes, spawn each scoped agent in the
|
|
20
|
-
SAME turn, not one after another. Shared functions or cross-cutting concerns
|
|
21
|
-
do NOT justify collapsing them into one delegation: split per path, and Lead
|
|
22
|
-
verifies the cross-cutting parts (shared state, telemetry consistency, etc.)
|
|
23
|
-
directly. "One agent must see the whole context" is not a valid reason to
|
|
24
|
-
merge; the only legitimate single-scope case is a genuinely inseparable
|
|
25
|
-
dependency — and then state the reason.
|
|
26
|
-
- Follow-up work on the same path or scope MUST reuse the existing agent (same
|
|
27
|
-
tag). Spawn a new agent only for a genuinely separate scope.
|
|
28
|
-
- Pick the agent role defined in the User Workflow section that fits the task
|
|
29
|
-
(worker, heavy-worker, reviewer, debugger, …) when spawning.
|
|
30
|
-
- Write agent-facing briefs and follow-up task messages in English.
|
|
31
|
-
- Agent briefs must be bounded: state the goal/success criteria, known starting
|
|
32
|
-
files or anchors if available, allowed/forbidden changes, expected
|
|
33
|
-
deliverable, and verification boundary. For heavy-worker, include known first
|
|
34
|
-
components to inspect and the stopping condition; complex work must not
|
|
35
|
-
become open-ended.
|
|
36
|
-
|
|
37
|
-
Agent lifecycle:
|
|
38
|
-
- After spawning async agent(s), END THE TURN immediately. Do not poll
|
|
39
|
-
status/read, guess the outcome, or start dependent work — treat the result as
|
|
40
|
-
unknown until the completion notification resumes you. status/read are manual
|
|
41
|
-
recovery only, never progress checks.
|
|
42
|
-
- Unless instructed otherwise, wait for the spawned agent(s); once their results
|
|
43
|
-
are collected, automatically continue with the next turn.
|
|
44
|
-
|
|
45
|
-
Agent result handling:
|
|
46
|
-
- Cross-check material agent responses before using them for decisions or
|
|
47
|
-
summarizing them to the user.
|
|
48
|
-
- When an agent returns, always synthesize its result into a concise report for
|
|
49
|
-
the user (outcome + key changes/evidence). Never forward the raw agent output.
|
|
50
|
-
- If anything here conflicts with the User Workflow section, this Workflow takes
|
|
51
|
-
precedence, except that the `# Active Workflow` block always wins.
|