mixdog 0.9.0 → 0.9.1

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 (57) hide show
  1. package/package.json +3 -3
  2. package/scripts/session-ingest-smoke.mjs +2 -2
  3. package/src/headless-role.mjs +1 -1
  4. package/src/lib/mixdog-debug.cjs +0 -22
  5. package/src/lib/plugin-paths.cjs +1 -7
  6. package/src/lib/rules-builder.cjs +2 -2
  7. package/src/mixdog-session-runtime.mjs +0 -1
  8. package/src/repl.mjs +0 -2
  9. package/src/runtime/agent/orchestrator/internal-roles.mjs +1 -1
  10. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +27 -49
  11. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +5 -20
  12. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +8 -27
  13. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +52 -182
  14. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +8 -30
  15. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +258 -0
  16. package/src/runtime/agent/orchestrator/tools/bash-session.mjs +1 -1
  17. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +0 -8
  18. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +1 -44
  19. package/src/runtime/channels/index.mjs +0 -30
  20. package/src/runtime/channels/lib/cli-worker-host.mjs +1 -8
  21. package/src/runtime/channels/lib/config.mjs +0 -1
  22. package/src/runtime/channels/lib/drop-trace.mjs +1 -1
  23. package/src/runtime/channels/lib/executor.mjs +0 -3
  24. package/src/runtime/channels/lib/memory-client.mjs +0 -38
  25. package/src/runtime/channels/lib/output-forwarder.mjs +1 -8
  26. package/src/runtime/channels/lib/runtime-paths.mjs +0 -6
  27. package/src/runtime/channels/lib/session-discovery.mjs +0 -4
  28. package/src/runtime/channels/lib/tool-format.mjs +0 -1
  29. package/src/runtime/channels/lib/transcript-discovery.mjs +1 -10
  30. package/src/runtime/lib/keychain-cjs.cjs +0 -1
  31. package/src/runtime/memory/data/runtime-manifest.json +6 -7
  32. package/src/runtime/memory/index.mjs +3 -24
  33. package/src/runtime/memory/lib/llm-worker-host.mjs +0 -4
  34. package/src/runtime/memory/lib/memory-ops-policy.mjs +0 -1
  35. package/src/runtime/memory/lib/runtime-fetcher.mjs +43 -18
  36. package/src/runtime/memory/lib/session-ingest.mjs +9 -7
  37. package/src/runtime/search/index.mjs +2 -7
  38. package/src/runtime/search/lib/config.mjs +0 -4
  39. package/src/runtime/search/lib/state.mjs +1 -15
  40. package/src/runtime/search/lib/web-tools.mjs +0 -1
  41. package/src/runtime/shared/child-spawn-gate.mjs +0 -6
  42. package/src/standalone/seeds.mjs +1 -11
  43. package/src/tui/App.jsx +35 -12
  44. package/src/tui/components/PromptInput.jsx +63 -2
  45. package/src/tui/components/ToolExecution.jsx +7 -2
  46. package/src/tui/components/tool-output-format.mjs +156 -22
  47. package/src/tui/components/tool-output-format.test.mjs +93 -1
  48. package/src/tui/dist/index.mjs +473 -116
  49. package/src/tui/markdown/format-token.mjs +267 -108
  50. package/src/tui/markdown/format-token.test.mjs +105 -9
  51. package/src/tui/theme.mjs +10 -0
  52. package/src/vendor/statusline/bin/statusline-lib.mjs +0 -623
  53. package/vendor/ink/build/ink.js +54 -8
  54. package/src/hooks/lib/permission-rules.cjs +0 -170
  55. package/src/hooks/lib/settings-loader.cjs +0 -112
  56. package/src/lib/hook-pipe-path.cjs +0 -10
  57. package/src/runtime/channels/lib/hook-pipe-server.mjs +0 -671
