gloomberb 0.9.10 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (516) hide show
  1. package/README.md +41 -3
  2. package/README.zh-CN.md +294 -0
  3. package/package.json +10 -4
  4. package/patches/@opentui%2Fcore@0.3.2.patch +26 -69
  5. package/src/api-client/auth.ts +2 -0
  6. package/src/api-client/index.test.ts +4 -0
  7. package/src/api-client/types.ts +3 -0
  8. package/src/app/pane-runtime/pane-settings-runtime.tsx +1 -0
  9. package/src/app/pane-template-dialog-wizard.test.tsx +36 -0
  10. package/src/app/pane-template-dialog-wizard.tsx +10 -3
  11. package/src/app/runtime/desktop-deeplink.test.ts +15 -0
  12. package/src/app/runtime/desktop-deeplink.ts +21 -6
  13. package/src/app.tsx +39 -33
  14. package/src/capabilities/service-capabilities.ts +7 -2
  15. package/src/cli/commands/automation.test.ts +202 -0
  16. package/src/cli/commands/automation.ts +153 -36
  17. package/src/cli/commands/market.ts +1 -14
  18. package/src/cli/commands/system.ts +4 -1
  19. package/src/cli/context.ts +1 -1
  20. package/src/cli/desktop-pane-shot.ts +65 -4
  21. package/src/cli/entry.ts +1 -1
  22. package/src/cli/pane-functions/capabilities.ts +532 -0
  23. package/src/cli/pane-functions/catalog.ts +39 -4
  24. package/src/cli/pane-functions/data.test.ts +17 -0
  25. package/src/cli/pane-functions/data.ts +55 -13
  26. package/src/cli/pane-functions/discovery.ts +36 -9
  27. package/src/cli/pane-functions/index.test.ts +104 -1
  28. package/src/cli/pane-functions/index.ts +64 -5
  29. package/src/cli/pane-functions/options.ts +21 -6
  30. package/src/cli/pane-functions/report.ts +735 -72
  31. package/src/cli/pane-functions/resolver.ts +70 -6
  32. package/src/cli/pane-functions/screenshot.test.ts +431 -0
  33. package/src/cli/pane-functions/screenshot.ts +952 -8
  34. package/src/components/chart/composite/column-layout.ts +215 -0
  35. package/src/components/chart/composite/composite-chart.test.tsx +630 -0
  36. package/src/components/chart/composite/composite-chart.tsx +1148 -0
  37. package/src/components/chart/composite/format.test.ts +137 -0
  38. package/src/components/chart/composite/format.ts +135 -0
  39. package/src/components/chart/composite/index.ts +38 -0
  40. package/src/components/chart/composite/interactions.test.ts +109 -0
  41. package/src/components/chart/composite/interactions.ts +247 -0
  42. package/src/components/chart/composite/price-series.test.ts +39 -0
  43. package/src/components/chart/composite/price-series.ts +78 -0
  44. package/src/components/chart/composite/rasterizer.ts +359 -0
  45. package/src/components/chart/composite/renderers.test.ts +610 -0
  46. package/src/components/chart/composite/scene.test.ts +464 -0
  47. package/src/components/chart/composite/scene.ts +553 -0
  48. package/src/components/chart/composite/text-renderer.ts +285 -0
  49. package/src/components/chart/composite/time-scale.test.ts +88 -0
  50. package/src/components/chart/composite/time-scale.ts +217 -0
  51. package/src/components/chart/composite/types.ts +141 -0
  52. package/src/components/chart/core/data.ts +81 -5
  53. package/src/components/chart/core/index.test.ts +128 -43
  54. package/src/components/chart/core/resolution.ts +0 -6
  55. package/src/components/chart/native/chart-rasterizer.ts +1 -3
  56. package/src/components/chart/native/kitty/index.test.ts +99 -120
  57. package/src/components/chart/native/kitty/manager.ts +3 -0
  58. package/src/components/chart/native/kitty/protocol.ts +4 -1
  59. package/src/components/chart/native/raster/crosshair.ts +79 -46
  60. package/src/components/chart/native/raster/types.ts +2 -11
  61. package/src/components/chart/native/surface/manager.ts +48 -3
  62. package/src/components/chart/price-axis-labels.tsx +18 -4
  63. package/src/components/command-bar/commands/direct/index.ts +25 -0
  64. package/src/components/command-bar/commands/registry.ts +9 -0
  65. package/src/components/command-bar/helpers.test.ts +4 -1
  66. package/src/components/command-bar/list/view.tsx +18 -6
  67. package/src/components/command-bar/multi-select-picker.tsx +6 -5
  68. package/src/components/command-bar/pane-settings.test.ts +141 -0
  69. package/src/components/command-bar/pane-settings.ts +61 -1
  70. package/src/components/command-bar/panel/body.tsx +7 -6
  71. package/src/components/command-bar/routes/root/command-items.ts +4 -4
  72. package/src/components/command-bar/routes/root/results.ts +10 -1
  73. package/src/components/command-bar/routes/root/selection.test.ts +54 -0
  74. package/src/components/command-bar/routes/root/selection.ts +13 -0
  75. package/src/components/command-bar/routing/actions.ts +18 -2
  76. package/src/components/command-bar/routing/list-state.ts +2 -1
  77. package/src/components/command-bar/surface/index.test.tsx +36 -4
  78. package/src/components/command-bar/surface/pane.test.tsx +93 -0
  79. package/src/components/command-bar/theme-picker.tsx +2 -1
  80. package/src/components/command-bar/view-model.ts +19 -20
  81. package/src/components/command-bar/workflow/body.tsx +2 -1
  82. package/src/components/command-bar/workflow/field-row.tsx +3 -2
  83. package/src/components/command-bar/workflow/fields.ts +4 -2
  84. package/src/components/command-bar/workflow/ops.test.ts +161 -0
  85. package/src/components/command-bar/workflow/ops.ts +20 -50
  86. package/src/components/command-bar/workflow/route-actions.test.ts +34 -0
  87. package/src/components/command-bar/workflow/route-actions.ts +4 -0
  88. package/src/components/command-bar/workflow/types.ts +1 -0
  89. package/src/components/feed-data-table/stack-view.tsx +6 -5
  90. package/src/components/index.ts +13 -1
  91. package/src/components/layout/detached-pane-shell.tsx +2 -1
  92. package/src/components/layout/floating-pane.tsx +3 -0
  93. package/src/components/layout/header.tsx +15 -8
  94. package/src/components/layout/pane/footer/index.test.tsx +22 -3
  95. package/src/components/layout/pane/footer/index.tsx +3 -1
  96. package/src/components/layout/pane/footer/model.ts +9 -2
  97. package/src/components/layout/pane/header.tsx +4 -6
  98. package/src/components/layout/pane/index.tsx +3 -0
  99. package/src/components/layout/pane/sidebar.test.tsx +100 -0
  100. package/src/components/layout/pane/sidebar.tsx +239 -0
  101. package/src/components/layout/pane/title.ts +4 -3
  102. package/src/components/layout/shell/action-menu-overlay.tsx +5 -3
  103. package/src/components/layout/shell/drag/runtime.ts +2 -0
  104. package/src/components/layout/shell/menu.test.ts +19 -0
  105. package/src/components/layout/shell/menu.ts +8 -5
  106. package/src/components/layout/shell/native/pointer-runtime.ts +4 -1
  107. package/src/components/layout/shell/pane/layers.tsx +2 -2
  108. package/src/components/layout/status-bar.tsx +8 -7
  109. package/src/components/layout/window-controls.tsx +4 -3
  110. package/src/components/metric-treemap/index.tsx +3 -2
  111. package/src/components/onboarding/onboarding-steps.tsx +30 -29
  112. package/src/components/onboarding/onboarding-wizard.tsx +5 -4
  113. package/src/components/onboarding/portfolio-step/broker-fields-panel.tsx +15 -12
  114. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +17 -16
  115. package/src/components/onboarding/portfolio-step/broker-sync-panel.tsx +6 -5
  116. package/src/components/onboarding/portfolio-step/choose-panel.tsx +5 -4
  117. package/src/components/pane-settings-dialog/desktop.tsx +25 -3
  118. package/src/components/pane-settings-dialog/field-dialogs.tsx +5 -4
  119. package/src/components/pane-settings-dialog/tui.tsx +11 -9
  120. package/src/components/pane-settings-dialog/value.ts +8 -5
  121. package/src/components/pane-settings-dialog.test.tsx +235 -0
  122. package/src/components/pane-settings-dialog.tsx +24 -0
  123. package/src/components/pane-template-wizard.tsx +6 -2
  124. package/src/components/ticker/list-table-view.tsx +3 -2
  125. package/src/components/ui/button.tsx +3 -1
  126. package/src/components/ui/choice-dialog.tsx +6 -1
  127. package/src/components/ui/confirm-dialog.tsx +3 -2
  128. package/src/components/ui/fields.tsx +10 -1
  129. package/src/components/ui/frame.tsx +4 -1
  130. package/src/components/ui/index.ts +5 -0
  131. package/src/components/ui/inline-quick-add.tsx +104 -0
  132. package/src/components/ui/list-view.tsx +5 -4
  133. package/src/components/ui/loading.tsx +2 -1
  134. package/src/components/ui/multi-select/dialog.tsx +188 -44
  135. package/src/components/ui/popover.tsx +10 -0
  136. package/src/components/ui/shortcut-hint.tsx +2 -0
  137. package/src/components/ui/status.tsx +4 -3
  138. package/src/components/ui/tabs.tsx +19 -8
  139. package/src/components/ui/toggle.tsx +44 -3
  140. package/src/components/ui/ui.test.tsx +67 -5
  141. package/src/core/app-services.ts +4 -6
  142. package/src/core/state/session-persistence.ts +3 -2
  143. package/src/data/config/chart-settings.ts +712 -0
  144. package/src/data/config/layout.ts +24 -5
  145. package/src/data/config/store/index.test.ts +377 -14
  146. package/src/data/config/store/normalize.ts +79 -65
  147. package/src/data/fred-series.ts +137 -0
  148. package/src/i18n/index.test.ts +114 -0
  149. package/src/i18n/index.ts +147 -0
  150. package/src/i18n/ja.ts +1013 -0
  151. package/src/i18n/ko.ts +1011 -0
  152. package/src/i18n/languages.test.ts +31 -0
  153. package/src/i18n/languages.ts +72 -0
  154. package/src/i18n/zh-cn.ts +1013 -0
  155. package/src/i18n/zh-tw.ts +1013 -0
  156. package/src/plugins/builtin/account-management/footer.ts +3 -2
  157. package/src/plugins/builtin/account-management/form-components.tsx +3 -2
  158. package/src/plugins/builtin/account-management/keyboard.ts +6 -0
  159. package/src/plugins/builtin/account-management/model.ts +25 -21
  160. package/src/plugins/builtin/account-management/navigation.test.ts +27 -0
  161. package/src/plugins/builtin/account-management/navigation.ts +24 -0
  162. package/src/plugins/builtin/account-management/pane.tsx +120 -85
  163. package/src/plugins/builtin/account-management/password-dialog.tsx +10 -9
  164. package/src/plugins/builtin/ai/agent-history.ts +139 -0
  165. package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +133 -51
  166. package/src/plugins/builtin/ai/ask-ai.test.tsx +83 -22
  167. package/src/plugins/builtin/ai/index.test.ts +302 -0
  168. package/src/plugins/builtin/ai/index.tsx +374 -40
  169. package/src/plugins/builtin/ai/pane-settings.test.ts +155 -0
  170. package/src/plugins/builtin/ai/pane-settings.ts +319 -0
  171. package/src/plugins/builtin/ai/pi/credential-store.test.ts +80 -0
  172. package/src/plugins/builtin/ai/pi/credential-store.ts +138 -0
  173. package/src/plugins/builtin/ai/pi/file-store.ts +138 -0
  174. package/src/plugins/builtin/ai/pi/host.test.ts +500 -0
  175. package/src/plugins/builtin/ai/pi/host.ts +564 -0
  176. package/src/plugins/builtin/ai/pi/index.ts +5 -0
  177. package/src/plugins/builtin/ai/pi/models-store.test.ts +44 -0
  178. package/src/plugins/builtin/ai/pi/models-store.ts +141 -0
  179. package/src/plugins/builtin/ai/pi/providers.ts +68 -0
  180. package/src/plugins/builtin/ai/pi/runtime.test.ts +240 -0
  181. package/src/plugins/builtin/ai/pi/runtime.ts +635 -0
  182. package/src/plugins/builtin/ai/providers.test.ts +68 -0
  183. package/src/plugins/builtin/ai/providers.ts +163 -38
  184. package/src/plugins/builtin/ai/runner-selection.test.ts +174 -0
  185. package/src/plugins/builtin/ai/runner-selection.ts +193 -0
  186. package/src/plugins/builtin/ai/runner-selector.tsx +153 -0
  187. package/src/plugins/builtin/ai/runner.test.ts +198 -0
  188. package/src/plugins/builtin/ai/runner.ts +276 -73
  189. package/src/plugins/builtin/ai/screener/contract.test.ts +26 -73
  190. package/src/plugins/builtin/ai/screener/contract.ts +14 -52
  191. package/src/plugins/builtin/ai/screener/editor-runtime.ts +55 -5
  192. package/src/plugins/builtin/ai/screener/editor.tsx +42 -36
  193. package/src/plugins/builtin/ai/screener/footer.ts +82 -67
  194. package/src/plugins/builtin/ai/screener/keyboard.ts +27 -11
  195. package/src/plugins/builtin/ai/screener/model.test.ts +24 -0
  196. package/src/plugins/builtin/ai/screener/model.ts +9 -3
  197. package/src/plugins/builtin/ai/screener/pane.test.tsx +142 -55
  198. package/src/plugins/builtin/ai/screener/pane.tsx +95 -97
  199. package/src/plugins/builtin/ai/screener/results-view.tsx +8 -41
  200. package/src/plugins/builtin/ai/screener/runner.ts +41 -25
  201. package/src/plugins/builtin/ai/screener/tabs-bar.tsx +2 -2
  202. package/src/plugins/builtin/ai/use-runtime-providers.ts +28 -0
  203. package/src/plugins/builtin/ai/workspace/model.test.ts +227 -0
  204. package/src/plugins/builtin/ai/workspace/model.ts +308 -0
  205. package/src/plugins/builtin/ai/workspace/pane.test.tsx +197 -0
  206. package/src/plugins/builtin/ai/workspace/pane.tsx +896 -0
  207. package/src/plugins/builtin/analytics/index.test.tsx +3 -3
  208. package/src/plugins/builtin/analytics/index.tsx +3 -8
  209. package/src/plugins/builtin/broker-manager/detail.tsx +25 -24
  210. package/src/plugins/builtin/broker-manager/index.test.tsx +1 -1
  211. package/src/plugins/builtin/broker-manager/index.tsx +9 -11
  212. package/src/plugins/builtin/broker-manager/model.ts +11 -10
  213. package/src/plugins/builtin/broker-manager/pane-actions.tsx +22 -21
  214. package/src/plugins/builtin/broker-manager/table.ts +9 -8
  215. package/src/plugins/builtin/changelog/index.tsx +3 -8
  216. package/src/plugins/builtin/chart-composer/chart-spec.ts +89 -0
  217. package/src/plugins/builtin/chart-composer/cli-options.ts +98 -0
  218. package/src/plugins/builtin/chart-composer/date-window-dialog.tsx +120 -0
  219. package/src/plugins/builtin/chart-composer/editor.test.tsx +332 -0
  220. package/src/plugins/builtin/chart-composer/editor.tsx +1107 -0
  221. package/src/plugins/builtin/chart-composer/index.tsx +228 -0
  222. package/src/plugins/builtin/chart-composer/pane.tsx +645 -0
  223. package/src/plugins/builtin/chart-composer/presets.test.ts +561 -0
  224. package/src/plugins/builtin/chart-composer/presets.ts +759 -0
  225. package/src/plugins/builtin/chart-composer/quick-add.test.tsx +245 -0
  226. package/src/plugins/builtin/chart-composer/quick-add.tsx +409 -0
  227. package/src/plugins/builtin/chart-composer/semantic.ts +86 -0
  228. package/src/plugins/builtin/chart-composer/series-catalog.test.ts +65 -0
  229. package/src/plugins/builtin/chart-composer/series-catalog.ts +295 -0
  230. package/src/plugins/builtin/chart-composer/settings.test.ts +163 -0
  231. package/src/plugins/builtin/chart-composer/settings.ts +397 -0
  232. package/src/plugins/builtin/chart-composer/shortcuts.test.ts +44 -0
  233. package/src/plugins/builtin/chart-composer/shortcuts.ts +35 -0
  234. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +103 -0
  235. package/src/plugins/builtin/chat/channel-labels.ts +5 -4
  236. package/src/plugins/builtin/chat/channels.ts +12 -11
  237. package/src/plugins/builtin/chat/chat.test.tsx +32 -0
  238. package/src/plugins/builtin/chat/content/composer-runtime.ts +6 -1
  239. package/src/plugins/builtin/chat/content/composer.tsx +9 -8
  240. package/src/plugins/builtin/chat/content/index.tsx +36 -1
  241. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +8 -7
  242. package/src/plugins/builtin/chat/content/transcript.tsx +9 -3
  243. package/src/plugins/builtin/chat/controller/utils.ts +10 -9
  244. package/src/plugins/builtin/chat/message/desktop.tsx +17 -10
  245. package/src/plugins/builtin/chat/message/profile-popover.test.tsx +122 -3
  246. package/src/plugins/builtin/chat/message/profile-popover.tsx +38 -1
  247. package/src/plugins/builtin/chat/message/terminal.tsx +19 -10
  248. package/src/plugins/builtin/chat/pane-state.test.ts +31 -0
  249. package/src/plugins/builtin/chat/pane-state.ts +30 -0
  250. package/src/plugins/builtin/chat/pane.tsx +27 -4
  251. package/src/plugins/builtin/chat/profile-popover.ts +62 -5
  252. package/src/plugins/builtin/chat/sidebar.test.tsx +4 -7
  253. package/src/plugins/builtin/chat/sidebar.tsx +107 -168
  254. package/src/plugins/builtin/chat/test-harness.tsx +6 -0
  255. package/src/plugins/builtin/cloud/auth-actions.tsx +5 -4
  256. package/src/plugins/builtin/cloud/plugin.tsx +150 -127
  257. package/src/plugins/builtin/composite-plugins.ts +71 -0
  258. package/src/plugins/builtin/correlation/index.test.tsx +4 -4
  259. package/src/plugins/builtin/correlation/index.tsx +3 -8
  260. package/src/plugins/builtin/earnings/index.tsx +37 -21
  261. package/src/plugins/builtin/earnings/model.test.ts +52 -0
  262. package/src/plugins/builtin/earnings/model.ts +32 -0
  263. package/src/plugins/builtin/econ/detail-view.tsx +17 -4
  264. package/src/plugins/builtin/econ/fred-cache.test.ts +57 -11
  265. package/src/plugins/builtin/econ/index.tsx +16 -20
  266. package/src/plugins/builtin/fear-greed/index.tsx +2 -8
  267. package/src/plugins/builtin/fx-matrix/index.tsx +3 -8
  268. package/src/plugins/builtin/help/components.tsx +5 -4
  269. package/src/plugins/builtin/help/index.tsx +14 -17
  270. package/src/plugins/builtin/holders/index.tsx +2 -8
  271. package/src/plugins/builtin/insider/index.tsx +2 -7
  272. package/src/plugins/builtin/kelly-sizer/index.test.tsx +2 -2
  273. package/src/plugins/builtin/kelly-sizer/index.tsx +3 -7
  274. package/src/plugins/builtin/kelly-sizer/test-support.tsx +3 -3
  275. package/src/plugins/builtin/layout-manager/index.tsx +3 -7
  276. package/src/plugins/builtin/market-heatmap/index.tsx +3 -8
  277. package/src/plugins/builtin/market-movers/index.tsx +3 -8
  278. package/src/plugins/builtin/news/index.tsx +12 -16
  279. package/src/plugins/builtin/news/wire/breaking/pane.test.tsx +3 -3
  280. package/src/plugins/builtin/news/wire/index.tsx +83 -73
  281. package/src/plugins/builtin/options/index.tsx +2 -8
  282. package/src/plugins/builtin/plugin-module.test.ts +89 -0
  283. package/src/plugins/builtin/plugin-module.ts +116 -0
  284. package/src/plugins/builtin/portfolio-list/header.tsx +4 -3
  285. package/src/plugins/builtin/portfolio-list/index.test.ts +17 -0
  286. package/src/plugins/builtin/portfolio-list/index.tsx +3 -5
  287. package/src/plugins/builtin/portfolio-list/pane/index.test.tsx +3 -3
  288. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +53 -53
  289. package/src/plugins/builtin/portfolio-list/settings.ts +5 -3
  290. package/src/plugins/builtin/portfolio-list/summary/index.tsx +4 -3
  291. package/src/plugins/builtin/research/index.tsx +2 -8
  292. package/src/plugins/builtin/sec/index.tsx +2 -8
  293. package/src/plugins/builtin/sectors/index.tsx +3 -8
  294. package/src/plugins/builtin/thirteenf/index.tsx +3 -8
  295. package/src/plugins/builtin/thirteenf/pane.test.tsx +1 -1
  296. package/src/plugins/builtin/ticker-detail/chart-tab-switch.test.tsx +49 -23
  297. package/src/plugins/builtin/ticker-detail/index.test.tsx +15 -136
  298. package/src/plugins/builtin/ticker-detail/index.tsx +2 -93
  299. package/src/plugins/builtin/ticker-detail/overview/components.tsx +6 -5
  300. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +41 -17
  301. package/src/plugins/builtin/ticker-detail/pane.tsx +4 -3
  302. package/src/plugins/builtin/ticker-detail/quote-monitor/index.test.tsx +1 -1
  303. package/src/plugins/builtin/ticker-detail/settings.ts +3 -50
  304. package/src/plugins/builtin/ticker-research-backend-plugin.ts +17 -0
  305. package/src/plugins/builtin/ticker-research-plugin.ts +27 -0
  306. package/src/plugins/builtin/tv/channels.ts +27 -0
  307. package/src/plugins/builtin/tv/index.tsx +40 -0
  308. package/src/plugins/builtin/tv/pane.tsx +286 -0
  309. package/src/plugins/builtin/tv/youtube-stream.ts +100 -0
  310. package/src/plugins/builtin/world-indices/index.tsx +3 -8
  311. package/src/plugins/builtin/yield-curve/index.tsx +8 -8
  312. package/src/plugins/catalog-backend.test.ts +21 -0
  313. package/src/plugins/catalog-backend.ts +42 -0
  314. package/src/plugins/catalog-ui.ts +6 -14
  315. package/src/plugins/ibkr/instance-selection.test.ts +0 -1
  316. package/src/plugins/ownership.ts +143 -0
  317. package/src/plugins/prediction-markets/backend-plugin.ts +19 -0
  318. package/src/plugins/prediction-markets/chart.test.tsx +7 -5
  319. package/src/plugins/prediction-markets/chart.tsx +25 -7
  320. package/src/plugins/registry/index.test.ts +51 -0
  321. package/src/plugins/registry/index.ts +8 -0
  322. package/src/plugins/registry/pane-settings.ts +1 -1
  323. package/src/plugins/runtime/index.test.tsx +2 -2
  324. package/src/remote/app-host.tsx +16 -3
  325. package/src/remote/controller.test.ts +102 -1
  326. package/src/remote/controller.ts +122 -0
  327. package/src/remote/types.ts +11 -0
  328. package/src/renderers/electrobun/bun/core-capabilities.ts +123 -27
  329. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +5 -1
  330. package/src/renderers/electrobun/bun/desktop/initialization.ts +5 -1
  331. package/src/renderers/electrobun/bun/desktop/media.ts +15 -0
  332. package/src/renderers/electrobun/bun/desktop/window-style.ts +4 -1
  333. package/src/renderers/electrobun/bun/desktop/workspace/index.test.ts +32 -1
  334. package/src/renderers/electrobun/bun/desktop/workspace/index.ts +10 -0
  335. package/src/renderers/electrobun/bun/index.ts +5 -0
  336. package/src/renderers/electrobun/bun/tui-entry.ts +1 -6
  337. package/src/renderers/electrobun/view/ai-host.ts +124 -19
  338. package/src/renderers/electrobun/view/backend-rpc.ts +4 -0
  339. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +151 -39
  340. package/src/renderers/electrobun/view/desktop/popover.tsx +166 -0
  341. package/src/renderers/electrobun/view/dialog-host.test.ts +25 -0
  342. package/src/renderers/electrobun/view/dialog-host.tsx +75 -12
  343. package/src/renderers/electrobun/view/host/box.tsx +5 -0
  344. package/src/renderers/electrobun/view/host/chart-surface.tsx +10 -9
  345. package/src/renderers/electrobun/view/host/input.tsx +9 -19
  346. package/src/renderers/electrobun/view/host/media-surface.tsx +170 -0
  347. package/src/renderers/electrobun/view/host/mouse.ts +1 -0
  348. package/src/renderers/electrobun/view/host/style.ts +1 -1
  349. package/src/renderers/electrobun/view/host/tabs.tsx +4 -3
  350. package/src/renderers/electrobun/view/main.tsx +10 -3
  351. package/src/renderers/electrobun/view/styles.css +17 -0
  352. package/src/renderers/electrobun/view/ui-host.tsx +7 -0
  353. package/src/renderers/opentui/chart-surface.test.tsx +52 -6
  354. package/src/renderers/opentui/chart-surface.tsx +95 -11
  355. package/src/renderers/opentui/dialog-host.tsx +36 -5
  356. package/src/renderers/opentui/host.tsx +39 -0
  357. package/src/renderers/opentui/start.tsx +30 -0
  358. package/src/renderers/opentui/ui-host.tsx +2 -0
  359. package/src/sources/provider-router/index.test.ts +43 -0
  360. package/src/sources/provider-router/index.ts +4 -0
  361. package/src/sources/provider-router/supplemental.ts +46 -0
  362. package/src/sources/sec-edgar.test.ts +203 -2
  363. package/src/sources/sec-edgar.ts +70 -15
  364. package/src/state/app/context/index.tsx +13 -1
  365. package/src/state/app/context/selector.test.tsx +62 -1
  366. package/src/state/session-persistence.test.ts +13 -2
  367. package/src/sync/controller.test.ts +67 -0
  368. package/src/sync/core-contributors.test.ts +121 -0
  369. package/src/sync/core-contributors.ts +67 -14
  370. package/src/time-series/alignment.ts +158 -0
  371. package/src/time-series/economic.ts +49 -0
  372. package/src/time-series/field-catalog.ts +306 -0
  373. package/src/time-series/fundamentals.test.ts +505 -0
  374. package/src/time-series/fundamentals.ts +842 -0
  375. package/src/time-series/hooks.ts +45 -0
  376. package/src/time-series/index.ts +14 -0
  377. package/src/time-series/live-quotes.test.ts +219 -0
  378. package/src/time-series/live-quotes.ts +203 -0
  379. package/src/time-series/market-resolution.ts +53 -0
  380. package/src/time-series/market.ts +125 -0
  381. package/src/time-series/reporting.ts +98 -0
  382. package/src/time-series/resolve.test.ts +1281 -0
  383. package/src/time-series/resolve.ts +783 -0
  384. package/src/time-series/spec-studies.test.ts +400 -0
  385. package/src/time-series/spec.ts +487 -0
  386. package/src/time-series/studies.ts +563 -0
  387. package/src/time-series/transforms.test.ts +105 -0
  388. package/src/time-series/transforms.ts +152 -0
  389. package/src/time-series/types.ts +162 -0
  390. package/src/time-series/use-chart-resolution.ts +166 -0
  391. package/src/types/config.ts +9 -11
  392. package/src/types/desktop-window.ts +1 -0
  393. package/src/types/financials.ts +4 -0
  394. package/src/types/media.ts +17 -0
  395. package/src/types/plugin.ts +32 -1
  396. package/src/ui/context-menu.tsx +15 -3
  397. package/src/ui/dialog.tsx +14 -2
  398. package/src/ui/host.tsx +40 -1
  399. package/src/ui/index.tsx +9 -0
  400. package/src/utils/exchanges.test.ts +13 -1
  401. package/src/utils/exchanges.ts +10 -0
  402. package/src/utils/financial-statements.test.ts +138 -0
  403. package/src/utils/financial-statements.ts +115 -8
  404. package/src/utils/format.test.ts +11 -1
  405. package/src/utils/format.ts +7 -0
  406. package/src/version.ts +1 -1
  407. package/src/components/chart/bar-chart-renderer.test.ts +0 -233
  408. package/src/components/chart/bar-chart-renderer.ts +0 -445
  409. package/src/components/chart/comparison/data.test.ts +0 -159
  410. package/src/components/chart/comparison/data.ts +0 -302
  411. package/src/components/chart/comparison/renderer.test.ts +0 -187
  412. package/src/components/chart/comparison/renderer.ts +0 -282
  413. package/src/components/chart/comparison/scene.ts +0 -178
  414. package/src/components/chart/comparison-stock-chart/axis-width.ts +0 -99
  415. package/src/components/chart/comparison-stock-chart/canvas.ts +0 -148
  416. package/src/components/chart/comparison-stock-chart/controls.ts +0 -252
  417. package/src/components/chart/comparison-stock-chart/helpers.ts +0 -101
  418. package/src/components/chart/comparison-stock-chart/interactions.ts +0 -208
  419. package/src/components/chart/comparison-stock-chart/layout-metrics.ts +0 -62
  420. package/src/components/chart/comparison-stock-chart/layout.tsx +0 -155
  421. package/src/components/chart/comparison-stock-chart/legend.tsx +0 -74
  422. package/src/components/chart/comparison-stock-chart/native-surfaces.ts +0 -89
  423. package/src/components/chart/comparison-stock-chart/render-data.ts +0 -227
  424. package/src/components/chart/comparison-stock-chart/render-output.ts +0 -140
  425. package/src/components/chart/comparison-stock-chart/selection-runtime.ts +0 -128
  426. package/src/components/chart/comparison-stock-chart/sources.ts +0 -51
  427. package/src/components/chart/comparison-stock-chart/surface-runtime.ts +0 -159
  428. package/src/components/chart/comparison-stock-chart/toolbar.tsx +0 -117
  429. package/src/components/chart/comparison-stock-chart/types.ts +0 -22
  430. package/src/components/chart/comparison-stock-chart/view.tsx +0 -572
  431. package/src/components/chart/comparison-stock-chart/viewport-runtime.ts +0 -239
  432. package/src/components/chart/comparison-stock-chart.tsx +0 -24
  433. package/src/components/chart/core/axis-measure.ts +0 -33
  434. package/src/components/chart/core/controller.test.ts +0 -157
  435. package/src/components/chart/core/controller.ts +0 -349
  436. package/src/components/chart/core/indicator-selector.tsx +0 -75
  437. package/src/components/chart/core/keyboard.ts +0 -24
  438. package/src/components/chart/core/pane-settings.test.ts +0 -52
  439. package/src/components/chart/core/pane-settings.ts +0 -141
  440. package/src/components/chart/core/scroll.test.ts +0 -64
  441. package/src/components/chart/core/scroll.ts +0 -82
  442. package/src/components/chart/core/window-viewport.test.ts +0 -69
  443. package/src/components/chart/core/window-viewport.ts +0 -162
  444. package/src/components/chart/display-cursor.ts +0 -153
  445. package/src/components/chart/indicators/bands.test.ts +0 -36
  446. package/src/components/chart/indicators/bands.ts +0 -29
  447. package/src/components/chart/indicators/moving-averages.test.ts +0 -39
  448. package/src/components/chart/indicators/moving-averages.ts +0 -42
  449. package/src/components/chart/indicators/options.test.ts +0 -32
  450. package/src/components/chart/indicators/options.ts +0 -107
  451. package/src/components/chart/indicators/oscillators.test.ts +0 -58
  452. package/src/components/chart/indicators/oscillators.ts +0 -92
  453. package/src/components/chart/native/canvas-bitmaps.ts +0 -140
  454. package/src/components/chart/native/raster/comparison-chart.ts +0 -162
  455. package/src/components/chart/native/surface/hooks.ts +0 -144
  456. package/src/components/chart/native/surface/rendering.ts +0 -211
  457. package/src/components/chart/static/bar-chart-surface.test.tsx +0 -101
  458. package/src/components/chart/static/bar-chart-surface.tsx +0 -292
  459. package/src/components/chart/stock-chart/auto.ts +0 -216
  460. package/src/components/chart/stock-chart/axis-width.ts +0 -146
  461. package/src/components/chart/stock-chart/bitmaps.ts +0 -22
  462. package/src/components/chart/stock-chart/canvas.ts +0 -202
  463. package/src/components/chart/stock-chart/controls.tsx +0 -149
  464. package/src/components/chart/stock-chart/cursor.ts +0 -60
  465. package/src/components/chart/stock-chart/data-runtime.ts +0 -128
  466. package/src/components/chart/stock-chart/footer.test.ts +0 -65
  467. package/src/components/chart/stock-chart/footer.ts +0 -303
  468. package/src/components/chart/stock-chart/geometry.ts +0 -160
  469. package/src/components/chart/stock-chart/index.test.ts +0 -532
  470. package/src/components/chart/stock-chart/index.tsx +0 -29
  471. package/src/components/chart/stock-chart/indicators.ts +0 -226
  472. package/src/components/chart/stock-chart/interaction-runtime.ts +0 -44
  473. package/src/components/chart/stock-chart/interactions.ts +0 -300
  474. package/src/components/chart/stock-chart/keyboard.ts +0 -373
  475. package/src/components/chart/stock-chart/layout-metrics.ts +0 -62
  476. package/src/components/chart/stock-chart/layout.tsx +0 -177
  477. package/src/components/chart/stock-chart/native-surfaces.ts +0 -121
  478. package/src/components/chart/stock-chart/presentation.ts +0 -67
  479. package/src/components/chart/stock-chart/renderer-switch.test.tsx +0 -263
  480. package/src/components/chart/stock-chart/rendering/bounds.ts +0 -116
  481. package/src/components/chart/stock-chart/rendering/candidates.ts +0 -145
  482. package/src/components/chart/stock-chart/rendering/data.ts +0 -370
  483. package/src/components/chart/stock-chart/rendering/invalidation.ts +0 -68
  484. package/src/components/chart/stock-chart/rendering/output.ts +0 -304
  485. package/src/components/chart/stock-chart/rendering/planning.ts +0 -122
  486. package/src/components/chart/stock-chart/rendering/projection.test.tsx +0 -98
  487. package/src/components/chart/stock-chart/rendering/projection.ts +0 -112
  488. package/src/components/chart/stock-chart/rendering/state.test.ts +0 -70
  489. package/src/components/chart/stock-chart/rendering/state.ts +0 -283
  490. package/src/components/chart/stock-chart/requests.ts +0 -337
  491. package/src/components/chart/stock-chart/resolution-support.ts +0 -96
  492. package/src/components/chart/stock-chart/resolved/runtime.ts +0 -289
  493. package/src/components/chart/stock-chart/resolved.tsx +0 -359
  494. package/src/components/chart/stock-chart/settings.ts +0 -81
  495. package/src/components/chart/stock-chart/surface-runtime.ts +0 -62
  496. package/src/components/chart/stock-chart/types.ts +0 -25
  497. package/src/components/chart/stock-chart/view.tsx +0 -155
  498. package/src/components/chart/stock-chart/viewport/effects.ts +0 -293
  499. package/src/components/chart/stock-chart/viewport/index.ts +0 -144
  500. package/src/components/chart/stock-chart/viewport/runtime.ts +0 -375
  501. package/src/components/chart/time-axis-label.tsx +0 -175
  502. package/src/plugins/builtin/ai/gloomberb-cli.ts +0 -71
  503. package/src/plugins/builtin/ai/screener/action-bar.tsx +0 -58
  504. package/src/plugins/builtin/comparison-chart/index.test.tsx +0 -848
  505. package/src/plugins/builtin/comparison-chart/index.tsx +0 -194
  506. package/src/plugins/builtin/econ/fred-cache.ts +0 -106
  507. package/src/plugins/builtin/plugin-groups.ts +0 -130
  508. package/src/plugins/builtin/ticker-detail/chart-pane.tsx +0 -91
  509. package/src/plugins/builtin/ticker-detail/chart-tab.tsx +0 -100
  510. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/content.tsx +0 -296
  511. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/data.ts +0 -62
  512. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/model.ts +0 -608
  513. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/settings.ts +0 -65
  514. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph/types.ts +0 -58
  515. package/src/plugins/builtin/ticker-detail/data-panes/fundamental-graph.tsx +0 -138
  516. package/src/plugins/builtin/ticker-detail/data-panes.test.ts +0 -220
