@teammates/consolonia 0.7.1 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,7 @@ import * as esc from "../ansi/esc.js";
4
4
  import { AnsiOutput } from "../ansi/output.js";
5
5
  import { stripAnsi, truncateAnsi, visibleLength } from "../ansi/strip.js";
6
6
  import { detectTerminal } from "../ansi/terminal-env.js";
7
+ import { enableWin32Mouse, restoreWin32Console, } from "../ansi/win32-console.js";
7
8
  // ── Helpers ────────────────────────────────────────────────────────
8
9
  const ESC = "\x1b[";
9
10
  /** Build a mock writable stream that accumulates output to a string. */
@@ -534,7 +535,10 @@ describe("detectTerminal", () => {
534
535
  }
535
536
  Object.assign(process.env, origEnv);
536
537
  Object.defineProperty(process, "platform", { value: origPlatform });
537
- Object.defineProperty(process.stdout, "isTTY", { value: origIsTTY, writable: true });
538
+ Object.defineProperty(process.stdout, "isTTY", {
539
+ value: origIsTTY,
540
+ writable: true,
541
+ });
538
542
  });
539
543
  function setEnv(overrides) {
540
544
  for (const [k, v] of Object.entries(overrides)) {
@@ -545,7 +549,10 @@ describe("detectTerminal", () => {
545
549
  }
546
550
  }
547
551
  it("returns pipe caps when stdout is not a TTY", () => {
548
- Object.defineProperty(process.stdout, "isTTY", { value: false, writable: true });
552
+ Object.defineProperty(process.stdout, "isTTY", {
553
+ value: false,
554
+ writable: true,
555
+ });
549
556
  const caps = detectTerminal();
550
557
  expect(caps.isTTY).toBe(false);
551
558
  expect(caps.mouse).toBe(false);
@@ -554,7 +561,10 @@ describe("detectTerminal", () => {
554
561
  });
555
562
  it("detects Windows Terminal via WT_SESSION", () => {
556
563
  Object.defineProperty(process, "platform", { value: "win32" });
557
- Object.defineProperty(process.stdout, "isTTY", { value: true, writable: true });
564
+ Object.defineProperty(process.stdout, "isTTY", {
565
+ value: true,
566
+ writable: true,
567
+ });
558
568
  setEnv({ WT_SESSION: "some-guid" });
559
569
  const caps = detectTerminal();
560
570
  expect(caps.name).toBe("windows-terminal");
@@ -563,7 +573,10 @@ describe("detectTerminal", () => {
563
573
  });
564
574
  it("detects VS Code terminal on Windows", () => {
565
575
  Object.defineProperty(process, "platform", { value: "win32" });
566
- Object.defineProperty(process.stdout, "isTTY", { value: true, writable: true });
576
+ Object.defineProperty(process.stdout, "isTTY", {
577
+ value: true,
578
+ writable: true,
579
+ });
567
580
  setEnv({ WT_SESSION: undefined, TERM_PROGRAM: "vscode" });
568
581
  const caps = detectTerminal();
569
582
  expect(caps.name).toBe("vscode");
@@ -571,21 +584,40 @@ describe("detectTerminal", () => {
571
584
  });
572
585
  it("detects ConEmu on Windows", () => {
573
586
  Object.defineProperty(process, "platform", { value: "win32" });
574
- Object.defineProperty(process.stdout, "isTTY", { value: true, writable: true });
575
- setEnv({ WT_SESSION: undefined, TERM_PROGRAM: undefined, ConEmuPID: "1234" });
587
+ Object.defineProperty(process.stdout, "isTTY", {
588
+ value: true,
589
+ writable: true,
590
+ });
591
+ setEnv({
592
+ WT_SESSION: undefined,
593
+ TERM_PROGRAM: undefined,
594
+ ConEmuPID: "1234",
595
+ });
576
596
  const caps = detectTerminal();
577
597
  expect(caps.name).toBe("conemu");
578
598
  });
579
599
  it("detects mintty via TERM + MSYSTEM", () => {
580
600
  Object.defineProperty(process, "platform", { value: "win32" });
581
- Object.defineProperty(process.stdout, "isTTY", { value: true, writable: true });
582
- setEnv({ WT_SESSION: undefined, TERM_PROGRAM: undefined, ConEmuPID: undefined, TERM: "xterm-256color", MSYSTEM: "MINGW64" });
601
+ Object.defineProperty(process.stdout, "isTTY", {
602
+ value: true,
603
+ writable: true,
604
+ });
605
+ setEnv({
606
+ WT_SESSION: undefined,
607
+ TERM_PROGRAM: undefined,
608
+ ConEmuPID: undefined,
609
+ TERM: "xterm-256color",
610
+ MSYSTEM: "MINGW64",
611
+ });
583
612
  const caps = detectTerminal();
584
613
  expect(caps.name).toBe("mintty");
585
614
  });
586
615
  it("detects tmux on Unix", () => {
587
616
  Object.defineProperty(process, "platform", { value: "linux" });
588
- Object.defineProperty(process.stdout, "isTTY", { value: true, writable: true });
617
+ Object.defineProperty(process.stdout, "isTTY", {
618
+ value: true,
619
+ writable: true,
620
+ });
589
621
  setEnv({ TMUX: "/tmp/tmux-1000/default,1234,0", TERM: "screen-256color" });
590
622
  const caps = detectTerminal();
591
623
  expect(caps.name).toBe("tmux");
@@ -593,8 +625,16 @@ describe("detectTerminal", () => {
593
625
  });
594
626
  it("detects GNU screen with limited caps", () => {
595
627
  Object.defineProperty(process, "platform", { value: "linux" });
596
- Object.defineProperty(process.stdout, "isTTY", { value: true, writable: true });
597
- setEnv({ TMUX: undefined, TERM: "screen", TERM_PROGRAM: undefined, ITERM_SESSION_ID: undefined });
628
+ Object.defineProperty(process.stdout, "isTTY", {
629
+ value: true,
630
+ writable: true,
631
+ });
632
+ setEnv({
633
+ TMUX: undefined,
634
+ TERM: "screen",
635
+ TERM_PROGRAM: undefined,
636
+ ITERM_SESSION_ID: undefined,
637
+ });
598
638
  const caps = detectTerminal();
599
639
  expect(caps.name).toBe("screen");
600
640
  expect(caps.sgrMouse).toBe(false);
@@ -602,24 +642,48 @@ describe("detectTerminal", () => {
602
642
  });
603
643
  it("detects iTerm2", () => {
604
644
  Object.defineProperty(process, "platform", { value: "darwin" });
605
- Object.defineProperty(process.stdout, "isTTY", { value: true, writable: true });
606
- setEnv({ TMUX: undefined, TERM: "xterm-256color", TERM_PROGRAM: "iTerm.app" });
645
+ Object.defineProperty(process.stdout, "isTTY", {
646
+ value: true,
647
+ writable: true,
648
+ });
649
+ setEnv({
650
+ TMUX: undefined,
651
+ TERM: "xterm-256color",
652
+ TERM_PROGRAM: "iTerm.app",
653
+ });
607
654
  const caps = detectTerminal();
608
655
  expect(caps.name).toBe("iterm2");
609
656
  expect(caps.truecolor).toBe(true);
610
657
  });
611
658
  it("detects xterm-compatible with COLORTERM truecolor", () => {
612
659
  Object.defineProperty(process, "platform", { value: "linux" });
613
- Object.defineProperty(process.stdout, "isTTY", { value: true, writable: true });
614
- setEnv({ TMUX: undefined, TERM: "xterm-256color", TERM_PROGRAM: undefined, ITERM_SESSION_ID: undefined, COLORTERM: "truecolor" });
660
+ Object.defineProperty(process.stdout, "isTTY", {
661
+ value: true,
662
+ writable: true,
663
+ });
664
+ setEnv({
665
+ TMUX: undefined,
666
+ TERM: "xterm-256color",
667
+ TERM_PROGRAM: undefined,
668
+ ITERM_SESSION_ID: undefined,
669
+ COLORTERM: "truecolor",
670
+ });
615
671
  const caps = detectTerminal();
616
672
  expect(caps.truecolor).toBe(true);
617
673
  expect(caps.color256).toBe(true);
618
674
  });
619
675
  it("detects dumb terminal with minimal caps", () => {
620
676
  Object.defineProperty(process, "platform", { value: "linux" });
621
- Object.defineProperty(process.stdout, "isTTY", { value: true, writable: true });
622
- setEnv({ TMUX: undefined, TERM: "dumb", TERM_PROGRAM: undefined, ITERM_SESSION_ID: undefined });
677
+ Object.defineProperty(process.stdout, "isTTY", {
678
+ value: true,
679
+ writable: true,
680
+ });
681
+ setEnv({
682
+ TMUX: undefined,
683
+ TERM: "dumb",
684
+ TERM_PROGRAM: undefined,
685
+ ITERM_SESSION_ID: undefined,
686
+ });
623
687
  const caps = detectTerminal();
624
688
  expect(caps.name).toBe("dumb");
625
689
  expect(caps.mouse).toBe(false);
@@ -667,7 +731,10 @@ describe("esc environment-aware sequences", () => {
667
731
  describe("initSequence", () => {
668
732
  it("includes all features for a full-caps terminal", () => {
669
733
  const caps = makeCaps();
670
- const seq = esc.initSequence(caps, { alternateScreen: true, mouse: true });
734
+ const seq = esc.initSequence(caps, {
735
+ alternateScreen: true,
736
+ mouse: true,
737
+ });
671
738
  expect(seq).toContain(esc.alternateScreenOn);
672
739
  expect(seq).toContain(esc.hideCursor);
673
740
  expect(seq).toContain(esc.bracketedPasteOn);
@@ -676,34 +743,52 @@ describe("esc environment-aware sequences", () => {
676
743
  });
677
744
  it("skips alternate screen when not supported", () => {
678
745
  const caps = makeCaps({ alternateScreen: false });
679
- const seq = esc.initSequence(caps, { alternateScreen: true, mouse: false });
746
+ const seq = esc.initSequence(caps, {
747
+ alternateScreen: true,
748
+ mouse: false,
749
+ });
680
750
  expect(seq).not.toContain(esc.alternateScreenOn);
681
751
  });
682
752
  it("skips alternate screen when app opts out", () => {
683
753
  const caps = makeCaps();
684
- const seq = esc.initSequence(caps, { alternateScreen: false, mouse: false });
754
+ const seq = esc.initSequence(caps, {
755
+ alternateScreen: false,
756
+ mouse: false,
757
+ });
685
758
  expect(seq).not.toContain(esc.alternateScreenOn);
686
759
  });
687
760
  it("skips bracketed paste when not supported", () => {
688
761
  const caps = makeCaps({ bracketedPaste: false });
689
- const seq = esc.initSequence(caps, { alternateScreen: false, mouse: false });
762
+ const seq = esc.initSequence(caps, {
763
+ alternateScreen: false,
764
+ mouse: false,
765
+ });
690
766
  expect(seq).not.toContain(esc.bracketedPasteOn);
691
767
  });
692
768
  it("skips mouse when app opts out even if caps support it", () => {
693
769
  const caps = makeCaps();
694
- const seq = esc.initSequence(caps, { alternateScreen: false, mouse: false });
770
+ const seq = esc.initSequence(caps, {
771
+ alternateScreen: false,
772
+ mouse: false,
773
+ });
695
774
  expect(seq).not.toContain("?1000h");
696
775
  });
697
776
  it("returns empty string for non-TTY", () => {
698
777
  const caps = makeCaps({ isTTY: false });
699
- const seq = esc.initSequence(caps, { alternateScreen: true, mouse: true });
778
+ const seq = esc.initSequence(caps, {
779
+ alternateScreen: true,
780
+ mouse: true,
781
+ });
700
782
  expect(seq).toBe("");
701
783
  });
702
784
  });
703
785
  describe("restoreSequence", () => {
704
786
  it("includes all restore features for a full-caps terminal", () => {
705
787
  const caps = makeCaps();
706
- const seq = esc.restoreSequence(caps, { alternateScreen: true, mouse: true });
788
+ const seq = esc.restoreSequence(caps, {
789
+ alternateScreen: true,
790
+ mouse: true,
791
+ });
707
792
  expect(seq).toContain(esc.reset);
708
793
  expect(seq).toContain(esc.mouseTrackingOff);
709
794
  expect(seq).toContain(esc.bracketedPasteOff);
@@ -712,15 +797,51 @@ describe("esc environment-aware sequences", () => {
712
797
  });
713
798
  it("mirrors initSequence — skips what init skipped", () => {
714
799
  const caps = makeCaps({ bracketedPaste: false, alternateScreen: false });
715
- const seq = esc.restoreSequence(caps, { alternateScreen: true, mouse: false });
800
+ const seq = esc.restoreSequence(caps, {
801
+ alternateScreen: true,
802
+ mouse: false,
803
+ });
716
804
  expect(seq).not.toContain(esc.bracketedPasteOff);
717
805
  expect(seq).not.toContain(esc.alternateScreenOff);
718
806
  expect(seq).not.toContain(esc.mouseTrackingOff);
719
807
  });
720
808
  it("returns empty string for non-TTY", () => {
721
809
  const caps = makeCaps({ isTTY: false });
722
- const seq = esc.restoreSequence(caps, { alternateScreen: true, mouse: true });
810
+ const seq = esc.restoreSequence(caps, {
811
+ alternateScreen: true,
812
+ mouse: true,
813
+ });
723
814
  expect(seq).toBe("");
724
815
  });
725
816
  });
726
817
  });
818
+ // ═══════════════════════════════════════════════════════════════════
819
+ // win32-console.ts
820
+ // ═══════════════════════════════════════════════════════════════════
821
+ describe("win32-console", () => {
822
+ const originalPlatform = process.platform;
823
+ afterEach(() => {
824
+ Object.defineProperty(process, "platform", { value: originalPlatform });
825
+ });
826
+ describe("enableWin32Mouse", () => {
827
+ it("returns false on non-win32 platforms", () => {
828
+ Object.defineProperty(process, "platform", { value: "linux" });
829
+ expect(enableWin32Mouse()).toBe(false);
830
+ });
831
+ it("returns false on darwin", () => {
832
+ Object.defineProperty(process, "platform", { value: "darwin" });
833
+ expect(enableWin32Mouse()).toBe(false);
834
+ });
835
+ });
836
+ describe("restoreWin32Console", () => {
837
+ it("returns false on non-win32 platforms", () => {
838
+ Object.defineProperty(process, "platform", { value: "linux" });
839
+ expect(restoreWin32Console()).toBe(false);
840
+ });
841
+ it("returns false when no original mode was saved", () => {
842
+ // Even on win32, if enableWin32Mouse was never called, restore is a no-op
843
+ Object.defineProperty(process, "platform", { value: "win32" });
844
+ expect(restoreWin32Console()).toBe(false);
845
+ });
846
+ });
847
+ });
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Win32 Console Mode — enables mouse input on Windows terminals.
3
+ *
4
+ * Node.js `setRawMode(true)` enables ENABLE_VIRTUAL_TERMINAL_INPUT but
5
+ * does NOT disable ENABLE_QUICK_EDIT_MODE (which intercepts mouse clicks
6
+ * for text selection) or enable ENABLE_MOUSE_INPUT. This module uses
7
+ * koffi to call the Win32 API directly and set the correct flags.
8
+ *
9
+ * Only loaded on win32 — no-ops on other platforms.
10
+ */
11
+ /**
12
+ * Configure the Windows console for mouse input.
13
+ *
14
+ * Disables Quick Edit Mode (which swallows mouse clicks) and enables
15
+ * ENABLE_MOUSE_INPUT + ENABLE_EXTENDED_FLAGS + ENABLE_WINDOW_INPUT.
16
+ * Saves the original mode so it can be restored later.
17
+ *
18
+ * No-op on non-Windows platforms or if koffi is not available.
19
+ * Returns true if the mode was successfully changed.
20
+ */
21
+ export declare function enableWin32Mouse(): boolean;
22
+ /**
23
+ * Restore the original Windows console mode saved by enableWin32Mouse().
24
+ *
25
+ * No-op if enableWin32Mouse() was never called or failed.
26
+ * Returns true if the mode was successfully restored.
27
+ */
28
+ export declare function restoreWin32Console(): boolean;
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Win32 Console Mode — enables mouse input on Windows terminals.
3
+ *
4
+ * Node.js `setRawMode(true)` enables ENABLE_VIRTUAL_TERMINAL_INPUT but
5
+ * does NOT disable ENABLE_QUICK_EDIT_MODE (which intercepts mouse clicks
6
+ * for text selection) or enable ENABLE_MOUSE_INPUT. This module uses
7
+ * koffi to call the Win32 API directly and set the correct flags.
8
+ *
9
+ * Only loaded on win32 — no-ops on other platforms.
10
+ */
11
+ import { createRequire } from "node:module";
12
+ // ── Console mode flag constants ─────────────────────────────────────
13
+ const ENABLE_PROCESSED_INPUT = 0x0001;
14
+ const ENABLE_LINE_INPUT = 0x0002;
15
+ const ENABLE_ECHO_INPUT = 0x0004;
16
+ const ENABLE_WINDOW_INPUT = 0x0008;
17
+ const ENABLE_MOUSE_INPUT = 0x0010;
18
+ const ENABLE_QUICK_EDIT_MODE = 0x0040;
19
+ const ENABLE_EXTENDED_FLAGS = 0x0080;
20
+ const ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200;
21
+ const STD_INPUT_HANDLE = -10;
22
+ // ── State ───────────────────────────────────────────────────────────
23
+ let originalMode = null;
24
+ let _kernel32;
25
+ function getKernel32() {
26
+ if (_kernel32 !== undefined)
27
+ return _kernel32;
28
+ try {
29
+ // koffi is an optional native dependency — dynamic require so the
30
+ // module loads cleanly even when koffi is absent.
31
+ const require = createRequire(import.meta.url);
32
+ const koffi = require("koffi");
33
+ const lib = koffi.load("kernel32.dll");
34
+ _kernel32 = {
35
+ GetStdHandle: lib.func("void* __stdcall GetStdHandle(int nStdHandle)"),
36
+ GetConsoleMode: lib.func("bool __stdcall GetConsoleMode(void* hConsoleHandle, _Out_ uint32_t* lpMode)"),
37
+ SetConsoleMode: lib.func("bool __stdcall SetConsoleMode(void* hConsoleHandle, uint32_t dwMode)"),
38
+ };
39
+ }
40
+ catch {
41
+ _kernel32 = null;
42
+ }
43
+ return _kernel32;
44
+ }
45
+ // ── Public API ──────────────────────────────────────────────────────
46
+ /**
47
+ * Configure the Windows console for mouse input.
48
+ *
49
+ * Disables Quick Edit Mode (which swallows mouse clicks) and enables
50
+ * ENABLE_MOUSE_INPUT + ENABLE_EXTENDED_FLAGS + ENABLE_WINDOW_INPUT.
51
+ * Saves the original mode so it can be restored later.
52
+ *
53
+ * No-op on non-Windows platforms or if koffi is not available.
54
+ * Returns true if the mode was successfully changed.
55
+ */
56
+ export function enableWin32Mouse() {
57
+ if (process.platform !== "win32")
58
+ return false;
59
+ const k32 = getKernel32();
60
+ if (!k32)
61
+ return false;
62
+ try {
63
+ const handle = k32.GetStdHandle(STD_INPUT_HANDLE);
64
+ if (!handle)
65
+ return false;
66
+ // Read current mode
67
+ const modeBuffer = Buffer.alloc(4);
68
+ if (!k32.GetConsoleMode(handle, modeBuffer))
69
+ return false;
70
+ originalMode = modeBuffer.readUInt32LE(0);
71
+ // Build new mode:
72
+ // - Keep ENABLE_VIRTUAL_TERMINAL_INPUT (set by Node raw mode)
73
+ // - Add ENABLE_MOUSE_INPUT + ENABLE_WINDOW_INPUT + ENABLE_EXTENDED_FLAGS
74
+ // - Remove ENABLE_QUICK_EDIT_MODE
75
+ // - Remove line/echo/processed (already cleared by raw mode)
76
+ let newMode = originalMode;
77
+ newMode |= ENABLE_MOUSE_INPUT;
78
+ newMode |= ENABLE_WINDOW_INPUT;
79
+ newMode |= ENABLE_EXTENDED_FLAGS;
80
+ newMode &= ~ENABLE_QUICK_EDIT_MODE;
81
+ newMode &= ~ENABLE_LINE_INPUT;
82
+ newMode &= ~ENABLE_ECHO_INPUT;
83
+ newMode &= ~ENABLE_PROCESSED_INPUT;
84
+ // Preserve VT input if it was set
85
+ if (originalMode & ENABLE_VIRTUAL_TERMINAL_INPUT) {
86
+ newMode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
87
+ }
88
+ return k32.SetConsoleMode(handle, newMode);
89
+ }
90
+ catch {
91
+ return false;
92
+ }
93
+ }
94
+ /**
95
+ * Restore the original Windows console mode saved by enableWin32Mouse().
96
+ *
97
+ * No-op if enableWin32Mouse() was never called or failed.
98
+ * Returns true if the mode was successfully restored.
99
+ */
100
+ export function restoreWin32Console() {
101
+ if (process.platform !== "win32" || originalMode === null)
102
+ return false;
103
+ const k32 = getKernel32();
104
+ if (!k32) {
105
+ originalMode = null;
106
+ return false;
107
+ }
108
+ try {
109
+ const handle = k32.GetStdHandle(STD_INPUT_HANDLE);
110
+ if (!handle) {
111
+ originalMode = null;
112
+ return false;
113
+ }
114
+ const result = k32.SetConsoleMode(handle, originalMode);
115
+ originalMode = null;
116
+ return result;
117
+ }
118
+ catch {
119
+ originalMode = null;
120
+ return false;
121
+ }
122
+ }
package/dist/app.js CHANGED
@@ -7,7 +7,8 @@
7
7
  */
8
8
  import * as esc from "./ansi/esc.js";
9
9
  import { AnsiOutput } from "./ansi/output.js";
10
- import { detectTerminal, } from "./ansi/terminal-env.js";
10
+ import { detectTerminal } from "./ansi/terminal-env.js";
11
+ import { enableWin32Mouse, restoreWin32Console } from "./ansi/win32-console.js";
11
12
  import { DrawingContext } from "./drawing/context.js";
12
13
  import { createInputProcessor } from "./input/processor.js";
13
14
  import { disableRawMode, enableRawMode } from "./input/raw-mode.js";
@@ -97,25 +98,30 @@ export class App {
97
98
  const stdout = process.stdout;
98
99
  // 1. Enable raw mode
99
100
  enableRawMode();
100
- // 2. Create ANSI output
101
+ // 2. On Windows, configure console mode for mouse input
102
+ // (must happen after raw mode so we modify the right base flags)
103
+ if (this._mouse) {
104
+ enableWin32Mouse();
105
+ }
106
+ // 3. Create ANSI output
101
107
  this._output = new AnsiOutput(stdout);
102
- // 3. Prepare terminal (custom sequence instead of prepareTerminal()
108
+ // 4. Prepare terminal (custom sequence instead of prepareTerminal()
103
109
  // so we can conditionally enable mouse tracking)
104
110
  this._prepareTerminal();
105
- // 4. Set terminal title
111
+ // 5. Set terminal title
106
112
  if (this._title) {
107
113
  stdout.write(esc.setTitle(this._title));
108
114
  }
109
- // 5. Create pixel buffer at terminal dimensions
115
+ // 6. Create pixel buffer at terminal dimensions
110
116
  const cols = stdout.columns || 80;
111
117
  const rows = stdout.rows || 24;
112
118
  this._createRenderPipeline(cols, rows);
113
- // 6. Wire up input
119
+ // 7. Wire up input
114
120
  this._setupInput();
115
- // 7. Wire up resize
121
+ // 8. Wire up resize
116
122
  this._resizeListener = () => this._handleResize();
117
123
  stdout.on("resize", this._resizeListener);
118
- // 8. SIGINT fallback
124
+ // 9. SIGINT fallback
119
125
  this._sigintListener = () => this.stop();
120
126
  process.on("SIGINT", this._sigintListener);
121
127
  }
@@ -294,6 +300,8 @@ export class App {
294
300
  }
295
301
  // Restore terminal
296
302
  this._restoreTerminal();
303
+ // Restore Win32 console mode (before disabling raw mode)
304
+ restoreWin32Console();
297
305
  // Disable raw mode
298
306
  disableRawMode();
299
307
  // Resolve the run() promise
package/dist/index.d.ts CHANGED
@@ -16,7 +16,8 @@ export type { Constraint, Point, Rect, Size, } from "./layout/types.js";
16
16
  export * as esc from "./ansi/esc.js";
17
17
  export { AnsiOutput } from "./ansi/output.js";
18
18
  export { stripAnsi, truncateAnsi, visibleLength, } from "./ansi/strip.js";
19
- export { type TerminalCaps, detectTerminal, } from "./ansi/terminal-env.js";
19
+ export { detectTerminal, type TerminalCaps, } from "./ansi/terminal-env.js";
20
+ export { enableWin32Mouse, restoreWin32Console, } from "./ansi/win32-console.js";
20
21
  export { DirtyRegions, DirtySnapshot } from "./render/regions.js";
21
22
  export { RenderTarget } from "./render/render-target.js";
22
23
  export { EscapeMatcher } from "./input/escape-matcher.js";
package/dist/index.js CHANGED
@@ -24,6 +24,7 @@ export * as esc from "./ansi/esc.js";
24
24
  export { AnsiOutput } from "./ansi/output.js";
25
25
  export { stripAnsi, truncateAnsi, visibleLength, } from "./ansi/strip.js";
26
26
  export { detectTerminal, } from "./ansi/terminal-env.js";
27
+ export { enableWin32Mouse, restoreWin32Console, } from "./ansi/win32-console.js";
27
28
  // ── Render pipeline ─────────────────────────────────────────────────
28
29
  export { DirtyRegions, DirtySnapshot } from "./render/regions.js";
29
30
  export { RenderTarget } from "./render/render-target.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teammates/consolonia",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Terminal UI rendering engine inspired by Consolonia. Pixel-level compositing with ANSI output.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -41,5 +41,8 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "marked": "^17.0.4"
44
+ },
45
+ "optionalDependencies": {
46
+ "koffi": "^2.9.0"
44
47
  }
45
48
  }