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.
- package/LICENSE +25 -0
- package/README.md +68 -121
- package/bin/gloomberb +3 -0
- package/package.json +13 -4
- package/patches/@opentui%2Fcore@0.1.90.patch +356 -0
- package/src/app.tsx +1330 -0
- package/src/brokers/sync-broker-instance.test.ts +100 -0
- package/src/brokers/sync-broker-instance.ts +341 -0
- package/src/cli/commands/plugins.ts +173 -0
- package/src/cli/commands/portfolio.ts +210 -0
- package/src/cli/commands/search.ts +120 -0
- package/src/cli/commands/ticker.ts +375 -0
- package/src/cli/commands/watchlist.ts +210 -0
- package/src/cli/context.ts +62 -0
- package/src/cli/errors.ts +13 -0
- package/src/cli/helpers.ts +85 -0
- package/src/cli/index.ts +143 -0
- package/src/cli/ticker-resolution.ts +39 -0
- package/src/cli/types.ts +15 -0
- package/src/cli.test.ts +361 -0
- package/src/components/chart/chart-data.ts +239 -0
- package/src/components/chart/chart-renderer.ts +1199 -0
- package/src/components/chart/chart-types.ts +82 -0
- package/src/components/chart/chart-viewport.ts +21 -0
- package/src/components/chart/chart.test.ts +439 -0
- package/src/components/chart/comparison-chart-data.test.ts +109 -0
- package/src/components/chart/comparison-chart-data.ts +316 -0
- package/src/components/chart/comparison-chart-renderer.test.ts +84 -0
- package/src/components/chart/comparison-chart-renderer.ts +354 -0
- package/src/components/chart/comparison-stock-chart.tsx +1486 -0
- package/src/components/chart/cursor-motion.ts +48 -0
- package/src/components/chart/native/chart-rasterizer.ts +732 -0
- package/src/components/chart/native/kitty-adapter.ts +12 -0
- package/src/components/chart/native/kitty-manager.ts +142 -0
- package/src/components/chart/native/kitty-protocol.ts +110 -0
- package/src/components/chart/native/kitty-support.ts +71 -0
- package/src/components/chart/native/kitty.test.ts +620 -0
- package/src/components/chart/native/renderer-selection.ts +24 -0
- package/src/components/chart/native/surface-manager.ts +225 -0
- package/src/components/chart/native/surface-sync.ts +34 -0
- package/src/components/chart/stock-chart-renderer-switch.test.tsx +165 -0
- package/src/components/chart/stock-chart.test.ts +107 -0
- package/src/components/chart/stock-chart.tsx +1556 -0
- package/src/components/command-bar/__snapshots__/command-bar.test.tsx.snap +137 -0
- package/src/components/command-bar/command-bar.test.tsx +1524 -0
- package/src/components/command-bar/command-bar.tsx +4823 -0
- package/src/components/command-bar/command-registry.ts +261 -0
- package/src/components/command-bar/helpers.test.ts +224 -0
- package/src/components/command-bar/helpers.ts +371 -0
- package/src/components/command-bar/root-shortcuts.ts +158 -0
- package/src/components/command-bar/view-model.test.ts +152 -0
- package/src/components/command-bar/view-model.ts +185 -0
- package/src/components/command-bar/workflow-ops.test.ts +70 -0
- package/src/components/command-bar/workflow-ops.ts +433 -0
- package/src/components/command-bar/workflow-types.ts +127 -0
- package/src/components/detail-feed-view.test.tsx +105 -0
- package/src/components/detail-feed-view.tsx +295 -0
- package/src/components/index.ts +32 -0
- package/src/components/layout/floating-pane.tsx +49 -0
- package/src/components/layout/header.tsx +129 -0
- package/src/components/layout/pane-header.tsx +44 -0
- package/src/components/layout/pane.tsx +49 -0
- package/src/components/layout/pixel-mouse-mode.test.ts +122 -0
- package/src/components/layout/pixel-mouse.test.ts +40 -0
- package/src/components/layout/shell.test.tsx +625 -0
- package/src/components/layout/shell.tsx +1200 -0
- package/src/components/layout/status-bar.test.tsx +173 -0
- package/src/components/layout/status-bar.tsx +138 -0
- package/src/components/markdown-editor.tsx +134 -0
- package/src/components/onboarding/onboarding-wizard.test.tsx +184 -0
- package/src/components/onboarding/onboarding-wizard.tsx +1365 -0
- package/src/components/pane-settings-dialog.tsx +468 -0
- package/src/components/pane-template-wizard.test.tsx +52 -0
- package/src/components/pane-template-wizard.tsx +199 -0
- package/src/components/price-selector-dialog.tsx +195 -0
- package/src/components/spinner.tsx +2 -0
- package/src/components/tab-bar.tsx +17 -0
- package/src/components/ticker-badge-text.test.tsx +160 -0
- package/src/components/ticker-badge-text.tsx +58 -0
- package/src/components/ticker-badge.tsx +88 -0
- package/src/components/ticker-list-table.tsx +188 -0
- package/src/components/toggle-list.tsx +74 -0
- package/src/components/ui/button.tsx +77 -0
- package/src/components/ui/data-table.tsx +210 -0
- package/src/components/ui/external-link.tsx +22 -0
- package/src/components/ui/fields.tsx +187 -0
- package/src/components/ui/frame.tsx +73 -0
- package/src/components/ui/index.ts +53 -0
- package/src/components/ui/list-view.tsx +166 -0
- package/src/components/ui/loading.tsx +70 -0
- package/src/components/ui/status.tsx +83 -0
- package/src/components/ui/tabs.tsx +47 -0
- package/src/components/ui/toggle.tsx +164 -0
- package/src/components/ui/ui.test.tsx +134 -0
- package/src/data/app-persistence.ts +25 -0
- package/src/data/config-store.test.ts +310 -0
- package/src/data/config-store.ts +469 -0
- package/src/data/plugin-state-store.ts +102 -0
- package/src/data/resource-store.ts +323 -0
- package/src/data/session-store.ts +52 -0
- package/src/data/sqlite-cache.test.ts +103 -0
- package/src/data/sqlite-database.ts +62 -0
- package/src/data/sqlite-json.ts +19 -0
- package/src/data/ticker-repository.ts +45 -0
- package/src/data/ticker-store.ts +46 -0
- package/src/index.tsx +67 -0
- package/src/market-data/coordinator.test.ts +369 -0
- package/src/market-data/coordinator.ts +580 -0
- package/src/market-data/hooks.tsx +234 -0
- package/src/market-data/query-store.ts +28 -0
- package/src/market-data/request-types.test.ts +64 -0
- package/src/market-data/request-types.ts +70 -0
- package/src/market-data/result-types.ts +56 -0
- package/src/market-data/selectors.ts +166 -0
- package/src/market-data/trace.ts +7 -0
- package/src/pane-settings.test.ts +71 -0
- package/src/pane-settings.ts +73 -0
- package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +338 -0
- package/src/plugins/builtin/ai/gloomberb-cli.ts +70 -0
- package/src/plugins/builtin/ai/index.test.tsx +139 -0
- package/src/plugins/builtin/ai/index.tsx +86 -0
- package/src/plugins/builtin/ai/providers.ts +99 -0
- package/src/plugins/builtin/ai/runner.ts +82 -0
- package/src/plugins/builtin/ai/screener-contract.test.ts +117 -0
- package/src/plugins/builtin/ai/screener-contract.ts +174 -0
- package/src/plugins/builtin/ai/screener-pane.test.tsx +365 -0
- package/src/plugins/builtin/ai/screener-pane.tsx +1161 -0
- package/src/plugins/builtin/ai/settings.ts +79 -0
- package/src/plugins/builtin/ai/ticker-context.ts +64 -0
- package/src/plugins/builtin/ai/utils.ts +71 -0
- package/src/plugins/builtin/ask-ai.test.tsx +258 -0
- package/src/plugins/builtin/ask-ai.tsx +9 -0
- package/src/plugins/builtin/chat-controller.test.ts +217 -0
- package/src/plugins/builtin/chat-controller.ts +340 -0
- package/src/plugins/builtin/chat.test.tsx +451 -0
- package/src/plugins/builtin/chat.tsx +620 -0
- package/src/plugins/builtin/comparison-chart.test.tsx +277 -0
- package/src/plugins/builtin/comparison-chart.tsx +169 -0
- package/src/plugins/builtin/data-providers.ts +16 -0
- package/src/plugins/builtin/debug.tsx +351 -0
- package/src/plugins/builtin/help.test.tsx +110 -0
- package/src/plugins/builtin/help.tsx +281 -0
- package/src/plugins/builtin/layout-manager.tsx +264 -0
- package/src/plugins/builtin/manual-entry.tsx +25 -0
- package/src/plugins/builtin/news.tsx +143 -0
- package/src/plugins/builtin/notes-files.ts +58 -0
- package/src/plugins/builtin/notes.tsx +396 -0
- package/src/plugins/builtin/options-availability.test.tsx +179 -0
- package/src/plugins/builtin/options-availability.ts +158 -0
- package/src/plugins/builtin/options.tsx +364 -0
- package/src/plugins/builtin/portfolio-list/header.tsx +227 -0
- package/src/plugins/builtin/portfolio-list/index.tsx +99 -0
- package/src/plugins/builtin/portfolio-list/metrics.ts +436 -0
- package/src/plugins/builtin/portfolio-list/pane.tsx +533 -0
- package/src/plugins/builtin/portfolio-list/settings.ts +280 -0
- package/src/plugins/builtin/portfolio-list/summary.tsx +270 -0
- package/src/plugins/builtin/portfolio-list/table.tsx +64 -0
- package/src/plugins/builtin/portfolio-list.test.ts +74 -0
- package/src/plugins/builtin/portfolio-list.test.tsx +1164 -0
- package/src/plugins/builtin/portfolio-metrics.test.ts +153 -0
- package/src/plugins/builtin/quote-monitor.test.tsx +114 -0
- package/src/plugins/builtin/sec.tsx +250 -0
- package/src/plugins/builtin/ticker-detail/chart-tab.tsx +43 -0
- package/src/plugins/builtin/ticker-detail/financials-tab.tsx +390 -0
- package/src/plugins/builtin/ticker-detail/index.tsx +80 -0
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +242 -0
- package/src/plugins/builtin/ticker-detail/pane.tsx +183 -0
- package/src/plugins/builtin/ticker-detail/quote-monitor.tsx +83 -0
- package/src/plugins/builtin/ticker-detail/settings.ts +132 -0
- package/src/plugins/builtin/ticker-detail-chart-tab-switch.test.tsx +193 -0
- package/src/plugins/builtin/ticker-detail.test.tsx +578 -0
- package/src/plugins/builtin/yahoo.ts +18 -0
- package/src/plugins/event-bus.ts +37 -0
- package/src/plugins/ibkr/__snapshots__/trade-tab.test.tsx.snap +35 -0
- package/src/plugins/ibkr/account-cache.test.ts +101 -0
- package/src/plugins/ibkr/account-cache.ts +137 -0
- package/src/plugins/ibkr/broker-adapter.ts +168 -0
- package/src/plugins/ibkr/config.test.ts +68 -0
- package/src/plugins/ibkr/config.ts +262 -0
- package/src/plugins/ibkr/dialogs.tsx +83 -0
- package/src/plugins/ibkr/flex.test.ts +107 -0
- package/src/plugins/ibkr/flex.ts +267 -0
- package/src/plugins/ibkr/fundamental-parser.ts +149 -0
- package/src/plugins/ibkr/gateway-helpers.ts +28 -0
- package/src/plugins/ibkr/gateway-selection.ts +51 -0
- package/src/plugins/ibkr/gateway-service.test.ts +450 -0
- package/src/plugins/ibkr/gateway-service.ts +2228 -0
- package/src/plugins/ibkr/index.test.tsx +183 -0
- package/src/plugins/ibkr/index.tsx +153 -0
- package/src/plugins/ibkr/instance-selection.test.ts +121 -0
- package/src/plugins/ibkr/instance-selection.ts +36 -0
- package/src/plugins/ibkr/price-normalization.test.ts +38 -0
- package/src/plugins/ibkr/price-normalization.ts +59 -0
- package/src/plugins/ibkr/trade-badge.tsx +27 -0
- package/src/plugins/ibkr/trade-tab.test.tsx +225 -0
- package/src/plugins/ibkr/trade-tab.tsx +1050 -0
- package/src/plugins/ibkr/trade-utils.test.ts +175 -0
- package/src/plugins/ibkr/trade-utils.ts +149 -0
- package/src/plugins/ibkr/trading-pane.tsx +438 -0
- package/src/plugins/ibkr/trading-state.test.ts +109 -0
- package/src/plugins/ibkr/trading-state.ts +339 -0
- package/src/plugins/loader.ts +71 -0
- package/src/plugins/pane-manager.test.ts +103 -0
- package/src/plugins/pane-manager.ts +974 -0
- package/src/plugins/plugin-persistence.ts +85 -0
- package/src/plugins/plugin-runtime.test.tsx +185 -0
- package/src/plugins/plugin-runtime.tsx +175 -0
- package/src/plugins/prediction-markets/cache.ts +114 -0
- package/src/plugins/prediction-markets/categories.ts +223 -0
- package/src/plugins/prediction-markets/chart.tsx +512 -0
- package/src/plugins/prediction-markets/columns.ts +133 -0
- package/src/plugins/prediction-markets/controller-data.ts +614 -0
- package/src/plugins/prediction-markets/controller.ts +725 -0
- package/src/plugins/prediction-markets/detail/book.tsx +118 -0
- package/src/plugins/prediction-markets/detail/outcomes.tsx +102 -0
- package/src/plugins/prediction-markets/detail/overview.tsx +73 -0
- package/src/plugins/prediction-markets/detail/pane.tsx +308 -0
- package/src/plugins/prediction-markets/detail/rules.tsx +16 -0
- package/src/plugins/prediction-markets/detail/shared.tsx +29 -0
- package/src/plugins/prediction-markets/detail/trades.tsx +30 -0
- package/src/plugins/prediction-markets/detail.test.tsx +47 -0
- package/src/plugins/prediction-markets/index.tsx +102 -0
- package/src/plugins/prediction-markets/keyboard.ts +64 -0
- package/src/plugins/prediction-markets/launch.test.ts +126 -0
- package/src/plugins/prediction-markets/launch.ts +240 -0
- package/src/plugins/prediction-markets/metrics.ts +311 -0
- package/src/plugins/prediction-markets/navigation.ts +90 -0
- package/src/plugins/prediction-markets/outcome-order.ts +19 -0
- package/src/plugins/prediction-markets/pane.test.tsx +425 -0
- package/src/plugins/prediction-markets/pane.tsx +294 -0
- package/src/plugins/prediction-markets/plugin.test.tsx +570 -0
- package/src/plugins/prediction-markets/rows.ts +229 -0
- package/src/plugins/prediction-markets/services/fetch.ts +97 -0
- package/src/plugins/prediction-markets/services/kalshi-adapter.ts +555 -0
- package/src/plugins/prediction-markets/services/polymarket-adapter.ts +660 -0
- package/src/plugins/prediction-markets/services/polymarket-ws.ts +108 -0
- package/src/plugins/prediction-markets/settings.ts +164 -0
- package/src/plugins/prediction-markets/status.ts +24 -0
- package/src/plugins/prediction-markets/table.tsx +84 -0
- package/src/plugins/prediction-markets/test-helpers.tsx +636 -0
- package/src/plugins/prediction-markets/types.ts +186 -0
- package/src/plugins/registry.ts +633 -0
- package/src/sources/exchange-rates.ts +18 -0
- package/src/sources/gloomberb-cloud.test.ts +199 -0
- package/src/sources/gloomberb-cloud.ts +326 -0
- package/src/sources/provider-errors.ts +19 -0
- package/src/sources/provider-router.test.ts +1476 -0
- package/src/sources/provider-router.ts +1405 -0
- package/src/sources/sec-edgar.test.ts +286 -0
- package/src/sources/sec-edgar.ts +526 -0
- package/src/sources/yahoo-finance.test.ts +14 -0
- package/src/sources/yahoo-finance.ts +1017 -0
- package/src/state/app-activity.test.ts +41 -0
- package/src/state/app-activity.ts +106 -0
- package/src/state/app-bootstrap.test.ts +471 -0
- package/src/state/app-bootstrap.ts +308 -0
- package/src/state/app-context.test.ts +406 -0
- package/src/state/app-context.test.tsx +132 -0
- package/src/state/app-context.tsx +969 -0
- package/src/state/selectors.ts +67 -0
- package/src/state/session-persistence.test.ts +128 -0
- package/src/state/session-persistence.ts +161 -0
- package/src/state/ticker-refresh-queue.test.ts +46 -0
- package/src/state/ticker-refresh-queue.ts +40 -0
- package/src/state/use-inline-tickers.ts +174 -0
- package/src/state/use-quote-streaming.test.ts +37 -0
- package/src/state/use-quote-streaming.test.tsx +70 -0
- package/src/state/use-quote-streaming.ts +80 -0
- package/src/state/use-session-snapshot.ts +84 -0
- package/src/test-support/data-provider.ts +22 -0
- package/src/theme/color-utils.ts +67 -0
- package/src/theme/colors.ts +128 -0
- package/src/theme/themes.test.ts +45 -0
- package/src/theme/themes.ts +491 -0
- package/src/types/broker.ts +105 -0
- package/src/types/config.ts +434 -0
- package/src/types/data-provider.ts +81 -0
- package/src/types/financials.ts +142 -0
- package/src/types/instrument.ts +29 -0
- package/src/types/persistence.ts +21 -0
- package/src/types/plugin.ts +354 -0
- package/src/types/ticker.ts +58 -0
- package/src/types/trading.ts +85 -0
- package/src/updater.test.ts +162 -0
- package/src/updater.ts +247 -0
- package/src/utils/api-client.ts +666 -0
- package/src/utils/ascii-chart.ts +172 -0
- package/src/utils/broker-instances.ts +47 -0
- package/src/utils/cli-output.ts +83 -0
- package/src/utils/currency-units.test.ts +49 -0
- package/src/utils/currency-units.ts +82 -0
- package/src/utils/debug-log.ts +133 -0
- package/src/utils/exchange-rate-map.ts +8 -0
- package/src/utils/format.ts +158 -0
- package/src/utils/fuzzy-search.ts +34 -0
- package/src/utils/market-status.ts +95 -0
- package/src/utils/options.ts +86 -0
- package/src/utils/price-history.ts +39 -0
- package/src/utils/quote-time.test.ts +22 -0
- package/src/utils/quote-time.ts +50 -0
- package/src/utils/sec.test.ts +55 -0
- package/src/utils/sec.ts +45 -0
- package/src/utils/ticker-list.test.ts +22 -0
- package/src/utils/ticker-list.ts +35 -0
- package/src/utils/ticker-metadata.ts +51 -0
- package/src/utils/ticker-search.test.ts +227 -0
- package/src/utils/ticker-search.ts +764 -0
- package/src/utils/ticker-tokenizer.test.ts +48 -0
- package/src/utils/ticker-tokenizer.ts +72 -0
- package/src/version.ts +1 -0
- 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
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
7
|
+
> Why pay for Bloomberg when you can have Gloomberb?
|
|
19
8
|
|
|
20
|
-
|
|
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
|
-
|
|
11
|
+
</div>
|
|
33
12
|
|
|
34
|
-
|
|
35
|
-
# Install dependencies
|
|
36
|
-
bun install
|
|
37
|
-
|
|
38
|
-
# Run
|
|
39
|
-
bun dev
|
|
40
|
-
```
|
|
13
|
+
## ✨ Features
|
|
41
14
|
|
|
42
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
25
|
+
## 🚀 Install
|
|
58
26
|
|
|
59
|
-
|
|
27
|
+
```bash
|
|
28
|
+
bun install -g gloomberb
|
|
29
|
+
# or
|
|
30
|
+
curl -fsSL gloomberb.com/install | bash
|
|
60
31
|
```
|
|
61
32
|
|
|
62
|
-
|
|
33
|
+
Then run `gloomberb` to start.
|
|
63
34
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
##
|
|
39
|
+
## 🧩 Plugins
|
|
76
40
|
|
|
77
|
-
|
|
41
|
+
Gloomberb has a plugin architecture where everything, from the portfolio list to broker integrations, is a plugin.
|
|
78
42
|
|
|
79
|
-
|
|
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
|
-
|
|
45
|
+
See **[PLUGINS.md](PLUGINS.md)** for the plugin API and the shared UI surface available through `gloomberb/components`.
|
|
94
46
|
|
|
95
|
-
|
|
47
|
+
### Core plugins
|
|
96
48
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
63
|
+
#### AI plugin
|
|
115
64
|
|
|
116
|
-
|
|
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
|
-
|
|
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
|
-
|
|
71
|
+
| Provider | Description |
|
|
72
|
+
|----------|-------------|
|
|
73
|
+
| **Gloomberb Cloud** | Real-time data (recommended, free) |
|
|
74
|
+
| **Yahoo Finance** | Delayed data, rate-limiting |
|
|
126
75
|
|
|
127
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
85
|
+
## ⌨️ Keyboard Shortcuts
|
|
147
86
|
|
|
148
|
-
|
|
149
|
-
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gloomberb",
|
|
3
|
-
"version": "0.1
|
|
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
|
-
"
|
|
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",
|
|
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,
|