@@ -0,0 +1,532 @@
1
+ import type { PaneDef, PaneTemplateDef } from "../../types/plugin";
2
+
3
+ export type PaneFunctionReadiness = "ready" | "partial" | "unsupported";
4
+ export type PaneFunctionTickerCardinality = "none" | "one" | "one-or-more" | "two-or-more" | "one-or-two";
5
+ export type PaneFunctionOptionType = "enum" | "integer" | "string" | "boolean";
6
+ export type NormalizedPaneFunctionOptions = Record<string, string | number | boolean>;
7
+
8
+ export interface PaneFunctionOptionValue {
9
+ value: string;
10
+ aliases?: string[];
11
+ }
12
+
13
+ export interface PaneFunctionOptionDef {
14
+ key: string;
15
+ description: string;
16
+ type: PaneFunctionOptionType;
17
+ aliases?: string[];
18
+ values?: PaneFunctionOptionValue[];
19
+ defaultValue?: string | number | boolean;
20
+ minimum?: number;
21
+ maximum?: number;
22
+ settingKey?: string;
23
+ pluginState?: {
24
+ pluginId: string;
25
+ key?: string;
26
+ };
27
+ }
28
+
29
+ export interface PaneFunctionCapability {
30
+ id: string;
31
+ botSafe: boolean;
32
+ tickerCardinality: PaneFunctionTickerCardinality;
33
+ aliases: string[];
34
+ intents: string[];
35
+ outputKind: string;
36
+ reportReadiness: PaneFunctionReadiness;
37
+ screenshotReadiness: PaneFunctionReadiness;
38
+ dataRequirements: string[];
39
+ limitations: string[];
40
+ options: PaneFunctionOptionDef[];
41
+ }
42
+
43
+ const PERIOD_OPTION: PaneFunctionOptionDef = {
44
+ key: "period",
45
+ description: "Financial reporting period.",
46
+ type: "enum",
47
+ aliases: ["financialPeriod"],
48
+ values: [
49
+ { value: "annual", aliases: ["a", "ann", "year", "yearly", "fy"] },
50
+ { value: "quarterly", aliases: ["q", "qtr", "quarter"] },
51
+ ],
52
+ defaultValue: "annual",
53
+ };
54
+
55
+ const GRAPH_PERIOD_OPTION: PaneFunctionOptionDef = {
56
+ ...PERIOD_OPTION,
57
+ };
58
+
59
+ const GRAPH_PERIOD_COUNT_OPTION: PaneFunctionOptionDef = {
60
+ key: "periods",
61
+ description: "Keep only the latest N annual or quarterly observations per ticker.",
62
+ type: "integer",
63
+ aliases: ["years", "limit"],
64
+ minimum: 1,
65
+ maximum: 40,
66
+ };
67
+
68
+ const RANGE_VALUES: PaneFunctionOptionValue[] = [
69
+ { value: "1D", aliases: ["day", "daily"] },
70
+ { value: "1W", aliases: ["week", "weekly"] },
71
+ { value: "1M", aliases: ["month", "monthly"] },
72
+ { value: "3M" },
73
+ { value: "6M" },
74
+ { value: "1Y", aliases: ["year"] },
75
+ { value: "5Y", aliases: ["five-years", "five years"] },
76
+ { value: "ALL", aliases: ["max", "maximum"] },
77
+ ];
78
+
79
+ const FUNDAMENTAL_METRIC_VALUES: PaneFunctionOptionValue[] = [
80
+ { value: "totalRevenue", aliases: ["revenue", "sales"] },
81
+ { value: "grossProfit", aliases: ["gross profit"] },
82
+ { value: "grossMargin", aliases: ["gross margin"] },
83
+ { value: "operatingIncome", aliases: ["operating income", "ebit"] },
84
+ { value: "operatingMargin", aliases: ["operating margin"] },
85
+ { value: "netIncome", aliases: ["net income", "profit", "earnings"] },
86
+ { value: "netMargin", aliases: ["net margin", "profit margin"] },
87
+ { value: "operatingCashFlow", aliases: ["operating cash flow", "cash flow", "ocf"] },
88
+ { value: "freeCashFlow", aliases: ["free cash flow", "fcf"] },
89
+ { value: "freeCashFlowMargin", aliases: ["free cash flow margin", "fcf margin"] },
90
+ { value: "totalAssets", aliases: ["assets", "total assets"] },
91
+ { value: "totalDebt", aliases: ["debt", "total debt"] },
92
+ { value: "totalEquity", aliases: ["equity", "book value"] },
93
+ { value: "eps", aliases: ["earnings per share"] },
94
+ ];
95
+
96
+ const VALUATION_METRIC_VALUES: PaneFunctionOptionValue[] = [
97
+ { value: "trailingPE", aliases: ["pe", "p/e", "trailing pe"] },
98
+ { value: "forwardPE", aliases: ["forward pe", "forward p/e"] },
99
+ { value: "pegRatio", aliases: ["peg", "peg ratio"] },
100
+ { value: "priceSales", aliases: ["price sales", "price to sales", "p/s"] },
101
+ { value: "evSales", aliases: ["ev sales", "ev/sales"] },
102
+ { value: "evEbitda", aliases: ["ev ebitda", "ev/ebitda"] },
103
+ { value: "priceFcf", aliases: ["price fcf", "price to free cash flow", "p/fcf"] },
104
+ ];
105
+
106
+ const CAPABILITIES: Record<string, PaneFunctionCapability> = {
107
+ "chart-composer-pane": {
108
+ id: "chart-composer",
109
+ botSafe: true,
110
+ tickerCardinality: "none",
111
+ aliases: ["custom chart", "mixed series chart", "chart composer", "economic chart"],
112
+ intents: ["chart arbitrary market fundamental valuation and economic series together"],
113
+ outputKind: "chart-series",
114
+ reportReadiness: "ready",
115
+ screenshotReadiness: "ready",
116
+ dataRequirements: ["data required by each authored chart series"],
117
+ limitations: ["FRED observations do not include historical vintage availability dates."],
118
+ options: [
119
+ {
120
+ key: "rangePreset",
121
+ description: "Chart history window.",
122
+ type: "enum",
123
+ aliases: ["range"],
124
+ values: RANGE_VALUES,
125
+ },
126
+ {
127
+ key: "chartResolution",
128
+ description: "Market-price sampling resolution.",
129
+ type: "enum",
130
+ aliases: ["resolution"],
131
+ values: ["auto", "1m", "5m", "15m", "30m", "45m", "1h", "1d", "1wk", "1mo"]
132
+ .map((value) => ({ value })),
133
+ },
134
+ ],
135
+ },
136
+ "financial-analysis-pane": {
137
+ id: "financial-statements",
138
+ botSafe: true,
139
+ tickerCardinality: "one",
140
+ aliases: ["financials", "financial statement", "income statement", "balance sheet", "cash flow statement"],
141
+ intents: ["inspect company financial statements", "review income balance sheet or cash flow"],
142
+ outputKind: "financial-statement",
143
+ reportReadiness: "ready",
144
+ screenshotReadiness: "ready",
145
+ dataRequirements: ["ticker financial statements"],
146
+ limitations: ["One company per invocation; use GF for cross-company metric comparisons."],
147
+ options: [
148
+ PERIOD_OPTION,
149
+ {
150
+ key: "statement",
151
+ description: "Statement to display.",
152
+ type: "enum",
153
+ aliases: ["tab", "financialStatement"],
154
+ values: [
155
+ { value: "income", aliases: ["income statement", "is"] },
156
+ { value: "balance", aliases: ["balance sheet", "bs"] },
157
+ { value: "cashflow", aliases: ["cash flow", "cash flow statement", "cf", "cashflows"] },
158
+ ],
159
+ defaultValue: "income",
160
+ },
161
+ ],
162
+ },
163
+ "fundamental-graph-pane": {
164
+ id: "fundamental-series",
165
+ botSafe: true,
166
+ tickerCardinality: "one-or-more",
167
+ aliases: [
168
+ "fundamental comparison",
169
+ "financial metric comparison",
170
+ "cash flow comparison",
171
+ "revenue comparison",
172
+ "earnings comparison",
173
+ "operating cash flow",
174
+ "free cash flow",
175
+ "fcf",
176
+ "ocf",
177
+ ],
178
+ intents: ["compare company fundamentals over time", "compare cash flow revenue earnings margins assets debt or equity"],
179
+ outputKind: "fundamental-series",
180
+ reportReadiness: "ready",
181
+ screenshotReadiness: "ready",
182
+ dataRequirements: ["ticker annual or quarterly financial statements"],
183
+ limitations: ["One metric per invocation; run twice when both operating and free cash flow are requested."],
184
+ options: [
185
+ {
186
+ key: "metric",
187
+ description: "Fundamental metric to compare.",
188
+ type: "enum",
189
+ values: FUNDAMENTAL_METRIC_VALUES,
190
+ defaultValue: "totalRevenue",
191
+ },
192
+ GRAPH_PERIOD_OPTION,
193
+ GRAPH_PERIOD_COUNT_OPTION,
194
+ ],
195
+ },
196
+ "valuation-graph-pane": {
197
+ id: "valuation-series",
198
+ botSafe: true,
199
+ tickerCardinality: "one-or-more",
200
+ aliases: ["valuation comparison", "multiple comparison", "pe comparison", "price to sales comparison", "ev ebitda"],
201
+ intents: ["compare company valuation multiples over time"],
202
+ outputKind: "valuation-series",
203
+ reportReadiness: "ready",
204
+ screenshotReadiness: "ready",
205
+ dataRequirements: ["ticker financial statements", "price history"],
206
+ limitations: ["Historical multiples require usable prices and statement share counts."],
207
+ options: [
208
+ {
209
+ key: "metric",
210
+ description: "Valuation metric to compare.",
211
+ type: "enum",
212
+ values: VALUATION_METRIC_VALUES,
213
+ defaultValue: "priceSales",
214
+ },
215
+ GRAPH_PERIOD_OPTION,
216
+ GRAPH_PERIOD_COUNT_OPTION,
217
+ ],
218
+ },
219
+ "comparison-chart-pane": {
220
+ id: "price-comparison",
221
+ botSafe: true,
222
+ tickerCardinality: "two-or-more",
223
+ aliases: ["stock comparison", "price performance comparison", "returns comparison", "compare stock prices"],
224
+ intents: ["compare market price performance for multiple securities"],
225
+ outputKind: "price-performance",
226
+ reportReadiness: "ready",
227
+ screenshotReadiness: "ready",
228
+ dataRequirements: ["price history"],
229
+ limitations: ["Compares market prices or percentage returns, never company financial statements."],
230
+ options: [
231
+ {
232
+ key: "rangePreset",
233
+ description: "Price-history window.",
234
+ type: "enum",
235
+ aliases: ["range"],
236
+ values: RANGE_VALUES,
237
+ defaultValue: "1Y",
238
+ },
239
+ {
240
+ key: "axisMode",
241
+ description: "Display raw price or normalized percentage performance.",
242
+ type: "enum",
243
+ values: [
244
+ { value: "percent", aliases: ["return", "returns", "performance"] },
245
+ { value: "price", aliases: ["prices"] },
246
+ ],
247
+ defaultValue: "percent",
248
+ },
249
+ {
250
+ key: "chartResolution",
251
+ description: "Price sampling resolution.",
252
+ type: "enum",
253
+ aliases: ["resolution"],
254
+ values: ["1m", "5m", "15m", "30m", "45m", "1h", "1d", "1wk", "1mo"].map((value) => ({ value })),
255
+ defaultValue: "1d",
256
+ },
257
+ ],
258
+ },
259
+ "correlation-pane": {
260
+ id: "return-correlation",
261
+ botSafe: true,
262
+ tickerCardinality: "two-or-more",
263
+ aliases: ["correlation", "return correlation", "correlation matrix", "pearson correlation"],
264
+ intents: ["compare correlations between security returns"],
265
+ outputKind: "correlation-matrix",
266
+ reportReadiness: "ready",
267
+ screenshotReadiness: "partial",
268
+ dataRequirements: ["date-aligned price history"],
269
+ limitations: ["Correlation is computed from daily returns with at least five shared observations."],
270
+ options: [{
271
+ key: "rangePreset",
272
+ description: "Correlation history window.",
273
+ type: "enum",
274
+ aliases: ["range"],
275
+ values: RANGE_VALUES.filter(({ value }) => !["1D", "1W", "ALL"].includes(value)),
276
+ defaultValue: "1Y",
277
+ settingKey: "rangePreset",
278
+ }],
279
+ },
280
+ "relationship-graph-pane": {
281
+ id: "security-relationship",
282
+ botSafe: true,
283
+ tickerCardinality: "one-or-two",
284
+ aliases: ["relationship", "ratio", "beta", "regression", "rolling correlation"],
285
+ intents: ["analyze ratio correlation and regression between two securities"],
286
+ outputKind: "relationship-analysis",
287
+ reportReadiness: "ready",
288
+ screenshotReadiness: "partial",
289
+ dataRequirements: ["date-aligned price history"],
290
+ limitations: ["A single ticker is compared with SPY."],
291
+ options: [
292
+ {
293
+ key: "range",
294
+ description: "Relationship history window.",
295
+ type: "enum",
296
+ aliases: ["rangePreset"],
297
+ values: RANGE_VALUES.filter(({ value }) => !["1D", "1W"].includes(value)),
298
+ defaultValue: "1Y",
299
+ pluginState: { pluginId: "market-overview" },
300
+ },
301
+ {
302
+ key: "correlationWindow",
303
+ description: "Rolling-correlation window in observations.",
304
+ type: "integer",
305
+ aliases: ["window"],
306
+ defaultValue: 120,
307
+ minimum: 5,
308
+ maximum: 1000,
309
+ pluginState: { pluginId: "market-overview" },
310
+ },
311
+ ],
312
+ },
313
+ "relative-valuation-pane": {
314
+ id: "relative-valuation",
315
+ botSafe: true,
316
+ tickerCardinality: "one-or-more",
317
+ aliases: ["relative valuation", "peer valuation", "valuation comps", "compare multiples"],
318
+ intents: ["compare current valuation and operating metrics across peers"],
319
+ outputKind: "relative-valuation",
320
+ reportReadiness: "ready",
321
+ screenshotReadiness: "partial",
322
+ dataRequirements: ["ticker quote and fundamentals"],
323
+ limitations: ["Uses current provider fundamentals rather than a historical series."],
324
+ options: [],
325
+ },
326
+ "quote-monitor-pane": {
327
+ id: "quote-comparison",
328
+ botSafe: true,
329
+ tickerCardinality: "one-or-more",
330
+ aliases: ["quotes", "stock prices", "market snapshot", "price comparison"],
331
+ intents: ["compare current quotes for one or more securities"],
332
+ outputKind: "quote-comparison",
333
+ reportReadiness: "ready",
334
+ screenshotReadiness: "ready",
335
+ dataRequirements: ["current quotes"],
336
+ limitations: [],
337
+ options: [],
338
+ },
339
+ "historical-prices-pane": {
340
+ id: "historical-prices",
341
+ botSafe: true,
342
+ tickerCardinality: "one",
343
+ aliases: ["historical prices", "price history", "ohlcv", "daily prices"],
344
+ intents: ["inspect historical open high low close and volume"],
345
+ outputKind: "price-history",
346
+ reportReadiness: "ready",
347
+ screenshotReadiness: "partial",
348
+ dataRequirements: ["price history"],
349
+ limitations: [],
350
+ options: [{
351
+ key: "range",
352
+ description: "Price-history window.",
353
+ type: "enum",
354
+ aliases: ["rangePreset"],
355
+ values: RANGE_VALUES,
356
+ defaultValue: "ALL",
357
+ pluginState: { pluginId: "ticker-research" },
358
+ }],
359
+ },
360
+ "graph-price-pane": {
361
+ id: "price-chart",
362
+ botSafe: true,
363
+ tickerCardinality: "one",
364
+ aliases: ["price chart", "stock chart", "historical chart"],
365
+ intents: ["chart a security price over time"],
366
+ outputKind: "price-history",
367
+ reportReadiness: "ready",
368
+ screenshotReadiness: "ready",
369
+ dataRequirements: ["price history"],
370
+ limitations: [],
371
+ options: [{
372
+ key: "rangePreset",
373
+ settingKey: "chartRangePreset",
374
+ description: "Chart history window.",
375
+ type: "enum",
376
+ aliases: ["range"],
377
+ values: RANGE_VALUES,
378
+ defaultValue: "5Y",
379
+ }],
380
+ },
381
+ "graph-intraday-price-pane": {
382
+ id: "intraday-price-chart",
383
+ botSafe: true,
384
+ tickerCardinality: "one",
385
+ aliases: ["intraday chart", "intraday price", "one day chart"],
386
+ intents: ["chart intraday security prices"],
387
+ outputKind: "price-history",
388
+ reportReadiness: "ready",
389
+ screenshotReadiness: "partial",
390
+ dataRequirements: ["intraday price history"],
391
+ limitations: ["Intraday availability depends on the selected market-data provider."],
392
+ options: [],
393
+ },
394
+ };
395
+
396
+ const UNSUPPORTED_CAPABILITY: PaneFunctionCapability = {
397
+ id: "unverified-pane",
398
+ botSafe: false,
399
+ tickerCardinality: "none",
400
+ aliases: [],
401
+ intents: [],
402
+ outputKind: "pane",
403
+ reportReadiness: "unsupported",
404
+ screenshotReadiness: "unsupported",
405
+ dataRequirements: [],
406
+ limitations: ["This UI pane has not been verified as a deterministic CLI or bot capability."],
407
+ options: [],
408
+ };
409
+
410
+ function optionToken(value: string): string {
411
+ return value.trim().toLowerCase().replace(/[\s_.-]+/g, "");
412
+ }
413
+
414
+ export function getPaneFunctionCapability(
415
+ template: PaneTemplateDef | undefined,
416
+ _pane: PaneDef,
417
+ ): PaneFunctionCapability {
418
+ return template ? CAPABILITIES[template.id] ?? UNSUPPORTED_CAPABILITY : UNSUPPORTED_CAPABILITY;
419
+ }
420
+
421
+ function resolveOptionDef(
422
+ capability: PaneFunctionCapability,
423
+ rawKey: string,
424
+ ): PaneFunctionOptionDef | undefined {
425
+ const token = optionToken(rawKey);
426
+ return capability.options.find((option) => (
427
+ optionToken(option.key) === token
428
+ || option.aliases?.some((alias) => optionToken(alias) === token)
429
+ ));
430
+ }
431
+
432
+ function normalizeEnumValue(option: PaneFunctionOptionDef, rawValue: string): string {
433
+ const token = optionToken(rawValue);
434
+ const match = option.values?.find((candidate) => (
435
+ optionToken(candidate.value) === token
436
+ || candidate.aliases?.some((alias) => optionToken(alias) === token)
437
+ ));
438
+ if (match) return match.value;
439
+ throw new Error(
440
+ `Invalid --${option.key} value "${rawValue}". Use one of: ${option.values?.map(({ value }) => value).join(", ") ?? ""}.`,
441
+ );
442
+ }
443
+
444
+ function normalizeOptionValue(option: PaneFunctionOptionDef, rawValue: string | true): string | number | boolean {
445
+ if (option.type === "boolean") {
446
+ if (rawValue === true) return true;
447
+ if (/^true$/i.test(rawValue)) return true;
448
+ if (/^false$/i.test(rawValue)) return false;
449
+ throw new Error(`Invalid --${option.key} value "${rawValue}". Use true or false.`);
450
+ }
451
+ if (rawValue === true) throw new Error(`--${option.key} requires a value.`);
452
+ if (option.type === "enum") return normalizeEnumValue(option, rawValue);
453
+ if (option.type === "integer") {
454
+ const value = Number(rawValue);
455
+ if (!Number.isInteger(value)) throw new Error(`--${option.key} must be an integer.`);
456
+ if (option.minimum != null && value < option.minimum) {
457
+ throw new Error(`--${option.key} must be at least ${option.minimum}.`);
458
+ }
459
+ if (option.maximum != null && value > option.maximum) {
460
+ throw new Error(`--${option.key} must be at most ${option.maximum}.`);
461
+ }
462
+ return value;
463
+ }
464
+ return rawValue;
465
+ }
466
+
467
+ export function normalizeCapabilityOptions(
468
+ capability: PaneFunctionCapability,
469
+ options: Record<string, string | true>,
470
+ settings: { strict?: boolean } = {},
471
+ ): NormalizedPaneFunctionOptions {
472
+ if (!capability.botSafe) {
473
+ return Object.fromEntries(Object.entries(options).map(([key, value]) => [key, value]));
474
+ }
475
+
476
+ const normalized: Record<string, string | number | boolean> = {};
477
+ for (const option of capability.options) {
478
+ if (option.defaultValue !== undefined) normalized[option.key] = option.defaultValue;
479
+ }
480
+ for (const [rawKey, rawValue] of Object.entries(options)) {
481
+ const option = resolveOptionDef(capability, rawKey);
482
+ if (!option) {
483
+ if (settings.strict === false) {
484
+ normalized[rawKey] = rawValue;
485
+ continue;
486
+ }
487
+ const supported = capability.options.map(({ key }) => `--${key}`).join(", ");
488
+ throw new Error(
489
+ `${capability.id} does not support --${rawKey}.${supported ? ` Supported options: ${supported}.` : " It has no options."}`,
490
+ );
491
+ }
492
+ normalized[option.key] = normalizeOptionValue(option, rawValue);
493
+ }
494
+ return normalized;
495
+ }
496
+
497
+ export function capabilityPaneSettings(
498
+ capability: PaneFunctionCapability,
499
+ options: NormalizedPaneFunctionOptions,
500
+ ): Record<string, unknown> {
501
+ const settings: Record<string, unknown> = {};
502
+ for (const option of capability.options) {
503
+ if (option.pluginState) continue;
504
+ const value = options[option.key];
505
+ if (value !== undefined) settings[option.settingKey ?? option.key] = value;
506
+ }
507
+ return settings;
508
+ }
509
+
510
+ export function capabilityPluginState(
511
+ capability: PaneFunctionCapability,
512
+ options: NormalizedPaneFunctionOptions,
513
+ ): Record<string, Record<string, unknown>> {
514
+ const pluginState: Record<string, Record<string, unknown>> = {};
515
+ for (const option of capability.options) {
516
+ if (!option.pluginState) continue;
517
+ const value = options[option.key];
518
+ if (value === undefined) continue;
519
+ const plugin = pluginState[option.pluginState.pluginId] ?? {};
520
+ plugin[option.pluginState.key ?? option.key] = value;
521
+ pluginState[option.pluginState.pluginId] = plugin;
522
+ }
523
+ return pluginState;
524
+ }
525
+
526
+ export function capabilityOptionSummary(capability: PaneFunctionCapability): string[] {
527
+ return capability.options.map((option) => {
528
+ const values = option.values?.map(({ value }) => value).join("|");
529
+ const defaultValue = option.defaultValue !== undefined ? ` default=${String(option.defaultValue)}` : "";
530
+ return `--${option.key}${values ? ` <${values}>` : ` <${option.type}>`}${defaultValue}`;
531
+ });
532
+ }
@@ -5,6 +5,11 @@ import {
5
5
  normalizeLookupToken,
6
6
  type ParsedPaneCatalogArgs,
7
7
  } from "./options";
