gloomberb 0.2.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 (310) hide show
  1. package/README.md +20 -19
  2. package/bin/gloomberb +3 -0
  3. package/package.json +5 -4
  4. package/patches/@opentui%2Fcore@0.1.90.patch +356 -0
  5. package/src/app.tsx +1330 -0
  6. package/src/brokers/sync-broker-instance.test.ts +100 -0
  7. package/src/brokers/sync-broker-instance.ts +341 -0
  8. package/src/cli/commands/plugins.ts +173 -0
  9. package/src/cli/commands/portfolio.ts +210 -0
  10. package/src/cli/commands/search.ts +120 -0
  11. package/src/cli/commands/ticker.ts +375 -0
  12. package/src/cli/commands/watchlist.ts +210 -0
  13. package/src/cli/context.ts +62 -0
  14. package/src/cli/errors.ts +13 -0
  15. package/src/cli/helpers.ts +85 -0
  16. package/src/cli/index.ts +143 -0
  17. package/src/cli/ticker-resolution.ts +39 -0
  18. package/src/cli/types.ts +15 -0
  19. package/src/cli.test.ts +361 -0
  20. package/src/components/chart/chart-data.ts +239 -0
  21. package/src/components/chart/chart-renderer.ts +1199 -0
  22. package/src/components/chart/chart-types.ts +82 -0
  23. package/src/components/chart/chart-viewport.ts +21 -0
  24. package/src/components/chart/chart.test.ts +439 -0
  25. package/src/components/chart/comparison-chart-data.test.ts +109 -0
  26. package/src/components/chart/comparison-chart-data.ts +316 -0
  27. package/src/components/chart/comparison-chart-renderer.test.ts +84 -0
  28. package/src/components/chart/comparison-chart-renderer.ts +354 -0
  29. package/src/components/chart/comparison-stock-chart.tsx +1486 -0
  30. package/src/components/chart/cursor-motion.ts +48 -0
  31. package/src/components/chart/native/chart-rasterizer.ts +732 -0
  32. package/src/components/chart/native/kitty-adapter.ts +12 -0
  33. package/src/components/chart/native/kitty-manager.ts +142 -0
  34. package/src/components/chart/native/kitty-protocol.ts +110 -0
  35. package/src/components/chart/native/kitty-support.ts +71 -0
  36. package/src/components/chart/native/kitty.test.ts +620 -0
  37. package/src/components/chart/native/renderer-selection.ts +24 -0
  38. package/src/components/chart/native/surface-manager.ts +225 -0
  39. package/src/components/chart/native/surface-sync.ts +34 -0
  40. package/src/components/chart/stock-chart-renderer-switch.test.tsx +165 -0
  41. package/src/components/chart/stock-chart.test.ts +107 -0
  42. package/src/components/chart/stock-chart.tsx +1556 -0
  43. package/src/components/command-bar/__snapshots__/command-bar.test.tsx.snap +137 -0
  44. package/src/components/command-bar/command-bar.test.tsx +1524 -0
  45. package/src/components/command-bar/command-bar.tsx +4823 -0
  46. package/src/components/command-bar/command-registry.ts +261 -0
  47. package/src/components/command-bar/helpers.test.ts +224 -0
  48. package/src/components/command-bar/helpers.ts +371 -0
  49. package/src/components/command-bar/root-shortcuts.ts +158 -0
  50. package/src/components/command-bar/view-model.test.ts +152 -0
  51. package/src/components/command-bar/view-model.ts +185 -0
  52. package/src/components/command-bar/workflow-ops.test.ts +70 -0
  53. package/src/components/command-bar/workflow-ops.ts +433 -0
  54. package/src/components/command-bar/workflow-types.ts +127 -0
  55. package/src/components/detail-feed-view.test.tsx +105 -0
  56. package/src/components/detail-feed-view.tsx +295 -0
  57. package/src/components/index.ts +32 -0
  58. package/src/components/layout/floating-pane.tsx +49 -0
  59. package/src/components/layout/header.tsx +129 -0
  60. package/src/components/layout/pane-header.tsx +44 -0
  61. package/src/components/layout/pane.tsx +49 -0
  62. package/src/components/layout/pixel-mouse-mode.test.ts +122 -0
  63. package/src/components/layout/pixel-mouse.test.ts +40 -0
  64. package/src/components/layout/shell.test.tsx +625 -0
  65. package/src/components/layout/shell.tsx +1200 -0
  66. package/src/components/layout/status-bar.test.tsx +173 -0
  67. package/src/components/layout/status-bar.tsx +138 -0
  68. package/src/components/markdown-editor.tsx +134 -0
  69. package/src/components/onboarding/onboarding-wizard.test.tsx +184 -0
  70. package/src/components/onboarding/onboarding-wizard.tsx +1365 -0
  71. package/src/components/pane-settings-dialog.tsx +468 -0
  72. package/src/components/pane-template-wizard.test.tsx +52 -0
  73. package/src/components/pane-template-wizard.tsx +199 -0
  74. package/src/components/price-selector-dialog.tsx +195 -0
  75. package/src/components/spinner.tsx +2 -0
  76. package/src/components/tab-bar.tsx +17 -0
  77. package/src/components/ticker-badge-text.test.tsx +160 -0
  78. package/src/components/ticker-badge-text.tsx +58 -0
  79. package/src/components/ticker-badge.tsx +88 -0
  80. package/src/components/ticker-list-table.tsx +188 -0
  81. package/src/components/toggle-list.tsx +74 -0
  82. package/src/components/ui/button.tsx +77 -0
  83. package/src/components/ui/data-table.tsx +210 -0
  84. package/src/components/ui/external-link.tsx +22 -0
  85. package/src/components/ui/fields.tsx +187 -0
  86. package/src/components/ui/frame.tsx +73 -0
  87. package/src/components/ui/index.ts +53 -0
  88. package/src/components/ui/list-view.tsx +166 -0
  89. package/src/components/ui/loading.tsx +70 -0
  90. package/src/components/ui/status.tsx +83 -0
  91. package/src/components/ui/tabs.tsx +47 -0
  92. package/src/components/ui/toggle.tsx +164 -0
  93. package/src/components/ui/ui.test.tsx +134 -0
  94. package/src/data/app-persistence.ts +25 -0
  95. package/src/data/config-store.test.ts +310 -0
  96. package/src/data/config-store.ts +469 -0
  97. package/src/data/plugin-state-store.ts +102 -0
  98. package/src/data/resource-store.ts +323 -0
  99. package/src/data/session-store.ts +52 -0
  100. package/src/data/sqlite-cache.test.ts +103 -0
  101. package/src/data/sqlite-database.ts +62 -0
  102. package/src/data/sqlite-json.ts +19 -0
  103. package/src/data/ticker-repository.ts +45 -0
  104. package/src/data/ticker-store.ts +46 -0
  105. package/src/index.tsx +67 -0
  106. package/src/market-data/coordinator.test.ts +369 -0
  107. package/src/market-data/coordinator.ts +580 -0
  108. package/src/market-data/hooks.tsx +234 -0
  109. package/src/market-data/query-store.ts +28 -0
  110. package/src/market-data/request-types.test.ts +64 -0
  111. package/src/market-data/request-types.ts +70 -0
  112. package/src/market-data/result-types.ts +56 -0
  113. package/src/market-data/selectors.ts +166 -0
  114. package/src/market-data/trace.ts +7 -0
  115. package/src/pane-settings.test.ts +71 -0
  116. package/src/pane-settings.ts +73 -0
  117. package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +338 -0
  118. package/src/plugins/builtin/ai/gloomberb-cli.ts +70 -0
  119. package/src/plugins/builtin/ai/index.test.tsx +139 -0
  120. package/src/plugins/builtin/ai/index.tsx +86 -0
  121. package/src/plugins/builtin/ai/providers.ts +99 -0
  122. package/src/plugins/builtin/ai/runner.ts +82 -0
  123. package/src/plugins/builtin/ai/screener-contract.test.ts +117 -0
  124. package/src/plugins/builtin/ai/screener-contract.ts +174 -0
  125. package/src/plugins/builtin/ai/screener-pane.test.tsx +365 -0
  126. package/src/plugins/builtin/ai/screener-pane.tsx +1161 -0
  127. package/src/plugins/builtin/ai/settings.ts +79 -0
  128. package/src/plugins/builtin/ai/ticker-context.ts +64 -0
  129. package/src/plugins/builtin/ai/utils.ts +71 -0
  130. package/src/plugins/builtin/ask-ai.test.tsx +258 -0
  131. package/src/plugins/builtin/ask-ai.tsx +9 -0
  132. package/src/plugins/builtin/chat-controller.test.ts +217 -0
  133. package/src/plugins/builtin/chat-controller.ts +340 -0
  134. package/src/plugins/builtin/chat.test.tsx +451 -0
  135. package/src/plugins/builtin/chat.tsx +620 -0
  136. package/src/plugins/builtin/comparison-chart.test.tsx +277 -0
  137. package/src/plugins/builtin/comparison-chart.tsx +169 -0
  138. package/src/plugins/builtin/data-providers.ts +16 -0
  139. package/src/plugins/builtin/debug.tsx +351 -0
  140. package/src/plugins/builtin/help.test.tsx +110 -0
  141. package/src/plugins/builtin/help.tsx +281 -0
  142. package/src/plugins/builtin/layout-manager.tsx +264 -0
  143. package/src/plugins/builtin/manual-entry.tsx +25 -0
  144. package/src/plugins/builtin/news.tsx +143 -0
  145. package/src/plugins/builtin/notes-files.ts +58 -0
  146. package/src/plugins/builtin/notes.tsx +396 -0
  147. package/src/plugins/builtin/options-availability.test.tsx +179 -0
  148. package/src/plugins/builtin/options-availability.ts +158 -0
  149. package/src/plugins/builtin/options.tsx +364 -0
  150. package/src/plugins/builtin/portfolio-list/header.tsx +227 -0
  151. package/src/plugins/builtin/portfolio-list/index.tsx +99 -0
  152. package/src/plugins/builtin/portfolio-list/metrics.ts +436 -0
  153. package/src/plugins/builtin/portfolio-list/pane.tsx +533 -0
  154. package/src/plugins/builtin/portfolio-list/settings.ts +280 -0
  155. package/src/plugins/builtin/portfolio-list/summary.tsx +270 -0
  156. package/src/plugins/builtin/portfolio-list/table.tsx +64 -0
  157. package/src/plugins/builtin/portfolio-list.test.ts +74 -0
  158. package/src/plugins/builtin/portfolio-list.test.tsx +1164 -0
  159. package/src/plugins/builtin/portfolio-metrics.test.ts +153 -0
  160. package/src/plugins/builtin/quote-monitor.test.tsx +114 -0
  161. package/src/plugins/builtin/sec.tsx +250 -0
  162. package/src/plugins/builtin/ticker-detail/chart-tab.tsx +43 -0
  163. package/src/plugins/builtin/ticker-detail/financials-tab.tsx +390 -0
  164. package/src/plugins/builtin/ticker-detail/index.tsx +80 -0
  165. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +242 -0
  166. package/src/plugins/builtin/ticker-detail/pane.tsx +183 -0
  167. package/src/plugins/builtin/ticker-detail/quote-monitor.tsx +83 -0
  168. package/src/plugins/builtin/ticker-detail/settings.ts +132 -0
  169. package/src/plugins/builtin/ticker-detail-chart-tab-switch.test.tsx +193 -0
  170. package/src/plugins/builtin/ticker-detail.test.tsx +578 -0
  171. package/src/plugins/builtin/yahoo.ts +18 -0
  172. package/src/plugins/event-bus.ts +37 -0
  173. package/src/plugins/ibkr/__snapshots__/trade-tab.test.tsx.snap +35 -0
  174. package/src/plugins/ibkr/account-cache.test.ts +101 -0
  175. package/src/plugins/ibkr/account-cache.ts +137 -0
  176. package/src/plugins/ibkr/broker-adapter.ts +168 -0
  177. package/src/plugins/ibkr/config.test.ts +68 -0
  178. package/src/plugins/ibkr/config.ts +262 -0
  179. package/src/plugins/ibkr/dialogs.tsx +83 -0
  180. package/src/plugins/ibkr/flex.test.ts +107 -0
  181. package/src/plugins/ibkr/flex.ts +267 -0
  182. package/src/plugins/ibkr/fundamental-parser.ts +149 -0
  183. package/src/plugins/ibkr/gateway-helpers.ts +28 -0
  184. package/src/plugins/ibkr/gateway-selection.ts +51 -0
  185. package/src/plugins/ibkr/gateway-service.test.ts +450 -0
  186. package/src/plugins/ibkr/gateway-service.ts +2228 -0
  187. package/src/plugins/ibkr/index.test.tsx +183 -0
  188. package/src/plugins/ibkr/index.tsx +153 -0
  189. package/src/plugins/ibkr/instance-selection.test.ts +121 -0
  190. package/src/plugins/ibkr/instance-selection.ts +36 -0
  191. package/src/plugins/ibkr/price-normalization.test.ts +38 -0
  192. package/src/plugins/ibkr/price-normalization.ts +59 -0
  193. package/src/plugins/ibkr/trade-badge.tsx +27 -0
  194. package/src/plugins/ibkr/trade-tab.test.tsx +225 -0
  195. package/src/plugins/ibkr/trade-tab.tsx +1050 -0
  196. package/src/plugins/ibkr/trade-utils.test.ts +175 -0
  197. package/src/plugins/ibkr/trade-utils.ts +149 -0
  198. package/src/plugins/ibkr/trading-pane.tsx +438 -0
  199. package/src/plugins/ibkr/trading-state.test.ts +109 -0
  200. package/src/plugins/ibkr/trading-state.ts +339 -0
  201. package/src/plugins/loader.ts +71 -0
  202. package/src/plugins/pane-manager.test.ts +103 -0
  203. package/src/plugins/pane-manager.ts +974 -0
  204. package/src/plugins/plugin-persistence.ts +85 -0
  205. package/src/plugins/plugin-runtime.test.tsx +185 -0
  206. package/src/plugins/plugin-runtime.tsx +175 -0
  207. package/src/plugins/prediction-markets/cache.ts +114 -0
  208. package/src/plugins/prediction-markets/categories.ts +223 -0
  209. package/src/plugins/prediction-markets/chart.tsx +512 -0
  210. package/src/plugins/prediction-markets/columns.ts +133 -0
  211. package/src/plugins/prediction-markets/controller-data.ts +614 -0
  212. package/src/plugins/prediction-markets/controller.ts +725 -0
  213. package/src/plugins/prediction-markets/detail/book.tsx +118 -0
  214. package/src/plugins/prediction-markets/detail/outcomes.tsx +102 -0
  215. package/src/plugins/prediction-markets/detail/overview.tsx +73 -0
  216. package/src/plugins/prediction-markets/detail/pane.tsx +308 -0
  217. package/src/plugins/prediction-markets/detail/rules.tsx +16 -0
  218. package/src/plugins/prediction-markets/detail/shared.tsx +29 -0
  219. package/src/plugins/prediction-markets/detail/trades.tsx +30 -0
  220. package/src/plugins/prediction-markets/detail.test.tsx +47 -0
  221. package/src/plugins/prediction-markets/index.tsx +102 -0
  222. package/src/plugins/prediction-markets/keyboard.ts +64 -0
  223. package/src/plugins/prediction-markets/launch.test.ts +126 -0
  224. package/src/plugins/prediction-markets/launch.ts +240 -0
  225. package/src/plugins/prediction-markets/metrics.ts +311 -0
  226. package/src/plugins/prediction-markets/navigation.ts +90 -0
  227. package/src/plugins/prediction-markets/outcome-order.ts +19 -0
  228. package/src/plugins/prediction-markets/pane.test.tsx +425 -0
  229. package/src/plugins/prediction-markets/pane.tsx +294 -0
  230. package/src/plugins/prediction-markets/plugin.test.tsx +570 -0
  231. package/src/plugins/prediction-markets/rows.ts +229 -0
  232. package/src/plugins/prediction-markets/services/fetch.ts +97 -0
  233. package/src/plugins/prediction-markets/services/kalshi-adapter.ts +555 -0
  234. package/src/plugins/prediction-markets/services/polymarket-adapter.ts +660 -0
  235. package/src/plugins/prediction-markets/services/polymarket-ws.ts +108 -0
  236. package/src/plugins/prediction-markets/settings.ts +164 -0
  237. package/src/plugins/prediction-markets/status.ts +24 -0
  238. package/src/plugins/prediction-markets/table.tsx +84 -0
  239. package/src/plugins/prediction-markets/test-helpers.tsx +636 -0
  240. package/src/plugins/prediction-markets/types.ts +186 -0
  241. package/src/plugins/registry.ts +633 -0
  242. package/src/sources/exchange-rates.ts +18 -0
  243. package/src/sources/gloomberb-cloud.test.ts +199 -0
  244. package/src/sources/gloomberb-cloud.ts +326 -0
  245. package/src/sources/provider-errors.ts +19 -0
  246. package/src/sources/provider-router.test.ts +1476 -0
  247. package/src/sources/provider-router.ts +1405 -0
  248. package/src/sources/sec-edgar.test.ts +286 -0
  249. package/src/sources/sec-edgar.ts +526 -0
  250. package/src/sources/yahoo-finance.test.ts +14 -0
  251. package/src/sources/yahoo-finance.ts +1017 -0
  252. package/src/state/app-activity.test.ts +41 -0
  253. package/src/state/app-activity.ts +106 -0
  254. package/src/state/app-bootstrap.test.ts +471 -0
  255. package/src/state/app-bootstrap.ts +308 -0
  256. package/src/state/app-context.test.ts +406 -0
  257. package/src/state/app-context.test.tsx +132 -0
  258. package/src/state/app-context.tsx +969 -0
  259. package/src/state/selectors.ts +67 -0
  260. package/src/state/session-persistence.test.ts +128 -0
  261. package/src/state/session-persistence.ts +161 -0
  262. package/src/state/ticker-refresh-queue.test.ts +46 -0
  263. package/src/state/ticker-refresh-queue.ts +40 -0
  264. package/src/state/use-inline-tickers.ts +174 -0
  265. package/src/state/use-quote-streaming.test.ts +37 -0
  266. package/src/state/use-quote-streaming.test.tsx +70 -0
  267. package/src/state/use-quote-streaming.ts +80 -0
  268. package/src/state/use-session-snapshot.ts +84 -0
  269. package/src/test-support/data-provider.ts +22 -0
  270. package/src/theme/color-utils.ts +67 -0
  271. package/src/theme/colors.ts +128 -0
  272. package/src/theme/themes.test.ts +45 -0
  273. package/src/theme/themes.ts +491 -0
  274. package/src/types/broker.ts +105 -0
  275. package/src/types/config.ts +434 -0
  276. package/src/types/data-provider.ts +81 -0
  277. package/src/types/financials.ts +142 -0
  278. package/src/types/instrument.ts +29 -0
  279. package/src/types/persistence.ts +21 -0
  280. package/src/types/plugin.ts +354 -0
  281. package/src/types/ticker.ts +58 -0
  282. package/src/types/trading.ts +85 -0
  283. package/src/updater.test.ts +162 -0
  284. package/src/updater.ts +247 -0
  285. package/src/utils/api-client.ts +666 -0
  286. package/src/utils/ascii-chart.ts +172 -0
  287. package/src/utils/broker-instances.ts +47 -0
  288. package/src/utils/cli-output.ts +83 -0
  289. package/src/utils/currency-units.test.ts +49 -0
  290. package/src/utils/currency-units.ts +82 -0
  291. package/src/utils/debug-log.ts +133 -0
  292. package/src/utils/exchange-rate-map.ts +8 -0
  293. package/src/utils/format.ts +158 -0
  294. package/src/utils/fuzzy-search.ts +34 -0
  295. package/src/utils/market-status.ts +95 -0
  296. package/src/utils/options.ts +86 -0
  297. package/src/utils/price-history.ts +39 -0
  298. package/src/utils/quote-time.test.ts +22 -0
  299. package/src/utils/quote-time.ts +50 -0
  300. package/src/utils/sec.test.ts +55 -0
  301. package/src/utils/sec.ts +45 -0
  302. package/src/utils/ticker-list.test.ts +22 -0
  303. package/src/utils/ticker-list.ts +35 -0
  304. package/src/utils/ticker-metadata.ts +51 -0
  305. package/src/utils/ticker-search.test.ts +227 -0
  306. package/src/utils/ticker-search.ts +764 -0
  307. package/src/utils/ticker-tokenizer.test.ts +48 -0
  308. package/src/utils/ticker-tokenizer.ts +72 -0
  309. package/src/version.ts +1 -0
  310. package/install.mjs +0 -68
