gloomberb 0.8.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +9 -7
  2. package/package.json +14 -13
  3. package/patches/{@opentui%2Fcore@0.1.90.patch → @opentui%2Fcore@0.3.2.patch} +175 -90
  4. package/src/app/global-shortcuts.test.tsx +54 -4
  5. package/src/app/global-shortcuts.ts +11 -5
  6. package/src/components/command-bar/action-runtime.ts +1 -0
  7. package/src/components/command-bar/layout-items/current-layout.test.ts +115 -0
  8. package/src/components/command-bar/layout-items/current-layout.ts +33 -0
  9. package/src/components/command-bar/list/view.tsx +3 -1
  10. package/src/components/command-bar/pane-templates/items.ts +4 -1
  11. package/src/components/command-bar/panel/body.tsx +1 -0
  12. package/src/components/command-bar/routes/root/results.ts +0 -30
  13. package/src/components/command-bar/routes/root/runtime.ts +2 -20
  14. package/src/components/command-bar/routes/ticker-search/actions.ts +42 -4
  15. package/src/components/command-bar/routes/ticker-search/route.ts +4 -1
  16. package/src/components/command-bar/routing/launch-request.ts +14 -7
  17. package/src/components/command-bar/routing/list-state.ts +1 -3
  18. package/src/components/command-bar/surface/index.test.tsx +76 -4
  19. package/src/components/command-bar/surface/index.tsx +0 -2
  20. package/src/components/command-bar/surface/pane.test.tsx +1 -0
  21. package/src/components/command-bar/surface/test-harness.tsx +1 -0
  22. package/src/components/command-bar/view-model.ts +3 -3
  23. package/src/components/layout/shell/index.test.tsx +120 -2
  24. package/src/components/layout/shell/index.tsx +2 -0
  25. package/src/components/layout/shell/menu.ts +1 -7
  26. package/src/components/layout/shell/pane/actions.ts +8 -0
  27. package/src/components/layout/shell/pane/management-shortcuts.ts +12 -2
  28. package/src/components/layout/shell/shortcuts.ts +14 -6
  29. package/src/components/layout/shell/window-mode/index.ts +8 -3
  30. package/src/components/layout/window-edit/presentation.ts +4 -4
  31. package/src/components/onboarding/onboarding-steps.tsx +3 -2
  32. package/src/components/ticker/list-table-view.tsx +6 -0
  33. package/src/components/ui/remote-image.tsx +1 -14
  34. package/src/components/ui/tabs.tsx +95 -80
  35. package/src/components/ui/ui.test.tsx +54 -0
  36. package/src/core/state/app/types.ts +12 -4
  37. package/src/plugins/builtin/chat/content/channel-navigation.ts +44 -11
  38. package/src/plugins/builtin/chat/content/index.tsx +5 -4
  39. package/src/plugins/builtin/chat/content/shortcuts.ts +7 -0
  40. package/src/plugins/builtin/chat/sidebar.test.tsx +71 -0
  41. package/src/plugins/builtin/help/components.tsx +1 -1
  42. package/src/plugins/builtin/help/index.test.tsx +105 -30
  43. package/src/plugins/builtin/help/index.tsx +324 -168
  44. package/src/plugins/builtin/help/shortcut-model.ts +5 -6
  45. package/src/plugins/builtin/portfolio-list/column-values.ts +304 -1
  46. package/src/plugins/builtin/portfolio-list/metrics.test.ts +93 -0
  47. package/src/plugins/builtin/portfolio-list/pane/data.ts +7 -0
  48. package/src/plugins/builtin/portfolio-list/pane/index.tsx +25 -2
  49. package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +281 -0
  50. package/src/plugins/builtin/portfolio-list/settings.ts +27 -0
  51. package/src/plugins/builtin/portfolio-list/table.tsx +4 -2
  52. package/src/plugins/builtin/portfolio-list/use-throttled-cursor-symbol.ts +10 -68
  53. package/src/plugins/builtin/substack/api/auth.ts +185 -0
  54. package/src/plugins/builtin/substack/api/cache.ts +78 -0
  55. package/src/plugins/builtin/substack/api/loaders.ts +146 -0
  56. package/src/plugins/builtin/substack/api/store.ts +186 -0
  57. package/src/plugins/builtin/substack/api/types.ts +40 -0
  58. package/src/plugins/builtin/substack/api.test.ts +298 -0
  59. package/src/plugins/builtin/substack/article-detail.tsx +359 -0
  60. package/src/plugins/builtin/substack/article-stack.tsx +129 -0
  61. package/src/plugins/builtin/substack/content.ts +478 -0
  62. package/src/plugins/builtin/substack/feed-tabs.tsx +41 -0
  63. package/src/plugins/builtin/substack/index.tsx +49 -0
  64. package/src/plugins/builtin/substack/login-view.tsx +126 -0
  65. package/src/plugins/builtin/substack/model.test.ts +155 -0
  66. package/src/plugins/builtin/substack/normalize.ts +343 -0
  67. package/src/plugins/builtin/substack/pane-footer.ts +71 -0
  68. package/src/plugins/builtin/substack/pane-state.ts +170 -0
  69. package/src/plugins/builtin/substack/pane.tsx +500 -0
  70. package/src/plugins/builtin/substack/table.ts +111 -0
  71. package/src/plugins/builtin/substack/types.ts +71 -0
  72. package/src/plugins/builtin/substack/utils.ts +131 -0
  73. package/src/plugins/builtin/ticker-detail/index.test.tsx +16 -2
  74. package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
  75. package/src/plugins/builtin/ticker-detail/pane.tsx +13 -1
  76. package/src/plugins/catalog-ui.ts +2 -0
  77. package/src/plugins/pane-manager/layout-state.ts +11 -0
  78. package/src/plugins/pane-manager.ts +1 -1
  79. package/src/react/use-throttled-commit-value.ts +116 -0
  80. package/src/renderers/electrobun/bun/desktop/http-fetch.test.ts +42 -0
  81. package/src/renderers/electrobun/bun/desktop/http-fetch.ts +5 -0
  82. package/src/renderers/electrobun/view/http-fetch.ts +10 -3
  83. package/src/state/app/context/index.test.tsx +16 -0
  84. package/src/tickers/search/index.ts +1 -0
  85. package/src/version.ts +1 -1
