gloomberb 0.1.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/LICENSE +25 -0
  2. package/README.md +68 -121
  3. package/bin/gloomberb +3 -0
  4. package/package.json +13 -4
  5. package/patches/@opentui%2Fcore@0.1.90.patch +356 -0
  6. package/src/app.tsx +1330 -0
  7. package/src/brokers/sync-broker-instance.test.ts +100 -0
  8. package/src/brokers/sync-broker-instance.ts +341 -0
  9. package/src/cli/commands/plugins.ts +173 -0
  10. package/src/cli/commands/portfolio.ts +210 -0
  11. package/src/cli/commands/search.ts +120 -0
  12. package/src/cli/commands/ticker.ts +375 -0
  13. package/src/cli/commands/watchlist.ts +210 -0
  14. package/src/cli/context.ts +62 -0
  15. package/src/cli/errors.ts +13 -0
  16. package/src/cli/helpers.ts +85 -0
  17. package/src/cli/index.ts +143 -0
  18. package/src/cli/ticker-resolution.ts +39 -0
  19. package/src/cli/types.ts +15 -0
  20. package/src/cli.test.ts +361 -0
  21. package/src/components/chart/chart-data.ts +239 -0
  22. package/src/components/chart/chart-renderer.ts +1199 -0
  23. package/src/components/chart/chart-types.ts +82 -0
  24. package/src/components/chart/chart-viewport.ts +21 -0
  25. package/src/components/chart/chart.test.ts +439 -0
  26. package/src/components/chart/comparison-chart-data.test.ts +109 -0
  27. package/src/components/chart/comparison-chart-data.ts +316 -0
  28. package/src/components/chart/comparison-chart-renderer.test.ts +84 -0
  29. package/src/components/chart/comparison-chart-renderer.ts +354 -0
  30. package/src/components/chart/comparison-stock-chart.tsx +1486 -0
  31. package/src/components/chart/cursor-motion.ts +48 -0
  32. package/src/components/chart/native/chart-rasterizer.ts +732 -0
  33. package/src/components/chart/native/kitty-adapter.ts +12 -0
  34. package/src/components/chart/native/kitty-manager.ts +142 -0
  35. package/src/components/chart/native/kitty-protocol.ts +110 -0
  36. package/src/components/chart/native/kitty-support.ts +71 -0
  37. package/src/components/chart/native/kitty.test.ts +620 -0
  38. package/src/components/chart/native/renderer-selection.ts +24 -0
  39. package/src/components/chart/native/surface-manager.ts +225 -0
  40. package/src/components/chart/native/surface-sync.ts +34 -0
  41. package/src/components/chart/stock-chart-renderer-switch.test.tsx +165 -0
  42. package/src/components/chart/stock-chart.test.ts +107 -0
  43. package/src/components/chart/stock-chart.tsx +1556 -0
  44. package/src/components/command-bar/__snapshots__/command-bar.test.tsx.snap +137 -0
  45. package/src/components/command-bar/command-bar.test.tsx +1524 -0
  46. package/src/components/command-bar/command-bar.tsx +4823 -0
  47. package/src/components/command-bar/command-registry.ts +261 -0
  48. package/src/components/command-bar/helpers.test.ts +224 -0
  49. package/src/components/command-bar/helpers.ts +371 -0
  50. package/src/components/command-bar/root-shortcuts.ts +158 -0
  51. package/src/components/command-bar/view-model.test.ts +152 -0
  52. package/src/components/command-bar/view-model.ts +185 -0
  53. package/src/components/command-bar/workflow-ops.test.ts +70 -0
  54. package/src/components/command-bar/workflow-ops.ts +433 -0
  55. package/src/components/command-bar/workflow-types.ts +127 -0
  56. package/src/components/detail-feed-view.test.tsx +105 -0
  57. package/src/components/detail-feed-view.tsx +295 -0
  58. package/src/components/index.ts +32 -0
  59. package/src/components/layout/floating-pane.tsx +49 -0
  60. package/src/components/layout/header.tsx +129 -0
  61. package/src/components/layout/pane-header.tsx +44 -0
  62. package/src/components/layout/pane.tsx +49 -0
  63. package/src/components/layout/pixel-mouse-mode.test.ts +122 -0
  64. package/src/components/layout/pixel-mouse.test.ts +40 -0
  65. package/src/components/layout/shell.test.tsx +625 -0
  66. package/src/components/layout/shell.tsx +1200 -0
  67. package/src/components/layout/status-bar.test.tsx +173 -0
  68. package/src/components/layout/status-bar.tsx +138 -0
  69. package/src/components/markdown-editor.tsx +134 -0
  70. package/src/components/onboarding/onboarding-wizard.test.tsx +184 -0
  71. package/src/components/onboarding/onboarding-wizard.tsx +1365 -0
  72. package/src/components/pane-settings-dialog.tsx +468 -0
  73. package/src/components/pane-template-wizard.test.tsx +52 -0
  74. package/src/components/pane-template-wizard.tsx +199 -0
  75. package/src/components/price-selector-dialog.tsx +195 -0
  76. package/src/components/spinner.tsx +2 -0
  77. package/src/components/tab-bar.tsx +17 -0
  78. package/src/components/ticker-badge-text.test.tsx +160 -0
  79. package/src/components/ticker-badge-text.tsx +58 -0
  80. package/src/components/ticker-badge.tsx +88 -0
  81. package/src/components/ticker-list-table.tsx +188 -0
  82. package/src/components/toggle-list.tsx +74 -0
  83. package/src/components/ui/button.tsx +77 -0
  84. package/src/components/ui/data-table.tsx +210 -0
  85. package/src/components/ui/external-link.tsx +22 -0
  86. package/src/components/ui/fields.tsx +187 -0
  87. package/src/components/ui/frame.tsx +73 -0
  88. package/src/components/ui/index.ts +53 -0
  89. package/src/components/ui/list-view.tsx +166 -0
  90. package/src/components/ui/loading.tsx +70 -0
  91. package/src/components/ui/status.tsx +83 -0
  92. package/src/components/ui/tabs.tsx +47 -0
  93. package/src/components/ui/toggle.tsx +164 -0
  94. package/src/components/ui/ui.test.tsx +134 -0
  95. package/src/data/app-persistence.ts +25 -0
  96. package/src/data/config-store.test.ts +310 -0
  97. package/src/data/config-store.ts +469 -0
  98. package/src/data/plugin-state-store.ts +102 -0
  99. package/src/data/resource-store.ts +323 -0
  100. package/src/data/session-store.ts +52 -0
  101. package/src/data/sqlite-cache.test.ts +103 -0
  102. package/src/data/sqlite-database.ts +62 -0
  103. package/src/data/sqlite-json.ts +19 -0
  104. package/src/data/ticker-repository.ts +45 -0
  105. package/src/data/ticker-store.ts +46 -0
  106. package/src/index.tsx +67 -0
  107. package/src/market-data/coordinator.test.ts +369 -0
  108. package/src/market-data/coordinator.ts +580 -0
  109. package/src/market-data/hooks.tsx +234 -0
  110. package/src/market-data/query-store.ts +28 -0
  111. package/src/market-data/request-types.test.ts +64 -0
  112. package/src/market-data/request-types.ts +70 -0
  113. package/src/market-data/result-types.ts +56 -0
  114. package/src/market-data/selectors.ts +166 -0
  115. package/src/market-data/trace.ts +7 -0
  116. package/src/pane-settings.test.ts +71 -0
  117. package/src/pane-settings.ts +73 -0
  118. package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +338 -0
  119. package/src/plugins/builtin/ai/gloomberb-cli.ts +70 -0
  120. package/src/plugins/builtin/ai/index.test.tsx +139 -0
  121. package/src/plugins/builtin/ai/index.tsx +86 -0
  122. package/src/plugins/builtin/ai/providers.ts +99 -0
  123. package/src/plugins/builtin/ai/runner.ts +82 -0
  124. package/src/plugins/builtin/ai/screener-contract.test.ts +117 -0
  125. package/src/plugins/builtin/ai/screener-contract.ts +174 -0
  126. package/src/plugins/builtin/ai/screener-pane.test.tsx +365 -0
  127. package/src/plugins/builtin/ai/screener-pane.tsx +1161 -0
  128. package/src/plugins/builtin/ai/settings.ts +79 -0
  129. package/src/plugins/builtin/ai/ticker-context.ts +64 -0
  130. package/src/plugins/builtin/ai/utils.ts +71 -0
  131. package/src/plugins/builtin/ask-ai.test.tsx +258 -0
  132. package/src/plugins/builtin/ask-ai.tsx +9 -0
  133. package/src/plugins/builtin/chat-controller.test.ts +217 -0
  134. package/src/plugins/builtin/chat-controller.ts +340 -0
  135. package/src/plugins/builtin/chat.test.tsx +451 -0
  136. package/src/plugins/builtin/chat.tsx +620 -0
  137. package/src/plugins/builtin/comparison-chart.test.tsx +277 -0
  138. package/src/plugins/builtin/comparison-chart.tsx +169 -0
  139. package/src/plugins/builtin/data-providers.ts +16 -0
  140. package/src/plugins/builtin/debug.tsx +351 -0
  141. package/src/plugins/builtin/help.test.tsx +110 -0
  142. package/src/plugins/builtin/help.tsx +281 -0
  143. package/src/plugins/builtin/layout-manager.tsx +264 -0
  144. package/src/plugins/builtin/manual-entry.tsx +25 -0
  145. package/src/plugins/builtin/news.tsx +143 -0
  146. package/src/plugins/builtin/notes-files.ts +58 -0
  147. package/src/plugins/builtin/notes.tsx +396 -0
  148. package/src/plugins/builtin/options-availability.test.tsx +179 -0
  149. package/src/plugins/builtin/options-availability.ts +158 -0
  150. package/src/plugins/builtin/options.tsx +364 -0
  151. package/src/plugins/builtin/portfolio-list/header.tsx +227 -0
  152. package/src/plugins/builtin/portfolio-list/index.tsx +99 -0
  153. package/src/plugins/builtin/portfolio-list/metrics.ts +436 -0
  154. package/src/plugins/builtin/portfolio-list/pane.tsx +533 -0
  155. package/src/plugins/builtin/portfolio-list/settings.ts +280 -0
  156. package/src/plugins/builtin/portfolio-list/summary.tsx +270 -0
  157. package/src/plugins/builtin/portfolio-list/table.tsx +64 -0
  158. package/src/plugins/builtin/portfolio-list.test.ts +74 -0
  159. package/src/plugins/builtin/portfolio-list.test.tsx +1164 -0
  160. package/src/plugins/builtin/portfolio-metrics.test.ts +153 -0
  161. package/src/plugins/builtin/quote-monitor.test.tsx +114 -0
  162. package/src/plugins/builtin/sec.tsx +250 -0
  163. package/src/plugins/builtin/ticker-detail/chart-tab.tsx +43 -0
  164. package/src/plugins/builtin/ticker-detail/financials-tab.tsx +390 -0
  165. package/src/plugins/builtin/ticker-detail/index.tsx +80 -0
  166. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +242 -0
  167. package/src/plugins/builtin/ticker-detail/pane.tsx +183 -0
  168. package/src/plugins/builtin/ticker-detail/quote-monitor.tsx +83 -0
  169. package/src/plugins/builtin/ticker-detail/settings.ts +132 -0
  170. package/src/plugins/builtin/ticker-detail-chart-tab-switch.test.tsx +193 -0
  171. package/src/plugins/builtin/ticker-detail.test.tsx +578 -0
  172. package/src/plugins/builtin/yahoo.ts +18 -0
  173. package/src/plugins/event-bus.ts +37 -0
  174. package/src/plugins/ibkr/__snapshots__/trade-tab.test.tsx.snap +35 -0
  175. package/src/plugins/ibkr/account-cache.test.ts +101 -0
  176. package/src/plugins/ibkr/account-cache.ts +137 -0
  177. package/src/plugins/ibkr/broker-adapter.ts +168 -0
  178. package/src/plugins/ibkr/config.test.ts +68 -0
  179. package/src/plugins/ibkr/config.ts +262 -0
  180. package/src/plugins/ibkr/dialogs.tsx +83 -0
  181. package/src/plugins/ibkr/flex.test.ts +107 -0
  182. package/src/plugins/ibkr/flex.ts +267 -0
  183. package/src/plugins/ibkr/fundamental-parser.ts +149 -0
  184. package/src/plugins/ibkr/gateway-helpers.ts +28 -0
  185. package/src/plugins/ibkr/gateway-selection.ts +51 -0
  186. package/src/plugins/ibkr/gateway-service.test.ts +450 -0
  187. package/src/plugins/ibkr/gateway-service.ts +2228 -0
  188. package/src/plugins/ibkr/index.test.tsx +183 -0
  189. package/src/plugins/ibkr/index.tsx +153 -0
  190. package/src/plugins/ibkr/instance-selection.test.ts +121 -0
  191. package/src/plugins/ibkr/instance-selection.ts +36 -0
  192. package/src/plugins/ibkr/price-normalization.test.ts +38 -0
  193. package/src/plugins/ibkr/price-normalization.ts +59 -0
  194. package/src/plugins/ibkr/trade-badge.tsx +27 -0
  195. package/src/plugins/ibkr/trade-tab.test.tsx +225 -0
  196. package/src/plugins/ibkr/trade-tab.tsx +1050 -0
  197. package/src/plugins/ibkr/trade-utils.test.ts +175 -0
  198. package/src/plugins/ibkr/trade-utils.ts +149 -0
  199. package/src/plugins/ibkr/trading-pane.tsx +438 -0
  200. package/src/plugins/ibkr/trading-state.test.ts +109 -0
  201. package/src/plugins/ibkr/trading-state.ts +339 -0
  202. package/src/plugins/loader.ts +71 -0
  203. package/src/plugins/pane-manager.test.ts +103 -0
  204. package/src/plugins/pane-manager.ts +974 -0
  205. package/src/plugins/plugin-persistence.ts +85 -0
  206. package/src/plugins/plugin-runtime.test.tsx +185 -0
  207. package/src/plugins/plugin-runtime.tsx +175 -0
  208. package/src/plugins/prediction-markets/cache.ts +114 -0
  209. package/src/plugins/prediction-markets/categories.ts +223 -0
  210. package/src/plugins/prediction-markets/chart.tsx +512 -0
  211. package/src/plugins/prediction-markets/columns.ts +133 -0
  212. package/src/plugins/prediction-markets/controller-data.ts +614 -0
  213. package/src/plugins/prediction-markets/controller.ts +725 -0
  214. package/src/plugins/prediction-markets/detail/book.tsx +118 -0
  215. package/src/plugins/prediction-markets/detail/outcomes.tsx +102 -0
  216. package/src/plugins/prediction-markets/detail/overview.tsx +73 -0
  217. package/src/plugins/prediction-markets/detail/pane.tsx +308 -0
  218. package/src/plugins/prediction-markets/detail/rules.tsx +16 -0
  219. package/src/plugins/prediction-markets/detail/shared.tsx +29 -0
  220. package/src/plugins/prediction-markets/detail/trades.tsx +30 -0
  221. package/src/plugins/prediction-markets/detail.test.tsx +47 -0
  222. package/src/plugins/prediction-markets/index.tsx +102 -0
  223. package/src/plugins/prediction-markets/keyboard.ts +64 -0
  224. package/src/plugins/prediction-markets/launch.test.ts +126 -0
  225. package/src/plugins/prediction-markets/launch.ts +240 -0
  226. package/src/plugins/prediction-markets/metrics.ts +311 -0
  227. package/src/plugins/prediction-markets/navigation.ts +90 -0
  228. package/src/plugins/prediction-markets/outcome-order.ts +19 -0
  229. package/src/plugins/prediction-markets/pane.test.tsx +425 -0
  230. package/src/plugins/prediction-markets/pane.tsx +294 -0
  231. package/src/plugins/prediction-markets/plugin.test.tsx +570 -0
  232. package/src/plugins/prediction-markets/rows.ts +229 -0
  233. package/src/plugins/prediction-markets/services/fetch.ts +97 -0
  234. package/src/plugins/prediction-markets/services/kalshi-adapter.ts +555 -0
  235. package/src/plugins/prediction-markets/services/polymarket-adapter.ts +660 -0
  236. package/src/plugins/prediction-markets/services/polymarket-ws.ts +108 -0
  237. package/src/plugins/prediction-markets/settings.ts +164 -0
  238. package/src/plugins/prediction-markets/status.ts +24 -0
  239. package/src/plugins/prediction-markets/table.tsx +84 -0
  240. package/src/plugins/prediction-markets/test-helpers.tsx +636 -0
  241. package/src/plugins/prediction-markets/types.ts +186 -0
  242. package/src/plugins/registry.ts +633 -0
  243. package/src/sources/exchange-rates.ts +18 -0
  244. package/src/sources/gloomberb-cloud.test.ts +199 -0
  245. package/src/sources/gloomberb-cloud.ts +326 -0
  246. package/src/sources/provider-errors.ts +19 -0
  247. package/src/sources/provider-router.test.ts +1476 -0
  248. package/src/sources/provider-router.ts +1405 -0
  249. package/src/sources/sec-edgar.test.ts +286 -0
  250. package/src/sources/sec-edgar.ts +526 -0
  251. package/src/sources/yahoo-finance.test.ts +14 -0
  252. package/src/sources/yahoo-finance.ts +1017 -0
  253. package/src/state/app-activity.test.ts +41 -0
  254. package/src/state/app-activity.ts +106 -0
  255. package/src/state/app-bootstrap.test.ts +471 -0
  256. package/src/state/app-bootstrap.ts +308 -0
  257. package/src/state/app-context.test.ts +406 -0
  258. package/src/state/app-context.test.tsx +132 -0
  259. package/src/state/app-context.tsx +969 -0
  260. package/src/state/selectors.ts +67 -0
  261. package/src/state/session-persistence.test.ts +128 -0
  262. package/src/state/session-persistence.ts +161 -0
  263. package/src/state/ticker-refresh-queue.test.ts +46 -0
  264. package/src/state/ticker-refresh-queue.ts +40 -0
  265. package/src/state/use-inline-tickers.ts +174 -0
  266. package/src/state/use-quote-streaming.test.ts +37 -0
  267. package/src/state/use-quote-streaming.test.tsx +70 -0
  268. package/src/state/use-quote-streaming.ts +80 -0
  269. package/src/state/use-session-snapshot.ts +84 -0
  270. package/src/test-support/data-provider.ts +22 -0
  271. package/src/theme/color-utils.ts +67 -0
  272. package/src/theme/colors.ts +128 -0
  273. package/src/theme/themes.test.ts +45 -0
  274. package/src/theme/themes.ts +491 -0
  275. package/src/types/broker.ts +105 -0
  276. package/src/types/config.ts +434 -0
  277. package/src/types/data-provider.ts +81 -0
  278. package/src/types/financials.ts +142 -0
  279. package/src/types/instrument.ts +29 -0
  280. package/src/types/persistence.ts +21 -0
  281. package/src/types/plugin.ts +354 -0
  282. package/src/types/ticker.ts +58 -0
  283. package/src/types/trading.ts +85 -0
  284. package/src/updater.test.ts +162 -0
  285. package/src/updater.ts +247 -0
  286. package/src/utils/api-client.ts +666 -0
  287. package/src/utils/ascii-chart.ts +172 -0
  288. package/src/utils/broker-instances.ts +47 -0
  289. package/src/utils/cli-output.ts +83 -0
  290. package/src/utils/currency-units.test.ts +49 -0
  291. package/src/utils/currency-units.ts +82 -0
  292. package/src/utils/debug-log.ts +133 -0
  293. package/src/utils/exchange-rate-map.ts +8 -0
  294. package/src/utils/format.ts +158 -0
  295. package/src/utils/fuzzy-search.ts +34 -0
  296. package/src/utils/market-status.ts +95 -0
  297. package/src/utils/options.ts +86 -0
  298. package/src/utils/price-history.ts +39 -0
  299. package/src/utils/quote-time.test.ts +22 -0
  300. package/src/utils/quote-time.ts +50 -0
  301. package/src/utils/sec.test.ts +55 -0
  302. package/src/utils/sec.ts +45 -0
  303. package/src/utils/ticker-list.test.ts +22 -0
  304. package/src/utils/ticker-list.ts +35 -0
  305. package/src/utils/ticker-metadata.ts +51 -0
  306. package/src/utils/ticker-search.test.ts +227 -0
  307. package/src/utils/ticker-search.ts +764 -0
  308. package/src/utils/ticker-tokenizer.test.ts +48 -0
  309. package/src/utils/ticker-tokenizer.ts +72 -0
  310. package/src/version.ts +1 -0
  311. package/install.mjs +0 -69
