@simon_he/vue-tui 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -380,6 +380,308 @@ function ansiColors(level) {
380
380
  return ANSI256_COLORS;
381
381
  }
382
382
 
383
+ //#endregion
384
+ //#region src/observability/cli-latency.ts
385
+ const EVENT_OP_ID = Symbol("dimcode.cliLatencyOpId");
386
+ const DEFAULT_LOG_PATH = "/tmp/dimcode-cli-latency.jsonl";
387
+ const INVALIDATE_ASSOCIATION_WINDOW_MS = 32;
388
+ const MAX_OP_AGE_MS = 5e3;
389
+ let nextOpId = 1;
390
+ let singleton;
391
+ function now$2() {
392
+ return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
393
+ }
394
+ function diffMs(end, start) {
395
+ if (end == null || start == null) return null;
396
+ return Math.max(0, end - start);
397
+ }
398
+ function parseEnabled$1(value) {
399
+ const raw = String(value ?? "").trim().toLowerCase();
400
+ return raw === "1" || raw === "true" || raw === "yes";
401
+ }
402
+ function isTrackedEventType(type) {
403
+ return type === "keydown" || type === "beforeinput" || type === "input" || type === "paste";
404
+ }
405
+ function defineOpId(target, id) {
406
+ try {
407
+ Object.defineProperty(target, EVENT_OP_ID, {
408
+ configurable: true,
409
+ enumerable: false,
410
+ writable: true,
411
+ value: id
412
+ });
413
+ } catch {}
414
+ }
415
+ function readOpId(target) {
416
+ const value = target === null || target === void 0 ? void 0 : target[EVENT_OP_ID];
417
+ return typeof value === "number" ? value : null;
418
+ }
419
+ function createDisabledProfiler() {
420
+ return null;
421
+ }
422
+ function createProfiler() {
423
+ var _process$once;
424
+ const env = (process$1 === null || process$1 === void 0 ? void 0 : process$1.env) ?? {};
425
+ if (!parseEnabled$1(env.DIMCODE_PROFILE_INPUT_LATENCY)) return createDisabledProfiler();
426
+ const logPath = String(env.DIMCODE_PROFILE_INPUT_LATENCY_LOG_PATH ?? DEFAULT_LOG_PATH).trim() || DEFAULT_LOG_PATH;
427
+ const ops = new Map();
428
+ const pendingCommitIds = new Set();
429
+ const pendingWriteIds = new Set();
430
+ let currentDispatchOpId = null;
431
+ let lastDispatchOpId = null;
432
+ let lastDispatchEndedAt = null;
433
+ let currentFlushIds = [];
434
+ let lastRawInputAt = null;
435
+ const emit = (record) => {
436
+ try {
437
+ appendFileSync(logPath, `${JSON.stringify(record)}\n`);
438
+ } catch {}
439
+ };
440
+ const cleanupOp = (id) => {
441
+ ops.delete(id);
442
+ pendingCommitIds.delete(id);
443
+ pendingWriteIds.delete(id);
444
+ if (currentDispatchOpId === id) currentDispatchOpId = null;
445
+ if (lastDispatchOpId === id) {
446
+ lastDispatchOpId = null;
447
+ lastDispatchEndedAt = null;
448
+ }
449
+ if (currentFlushIds.includes(id)) currentFlushIds = currentFlushIds.filter((value) => value !== id);
450
+ };
451
+ const flushOp = (op, outcome) => {
452
+ const totalStart = op.rawInputAt ?? op.stdinDispatchAt ?? op.dispatchStartAt;
453
+ emit({
454
+ ts: op.createdAtIso,
455
+ id: op.id,
456
+ event: {
457
+ type: op.eventType,
458
+ key: op.key,
459
+ code: op.code,
460
+ defaultPrevented: op.defaultPrevented,
461
+ parser: op.parser
462
+ },
463
+ operation: op.operation,
464
+ stages: {
465
+ rawInputAt: op.rawInputAt,
466
+ stdinDispatchAt: op.stdinDispatchAt,
467
+ dispatchStartAt: op.dispatchStartAt,
468
+ dispatchEndAt: op.dispatchEndAt,
469
+ invalidateAt: op.invalidateAt,
470
+ flushStartAt: op.flushStartAt,
471
+ flushEndAt: op.flushEndAt,
472
+ commitAt: op.commitAt,
473
+ stdoutRenderStartAt: op.stdoutRenderStartAt,
474
+ writeStartAt: op.writeStartAt,
475
+ writeEndAt: op.writeEndAt
476
+ },
477
+ timingsMs: {
478
+ inputParseWait: diffMs(op.stdinDispatchAt, op.rawInputAt),
479
+ eventDispatch: diffMs(op.dispatchEndAt, op.dispatchStartAt),
480
+ dispatchToInvalidate: diffMs(op.invalidateAt, op.dispatchEndAt),
481
+ dispatchToFlush: diffMs(op.flushStartAt, op.dispatchEndAt),
482
+ flushToCommitDone: diffMs(op.flushEndAt, op.flushStartAt),
483
+ commitToRender: diffMs(op.stdoutRenderStartAt, op.commitAt),
484
+ renderToWriteStart: diffMs(op.writeStartAt, op.stdoutRenderStartAt),
485
+ write: op.writeDurationMs,
486
+ totalToWrite: diffMs(op.writeEndAt, totalStart)
487
+ },
488
+ scheduler: {
489
+ invalidatePriority: op.invalidatePriority,
490
+ invalidatePlane: op.invalidatePlane,
491
+ commitSync: op.commitSync,
492
+ commitPlaneCount: op.commitPlaneCount,
493
+ commitDirtyRows: op.commitDirtyRows,
494
+ stdoutQueuedDelayMs: op.stdoutQueuedDelayMs,
495
+ writeMode: op.writeMode,
496
+ writeBytes: op.writeBytes
497
+ },
498
+ outcome
499
+ });
500
+ cleanupOp(op.id);
501
+ };
502
+ const expireOldOps = () => {
503
+ const currentTime = now$2();
504
+ for (const op of ops.values()) {
505
+ if (currentTime - op.createdAt < MAX_OP_AGE_MS) continue;
506
+ flushOp(op, op.writeEndAt != null ? "completed" : "timeout");
507
+ }
508
+ };
509
+ const flushPendingOps = (outcome) => {
510
+ for (const op of Array.from(ops.values())) flushOp(op, op.writeEndAt != null ? "completed" : outcome);
511
+ };
512
+ const ensureOp = (event) => {
513
+ const type = String((event === null || event === void 0 ? void 0 : event.type) ?? "");
514
+ if (!isTrackedEventType(type)) return null;
515
+ const existingId = readOpId(event);
516
+ if (existingId != null) return ops.get(existingId) ?? null;
517
+ const id = nextOpId++;
518
+ const op = {
519
+ id,
520
+ createdAt: now$2(),
521
+ createdAtIso: new Date().toISOString(),
522
+ eventType: type,
523
+ key: String((event === null || event === void 0 ? void 0 : event.key) ?? ""),
524
+ code: String((event === null || event === void 0 ? void 0 : event.code) ?? ""),
525
+ operation: null,
526
+ rawInputAt: null,
527
+ stdinDispatchAt: null,
528
+ dispatchStartAt: null,
529
+ dispatchEndAt: null,
530
+ invalidateAt: null,
531
+ invalidatePriority: null,
532
+ invalidatePlane: null,
533
+ flushStartAt: null,
534
+ flushEndAt: null,
535
+ commitAt: null,
536
+ commitSync: null,
537
+ commitPlaneCount: null,
538
+ commitDirtyRows: null,
539
+ stdoutQueuedDelayMs: null,
540
+ stdoutRenderStartAt: null,
541
+ writeStartAt: null,
542
+ writeEndAt: null,
543
+ writeDurationMs: null,
544
+ writeMode: null,
545
+ writeBytes: null,
546
+ defaultPrevented: null,
547
+ parser: null
548
+ };
549
+ ops.set(id, op);
550
+ defineOpId(event, id);
551
+ expireOldOps();
552
+ return op;
553
+ };
554
+ const forIds = (ids, fn) => {
555
+ for (const id of ids) {
556
+ const op = ops.get(id);
557
+ if (!op) continue;
558
+ fn(op);
559
+ }
560
+ };
561
+ const resolveActiveOp = () => {
562
+ if (currentDispatchOpId != null) return ops.get(currentDispatchOpId) ?? null;
563
+ if (lastDispatchOpId != null && lastDispatchEndedAt != null && now$2() - lastDispatchEndedAt <= INVALIDATE_ASSOCIATION_WINDOW_MS) return ops.get(lastDispatchOpId) ?? null;
564
+ return null;
565
+ };
566
+ process$1 === null || process$1 === void 0 || (_process$once = process$1.once) === null || _process$once === void 0 || _process$once.call(process$1, "exit", () => {
567
+ flushPendingOps("process-exit");
568
+ });
569
+ return {
570
+ enabled: true,
571
+ recordRawInput(_info) {
572
+ lastRawInputAt = now$2();
573
+ expireOldOps();
574
+ },
575
+ recordStdinDispatch(event, info) {
576
+ const op = ensureOp(event);
577
+ if (!op) return;
578
+ if (op.rawInputAt == null && lastRawInputAt != null) op.rawInputAt = lastRawInputAt;
579
+ if (op.stdinDispatchAt == null) op.stdinDispatchAt = now$2();
580
+ if (!op.parser && (info === null || info === void 0 ? void 0 : info.parser)) op.parser = String(info.parser);
581
+ },
582
+ recordEventDispatchStart(event) {
583
+ const op = ensureOp(event);
584
+ if (!op) return;
585
+ currentDispatchOpId = op.id;
586
+ if (op.dispatchStartAt == null) op.dispatchStartAt = now$2();
587
+ },
588
+ recordEventDispatchEnd(event, info) {
589
+ const op = ensureOp(event);
590
+ if (!op) return;
591
+ op.defaultPrevented = Boolean(info.defaultPrevented);
592
+ if (op.dispatchEndAt == null) op.dispatchEndAt = now$2();
593
+ currentDispatchOpId = currentDispatchOpId === op.id ? null : currentDispatchOpId;
594
+ lastDispatchOpId = op.id;
595
+ lastDispatchEndedAt = op.dispatchEndAt;
596
+ },
597
+ recordSchedulerInvalidate(info) {
598
+ const op = resolveActiveOp();
599
+ if (!op) return;
600
+ if (op.invalidateAt == null) op.invalidateAt = now$2();
601
+ if (!op.invalidatePriority && (info === null || info === void 0 ? void 0 : info.priority)) op.invalidatePriority = String(info.priority);
602
+ if (!op.invalidatePlane && (info === null || info === void 0 ? void 0 : info.plane)) op.invalidatePlane = String(info.plane);
603
+ pendingCommitIds.add(op.id);
604
+ },
605
+ recordFlushStart(info) {
606
+ currentFlushIds = Array.from(pendingCommitIds);
607
+ if (!currentFlushIds.length) return;
608
+ const flushTime = now$2();
609
+ forIds(currentFlushIds, (op) => {
610
+ if (op.flushStartAt == null) op.flushStartAt = flushTime;
611
+ if (op.commitSync == null && (info === null || info === void 0 ? void 0 : info.sync) != null) op.commitSync = Boolean(info.sync);
612
+ if (op.commitPlaneCount == null && Array.isArray(info === null || info === void 0 ? void 0 : info.activePlanes)) op.commitPlaneCount = info.activePlanes.length;
613
+ });
614
+ },
615
+ recordFlushEnd() {
616
+ if (!currentFlushIds.length) return;
617
+ const flushTime = now$2();
618
+ forIds(currentFlushIds, (op) => {
619
+ if (op.flushEndAt == null) op.flushEndAt = flushTime;
620
+ });
621
+ currentFlushIds = [];
622
+ },
623
+ recordCommit(info) {
624
+ if (!pendingCommitIds.size) return;
625
+ const commitTime = now$2();
626
+ const ids = Array.from(pendingCommitIds);
627
+ pendingCommitIds.clear();
628
+ forIds(ids, (op) => {
629
+ if (op.flushEndAt == null && op.flushStartAt != null) op.flushEndAt = commitTime;
630
+ if (op.commitAt == null) op.commitAt = commitTime;
631
+ op.commitSync = (info === null || info === void 0 ? void 0 : info.sync) == null ? op.commitSync : Boolean(info.sync);
632
+ op.commitPlaneCount = Array.isArray(info === null || info === void 0 ? void 0 : info.planes) ? info.planes.length : op.commitPlaneCount;
633
+ op.commitDirtyRows = Array.isArray(info === null || info === void 0 ? void 0 : info.dirtyRows) ? info.dirtyRows.length : (info === null || info === void 0 ? void 0 : info.dirtyRows) === null ? null : op.commitDirtyRows;
634
+ pendingWriteIds.add(op.id);
635
+ });
636
+ },
637
+ recordStdoutQueued(delayMs) {
638
+ if (!pendingWriteIds.size) return;
639
+ forIds(pendingWriteIds, (op) => {
640
+ if (op.stdoutQueuedDelayMs == null) op.stdoutQueuedDelayMs = Math.max(0, delayMs);
641
+ });
642
+ },
643
+ recordStdoutRenderStart() {
644
+ if (!pendingWriteIds.size) return;
645
+ const renderTime = now$2();
646
+ forIds(pendingWriteIds, (op) => {
647
+ if (op.stdoutRenderStartAt == null) op.stdoutRenderStartAt = renderTime;
648
+ });
649
+ },
650
+ recordStdoutNoOutput() {
651
+ if (!pendingWriteIds.size) return;
652
+ const ids = Array.from(pendingWriteIds);
653
+ pendingWriteIds.clear();
654
+ forIds(ids, (op) => flushOp(op, "no-output"));
655
+ },
656
+ recordStdoutWrite(info) {
657
+ if (!pendingWriteIds.size) return;
658
+ const writeEndTime = now$2();
659
+ const ids = Array.from(pendingWriteIds);
660
+ pendingWriteIds.clear();
661
+ forIds(ids, (op) => {
662
+ op.writeEndAt = writeEndTime;
663
+ op.writeDurationMs = Math.max(0, info.durationMs);
664
+ op.writeStartAt = writeEndTime - op.writeDurationMs;
665
+ op.writeMode = String(info.mode ?? "");
666
+ op.writeBytes = Math.max(0, Math.floor(info.bytes));
667
+ flushOp(op, "completed");
668
+ });
669
+ },
670
+ markOperation(operation) {
671
+ const nextOperation = String(operation ?? "").trim();
672
+ if (!nextOperation) return;
673
+ const op = resolveActiveOp();
674
+ if (!op) return;
675
+ op.operation = nextOperation;
676
+ }
677
+ };
678
+ }
679
+ function getCliLatencyProfiler() {
680
+ if (singleton !== void 0) return singleton;
681
+ singleton = createProfiler();
682
+ return singleton;
683
+ }
684
+
383
685
  //#endregion