package/README.md CHANGED
@@ -51,7 +51,7 @@ For the best terminal experience, use a [Kitty](https://sw.kovidgoyal.net/kitty/
51
51
 
52
52
  ## Start
53
53
 
54
- Open the command bar with `Ctrl+P` or `` ` ``, then type a command.
54
+ Open command mode with `Ctrl+P`, then type a command. Press `` ` `` to open ticker search directly.
55
55
 
56
56
  | Try | Opens |
57
57
  |-----|-------|
@@ -65,7 +65,7 @@ Open the command bar with `Ctrl+P` or `` ` ``, then type a command.
65
65
  ## What It Does
66
66
 
67
67
  - Research companies with quotes, charts, financials, filings, holders, insiders, options, analyst ratings, events, and relative valuation.
68
- - Follow markets with top stories, breaking news, sector feeds, global indices, FX, macro events, yield curves, market movers, and fear/greed.
68
+ - Follow markets with top stories, breaking news, sector feeds, Substack subscriptions, global indices, FX, macro events, yield curves, market movers, and fear/greed.
69
69
  - Track portfolios and watchlists, connect brokers, set alerts, keep notes, run AI screens, browse prediction markets, and use Gloom Cloud chat.
70
70
 
71
71
  ## CLI
@@ -94,7 +94,7 @@ Core plugin areas include:
94
94
 
95
95
  - Portfolios, watchlists, manual entry, and broker connections
96
96
  - Ticker details, quotes, charts, options, filings, holders, insiders, and research
97
- - News, market movers, global indices, sectors, FX, earnings, macro data, and yield curves
97
+ - News, Substack reader feeds, market movers, global indices, sectors, FX, earnings, macro data, and yield curves
98
98
  - Prediction markets, alerts, notes, chat, AI screeners, and external plugins
99
99
 
100
100
  See [PLUGINS.md](PLUGINS.md) for the plugin API and the shared UI surface available through `gloomberb/components`.
@@ -103,7 +103,8 @@ See [PLUGINS.md](PLUGINS.md) for the plugin API and the shared UI surface availa
103
103
 
104
104
  | Key | Action |
105
105
  |-----|--------|
106
- | `Ctrl+P` or `` ` `` | Open command bar |
106
+ | `Ctrl+P` | Open command mode |
107
+ | `` ` `` | Open ticker search |
107
108
  | `Ctrl+,` | Open focused pane settings |
108
109
  | `Ctrl+W` | Close focused pane |
109
110
  | `Ctrl+Shift+M` | Move focused window (`WIN resize` starts resize mode) |
@@ -155,11 +156,15 @@ Use `HELP` inside Gloomberb for the live shortcut list. The common command-bar p
155
156
  |----------|----------|
156
157
  | `TOP` | Ranked market stories |
157
158
  | `MOST` | Top gainers, losers, most active, and trending tickers |
159
+ | `PM <query>` | Polymarket and Kalshi prediction data |
158
160
  | `N` | News feed |
159
161
  | `CN <ticker>` | Ticker news |
160
162
  | `NI` | Sector news |
163
+ | `SUB` | Authenticated Substack reader feed |
161
164
  | `FIRST` | Breaking news |
162
165
  | `TWIT <query>` | Ticker-related market posts |
166
+ | `TBO` | TheBuildout infrastructure intelligence |
167
+ | `CG` | Congress trading disclosures |
163
168
  | `WEI` | Global equity indices |
164
169
  | `ECON` | Economic events and releases |
165
170
  | `GC` | Yield curve |
@@ -176,13 +181,10 @@ Use `HELP` inside Gloomberb for the live shortcut list. The common command-bar p
176
181
  | `PORT` | Portfolio risk and sector exposure |
177
182
  | `ALRT` | Price alerts |
178
183
  | `SA <symbol condition price>` | Create a price alert |
179
- | `PM <query>` | Polymarket and Kalshi prediction data |
180
184
  | `AI <prompt>` | AI screener |
181
185
  | `CHAT [channel]` | Gloom Cloud chat |
182
186
  | `DM @user [@user...]` | Open or start a direct or group chat |
183
187
  | `ACM` | Gloom Cloud account settings |
184
- | `TBO` | TheBuildout infrastructure intelligence |
185
- | `CG` | Congress trading disclosures |
186
188
  | `NOTE` | Notes |
187
189
  | `IBKR` | IBKR trading pane |
188
190
  | `BR` | Broker connections |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gloomberb",
3
- "version": "0.8.2",
3
+ "version": "0.9.0",
4
4
  "description": "Market research and portfolio tracker for the terminal",
5
5
  "module": "src/index.tsx",
6
6
  "type": "module",
@@ -37,27 +37,28 @@
37
37
  "finance"
38
38
  ],
39
39
  "devDependencies": {
40
- "@types/bun": "latest",
40
+ "@types/bun": "^1.3.14",
41
41
  "@types/react-dom": "^19.2.3",
42
- "electrobun": "^1.16.0",
43
- "react-dom": "19.2.5"
42
+ "electrobun": "^1.18.1",
43
+ "react-dom": "19.2.7"
44
44
  },
45
45
  "peerDependencies": {
46
- "typescript": "^5"
46
+ "typescript": "^5.9.2"
47
47
  },
48
48
  "dependencies": {
49
49
  "@opentui-ui/dialog": "^0.1.2",
50
50
  "@opentui-ui/toast": "^0.0.5",
51
- "@opentui/core": "^0.1.90",
52
- "@opentui/react": "^0.1.90",
53
- "@stoqey/ib": "^1.5.3",
54
- "@tanstack/react-virtual": "^3.13.23",
55
- "jimp": "1.6.0",
51
+ "@opentui/core": "^0.3.2",
52
+ "@opentui/react": "^0.3.2",
53
+ "@stoqey/ib": "^1.5.6",
54
+ "@tanstack/react-virtual": "^3.14.2",
55
+ "jimp": "1.6.1",
56
56
  "opentui-spinner": "^0.0.6",
57
- "react": "19.2.5",
58
- "rxjs": "^7.8.2"
57
+ "react": "19.2.7",
58
+ "rxjs": "^7.8.2",
59
+ "web-tree-sitter": "0.25.10"
59
60
  },
60
61
  "patchedDependencies": {
61
- "@opentui/core@0.1.90": "patches/@opentui%2Fcore@0.1.90.patch"
62
+ "@opentui/core@0.3.2": "patches/@opentui%2Fcore@0.3.2.patch"
62
63
  }
63
64
  }
@@ -1,8 +1,8 @@
1
- diff --git a/index-e89anq5x.js b/index-e89anq5x.js
2
- index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9ace80b7b1 100644
3
- --- a/index-e89anq5x.js
4
- +++ b/index-e89anq5x.js
5
- @@ -6328,17 +6328,27 @@ class MouseParser {
1
+ diff --git a/index-218h9p3f.js b/index-218h9p3f.js
2
+ index b9445d2cca9477dfe06026da451b6d19268fcbdd..3efd05fa41eb713ac6e539764b15c346939bb068 100644
3
+ --- a/index-218h9p3f.js
4
+ +++ b/index-218h9p3f.js
5
+ @@ -6487,17 +6487,27 @@ class MouseParser {
6
6
  const buf = Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
7
7
  return buf.toString("latin1");
8
8
  }
@@ -17,14 +17,14 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
17
17
  + const projected = Math.floor(Math.max(pixel, 0) * cellCount / pixelExtent);
18
18
  + return Math.max(0, Math.min(projected, cellCount - 1));
19
19
  + }
20
- + parseMouseEvent(data, context = void 0) {
20
+ + parseMouseEvent(data, context = undefined) {
21
21
  const str = this.decodeInput(data);
22
22
  - const parsed = this.parseMouseSequenceAt(str, 0);
23
23
  + const parsed = this.parseMouseSequenceAt(str, 0, context);
24
24
  return parsed?.event ?? null;
25
25
  }
26
26
  - parseAllMouseEvents(data) {
27
- + parseAllMouseEvents(data, context = void 0) {
27
+ + parseAllMouseEvents(data, context = undefined) {
28
28
  const str = this.decodeInput(data);
29
29
  const events = [];
30
30
  let offset = 0;
@@ -34,12 +34,12 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
34
34
  if (!parsed) {
35
35
  break;
36
36
  }
37
- @@ -6347,19 +6357,19 @@ class MouseParser {
37
+ @@ -6506,19 +6516,19 @@ class MouseParser {
38
38
  }
39
39
  return events;
40
40
  }
41
41
  - parseMouseSequenceAt(str, offset) {
42
- + parseMouseSequenceAt(str, offset, context = void 0) {
42
+ + parseMouseSequenceAt(str, offset, context = undefined) {
43
43
  if (!str.startsWith("\x1B[", offset))
44
44
  return null;
45
45
  const introducer = str[offset + 2];
@@ -53,11 +53,11 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
53
53
  return null;
54
54
  }
55
55
  - parseSgrSequence(str, offset) {
56
- + parseSgrSequence(str, offset, context = void 0) {
56
+ + parseSgrSequence(str, offset, context = undefined) {
57
57
  let index = offset + 3;
58
58
  const values = [0, 0, 0];
59
59
  let part = 0;
60
- @@ -6387,7 +6397,7 @@ class MouseParser {
60
+ @@ -6546,7 +6556,7 @@ class MouseParser {
61
61
  if (!hasDigit || part !== 2)
62
62
  return null;
63
63
  return {
@@ -66,13 +66,13 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
66
66
  consumed: index - offset + 1
67
67
  };
68
68
  }
69
- @@ -6408,10 +6418,12 @@ class MouseParser {
69
+ @@ -6567,10 +6577,12 @@ class MouseParser {
70
70
  consumed: 6
71
71
  };
72
72
  }
73
73
  - decodeSgrEvent(rawButtonCode, wireX, wireY, pressRelease) {
74
74
  - const button = rawButtonCode & 3;
75
- + decodeSgrEvent(rawButtonCode, wireX, wireY, pressRelease, context = void 0) {
75
+ + decodeSgrEvent(rawButtonCode, wireX, wireY, pressRelease, context = undefined) {
76
76
  + const encodedButton = rawButtonCode & 3;
77
77
  + const isExtendedButton = (rawButtonCode & 128) !== 0;
78
78
  + const button = isExtendedButton ? 8 + encodedButton : encodedButton;
@@ -82,7 +82,7 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
82
82
  const isMotion = (rawButtonCode & 32) !== 0;
83
83
  const modifiers = {
84
84
  shift: (rawButtonCode & 4) !== 0,
85
- @@ -6422,7 +6434,7 @@ class MouseParser {
85
+ @@ -6581,7 +6593,7 @@ class MouseParser {
86
86
  let scrollInfo;
87
87
  if (isMotion) {
88
88
  const isDragging = this.mouseButtonsPressed.size > 0;
@@ -91,7 +91,7 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
91
91
  type = "move";
92
92
  } else if (isDragging) {
93
93
  type = "drag";
94
- @@ -6437,17 +6449,32 @@ class MouseParser {
94
+ @@ -6596,17 +6608,24 @@ class MouseParser {
95
95
  };
96
96
  } else {
97
97
  type = pressRelease === "M" ? "down" : "up";
@@ -104,36 +104,28 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
104
104
  }
105
105
  + const pixelModeRequested = context?.mouseUsesPixels === true;
106
106
  + const pixelModeConfirmed = context?.mousePixelsConfirmed === true;
107
- + const pixelModeDetected = pixelModeRequested && (
108
- + pixelModeConfirmed ||
109
- + wireX > (context?.terminalWidth ?? Number.POSITIVE_INFINITY) ||
110
- + wireY > (context?.terminalHeight ?? Number.POSITIVE_INFINITY)
111
- + );
112
- + const pixelX = pixelModeDetected ? Math.max(wireX - 1, 0) : void 0;
113
- + const pixelY = pixelModeDetected ? Math.max(wireY - 1, 0) : void 0;
107
+ + const pixelModeDetected = pixelModeRequested && (pixelModeConfirmed || wireX > (context?.terminalWidth ?? Number.POSITIVE_INFINITY) || wireY > (context?.terminalHeight ?? Number.POSITIVE_INFINITY));
108
+ + const pixelX = pixelModeDetected ? Math.max(wireX - 1, 0) : undefined;
109
+ + const pixelY = pixelModeDetected ? Math.max(wireY - 1, 0) : undefined;
114
110
  return {
115
111
  type,
116
112
  - button: button === 3 ? 0 : button,
117
113
  - x: wireX - 1,
118
114
  - y: wireY - 1,
119
115
  + button: !isExtendedButton && encodedButton === 3 ? 0 : button,
120
- + x: pixelModeDetected && pixelX !== void 0
121
- + ? this.projectPixelToCell(pixelX, context?.pixelWidth ?? 0, context?.terminalWidth ?? 0)
122
- + : wireX - 1,
123
- + y: pixelModeDetected && pixelY !== void 0
124
- + ? this.projectPixelToCell(pixelY, context?.pixelHeight ?? 0, context?.terminalHeight ?? 0)
125
- + : wireY - 1,
116
+ + x: pixelModeDetected && pixelX !== undefined ? this.projectPixelToCell(pixelX, context?.pixelWidth ?? 0, context?.terminalWidth ?? 0) : wireX - 1,
117
+ + y: pixelModeDetected && pixelY !== undefined ? this.projectPixelToCell(pixelY, context?.pixelHeight ?? 0, context?.terminalHeight ?? 0) : wireY - 1,
126
118
  + pixelX,
127
119
  + pixelY,
128
120
  modifiers,
129
121
  scroll: scrollInfo
130
122
  };
131
- @@ -6856,7 +6883,13 @@ var DEFAULT_PROTOCOL_CONTEXT = {
132
- kittyKeyboardEnabled: false,
123
+ @@ -7030,7 +7049,13 @@ var DEFAULT_PROTOCOL_CONTEXT = {
133
124
  privateCapabilityRepliesActive: false,
134
125
  pixelResolutionQueryActive: false,
135
- - explicitWidthCprActive: false
136
- + explicitWidthCprActive: false,
126
+ explicitWidthCprActive: false,
127
+ - startupCursorCprActive: false
128
+ + startupCursorCprActive: false,
137
129
  + mouseUsesPixels: false,
138
130
  + mousePixelsConfirmed: false,
139
131
  + terminalWidth: 0,
@@ -143,12 +135,12 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
143
135
  };
144
136
  var RXVT_DOLLAR_CSI_RE = /^\x1b\[\d+\$$/;
145
137
  var SYSTEM_CLOCK = new SystemClock;
146
- @@ -7149,7 +7182,13 @@ class StdinParser {
147
- kittyKeyboardEnabled: options.protocolContext?.kittyKeyboardEnabled ?? false,
138
+ @@ -7369,7 +7394,13 @@ class StdinParser {
148
139
  privateCapabilityRepliesActive: options.protocolContext?.privateCapabilityRepliesActive ?? false,
149
140
  pixelResolutionQueryActive: options.protocolContext?.pixelResolutionQueryActive ?? false,
150
- - explicitWidthCprActive: options.protocolContext?.explicitWidthCprActive ?? false
151
- + explicitWidthCprActive: options.protocolContext?.explicitWidthCprActive ?? false,
141
+ explicitWidthCprActive: options.protocolContext?.explicitWidthCprActive ?? false,
142
+ - startupCursorCprActive: options.protocolContext?.startupCursorCprActive ?? false
143
+ + startupCursorCprActive: options.protocolContext?.startupCursorCprActive ?? false,
152
144
  + mouseUsesPixels: options.protocolContext?.mouseUsesPixels ?? false,
153
145
  + mousePixelsConfirmed: options.protocolContext?.mousePixelsConfirmed ?? false,
154
146
  + terminalWidth: options.protocolContext?.terminalWidth ?? 0,
@@ -158,7 +150,7 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
158
150
  };
159
151
  }
160
152
  get bufferCapacity() {
161
- @@ -7952,11 +7991,14 @@ class StdinParser {
153
+ @@ -8298,11 +8329,14 @@ class StdinParser {
162
154
  });
163
155
  }
164
156
  emitMouse(rawBytes, encoding) {
@@ -168,13 +160,57 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
168
160
  this.emitOpaqueResponse("unknown", rawBytes);
169
161
  return;
170
162
  }
171
- + if (event.pixelX !== void 0 && event.pixelY !== void 0 && !this.protocolContext.mousePixelsConfirmed) {
163
+ + if (event.pixelX !== undefined && event.pixelY !== undefined && !this.protocolContext.mousePixelsConfirmed) {
172
164
  + this.updateProtocolContext({ mousePixelsConfirmed: true });
173
165
  + }
174
166
  this.events.push({
175
167
  type: "mouse",
176
168
  raw: decodeLatin1(rawBytes),
177
- @@ -17295,6 +17337,8 @@ class MouseEvent {
169
+ @@ -12538,34 +12572,35 @@ function validateLinuxLibcOverride() {
170
+ throw new Error(`OPENTUI_LIBC must be "glibc" or "musl", got "${libc}"`);
171
+ }
172
+ async function resolveNativePackage() {
173
+ + const loadNativePackage = async (packageName) => await import(packageName);
174
+ if (process.platform === "darwin") {
175
+ if (process.arch === "x64")
176
+ - return await import("@opentui/core-darwin-x64");
177
+ + return await loadNativePackage("@opentui/core-darwin-x64");
178
+ if (process.arch === "arm64")
179
+ - return await import("@opentui/core-darwin-arm64");
180
+ + return await loadNativePackage("@opentui/core-darwin-arm64");
181
+ }
182
+ if (process.platform === "linux") {
183
+ validateLinuxLibcOverride();
184
+ if (process.arch === "x64") {
185
+ if (process.env.OPENTUI_LIBC === "musl") {
186
+ - return await import("@opentui/core-linux-x64-musl");
187
+ + return await loadNativePackage("@opentui/core-linux-x64-musl");
188
+ } else {
189
+ - return await import("@opentui/core-linux-x64");
190
+ + return await loadNativePackage("@opentui/core-linux-x64");
191
+ }
192
+ }
193
+ if (process.arch === "arm64") {
194
+ if (process.env.OPENTUI_LIBC === "musl") {
195
+ - return await import("@opentui/core-linux-arm64-musl");
196
+ + return await loadNativePackage("@opentui/core-linux-arm64-musl");
197
+ } else {
198
+ - return await import("@opentui/core-linux-arm64");
199
+ + return await loadNativePackage("@opentui/core-linux-arm64");
200
+ }
201
+ }
202
+ }
203
+ if (process.platform === "win32") {
204
+ if (process.arch === "x64")
205
+ - return await import("@opentui/core-win32-x64");
206
+ + return await loadNativePackage("@opentui/core-win32-x64");
207
+ if (process.arch === "arm64")
208
+ - return await import("@opentui/core-win32-arm64");
209
+ + return await loadNativePackage("@opentui/core-win32-arm64");
210
+ }
211
+ throw new Error(`opentui is not supported on the current platform: ${process.platform}-${process.arch}`);
212
+ }
213
+ @@ -22288,6 +22323,8 @@ class MouseEvent {
178
214
  button;
179
215
  x;
180
216
  y;
@@ -183,7 +219,7 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
183
219
  source;
184
220
  modifiers;
185
221
  scroll;
186
- @@ -17314,6 +17358,8 @@ class MouseEvent {
222
+ @@ -22307,6 +22344,8 @@ class MouseEvent {
187
223
  this.button = attributes.button;
188
224
  this.x = attributes.x;
189
225
  this.y = attributes.y;
@@ -192,30 +228,30 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
192
228
  this.modifiers = attributes.modifiers;
193
229
  this.scroll = attributes.scroll;
194
230
  this.source = attributes.source;
195
- @@ -17479,6 +17525,8 @@ class CliRenderer extends EventEmitter8 {
231
+ @@ -22457,6 +22496,8 @@ class CliRenderer extends EventEmitter9 {
196
232
  resizeDebounceDelay = 100;
197
233
  enableMouseMovement = false;
198
234
  _useMouse = true;
199
235
  + _mouseProtocolSignature = "disabled";
200
236
  + _pixelMouseEnabled = false;
201
237
  autoFocus = true;
202
- _useAlternateScreen = env.OTUI_USE_ALTERNATE_SCREEN;
203
- _suspendedMouseEnabled = false;
204
- @@ -17507,7 +17555,7 @@ class CliRenderer extends EventEmitter8 {
238
+ _screenMode = "alternate-screen";
239
+ _footerHeight = DEFAULT_FOOTER_HEIGHT;
240
+ @@ -22491,7 +22532,7 @@ class CliRenderer extends EventEmitter9 {
205
241
  this.handleResize(width, height);
206
242
  }).bind(this);
207
243
  _capabilities = null;
208
244
  - _latestPointer = { x: 0, y: 0 };
209
- + _latestPointer = { x: 0, y: 0, pixelX: void 0, pixelY: void 0 };
245
+ + _latestPointer = { x: 0, y: 0, pixelX: undefined, pixelY: undefined };
210
246
  _hasPointer = false;
211
- _lastPointerModifiers = { shift: false, alt: false, ctrl: false };
212
- _currentMousePointerStyle = undefined;
213
- @@ -17661,7 +17709,13 @@ Captured output:
214
- kittyKeyboardEnabled: useKittyForParsing,
247
+ _lastPointerModifiers = {
248
+ shift: false,
249
+ @@ -22738,7 +22779,13 @@ Captured external output:
215
250
  privateCapabilityRepliesActive: false,
216
251
  pixelResolutionQueryActive: false,
217
- - explicitWidthCprActive: false
218
- + explicitWidthCprActive: false,
252
+ explicitWidthCprActive: false,
253
+ - startupCursorCprActive: false
254
+ + startupCursorCprActive: false,
219
255
  + mouseUsesPixels: false,
220
256
  + mousePixelsConfirmed: false,
221
257
  + terminalWidth: this._terminalWidth,
@@ -225,7 +261,7 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
225
261
  },
226
262
  clock: this.clock
227
263
  });
228
- @@ -17983,12 +18037,14 @@ Captured output:
264
+ @@ -24021,12 +24068,14 @@ Captured external output:
229
265
  enableMouse() {
230
266
  this._useMouse = true;
231
267
  this.lib.enableMouse(this.rendererPtr, this.enableMouseMovement);
@@ -240,7 +276,7 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
240
276
  }
241
277
  enableKittyKeyboard(flags = 3) {
242
278
  this.lib.enableKittyKeyboard(this.rendererPtr, flags);
243
- @@ -17998,6 +18054,64 @@ Captured output:
279
+ @@ -24036,6 +24085,52 @@ Captured external output:
244
280
  this.lib.disableKittyKeyboard(this.rendererPtr);
245
281
  this.updateStdinParserProtocolContext({ kittyKeyboardEnabled: false }, true);
246
282
  }
@@ -248,27 +284,15 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
248
284
  + return this.enableMouseMovement ? "any" : "press";
249
285
  + }
250
286
  + buildMouseProtocolSequence(pixelEnabled) {
251
- + const trackingSequence = this.enableMouseMovement
252
- + ? "\x1B[?1000l\x1B[?1002l\x1B[?1003h"
253
- + : "\x1B[?1003l\x1B[?1002l\x1B[?1000h";
287
+ + const trackingSequence = this.enableMouseMovement ? "\x1B[?1000l\x1B[?1002l\x1B[?1003h" : "\x1B[?1003l\x1B[?1002l\x1B[?1000h";
254
288
  + return "\x1B[?1005l\x1B[?1015l\x1B[?1006h" + trackingSequence + (pixelEnabled ? "\x1B[?1016h" : "\x1B[?1016l");
255
289
  + }
256
290
  + syncPixelMouseMode(force = false) {
257
291
  + const nextEnabled = Boolean(this._useMouse);
258
- + const pixelMouseDisabled = typeof process !== "undefined" && process?.env?.GLOOMBERB_DISABLE_PIXEL_MOUSE === "1";
259
292
  + const hasPixelCapability = this._capabilities?.sgr_pixels === true;
260
293
  + const hasPixelResolution = (this._resolution?.width ?? 0) > 0 && (this._resolution?.height ?? 0) > 0;
261
- + const nextPixelEnabled = Boolean(
262
- + nextEnabled &&
263
- + !pixelMouseDisabled &&
264
- + hasPixelCapability &&
265
- + hasPixelResolution &&
266
- + this._terminalWidth > 0 &&
267
- + this._terminalHeight > 0
268
- + );
269
- + const nextSignature = nextEnabled
270
- + ? `${this.getMouseProtocolTrackingMode()}:${nextPixelEnabled ? "pixel" : "cell"}`
271
- + : "disabled";
294
+ + const nextPixelEnabled = Boolean(nextEnabled && hasPixelCapability && hasPixelResolution && this._terminalWidth > 0 && this._terminalHeight > 0);
295
+ + const nextSignature = nextEnabled ? `${this.getMouseProtocolTrackingMode()}:${nextPixelEnabled ? "pixel" : "cell"}` : "disabled";
272
296
  + if (nextEnabled) {
273
297
  + if (force || this._mouseProtocolSignature !== nextSignature) {
274
298
  + this.writeOut(this.buildMouseProtocolSequence(nextPixelEnabled));
@@ -305,23 +329,15 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
305
329
  set useThread(useThread) {
306
330
  this._useThread = useThread;
307
331
  this.lib.setUseThread(this.rendererPtr, useThread);
308
- @@ -18031,6 +18145,7 @@ Captured output:
309
- if (this._useMouse) {
310
- this.enableMouse();
332
+ @@ -24141,6 +24236,7 @@ Captured external output:
311
333
  }
334
+ this.lib.processCapabilityResponse(this.rendererPtr, sequence);
335
+ this._capabilities = this.lib.getTerminalCapabilities(this.rendererPtr);
312
336
  + this.syncPixelMouseMode();
313
- this.queryPixelResolution();
314
- }
315
- stdinListener = ((chunk) => {
316
- @@ -18070,6 +18185,7 @@ Captured output:
317
- if (isCapabilityResponse(sequence)) {
318
- this.lib.processCapabilityResponse(this.rendererPtr, sequence);
319
- this._capabilities = this.lib.getTerminalCapabilities(this.rendererPtr);
320
- + this.syncPixelMouseMode();
321
- this.emit("capabilities" /* CAPABILITIES */, this._capabilities);
322
- return true;
337
+ if (this._capabilities?.terminal?.from_xtversion) {
338
+ this.resolveXtVersionWaiters();
323
339
  }
324
- @@ -18079,6 +18195,7 @@ Captured output:
340
+ @@ -24170,6 +24266,7 @@ Captured external output:
325
341
  if (sequence === "\x1B[I") {
326
342
  if (this.shouldRestoreModesOnNextFocus) {
327
343
  this.lib.restoreTerminalModes(this.rendererPtr);
@@ -329,7 +345,7 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
329
345
  this.shouldRestoreModesOnNextFocus = false;
330
346
  }
331
347
  if (this._terminalFocusState !== true) {
332
- @@ -18187,6 +18304,7 @@ Captured output:
348
+ @@ -24264,6 +24361,7 @@ Captured external output:
333
349
  }
334
350
  this.waitingForPixelResolution = false;
335
351
  this.updateStdinParserProtocolContext({ pixelResolutionQueryActive: false }, true);
@@ -337,11 +353,11 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
337
353
  return true;
338
354
  }
339
355
  return false;
340
- @@ -18221,9 +18339,15 @@ Captured output:
356
+ @@ -24298,9 +24396,15 @@ Captured external output:
341
357
  return false;
342
358
  }
343
359
  mouseEvent.y -= this.renderOffset;
344
- + if (mouseEvent.pixelY !== void 0 && this._resolution) {
360
+ + if (mouseEvent.pixelY !== undefined && this._resolution) {
345
361
  + const cellHeight = this._resolution.height / Math.max(this._terminalHeight, 1);
346
362
  + mouseEvent.pixelY = Math.max(mouseEvent.pixelY - this.renderOffset * cellHeight, 0);
347
363
  + }
@@ -353,7 +369,7 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
353
369
  this._hasPointer = true;
354
370
  this._lastPointerModifiers = mouseEvent.modifiers;
355
371
  if (this._console.visible) {
356
- @@ -18352,6 +18476,8 @@ Captured output:
372
+ @@ -24441,6 +24545,8 @@ Captured external output:
357
373
  button: 0,
358
374
  x: this._latestPointer.x,
359
375
  y: this._latestPointer.y,
@@ -362,19 +378,88 @@ index e3b6cf9f90b13698966eec991fa7a1b2e1e22d96..709940f3998e5cb1caa88642fa68fa9a
362
378
  modifiers: this._lastPointerModifiers
363
379
  };
364
380
  if (lastOver && !lastOver.isDestroyed) {
365
- @@ -18435,6 +18561,7 @@ Captured output:
366
- const prevWidth = this._terminalWidth;
381
+ @@ -24531,6 +24637,7 @@ Captured external output:
382
+ const visiblePreviousSplitHeight = pendingSplitFooterTransition?.sourceHeight ?? previousGeometry.effectiveFooterHeight;
367
383
  this._terminalWidth = width;
368
384
  this._terminalHeight = height;
369
385
  + this.syncPixelMouseMode();
370
386
  this.queryPixelResolution();
371
387
  this.setCapturedRenderable(undefined);
372
388
  this.stdinParser?.resetMouseState();
373
- @@ -18712,6 +18839,7 @@ Captured output:
374
- }
389
+ @@ -24848,6 +24955,7 @@ Captured external output:
390
+ this.themeModeState.cancelRefresh();
375
391
  this._isRunning = false;
376
392
  this.waitingForPixelResolution = false;
377
393
  + this.disablePixelMouseMode();
378
394
  this.updateStdinParserProtocolContext({
379
395
  privateCapabilityRepliesActive: false,
380
396
  pixelResolutionQueryActive: false,
397
+ diff --git a/lib/parse.mouse.d.ts b/lib/parse.mouse.d.ts
398
+ index c29f953fde0b78f09d2ec7a830e5a72452c1fe7e..04613b921bd9b4a9a7a1a4fbd0234d4012df67a1 100644
399
+ --- a/lib/parse.mouse.d.ts
400
+ +++ b/lib/parse.mouse.d.ts
401
+ @@ -8,6 +8,8 @@ export type RawMouseEvent = {
402
+ button: number;
403
+ x: number;
404
+ y: number;
405
+ + pixelX?: number;
406
+ + pixelY?: number;
407
+ modifiers: {
408
+ shift: boolean;
409
+ alt: boolean;
410
+ @@ -20,8 +22,23 @@ export declare class MouseParser {
411
+ private static readonly SCROLL_DIRECTIONS;
412
+ reset(): void;
413
+ private decodeInput;
414
+ - parseMouseEvent(data: Buffer | Uint8Array): RawMouseEvent | null;
415
+ - parseAllMouseEvents(data: Buffer | Uint8Array): RawMouseEvent[];
416
+ + private projectPixelToCell;
417
+ + parseMouseEvent(data: Buffer | Uint8Array, context?: {
418
+ + mouseUsesPixels?: boolean;
419
+ + mousePixelsConfirmed?: boolean;
420
+ + terminalWidth?: number;
421
+ + terminalHeight?: number;
422
+ + pixelWidth?: number;
423
+ + pixelHeight?: number;
424
+ + }): RawMouseEvent | null;
425
+ + parseAllMouseEvents(data: Buffer | Uint8Array, context?: {
426
+ + mouseUsesPixels?: boolean;
427
+ + mousePixelsConfirmed?: boolean;
428
+ + terminalWidth?: number;
429
+ + terminalHeight?: number;
430
+ + pixelWidth?: number;
431
+ + pixelHeight?: number;
432
+ + }): RawMouseEvent[];
433
+ private parseMouseSequenceAt;
434
+ private parseSgrSequence;
435
+ private parseBasicSequence;
436
+ diff --git a/lib/stdin-parser.d.ts b/lib/stdin-parser.d.ts
437
+ index 6b733d534d8e9b77c5c2773f93c7a22063c18d84..a5c318d591e9f3775e276e555c15052c8dbd20cb 100644
438
+ --- a/lib/stdin-parser.d.ts
439
+ +++ b/lib/stdin-parser.d.ts
440
+ @@ -28,6 +28,12 @@ export interface StdinParserProtocolContext {
441
+ pixelResolutionQueryActive: boolean;
442
+ explicitWidthCprActive: boolean;
443
+ startupCursorCprActive: boolean;
444
+ + mouseUsesPixels: boolean;
445
+ + mousePixelsConfirmed: boolean;
446
+ + terminalWidth: number;
447
+ + terminalHeight: number;
448
+ + pixelWidth: number;
449
+ + pixelHeight: number;
450
+ }
451
+ export interface StdinParserOptions {
452
+ timeoutMs?: number;
453
+ diff --git a/renderer.d.ts b/renderer.d.ts
454
+ index 96189246f423809fc52d2ad182d57ed2e80ac098..7dd0baf1697041cf8ad556b115cd13ad2e18bc65 100644
455
+ --- a/renderer.d.ts
456
+ +++ b/renderer.d.ts
457
+ @@ -143,6 +143,8 @@ export declare class MouseEvent {
458
+ readonly button: number;
459
+ readonly x: number;
460
+ readonly y: number;
461
+ + readonly pixelX?: number;
462
+ + readonly pixelY?: number;
463
+ readonly source?: Renderable;
464
+ readonly modifiers: {
465
+ shift: boolean;