package/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gloomberb Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ When using this software in a product or service, attribution to the Gloomberb
16
+ project (https://github.com/vincelwt/gloomberb) is appreciated and encouraged,
17
+ though not legally required beyond preserving the above copyright notice.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
package/README.md CHANGED
@@ -1,152 +1,99 @@
1
- # Gloomberb Terminal
1
+ <div align="center">
2
2
 
3
- A Bloomberg-inspired stock portfolio tracker for your terminal. Built with [OpenTUI](https://github.com/msmps/opentui) + React + Bun.
3
+ # 📉 Gloomberb
4
4
 
5
- ```
6
- +--[ GLOOMBERB TERMINAL ]----------[ 15:42:03 ]--[ USD ]--+
7
- | | |
8
- | [Main Portfolio|Tech WL] | [Overview|Financials|Chart] |
9
- | -------------------------| |
10
- | TICKER PRICE CHG% PE | AAPL - Apple Inc. |
11
- | AAPL $189.50 +1.2% 29 | Price: $189.50 (+$2.24) |
12
- |>MSFT $420.10 -0.3% 35 | ▁▂▃▄▅▆▅▄▅▆▇▆▅▆▇▆▅▆▇█▇▆▇ |
13
- | GOOGL $175.80 +0.8% 25 | MCap: $2.91T P/E: 29.1 |
14
- | NVDA $875.30 +2.1% 62 | Revenue: $391B FCF: $112B |
15
- +---[ Ctrl+P search | Tab switch | q quit ]---------------+
16
- ```
5
+ **Extensible financial terminal, for the terminal.**
17
6
 
18
- ## Features
7
+ > Why pay for Bloomberg when you can have Gloomberb?
19
8
 
20
- - **Two-panel Bloomberg layout** with amber-on-black theme
21
- - **Yahoo Finance integration** for real-time quotes, fundamentals, and 5-year price history
22
- - **Markdown-based storage** - one `.md` file per ticker with YAML frontmatter, perfect for LLM agents
23
- - **Multiple portfolios & watchlists** with configurable columns
24
- - **Plugin architecture** - everything is a plugin, including core panes and broker integrations
25
- - **Prefix command bar** (`Ctrl+P`) for fast keyboard-driven workflow
26
- - **Multi-currency** support with cached exchange rates
27
- - **ASCII stock charts** using braille characters with price/time axes
28
- - **Editable notes** per ticker, saved to markdown
29
- - **Interactive Brokers** integration via Flex Queries
30
- - **Local-first** - all data stays on your machine (SQLite cache + markdown files)
9
+ <img src="https://gloomberb.com/landing-terminal.png" alt="Gloomberb terminal screenshot" width="720" />
31
10
 
32
- ## Quick Start
11
+ </div>
33
12
 
34
- ```bash
35
- # Install dependencies
36
- bun install
37
-
38
- # Run
39
- bun dev
40
- ```
13
+ ## ✨ Features
41
14
 
42
- On first launch, data is stored in `~/gloomberb-data/`. Each ticker gets its own markdown file:
15
+ - **Track portfolios & trade**
16
+ - **Real-time quotes & fundamentals**
17
+ - **Beautiful high-rez charts**
18
+ - **Fast & keyboard-driven**
19
+ - **Powerful layouts**
20
+ - **Extensible**
21
+ - **100% local**
43
22
 
44
- ```markdown
45
- ---
46
- ticker: AAPL
47
- exchange: NASDAQ
48
- currency: USD
49
- name: Apple Inc.
50
- sector: Technology
51
- portfolios:
52
- - main
53
- watchlists:
54
- - tech
55
- ---
23
+ For the best experience, use a [Kitty](https://sw.kovidgoyal.net/kitty/)-compatible terminal such as Ghostty, Kitty or WezTerm.
56
24
 
57
- ## Notes
25
+ ## 🚀 Install
58
26
 
59
- Strong services growth. Watch for Vision Pro adoption.
27
+ ```bash
28
+ bun install -g gloomberb
29
+ # or
30
+ curl -fsSL gloomberb.com/install | bash
60
31
  ```
61
32
 
62
- ## Keyboard Shortcuts
33
+ Then run `gloomberb` to start.
63
34
 
64
- | Key | Action |
65
- |-----|--------|
66
- | `Ctrl+P` or `` ` `` | Open command bar |
67
- | `Tab` | Switch between left/right panels |
68
- | `j` / `k` | Navigate ticker list |
69
- | `h` / `l` | Switch tabs |
70
- | `r` | Refresh selected ticker |
71
- | `Shift+R` | Refresh all tickers |
72
- | `Ctrl+,` | Open settings |
73
- | `q` | Quit |
35
+ When developing from source, launch with a real Bun runtime, for example `bun src/index.tsx`.
36
+ If `bun --help` prints Gloomberb help instead of Bun help, your Bun binary has been overwritten and needs to be reinstalled.
37
+ In-app self-updates are disabled while running from source so Gloomberb does not replace the Bun executable.
74
38
 
75
- ## Command Bar Prefixes
39
+ ## 🧩 Plugins
76
40
 
77
- The command bar uses a prefix system for fast actions:
41
+ Gloomberb has a plugin architecture where everything, from the portfolio list to broker integrations, is a plugin.
78
42
 
79
- | Prefix | Action |
80
- |--------|--------|
81
- | `T <query>` | Search Yahoo Finance for a ticker |
82
- | `AW` | Add current ticker to watchlist |
83
- | `AP` | Add current ticker to portfolio |
84
- | `RW` | Remove from watchlist |
85
- | `RP` | Remove from portfolio |
86
- | `NP` | New portfolio |
87
- | `NW` | New watchlist |
88
- | `R` | Refresh current ticker |
89
- | `RA` | Refresh all |
90
- | `IB` | Import from Interactive Brokers |
91
- | `S` | Open settings |
43
+ Plugins can add tabs, columns, commands, status bar widgets, and more.
92
44
 
93
- ## Architecture
45
+ See **[PLUGINS.md](PLUGINS.md)** for the plugin API and the shared UI surface available through `gloomberb/components`.
94
46
 
95
- Everything is a plugin. Core features use the same `GloomPlugin` interface as external extensions.
47
+ ### Core plugins
96
48
 
97
- ```
98
- src/
99
- plugins/
100
- registry.ts # OpenTUI slot-based plugin system
101
- pane-manager.ts # Customizable pane layout
102
- builtin/
103
- portfolio-list.tsx # Left pane (portfolios + watchlists)
104
- ticker-detail.tsx # Right pane (overview, financials, chart, notes)
105
- ibkr-flex.tsx # IBKR Flex Query broker plugin
106
- manual-entry.tsx # Manual position entry
107
- sources/
108
- yahoo-finance.ts # Yahoo Finance client with retry + caching
109
- data/
110
- markdown-store.ts # Ticker markdown file read/write
111
- sqlite-cache.ts # Bun SQLite cache for Yahoo data
112
- ```
49
+ | Plugin | Description |
50
+ |--------|-------------|
51
+ | **Portfolio List** | Main ticker list with portfolios & watchlists |
52
+ | **Ticker Detail** | Overview, financials, and chart tabs |
53
+ | **News** | View latest news for each ticker (via Yahoo Finance) |
54
+ | **SEC** | View recent SEC filings for supported US equities |
55
+ | **Notes** | Write and save markdown notes, stored locally |
56
+ | **Options** | View US equity options chains |
57
+ | **AI** | Keep an Ask AI detail tab for tickers and create prompt-driven AI screener panes |
58
+ | **Compare Charts** | Compare multiple ticker charts overlaid on one shared chart |
59
+ | **X Scanner** | WIP |
60
+ | **Alerts** | WIP |
61
+ | **Scanner** | WIP |
113
62
 
114
- ### Plugin Slots
63
+ #### AI plugin
115
64
 
116
- Plugins can extend the UI through defined slots:
65
+ - The ticker detail pane keeps its `Ask AI` tab for per-company questions.
66
+ - The `AI Screener` pane lets you create multiple prompt-based screening tabs, refresh them, force reruns, edit the prompt, and review the last run time.
67
+ - Use the `AI <prompt>` shortcut from the command bar to open a new screener pane seeded with a prompt.
117
68
 
118
- - `detail:tab` / `detail:section` - Add tabs or sections to the detail pane
119
- - `list:column` - Custom columns in the ticker list
120
- - `command:extra` / `command:preset` - Extend the command bar
121
- - `status:widget` - Status bar widgets
122
- - `config:section` - Settings page sections
123
- - `data:post-refresh` / `data:enricher` - Hook into data lifecycle
69
+ ### Data providers
124
70
 
125
- ### Planned Plugins
71
+ | Provider | Description |
72
+ |----------|-------------|
73
+ | **Gloomberb Cloud** | Real-time data (recommended, free) |
74
+ | **Yahoo Finance** | Delayed data, rate-limiting |
126
75
 
127
- - News feed pane
128
- - Chat component
129
- - Option chain viewer
130
- - Analyst ratings
131
- - Tweet/social scanner
132
- - Crypto feeds
133
- - Custom columns (conviction score, etc.)
134
- - Live stock feeds
76
+ ### Brokers connectors
135
77
 
136
- ## Data Storage
78
+ | Plugin | Description |
79
+ |--------|-------------|
80
+ | **IBKR** | Import positions from Flex Query or trade with Gateway API. |
81
+ | **Manual Entry** | Manually add positions, saved locally |
137
82
 
138
- | Data | Storage | Why |
139
- |------|---------|-----|
140
- | Ticker metadata, positions, notes | Markdown files | Agent-readable, version-controllable |
141
- | Yahoo Finance cache | SQLite (`bun:sqlite`) | Fast TTL-based lookup |
142
- | Exchange rates | SQLite | Cached with 1hr TTL |
143
- | Price history | SQLite | Large dataset, bad fit for markdown |
144
- | App config | `config.json` | User settings |
83
+ Toggleable plugins can be enabled/disabled from the command bar screen (`Ctrl+p`).
145
84
 
146
- ## Requirements
85
+ ## ⌨️ Keyboard Shortcuts
147
86
 
148
- - [Bun](https://bun.sh) runtime
149
- - A terminal with true color support
87
+ | Key | Action |
88
+ |-----|--------|
89
+ | `Ctrl+P` or `` ` `` | Open command bar |
90
+ | `Ctrl+x` | Close current window |
91
+ | `Tab` | Switch between panels |
92
+ `j` / `k` | Navigate ticker list |
93
+ | `h` / `l` | Switch tabs |
94
+ | `Ctrl+,` | Open settings |
95
+ | `m` | Cycle chart mode in the chart tab |
96
+ | `q` | Quit |
150
97
 
151
98
  ## License
152
99
 
package/bin/gloomberb ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import "../src/index.tsx"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gloomberb",
3
- "version": "0.1.0",
3
+ "version": "0.3.1",
4
4
  "description": "Bloomberg-style stock portfolio tracker for the terminal",
5
5
  "module": "src/index.tsx",
6
6
  "type": "module",
@@ -9,13 +9,16 @@
9
9
  },
10
10
  "files": [
11
11
  "bin",
12
- "install.mjs"
12
+ "src",
13
+ "patches"
13
14
  ],
14
15
  "scripts": {
15
16
  "dev": "bun run --watch src/index.tsx",
17
+ "start": "bun src/index.tsx",
16
18
  "build": "bun run scripts/build.ts",
17
19
  "build:all": "bun run scripts/build.ts --all",
18
- "postinstall": "node install.mjs"
20
+ "test": "bun test",
21
+ "release": "./scripts/release.sh"
19
22
  },
20
23
  "license": "MIT",
21
24
  "repository": {
@@ -38,10 +41,16 @@
38
41
  },
39
42
  "dependencies": {
40
43
  "@opentui-ui/dialog": "^0.1.2",
44
+ "@opentui-ui/toast": "^0.0.5",
41
45
  "@opentui/core": "^0.1.90",
42
46
  "@opentui/react": "^0.1.90",
47
+ "@stoqey/ib": "^1.5.3",
43
48
  "gray-matter": "^4.0.3",
49
+ "opentui-spinner": "^0.0.6",
44
50
  "react": "^19.2.4",
45
51
  "yahoo-finance2": "^3.13.2"
52
+ },
53
+ "patchedDependencies": {
54
+ "@opentui/core@0.1.90": "patches/@opentui%2Fcore@0.1.90.patch"
46
55
  }
47
- }
56
+ }
@@ -0,0 +1,356 @@
1
+ diff --git a/index-e89anq5x.js b/index-e89anq5x.js
2
+ index e3b6cf9..14a46d7 100644
3
+ --- a/index-e89anq5x.js
4
+ +++ b/index-e89anq5x.js
5
+ @@ -6328,17 +6328,27 @@ class MouseParser {
6
+ const buf = Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
7
+ return buf.toString("latin1");
8
+ }
9
+ - parseMouseEvent(data) {
10
+ + projectPixelToCell(pixel, pixelExtent, cellCount) {
11
+ + if (cellCount <= 1) {
12
+ + return 0;
13
+ + }
14
+ + if (!(pixelExtent > 0)) {
15
+ + return Math.max(Math.floor(pixel), 0);
16
+ + }
17
+ + const projected = Math.floor(Math.max(pixel, 0) * cellCount / pixelExtent);
18
+ + return Math.max(0, Math.min(projected, cellCount - 1));
19
+ + }
20
+ + parseMouseEvent(data, context = void 0) {
21
+ const str = this.decodeInput(data);
22
+ - const parsed = this.parseMouseSequenceAt(str, 0);
23
+ + const parsed = this.parseMouseSequenceAt(str, 0, context);
24
+ return parsed?.event ?? null;
25
+ }
26
+ - parseAllMouseEvents(data) {
27
+ + parseAllMouseEvents(data, context = void 0) {
28
+ const str = this.decodeInput(data);
29
+ const events = [];
30
+ let offset = 0;
31
+ while (offset < str.length) {
32
+ - const parsed = this.parseMouseSequenceAt(str, offset);
33
+ + const parsed = this.parseMouseSequenceAt(str, offset, context);
34
+ if (!parsed) {
35
+ break;
36
+ }
37
+ @@ -6347,19 +6357,19 @@ class MouseParser {
38
+ }
39
+ return events;
40
+ }
41
+ - parseMouseSequenceAt(str, offset) {
42
+ + parseMouseSequenceAt(str, offset, context = void 0) {
43
+ if (!str.startsWith("\x1B[", offset))
44
+ return null;
45
+ const introducer = str[offset + 2];
46
+ if (introducer === "<") {
47
+ - return this.parseSgrSequence(str, offset);
48
+ + return this.parseSgrSequence(str, offset, context);
49
+ }
50
+ if (introducer === "M") {
51
+ return this.parseBasicSequence(str, offset);
52
+ }
53
+ return null;
54
+ }
55
+ - parseSgrSequence(str, offset) {
56
+ + parseSgrSequence(str, offset, context = void 0) {
57
+ let index = offset + 3;
58
+ const values = [0, 0, 0];
59
+ let part = 0;
60
+ @@ -6387,7 +6397,7 @@ class MouseParser {
61
+ if (!hasDigit || part !== 2)
62
+ return null;
63
+ return {
64
+ - event: this.decodeSgrEvent(values[0], values[1], values[2], char),
65
+ + event: this.decodeSgrEvent(values[0], values[1], values[2], char, context),
66
+ consumed: index - offset + 1
67
+ };
68
+ }
69
+ @@ -6408,7 +6418,7 @@ class MouseParser {
70
+ consumed: 6
71
+ };
72
+ }
73
+ - decodeSgrEvent(rawButtonCode, wireX, wireY, pressRelease) {
74
+ + decodeSgrEvent(rawButtonCode, wireX, wireY, pressRelease, context = void 0) {
75
+ const button = rawButtonCode & 3;
76
+ const isScroll = (rawButtonCode & 64) !== 0;
77
+ const scrollDirection = !isScroll ? undefined : MouseParser.SCROLL_DIRECTIONS[button];
78
+ @@ -6443,11 +6453,26 @@ class MouseParser {
79
+ this.mouseButtonsPressed.clear();
80
+ }
81
+ }
82
+ + const pixelModeRequested = context?.mouseUsesPixels === true;
83
+ + const pixelModeConfirmed = context?.mousePixelsConfirmed === true;
84
+ + const pixelModeDetected = pixelModeRequested && (
85
+ + pixelModeConfirmed ||
86
+ + wireX > (context?.terminalWidth ?? Number.POSITIVE_INFINITY) ||
87
+ + wireY > (context?.terminalHeight ?? Number.POSITIVE_INFINITY)
88
+ + );
89
+ + const pixelX = pixelModeDetected ? Math.max(wireX - 1, 0) : void 0;
90
+ + const pixelY = pixelModeDetected ? Math.max(wireY - 1, 0) : void 0;
91
+ return {
92
+ type,
93
+ button: button === 3 ? 0 : button,
94
+ - x: wireX - 1,
95
+ - y: wireY - 1,
96
+ + x: pixelModeDetected && pixelX !== void 0
97
+ + ? this.projectPixelToCell(pixelX, context?.pixelWidth ?? 0, context?.terminalWidth ?? 0)
98
+ + : wireX - 1,
99
+ + y: pixelModeDetected && pixelY !== void 0
100
+ + ? this.projectPixelToCell(pixelY, context?.pixelHeight ?? 0, context?.terminalHeight ?? 0)
101
+ + : wireY - 1,
102
+ + pixelX,
103
+ + pixelY,
104
+ modifiers,
105
+ scroll: scrollInfo
106
+ };
107
+ @@ -6856,7 +6881,13 @@ var DEFAULT_PROTOCOL_CONTEXT = {
108
+ kittyKeyboardEnabled: false,
109
+ privateCapabilityRepliesActive: false,
110
+ pixelResolutionQueryActive: false,
111
+ - explicitWidthCprActive: false
112
+ + explicitWidthCprActive: false,
113
+ + mouseUsesPixels: false,
114
+ + mousePixelsConfirmed: false,
115
+ + terminalWidth: 0,
116
+ + terminalHeight: 0,
117
+ + pixelWidth: 0,
118
+ + pixelHeight: 0
119
+ };
120
+ var RXVT_DOLLAR_CSI_RE = /^\x1b\[\d+\$$/;
121
+ var SYSTEM_CLOCK = new SystemClock;
122
+ @@ -7149,7 +7180,13 @@ class StdinParser {
123
+ kittyKeyboardEnabled: options.protocolContext?.kittyKeyboardEnabled ?? false,
124
+ privateCapabilityRepliesActive: options.protocolContext?.privateCapabilityRepliesActive ?? false,
125
+ pixelResolutionQueryActive: options.protocolContext?.pixelResolutionQueryActive ?? false,
126
+ - explicitWidthCprActive: options.protocolContext?.explicitWidthCprActive ?? false
127
+ + explicitWidthCprActive: options.protocolContext?.explicitWidthCprActive ?? false,
128
+ + mouseUsesPixels: options.protocolContext?.mouseUsesPixels ?? false,
129
+ + mousePixelsConfirmed: options.protocolContext?.mousePixelsConfirmed ?? false,
130
+ + terminalWidth: options.protocolContext?.terminalWidth ?? 0,
131
+ + terminalHeight: options.protocolContext?.terminalHeight ?? 0,
132
+ + pixelWidth: options.protocolContext?.pixelWidth ?? 0,
133
+ + pixelHeight: options.protocolContext?.pixelHeight ?? 0
134
+ };
135
+ }
136
+ get bufferCapacity() {
137
+ @@ -7952,11 +7989,14 @@ class StdinParser {
138
+ });
139
+ }
140
+ emitMouse(rawBytes, encoding) {
141
+ - const event = this.mouseParser.parseMouseEvent(rawBytes);
142
+ + const event = this.mouseParser.parseMouseEvent(rawBytes, this.protocolContext);
143
+ if (!event) {
144
+ this.emitOpaqueResponse("unknown", rawBytes);
145
+ return;
146
+ }
147
+ + if (event.pixelX !== void 0 && event.pixelY !== void 0 && !this.protocolContext.mousePixelsConfirmed) {
148
+ + this.updateProtocolContext({ mousePixelsConfirmed: true });
149
+ + }
150
+ this.events.push({
151
+ type: "mouse",
152
+ raw: decodeLatin1(rawBytes),
153
+ @@ -17295,6 +17335,8 @@ class MouseEvent {
154
+ button;
155
+ x;
156
+ y;
157
+ + pixelX;
158
+ + pixelY;
159
+ source;
160
+ modifiers;
161
+ scroll;
162
+ @@ -17314,6 +17356,8 @@ class MouseEvent {
163
+ this.button = attributes.button;
164
+ this.x = attributes.x;
165
+ this.y = attributes.y;
166
+ + this.pixelX = attributes.pixelX;
167
+ + this.pixelY = attributes.pixelY;
168
+ this.modifiers = attributes.modifiers;
169
+ this.scroll = attributes.scroll;
170
+ this.source = attributes.source;
171
+ @@ -17479,6 +17523,8 @@ class CliRenderer extends EventEmitter8 {
172
+ resizeDebounceDelay = 100;
173
+ enableMouseMovement = false;
174
+ _useMouse = true;
175
+ + _mouseProtocolSignature = "disabled";
176
+ + _pixelMouseEnabled = false;
177
+ autoFocus = true;
178
+ _useAlternateScreen = env.OTUI_USE_ALTERNATE_SCREEN;
179
+ _suspendedMouseEnabled = false;
180
+ @@ -17507,7 +17553,7 @@ class CliRenderer extends EventEmitter8 {
181
+ this.handleResize(width, height);
182
+ }).bind(this);
183
+ _capabilities = null;
184
+ - _latestPointer = { x: 0, y: 0 };
185
+ + _latestPointer = { x: 0, y: 0, pixelX: void 0, pixelY: void 0 };
186
+ _hasPointer = false;
187
+ _lastPointerModifiers = { shift: false, alt: false, ctrl: false };
188
+ _currentMousePointerStyle = undefined;
189
+ @@ -17661,7 +17707,13 @@ Captured output:
190
+ kittyKeyboardEnabled: useKittyForParsing,
191
+ privateCapabilityRepliesActive: false,
192
+ pixelResolutionQueryActive: false,
193
+ - explicitWidthCprActive: false
194
+ + explicitWidthCprActive: false,
195
+ + mouseUsesPixels: false,
196
+ + mousePixelsConfirmed: false,
197
+ + terminalWidth: this._terminalWidth,
198
+ + terminalHeight: this._terminalHeight,
199
+ + pixelWidth: 0,
200
+ + pixelHeight: 0
201
+ },
202
+ clock: this.clock
203
+ });
204
+ @@ -17983,12 +18035,14 @@ Captured output:
205
+ enableMouse() {
206
+ this._useMouse = true;
207
+ this.lib.enableMouse(this.rendererPtr, this.enableMouseMovement);
208
+ + this.syncPixelMouseMode();
209
+ }
210
+ disableMouse() {
211
+ this._useMouse = false;
212
+ this.setCapturedRenderable(undefined);
213
+ this.stdinParser?.resetMouseState();
214
+ this.lib.disableMouse(this.rendererPtr);
215
+ + this.disablePixelMouseMode();
216
+ }
217
+ enableKittyKeyboard(flags = 3) {
218
+ this.lib.enableKittyKeyboard(this.rendererPtr, flags);
219
+ @@ -17998,6 +18052,64 @@ Captured output:
220
+ this.lib.disableKittyKeyboard(this.rendererPtr);
221
+ this.updateStdinParserProtocolContext({ kittyKeyboardEnabled: false }, true);
222
+ }
223
+ + getMouseProtocolTrackingMode() {
224
+ + return this.enableMouseMovement ? "any" : "press";
225
+ + }
226
+ + buildMouseProtocolSequence(pixelEnabled) {
227
+ + const trackingSequence = this.enableMouseMovement
228
+ + ? "\x1B[?1000l\x1B[?1002l\x1B[?1003h"
229
+ + : "\x1B[?1003l\x1B[?1002l\x1B[?1000h";
230
+ + return "\x1B[?1005l\x1B[?1015l\x1B[?1006h" + trackingSequence + (pixelEnabled ? "\x1B[?1016h" : "\x1B[?1016l");
231
+ + }
232
+ + syncPixelMouseMode(force = false) {
233
+ + const nextEnabled = Boolean(this._useMouse);
234
+ + const pixelMouseDisabled = typeof process !== "undefined" && process?.env?.GLOOMBERB_DISABLE_PIXEL_MOUSE === "1";
235
+ + const hasPixelCapability = this._capabilities?.sgr_pixels === true;
236
+ + const hasPixelResolution = (this._resolution?.width ?? 0) > 0 && (this._resolution?.height ?? 0) > 0;
237
+ + const nextPixelEnabled = Boolean(
238
+ + nextEnabled &&
239
+ + !pixelMouseDisabled &&
240
+ + hasPixelCapability &&
241
+ + hasPixelResolution &&
242
+ + this._terminalWidth > 0 &&
243
+ + this._terminalHeight > 0
244
+ + );
245
+ + const nextSignature = nextEnabled
246
+ + ? `${this.getMouseProtocolTrackingMode()}:${nextPixelEnabled ? "pixel" : "cell"}`
247
+ + : "disabled";
248
+ + if (nextEnabled) {
249
+ + if (force || this._mouseProtocolSignature !== nextSignature) {
250
+ + this.writeOut(this.buildMouseProtocolSequence(nextPixelEnabled));
251
+ + }
252
+ + } else if (force || this._mouseProtocolSignature !== "disabled") {
253
+ + this.writeOut("\x1B[?1016l\x1B[?1006l\x1B[?1005l\x1B[?1015l\x1B[?1003l\x1B[?1002l\x1B[?1000l");
254
+ + }
255
+ + this._mouseProtocolSignature = nextSignature;
256
+ + this._pixelMouseEnabled = nextPixelEnabled;
257
+ + this.updateStdinParserProtocolContext({
258
+ + mouseUsesPixels: nextPixelEnabled,
259
+ + mousePixelsConfirmed: nextPixelEnabled,
260
+ + terminalWidth: this._terminalWidth,
261
+ + terminalHeight: this._terminalHeight,
262
+ + pixelWidth: this._resolution?.width ?? 0,
263
+ + pixelHeight: this._resolution?.height ?? 0
264
+ + }, true);
265
+ + }
266
+ + disablePixelMouseMode() {
267
+ + if (this._mouseProtocolSignature !== "disabled") {
268
+ + this.writeOut("\x1B[?1016l\x1B[?1006l\x1B[?1005l\x1B[?1015l\x1B[?1003l\x1B[?1002l\x1B[?1000l");
269
+ + }
270
+ + this._mouseProtocolSignature = "disabled";
271
+ + this._pixelMouseEnabled = false;
272
+ + this.updateStdinParserProtocolContext({
273
+ + mouseUsesPixels: false,
274
+ + mousePixelsConfirmed: false,
275
+ + terminalWidth: this._terminalWidth,
276
+ + terminalHeight: this._terminalHeight,
277
+ + pixelWidth: this._resolution?.width ?? 0,
278
+ + pixelHeight: this._resolution?.height ?? 0
279
+ + }, true);
280
+ + }
281
+ set useThread(useThread) {
282
+ this._useThread = useThread;
283
+ this.lib.setUseThread(this.rendererPtr, useThread);
284
+ @@ -18031,6 +18143,7 @@ Captured output:
285
+ if (this._useMouse) {
286
+ this.enableMouse();
287
+ }
288
+ + this.syncPixelMouseMode();
289
+ this.queryPixelResolution();
290
+ }
291
+ stdinListener = ((chunk) => {
292
+ @@ -18070,6 +18183,7 @@ Captured output:
293
+ if (isCapabilityResponse(sequence)) {
294
+ this.lib.processCapabilityResponse(this.rendererPtr, sequence);
295
+ this._capabilities = this.lib.getTerminalCapabilities(this.rendererPtr);
296
+ + this.syncPixelMouseMode();
297
+ this.emit("capabilities" /* CAPABILITIES */, this._capabilities);
298
+ return true;
299
+ }
300
+ @@ -18079,6 +18193,7 @@ Captured output:
301
+ if (sequence === "\x1B[I") {
302
+ if (this.shouldRestoreModesOnNextFocus) {
303
+ this.lib.restoreTerminalModes(this.rendererPtr);
304
+ + this.syncPixelMouseMode(true);
305
+ this.shouldRestoreModesOnNextFocus = false;
306
+ }
307
+ if (this._terminalFocusState !== true) {
308
+ @@ -18187,6 +18302,7 @@ Captured output:
309
+ }
310
+ this.waitingForPixelResolution = false;
311
+ this.updateStdinParserProtocolContext({ pixelResolutionQueryActive: false }, true);
312
+ + this.syncPixelMouseMode();
313
+ return true;
314
+ }
315
+ return false;
316
+ @@ -18221,9 +18337,15 @@ Captured output:
317
+ return false;
318
+ }
319
+ mouseEvent.y -= this.renderOffset;
320
+ + if (mouseEvent.pixelY !== void 0 && this._resolution) {
321
+ + const cellHeight = this._resolution.height / Math.max(this._terminalHeight, 1);
322
+ + mouseEvent.pixelY = Math.max(mouseEvent.pixelY - this.renderOffset * cellHeight, 0);
323
+ + }
324
+ }
325
+ this._latestPointer.x = mouseEvent.x;
326
+ this._latestPointer.y = mouseEvent.y;
327
+ + this._latestPointer.pixelX = mouseEvent.pixelX;
328
+ + this._latestPointer.pixelY = mouseEvent.pixelY;
329
+ this._hasPointer = true;
330
+ this._lastPointerModifiers = mouseEvent.modifiers;
331
+ if (this._console.visible) {
332
+ @@ -18352,6 +18474,8 @@ Captured output:
333
+ button: 0,
334
+ x: this._latestPointer.x,
335
+ y: this._latestPointer.y,
336
+ + pixelX: this._latestPointer.pixelX,
337
+ + pixelY: this._latestPointer.pixelY,
338
+ modifiers: this._lastPointerModifiers
339
+ };
340
+ if (lastOver && !lastOver.isDestroyed) {
341
+ @@ -18435,6 +18559,7 @@ Captured output:
342
+ const prevWidth = this._terminalWidth;
343
+ this._terminalWidth = width;
344
+ this._terminalHeight = height;
345
+ + this.syncPixelMouseMode();
346
+ this.queryPixelResolution();
347
+ this.setCapturedRenderable(undefined);
348
+ this.stdinParser?.resetMouseState();
349
+ @@ -18712,6 +18837,7 @@ Captured output:
350
+ }
351
+ this._isRunning = false;
352
+ this.waitingForPixelResolution = false;
353
+ + this.disablePixelMouseMode();
354
+ this.updateStdinParserProtocolContext({
355
+ privateCapabilityRepliesActive: false,
356
+ pixelResolutionQueryActive: false,