8
+ import {
9
+ capabilityOptionSummary,
10
+ getPaneFunctionCapability,
11
+ type PaneFunctionCapability,
12
+ } from "./capabilities";
8
13
 
9
14
  export interface PaneFunctionCatalog {
10
15
  panes: ReadonlyMap<string, PaneDef>;
@@ -24,6 +29,7 @@ export interface PaneCatalogEntry {
24
29
  argPlaceholder?: string;
25
30
  keywords: string[];
26
31
  defaultSettings: Record<string, unknown>;
32
+ capability: PaneFunctionCapability;
27
33
  }
28
34
 
29
35
  export function buildTemplateContext(context: MarketContext, symbol: string | null) {
@@ -122,6 +128,7 @@ async function buildTemplateCatalogEntry(
122
128
  argPlaceholder: template.shortcut?.argPlaceholder,
123
129
  keywords: template.keywords ?? [],
124
130
  defaultSettings,
131
+ capability: getPaneFunctionCapability(template, pane),
125
132
  };
126
133
  }
127
134
 
@@ -149,6 +156,7 @@ export async function buildPaneCatalogEntries(
149
156
  paneName: pane.name,
150
157
  keywords: [],
151
158
  defaultSettings: {},
159
+ capability: getPaneFunctionCapability(undefined, pane),
152
160
  });
