@kontextmind/kxm 0.7.175 → 0.7.177

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.
@@ -11,7 +11,7 @@
11
11
  "name": "kxm",
12
12
  "source": "./plugins/kxm",
13
13
  "description": "Durable workflows, peer agents, and kxm tui",
14
- "version": "0.7.175",
14
+ "version": "0.7.177",
15
15
  "category": "development",
16
16
  "tags": ["kxm", "multi-agent", "workflows", "mcp"]
17
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.175",
3
+ "version": "0.7.177",
4
4
  "description": "KXM local-first multi-agent orchestration and operator dashboard",
5
5
  "type": "module",
6
6
  "author": "KontextMind",
@@ -77,9 +77,9 @@
77
77
  ]
78
78
  },
79
79
  "dependencies": {
80
- "@anthropic-ai/claude-agent-sdk": "0.3.283",
81
- "@earendil-works/pi-tui": "0.87.1",
82
- "@modelcontextprotocol/sdk": "1.30.1",
80
+ "@anthropic-ai/claude-agent-sdk": "0.3.289",
81
+ "@earendil-works/pi-tui": "1.0.2",
82
+ "@modelcontextprotocol/sdk": "1.32.0",
83
83
  "yaml": "^2.9.0"
84
84
  },
85
85
  "peerDependencies": {
@@ -95,10 +95,10 @@
95
95
  }
96
96
  },