@@ -99,6 +99,8 @@ var mixdogPalette = {
99
99
  // ``` fence + lang label rule
100
100
  mdCodeBlockBg: "rgb(34,35,40)",
101
101
  // code-block background band (distinct from bg)
102
+ mdCodeSpanBg: "rgb(42,43,48)",
103
+ // inline codespan background (subtle lift from block bg)
102
104
  mdLink: "rgb(47,127,255)",
103
105
  // link URL (suggestion blue)
104
106
  mdLinkText: "rgb(138,190,183)",
@@ -175,6 +177,7 @@ var piDarkPalette = {
175
177
  codeBlock: "rgb(181,189,104)",
176
178
  mdCodeBlockBorder: "rgb(96,104,116)",
177
179
  mdCodeBlockBg: "rgb(32,36,44)",
180
+ mdCodeSpanBg: "rgb(40,44,52)",
178
181
  mdLink: "rgb(95,135,255)",
179
182
  mdLinkText: "rgb(138,190,183)",
180
183
  mdStrong: "rgb(181,189,104)",
@@ -242,6 +245,7 @@ var claudeDarkPalette = {
242
245
  mdListBullet: "rgb(177,185,249)",
243
246
  mdCodeBlockBorder: "rgb(120,120,120)",
244
247
  mdCodeBlockBg: "rgb(34,35,40)",
248
+ mdCodeSpanBg: "rgb(42,43,48)",
245
249
  mdLink: "rgb(177,185,249)",
246
250
  mdLinkText: "rgb(150,200,210)",
247
251
  mdStrong: "rgb(235,159,127)",
@@ -308,6 +312,7 @@ var draculaPalette = {
308
312
  mdListBullet: "rgb(189,147,249)",
309
313
  mdCodeBlockBorder: "rgb(68,71,90)",
310
314
  mdCodeBlockBg: "rgb(60,63,79)",
315
+ mdCodeSpanBg: "rgb(68,71,87)",
311
316
  mdLink: "rgb(139,233,253)",
312
317
  mdLinkText: "rgb(255,121,198)",
313
318
  // pink
@@ -373,6 +378,7 @@ var tokyonightPalette = {
373
378
  mdListBullet: "rgb(130,170,255)",
374
379
  mdCodeBlockBorder: "rgb(84,92,126)",
375
380
  mdCodeBlockBg: "rgb(45,47,64)",
381
+ mdCodeSpanBg: "rgb(53,55,72)",
376
382
  mdLink: "rgb(130,170,255)",
377
383
  mdLinkText: "rgb(134,225,252)",
378
384
  // cyan
@@ -437,6 +443,7 @@ var nordPalette = {
437
443
  mdListBullet: "rgb(136,192,208)",
438
444
  mdCodeBlockBorder: "rgb(67,76,94)",
439
445
  mdCodeBlockBg: "rgb(64,71,87)",
446
+ mdCodeSpanBg: "rgb(72,79,95)",
440
447
  mdLink: "rgb(129,161,193)",
441
448
  mdLinkText: "rgb(143,188,187)",
442
449
  mdStrong: "rgb(235,203,139)",
@@ -498,6 +505,7 @@ var gruvboxPalette = {
498
505
  mdListBullet: "rgb(131,165,152)",
499
506
  mdCodeBlockBorder: "rgb(80,73,69)",
500
507
  mdCodeBlockBg: "rgb(60,58,52)",
508
+ mdCodeSpanBg: "rgb(68,66,60)",
501
509
  mdLink: "rgb(142,192,124)",
502
510
  mdLinkText: "rgb(184,187,38)",
503
511
  mdStrong: "rgb(254,128,25)",
@@ -560,6 +568,7 @@ var catppuccinPalette = {
560
568
  mdListBullet: "rgb(137,180,250)",
561
569
  mdCodeBlockBorder: "rgb(49,50,68)",
562
570
  mdCodeBlockBg: "rgb(49,50,68)",
571
+ mdCodeSpanBg: "rgb(57,58,76)",
563
572
  mdLink: "rgb(137,180,250)",
564
573
  mdLinkText: "rgb(137,220,235)",
565
574
  // sky
@@ -624,6 +633,7 @@ var everforestPalette = {
624
633
  mdListBullet: "rgb(167,192,128)",
625
634
  mdCodeBlockBorder: "rgb(52,63,68)",
626
635
  mdCodeBlockBg: "rgb(62,71,78)",
636
+ mdCodeSpanBg: "rgb(70,79,86)",
627
637
  mdLink: "rgb(167,192,128)",
628
638
  mdLinkText: "rgb(131,192,146)",
629
639
  // cyan
@@ -692,6 +702,7 @@ var whitePalette = {
692
702
  mdListBullet: "rgb(9,105,218)",
693
703
  mdCodeBlockBorder: "rgb(200,206,212)",
694
704
  mdCodeBlockBg: "rgb(232,232,236)",
705
+ mdCodeSpanBg: "rgb(240,240,244)",
695
706
  mdLink: "rgb(9,105,218)",
696
707
  mdLinkText: "rgb(0,92,197)",
697
708
  mdStrong: "rgb(130,80,8)",
@@ -820,6 +831,7 @@ import { marked } from "marked";
820
831
 
821
832
  // src/tui/markdown/format-token.mjs
822
833
  import { Chalk } from "chalk";
834
+ import { highlight, supportsLanguage } from "cli-highlight";
823
835
  import stripAnsi from "strip-ansi";
824
836
  import stringWidth from "string-width";
825
837
  import wrapAnsi from "wrap-ansi";
@@ -886,7 +898,8 @@ function extraColorizers() {
886
898
  synPunct: rgbColor(theme.syntaxPunctuation ?? theme.mdCodeBlock),
887
899
  body: fallbackBody,
888
900
  // Truecolor background band for fenced code blocks (per-line wrap).
889
- codeBg: rgbBg(theme.mdCodeBlockBg ?? theme.background)
901
+ codeBg: rgbBg(theme.mdCodeBlockBg ?? theme.background),
902
+ codeSpanBg: rgbBg(theme.mdCodeSpanBg ?? theme.mdCodeBlockBg ?? theme.background)
890
903
  };
891
904
  return _extra;
892
905
  }
@@ -894,7 +907,6 @@ function decodeEntities(s) {
894
907
  if (typeof s !== "string" || s.indexOf("&") === -1) return s;
895
908
  return s.replace(/&quot;/g, '"').replace(/&#0*39;/g, "'").replace(/&apos;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&#(\d+);/g, (_, n) => String.fromCodePoint(Number(n))).replace(/&#[xX]([0-9a-fA-F]+);/g, (_, h) => String.fromCodePoint(parseInt(h, 16))).replace(/&amp;/g, "&");
896
909
  }
897
- var CODE_BLOCK_INDENT = " ";
898
910
  var DIFF_LANGS = /* @__PURE__ */ new Set(["diff", "patch", "udiff", "git-diff", "gitdiff"]);
899
911
  function wrapTextToWidth(text, width, options) {
900
912
  if (width <= 0) return [text];
@@ -927,14 +939,28 @@ function hardWrapAnsiLines(text, width) {
927
939
  }
928
940
  return out.length > 0 ? out : [""];
929
941
  }
930
- function wrapIndentedCodeLine(ansiContent, maxLineWidth) {
931
- const indentW = stringWidth(CODE_BLOCK_INDENT);
932
- const contentMax = Math.max(1, maxLineWidth - indentW);
933
- const segments = hardWrapAnsiLines(ansiContent, contentMax);
934
- return segments.map((seg) => `${CODE_BLOCK_INDENT}${seg}`);
942
+ function wrapCodeLine(ansiContent, maxLineWidth) {
943
+ const contentMax = Math.max(1, maxLineWidth);
944
+ return hardWrapAnsiLines(ansiContent, contentMax);
935
945
  }
936
- function tintCodeLines(lines, codeBg) {
937
- return lines.map((line) => codeBg(line)).join(EOL);
946
+ function visibleLineWidth(line) {
947
+ return stringWidth(stripAnsi(String(line ?? "")));
948
+ }
949
+ function codeBlockContentWidth(langLine, bodyLines) {
950
+ const all = [...langLine ? [langLine] : [], ...bodyLines];
951
+ if (all.length === 0) return 0;
952
+ return Math.max(1, ...all.map(visibleLineWidth));
953
+ }
954
+ function tintCodeLineToBlockWidth(line, codeBg, blockWidth) {
955
+ const w = visibleLineWidth(line);
956
+ const pad = Math.max(0, blockWidth - w);
957
+ return codeBg(`${line ?? ""}${" ".repeat(pad)}`);
958
+ }
959
+ function tintCodeBlockBody(langLine, bodyLines, codeBg) {
960
+ const blockWidth = codeBlockContentWidth(langLine, bodyLines);
961
+ const langOut = langLine ? tintCodeLineToBlockWidth(langLine, codeBg, blockWidth) : "";
962
+ const bodyOut = bodyLines.map((line) => tintCodeLineToBlockWidth(line, codeBg, blockWidth)).join(EOL);
963
+ return { langOut, bodyOut };
938
964
  }
939
965
  function contentWidthAfterPrefix(width, prefix) {
940
966
  const base = Number(width) || 0;
@@ -994,37 +1020,62 @@ function colorizeDiffLine(line, c) {
994
1020
  function colorizeDiffStatTrailer(line, c) {
995
1021
  return line.replace(/(\d+)(\s+insertions?\(\+\))/g, (_, n, rest) => `${c.diffAdded(n)}${c.diffContext(rest)}`).replace(/(\d+)(\s+deletions?\(-\))/g, (_, n, rest) => `${c.diffRemoved(n)}${c.diffContext(rest)}`);
996
1022
  }
997
- function renderDiffBody(text, c, bandWidth) {
1023
+ function collectDiffBodyLines(text, c, bandWidth) {
998
1024
  const lines = [];
999
1025
  for (const line of String(text ?? "").split(EOL)) {
1000
1026
  const colored = colorizeDiffLine(line, c);
1001
- lines.push(...wrapIndentedCodeLine(colored, bandWidth));
1002
- }
1003
- return tintCodeLines(lines, c.codeBg);
1004
- }
1005
- var KEYWORDS = {
1006
- js: ["const", "let", "var", "function", "return", "if", "else", "for", "while", "do", "switch", "case", "break", "continue", "new", "class", "extends", "super", "this", "import", "export", "from", "default", "async", "await", "yield", "try", "catch", "finally", "throw", "typeof", "instanceof", "in", "of", "void", "delete", "null", "undefined", "true", "false"],
1007
- py: ["def", "class", "return", "if", "elif", "else", "for", "while", "import", "from", "as", "with", "try", "except", "finally", "raise", "pass", "break", "continue", "lambda", "yield", "global", "nonlocal", "async", "await", "and", "or", "not", "in", "is", "None", "True", "False", "self"],
1008
- sh: ["if", "then", "else", "elif", "fi", "for", "while", "do", "done", "case", "esac", "function", "return", "in", "export", "local", "echo", "cd", "set", "unset", "read", "source"],
1009
- css: [],
1010
- go: ["package", "import", "func", "return", "if", "else", "for", "range", "switch", "case", "default", "break", "continue", "fallthrough", "goto", "defer", "go", "select", "chan", "map", "struct", "interface", "type", "var", "const", "nil", "true", "false", "iota", "string", "int", "int64", "float64", "bool", "byte", "rune", "error"],
1011
- rust: ["fn", "let", "mut", "const", "static", "return", "if", "else", "match", "for", "while", "loop", "break", "continue", "struct", "enum", "trait", "impl", "mod", "use", "pub", "crate", "self", "super", "where", "as", "dyn", "move", "ref", "unsafe", "async", "await", "type", "true", "false", "Some", "None", "Ok", "Err", "Box", "Vec", "String", "usize", "isize", "i32", "u32", "i64", "u64", "f64", "bool"],
1012
- java: ["public", "private", "protected", "class", "interface", "enum", "extends", "implements", "abstract", "final", "static", "void", "new", "return", "if", "else", "for", "while", "do", "switch", "case", "default", "break", "continue", "try", "catch", "finally", "throw", "throws", "import", "package", "this", "super", "instanceof", "synchronized", "volatile", "transient", "native", "int", "long", "short", "byte", "char", "float", "double", "boolean", "true", "false", "null"],
1013
- c: ["auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long", "register", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", "class", "namespace", "template", "public", "private", "protected", "virtual", "new", "delete", "using", "nullptr", "true", "false", "bool"],
1014
- ruby: ["def", "end", "class", "module", "if", "elsif", "else", "unless", "case", "when", "then", "while", "until", "for", "in", "do", "begin", "rescue", "ensure", "raise", "return", "yield", "break", "next", "redo", "retry", "self", "nil", "true", "false", "and", "or", "not", "require", "require_relative", "attr_accessor", "attr_reader", "attr_writer", "puts", "lambda", "proc"],
1015
- sql: ["select", "from", "where", "insert", "into", "values", "update", "set", "delete", "create", "alter", "drop", "table", "view", "index", "join", "inner", "left", "right", "outer", "full", "on", "group", "by", "order", "having", "limit", "offset", "distinct", "as", "and", "or", "not", "null", "is", "in", "between", "like", "union", "all", "primary", "key", "foreign", "references", "default", "constraint", "unique", "count", "sum", "avg", "min", "max"],
1016
- yaml: [],
1017
- toml: []
1027
+ lines.push(...wrapCodeLine(colored, bandWidth));
1028
+ }
1029
+ return lines;
1030
+ }
1031
+ var FAMILY_TO_HLJS = {
1032
+ js: "javascript",
1033
+ ts: "typescript",
1034
+ tsx: "tsx",
1035
+ jsx: "jsx",
1036
+ json: "json",
1037
+ sh: "bash",
1038
+ py: "python",
1039
+ css: "css",
1040
+ html: "xml",
1041
+ go: "go",
1042
+ rust: "rust",
1043
+ java: "java",
1044
+ c: "cpp",
1045
+ ruby: "ruby",
1046
+ sql: "sql",
1047
+ yaml: "yaml",
1048
+ toml: "ini",
1049
+ kotlin: "kotlin",
1050
+ swift: "swift",
1051
+ php: "php",
1052
+ csharp: "csharp",
1053
+ dockerfile: "dockerfile",
1054
+ protobuf: "protobuf",
1055
+ scala: "scala",
1056
+ dart: "dart",
1057
+ lua: "lua",
1058
+ perl: "perl",
1059
+ r: "r",
1060
+ objc: "objectivec",
1061
+ powershell: "powershell",
1062
+ makefile: "makefile",
1063
+ nginx: "nginx",
1064
+ ini: "ini",
1065
+ vim: "vim",
1066
+ haskell: "haskell",
1067
+ elixir: "elixir",
1068
+ clojure: "clojure"
1018
1069
  };
1019
1070
  var LANG_FAMILY = {
1020
1071
  js: "js",
1021
1072
  javascript: "js",
1022
1073
  mjs: "js",
1023
1074
  cjs: "js",
1024
- ts: "js",
1025
- typescript: "js",
1026
- jsx: "js",
1027
- tsx: "js",
1075
+ ts: "ts",
1076
+ typescript: "ts",
1077
+ jsx: "jsx",
1078
+ tsx: "tsx",
1028
1079
  json: "json",
1029
1080
  json5: "json",
1030
1081
  bash: "sh",
@@ -1056,51 +1107,173 @@ var LANG_FAMILY = {
1056
1107
  sql: "sql",
1057
1108
  yaml: "yaml",
1058
1109
  yml: "yaml",
1059
- toml: "toml"
1110
+ toml: "toml",
1111
+ kotlin: "kotlin",
1112
+ kt: "kotlin",
1113
+ kts: "kotlin",
1114
+ swift: "swift",
1115
+ php: "php",
1116
+ csharp: "csharp",
1117
+ cs: "csharp",
1118
+ "c#": "csharp",
1119
+ dockerfile: "dockerfile",
1120
+ docker: "dockerfile",
1121
+ graphql: "graphql",
1122
+ gql: "graphql",
1123
+ protobuf: "protobuf",
1124
+ proto: "protobuf",
1125
+ scala: "scala",
1126
+ dart: "dart",
1127
+ lua: "lua",
1128
+ perl: "perl",
1129
+ pl: "perl",
1130
+ r: "r",
1131
+ rl: "r",
1132
+ objc: "objc",
1133
+ "objective-c": "objc",
1134
+ "obj-c": "objc",
1135
+ powershell: "powershell",
1136
+ ps1: "powershell",
1137
+ ps: "powershell",
1138
+ pwsh: "powershell",
1139
+ makefile: "makefile",
1140
+ make: "makefile",
1141
+ nginx: "nginx",
1142
+ ini: "ini",
1143
+ vim: "vim",
1144
+ haskell: "haskell",
1145
+ hs: "haskell",
1146
+ elixir: "elixir",
1147
+ ex: "elixir",
1148
+ exs: "elixir",
1149
+ clojure: "clojure",
1150
+ clj: "clojure"
1060
1151
  };
1061
- var HASH_COMMENT_FAMILIES = /* @__PURE__ */ new Set(["sh", "py", "yaml", "toml"]);
1062
- function highlightCodeLine(line, family, c) {
1063
- const kw = new Set(KEYWORDS[family === "json" ? "js" : family] ?? []);
1064
- if (family === "js" && /^\s*\/\//.test(line)) return c.synComment(line);
1065
- if (HASH_COMMENT_FAMILIES.has(family) && /^\s*#/.test(line)) return c.synComment(line);
1066
- if (family === "html" && /^\s*<!--/.test(line)) return c.synComment(line);
1067
- const TOKEN_RE = /(`(?:\\.|[^`\\])*`|"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*')|(\/\/[^\n]*|#[^\n]*)|(\b\d+(?:\.\d+)?\b)|([A-Za-z_$][A-Za-z0-9_$]*)|([{}()[\].,;:=+\-*/%<>!&|^~?]+)/g;
1068
- let out = "";
1069
- let last = 0;
1070
- let m;
1071
- TOKEN_RE.lastIndex = 0;
1072
- while ((m = TOKEN_RE.exec(line)) !== null) {
1073
- if (m.index > last) out += c.body(line.slice(last, m.index));
1074
- const [, str, comment, num2, ident, punct] = m;
1075
- if (str !== void 0) {
1076
- out += c.synString(str);
1077
- } else if (comment !== void 0) {
1078
- if (comment.startsWith("//") ? family === "js" : HASH_COMMENT_FAMILIES.has(family)) {
1079
- out += c.synComment(comment);
1080
- } else {
1081
- out += c.body(comment);
1082
- }
1083
- } else if (num2 !== void 0) {
1084
- out += c.synNumber(num2);
1085
- } else if (ident !== void 0) {
1086
- if (kw.has(ident)) out += c.synKeyword(ident);
1087
- else if (line[TOKEN_RE.lastIndex] === "(") out += c.synFunction(ident);
1088
- else out += c.body(ident);
1089
- } else if (punct !== void 0) {
1090
- out += c.synOperator(punct);
1152
+ var HIGHLIGHT_CACHE_MAX = 300;
1153
+ var highlightCache = /* @__PURE__ */ new Map();
1154
+ var _hljsThemeVersion = -1;
1155
+ var _hljsTheme = null;
1156
+ function buildCliHighlightTheme(c) {
1157
+ const plain = (s) => c.body(s);
1158
+ return {
1159
+ default: plain,
1160
+ keyword: c.synKeyword,
1161
+ built_in: c.synType,
1162
+ type: c.synType,
1163
+ literal: c.synKeyword,
1164
+ number: c.synNumber,
1165
+ regexp: c.synString,
1166
+ string: c.synString,
1167
+ subst: plain,
1168
+ symbol: plain,
1169
+ class: c.synType,
1170
+ function: c.synFunction,
1171
+ title: c.synFunction,
1172
+ params: c.synVariable,
1173
+ comment: c.synComment,
1174
+ doctag: c.synComment,
1175
+ meta: c.synComment,
1176
+ section: c.synType,
1177
+ tag: c.synPunct,
1178
+ name: c.synFunction,
1179
+ builtin: c.synType,
1180
+ attr: c.synType,
1181
+ attribute: c.synType,
1182
+ variable: c.synVariable,
1183
+ selector: c.synKeyword,
1184
+ template: c.synVariable,
1185
+ bullet: plain,
1186
+ code: plain,
1187
+ emphasis: plain,
1188
+ strong: plain,
1189
+ formula: plain,
1190
+ link: plain,
1191
+ quote: plain,
1192
+ addition: c.synString,
1193
+ deletion: c.synString
1194
+ };
1195
+ }
1196
+ function getCliHighlightTheme() {
1197
+ const version = getThemeVersion();
1198
+ if (_hljsTheme && _hljsThemeVersion === version) return _hljsTheme;
1199
+ _hljsThemeVersion = version;
1200
+ _hljsTheme = buildCliHighlightTheme(extraColorizers());
1201
+ return _hljsTheme;
1202
+ }
1203
+ function hljsLanguageFromFamily(family) {
1204
+ if (!family || family === "md") return null;
1205
+ const mapped = FAMILY_TO_HLJS[family];
1206
+ if (mapped && supportsLanguage(mapped)) return mapped;
1207
+ if (supportsLanguage(family)) return family;
1208
+ return null;
1209
+ }
1210
+ function resolveHljsLanguage(lang) {
1211
+ const normalized = normalizeLang(lang);
1212
+ if (!normalized) return null;
1213
+ const viaFamily = hljsLanguageFromFamily(LANG_FAMILY[normalized]);
1214
+ if (viaFamily) return viaFamily;
1215
+ return supportsLanguage(normalized) ? normalized : null;
1216
+ }
1217
+ function highlightCodeText(text, hljsLang) {
1218
+ if (!hljsLang || !supportsLanguage(hljsLang)) return null;
1219
+ const src = String(text ?? "");
1220
+ if (!src.trim()) return null;
1221
+ if (!/[A-Za-z0-9]/.test(src)) return null;
1222
+ const cacheKey = `${hljsLang}|${getThemeVersion()}|${src}`;
1223
+ const cached = highlightCache.get(cacheKey);
1224
+ if (cached !== void 0) {
1225
+ highlightCache.delete(cacheKey);
1226
+ highlightCache.set(cacheKey, cached);
1227
+ return cached;
1228
+ }
1229
+ try {
1230
+ const out = highlight(src, {
1231
+ language: hljsLang,
1232
+ theme: getCliHighlightTheme(),
1233
+ ignoreIllegals: true
1234
+ });
1235
+ if (highlightCache.size >= HIGHLIGHT_CACHE_MAX) {
1236
+ const first = highlightCache.keys().next().value;
1237
+ if (first !== void 0) highlightCache.delete(first);
1091
1238
  }
1092
- last = TOKEN_RE.lastIndex;
1239
+ highlightCache.set(cacheKey, out);
1240
+ return out;
1241
+ } catch {
1242
+ return null;
1093
1243
  }
1094
- if (last < line.length) out += c.body(line.slice(last));
1095
- return out;
1096
1244
  }
1097
- function renderHighlightedBody(text, family, c, bandWidth) {
1245
+ function highlightCodeLine(line, family, c) {
1246
+ const hljsLang = hljsLanguageFromFamily(family);
1247
+ const highlighted = highlightCodeText(line, hljsLang);
1248
+ if (highlighted != null) return highlighted;
1249
+ return line ? c.body(line) : "";
1250
+ }
1251
+ function highlightCodeBlockToLines(text, family, c) {
1252
+ const hljsLang = hljsLanguageFromFamily(family);
1253
+ const raw = String(text ?? "");
1254
+ const highlighted = hljsLang ? highlightCodeText(raw, hljsLang) : null;
1255
+ if (highlighted != null) {
1256
+ return highlighted.split(EOL);
1257
+ }
1258
+ return raw.split(EOL).map((line) => line ? c.body(line) : "");
1259
+ }
1260
+ function collectFlatBodyLines(text, codeBlock, bandWidth) {
1098
1261
  const lines = [];
1099
1262
  for (const line of String(text ?? "").split(EOL)) {
1100
- const colored = line ? highlightCodeLine(line, family, c) : "";
1101
- lines.push(...wrapIndentedCodeLine(colored, bandWidth));
1263
+ const colored = codeBlock(line);
1264
+ lines.push(...wrapCodeLine(colored, bandWidth));
1265
+ }
1266
+ return lines;
1267
+ }
1268
+ function collectHighlightedBodyLines(text, hljsLang, bandWidth) {
1269
+ const highlighted = highlightCodeText(text, hljsLang);
1270
+ const { codeBlock } = colorizers();
1271
+ const source = highlighted != null ? highlighted : String(text ?? "").split(EOL).map(codeBlock).join(EOL);
1272
+ const lines = [];
1273
+ for (const line of source.split(EOL)) {
1274
+ lines.push(...wrapCodeLine(line, bandWidth));
1102
1275
  }
1103
- return tintCodeLines(lines, c.codeBg);
1276
+ return lines;
1104
1277
  }
1105
1278
  function renderCodeBlock(token, width = 0) {
1106
1279
  const { codeBlock } = colorizers();
@@ -1108,24 +1281,20 @@ function renderCodeBlock(token, width = 0) {
1108
1281
  const lang = normalizeLang(token.lang);
1109
1282
  const text = decodeEntities(token.text ?? "");
1110
1283
  const bandWidth = Math.max(8, Number(width) || 80);
1111
- let body;
1284
+ let bodyLines;
1112
1285
  if (DIFF_LANGS.has(lang) || !lang && looksLikeUnifiedDiff(text)) {
1113
- body = renderDiffBody(text, c, bandWidth);
1286
+ bodyLines = collectDiffBodyLines(text, c, bandWidth);
1114
1287
  } else {
1288
+ const hljsLang = resolveHljsLanguage(lang);
1115
1289
  const family = LANG_FAMILY[lang];
1116
- if (family && family !== "md") {
1117
- body = renderHighlightedBody(text, family, c, bandWidth);
1290
+ if (hljsLang && family !== "md") {
1291
+ bodyLines = collectHighlightedBodyLines(text, hljsLang, bandWidth);
1118
1292
  } else {
1119
- const lines = [];
1120
- for (const line of text.split(EOL)) {
1121
- const colored = codeBlock(line);
1122
- lines.push(...wrapIndentedCodeLine(colored, bandWidth));
1123
- }
1124
- body = tintCodeLines(lines, c.codeBg);
1293
+ bodyLines = collectFlatBodyLines(text, codeBlock, bandWidth);
1125
1294
  }
1126
1295
  }
1127
- const langLine = lang ? `${c.codeBg(c.fenceBorder(lang))}${EOL}` : "";
1128
- return `${langLine}${body}${body ? EOL : ""}`;
1296
+ const { bodyOut } = tintCodeBlockBody(null, bodyLines, c.codeBg);
1297
+ return `${bodyOut}${bodyOut ? EOL : ""}`;
1129
1298
  }
1130
1299
  function numberToLetter(n) {
1131
1300
  let result = "";
@@ -1183,14 +1352,15 @@ function formatToken(token, listBaseIndent = 0, orderedListNumber = null, parent
1183
1352
  const quotePrefix = `${BLOCKQUOTE_BAR} `;
1184
1353
  const innerWidth = contentWidthAfterPrefix(width, quotePrefix);
1185
1354
  const inner = (token.tokens ?? []).map((t) => formatToken(t, 0, null, null, innerWidth)).join("");
1186
- return inner.split(EOL).map(
1187
- (line) => stripAnsi(line).trim() ? `${bar} ${quoteText(chalk.italic(line))}` : line
1188
- ).join(EOL);
1355
+ return inner.split(EOL).map((line) => {
1356
+ if (stringWidth(stripAnsi(line)) === 0) return line;
1357
+ return `${bar} ${quoteText(chalk.italic(line))}`;
1358
+ }).join(EOL);
1189
1359
  }
1190
1360
  case "code":
1191
1361
  return renderCodeBlock(token, width);
1192
1362
  case "codespan":
1193
- return accent(decodeEntities(token.text));
1363
+ return ex.codeSpanBg(accent(decodeEntities(token.text)));
1194
1364
  case "em":
1195
1365
  return ex.emph(chalk.italic((token.tokens ?? []).map((t) => formatToken(t, 0, null, parent)).join("")));
1196
1366
  case "strong":
@@ -1296,7 +1466,7 @@ function formatListItem(token, listBaseIndent, orderedListNumber, parent, depth
1296
1466
  out += `${markerPrefix.trimEnd()}${EOL}`;
1297
1467
  firstBlock = false;
1298
1468
  }
1299
- out += formatToken(child, nestedListIndent, null, token, childWidth, depth + 1);
1469
+ out += formatToken(child, nestedListIndent, null, token, width, depth + 1);
1300
1470
  continue;
1301
1471
  }
1302
1472
  const rendered = formatToken(child, listBaseIndent, orderedListNumber, token, childWidth, depth);
@@ -3579,10 +3749,51 @@ import stringWidth3 from "string-width";
3579
3749
  import stripAnsi3 from "strip-ansi";
3580
3750
  var DEFAULT_MARKDOWN_WIDTH = 80;
3581
3751
  var MAX_EXPANDED_CHARS = 256 * 1024;
3582
- var MAX_EXPANDED_LINES = 80;
3752
+ var MAX_EXPANDED_LINES = 4e3;
3583
3753
  var MAX_JSON_FORMAT_LENGTH = 1e4;
3584
3754
  var MAX_HIGHLIGHT_LINE_CHARS = 2e3;
3585
3755
  var MIN_EXPANDED_BODY_COLS = 24;
3756
+ function resolveToolOutputMaxRenderLines() {
3757
+ const raw = process.env.MIXDOG_TUI_TOOL_OUTPUT_MAX_RENDER_LINES;
3758
+ if (raw !== void 0 && String(raw).trim() !== "") {
3759
+ const v = Number(raw);
3760
+ if (Number.isFinite(v) && v <= 0) return 0;
3761
+ if (Number.isFinite(v) && v > 0) return Math.floor(v);
3762
+ }
3763
+ const legacy = process.env.MIXDOG_TUI_EXPANDED_MAX_ROWS;
3764
+ if (legacy !== void 0 && String(legacy).trim() !== "") {
3765
+ const v = Number(legacy);
3766
+ if (Number.isFinite(v) && v > 0) return Math.floor(v);
3767
+ }
3768
+ return 600;
3769
+ }
3770
+ function omittedPhysicalRowsMarker(omitted, isShell) {
3771
+ if (isShell) {
3772
+ const n = Math.max(1, Math.floor(Number(omitted) || 0));
3773
+ return `\u2026 [${n} line${n === 1 ? "" : "s"} omitted above \u2014 showing newest output below]`;
3774
+ }
3775
+ return "\u2026 [output truncated for display \u2014 collapse (ctrl+o) or re-read a narrower range]";
3776
+ }
3777
+ function shellLogicalOmittedMarker({ omittedLines = 0, omittedChars = false }, c) {
3778
+ if (omittedLines > 0) {
3779
+ return c.synComment(omittedPhysicalRowsMarker(omittedLines, true));
3780
+ }
3781
+ if (omittedChars) {
3782
+ return c.synComment("\u2026 [earlier output omitted above \u2014 showing newest output below]");
3783
+ }
3784
+ return null;
3785
+ }
3786
+ function finalizeShellPhysicalCap(buffer, omitted, maxRows) {
3787
+ const bodySlots = Math.max(0, maxRows - 1);
3788
+ if (omitted <= 0) {
3789
+ return buffer.length > 0 ? buffer : [" "];
3790
+ }
3791
+ const tail = bodySlots > 0 ? buffer.slice(-bodySlots) : [];
3792
+ const extraHidden = Math.max(0, buffer.length - bodySlots);
3793
+ const totalOmitted = omitted + extraHidden;
3794
+ const out = [omittedPhysicalRowsMarker(totalOmitted, true), ...tail];
3795
+ return out.length > 0 ? out.slice(0, maxRows) : [" "];
3796
+ }
3586
3797
  var READ_LINE_RE = /^(\s*)(\d+)(\u2192)(.*)$/;
3587
3798
  var GREP_LINE_RE = /^(\s*)((?:[A-Za-z]:[\\/](?:[^\n:])*|[^\n:]*):\d+:|\d+:)(\s?)(.*)$/;
3588
3799
  var URL_RE = /https?:\/\/[^\s"'<>\x1b\\)\]]+/g;
@@ -3688,17 +3899,21 @@ function formatExpandedResult(text, { pathArg = "", isShell = false } = {}) {
3688
3899
  let src = String(text ?? "");
3689
3900
  if (!src) return [];
3690
3901
  let truncatedChars = false;
3902
+ let shellOmittedLines = 0;
3903
+ let shellOmittedChars = false;
3691
3904
  if (src.length > MAX_EXPANDED_CHARS) {
3692
- src = src.slice(0, MAX_EXPANDED_CHARS);
3693
- truncatedChars = true;
3905
+ src = isShell ? src.slice(-MAX_EXPANDED_CHARS) : src.slice(0, MAX_EXPANDED_CHARS);
3906
+ if (isShell) shellOmittedChars = true;
3907
+ else truncatedChars = true;
3694
3908
  }
3695
3909
  const carriesAnsi = hasAnsi(src);
3696
3910
  if (!carriesAnsi) src = tryFormatJson(src);
3697
3911
  let lines = src.split("\n");
3698
3912
  let truncatedLines = false;
3699
3913
  if (lines.length > MAX_EXPANDED_LINES) {
3700
- lines = lines.slice(0, MAX_EXPANDED_LINES);
3701
- truncatedLines = true;
3914
+ if (isShell) shellOmittedLines = lines.length - MAX_EXPANDED_LINES;
3915
+ lines = isShell ? lines.slice(-MAX_EXPANDED_LINES) : lines.slice(0, MAX_EXPANDED_LINES);
3916
+ if (!isShell) truncatedLines = true;
3702
3917
  }
3703
3918
  const c = extraColorizers();
3704
3919
  const diffMode = !carriesAnsi && !isShell && looksLikeUnifiedDiff(src);
@@ -3707,21 +3922,28 @@ function formatExpandedResult(text, { pathArg = "", isShell = false } = {}) {
3707
3922
  if (shouldRenderExpandedMarkdown({ src, lines, carriesAnsi, isShell, diffMode, family })) {
3708
3923
  out = formatExpandedMarkdownLines(src);
3709
3924
  if (out.length > MAX_EXPANDED_LINES) {
3710
- out = out.slice(0, MAX_EXPANDED_LINES);
3711
- truncatedLines = true;
3925
+ if (isShell) shellOmittedLines += out.length - MAX_EXPANDED_LINES;
3926
+ out = isShell ? out.slice(-MAX_EXPANDED_LINES) : out.slice(0, MAX_EXPANDED_LINES);
3927
+ if (!isShell) truncatedLines = true;
3712
3928
  }
3713
3929
  } else {
3714
- out = lines.map((line) => formatLine(line, { c, family, diffMode, carriesAnsi, isShell }));
3930
+ if (family && family !== "md" && !diffMode && !carriesAnsi && !isShell) {
3931
+ out = formatSyntaxBlock(lines, { c, family });
3932
+ } else {
3933
+ out = lines.map((line) => formatLine(line, { c, family, diffMode, carriesAnsi, isShell }));
3934
+ }
3935
+ }
3936
+ if (isShell) {
3937
+ const marker = shellLogicalOmittedMarker({ omittedLines: shellOmittedLines, omittedChars: shellOmittedChars }, c);
3938
+ if (marker) return [marker, ...out];
3939
+ return out;
3715
3940
  }
3716
3941
  if (truncatedChars || truncatedLines) {
3717
3942
  out.push(c.synComment("\u2026 [output truncated for display \u2014 re-read a narrower range]"));
3718
3943
  }
3719
3944
  return out;
3720
3945
  }
3721
- function formatLine(line, { c, family, diffMode, carriesAnsi, isShell }) {
3722
- if (carriesAnsi || isShell) {
3723
- return linkifyUrls(stripUnderlineAnsi(line));
3724
- }
3946
+ function splitGutter(line) {
3725
3947
  let indent = "";
3726
3948
  let gutter = "";
3727
3949
  let body = line;
@@ -3738,6 +3960,26 @@ function formatLine(line, { c, family, diffMode, carriesAnsi, isShell }) {
3738
3960
  body = gm[4];
3739
3961
  }
3740
3962
  }
3963
+ return { indent, gutter, body };
3964
+ }
3965
+ function formatSyntaxBlock(lines, { c, family }) {
3966
+ const parts = lines.map(splitGutter);
3967
+ const bodies = parts.map(
3968
+ (p) => p.body.length > MAX_HIGHLIGHT_LINE_CHARS ? "" : p.body
3969
+ );
3970
+ const highlighted = highlightCodeBlockToLines(bodies.join("\n"), family, c);
3971
+ return parts.map((p, i) => {
3972
+ const rawBody = p.body;
3973
+ const bodyOut = rawBody.length > MAX_HIGHLIGHT_LINE_CHARS ? c.body(rawBody) : highlighted[i] ?? "";
3974
+ const linked = linkifyUrls(bodyOut);
3975
+ return p.gutter ? `${p.indent}${c.synComment(p.gutter)}${linked}` : linked;
3976
+ });
3977
+ }
3978
+ function formatLine(line, { c, family, diffMode, carriesAnsi, isShell }) {
3979
+ if (carriesAnsi || isShell) {
3980
+ return linkifyUrls(stripUnderlineAnsi(line));
3981
+ }
3982
+ const { indent, gutter, body } = splitGutter(line);
3741
3983
  const coloredBody = highlightBody(body, { c, family, diffMode });
3742
3984
  const linked = linkifyUrls(coloredBody);
3743
3985
  return gutter ? `${indent}${c.synComment(gutter)}${linked}` : linked;
@@ -3811,12 +4053,47 @@ function wrapOneExpandedLogicalLine(line, maxWidth) {
3811
4053
  }
3812
4054
  return out;
3813
4055
  }
3814
- function wrapExpandedResultLines(logicalLines, columns = 80) {
4056
+ function wrapExpandedResultLines(logicalLines, columns = 80, { isShell = false } = {}) {
4057
+ const maxRows = resolveToolOutputMaxRenderLines();
4058
+ const capOn = maxRows > 0;
3815
4059
  const maxWidth = expandedResultBodyWidth(columns);
3816
4060
  const lines = Array.isArray(logicalLines) ? logicalLines : [];
3817
4061
  const out = [];
3818
- for (const line of lines) {
3819
- out.push(...wrapOneExpandedLogicalLine(line, maxWidth));
4062
+ if (!capOn) {
4063
+ for (const line of lines) {
4064
+ for (const row of wrapOneExpandedLogicalLine(line, maxWidth)) out.push(row);
4065
+ }
4066
+ return out.length > 0 ? out : [" "];
4067
+ }
4068
+ if (isShell) {
4069
+ let omitted = 0;
4070
+ for (const line of lines) {
4071
+ for (const row of wrapOneExpandedLogicalLine(line, maxWidth)) {
4072
+ out.push(row);
4073
+ if (out.length > maxRows) {
4074
+ out.shift();
4075
+ omitted += 1;
4076
+ }
4077
+ }
4078
+ }
4079
+ return finalizeShellPhysicalCap(out, omitted, maxRows);
4080
+ }
4081
+ let truncated = false;
4082
+ outer: for (const line of lines) {
4083
+ for (const row of wrapOneExpandedLogicalLine(line, maxWidth)) {
4084
+ if (out.length < maxRows) {
4085
+ out.push(row);
4086
+ } else {
4087
+ truncated = true;
4088
+ break outer;
4089
+ }
4090
+ }
4091
+ }
4092
+ if (truncated) {
4093
+ const bodySlots = Math.max(0, maxRows - 1);
4094
+ if (out.length > bodySlots) out.length = bodySlots;
4095
+ if (maxRows > 0) out.push(omittedPhysicalRowsMarker(1, false));
4096
+ return out.length > 0 ? out.slice(0, maxRows) : [" "];
3820
4097
  }
3821
4098
  return out.length > 0 ? out : [" "];
3822
4099
  }
@@ -3869,7 +4146,11 @@ function renderDeltaText(text) {
3869
4146
  return deltaTextParts(text).map((part, index) => part.color ? /* @__PURE__ */ jsx5(Text5, { color: part.color, children: part.text }, index) : part.text);
3870
4147
  }
3871
4148
  function ResultBody({ lines, rawText, pathArg = "", isShell = false, columns, color, raw }) {
3872
- const renderLines = raw ? wrapExpandedResultLines(formatExpandedResult(rawText, { pathArg, isShell }), columns) : lines || [];
4149
+ const renderLines = raw ? wrapExpandedResultLines(
4150
+ formatExpandedResult(rawText, { pathArg, isShell }),
4151
+ columns,
4152
+ { isShell }
4153
+ ) : lines || [];
3873
4154
  if (!renderLines || renderLines.length === 0) return null;
3874
4155
  return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", children: [
3875
4156
  /* @__PURE__ */ jsx5(Box3, { flexShrink: 0, flexDirection: "column", children: renderLines.map((_, i) => /* @__PURE__ */ jsx5(Text5, { color: theme.subtle, children: i === 0 ? RESULT_GUTTER : RESULT_GUTTER_CONT }, i)) }),
@@ -5826,6 +6107,7 @@ function hintStyle(tone) {
5826
6107
  return { textColor: theme.inactive };
5827
6108
  }
5828
6109
  var IME_LEFT_GUARD_COLUMNS = 0;
6110
+ var MOUSE_EXTEND_COALESCE_MS = 24;
5829
6111
  function insertText(draft, input) {
5830
6112
  if (!input) return draft;
5831
6113
  return replaceSelection(draft, input);
@@ -5901,6 +6183,7 @@ function PromptInput({
5901
6183
  const cursorEnabledRef = useRef4(false);
5902
6184
  const contentWidthRef = useRef4(80);
5903
6185
  const preferredColumnRef = useRef4(null);
6186
+ const mouseExtendCoalesceRef = useRef4({ pendingNext: null, timer: null, t: 0 });
5904
6187
  const { value, cursor } = draft;
5905
6188
  draftRef.current = draft;
5906
6189
  if (selectionRef) {
@@ -5969,25 +6252,79 @@ function PromptInput({
5969
6252
  const updateDraft = (fn, options = {}) => {
5970
6253
  commitDraft(fn(draftRef.current), options);
5971
6254
  };
6255
+ const cancelMouseExtendCoalesce = () => {
6256
+ const state = mouseExtendCoalesceRef.current;
6257
+ if (state.timer) {
6258
+ clearTimeout(state.timer);
6259
+ state.timer = null;
6260
+ }
6261
+ state.pendingNext = null;
6262
+ };
6263
+ const queueMouseExtendCommit = (next, immediate = false) => {
6264
+ if (immediate) {
6265
+ cancelMouseExtendCoalesce();
6266
+ commitDraft(next);
6267
+ mouseExtendCoalesceRef.current.t = Date.now();
6268
+ return;
6269
+ }
6270
+ if (draftStateEqual(draftRef.current, next)) {
6271
+ cancelMouseExtendCoalesce();
6272
+ commitDraft(next);
6273
+ return;
6274
+ }
6275
+ const state = mouseExtendCoalesceRef.current;
6276
+ state.pendingNext = next;
6277
+ const now = Date.now();
6278
+ const elapsed = now - state.t;
6279
+ if (elapsed >= MOUSE_EXTEND_COALESCE_MS) {
6280
+ cancelMouseExtendCoalesce();
6281
+ state.t = now;
6282
+ commitDraft(next);
6283
+ return;
6284
+ }
6285
+ if (state.timer) return;
6286
+ state.timer = setTimeout(() => {
6287
+ const current = mouseExtendCoalesceRef.current;
6288
+ const pending = current.pendingNext;
6289
+ current.timer = null;
6290
+ current.pendingNext = null;
6291
+ current.t = Date.now();
6292
+ if (pending) commitDraft(pending);
6293
+ }, Math.max(1, MOUSE_EXTEND_COALESCE_MS - elapsed));
6294
+ state.timer.unref?.();
6295
+ };
5972
6296
  if (mouseSelectionRef) {
5973
6297
  mouseSelectionRef.current = {
5974
6298
  offsetAtCell: (row, col) => offsetAtCell(draftRef.current.value, row, col, contentWidthRef.current),
5975
6299
  anchorAt: (offset) => {
6300
+ cancelMouseExtendCoalesce();
5976
6301
  const value2 = draftRef.current.value;
5977
6302
  const off = Math.max(0, Math.min(value2.length, Math.floor(Number(offset) || 0)));
5978
6303
  commitDraft({ ...draftRef.current, cursor: off, selectionAnchor: off });
6304
+ mouseExtendCoalesceRef.current.t = Date.now();
5979
6305
  },
5980
- extendTo: (offset) => {
6306
+ extendTo: (offset, immediate = false) => {
6307
+ if (offset == null) {
6308
+ if (immediate) cancelMouseExtendCoalesce();
6309
+ return;
6310
+ }
5981
6311
  const d = draftRef.current;
5982
6312
  const off = Math.max(0, Math.min(d.value.length, Math.floor(Number(offset) || 0)));
5983
6313
  const anchor = Number.isFinite(d.selectionAnchor) ? d.selectionAnchor : d.cursor;
5984
- commitDraft({ ...d, cursor: off, selectionAnchor: anchor });
6314
+ queueMouseExtendCommit({ ...d, cursor: off, selectionAnchor: anchor }, immediate);
5985
6315
  },
5986
6316
  clear: () => {
6317
+ cancelMouseExtendCoalesce();
5987
6318
  if (selectionRange(draftRef.current)) commitDraft(clearSelection(draftRef.current));
5988
6319
  }
5989
6320
  };
5990
6321
  }
6322
+ useEffect3(() => () => {
6323
+ const state = mouseExtendCoalesceRef.current;
6324
+ if (state.timer) clearTimeout(state.timer);
6325
+ state.timer = null;
6326
+ state.pendingNext = null;
6327
+ }, []);
5991
6328
  const moveDraftVertically = (direction, { extend = false } = {}) => {
5992
6329
  const current = draftRef.current;
5993
6330
  const moved = verticalOffset(
@@ -8949,6 +9286,12 @@ function toolHasDisplayResultForRows(item) {
8949
9286
  }
8950
9287
  return true;
8951
9288
  }
9289
+ function toolExpandedRawTextForRows(item, rawRt) {
9290
+ if (item?.aggregate) return rawRt;
9291
+ const hasDisplayResult = toolHasDisplayResultForRows(item);
9292
+ if (hasDisplayResult) return toolDisplayedResultTextForRows(item);
9293
+ return rawRt;
9294
+ }
8952
9295
  function toolHeaderFailureOnlyForRows(item, normalizedName, hasDisplayResult) {
8953
9296
  if (hasDisplayResult) return false;
8954
9297
  const bgArgs = backgroundArgsForRows(item.args);
@@ -8979,16 +9322,21 @@ function toolArgPathForRows(item) {
8979
9322
  const a = backgroundArgsForRows(item?.args);
8980
9323
  return a?.path ?? a?.file_path ?? a?.file ?? "";
8981
9324
  }
8982
- function isShellSurfaceForRows(normalizedName) {
9325
+ function isShellSurfaceForRows(normalizedName, label = "") {
8983
9326
  const n = String(normalizedName || "").toLowerCase();
8984
- return n === "shell" || n === "bash" || n === "bash_session" || n === "shell_command" || n === "job_wait";
9327
+ const l = String(label || "").toLowerCase();
9328
+ return n === "shell" || n === "bash" || n === "bash_session" || n === "shell_command" || n === "job_wait" || l === "run";
9329
+ }
9330
+ function isShellSurfaceForToolItem(item, normalizedName) {
9331
+ const label = formatToolSurface(item?.name, item?.args)?.label || "";
9332
+ return isShellSurfaceForRows(normalizedName, label);
8985
9333
  }
8986
9334
  function estimateToolRenderedResultRows(value, { pathArg = "", isShell = false, columns = 80 } = {}) {
8987
9335
  const text = String(value ?? "").replace(/\s+$/, "");
8988
9336
  if (!text) return 1;
8989
9337
  try {
8990
9338
  const logical = formatExpandedResult(text, { pathArg, isShell });
8991
- const rows = wrapExpandedResultLines(logical, columns).length;
9339
+ const rows = wrapExpandedResultLines(logical, columns, { isShell }).length;
8992
9340
  return Math.max(1, rows);
8993
9341
  } catch {
8994
9342
  return Math.max(1, text.split("\n").length);
@@ -9028,8 +9376,9 @@ function estimateTranscriptItemRows(item, columns, toolOutputExpanded) {
9028
9376
  return TOOL_MARGIN_TOP + 1 + 1;
9029
9377
  }
9030
9378
  if (hasRawResult) {
9031
- const rawOpts = item.aggregate ? {} : { pathArg: toolArgPathForRows(item), isShell: isShellSurfaceForRows(normalizedName) };
9032
- return TOOL_MARGIN_TOP + 1 + estimateToolRenderedResultRows(rawRt, { ...rawOpts, columns });
9379
+ const estimateText = toolExpandedRawTextForRows(item, rawRt);
9380
+ const rawOpts = item.aggregate ? {} : { pathArg: toolArgPathForRows(item), isShell: isShellSurfaceForToolItem(item, normalizedName) };
9381
+ return TOOL_MARGIN_TOP + 1 + estimateToolRenderedResultRows(estimateText, { ...rawOpts, columns });
9033
9382
  }
9034
9383
  if (isAgentSurface && !hasResult) return TOOL_MARGIN_TOP + 1 + 1;
9035
9384
  if (isSkillSurface && !hasResult) return TOOL_MARGIN_TOP + 1;
@@ -9054,7 +9403,7 @@ function estimateTranscriptItemRows(item, columns, toolOutputExpanded) {
9054
9403
  const resultText = backgroundMeta?.hasResponse ? backgroundMeta.body : rt;
9055
9404
  const resultRows = estimateToolRenderedResultRows(resultText, {
9056
9405
  pathArg: toolArgPathForRows(item),
9057
- isShell: isShellSurfaceForRows(normalizedName),
9406
+ isShell: isShellSurfaceForToolItem(item, normalizedName),
9058
9407
  columns
9059
9408
  });
9060
9409
  return TOOL_MARGIN_TOP + 1 + resultRows;
@@ -9710,13 +10059,21 @@ function App({ store, initialStatusLine = "" }) {
9710
10059
  if (options.captureText === false) clipped.captureText = false;
9711
10060
  return clipped;
9712
10061
  }, [selectionClip]);
9713
- const paintSelectionRect = useCallback2((clippedRect, { rememberText = true } = {}) => {
10062
+ const paintSelectionRect = useCallback2((clippedRect, { rememberText = true, immediate = false } = {}) => {
9714
10063
  const nextRect = clippedRect || null;
9715
10064
  const state2 = selectionPaintRef.current;
9716
- if (selectionRectsEqual(state2.rect, nextRect)) return false;
10065
+ if (selectionRectsEqual(state2.rect, nextRect)) {
10066
+ const needsCapture = nextRect && rememberText && nextRect.captureText !== false;
10067
+ if (!immediate && !needsCapture) return false;
10068
+ if (immediate || needsCapture) {
10069
+ store.setRenderSelection?.(nextRect, { immediate: true });
10070
+ }
10071
+ if (needsCapture) rememberSelectionTextSoon();
10072
+ return true;
10073
+ }
9717
10074
  state2.rect = nextRect;
9718
10075
  state2.t = Date.now();
9719
- store.setRenderSelection?.(nextRect);
10076
+ store.setRenderSelection?.(nextRect, immediate ? { immediate: true } : void 0);
9720
10077
  if (nextRect && rememberText && nextRect.captureText !== false) rememberSelectionTextSoon();
9721
10078
  return true;
9722
10079
  }, [store, rememberSelectionTextSoon]);
@@ -9730,7 +10087,7 @@ function App({ store, initialStatusLine = "" }) {
9730
10087
  state2.timer = null;
9731
10088
  state2.pending = null;
9732
10089
  }
9733
- paintSelectionRect(clippedRect, { rememberText: true });
10090
+ paintSelectionRect(clippedRect, { rememberText: true, immediate: true });
9734
10091
  }, [paintSelectionRect, withSelectionClip]);
9735
10092
  const applySelectionRectThrottled = useCallback2((rect) => {
9736
10093
  const clippedRect = withSelectionClip(rect, { captureText: false });
@@ -10014,7 +10371,7 @@ function App({ store, initialStatusLine = "" }) {
10014
10371
  if (region === "prompt") {
10015
10372
  const offset = promptOffsetAt(x, y);
10016
10373
  dragRef.current.active = false;
10017
- if (offset != null) promptMouseSelectionRef.current?.extendTo?.(offset);
10374
+ promptMouseSelectionRef.current?.extendTo?.(offset, true);
10018
10375
  continue;
10019
10376
  }
10020
10377
  const anchor = region === "status" ? dragRef.current.anchor : selectionPointAtCurrentScroll(dragRef.current.anchor, dragRef.current.anchorScroll);
@@ -14722,7 +15079,7 @@ ${p.description}` : ""
14722
15079
  if (deltaY === 0) return;
14723
15080
  const clippedRect = withSelectionClip(shiftSelectionRectY(dragRef.current.rect, deltaY));
14724
15081
  dragRef.current = { ...dragRef.current, rect: clippedRect };
14725
- paintSelectionRect(clippedRect, { rememberText: true });
15082
+ paintSelectionRect(clippedRect, { rememberText: true, immediate: true });
14726
15083
  }, [viewportHeight, transcriptWindow.totalRows, transcriptWindow.effectiveScrollOffset, withSelectionClip, paintSelectionRect]);
14727
15084
  useEffect7(() => {
14728
15085
  const maxRows = Math.max(0, Number(transcriptWindow.maxScrollRows) || 0);