package/README.md CHANGED
@@ -14,21 +14,28 @@
14
14
 
15
15
  - **Track portfolios & trade**
16
16
  - **Real-time quotes & fundamentals**
17
- - **Beautiful terminal charts**
18
- - **Keyboard-driven**
17
+ - **Beautiful high-rez charts**
18
+ - **Fast & keyboard-driven**
19
+ - **Powerful layouts**
19
20
  - **Extensible**
20
21
  - **100% local**
21
22
 
23
+ For the best experience, use a [Kitty](https://sw.kovidgoyal.net/kitty/)-compatible terminal such as Ghostty, Kitty or WezTerm.
24
+
22
25
  ## 🚀 Install
23
26
 
24
27
  ```bash
25
28
  bun install -g gloomberb
26
29
  # or
27
- npm install -g gloomberb
30
+ curl -fsSL gloomberb.com/install | bash
28
31
  ```
29
32
 
30
33
  Then run `gloomberb` to start.
31
34
 
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.
38
+
32
39
  ## 🧩 Plugins
33
40
 
34
41
  Gloomberb has a plugin architecture where everything, from the portfolio list to broker integrations, is a plugin.
@@ -47,12 +54,18 @@ See **[PLUGINS.md](PLUGINS.md)** for the plugin API and the shared UI surface av
47
54
  | **SEC** | View recent SEC filings for supported US equities |
48
55
  | **Notes** | Write and save markdown notes, stored locally |
49
56
  | **Options** | View US equity options chains |
50
- | **Ask AI** | Chat with AI about tickers using local CLI tools |
57
+ | **AI** | Keep an Ask AI detail tab for tickers and create prompt-driven AI screener panes |
51
58
  | **Compare Charts** | Compare multiple ticker charts overlaid on one shared chart |
52
59
  | **X Scanner** | WIP |
53
60
  | **Alerts** | WIP |
54
61
  | **Scanner** | WIP |
55
62
 
63
+ #### AI plugin
64
+
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.
68
+
56
69
  ### Data providers
57
70
 
58
71
  | Provider | Description |
@@ -64,32 +77,20 @@ See **[PLUGINS.md](PLUGINS.md)** for the plugin API and the shared UI surface av
64
77
 
65
78
  | Plugin | Description |
66
79
  |--------|-------------|
67
- | **IBKR** | Import positions from Interactive Brokers (Flex Query or Gateway API) |
80
+ | **IBKR** | Import positions from Flex Query or trade with Gateway API. |
68
81
  | **Manual Entry** | Manually add positions, saved locally |
69
82
 
70
83
  Toggleable plugins can be enabled/disabled from the command bar screen (`Ctrl+p`).
71
84
 
72
- ### Plugin slots
73
-
74
- Plugins extend the UI through defined slots:
75
-
76
- - `detail:tab` / `detail:section` — tabs or sections in the detail pane
77
- - `list:column` — custom columns in the ticker list
78
- - `command:extra` / `command:preset` — extend the command bar
79
- - `status:widget` — status bar widgets
80
- - `config:section` — settings page sections
81
- - `data:post-refresh` / `data:enricher` — hook into the data lifecycle
82
-
83
85
  ## ⌨️ Keyboard Shortcuts
84
86
 
85
87
  | Key | Action |
86
88
  |-----|--------|
87
89
  | `Ctrl+P` or `` ` `` | Open command bar |
90
+ | `Ctrl+x` | Close current window |
88
91
  | `Tab` | Switch between panels |
89
- | `j` / `k` | Navigate ticker list |
92
+ `j` / `k` | Navigate ticker list |
90
93
  | `h` / `l` | Switch tabs |
91
- | `r` | Refresh selected ticker |
92
- | `Shift+R` | Refresh all tickers |
93
94
  | `Ctrl+,` | Open settings |
94
95
  | `m` | Cycle chart mode in the chart tab |
95
96
  | `q` | Quit |
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.2.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,15 +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
20
  "test": "bun test",
19
- "release": "./scripts/release.sh",
20
- "postinstall": "node install.mjs"
21
+ "release": "./scripts/release.sh"
21
22
  },
22
23
  "license": "MIT",
23
24
  "repository": {
@@ -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,