97
97
  "devDependencies": {
98
- "@earendil-works/pi-coding-agent": "0.87.1",
99
- "@modelcontextprotocol/sdk": "1.30.1",
98
+ "@earendil-works/pi-coding-agent": "1.0.2",
99
+ "@modelcontextprotocol/sdk": "1.32.0",
100
100
  "@playwright/test": "1.63.0",
101
- "@types/node": "26.6.3",
101
+ "@types/node": "26.6.4",
102
102
  "ajv": "8.20.0",
103
103
  "commander": "15.0.0",
104
104
  "esbuild": "0.28.2",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "kxm",
4
4
  "displayName": "KXM",
5
- "version": "0.7.175",
5
+ "version": "0.7.177",
6
6
  "description": "Headless multi-agent orchestration, durable workflows, and a live operator dashboard for Pi and Claude Code",
7
7
  "author": {
8
8
  "name": "KontextMind",
@@ -43129,8 +43129,12 @@ function finalizeTruncatedResult(prefix, prefixWidth, ellipsis, ellipsisWidth, m
43129
43129
  return pad2 ? result + " ".repeat(Math.max(0, maxWidth - visibleWidth2)) : result;
43130
43130
  }
43131
43131
  function graphemeWidth(segment) {
43132
- if (segment === " ") {
43133
- return 3;
43132
+ if (segment.length === 1) {
43133
+ const code = segment.charCodeAt(0);
43134
+ if (code >= 32 && code <= 126)
43135
+ return 1;
43136
+ if (code === 9)
43137
+ return 3;
43134
43138
  }
43135
43139
  if (terminalSpacingMarkRegex.test(segment)) {
43136
43140
  return [...segment].length;
@@ -43174,8 +43178,9 @@ function visibleWidth(str) {
43174
43178
  if (str.length === 0) {
43175
43179
  return 0;
43176
43180
  }
43177
- if (isPrintableAscii(str)) {
43178
- return str.length;
43181
+ const asciiWidth = asciiVisibleWidth(str);
43182
+ if (asciiWidth !== -1) {
43183
+ return asciiWidth;
43179
43184
  }
43180
43185
  const cached = widthCache.get(str);
43181
43186
  if (cached !== void 0) {
@@ -43185,19 +43190,22 @@ function visibleWidth(str) {
43185
43190
  if (str.includes(" ")) {
43186
43191
  clean = clean.replace(/\t/g, " ");
43187
43192
  }
43188
- if (clean.includes("\x1B")) {
43193
+ let escapeIndex = clean.indexOf("\x1B");
43194
+ if (escapeIndex !== -1) {
43189
43195
  let stripped = "";
43190
- let i = 0;
43191
- while (i < clean.length) {
43192
- const ansi = extractAnsiCode(clean, i);
43193
- if (ansi) {
43194
- i += ansi.length;
43195
- continue;
43196
+ let copyFrom = 0;
43197
+ while (escapeIndex !== -1) {
43198
+ const length = ansiCodeLength(clean, escapeIndex);
43199
+ if (length > 0) {
43200
+ stripped += clean.slice(copyFrom, escapeIndex);
43201
+ escapeIndex += length;
43202
+ copyFrom = escapeIndex;
43203
+ } else {
43204
+ escapeIndex++;
43196
43205
  }
43197
- stripped += clean[i];
43198
- i++;
43206
+ escapeIndex = clean.indexOf("\x1B", escapeIndex);
43199
43207
  }
43200
- clean = stripped;
43208
+ clean = stripped + clean.slice(copyFrom);
43201
43209
  }
43202
43210
  let width = 0;
43203
43211
  for (const { segment } of graphemeSegmenter.segment(clean)) {
@@ -43301,40 +43309,54 @@ function normalizeTerminalOutput(str) {
43301
43309
  return result;
43302
43310
  }
43303
43311
  function extractAnsiCode(str, pos) {
43304
- if (pos >= str.length || str[pos] !== "\x1B")
43305
- return null;
43312
+ const length = ansiCodeLength(str, pos);
43313
+ return length > 0 ? { code: str.substring(pos, pos + length), length } : null;
43314
+ }
43315
+ function asciiVisibleWidth(str) {
43316
+ let width = 0;
43317
+ let i = 0;
43318
+ while (i < str.length) {
43319
+ const code = str.charCodeAt(i);
43320
+ if (code >= 32 && code <= 126) {
43321
+ width++;
43322
+ i++;
43323
+ } else if (code === 9) {
43324
+ width += 3;
43325
+ i++;
43326
+ } else if (code === 27) {
43327
+ const length = ansiCodeLength(str, i);
43328
+ if (length === 0)
43329
+ return -1;
43330
+ i += length;
43331
+ } else {
43332
+ return -1;
43333
+ }
43334
+ }
43335
+ return width;
43336
+ }
43337
+ function ansiCodeLength(str, pos) {
43338
+ if (pos >= str.length || str.charCodeAt(pos) !== 27)
43339
+ return 0;
43306
43340
  const next = str[pos + 1];
43307
43341
  if (next === "[") {
43308
- let j2 = pos + 2;
43309
- while (j2 < str.length && !/[mGKHJ]/.test(str[j2]))
43310
- j2++;
43311
- if (j2 < str.length)
43312
- return { code: str.substring(pos, j2 + 1), length: j2 + 1 - pos };
43313
- return null;
43314
- }
43315
- if (next === "]") {
43316
- let j2 = pos + 2;
43317
- while (j2 < str.length) {
43318
- if (str[j2] === "\x07")
43319
- return { code: str.substring(pos, j2 + 1), length: j2 + 1 - pos };
43320
- if (str[j2] === "\x1B" && str[j2 + 1] === "\\")
43321
- return { code: str.substring(pos, j2 + 2), length: j2 + 2 - pos };
43322
- j2++;
43342
+ for (let j2 = pos + 2; j2 < str.length; j2++) {
43343
+ const c = str.charCodeAt(j2);
43344
+ if (c === 109 || c === 71 || c === 75 || c === 72 || c === 74)
43345
+ return j2 + 1 - pos;
43323
43346
  }
43324
- return null;
43347
+ return 0;
43325
43348
  }
43326
- if (next === "_") {
43327
- let j2 = pos + 2;
43328
- while (j2 < str.length) {
43329
- if (str[j2] === "\x07")
43330
- return { code: str.substring(pos, j2 + 1), length: j2 + 1 - pos };
43331
- if (str[j2] === "\x1B" && str[j2 + 1] === "\\")
43332
- return { code: str.substring(pos, j2 + 2), length: j2 + 2 - pos };
43333
- j2++;
43349
+ if (next === "]" || next === "_") {
43350
+ for (let j2 = pos + 2; j2 < str.length; j2++) {
43351
+ const c = str.charCodeAt(j2);
43352
+ if (c === 7)
43353
+ return j2 + 1 - pos;
43354
+ if (c === 27 && str[j2 + 1] === "\\")
43355
+ return j2 + 2 - pos;
43334
43356
  }
43335
- return null;
43357
+ return 0;
43336
43358
  }
43337
- return null;
43359
+ return 0;
43338
43360
  }
43339
43361
  function parseOsc8Hyperlink(ansiCode) {
43340
43362
  if (!ansiCode.startsWith("\x1B]8;")) {
@@ -43578,15 +43600,16 @@ var AnsiCodeTracker = class {
43578
43600
  }
43579
43601
  };
43580
43602
  function updateTrackerFromText(text, tracker) {
43581
- let i = 0;
43582
- while (i < text.length) {
43583
- const ansiResult = extractAnsiCode(text, i);
43584
- if (ansiResult) {
43585
- tracker.process(ansiResult.code);
43586
- i += ansiResult.length;
43603
+ let i = text.indexOf("\x1B");
43604
+ while (i !== -1) {
43605
+ const length = ansiCodeLength(text, i);
43606
+ if (length > 0) {
43607
+ tracker.process(text.substring(i, i + length));
43608
+ i += length;
43587
43609
  } else {
43588
43610
  i++;
43589
43611
  }
43612
+ i = text.indexOf("\x1B", i);
43590
43613
  }
43591
43614
  }
43592
43615
  function getActiveBackgroundAnsi(text) {
@@ -43594,6 +43617,10 @@ function getActiveBackgroundAnsi(text) {
43594
43617
  updateTrackerFromText(text, tracker);
43595
43618
  return tracker.getActiveBackgroundCode();
43596
43619
  }
43620
+ function* graphemeSegments(text) {
43621
+ for (const { segment } of graphemeSegmenter.segment(text))
43622
+ yield segment;
43623
+ }
43597
43624
  function splitIntoTokensWithAnsi(text) {
43598
43625
  const tokens = [];
43599
43626
  let current = "";
@@ -43615,13 +43642,17 @@ function splitIntoTokensWithAnsi(text) {
43615
43642
  i += ansiResult.length;
43616
43643
  continue;
43617
43644
  }
43618
- let end = i;
43619
- while (end < text.length && !extractAnsiCode(text, end)) {
43620
- end++;
43645
+ let end = text.indexOf("\x1B", i + 1);
43646
+ while (end !== -1 && ansiCodeLength(text, end) === 0) {
43647
+ end = text.indexOf("\x1B", end + 1);
43621
43648
  }
43622
- for (const { segment } of graphemeSegmenter.segment(text.slice(i, end))) {
43649
+ if (end === -1)
43650
+ end = text.length;
43651
+ const chunk = text.slice(i, end);
43652
+ const ascii = isPrintableAscii(chunk);
43653
+ for (const segment of ascii ? chunk : graphemeSegments(chunk)) {
43623
43654
  const segmentIsSpace = segment === " ";
43624
- if (!segmentIsSpace && cjkBreakRegex.test(segment)) {
43655
+ if (!ascii && !segmentIsSpace && cjkBreakRegex.test(segment)) {
43625
43656
  flushCurrent();
43626
43657
  const token = pendingAnsi + segment;
43627
43658
  pendingAnsi = "";
@@ -43655,6 +43686,10 @@ function splitIntoTokensWithAnsi(text) {
43655
43686
  }
43656
43687
  return tokens;
43657
43688
  }
43689
+ function flattenLines(lines) {
43690
+ for (const line of lines)
43691
+ Number(line);
43692
+ }
43658
43693
  function wrapTextWithAnsi(text, width) {
43659
43694
  if (!text) {
43660
43695
  return [""];
@@ -43927,9 +43962,10 @@ function sliceWithWidth(line, startCol, length, strict = false) {
43927
43962
  while (i < line.length) {
43928
43963
  const ansi = extractAnsiCode(line, i);
43929
43964
  if (ansi) {
43930
- if (currentCol >= startCol && currentCol < endCol)
43931
- result += ansi.code;
43932
- else if (currentCol < startCol)
43965
+ if (currentCol >= startCol && currentCol < endCol) {
43966
+ result += pendingAnsi + ansi.code;
43967
+ pendingAnsi = "";
43968
+ } else if (currentCol < startCol)
43933
43969
  pendingAnsi += ansi.code;
43934
43970
  i += ansi.length;
43935
43971
  continue;
@@ -44016,8 +44052,19 @@ function extractSegments(line, beforeEnd, afterStart, afterLen, strictAfter = fa
44016
44052
  // node_modules/@earendil-works/pi-tui/dist/autocomplete.js
44017
44053
  var tokenStartRegex = new RegExp(`${autocompleteBoundaryRegex.source}$`, "u");
44018
44054
 
44055
+ // node_modules/@earendil-works/pi-tui/dist/oklab.js
44056
+ var K1 = 0.206;
44057
+ var K2 = 0.03;
44058
+ var K3 = (1 + K1) / (1 + K2);
44059
+
44060
+ // node_modules/@earendil-works/pi-tui/dist/colors.js
44061
+ var NUMBER_PATTERN = String.raw`[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?`;
44062
+ var OKLCH_PATTERN = new RegExp(`^oklch\\(\\s*(${NUMBER_PATTERN})(%)?\\s+(${NUMBER_PATTERN})\\s+(${NUMBER_PATTERN})(?:deg)?\\s*\\)$`, "i");
44063
+ var OKHSL_PATTERN = new RegExp(`^okhsl\\(\\s*(${NUMBER_PATTERN})(?:deg)?\\s+(${NUMBER_PATTERN})(%)?\\s+(${NUMBER_PATTERN})(%)?\\s*\\)$`, "i");
44064
+ var GRAY_VALUES = Array.from({ length: 24 }, (_2, index) => 8 + index * 10);
44065
+
44019
44066
  // node_modules/@earendil-works/pi-tui/dist/tui.js
44020
- import { performance } from "node:perf_hooks";
44067
+ import { performance as performance2 } from "node:perf_hooks";
44021
44068
 
44022
44069
  // node_modules/@earendil-works/pi-tui/dist/keys.js
44023
44070
  var _kittyProtocolActive = false;
@@ -44729,17 +44776,18 @@ function parseOscHexChannel(channel) {
44729
44776
  }
44730
44777
  return Math.round(parseInt(channel, 16) / max * 255);
44731
44778
  }
44732
- var OSC11_BACKGROUND_COLOR_RESPONSE_PATTERN = /^\x1b\]11;([^\x07\x1b]*)(?:\x07|\x1b\\)$/i;
44779
+ var OSC_COLOR_RESPONSE_PATTERN = /^\x1b\](?:(1[01])|4;(\d{1,3}));([^\x07\x1b]*)(?:\x07|\x1b\\)$/i;
44733
44780
  var COLOR_SCHEME_REPORT_PATTERN = /^(?:\x1b\[\?997;(1|2)n)+$/;
44734
- function isOsc11BackgroundColorResponse(data) {
44735
- return OSC11_BACKGROUND_COLOR_RESPONSE_PATTERN.test(data);
44736
- }
44737
- function parseOsc11BackgroundColor(data) {
44738
- const match = data.match(OSC11_BACKGROUND_COLOR_RESPONSE_PATTERN);
44781
+ function parseOscColorResponse(data) {
44782
+ const match = data.match(OSC_COLOR_RESPONSE_PATTERN);
44739
44783
  if (!match) {
44740
44784
  return void 0;
44741
44785
  }
44742
- const value = match[1].trim();
44786
+ const target = match[1] === "10" ? "foreground" : match[1] === "11" ? "background" : Number.parseInt(match[2], 10);
44787
+ return { target, rgb: parseOscColorValue(match[3]) };
44788
+ }
44789
+ function parseOscColorValue(rawValue) {
44790
+ const value = rawValue.trim();
44743
44791
  if (value.startsWith("#")) {
44744
44792
  const hex = value.slice(1);
44745
44793
  if (/^[0-9a-f]{6}$/i.test(hex)) {
@@ -44796,7 +44844,7 @@ function detectCapabilitiesFromEnvironment(tmuxForwardsHyperlink) {
44796
44844
  const terminalEmulator = process.env.TERMINAL_EMULATOR?.toLowerCase() || "";
44797
44845
  const term = process.env.TERM?.toLowerCase() || "";
44798
44846
  const colorTerm = process.env.COLORTERM?.toLowerCase() || "";
44799
- const hasTrueColorHint = colorTerm === "truecolor" || colorTerm === "24bit";
44847
+ const hasTrueColorHint = colorTerm === "truecolor" || colorTerm === "24bit" || term.endsWith("-direct");
44800
44848
  const isWindowsConsole = process.platform === "win32";
44801
44849
  if (process.env.TMUX || term.startsWith("tmux")) {
44802
44850
  return { images: null, trueColor: hasTrueColorHint, hyperlinks: tmuxForwardsHyperlink() };
@@ -44880,12 +44928,23 @@ function deleteAllKittyPlacements() {
44880
44928
  return "\x1B_Ga=d,d=a,q=2\x1B\\";
44881
44929
  }
44882
44930
  var kittyImageMetadata = /* @__PURE__ */ new Map();
44931
+ function getRegisteredKittyImageMetadataFromControls(controls) {
44932
+ const imageId = /(?:^|,)i=(\d+)(?:,|$)/.exec(controls)?.[1];
44933
+ return imageId === void 0 ? void 0 : kittyImageMetadata.get(Number.parseInt(imageId, 10));
44934
+ }
44883
44935
  function getRegisteredKittyImageMetadata(line) {
44884
44936
  const controls = /\x1b_G([^;]*);/.exec(line)?.[1];
44885
- if (!controls)
44937
+ return controls === void 0 ? void 0 : getRegisteredKittyImageMetadataFromControls(controls);
44938
+ }
44939
+ function getExplicitKittyImageRows(controls) {
44940
+ const value = /(?:^|,)r=(\d+)(?:,|$)/.exec(controls)?.[1];
44941
+ if (value === void 0)
44886
44942
  return void 0;
44887
- const imageId = /(?:^|,)i=(\d+)(?:,|$)/.exec(controls)?.[1];
44888
- return imageId === void 0 ? void 0 : kittyImageMetadata.get(Number.parseInt(imageId, 10));
44943
+ const rows = Number.parseInt(value, 10);
44944
+ return rows > 0 ? rows : void 0;
44945
+ }
44946
+ function getKittyImageRowsFromControls(controls, fallbackRows) {
44947
+ return getExplicitKittyImageRows(controls) ?? fallbackRows;
44889
44948
  }
44890
44949
  function getKittyImageMetadata(line) {
44891
44950
  const metadata = getRegisteredKittyImageMetadata(line);
@@ -44918,10 +44977,21 @@ var KITTY_PLACEMENT_CONTROL_KEYS = /* @__PURE__ */ new Set([
44918
44977
  "H",
44919
44978
  "V"
44920
44979
  ]);
44980
+ function getKittyImagePlacementRows(line) {
44981
+ const controls = /\x1b_G([^;]*);/.exec(line)?.[1];
44982
+ if (controls === void 0)
44983
+ return void 0;
44984
+ const explicitRows = getExplicitKittyImageRows(controls);
44985
+ if (explicitRows !== void 0)
44986
+ return explicitRows;
44987
+ return getRegisteredKittyImageMetadataFromControls(controls)?.rows;
44988
+ }
44921
44989
  function getKittyImagePlacement(line) {
44922
44990
  const match = /\x1b_G([^;]*);/.exec(line);
44923
- const metadata = getRegisteredKittyImageMetadata(line);
44924
- if (!match || !metadata)
44991
+ if (!match)
44992
+ return void 0;
44993
+ const metadata = getRegisteredKittyImageMetadataFromControls(match[1]);
44994
+ if (!metadata)
44925
44995
  return void 0;
44926
44996
  let commandStart = match.index;
44927
44997
  let commandControls = match[1];
@@ -44948,6 +45018,7 @@ function getKittyImagePlacement(line) {
44948
45018
  transmissionGeneration: metadata.transmissionGeneration,
44949
45019
  transmissionBytes: transmissionEnd - match.index,
44950
45020
  estimatedDecodedBytes: metadata.widthPx * metadata.heightPx * 4,
45021
+ rows: getKittyImageRowsFromControls(match[1], metadata.rows),
44951
45022
  sequence,
44952
45023
  replacementLine: `${line.slice(0, match.index)}${sequence}${line.slice(transmissionEnd)}`
44953
45024
  };
@@ -44973,8 +45044,10 @@ function dispatchMouseEvent(component, event) {
44973
45044
  const result = component.handleMouse?.(event);
44974
45045
  if (!result)
44975
45046
  return void 0;
44976
- if ("target" in result)
44977
- return result;
45047
+ if ("target" in result) {
45048
+ const forwarded = result;
45049
+ return forwarded.focus && component.handleInput ? { ...forwarded, focusTarget: component } : forwarded;
45050
+ }
44978
45051
  if (!result.handled && !result.capture && !result.focus)
44979
45052
  return void 0;
44980
45053
  return {
@@ -44999,6 +45072,10 @@ function retargetMouseEvent(event, target) {
44999
45072
  height: target.height
45000
45073
  };
45001
45074
  }
45075
+ var TERMINAL_PALETTE_SIZE = 16;
45076
+ var TERMINAL_COLOR_REPLY_COUNT = 2 + TERMINAL_PALETTE_SIZE;
45077
+ var TERMINAL_COLOR_QUERY = `\x1B]10;?\x07\x1B]11;?\x07${Array.from({ length: TERMINAL_PALETTE_SIZE }, (_2, index) => `\x1B]4;${index};?\x07`).join("")}\x1B[c`;
45078
+ var DEVICE_ATTRIBUTES_RESPONSE_PATTERN = /^\x1b\[\?[\d;]*c$/;
45002
45079
  function isFocusable(component) {
45003
45080
  return component !== null && "focused" in component;
45004
45081
  }
@@ -45100,8 +45177,11 @@ var TuiBase = class _TuiBase extends Container {
45100
45177
  clearOnShrink = false;
45101
45178
  fullRedrawCount = 0;
45102
45179
  stopped = false;
45103
- pendingOsc11BackgroundReplies = 0;
45104
- pendingOsc11BackgroundQueries = [];
45180
+ /**
45181
+ * Color queries waiting for their DA1 reply, oldest first. Terminals answer in order, so color
45182
+ * replies belong to the oldest one. Queries stay here after a timeout to collect late replies.
45183
+ */
45184
+ pendingTerminalColorQueries = [];
45105
45185
  terminalColorSchemeListeners = /* @__PURE__ */ new Set();
45106
45186
  terminalColorSchemeNotificationsEnabled = false;
45107
45187
  /** Directory for debug/crash logs. When undefined, debug logging is disabled and crash dumps fall back to the OS temp directory. */
@@ -45143,7 +45223,7 @@ var TuiBase = class _TuiBase extends Container {
45143
45223
  return;
45144
45224
  this.showHardwareCursor = enabled;
45145
45225
  if (!enabled) {
45146
- this.terminal.hideCursor();
45226
+ this.hideTerminalCursor();
45147
45227
  }
45148
45228
  this.requestRender();
45149
45229
  }
@@ -45279,7 +45359,7 @@ var TuiBase = class _TuiBase extends Container {
45279
45359
  if (!options?.nonCapturing && this.isOverlayVisible(entry)) {
45280
45360
  this.setFocus(component);
45281
45361
  }
45282
- this.terminal.hideCursor();
45362
+ this.hideTerminalCursor();
45283
45363
  this.requestRender();
45284
45364
  return {
45285
45365
  hide: () => {
@@ -45293,7 +45373,7 @@ var TuiBase = class _TuiBase extends Container {
45293
45373
  this.setFocus(topVisible?.component ?? entry.preFocus);
45294
45374
  }
45295
45375
  if (this.overlayStack.length === 0)
45296
- this.terminal.hideCursor();
45376
+ this.hideTerminalCursor();
45297
45377
  this.requestRender();
45298
45378
  }
45299
45379
  },
@@ -45372,9 +45452,14 @@ var TuiBase = class _TuiBase extends Container {
45372
45452
  this.setFocus(topVisible?.component ?? overlay.preFocus);
45373
45453
  }
45374
45454
  if (this.overlayStack.length === 0)
45375
- this.terminal.hideCursor();
45455
+ this.hideTerminalCursor();
45376
45456
  this.requestRender();
45377
45457
  }
45458
+ /** Hide the cursor while running. After stop(), the shell owns the cursor and it must stay visible. */
45459
+ hideTerminalCursor() {
45460
+ if (!this.stopped)
45461
+ this.terminal.hideCursor();
45462
+ }
45378
45463
  /** Check if there are any visible overlays */
45379
45464
  hasOverlay() {
45380
45465
  return this.overlayStack.some((o) => this.isOverlayVisible(o));
@@ -45499,7 +45584,7 @@ var TuiBase = class _TuiBase extends Container {
45499
45584
  this.resetRenderState();
45500
45585
  this.renderRequested = false;
45501
45586
  this.cancelRenderTimer();
45502
- this.lastRenderAt = performance.now();
45587
+ this.lastRenderAt = performance2.now();
45503
45588
  this.doRender();
45504
45589
  }
45505
45590
  requestRender(force = false) {
@@ -45525,7 +45610,7 @@ var TuiBase = class _TuiBase extends Container {
45525
45610
  return;
45526
45611
  this.cancelRenderTimer();
45527
45612
  this.renderRequested = false;
45528
- this.lastRenderAt = performance.now();
45613
+ this.lastRenderAt = performance2.now();
45529
45614
  this.doRender();
45530
45615
  });
45531
45616
  }
@@ -45539,7 +45624,7 @@ var TuiBase = class _TuiBase extends Container {
45539
45624
  if (this.stopped || this.renderTimer || !this.renderRequested) {
45540
45625
  return;
45541
45626
  }
45542
- const elapsed = performance.now() - this.lastRenderAt;
45627
+ const elapsed = performance2.now() - this.lastRenderAt;
45543
45628
  const delay = Math.max(0, _TuiBase.MIN_RENDER_INTERVAL_MS - elapsed);
45544
45629
  this.renderTimer = setTimeout(() => {
45545
45630
  this.renderTimer = void 0;
@@ -45547,7 +45632,7 @@ var TuiBase = class _TuiBase extends Container {
45547
45632
  return;
45548
45633
  }
45549
45634
  this.renderRequested = false;
45550
- this.lastRenderAt = performance.now();
45635
+ this.lastRenderAt = performance2.now();
45551
45636
  this.doRender();
45552
45637
  if (this.renderRequested) {
45553
45638
  this.scheduleRender();
@@ -45555,7 +45640,7 @@ var TuiBase = class _TuiBase extends Container {
45555
45640
  }, delay);
45556
45641
  }
45557
45642
  handleTerminalInput(data) {
45558
- if (this.consumeOsc11BackgroundResponse(data)) {
45643
+ if (this.consumeTerminalColorResponse(data)) {
45559
45644
  return;
45560
45645
  }
45561
45646
  if (this.consumeTerminalColorSchemeReport(data)) {
@@ -45615,27 +45700,48 @@ var TuiBase = class _TuiBase extends Container {
45615
45700
  this.requestImmediateRender();
45616
45701
  }
45617
45702
  }
45618
- consumeOsc11BackgroundResponse(data) {
45619
- if (this.pendingOsc11BackgroundReplies <= 0) {
45703
+ consumeTerminalColorResponse(data) {
45704
+ const query = this.pendingTerminalColorQueries[0];
45705
+ if (!query) {
45620
45706
  return false;
45621
45707
  }
45622
- if (!isOsc11BackgroundColorResponse(data)) {
45708
+ if (DEVICE_ATTRIBUTES_RESPONSE_PATTERN.test(data)) {
45709
+ this.pendingTerminalColorQueries.shift();
45710
+ this.completeTerminalColorQuery(query);
45711
+ return true;
45712
+ }
45713
+ const response = parseOscColorResponse(data);
45714
+ if (!response) {
45623
45715
  return false;
45624
45716
  }
45625
- const rgb = parseOsc11BackgroundColor(data);
45626
- this.pendingOsc11BackgroundReplies -= 1;
45627
- const query = this.pendingOsc11BackgroundQueries.shift();
45628
- if (query && !query.settled) {
45629
- query.settled = true;
45630
- if (query.timer) {
45631
- clearTimeout(query.timer);
45632
- query.timer = void 0;
45633
- }
45634
- query.resolve?.(rgb);
45635
- query.resolve = void 0;
45717
+ const { target, rgb } = response;
45718
+ const key = String(target);
45719
+ if (!query.deliver || query.replied.has(key)) {
45720
+ return true;
45721
+ }
45722
+ query.replied.add(key);
45723
+ if (target === "foreground") {
45724
+ query.foreground = rgb;
45725
+ } else if (target === "background") {
45726
+ query.background = rgb;
45727
+ } else if (target < TERMINAL_PALETTE_SIZE) {
45728
+ query.palette[target] = rgb;
45729
+ }
45730
+ if (query.replied.size === TERMINAL_COLOR_REPLY_COUNT) {
45731
+ this.completeTerminalColorQuery(query);
45636
45732
  }
45637
45733
  return true;
45638
45734
  }
45735
+ terminalColorQueryResult(query) {
45736
+ const palette = query.palette.every((color) => color !== void 0) ? query.palette : void 0;
45737
+ return { foreground: query.foreground, background: query.background, palette };
45738
+ }
45739
+ completeTerminalColorQuery(query) {
45740
+ const deliver = query.deliver;
45741
+ query.deliver = void 0;
45742
+ clearTimeout(query.timer);
45743
+ deliver?.(this.terminalColorQueryResult(query));
45744
+ }
45639
45745
  consumeTerminalColorSchemeReport(data) {
45640
45746
  const scheme = parseTerminalColorSchemeReport(data);
45641
45747
  if (!scheme) {
@@ -45844,56 +45950,27 @@ var TuiBase = class _TuiBase extends Container {
45844
45950
  return null;
45845
45951
  }
45846
45952
  /**
45847
- * Query the terminal's default background color with OSC 11 (`ESC ] 11 ; ? BEL`).
45848
- * @param timeoutMs Query timeout in milliseconds.
45849
- * @returns Promise containing the parsed RGB color, or undefined if it times out or fails to parse.
45953
+ * Query the terminal's theme colors: the default foreground (OSC 10), the default background
45954
+ * (OSC 11), and ANSI colors 0-15 (OSC 4), followed by a DA1 request that marks the end of the
45955
+ * replies. Resolves when the DA1 reply or all color replies arrive, or when the timeout expires.
45956
+ * Colors the terminal did not report are undefined; the palette is only set when all 16 arrived.
45957
+ * @param timeoutMs Query timeout in milliseconds, for terminals that do not answer DA1 either.
45958
+ * @param onLateReply Receives the replies if the query completes after the timeout, e.g. over slow links.
45850
45959
  */
45851
- queryTerminalBackgroundColor({ timeoutMs }) {
45960
+ queryTerminalColors({ timeoutMs, onLateReply }) {
45852
45961
  return new Promise((resolve35) => {
45853
45962
  const query = {
45854
- settled: false,
45855
- resolve: resolve35,
45963
+ palette: Array.from({ length: TERMINAL_PALETTE_SIZE }, () => void 0),
45964
+ replied: /* @__PURE__ */ new Set(),
45965
+ deliver: resolve35,
45856
45966
  timer: void 0
45857
45967
  };
45858
45968
  query.timer = setTimeout(() => {
45859
- if (query.settled) {
45860
- return;
45861
- }
45862
- query.settled = true;
45863
- query.timer = void 0;
45864
- query.resolve?.(void 0);
45865
- query.resolve = void 0;
45969
+ query.deliver = onLateReply;
45970
+ resolve35(this.terminalColorQueryResult(query));
45866
45971
  }, timeoutMs);
45867
- this.pendingOsc11BackgroundQueries.push(query);
45868
- this.pendingOsc11BackgroundReplies += 1;
45869
- this.terminal.write("\x1B]11;?\x07");
45870
- });
45871
- }
45872
- /**
45873
- * Query the terminal's color-scheme preference with DSR (`CSI ? 996 n`).
45874
- * Terminals that support the color palette notification protocol reply with
45875
- * `CSI ? 997 ; 1 n` for dark or `CSI ? 997 ; 2 n` for light.
45876
- */
45877
- queryTerminalColorScheme({ timeoutMs }) {
45878
- return new Promise((resolve35) => {
45879
- let settled = false;
45880
- let timer;
45881
- let unsubscribe = () => {
45882
- };
45883
- const settle = (scheme) => {
45884
- if (settled)
45885
- return;
45886
- settled = true;
45887
- if (timer) {
45888
- clearTimeout(timer);
45889
- timer = void 0;
45890
- }
45891
- unsubscribe();
45892
- resolve35(scheme);
45893
- };
45894
- unsubscribe = this.onTerminalColorSchemeChange(settle);
45895
- timer = setTimeout(() => settle(void 0), timeoutMs);
45896
- this.terminal.write("\x1B[?996n");
45972
+ this.pendingTerminalColorQueries.push(query);
45973
+ this.terminal.write(TERMINAL_COLOR_QUERY);
45897
45974
  });
45898
45975
  }
45899
45976
  };
@@ -45977,7 +46054,7 @@ var Box = class {
45977
46054
  const lines = child.render(contentWidth);
45978
46055
  mouseChildren.push({ component: child, height: lines.length });
45979
46056
  for (const line of lines) {
45980
- childLines.push(leftPad + line);
46057
+ childLines.push(line);
45981
46058
  }
45982
46059
  }
45983
46060
  this.mouseLayout = { width: contentWidth, children: mouseChildren };
@@ -45993,11 +46070,12 @@ var Box = class {
45993
46070
  result.push(this.applyBg("", width));
45994
46071
  }
45995
46072
  for (const line of childLines) {
45996
- result.push(this.applyBg(line, width));
46073
+ result.push(this.applyBg(leftPad + line, width));
45997
46074
  }
45998
46075
  for (let i = 0; i < this.paddingY; i++) {
45999
46076
  result.push(this.applyBg("", width));
46000
46077
  }
46078
+ flattenLines(result);
46001
46079
  this.cache = { childLines, width, bgSample, lines: result };
46002
46080
  return result;
46003
46081
  }
@@ -46005,10 +46083,7 @@ var Box = class {
46005
46083
  const visLen = visibleWidth(line);
46006
46084
  const padNeeded = Math.max(0, width - visLen);
46007
46085
  const padded = line + " ".repeat(padNeeded);
46008
- if (this.bgFn) {
46009
- return applyBackgroundToLine(padded, width, this.bgFn);
46010
- }
46011
- return padded;
46086
+ return this.bgFn ? this.bgFn(padded) : padded;
46012
46087
  }
46013
46088
  };
46014
46089
 
@@ -46312,6 +46387,7 @@ var Text = class {
46312
46387
  emptyLines.push(line);
46313
46388
  }
46314
46389
  const result = [...emptyLines, ...contentLines, ...emptyLines];
46390
+ flattenLines(result);
46315
46391
  this.cachedText = this.text;
46316
46392
  this.cachedWidth = width;
46317
46393
  this.cachedLines = result;
@@ -46443,6 +46519,7 @@ function findWordForward(text, cursor2, options) {
46443
46519
  var graphemeSegmenter2 = getGraphemeSegmenter();
46444
46520
  var wordSegmenter3 = getWordSegmenter();
46445
46521
  var unquotedAutocompleteSuffixRegex = new RegExp(`(?:(?!${autocompleteSeparatorRegex.source}).)*`, "u");
46522
+ var autocompleteTokenStartSource = `${autocompleteBoundaryRegex.source}[([{<\`]*`;
46446
46523
 
46447
46524
  // node_modules/@earendil-works/pi-tui/dist/layout-node.js
46448
46525
  var LAYOUT_NODE = /* @__PURE__ */ Symbol.for("@earendil-works/pi-tui/layout-node");
@@ -47733,6 +47810,8 @@ var ProcessTerminal = class {
47733
47810
  _kittyProtocolActive = false;
47734
47811
  _modifyOtherKeysActive = false;
47735
47812
  keyboardProtocolPushed = false;
47813
+ /** DA1 replies owed to keyboard protocol queries. Later DA1 replies answer other queries and are forwarded. */
47814
+ pendingKeyboardProtocolDeviceAttributes = 0;
47736
47815
  keyboardProtocolNegotiationBuffer = "";
47737
47816
  keyboardProtocolBufferFlushTimer;
47738
47817
  stdinBuffer;
@@ -47784,15 +47863,15 @@ var ProcessTerminal = class {
47784
47863
  setupStdinBuffer() {
47785
47864
  this.stdinBuffer = new StdinBuffer({ escapeTimeout: resolveEscapeTimeoutMs() });
47786
47865
  this.stdinBuffer.on("data", (sequence) => {
47787
- const negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence);
47788
- if (negotiationSequence === "pending") {
47866
+ const negotiation = this.readKeyboardProtocolNegotiationSequence(sequence);
47867
+ if (negotiation === "pending") {
47789
47868
  this.scheduleKeyboardProtocolNegotiationBufferFlush();
47790
47869
  return;
47791
47870
  }
47792
- if (this.handleKeyboardProtocolNegotiationSequence(negotiationSequence)) {
47871
+ if (negotiation && this.handleKeyboardProtocolNegotiationSequence(negotiation.parsed)) {
47793
47872
  return;
47794
47873
  }
47795
- this.forwardInputSequence(sequence);
47874
+ this.forwardInputSequence(negotiation?.sequence ?? sequence);
47796
47875
  });
47797
47876
  this.stdinBuffer.on("paste", (content) => {
47798
47877
  if (this.inputHandler) {
@@ -47820,13 +47899,17 @@ var ProcessTerminal = class {
47820
47899
  this.setupStdinBuffer();
47821
47900
  process.stdin.on("data", this.stdinDataHandler);
47822
47901
  this.keyboardProtocolPushed = true;
47902
+ this.pendingKeyboardProtocolDeviceAttributes += 1;
47823
47903
  this.clearKeyboardProtocolNegotiationBuffer();
47824
47904
  process.stdout.write(KITTY_KEYBOARD_PROTOCOL_QUERY);
47825
47905
  }
47826
47906
  handleKeyboardProtocolNegotiationSequence(negotiationSequence) {
47827
- if (!negotiationSequence)
47828
- return false;
47829
47907
  this.clearKeyboardProtocolNegotiationBuffer();
47908
+ if (negotiationSequence.type === "device-attributes") {
47909
+ if (this.pendingKeyboardProtocolDeviceAttributes === 0)
47910
+ return false;
47911
+ this.pendingKeyboardProtocolDeviceAttributes -= 1;
47912
+ }
47830
47913
  if (negotiationSequence.type === "kitty-flags") {
47831
47914
  if (negotiationSequence.flags !== 0) {
47832
47915
  this.disableModifyOtherKeys();
@@ -47844,13 +47927,14 @@ var ProcessTerminal = class {
47844
47927
  }
47845
47928
  return true;
47846
47929
  }
47930
+ /** Returns the parsed negotiation reply with its full (possibly reassembled) sequence. */
47847
47931
  readKeyboardProtocolNegotiationSequence(sequence) {
47848
47932
  if (this.keyboardProtocolNegotiationBuffer) {
47849
47933
  const bufferedSequence = this.keyboardProtocolNegotiationBuffer + sequence;
47850
47934
  const negotiationSequence2 = parseKeyboardProtocolNegotiationSequence(bufferedSequence);
47851
47935
  if (negotiationSequence2) {
47852
47936
  this.clearKeyboardProtocolNegotiationBuffer();
47853
- return negotiationSequence2;
47937
+ return { parsed: negotiationSequence2, sequence: bufferedSequence };
47854
47938
  }
47855
47939
  if (isKeyboardProtocolNegotiationSequencePrefix(bufferedSequence)) {
47856
47940
  this.setKeyboardProtocolNegotiationBuffer(bufferedSequence);
@@ -47860,7 +47944,7 @@ var ProcessTerminal = class {
47860
47944
  }
47861
47945
  const negotiationSequence = parseKeyboardProtocolNegotiationSequence(sequence);
47862
47946
  if (negotiationSequence)
47863
- return negotiationSequence;
47947
+ return { parsed: negotiationSequence, sequence };
47864
47948
  if (isKeyboardProtocolNegotiationSequencePrefix(sequence)) {
47865
47949
  this.setKeyboardProtocolNegotiationBuffer(sequence);
47866
47950
  return "pending";
@@ -48677,6 +48761,61 @@ function getScrollViewsAt(frame, x2, y2) {
48677
48761
  return result.map((entry) => entry.scrollView);
48678
48762
  }
48679
48763
 
48764
+ // node_modules/@earendil-works/pi-tui/dist/wheel-scroll.js
48765
+ var BURST_GAP_MS = 5;
48766
+ var GESTURE_GAP_MS = 200;
48767
+ var REFERENCE_GAP_MS = 100;
48768
+ var MAX_AUTO_LINES = 6;
48769
+ function terminalAcceleratesWheel() {
48770
+ const env = process.env;
48771
+ return process.platform === "darwin" && env.SSH_CONNECTION === void 0 && env.SSH_CLIENT === void 0 && env.SSH_TTY === void 0;
48772
+ }
48773
+ var WheelScrollAccelerator = class {
48774
+ lines;
48775
+ accelerate;
48776
+ lastTime = Number.NEGATIVE_INFINITY;
48777
+ lastDirection = 0;
48778
+ averageGap;
48779
+ carry = 0;
48780
+ constructor(lines = "auto", accelerate = !terminalAcceleratesWheel()) {
48781
+ this.lines = lines;
48782
+ this.accelerate = accelerate;
48783
+ }
48784
+ setLines(lines) {
48785
+ this.lines = lines;
48786
+ this.reset();
48787
+ }
48788
+ /** Return the positive line count for a wheel event in `direction` at time `now` (milliseconds). */
48789
+ next(direction, now) {
48790
+ if (this.lines !== "auto")
48791
+ return Number.isFinite(this.lines) ? Math.max(1, Math.floor(this.lines)) : 1;
48792
+ if (!this.accelerate)
48793
+ return 1;
48794
+ const gap = now - this.lastTime;
48795
+ const sameGesture = direction === this.lastDirection && gap <= GESTURE_GAP_MS;
48796
+ this.lastTime = now;
48797
+ this.lastDirection = direction;
48798
+ if (!sameGesture) {
48799
+ this.averageGap = void 0;
48800
+ this.carry = 0;
48801
+ return 1;
48802
+ }
48803
+ if (gap < BURST_GAP_MS)
48804
+ return 1;
48805
+ this.averageGap = this.averageGap === void 0 ? gap : (this.averageGap + gap) / 2;
48806
+ const lines = Math.min(MAX_AUTO_LINES, Math.max(1, REFERENCE_GAP_MS / this.averageGap)) + this.carry;
48807
+ const whole = Math.floor(lines);
48808
+ this.carry = lines - whole;
48809
+ return whole;
48810
+ }
48811
+ reset() {
48812
+ this.lastTime = Number.NEGATIVE_INFINITY;
48813
+ this.lastDirection = 0;
48814
+ this.averageGap = void 0;
48815
+ this.carry = 0;
48816
+ }
48817
+ };
48818
+
48680
48819
  // node_modules/@earendil-works/pi-tui/dist/tui-alt-screen.js
48681
48820
  var ENTER_ALT_SCREEN = "\x1B[?1049h";
48682
48821
  var EXIT_ALT_SCREEN = "\x1B[?1049l";
@@ -48736,7 +48875,7 @@ var TuiAltScreen = class extends TuiBase {
48736
48875
  mousePressPoint;
48737
48876
  mousePressMoved = false;
48738
48877
  lastComponentClick;
48739
- wheelScrollLines;
48878
+ wheelScroll;
48740
48879
  mouseEnabled;
48741
48880
  searchMatchStyle;
48742
48881
  searchCurrentMatchStyle;
@@ -48758,7 +48897,7 @@ var TuiAltScreen = class extends TuiBase {
48758
48897
  };
48759
48898
  this.implicitScrollView = new ScrollView(this.implicitDocument, { follow: "end", primary: true });
48760
48899
  this.flashes = new AltScreenFlashContainer(() => this.requestRender());
48761
- this.wheelScrollLines = Math.max(1, Math.floor(options.wheelScrollLines ?? 1));
48900
+ this.wheelScroll = new WheelScrollAccelerator(options.wheelScrollLines ?? 1);
48762
48901
  this.mouseEnabled = options.mouse ?? true;
48763
48902
  this.searchMatchStyle = options.searchMatchStyle ?? ((text) => `\x1B[4m${text}\x1B[24m`);
48764
48903
  this.searchCurrentMatchStyle = options.searchCurrentMatchStyle ?? ((text) => `\x1B[1;7m${text}\x1B[22;27m`);
@@ -48776,6 +48915,9 @@ var TuiAltScreen = class extends TuiBase {
48776
48915
  get isFollowingOutput() {
48777
48916
  return this.getPrimaryScrollView().isFollowingEnd;
48778
48917
  }
48918
+ setWheelScrollLines(lines) {
48919
+ this.wheelScroll.setLines(lines);
48920
+ }
48779
48921
  getCopyOnSelect() {
48780
48922
  return this.copyOnSelect;
48781
48923
  }
@@ -48793,6 +48935,10 @@ var TuiAltScreen = class extends TuiBase {
48793
48935
  return false;
48794
48936
  return this.copyTextToClipboard(text);
48795
48937
  }
48938
+ /** The lines of the last rendered frame, one per terminal row, as written to the terminal. */
48939
+ getScreenLines() {
48940
+ return [...this.previousScreen];
48941
+ }
48796
48942
  setLayoutRoot(component) {
48797
48943
  if (this.layoutRoot === component)
48798
48944
  return;
@@ -49135,9 +49281,9 @@ var TuiAltScreen = class extends TuiBase {
49135
49281
  return { consume: true };
49136
49282
  const wheelEvent = this.parseWheelEvent(data);
49137
49283
  if (wheelEvent) {
49138
- const event = this.createMouseEvent("wheel", wheelEvent.button, wheelEvent.x, wheelEvent.y, {
49139
- wheelDelta: wheelEvent.direction * this.getWheelScrollLines(wheelEvent.button)
49140
- });
49284
+ const lines = this.wheelScroll.next(wheelEvent.direction, performance.now());
49285
+ const wheelDelta = wheelEvent.direction * ((wheelEvent.button & 8) !== 0 ? lines * ALT_WHEEL_SCROLL_MULTIPLIER : lines);
49286
+ const event = this.createMouseEvent("wheel", wheelEvent.button, wheelEvent.x, wheelEvent.y, { wheelDelta });
49141
49287
  const overlay = this.dispatchMouseToOverlay(event);
49142
49288
  const result = overlay.result ?? (overlay.hit ? void 0 : this.dispatchMouseToLayout(event));
49143
49289
  if (result) {
@@ -49147,7 +49293,7 @@ var TuiAltScreen = class extends TuiBase {
49147
49293
  }
49148
49294
  if (this.shouldDeferViewportInputToOverlay())
49149
49295
  return void 0;
49150
- this.routeWheel(wheelEvent);
49296
+ this.routeWheel(wheelEvent, wheelDelta);
49151
49297
  return { consume: true };
49152
49298
  }
49153
49299
  const mouseEvent = this.parseSgrMouseEvent(data);
@@ -49410,11 +49556,8 @@ var TuiAltScreen = class extends TuiBase {
49410
49556
  }
49411
49557
  return void 0;
49412
49558
  }
49413
- getWheelScrollLines(button) {
49414
- return (button & 8) !== 0 ? this.wheelScrollLines * ALT_WHEEL_SCROLL_MULTIPLIER : this.wheelScrollLines;
49415
- }
49416
- routeWheel(event) {
49417
- let remaining = event.direction * this.getWheelScrollLines(event.button);
49559
+ routeWheel(event, delta) {
49560
+ let remaining = delta;
49418
49561
  const seen = /* @__PURE__ */ new Set();
49419
49562
  for (const scrollView of this.currentLayout ? getScrollViewsAt(this.currentLayout, event.x, event.y) : []) {
49420
49563
  seen.add(scrollView);
@@ -50035,7 +50178,20 @@ var TuiAltScreen = class extends TuiBase {
50035
50178
  return sliceByColumn(line, 0, width, true);
50036
50179
  });
50037
50180
  const fullRedraw = this.previousScreen.length === 0 || this.previousScreenWidth !== width || this.previousScreenHeight !== height;
50038
- const imagesNeedRedraw = screen.some((line, row) => line !== this.previousScreen[row] && (isImageLine(line) || isImageLine(this.previousScreen[row] ?? "")));
50181
+ const changedRows = screen.map((line, row) => line !== this.previousScreen[row]);
50182
+ const imageAnchorsNeedRedraw = screen.some((line, row) => changedRows[row] && (isImageLine(line) || isImageLine(this.previousScreen[row] ?? "")));
50183
+ const isWezTerm = Boolean(process.env.WEZTERM_PANE) || process.env.TERM_PROGRAM?.toLowerCase() === "wezterm";
50184
+ const imageCellsNeedRedraw = !imageAnchorsNeedRedraw && isWezTerm && this.imageProtocol === "kitty" && changedRows.some(Boolean) && screen.some((line, row) => {
50185
+ const placementRows = getKittyImagePlacementRows(line);
50186
+ if (placementRows === void 0)
50187
+ return false;
50188
+ for (let coveredRow = row; coveredRow < row + placementRows; coveredRow++) {
50189
+ if (changedRows[coveredRow])
50190
+ return true;
50191
+ }
50192
+ return false;
50193
+ });
50194
+ const imagesNeedRedraw = imageAnchorsNeedRedraw || imageCellsNeedRedraw;
50039
50195
  const redrawImages = fullRedraw || imagesNeedRedraw;
50040
50196
  const hadUploadedKittyImages = this.uploadedKittyImages.size > 0;
50041
50197
  const preparedKittyScreen = redrawImages && this.imageProtocol === "kitty" ? this.prepareKittyScreen(screen) : { lines: screen, evictedImageDeletion: "" };
@@ -50051,18 +50207,33 @@ var TuiAltScreen = class extends TuiBase {
50051
50207
  buffer += deleteAllKittyPlacements();
50052
50208
  }
50053
50209
  buffer += preparedKittyScreen.evictedImageDeletion;
50054
- const clearRowsBeforeKittyImages = redrawImages && this.imageProtocol === "kitty" && screen.some(isImageLine) && (Boolean(process.env.WEZTERM_PANE) || process.env.TERM_PROGRAM?.toLowerCase() === "wezterm");
50055
- if (clearRowsBeforeKittyImages) {
50210
+ const drawKittyImagesLast = redrawImages && this.imageProtocol === "kitty" && screen.some(isImageLine) && isWezTerm;
50211
+ if (drawKittyImagesLast) {
50056
50212
  for (let row = 0; row < height; row++) {
50057
50213
  if (!fullRedraw && !imagesNeedRedraw && screen[row] === this.previousScreen[row])
50058
50214
  continue;
50059
50215
  buffer += `\x1B[${row + 1};1H\x1B[2K`;
50060
50216
  }
50061
- }
50062
- for (let row = 0; row < height; row++) {
50063
- if (!fullRedraw && !imagesNeedRedraw && screen[row] === this.previousScreen[row])
50064
- continue;
50065
- buffer += `\x1B[${row + 1};1H${clearRowsBeforeKittyImages ? "" : "\x1B[2K"}${preparedKittyScreen.lines[row] ?? ""}`;
50217
+ for (let row = 0; row < height; row++) {
50218
+ if (!fullRedraw && !imagesNeedRedraw && screen[row] === this.previousScreen[row])
50219
+ continue;
50220
+ if (isImageLine(preparedKittyScreen.lines[row] ?? ""))
50221
+ continue;
50222
+ buffer += `\x1B[${row + 1};1H${preparedKittyScreen.lines[row] ?? ""}`;
50223
+ }
50224
+ for (let row = 0; row < height; row++) {
50225
+ if (!fullRedraw && !imagesNeedRedraw && screen[row] === this.previousScreen[row])
50226
+ continue;
50227
+ if (!isImageLine(preparedKittyScreen.lines[row] ?? ""))
50228
+ continue;
50229
+ buffer += `\x1B[${row + 1};1H${preparedKittyScreen.lines[row] ?? ""}`;
50230
+ }
50231
+ } else {
50232
+ for (let row = 0; row < height; row++) {
50233
+ if (!fullRedraw && !imagesNeedRedraw && screen[row] === this.previousScreen[row])
50234
+ continue;
50235
+ buffer += `\x1B[${row + 1};1H\x1B[2K${preparedKittyScreen.lines[row] ?? ""}`;
50236
+ }
50066
50237
  }
50067
50238
  if (cursorPos) {
50068
50239
  buffer += `\x1B[${cursorPos.row + 1};${Math.min(width, cursorPos.col) + 1}H`;
@@ -33758,6 +33758,9 @@ var Protocol = class {
33758
33758
  this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => {
33759
33759
  const handleTaskResult = async () => {
33760
33760
  const taskId = request.params.taskId;
33761
+ if (!await this._taskStore.getTask(taskId, extra.sessionId)) {
33762
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
33763
+ }
33761
33764
  if (this._taskMessageQueue) {
33762
33765
  let queuedMessage;
33763
33766
  while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
@@ -33788,12 +33791,12 @@ var Protocol = class {
33788
33791
  throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
33789
33792
  }
33790
33793
  if (!isTerminal(task.status)) {
33791
- await this._waitForTaskUpdate(taskId, extra.signal);
33794
+ await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId);
33792
33795
  return await handleTaskResult();
33793
33796
  }
33794
33797
  if (isTerminal(task.status)) {
33795
33798
  const result2 = await this._taskStore.getTaskResult(taskId, extra.sessionId);
33796
- this._clearTaskQueue(taskId);
33799
+ this._clearTaskQueue(taskId, extra.sessionId);
33797
33800
  return {
33798
33801
  ...result2,
33799
33802
  _meta: {
@@ -33830,7 +33833,7 @@ var Protocol = class {
33830
33833
  throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
33831
33834
  }
33832
33835
  await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
33833
- this._clearTaskQueue(request.params.taskId);
33836
+ this._clearTaskQueue(request.params.taskId, extra.sessionId);
33834
33837
  const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
33835
33838
  if (!cancelledTask) {
33836
33839
  throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
@@ -33958,6 +33961,19 @@ var Protocol = class {
33958
33961
  const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
33959
33962
  const capturedTransport = this._transport;
33960
33963
  const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
33964
+ const sessionId = capturedTransport?.sessionId;
33965
+ const store = this._taskStore;
33966
+ let relatedTaskFound = true;
33967
+ let relatedTaskLookup;
33968
+ if (relatedTaskId && store && this._taskMessageQueue && sessionId !== void 0) {
33969
+ relatedTaskFound = false;
33970
+ relatedTaskLookup = (async () => {
33971
+ if (!await store.getTask(relatedTaskId, sessionId)) {
33972
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${relatedTaskId}`);
33973
+ }
33974
+ relatedTaskFound = true;
33975
+ })();
33976
+ }
33961
33977
  if (handler === void 0) {
33962
33978
  const errorResponse = {
33963
33979
  jsonrpc: "2.0",
@@ -33967,7 +33983,10 @@ var Protocol = class {
33967
33983
  message: "Method not found"
33968
33984
  }
33969
33985
  };
33970
- if (relatedTaskId && this._taskMessageQueue) {
33986
+ if (relatedTaskId && relatedTaskLookup) {
33987
+ const queuedError = { type: "error", message: errorResponse, timestamp: Date.now() };
33988
+ relatedTaskLookup.then(() => this._enqueueTaskMessage(relatedTaskId, queuedError, sessionId), () => capturedTransport?.send(errorResponse)).catch((error2) => this._onerror(new Error(`Failed to send an error response: ${error2}`)));
33989
+ } else if (relatedTaskId && this._taskMessageQueue) {
33971
33990
  this._enqueueTaskMessage(relatedTaskId, {
33972
33991
  type: "error",
33973
33992
  message: errorResponse,
@@ -34018,7 +34037,10 @@ var Protocol = class {
34018
34037
  closeSSEStream: extra?.closeSSEStream,
34019
34038
  closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
34020
34039
  };
34021
- Promise.resolve().then(() => {
34040
+ (relatedTaskLookup ?? Promise.resolve()).then(() => {
34041
+ if (relatedTaskLookup && abortController.signal.aborted) {
34042
+ throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
34043
+ }
34022
34044
  if (taskCreationParams) {
34023
34045
  this.assertTaskHandlerCapability(request.method);
34024
34046
  }
@@ -34053,7 +34075,7 @@ var Protocol = class {
34053
34075
  ...error2["data"] !== void 0 && { data: error2["data"] }
34054
34076
  }
34055
34077
  };
34056
- if (relatedTaskId && this._taskMessageQueue) {
34078
+ if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) {
34057
34079
  await this._enqueueTaskMessage(relatedTaskId, {
34058
34080
  type: "error",
34059
34081
  message: errorResponse,
@@ -34533,7 +34555,7 @@ var Protocol = class {
34533
34555
  throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
34534
34556
  }
34535
34557
  const maxQueueSize = this._options?.maxTaskQueueSize;
34536
- await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
34558
+ await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize);
34537
34559
  }
34538
34560
  /**
34539
34561
  * Clears the message queue for a task and rejects any pending request resolvers.
@@ -34562,12 +34584,13 @@ var Protocol = class {
34562
34584
  * Uses polling to check for updates at the task's configured poll interval.
34563
34585
  * @param taskId The task ID to wait for
34564
34586
  * @param signal Abort signal to cancel the wait
34587
+ * @param sessionId Session of the request that waits, passed to the task store
34565
34588
  * @returns Promise that resolves when an update occurs or rejects if aborted
34566
34589
  */
34567
- async _waitForTaskUpdate(taskId, signal) {
34590
+ async _waitForTaskUpdate(taskId, signal, sessionId) {
34568
34591
  let interval = this._options?.defaultTaskPollInterval ?? 1e3;
34569
34592
  try {
34570
- const task = await this._taskStore?.getTask(taskId);
34593
+ const task = await this._taskStore?.getTask(taskId, sessionId);
34571
34594
  if (task?.pollInterval) {
34572
34595
  interval = task.pollInterval;
34573
34596
  }
@@ -35446,6 +35469,42 @@ var ExperimentalMcpServerTasks = class {
35446
35469
  };
35447
35470
 
35448
35471
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
35472
+ function toolInputElementCount(value, max) {
35473
+ let count = 0;
35474
+ const stack = [value];
35475
+ while (stack.length > 0) {
35476
+ const node = stack.pop();
35477
+ if (node === null || typeof node !== "object")
35478
+ continue;
35479
+ if (Array.isArray(node)) {
35480
+ for (const child of node) {
35481
+ if (++count > max)
35482
+ return count;
35483
+ if (child !== null && typeof child === "object")
35484
+ stack.push(child);
35485
+ }
35486
+ } else {
35487
+ for (const key in node) {
35488
+ if (!Object.prototype.hasOwnProperty.call(node, key))
35489
+ continue;
35490
+ if (++count > max)
35491
+ return count;
35492
+ const child = node[key];
35493
+ if (child !== null && typeof child === "object")
35494
+ stack.push(child);
35495
+ }
35496
+ }
35497
+ }
35498
+ return count;
35499
+ }
35500
+ function resolveMaxToolInputElements(value) {
35501
+ if (value === void 0 || value === Infinity)
35502
+ return void 0;
35503
+ if (typeof value !== "number" || Number.isNaN(value) || value < 1) {
35504
+ throw new RangeError(`maxToolInputElements must be a number of at least 1, or Infinity, got ${String(value)}`);
35505
+ }
35506
+ return value;
35507
+ }
35449
35508
  var McpServer = class {
35450
35509
  constructor(serverInfo, options) {
35451
35510
  this._registeredResources = {};
@@ -35457,6 +35516,7 @@ var McpServer = class {
35457
35516
  this._resourceHandlersInitialized = false;
35458
35517
  this._promptHandlersInitialized = false;
35459
35518
  this.server = new Server(serverInfo, options);
35519
+ this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
35460
35520
  }
35461
35521
  /**
35462
35522
  * Access experimental features.
@@ -35587,12 +35647,15 @@ var McpServer = class {
35587
35647
  * Validates tool input arguments against the tool's input schema.
35588
35648
  */
35589
35649
  async validateToolInput(tool, args, toolName) {
35650
+ if (this._maxToolInputElements !== void 0 && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) {
35651
+ throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
35652
+ }
35590
35653
  if (!tool.inputSchema) {
35591
35654
  return void 0;
35592
35655
  }
35593
35656
  const inputObj = normalizeObjectSchema(tool.inputSchema);
35594
35657
  const schemaToParse = inputObj ?? tool.inputSchema;
35595
- const parseResult = await safeParseAsync2(schemaToParse, args);
35658
+ const parseResult = await safeParseAsync2(schemaToParse, args ?? {});
35596
35659
  if (!parseResult.success) {
35597
35660
  const error2 = "error" in parseResult ? parseResult.error : "Unknown error";
35598
35661
  const errorMessage = getParseErrorMessage(error2);
@@ -35830,7 +35893,7 @@ var McpServer = class {
35830
35893
  }
35831
35894
  if (prompt.argsSchema) {
35832
35895
  const argsObj = normalizeObjectSchema(prompt.argsSchema);
35833
- const parseResult = await safeParseAsync2(argsObj, request.params.arguments);
35896
+ const parseResult = await safeParseAsync2(argsObj, request.params.arguments ?? {});
35834
35897
  if (!parseResult.success) {
35835
35898
  const error2 = "error" in parseResult ? parseResult.error : "Unknown error";
35836
35899
  const errorMessage = getParseErrorMessage(error2);
@@ -21387,6 +21387,9 @@ var Protocol = class {
21387
21387
  this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => {
21388
21388
  const handleTaskResult = async () => {
21389
21389
  const taskId = request.params.taskId;
21390
+ if (!await this._taskStore.getTask(taskId, extra.sessionId)) {
21391
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
21392
+ }
21390
21393
  if (this._taskMessageQueue) {
21391
21394
  let queuedMessage;
21392
21395
  while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
@@ -21417,12 +21420,12 @@ var Protocol = class {
21417
21420
  throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
21418
21421
  }
21419
21422
  if (!isTerminal(task.status)) {
21420
- await this._waitForTaskUpdate(taskId, extra.signal);
21423
+ await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId);
21421
21424
  return await handleTaskResult();
21422
21425
  }
21423
21426
  if (isTerminal(task.status)) {
21424
21427
  const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
21425
- this._clearTaskQueue(taskId);
21428
+ this._clearTaskQueue(taskId, extra.sessionId);
21426
21429
  return {
21427
21430
  ...result,
21428
21431
  _meta: {
@@ -21459,7 +21462,7 @@ var Protocol = class {
21459
21462
  throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
21460
21463
  }
21461
21464
  await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
21462
- this._clearTaskQueue(request.params.taskId);
21465
+ this._clearTaskQueue(request.params.taskId, extra.sessionId);
21463
21466
  const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
21464
21467
  if (!cancelledTask) {
21465
21468
  throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
@@ -21587,6 +21590,19 @@ var Protocol = class {
21587
21590
  const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
21588
21591
  const capturedTransport = this._transport;
21589
21592
  const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
21593
+ const sessionId = capturedTransport?.sessionId;
21594
+ const store = this._taskStore;
21595
+ let relatedTaskFound = true;
21596
+ let relatedTaskLookup;
21597
+ if (relatedTaskId && store && this._taskMessageQueue && sessionId !== void 0) {
21598
+ relatedTaskFound = false;
21599
+ relatedTaskLookup = (async () => {
21600
+ if (!await store.getTask(relatedTaskId, sessionId)) {
21601
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${relatedTaskId}`);
21602
+ }
21603
+ relatedTaskFound = true;
21604
+ })();
21605
+ }
21590
21606
  if (handler === void 0) {
21591
21607
  const errorResponse = {
21592
21608
  jsonrpc: "2.0",
@@ -21596,7 +21612,10 @@ var Protocol = class {
21596
21612
  message: "Method not found"
21597
21613
  }
21598
21614
  };
21599
- if (relatedTaskId && this._taskMessageQueue) {
21615
+ if (relatedTaskId && relatedTaskLookup) {
21616
+ const queuedError = { type: "error", message: errorResponse, timestamp: Date.now() };
21617
+ relatedTaskLookup.then(() => this._enqueueTaskMessage(relatedTaskId, queuedError, sessionId), () => capturedTransport?.send(errorResponse)).catch((error2) => this._onerror(new Error(`Failed to send an error response: ${error2}`)));
21618
+ } else if (relatedTaskId && this._taskMessageQueue) {
21600
21619
  this._enqueueTaskMessage(relatedTaskId, {
21601
21620
  type: "error",
21602
21621
  message: errorResponse,
@@ -21647,7 +21666,10 @@ var Protocol = class {
21647
21666
  closeSSEStream: extra?.closeSSEStream,
21648
21667
  closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
21649
21668
  };
21650
- Promise.resolve().then(() => {
21669
+ (relatedTaskLookup ?? Promise.resolve()).then(() => {
21670
+ if (relatedTaskLookup && abortController.signal.aborted) {
21671
+ throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
21672
+ }
21651
21673
  if (taskCreationParams) {
21652
21674
  this.assertTaskHandlerCapability(request.method);
21653
21675
  }
@@ -21682,7 +21704,7 @@ var Protocol = class {
21682
21704
  ...error2["data"] !== void 0 && { data: error2["data"] }
21683
21705
  }
21684
21706
  };
21685
- if (relatedTaskId && this._taskMessageQueue) {
21707
+ if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) {
21686
21708
  await this._enqueueTaskMessage(relatedTaskId, {
21687
21709
  type: "error",
21688
21710
  message: errorResponse,
@@ -22162,7 +22184,7 @@ var Protocol = class {
22162
22184
  throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
22163
22185
  }
22164
22186
  const maxQueueSize = this._options?.maxTaskQueueSize;
22165
- await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
22187
+ await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize);
22166
22188
  }
22167
22189
  /**
22168
22190
  * Clears the message queue for a task and rejects any pending request resolvers.
@@ -22191,12 +22213,13 @@ var Protocol = class {
22191
22213
  * Uses polling to check for updates at the task's configured poll interval.
22192
22214
  * @param taskId The task ID to wait for
22193
22215
  * @param signal Abort signal to cancel the wait
22216
+ * @param sessionId Session of the request that waits, passed to the task store
22194
22217
  * @returns Promise that resolves when an update occurs or rejects if aborted
22195
22218
  */
22196
- async _waitForTaskUpdate(taskId, signal) {
22219
+ async _waitForTaskUpdate(taskId, signal, sessionId) {
22197
22220
  let interval = this._options?.defaultTaskPollInterval ?? 1e3;
22198
22221
  try {
22199
- const task = await this._taskStore?.getTask(taskId);
22222
+ const task = await this._taskStore?.getTask(taskId, sessionId);
22200
22223
  if (task?.pollInterval) {
22201
22224
  interval = task.pollInterval;
22202
22225
  }
@@ -25438,7 +25461,7 @@ function sessionTokenFixHint(policy) {
25438
25461
  }
25439
25462
 
25440
25463
  // plugins/kxm/src/mcp-server.ts
25441
- var VERSION = "0.7.175";
25464
+ var VERSION = "0.7.177";
25442
25465
  var CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
25443
25466
  var inbox = /* @__PURE__ */ new Map();
25444
25467
  var notifiedInbox = /* @__PURE__ */ new Set();
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-plugin",
3
- "version": "0.7.175",
3
+ "version": "0.7.177",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "engines": {
@@ -11,7 +11,7 @@ import { deliverInboxNotification } from "./inbox.ts";
11
11
  import type { HubEvent, MessageRecord } from "./protocol.ts";
12
12
  import { sessionTokenFixHint } from "./session-token-hint.ts";
13
13
 
14
- const VERSION = "0.7.175";
14
+ const VERSION = "0.7.177";
15
15
  const CONFIGURE_PLUGIN = "/plugin configure kxm@kxm";
16
16
  const inbox = new Map<string, MessageRecord>();
17
17
  const notifiedInbox = new Set<string>();