153
161
  }
154
162
 
@@ -176,23 +184,37 @@ function paneCatalogSearchScore(entry: PaneCatalogEntry, query: string): number
176
184
  entry.argKind,
177
185
  entry.argPlaceholder,
178
186
  ...entry.keywords,
187
+ ...entry.capability.aliases,
188
+ ...entry.capability.intents,
189
+ entry.capability.outputKind,
190
+ ...entry.capability.options.flatMap((option) => [
191
+ option.key,
192
+ option.description,
193
+ ...(option.aliases ?? []),
194
+ ...(option.values ?? []).flatMap((value) => [value.value, ...(value.aliases ?? [])]),
195
+ ]),
179
196
  ...Object.keys(entry.defaultSettings),
180
197
  ].filter((value): value is string => !!value).join(" ").toLowerCase();
181
198
 
182
- let score = searchable.includes(query.toLowerCase()) ? 4 : 0;
199
+ let score = searchable.includes(query.toLowerCase()) ? 12 : 0;
200
+ let matchedTerms = 0;
183
201
  for (const term of terms) {
184
202
  const normalized = normalizeLookupToken(term);
185
203
  if (exactTokens.includes(normalized)) {
186
204
  score += 8;
205
+ matchedTerms += 1;
187
206
  } else if (searchable.includes(term)) {
188
207
  score += 2;
208
+ matchedTerms += 1;
189
209
  } else if (searchable.includes(normalized)) {
190
210
  score += 1;
191
- } else {
192
- return 0;
211
+ matchedTerms += 1;
193
212
  }
194
213
  }