384
686
  //#region src/utils/newlines.ts
385
687
  function normalizeNewlines(text) {
@@ -1422,6 +1724,7 @@ function parseMouseSequence(sequence) {
1422
1724
  const ESC$1 = "\x1B";
1423
1725
  const BRACKETED_PASTE_START = "\x1B[200~";
1424
1726
  const BRACKETED_PASTE_END = "\x1B[201~";
1727
+ const ESC_CONTINUATION_RESCUE_WINDOW_MS = 64;
1425
1728
  function looksLikeQuotedPathPaste(value) {
1426
1729
  if (!value) return false;
1427
1730
  if (value.includes(ESC$1)) return false;
@@ -1524,6 +1827,11 @@ function extractCompleteSequences(buffer) {
1524
1827
  remainder: ""
1525
1828
  };
1526
1829
  }
1830
+ function looksLikeSplitEscapeContinuation(value) {
1831
+ const first = value[0];
1832
+ if (first !== "[" && first !== "]" && first !== "P" && first !== "_" && first !== "O") return false;
1833
+ return isCompleteSequence(`${ESC$1}${value}`) !== "not-escape";
1834
+ }
1527
1835
  var StdinBuffer = class extends EventEmitter {
1528
1836
  constructor(options = {}) {
1529
1837
  super();
@@ -1531,6 +1839,7 @@ var StdinBuffer = class extends EventEmitter {
1531
1839
  this.timeout = null;
1532
1840
  this.timeoutMs = void 0;
1533
1841
  this.escTimeoutMs = void 0;
1842
+ this.pendingEscContinuationAt = null;
1534
1843
  this.pasteMode = false;
1535
1844
  this.pasteBuffer = "";
1536
1845
  this.timeoutMs = options.timeout ?? 10;
@@ -1547,6 +1856,11 @@ var StdinBuffer = class extends EventEmitter {
1547
1856
  str = `\x1B${String.fromCharCode(byte)}`;
1548
1857
  } else str = data.toString();
1549
1858
  else str = data;
1859
+ if (this.pendingEscContinuationAt != null) {
1860
+ const canRescue = Date.now() - this.pendingEscContinuationAt <= ESC_CONTINUATION_RESCUE_WINDOW_MS;
1861
+ this.pendingEscContinuationAt = null;
1862
+ if (canRescue && looksLikeSplitEscapeContinuation(str)) str = `${ESC$1}${str}`;
1863
+ }
1550
1864
  if (str.length === 0 && this.buffer.length === 0) {
1551
1865
  this.emit("data", "");
1552
1866
  return;
@@ -1600,7 +1914,9 @@ var StdinBuffer = class extends EventEmitter {
1600
1914
  if (this.buffer.length > 0) {
1601
1915
  const timeoutMs = this.buffer === ESC$1 ? this.escTimeoutMs : this.timeoutMs;
1602
1916
  this.timeout = setTimeout(() => {
1917
+ const rescuableLoneEsc = this.buffer === ESC$1;
1603
1918
  const flushed = this.flush();
1919
+ if (rescuableLoneEsc && flushed.length === 1 && flushed[0] === ESC$1) this.pendingEscContinuationAt = Date.now();
1604
1920
  for (const sequence of flushed) this.emit("data", sequence);
1605
1921
  }, timeoutMs);
1606
1922
  }
@@ -1621,6 +1937,7 @@ var StdinBuffer = class extends EventEmitter {
1621
1937
  this.timeout = null;
1622
1938
  }
1623
1939
  this.buffer = "";
1940
+ this.pendingEscContinuationAt = null;
1624
1941
  this.pasteMode = false;
1625
1942
  this.pasteBuffer = "";
1626
1943
  }
@@ -1634,6 +1951,10 @@ var StdinBuffer = class extends EventEmitter {
1634
1951
 
1635
1952
  //#endregion
1636
1953
  //#region src/cli/input.ts
1954
+ const KITTY_KEYBOARD_PROTOCOL_ENABLE = "\x1B[>1u";
1955
+ const KITTY_KEYBOARD_PROTOCOL_DISABLE = "\x1B[<u";
1956
+ const XTERM_MODIFY_OTHER_KEYS_ENABLE = "\x1B[>4;2m";
1957
+ const XTERM_MODIFY_OTHER_KEYS_DISABLE = "\x1B[>4n";
1637
1958
  function isPrintable(ch) {
1638
1959
  if (ch.length === 0) return false;
1639
1960
  if (ch.length === 1) {
@@ -1653,12 +1974,54 @@ function ctrlKeyFromChar(ch) {
1653
1974
  if (code >= 1 && code <= 26) return String.fromCharCode(code + 96);
1654
1975
  return null;
1655
1976
  }
1977
+ function isUnhandledCtrlC(event) {
1978
+ return event.type === "keydown" && (event.key === "c" || event.key === "C") && event.ctrlKey === true && event.metaKey !== true && event.altKey !== true && event.shiftKey !== true;
1979
+ }
1980
+ function parseKeyboardProtocol(value) {
1981
+ const normalized = String(value ?? "").trim().toLowerCase();
1982
+ if (normalized === "auto" || normalized === "kitty" || normalized === "xterm" || normalized === "off") return normalized;
1983
+ return null;
1984
+ }
1985
+ function detectKeyboardProtocol(env) {
1986
+ const termProgram = String(env.TERM_PROGRAM ?? "").trim().toLowerCase();
1987
+ const term = String(env.TERM ?? "").trim().toLowerCase();
1988
+ const hasKittyProtocolTerminal = "GHOSTTY_RESOURCES_DIR" in env || "WEZTERM_PANE" in env || "KITTY_WINDOW_ID" in env || "KITTY_INSTALLATION_DIR" in env || "ALACRITTY_WINDOW_ID" in env || "ALACRITTY_LOG" in env || termProgram.includes("ghostty") || termProgram.includes("wezterm") || termProgram.includes("kitty") || termProgram.includes("alacritty");
1989
+ if (hasKittyProtocolTerminal) return "kitty";
1990
+ const isScreenLike = "TMUX" in env || term.includes("screen") || term.includes("tmux");
1991
+ const hasXtermKeyboardTerminal = termProgram.includes("iterm") || termProgram.includes("apple_terminal") || termProgram.includes("vscode") || term.includes("xterm") && !isScreenLike;
1992
+ return hasXtermKeyboardTerminal ? "xterm" : "off";
1993
+ }
1994
+ function resolveKeyboardProtocol(options) {
1995
+ var _options$env;
1996
+ const configured = parseKeyboardProtocol(options.keyboardProtocol) ?? "auto";
1997
+ if (configured !== "auto") return configured;
1998
+ const envOverride = parseKeyboardProtocol((_options$env = options.env) === null || _options$env === void 0 ? void 0 : _options$env.DIMCODE_KEYBOARD_PROTOCOL);
1999
+ if (envOverride && envOverride !== "auto") return envOverride;
2000
+ return detectKeyboardProtocol(options.env ?? {});
2001
+ }
2002
+ function getKeyboardProtocolSequences(protocol) {
2003
+ if (protocol === "kitty") return {
2004
+ enable: KITTY_KEYBOARD_PROTOCOL_ENABLE,
2005
+ disable: KITTY_KEYBOARD_PROTOCOL_DISABLE
2006
+ };
2007
+ if (protocol === "xterm") return {
2008
+ enable: XTERM_MODIFY_OTHER_KEYS_ENABLE,
2009
+ disable: XTERM_MODIFY_OTHER_KEYS_DISABLE
2010
+ };
2011
+ return null;
2012
+ }
1656
2013
  function createStdinDriver(options) {
1657
2014
  const stdin = options.stdin ?? process$1.stdin;
1658
2015
  const stdout = options.stdout ?? process$1.stdout;
1659
2016
  if (!stdin || !stdout) throw new Error("createStdinDriver requires Node process.stdin/stdout");
2017
+ const env = options.env ?? process$1.env ?? {};
1660
2018
  const enableMouse = options.enableMouse ?? true;
1661
2019
  const enableMouseMotion = options.enableMouseMotion ?? false;
2020
+ const keyboardProtocol = resolveKeyboardProtocol({
2021
+ keyboardProtocol: options.keyboardProtocol,
2022
+ env
2023
+ });
2024
+ const keyboardProtocolSequences = getKeyboardProtocolSequences(keyboardProtocol);
1662
2025
  let disposed = false;
1663
2026
  let swallowNextLF = false;
1664
2027
  let lastMouseDown = null;
@@ -1668,55 +2031,61 @@ function createStdinDriver(options) {
1668
2031
  });
1669
2032
  const stdinBuffer = new StdinBuffer({
1670
2033
  timeout: 50,
1671
- escTimeout: enableMouse ? 80 : 20
2034
+ escTimeout: enableMouse ? 8 : 6
1672
2035
  });
2036
+ const latency = getCliLatencyProfiler();
2037
+ const dispatchEvent = (event, parser) => {
2038
+ var _options$onExit;
2039
+ latency === null || latency === void 0 || latency.recordStdinDispatch(event, { parser });
2040
+ const prevented = Boolean(options.dispatch(event));
2041
+ if (isUnhandledCtrlC(event) && !prevented) (_options$onExit = options.onExit) === null || _options$onExit === void 0 || _options$onExit.call(options);
2042
+ return prevented;
2043
+ };
1673
2044
  const handlePlainChar = (ch) => {
1674
2045
  if (swallowNextLF) {
1675
2046
  swallowNextLF = false;
1676
2047
  if (ch === "\n") return;
1677
2048
  }
1678
2049
  if (ch === "") {
1679
- var _options$onExit;
1680
- const prevented = Boolean(options.dispatch(keyEvent("c", "", { ctrlKey: true })));
1681
- if (!prevented) (_options$onExit = options.onExit) === null || _options$onExit === void 0 || _options$onExit.call(options);
2050
+ dispatchEvent(keyEvent("c", "", { ctrlKey: true }), "plain");
1682
2051
  return;
1683
2052
  }
1684
2053
  if (ch === "\r") {
1685
2054
  swallowNextLF = true;
1686
- options.dispatch(keyEvent("Enter", "Enter"));
2055
+ dispatchEvent(keyEvent("Enter", "Enter"), "plain");
1687
2056
  return;
1688
2057
  }
1689
2058
  if (ch === "\n") {
1690
- options.dispatch({
2059
+ dispatchEvent({
1691
2060
  type: "input",
1692
2061
  data: "\n",
1693
2062
  inputType: "insertLineBreak",
1694
2063
  text: "\n"
1695
- });
2064
+ }, "plain");
1696
2065
  return;
1697
2066
  }
1698
2067
  const ctrlKey = ctrlKeyFromChar(ch);
1699
2068
  if (ctrlKey) {
1700
2069
  if (ctrlKey === "i") {
1701
- options.dispatch(keyEvent("Tab", "Tab"));
2070
+ dispatchEvent(keyEvent("Tab", "Tab"), "plain");
1702
2071
  return;
1703
2072
  }
1704
2073
  if (ctrlKey === "h") {
1705
- options.dispatch(keyEvent("Backspace", "Backspace"));
2074
+ dispatchEvent(keyEvent("Backspace", "Backspace"), "plain");
1706
2075
  return;
1707
2076
  }
1708
- options.dispatch(keyEvent(ctrlKey, "", { ctrlKey: true }));
2077
+ dispatchEvent(keyEvent(ctrlKey, "", { ctrlKey: true }), "plain");
1709
2078
  return;
1710
2079
  }
1711
2080
  if (ch === "") {
1712
- options.dispatch(keyEvent("Backspace", "Backspace"));
2081
+ dispatchEvent(keyEvent("Backspace", "Backspace"), "plain");
1713
2082
  return;
1714
2083
  }
1715
2084
  if (ch === " ") {
1716
- options.dispatch(keyEvent("Tab", "Tab"));
2085
+ dispatchEvent(keyEvent("Tab", "Tab"), "plain");
1717
2086
  return;
1718
2087
  }
1719
- if (isPrintable(ch)) options.dispatch(keyEvent(ch));
2088
+ if (isPrintable(ch)) dispatchEvent(keyEvent(ch), "plain");
1720
2089
  };
1721
2090
  const handleMouseEvent = (event) => {
1722
2091
  const ev = event;
@@ -1789,21 +2158,21 @@ function createStdinDriver(options) {
1789
2158
  }
1790
2159
  const kitty = parseKittySequence(sequence);
1791
2160
  if (kitty.handled) {
1792
- if (kitty.event) options.dispatch(kitty.event);
2161
+ if (kitty.event) dispatchEvent(kitty.event, "kitty");
1793
2162
  return;
1794
2163
  }
1795
2164
  const legacy = parseLegacySequence(sequence);
1796
2165
  if (legacy.handled) {
1797
- if (legacy.event) options.dispatch(legacy.event);
2166
+ if (legacy.event) dispatchEvent(legacy.event, "legacy");
1798
2167
  return;
1799
2168
  }
1800
2169
  if (sequence.startsWith("\x1B")) {
1801
2170
  if (sequence.length === 2 && isPrintable(sequence[1])) {
1802
- options.dispatch(keyEvent(sequence[1], "", { altKey: true }));
2171
+ dispatchEvent(keyEvent(sequence[1], "", { altKey: true }), "alt");
1803
2172
  return;
1804
2173
  }
1805
2174
  if (sequence === "\x1B") {
1806
- options.dispatch(keyEvent("Escape", "Escape"));
2175
+ dispatchEvent(keyEvent("Escape", "Escape"), "escape");
1807
2176
  return;
1808
2177
  }
1809
2178
  return;
@@ -1813,10 +2182,10 @@ function createStdinDriver(options) {
1813
2182
  stdinBuffer.on("data", handleSequence);
1814
2183
  stdinBuffer.on("paste", (data) => {
1815
2184
  const pastedText = normalizeNewlines(data);
1816
- if (pastedText) options.dispatch({
2185
+ if (pastedText) dispatchEvent({
1817
2186
  type: "paste",
1818
2187
  text: pastedText
1819
- });
2188
+ }, "paste");
1820
2189
  });
1821
2190
  const decodeBytes = (bytes) => {
1822
2191
  if (bytes.length === 1 && bytes[0] > 127) {
@@ -1829,6 +2198,7 @@ function createStdinDriver(options) {
1829
2198
  };
1830
2199
  const onData = (chunk) => {
1831
2200
  if (disposed) return;
2201
+ latency === null || latency === void 0 || latency.recordRawInput();
1832
2202
  if (typeof chunk === "string") {
1833
2203
  stdinBuffer.process(chunk);
1834
2204
  return;
@@ -1854,6 +2224,7 @@ function createStdinDriver(options) {
1854
2224
  if (stdout.isTTY) {
1855
2225
  stdout.write("\x1B[?2004h");
1856
2226
  stdout.write("\x1B[?1004h");
2227
+ if (keyboardProtocolSequences) stdout.write(keyboardProtocolSequences.enable);
1857
2228
  if (enableMouse) {
1858
2229
  stdout.write("\x1B[?1007h");
1859
2230
  if (enableMouseMotion) stdout.write("\x1B[?1000h\x1B[?1003h\x1B[?1006h");
@@ -1876,6 +2247,7 @@ function createStdinDriver(options) {
1876
2247
  if (stdout.isTTY) {
1877
2248
  stdout.write("\x1B[?2004l");
1878
2249
  stdout.write("\x1B[?1004l");
2250
+ if (keyboardProtocolSequences) stdout.write(keyboardProtocolSequences.disable);
1879
2251
  if (enableMouse) {
1880
2252
  stdout.write("\x1B[?1007l");
1881
2253
  if (enableMouseMotion) stdout.write("\x1B[?1000l\x1B[?1003l\x1B[?1006l");
@@ -3901,6 +4273,7 @@ function createCliEventManager(options) {
3901
4273
  let hoverPath = [];
3902
4274
  const record = options === null || options === void 0 ? void 0 : options.record;
3903
4275
  const onFocusChange = options === null || options === void 0 ? void 0 : options.onFocusChange;
4276
+ const latency = getCliLatencyProfiler();
3904
4277
  const MODAL_FOCUS_Z_THRESHOLD = 100;
3905
4278
  const MODAL_ROOT_MIN_AREA = 40;
3906
4279
  function focusLockTarget() {
@@ -4280,51 +4653,65 @@ function createCliEventManager(options) {
4280
4653
  },
4281
4654
  dispatch(event) {
4282
4655
  record === null || record === void 0 || record(event);
4283
- if (event.type === "keydown" || event.type === "keyup") return dispatchToFocused(event.type, event);
4284
- if (event.type === "pointerdown" || event.type === "pointermove" || event.type === "pointerup" || event.type === "click" || event.type === "dblclick" || event.type === "contextmenu" || event.type === "wheel") {
4285
- if (event.type === "pointerdown") {
4286
- const list = candidatesAt(event.cellX, event.cellY);
4287
- const target = pickTarget(list);
4288
- if (target === null || target === void 0 ? void 0 : target.focusable) setFocus(target.id);
4289
- capturedId = (target === null || target === void 0 ? void 0 : target.id) ?? null;
4290
- updateHover(target, event);
4291
- dispatchPointerEvent("pointerdown", event, target);
4292
- return false;
4293
- }
4294
- if (event.type === "pointermove" && capturedId) {
4295
- const target = nodes.get(capturedId) ?? null;
4296
- if (!target) return false;
4297
- updateHover(target, event);
4298
- const path = ancestorsForTarget(target);
4299
- const ev = buildPointerEvent("pointermove", path, event);
4300
- dispatchWithPhases("pointermove", path, target, ev);
4301
- return ev.defaultPrevented;
4302
- }
4303
- if (event.type === "pointermove") {
4304
- const list = candidatesAt(event.cellX, event.cellY);
4305
- const target = pickTarget(list);
4306
- updateHover(target, event);
4307
- dispatchPointerEvent("pointermove", event, target);
4308
- return false;
4656
+ latency === null || latency === void 0 || latency.recordEventDispatchStart(event);
4657
+ let prevented = false;
4658
+ try {
4659
+ if (event.type === "keydown" || event.type === "keyup") {
4660
+ prevented = dispatchToFocused(event.type, event);
4661
+ return prevented;
4309
4662
  }
4310
- if (event.type === "pointerup" && capturedId) {
4311
- const target = nodes.get(capturedId) ?? null;
4312
- const path = target ? ancestorsForTarget(target) : [];
4313
- const ev = buildPointerEvent("pointerup", path, event);
4314
- dispatchWithPhases("pointerup", path, target, ev);
4315
- capturedId = null;
4316
- return ev.defaultPrevented;
4663
+ if (event.type === "pointerdown" || event.type === "pointermove" || event.type === "pointerup" || event.type === "click" || event.type === "dblclick" || event.type === "contextmenu" || event.type === "wheel") {
4664
+ if (event.type === "pointerdown") {
4665
+ const list = candidatesAt(event.cellX, event.cellY);
4666
+ const target = pickTarget(list);
4667
+ if (target === null || target === void 0 ? void 0 : target.focusable) setFocus(target.id);
4668
+ capturedId = (target === null || target === void 0 ? void 0 : target.id) ?? null;
4669
+ updateHover(target, event);
4670
+ dispatchPointerEvent("pointerdown", event, target);
4671
+ return prevented;
4672
+ }
4673
+ if (event.type === "pointermove" && capturedId) {
4674
+ const target = nodes.get(capturedId) ?? null;
4675
+ if (!target) return prevented;
4676
+ updateHover(target, event);
4677
+ const path = ancestorsForTarget(target);
4678
+ const ev = buildPointerEvent("pointermove", path, event);
4679
+ dispatchWithPhases("pointermove", path, target, ev);
4680
+ prevented = ev.defaultPrevented;
4681
+ return prevented;
4682
+ }
4683
+ if (event.type === "pointermove") {
4684
+ const list = candidatesAt(event.cellX, event.cellY);
4685
+ const target = pickTarget(list);
4686
+ updateHover(target, event);
4687
+ dispatchPointerEvent("pointermove", event, target);
4688
+ return prevented;
4689
+ }
4690
+ if (event.type === "pointerup" && capturedId) {
4691
+ const target = nodes.get(capturedId) ?? null;
4692
+ const path = target ? ancestorsForTarget(target) : [];
4693
+ const ev = buildPointerEvent("pointerup", path, event);
4694
+ dispatchWithPhases("pointerup", path, target, ev);
4695
+ capturedId = null;
4696
+ prevented = ev.defaultPrevented;
4697
+ return prevented;
4698
+ }
4699
+ if (event.type === "pointerup") {
4700
+ dispatchPointerEvent("pointerup", event);
4701
+ capturedId = null;
4702
+ return prevented;
4703
+ }
4704
+ dispatchPointerEvent(event.type, event);
4705
+ return prevented;
4317
4706
  }
4318
- if (event.type === "pointerup") {
4319
- dispatchPointerEvent("pointerup", event);
4320
- capturedId = null;
4321
- return false;
4707
+ if (event.type === "beforeinput" || event.type === "input" || event.type === "compositionstart" || event.type === "compositionupdate" || event.type === "compositionend" || event.type === "paste") {
4708
+ prevented = dispatchToFocusedText(event.type, event);
4709
+ return prevented;
4322
4710
  }
4323
- dispatchPointerEvent(event.type, event);
4324
- return false;
4711
+ return prevented;
4712
+ } finally {
4713
+ latency === null || latency === void 0 || latency.recordEventDispatchEnd(event, { defaultPrevented: prevented });
4325
4714
  }
4326
- if (event.type === "beforeinput" || event.type === "input" || event.type === "compositionstart" || event.type === "compositionupdate" || event.type === "compositionend" || event.type === "paste") return dispatchToFocusedText(event.type, event);
4327
- return false;
4328
4715
  },
4329
4716
  debugNodes() {
4330
4717
  return Array.from(nodes.values()).map((n) => ({
@@ -5439,8 +5826,8 @@ function createTuiProfiler(name) {
5439
5826
  const invalidatePlaneCounts = new Map();
5440
5827
  const renderPlaneCounts = new Map();
5441
5828
  const logEveryMs = Number((env === null || env === void 0 ? void 0 : env.DIMCODE_PROFILE_TUI_LOG_EVERY_MS) ?? 1e3);
5442
- const now$2 = defaultNow;
5443
- let lastLogAt = now$2();
5829
+ const now$3 = defaultNow;
5830
+ let lastLogAt = now$3();
5444
5831
  function incrementPlaneCount(target, key) {
5445
5832
  const normalized = String(key ?? "all").trim() || "all";
5446
5833
  target.set(normalized, (target.get(normalized) ?? 0) + 1);
@@ -5453,7 +5840,7 @@ function createTuiProfiler(name) {
5453
5840
  if (dest === "stdout" || dest === "both") console.log(line);
5454
5841
  }
5455
5842
  function flushLog() {
5456
- const at = now$2();
5843
+ const at = now$3();
5457
5844
  const elapsed = at - lastLogAt;
5458
5845
  if (elapsed <= 0) return;
5459
5846
  lastLogAt = at;
@@ -5524,7 +5911,7 @@ function createTuiProfiler(name) {
5524
5911
  const timer = setInterval(flushLog, Number.isFinite(logEveryMs) ? Math.max(100, logEveryMs) : 1e3);
5525
5912
  (_unref = timer.unref) === null || _unref === void 0 || _unref.call(timer);
5526
5913
  return {
5527
- now: now$2,
5914
+ now: now$3,
5528
5915
  recordInvalidate(info) {
5529
5916
  invalidates++;
5530
5917
  incrementPlaneCount(invalidatePlaneCounts, (info === null || info === void 0 ? void 0 : info.plane) ?? "all");
@@ -6644,6 +7031,7 @@ function createTerminalApp(options) {
6644
7031
  rows: options.rows
6645
7032
  });
6646
7033
  const trace = createTraceStore({ enabled: Boolean(globalThis.__VT_DEBUG_TRACE__) });
7034
+ const latency = getCliLatencyProfiler();
6647
7035
  const profiler = createTuiProfiler("cli-scheduler");
6648
7036
  const events = createCliEventManager({
6649
7037
  record: (event) => {
@@ -6665,7 +7053,12 @@ function createTerminalApp(options) {
6665
7053
  }
6666
7054
  });
6667
7055
  const render = createRenderManager(terminal);
6668
- const offCommit = terminal.on("commit", ({ dirtyRows, planes }) => {
7056
+ const offCommit = terminal.on("commit", ({ dirtyRows, planes, sync }) => {
7057
+ latency === null || latency === void 0 || latency.recordCommit({
7058
+ dirtyRows,
7059
+ planes,
7060
+ sync
7061
+ });
6669
7062
  if (!trace.enabled.value) return;
6670
7063
  trace.push({
6671
7064
  type: "commit",
@@ -6686,7 +7079,6 @@ function createTerminalApp(options) {
6686
7079
  let pendingInvalidateAllPlanes = false;
6687
7080
  const pendingInvalidatePlanes = new Set();
6688
7081
  const env = (process$1 === null || process$1 === void 0 ? void 0 : process$1.env) ?? {};
6689
- const isGhostty = "GHOSTTY_RESOURCES_DIR" in env;
6690
7082
  const throttleMs = (() => {
6691
7083
  const raw = env.DIMCODE_TUI_THROTTLE_MS;
6692
7084
  if (!raw) return 0;
@@ -6696,7 +7088,7 @@ function createTerminalApp(options) {
6696
7088
  const frameThrottleMs = (() => {
6697
7089
  var _process$stdout;
6698
7090
  if (!(process$1 === null || process$1 === void 0 || (_process$stdout = process$1.stdout) === null || _process$stdout === void 0 ? void 0 : _process$stdout.isTTY)) return 0;
6699
- return isGhostty ? 24 : 16;
7091
+ return 16;
6700
7092
  })();
6701
7093
  function queueInvalidatePlane(plane) {
6702
7094
  if (!plane) {
@@ -6723,14 +7115,22 @@ function createTerminalApp(options) {
6723
7115
  scheduled = false;
6724
7116
  flushing = true;
6725
7117
  const activePlanes = takeActivePlanes();
6726
- render.render({ activePlanes });
6727
- terminal.commit({
6728
- planes: activePlanes,
6729
- sync
7118
+ latency === null || latency === void 0 || latency.recordFlushStart({
7119
+ sync,
7120
+ activePlanes
6730
7121
  });
6731
- flushing = false;
6732
- lastFlushAtMs = Date.now();
6733
- scheduledAtMs = 0;
7122
+ try {
7123
+ render.render({ activePlanes });
7124
+ terminal.commit({
7125
+ planes: activePlanes,
7126
+ sync
7127
+ });
7128
+ } finally {
7129
+ latency === null || latency === void 0 || latency.recordFlushEnd();
7130
+ flushing = false;
7131
+ lastFlushAtMs = Date.now();
7132
+ scheduledAtMs = 0;
7133
+ }
6734
7134
  if (pendingInvalidateAfterFlush) {
6735
7135
  pendingInvalidateAfterFlush = false;
6736
7136
  flush(true);
@@ -6774,12 +7174,16 @@ function createTerminalApp(options) {
6774
7174
  }
6775
7175
  function invalidate(options$1) {
6776
7176
  if (disposed) return;
7177
+ const priority = (options$1 === null || options$1 === void 0 ? void 0 : options$1.priority) ?? "normal";
7178
+ latency === null || latency === void 0 || latency.recordSchedulerInvalidate({
7179
+ priority,
7180
+ plane: (options$1 === null || options$1 === void 0 ? void 0 : options$1.plane) ?? null
7181
+ });
6777
7182
  if (flushing) {
6778
7183
  queueInvalidatePlane(options$1 === null || options$1 === void 0 ? void 0 : options$1.plane);
6779
7184
  pendingInvalidateAfterFlush = true;
6780
7185
  return;
6781
7186
  }
6782
- const priority = (options$1 === null || options$1 === void 0 ? void 0 : options$1.priority) ?? "normal";
6783
7187
  queueInvalidatePlane(options$1 === null || options$1 === void 0 ? void 0 : options$1.plane);
6784
7188
  profiler === null || profiler === void 0 || profiler.recordInvalidate({ plane: (options$1 === null || options$1 === void 0 ? void 0 : options$1.plane) ?? null });
6785
7189
  if (priority === "high") {
@@ -7016,6 +7420,7 @@ function createStdoutRenderer(terminal, options) {
7016
7420
  let palette = options === null || options === void 0 ? void 0 : options.palette;
7017
7421
  const trackResize = (options === null || options === void 0 ? void 0 : options.trackResize) ?? true;
7018
7422
  const getImeAnchor = options === null || options === void 0 ? void 0 : options.getImeAnchor;
7423
+ const cliLatency = getCliLatencyProfiler();
7019
7424
  const profiler = createTuiProfiler("stdout-renderer");
7020
7425
  function resolveUseSyncOutput() {
7021
7426
  if ((options === null || options === void 0 ? void 0 : options.useSyncOutput) != null) return options.useSyncOutput;
@@ -7025,13 +7430,13 @@ function createStdoutRenderer(terminal, options) {
7025
7430
  const v = String(envValue).trim().toLowerCase();
7026
7431
  return v === "1" || v === "true" || v === "yes";
7027
7432
  }
7028
- const term = String(env$1.TERM ?? "").toLowerCase();
7029
- const termProgram = String(env$1.TERM_PROGRAM ?? "").toLowerCase();
7433
+ const term$1 = String(env$1.TERM ?? "").toLowerCase();
7434
+ const termProgram$1 = String(env$1.TERM_PROGRAM ?? "").toLowerCase();
7030
7435
  const termProgramVersion = env$1.TERM_PROGRAM_VERSION;
7031
7436
  const isGhostty$1 = "GHOSTTY_RESOURCES_DIR" in env$1;
7032
- const isProblematicTerminal = isGhostty$1 || termProgram.includes("apple_terminal") || term.includes("screen") && !term.includes("tmux");
7437
+ const isProblematicTerminal = isGhostty$1 || termProgram$1.includes("apple_terminal") || term$1.includes("screen") && !term$1.includes("tmux");
7033
7438
  if (isProblematicTerminal) return false;
7034
- const isGoodTerminal = termProgram.includes("iterm") && termProgramVersion && compareVersion(String(termProgramVersion), "3.5.0") >= 0;
7439
+ const isGoodTerminal = termProgram$1.includes("iterm") && termProgramVersion && compareVersion(String(termProgramVersion), "3.5.0") >= 0;
7035
7440
  if (isGoodTerminal) return true;
7036
7441
  return false;
7037
7442
  }
@@ -7068,7 +7473,10 @@ function createStdoutRenderer(terminal, options) {
7068
7473
  return .6;
7069
7474
  })();
7070
7475
  const disableCursorPos = isGhostty && (process$1 === null || process$1 === void 0 || (_ref3 = process$1.env) === null || _ref3 === void 0 ? void 0 : _ref3.DIMCODE_DISABLE_CURSOR_POS) === "1";
7071
- const isVscodeTerminal = String(env.TERM_PROGRAM ?? "").trim().toLowerCase() === "vscode" || "VSCODE_PID" in env || "VSCODE_IPC_HOOK_CLI" in env;
7476
+ const termProgram = String(env.TERM_PROGRAM ?? "").trim().toLowerCase();
7477
+ const term = String(env.TERM ?? "").trim().toLowerCase();
7478
+ const isVscodeTerminal = termProgram === "vscode" || "VSCODE_PID" in env || "VSCODE_IPC_HOOK_CLI" in env;
7479
+ const useConservativeDirtyRowRendering = out.isTTY !== false && !isVscodeTerminal && (isGhostty || "KITTY_WINDOW_ID" in env || "ALACRITTY_WINDOW_ID" in env || "ALACRITTY_LOG" in env || "WEZTERM_PANE" in env || "WEZTERM_EXECUTABLE" in env || termProgram.includes("kitty") || termProgram.includes("alacritty") || termProgram.includes("wezterm") || term.includes("kitty") || term.includes("alacritty"));
7072
7480
  const enableOsc8Links = (() => {
7073
7481
  if (!out.isTTY) return false;
7074
7482
  const raw = String(env.DIMCODE_TUI_LINKS ?? "").trim().toLowerCase();
@@ -7089,7 +7497,7 @@ function createStdoutRenderer(terminal, options) {
7089
7497
  let accumulatedDirtyMax = -1;
7090
7498
  let accumulatedScrollOperations = null;
7091
7499
  let accumulatedSkipUnchangedDirtyRows = true;
7092
- const MIN_FRAME_MS = !out.isTTY ? 0 : isGhostty ? 24 : 16;
7500
+ const MIN_FRAME_MS = !out.isTTY ? 0 : 16;
7093
7501
  function clampCellToViewport(cell, size) {
7094
7502
  const maxX = Math.max(0, Math.floor(size.cols) - 1);
7095
7503
  const maxY = Math.max(0, Math.floor(size.rows) - 1);
@@ -7558,6 +7966,7 @@ function createStdoutRenderer(terminal, options) {
7558
7966
  function doRender(dirtyRows, scrollOperations, skipUnchangedDirtyRows = false) {
7559
7967
  if (isDebugEnabled()) getDebugLog().render(`doRender() START: dirtyRows=${(dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) ?? "null"}`);
7560
7968
  if (disposed) return;
7969
+ cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutRenderStart();
7561
7970
  pendingRender = false;
7562
7971
  accumulatedAllRows = false;
7563
7972
  accumulatedDirtyBits = null;
@@ -7628,6 +8037,7 @@ function createStdoutRenderer(terminal, options) {
7628
8037
  if (!sorted) outRows.sort((a, b) => a - b);
7629
8038
  return outRows;
7630
8039
  })();
8040
+ if (fpPrevValid && rowsToRender) currentFP.set(prevFP);
7631
8041
  const frameParts = [];
7632
8042
  frameParts.push(!isGhostty && useSyncOutput ? SYNC_START : "");
7633
8043
  frameParts.push("\x1B[?7l");
@@ -7735,6 +8145,10 @@ function createStdoutRenderer(terminal, options) {
7735
8145
  const overlayRowSet = overlayRows.length ? new Set(overlayRows) : null;
7736
8146
  const overlayPartialRows = Array.from(new Set([...overlayCoverage.partialRows, ...prevOverlayPartialRows])).sort((a, b) => a - b);
7737
8147
  const overlayPartialRowSet = overlayPartialRows.length ? new Set(overlayPartialRows) : null;
8148
+ const overlayTouchedRowSet = (() => {
8149
+ if (!overlayRowSet && !overlayPartialRowSet) return null;
8150
+ return new Set([...overlayRowSet ? Array.from(overlayRowSet) : [], ...overlayPartialRowSet ? Array.from(overlayPartialRowSet) : []]);
8151
+ })();
7738
8152
  let explicitScrollOperations = normalizedScrollOperations;
7739
8153
  let hiddenExplicitDirtyRows = null;
7740
8154
  let allowInferredScrollRegions = true;
@@ -7818,12 +8232,12 @@ function createStdoutRenderer(terminal, options) {
7818
8232
  frameParts.push("\x1B[r");
7819
8233
  }
7820
8234
  const explicitDirtyRows = Array.from(explicitRowsToRender).sort((a, b) => a - b);
7821
- const overlayDirtyRows = overlayRowSet ? explicitDirtyRows.filter((y) => overlayRowSet.has(y)) : [];
8235
+ const overlayDirtyRows = overlayTouchedRowSet ? explicitDirtyRows.filter((y) => overlayTouchedRowSet.has(y)) : [];
7822
8236
  const paintedExplicitRows = [];
7823
8237
  for (const y of explicitDirtyRows) {
7824
8238
  const row = terminal.getRow(y);
7825
- const overlayRow = overlayRowSet === null || overlayRowSet === void 0 ? void 0 : overlayRowSet.has(y);
7826
- if (overlayRow) {
8239
+ const overlayRow = overlayTouchedRowSet === null || overlayTouchedRowSet === void 0 ? void 0 : overlayTouchedRowSet.has(y);
8240
+ if (overlayRow || useConservativeDirtyRowRendering) {
7827
8241
  fingerprintRow(row, y, size.cols);
7828
8242
  renderRow$1(y, row);
7829
8243
  paintedExplicitRows.push(y);
@@ -7898,10 +8312,10 @@ function createStdoutRenderer(terminal, options) {
7898
8312
  const extraDirtyRows = overlayRowSet ? shift.extraDirtyRows.filter((y) => !overlayRowSet.has(y) || Boolean(overlayPartialRowSet === null || overlayPartialRowSet === void 0 ? void 0 : overlayPartialRowSet.has(y))) : shift.extraDirtyRows;
7899
8313
  for (const y of extraDirtyRows) {
7900
8314
  const row = terminal.getRow(y);
7901
- const overlayRow = overlayRowSet === null || overlayRowSet === void 0 ? void 0 : overlayRowSet.has(y);
7902
- if (overlayRow) {
7903
- renderRow$1(y, row);
8315
+ const overlayRow = overlayTouchedRowSet === null || overlayTouchedRowSet === void 0 ? void 0 : overlayTouchedRowSet.has(y);
8316
+ if (overlayRow || useConservativeDirtyRowRendering) {
7904
8317
  fingerprintRow(row, y, size.cols);
8318
+ renderRow$1(y, row);
7905
8319
  continue;
7906
8320
  }
7907
8321
  const span = resolveChangedSpanAgainstReference(row, y, size.cols);
@@ -7937,13 +8351,13 @@ function createStdoutRenderer(terminal, options) {
7937
8351
  renderRow$1(y, row);
7938
8352
  }
7939
8353
  } else {
7940
- const overlayDirtyRows = overlayRowSet ? rowsToRender.filter((y) => overlayRowSet.has(y)) : [];
8354
+ const overlayDirtyRows = overlayTouchedRowSet ? rowsToRender.filter((y) => overlayTouchedRowSet.has(y)) : [];
7941
8355
  if (isDebugEnabled()) getDebugLog().render(` Partial render: ${rowsToRender.length} dirty rows: [${rowsToRender.join(", ")}]${overlayDirtyRows.length ? ` (overlay-full-row: [${overlayDirtyRows.join(", ")}])` : ""}`);
7942
8356
  for (const y of rowsToRender) {
7943
8357
  const row = terminal.getRow(y);
7944
8358
  fingerprintRow(row, y, size.cols);
7945
- const overlayRow = overlayRowSet === null || overlayRowSet === void 0 ? void 0 : overlayRowSet.has(y);
7946
- if (overlayRow) {
8359
+ const overlayRow = overlayTouchedRowSet === null || overlayTouchedRowSet === void 0 ? void 0 : overlayTouchedRowSet.has(y);
8360
+ if (overlayRow || useConservativeDirtyRowRendering) {
7947
8361
  renderRow$1(y, row);
7948
8362
  continue;
7949
8363
  }
@@ -7991,6 +8405,7 @@ function createStdoutRenderer(terminal, options) {
7991
8405
  }
7992
8406
  if (!hasFrameOutput) {
7993
8407
  if (isDebugEnabled()) getDebugLog().render(" No-op frame skipped");
8408
+ cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutNoOutput();
7994
8409
  return;
7995
8410
  }
7996
8411
  if (enableOsc8Links && activeStyle.href) frameParts.push(OSC8_CLOSE);
@@ -8119,6 +8534,11 @@ function createStdoutRenderer(terminal, options) {
8119
8534
  bytes: frame.length,
8120
8535
  mode: writeMode === "sync" ? "sync" : writeMode === "chunked" ? "chunked" : "stream"
8121
8536
  });
8537
+ cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutWrite({
8538
+ durationMs: writeMs,
8539
+ bytes: frame.length,
8540
+ mode: writeMode === "sync" ? "sync" : writeMode === "chunked" ? "chunked" : "stream"
8541
+ });
8122
8542
  }
8123
8543
  if (isDebugEnabled()) {
8124
8544
  const totalTime = (performance.now() - renderStart).toFixed(2);
@@ -8219,9 +8639,13 @@ function createStdoutRenderer(terminal, options) {
8219
8639
  mergeScrollOperations(scrollOperations);
8220
8640
  accumulatedSkipUnchangedDirtyRows && (accumulatedSkipUnchangedDirtyRows = skipUnchangedDirtyRows);
8221
8641
  }
8222
- if (pendingRender && !sync) return;
8223
- const now$2 = Date.now();
8224
- const elapsed = now$2 - lastFrameTime;
8642
+ const now$3 = Date.now();
8643
+ const elapsed = now$3 - lastFrameTime;
8644
+ const queuedDelayMs = Math.max(0, MIN_FRAME_MS - elapsed);
8645
+ if (pendingRender && !sync) {
8646
+ cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutQueued(queuedDelayMs);
8647
+ return;
8648
+ }
8225
8649
  if (sync) {
8226
8650
  if (pendingRender) {
8227
8651
  pendingRender = false;
@@ -8232,12 +8656,14 @@ function createStdoutRenderer(terminal, options) {
8232
8656
  }
8233
8657
  const rows = buildAccumulatedRows();
8234
8658
  const pendingScrolls = buildAccumulatedScrollOperations();
8659
+ cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutQueued(0);
8235
8660
  doRender(rows, pendingScrolls, accumulatedSkipUnchangedDirtyRows);
8236
8661
  return;
8237
8662
  }
8238
8663
  if (elapsed >= MIN_FRAME_MS) {
8239
8664
  const rows = buildAccumulatedRows();
8240
8665
  const pendingScrolls = buildAccumulatedScrollOperations();
8666
+ cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutQueued(0);
8241
8667
  doRender(rows, pendingScrolls, accumulatedSkipUnchangedDirtyRows);
8242
8668
  } else {
8243
8669
  pendingRender = true;
@@ -8249,7 +8675,8 @@ function createStdoutRenderer(terminal, options) {
8249
8675
  const pendingScrolls = buildAccumulatedScrollOperations();
8250
8676
  doRender(rows, pendingScrolls, accumulatedSkipUnchangedDirtyRows);
8251
8677
  }
8252
- }, MIN_FRAME_MS - elapsed);
8678
+ }, queuedDelayMs);
8679
+ cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutQueued(queuedDelayMs);
8253
8680
  }
8254
8681
  }
8255
8682
  terminal.setFingerprintFn((ch, style) => {
@@ -8526,12 +8953,22 @@ const rowCache = new WeakMap();
8526
8953
  function segmentsToKey(segments) {
8527
8954
  return segments.map((s) => `${s.key}:${s.text}:${s.cols}:${s.wide}`).join("|");
8528
8955
  }
8956
+ function isPlainStyle(style) {
8957
+ return !style.fg && !style.bg && !style.bold && !style.dim && !style.italic && !style.underline && !style.inverse && !style.href;
8958
+ }
8959
+ function isTransparentBlankRow(segments) {
8960
+ return segments.length === 1 && isPlainStyle(segments[0].style) && segments[0].text.trim().length === 0;
8961
+ }
8529
8962
  function renderRow(terminal, metrics$1, wideScaleX, y, lineEl) {
8530
8963
  const segments = computeRowSegments(terminal, y);
8531
8964
  const newKey = segmentsToKey(segments);
8532
8965
  const cachedKey = rowCache.get(lineEl);
8533
8966
  if (cachedKey === newKey) return;
8534
8967
  rowCache.set(lineEl, newKey);
8968
+ if (isTransparentBlankRow(segments)) {
8969
+ lineEl.replaceChildren();
8970
+ return;
8971
+ }
8535
8972
  const fragment = document.createDocumentFragment();
8536
8973
  for (const seg of segments) {
8537
8974
  const span = document.createElement("span");
@@ -8552,6 +8989,7 @@ function createDomRenderer(terminal, container) {
8552
8989
  container.style.whiteSpace = "pre";
8553
8990
  container.style.display = "inline-block";
8554
8991
  container.style.overflow = "hidden";
8992
+ container.style.position = "relative";
8555
8993
  container.style.userSelect = "text";
8556
8994
  container.style.outline = "none";
8557
8995
  container.style.contain = "layout style";
@@ -8559,21 +8997,93 @@ function createDomRenderer(terminal, container) {
8559
8997
  installAnsiPaletteCssVars(container);
8560
8998
  let metrics$1 = measureCell(container);
8561
8999
  let wideScaleX = 1;
8562
- let lineEls = [];
9000
+ const planeLayers = new Map();
8563
9001
  let raf = 0;
8564
- const pending = new Set();
9002
+ const pending = new Map();
8565
9003
  let disposed = false;
9004
+ function applyPlaneOffset(plane, offsetPx) {
9005
+ const layer = planeLayers.get(plane);
9006
+ if (!layer) return;
9007
+ const next = Number.isFinite(offsetPx) ? offsetPx : 0;
9008
+ if (layer.offsetPx === next) return;
9009
+ layer.offsetPx = next;
9010
+ layer.contentEl.style.transform = next ? `translateY(${next}px)` : "translateY(0px)";
9011
+ }
9012
+ function applyPlaneViewport(plane, viewport) {
9013
+ const layer = planeLayers.get(plane);
9014
+ if (!layer) return;
9015
+ const totalHeight = terminal.size().rows * metrics$1.cellHeight;
9016
+ if (!viewport) {
9017
+ layer.viewportTopPx = 0;
9018
+ layer.viewportHeightPx = null;
9019
+ layer.el.style.clipPath = "none";
9020
+ return;
9021
+ }
9022
+ const topPx = Math.max(0, Math.min(totalHeight, Math.floor(viewport.topPx)));
9023
+ const heightPx = Math.max(0, Math.min(totalHeight - topPx, Math.floor(viewport.heightPx)));
9024
+ layer.viewportTopPx = topPx;
9025
+ layer.viewportHeightPx = heightPx;
9026
+ if (topPx === 0 && heightPx >= totalHeight) {
9027
+ layer.el.style.clipPath = "none";
9028
+ return;
9029
+ }
9030
+ const bottomPx = Math.max(0, totalHeight - topPx - heightPx);
9031
+ layer.el.style.clipPath = `inset(${topPx}px 0px ${bottomPx}px 0px)`;
9032
+ }
8566
9033
  function rebuildLines() {
8567
9034
  const { rows, cols } = terminal.size();
8568
9035
  container.style.width = `${cols * metrics$1.cellWidth}px`;
8569
9036
  container.style.height = `${rows * metrics$1.cellHeight}px`;
8570
9037
  const fragment = document.createDocumentFragment();
8571
- lineEls = Array.from({ length: rows }, () => {
8572
- const line = document.createElement("div");
8573
- line.style.cssText = `height:${metrics$1.cellHeight}px;width:${cols * metrics$1.cellWidth}px;overflow:hidden;contain:layout style`;
8574
- fragment.appendChild(line);
8575
- return line;
8576
- });
9038
+ for (let i = 0; i < TERMINAL_RENDER_PLANES.length; i++) {
9039
+ const plane = TERMINAL_RENDER_PLANES[i];
9040
+ const planeTerminal = getPlaneTerminal(terminal, plane);
9041
+ let layer = planeLayers.get(plane);
9042
+ if (!layer) {
9043
+ const el = document.createElement("div");
9044
+ const contentEl = document.createElement("div");
9045
+ el.dataset.vtPlane = plane;
9046
+ el.style.pointerEvents = "none";
9047
+ contentEl.style.position = "absolute";
9048
+ contentEl.style.left = "0";
9049
+ contentEl.style.top = "0";
9050
+ layer = {
9051
+ el,
9052
+ contentEl,
9053
+ lines: [],
9054
+ offsetPx: 0,
9055
+ terminal: planeTerminal,
9056
+ viewportTopPx: 0,
9057
+ viewportHeightPx: null
9058
+ };
9059
+ planeLayers.set(plane, layer);
9060
+ }
9061
+ layer.terminal = planeTerminal;
9062
+ layer.el.style.position = "absolute";
9063
+ layer.el.style.left = "0";
9064
+ layer.el.style.top = "0";
9065
+ layer.el.style.width = `${cols * metrics$1.cellWidth}px`;
9066
+ layer.el.style.height = `${rows * metrics$1.cellHeight}px`;
9067
+ layer.el.style.overflow = "hidden";
9068
+ layer.el.style.zIndex = String(i);
9069
+ layer.contentEl.style.width = `${cols * metrics$1.cellWidth}px`;
9070
+ layer.contentEl.style.height = `${rows * metrics$1.cellHeight}px`;
9071
+ applyPlaneOffset(plane, layer.offsetPx);
9072
+ applyPlaneViewport(plane, layer.viewportHeightPx == null ? null : {
9073
+ topPx: layer.viewportTopPx,
9074
+ heightPx: layer.viewportHeightPx
9075
+ });
9076
+ const lineFragment = document.createDocumentFragment();
9077
+ layer.lines = Array.from({ length: rows }, () => {
9078
+ const line = document.createElement("div");
9079
+ line.style.cssText = `height:${metrics$1.cellHeight}px;width:${cols * metrics$1.cellWidth}px;overflow:hidden;contain:layout style`;
9080
+ lineFragment.appendChild(line);
9081
+ return line;
9082
+ });
9083
+ layer.contentEl.replaceChildren(lineFragment);
9084
+ layer.el.replaceChildren(layer.contentEl);
9085
+ fragment.appendChild(layer.el);
9086
+ }
8577
9087
  container.replaceChildren(fragment);
8578
9088
  }
8579
9089
  function refresh() {
@@ -8582,22 +9092,46 @@ function createDomRenderer(terminal, container) {
8582
9092
  wideScaleX = wideW > 0 ? Math.max(1, Math.min(2, metrics$1.cellWidth * 2 / wideW)) : 1;
8583
9093
  rebuildLines();
8584
9094
  const size = terminal.size();
8585
- for (let y = 0; y < size.rows; y++) renderRow(terminal, metrics$1, wideScaleX, y, lineEls[y]);
9095
+ for (const plane of TERMINAL_RENDER_PLANES) {
9096
+ const layer = planeLayers.get(plane);
9097
+ if (!layer) continue;
9098
+ for (let y = 0; y < size.rows; y++) renderRow(layer.terminal, metrics$1, wideScaleX, y, layer.lines[y]);
9099
+ }
8586
9100
  }
8587
9101
  function flushPending() {
8588
9102
  raf = 0;
8589
9103
  if (disposed) return;
8590
- for (const y of pending) {
8591
- const line = lineEls[y];
8592
- if (line) renderRow(terminal, metrics$1, wideScaleX, y, line);
9104
+ for (const plane of TERMINAL_RENDER_PLANES) {
9105
+ const layer = planeLayers.get(plane);
9106
+ const rows = pending.get(plane);
9107
+ if (!layer || !(rows === null || rows === void 0 ? void 0 : rows.size)) continue;
9108
+ for (const y of rows) {
9109
+ const line = layer.lines[y];
9110
+ if (line) renderRow(layer.terminal, metrics$1, wideScaleX, y, line);
9111
+ }
9112
+ rows.clear();
8593
9113
  }
8594
- pending.clear();
8595
9114
  }
8596
- const offCommit = terminal.on("commit", ({ dirtyRows }) => {
9115
+ const offCommit = terminal.on("commit", ({ dirtyRows, planes }) => {
9116
+ const activePlanes = (planes === null || planes === void 0 ? void 0 : planes.length) ? planes : TERMINAL_RENDER_PLANES;
8597
9117
  if (dirtyRows === null) {
8598
9118
  const size = terminal.size();
8599
- for (let y = 0; y < size.rows; y++) pending.add(y);
8600
- } else for (const y of dirtyRows) pending.add(y);
9119
+ for (const plane of activePlanes) {
9120
+ let rows = pending.get(plane);
9121
+ if (!rows) {
9122
+ rows = new Set();
9123
+ pending.set(plane, rows);
9124
+ }
9125
+ for (let y = 0; y < size.rows; y++) rows.add(y);
9126
+ }
9127
+ } else for (const plane of activePlanes) {
9128
+ let rows = pending.get(plane);
9129
+ if (!rows) {
9130
+ rows = new Set();
9131
+ pending.set(plane, rows);
9132
+ }
9133
+ for (const y of dirtyRows) rows.add(y);
9134
+ }
8601
9135
  if (!raf) {
8602
9136
  raf = -1;
8603
9137
  const id = requestAnimationFrame(() => {
@@ -8623,7 +9157,14 @@ function createDomRenderer(terminal, container) {
8623
9157
  offResize();
8624
9158
  if (raf > 0) cancelAnimationFrame(raf);
8625
9159
  pending.clear();
9160
+ planeLayers.clear();
8626
9161
  container.replaceChildren();
9162
+ },
9163
+ setPlaneOffset(plane, offsetPx) {
9164
+ applyPlaneOffset(plane, offsetPx);
9165
+ },
9166
+ setPlaneViewport(plane, viewport) {
9167
+ applyPlaneViewport(plane, viewport);
8627
9168
  }
8628
9169
  };
8629
9170
  }
@@ -10032,6 +10573,7 @@ function mentionIndexAt$1(value, mentionToken, index) {
10032
10573
  return countMentionTokens$1(value, mentionToken, index);
10033
10574
  }
10034
10575
  function createPromptMentionPlugin(options = {}) {
10576
+ const latency = getCliLatencyProfiler();
10035
10577
  return {
10036
10578
  name: "promptMention",
10037
10579
  install: (ctx) => {
@@ -10177,6 +10719,12 @@ function createPromptMentionPlugin(options = {}) {
10177
10719
  query: ctx0.query
10178
10720
  });
10179
10721
  if (handled !== false) {
10722
+ const value = ctx.getValue();
10723
+ const before$1 = value.slice(0, ctx0.tokenStart);
10724
+ const after$1 = value.slice(ctx0.tokenEnd);
10725
+ const nextValue$1 = `${before$1}${after$1}`;
10726
+ ctx.pushUndoSnapshot(nextValue$1);
10727
+ ctx.applyEdit(nextValue$1, ctx0.tokenStart);
10180
10728
  promptMention.promptSuppressedKey.value = ctx0.key;
10181
10729
  ctx.scheduler.invalidate();
10182
10730
  return;
@@ -10213,8 +10761,17 @@ function createPromptMentionPlugin(options = {}) {
10213
10761
  }
10214
10762
  function handlePromptKeydown(e) {
10215
10763
  if (!promptMention.promptVisible.value) return false;
10764
+ const markPromptOperation = (suffix) => {
10765
+ const ctx0 = promptMention.activeContext.value;
10766
+ const mentionTrigger = getProps().mentionTrigger || "@";
10767
+ const skillTrigger = getProps().skillTrigger || "";
10768
+ const tokenText = String((ctx0 === null || ctx0 === void 0 ? void 0 : ctx0.tokenText) ?? "");
10769
+ const scope = tokenText.startsWith(mentionTrigger) ? "prompt.mention" : skillTrigger && tokenText.startsWith(skillTrigger) ? "prompt.skill" : "prompt.command";
10770
+ latency === null || latency === void 0 || latency.markOperation(`${scope}.${suffix}`);
10771
+ };
10216
10772
  const len = promptMention.promptMatches.value.length;
10217
10773
  if (e.key === "ArrowDown") {
10774
+ markPromptOperation("navigate.next");
10218
10775
  e.preventDefault();
10219
10776
  if (len <= 0) promptMention.promptActive.value = 0;
10220
10777
  else if (promptMention.promptActive.value >= len - 1) promptMention.promptActive.value = 0;
@@ -10223,6 +10780,7 @@ function createPromptMentionPlugin(options = {}) {
10223
10780
  return true;
10224
10781
  }
10225
10782
  if (e.key === "ArrowUp") {
10783
+ markPromptOperation("navigate.prev");
10226
10784
  e.preventDefault();
10227
10785
  if (len <= 0) promptMention.promptActive.value = 0;
10228
10786
  else if (promptMention.promptActive.value <= 0) promptMention.promptActive.value = len - 1;
@@ -10244,11 +10802,13 @@ function createPromptMentionPlugin(options = {}) {
10244
10802
  const typed = String((ctx0 === null || ctx0 === void 0 ? void 0 : ctx0.tokenText) ?? "");
10245
10803
  const candidate = String((match === null || match === void 0 || (_match$item = match.item) === null || _match$item === void 0 ? void 0 : _match$item.value) ?? "");
10246
10804
  if (!typed || !candidate.startsWith(typed)) return false;
10805
+ markPromptOperation("accept");
10247
10806
  e.preventDefault();
10248
10807
  acceptPrompt(promptMention.promptActive.value);
10249
10808
  return true;
10250
10809
  }
10251
10810
  if (e.key === "Tab" && (isMention || isSkill)) {
10811
+ markPromptOperation("accept");
10252
10812
  e.preventDefault();
10253
10813
  if (len === 0) return true;
10254
10814
  const list = promptMention.promptMatches.value;
@@ -10258,12 +10818,14 @@ function createPromptMentionPlugin(options = {}) {
10258
10818
  return true;
10259
10819
  }
10260
10820
  if (len === 0) return false;
10821
+ markPromptOperation("accept");
10261
10822
  e.preventDefault();
10262
10823
  acceptPrompt(promptMention.promptActive.value);
10263
10824
  return true;
10264
10825
  }
10265
10826
  if (e.key === "Escape") {
10266
10827
  var _promptMention$active;
10828
+ markPromptOperation("dismiss");
10267
10829
  e.preventDefault();
10268
10830
  promptMention.promptSuppressedKey.value = ((_promptMention$active = promptMention.activeContext.value) === null || _promptMention$active === void 0 ? void 0 : _promptMention$active.key) ?? null;
10269
10831
  ctx.scheduler.invalidate();
@@ -16015,8 +16577,8 @@ function normalizeDelta(deltaY, mode = "auto") {
16015
16577
  if (abs <= LINE_UNIT_THRESHOLD && Number.isInteger(deltaY)) return deltaY;
16016
16578
  return deltaY / PIXELS_PER_LINE;
16017
16579
  }
16018
- function accelFactor(now$2, lastAt) {
16019
- const dt = now$2 - lastAt;
16580
+ function accelFactor(now$3, lastAt) {
16581
+ const dt = now$3 - lastAt;
16020
16582
  if (!Number.isFinite(dt) || dt <= 0 || dt > ACCEL_WINDOW_MS) return 1;
16021
16583
  const t = 1 - dt / ACCEL_WINDOW_MS;
16022
16584
  return 1 + t * (MAX_ACCEL - 1);
@@ -16026,15 +16588,17 @@ function createWheelScrollState() {
16026
16588
  accumulator: 0,
16027
16589
  lastAt: 0,
16028
16590
  lastEdgeDir: 0,
16029
- lastEdgeAt: 0
16591
+ lastEdgeAt: 0,
16592
+ lastLineUnitDir: 0
16030
16593
  };
16031
16594
  }
16032
- function applyWheelScroll(state, deltaY, scrollTop, maxTop, now$2 = Date.now(), deltaMode = "auto") {
16595
+ function applyWheelScroll(state, deltaY, scrollTop, maxTop, now$3 = Date.now(), deltaMode = "auto", options = {}) {
16033
16596
  if (!Number.isFinite(deltaY) || deltaY === 0 || maxTop <= 0) {
16034
16597
  if (maxTop <= 0) {
16035
16598
  state.accumulator = 0;
16036
16599
  state.lastEdgeDir = 0;
16037
16600
  state.lastEdgeAt = 0;
16601
+ state.lastLineUnitDir = 0;
16038
16602
  }
16039
16603
  return {
16040
16604
  nextTop: scrollTop,
@@ -16042,15 +16606,17 @@ function applyWheelScroll(state, deltaY, scrollTop, maxTop, now$2 = Date.now(),
16042
16606
  lines: 0
16043
16607
  };
16044
16608
  }
16045
- const dt = state.lastAt ? now$2 - state.lastAt : Infinity;
16609
+ const dt = state.lastAt ? now$3 - state.lastAt : Infinity;
16046
16610
  const lineUnits = isLineUnitDelta(deltaY, deltaMode);
16047
- if (lineUnits && dt !== Infinity && dt >= 0 && dt < MIN_TICK_INTERVAL_MS) return {
16611
+ const inputDir = Math.sign(normalizeDelta(deltaY, deltaMode));
16612
+ if (lineUnits && dt !== Infinity && dt >= 0 && dt < MIN_TICK_INTERVAL_MS && inputDir === state.lastLineUnitDir) return {
16048
16613
  nextTop: scrollTop,
16049
16614
  dir: 0,
16050
16615
  lines: 0
16051
16616
  };
16052
- const accel = lineUnits ? 1 : state.lastAt ? accelFactor(now$2, state.lastAt) : 1;
16053
- state.lastAt = now$2;
16617
+ state.lastLineUnitDir = lineUnits ? inputDir : 0;
16618
+ const accel = lineUnits ? 1 : options.disableAcceleration ? 1 : state.lastAt ? accelFactor(now$3, state.lastAt) : 1;
16619
+ state.lastAt = now$3;
16054
16620
  state.accumulator += normalizeDelta(deltaY, deltaMode) * accel;
16055
16621
  const lines = Math.trunc(state.accumulator);
16056
16622
  if (lines === 0) return {
@@ -16064,7 +16630,7 @@ function applyWheelScroll(state, deltaY, scrollTop, maxTop, now$2 = Date.now(),
16064
16630
  const atBottom = scrollTop >= maxTop;
16065
16631
  if (dir < 0 && atTop || dir > 0 && atBottom) {
16066
16632
  state.lastEdgeDir = dir;
16067
- state.lastEdgeAt = now$2;
16633
+ state.lastEdgeAt = now$3;
16068
16634
  state.accumulator = 0;
16069
16635
  return {
16070
16636
  nextTop: scrollTop,
@@ -16072,7 +16638,7 @@ function applyWheelScroll(state, deltaY, scrollTop, maxTop, now$2 = Date.now(),
16072
16638
  lines: 0
16073
16639
  };
16074
16640
  }
16075
- if (state.lastEdgeDir !== 0 && now$2 - state.lastEdgeAt < EDGE_BOUNCE_MS && dir === -state.lastEdgeDir && (atTop || atBottom)) return {
16641
+ if (state.lastEdgeDir !== 0 && now$3 - state.lastEdgeAt < EDGE_BOUNCE_MS && dir === -state.lastEdgeDir && (atTop || atBottom)) return {
16076
16642
  nextTop: scrollTop,
16077
16643
  dir: 0,
16078
16644
  lines: 0
@@ -18169,4 +18735,4 @@ const TRouterView = defineComponent({
18169
18735
  });
18170
18736
 
18171
18737
  //#endregion
18172
- export { ANSI16_COLORS, ANSI256_COLORS, ANSI8_COLORS, SGR_RESET, TAnchor, TBox, TDebugOverlay, TDialog, TERMINAL_RENDER_PLANES, TFlow, TInput, TInputBox, TInputPluginsContextKey, TJsonEditor, TList, TMultilineModal, TPathPicker, TRenderLayer, TRenderPlane, TRouterView, TSelect, TText, TTransition, TView, TerminalProvider, ansiColors, ansiStyles, applyWheelScroll, charCellWidth, clearTextCaches, createCliEventManager, createDefaultTInputHostAdapter, createDomRenderer, createEventManager, createNodeMentionPathProvider, createNodePathPickerProvider, createPromptMentionPlugin, createRuntime, createStdinDriver, createStdoutRenderer, createTInputHostPlugin, createTerminal, createTerminalApp, createTerminalRouter, createTextRestrictionPlugin, createTraceStore, createWheelScrollState, defaultTInputHostPlugin, detectTerminalColorCapability, formatInlineCellLine, getStdoutRendererMetrics, lintJsonText, normalizeNewlines, padEndByCells, parseAnsiSgr, readEventLog, resolveUserPath$1 as resolveUserPath, rgbToAnsi256, sanitizeInlineText, sanitizeTextBlock, sliceByCells, sliceByCellsRange, spaces, suggestPaths, textCellWidth, truecolorBgOpen, truecolorFgOpen, useLayout, useRenderNode, useRoute, useRouter, useTerminal, useTerminalNode, useTerminalRuntime, useVisibility, wrapByCells, writeEventLog, writeSnapshot };
18738
+ export { ANSI16_COLORS, ANSI256_COLORS, ANSI8_COLORS, SGR_RESET, TAnchor, TBox, TDebugOverlay, TDialog, TERMINAL_RENDER_PLANES, TFlow, TInput, TInputBox, TInputPluginsContextKey, TJsonEditor, TList, TMultilineModal, TPathPicker, TRenderLayer, TRenderPlane, TRouterView, TSelect, TText, TTransition, TView, TerminalProvider, ansiColors, ansiStyles, applyWheelScroll, charCellWidth, clearTextCaches, createCliEventManager, createDefaultTInputHostAdapter, createDomRenderer, createEventManager, createNodeMentionPathProvider, createNodePathPickerProvider, createPromptMentionPlugin, createRuntime, createStdinDriver, createStdoutRenderer, createTInputHostPlugin, createTerminal, createTerminalApp, createTerminalRouter, createTextRestrictionPlugin, createTraceStore, createWheelScrollState, defaultTInputHostPlugin, detectTerminalColorCapability, formatInlineCellLine, getCliLatencyProfiler, getStdoutRendererMetrics, lintJsonText, normalizeNewlines, padEndByCells, parseAnsiSgr, readEventLog, resolveUserPath$1 as resolveUserPath, rgbToAnsi256, sanitizeInlineText, sanitizeTextBlock, sliceByCells, sliceByCellsRange, spaces, suggestPaths, textCellWidth, truecolorBgOpen, truecolorFgOpen, useLayout, useRenderNode, useRoute, useRouter, useTerminal, useTerminalNode, useTerminalRuntime, useVisibility, wrapByCells, writeEventLog, writeSnapshot };