195
214
 
215
+ if (matchedTerms === 0) return 0;
216
+ score += Math.round((matchedTerms / terms.length) * 8);
217
+ if (entry.capability.botSafe) score += 2;
196
218
  return score;
197
219
  }
198
220
 
@@ -233,11 +255,24 @@ export function renderPaneCatalogReport(entries: PaneCatalogEntry[], args: Parse
233
255
  if (entry.shortcut) lines.push(` Shortcut: ${entry.shortcut}`);
234
256
  if (entry.argKind) lines.push(` Argument: ${entry.argKind}${entry.argPlaceholder ? ` (${entry.argPlaceholder})` : ""}`);
235
257
  if (entry.keywords.length > 0) lines.push(` Keywords: ${entry.keywords.join(", ")}`);
258
+ lines.push(` Bot safe: ${entry.capability.botSafe ? "yes" : "no"}`);
259
+ lines.push(` Output: ${entry.capability.outputKind}`);
260
+ lines.push(` Readiness: report=${entry.capability.reportReadiness}, screenshot=${entry.capability.screenshotReadiness}`);
261
+ if (entry.capability.aliases.length > 0) lines.push(` Aliases: ${entry.capability.aliases.join(", ")}`);
262
+ if (entry.capability.intents.length > 0) lines.push(` Intents: ${entry.capability.intents.join("; ")}`);
263
+ const optionSummary = capabilityOptionSummary(entry.capability);
264
+ if (optionSummary.length > 0) lines.push(` Options: ${optionSummary.join(", ")}`);
265
+ if (entry.capability.dataRequirements.length > 0) {
266
+ lines.push(` Requires: ${entry.capability.dataRequirements.join(", ")}`);
267
+ }
268
+ if (entry.capability.limitations.length > 0) {
269
+ lines.push(` Limitations: ${entry.capability.limitations.join(" ")}`);
270
+ }
236
271
  lines.push(` Defaults: ${formatCatalogSettings(entry.defaultSettings)}`);
237
272
  lines.push(` Examples: gloomberb fn ${entry.token} ${arg} | gloomberb shot ${entry.token} ${arg} --output /tmp/${entry.token.toLowerCase()}.png`);
238
273
  lines.push("");
239
274
  }
240
275
 
241
- lines.push("Generic screenshot state options: --tab <id>, --activeTabId <id>, --state key=value, --state.<key> value.");
276
+ lines.push("Use --require-bot-safe to reject unverified functions and undeclared options. Generic UI screenshots may also accept --tab, --activeTabId, and --state options.");
242
277
  return lines.join("\n").trimEnd();
243
278
  }
@@ -0,0 +1,17 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { clipPriceHistoryToRange } from "./data";
3
+
4
+ describe("clipPriceHistoryToRange", () => {
5
+ test("anchors the requested window to the newest provider observation", () => {
6
+ const points = [
7
+ { date: new Date("2025-07-16T00:00:00Z"), close: 100 },
8
+ { date: new Date("2025-07-17T00:00:00Z"), close: 101 },
9
+ { date: new Date("2026-07-17T00:00:00Z"), close: 120 },
10
+ ];
11
+
12
+ expect(clipPriceHistoryToRange(points, "1Y").map(({ date }) => date.toISOString().slice(0, 10))).toEqual([
13
+ "2025-07-17",
14
+ "2026-07-17",
15
+ ]);
16
+ });
17
+ });