gloomberb 0.16.4 → 0.16.6

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 (852) hide show
  1. package/README.md +14 -91
  2. package/package.json +5 -1
  3. package/src/{plugins/builtin/cloud → account}/auth-form.tsx +9 -9
  4. package/src/{plugins/builtin/cloud → account}/auth-model.ts +4 -4
  5. package/src/account/billing.ts +57 -0
  6. package/src/{plugins/builtin/cloud → account}/device-signin-dialog.tsx +18 -12
  7. package/src/{plugins/builtin/cloud → account}/device-signin.ts +2 -2
  8. package/src/{plugins/builtin/cloud → account}/email-auth-attempt.ts +2 -2
  9. package/src/account/session.ts +16 -0
  10. package/src/{plugins/builtin/cloud → account}/upgrade-dialog.tsx +16 -15
  11. package/src/{plugins/builtin/cloud → account}/upgrade-personalization.ts +7 -7
  12. package/src/{plugins/builtin/cloud → account}/upgrade-tickers.ts +6 -6
  13. package/src/{plugins/builtin/cloud → account}/verification-panel.tsx +6 -6
  14. package/src/api-client/central-bank-rates.ts +6 -1
  15. package/src/api-client/chat.ts +26 -0
  16. package/src/api-client/credit-boards.ts +2 -0
  17. package/src/api-client/data.ts +73 -3
  18. package/src/api-client/earnings.ts +6 -0
  19. package/src/api-client/europe-energy.ts +106 -0
  20. package/src/api-client/futures-curve.ts +56 -0
  21. package/src/api-client/index.ts +13 -1
  22. package/src/api-client/market-discovery.ts +13 -1
  23. package/src/api-client/normalizers.ts +32 -0
  24. package/src/api-client/paths.ts +7 -0
  25. package/src/api-client/perps.ts +8 -0
  26. package/src/api-client/request.ts +9 -2
  27. package/src/api-client/research-activity.ts +15 -10
  28. package/src/api-client/socket.ts +29 -0
  29. package/src/api-client/themes.ts +22 -1
  30. package/src/api-client/types.ts +78 -2
  31. package/src/api-client/yield-curves.ts +8 -0
  32. package/src/app/global-shortcuts.ts +50 -2
  33. package/src/app/keybindings/actions.ts +12 -1
  34. package/src/app/pane-runtime/plugin-bindings.ts +2 -2
  35. package/src/app/pane-runtime/ticker-open-runtime.ts +16 -6
  36. package/src/app/runtime/desktop-deeplink.ts +10 -5
  37. package/src/app/runtime/startup.ts +1 -1
  38. package/src/app.tsx +6 -0
  39. package/src/architecture/core-builtin-allowlist.json +8 -26
  40. package/src/ask-gloom/pane-context.ts +114 -0
  41. package/src/ask-gloom/pane-request.ts +70 -0
  42. package/src/ask-gloom/pane-text.ts +201 -0
  43. package/src/brokers/signed-in/sign-in-dialog.tsx +11 -5
  44. package/src/capabilities/chart-series.ts +19 -2
  45. package/src/capabilities/factories.ts +1 -0
  46. package/src/cli/central-bank-events.ts +23 -0
  47. package/src/cli/command-options.ts +17 -5
  48. package/src/cli/commands/crypto-hints.ts +35 -2
  49. package/src/cli/commands/fred-series.ts +146 -0
  50. package/src/cli/commands/market.ts +501 -115
  51. package/src/cli/commands/news-hints.ts +62 -0
  52. package/src/cli/commands/news-search.ts +53 -0
  53. package/src/cli/commands/options-leaps.ts +5 -2
  54. package/src/cli/commands/overview.ts +132 -26
  55. package/src/cli/commands/remote.ts +2 -1
  56. package/src/cli/commands/search.ts +317 -13
  57. package/src/cli/commands/system.ts +55 -8
  58. package/src/cli/commands/ticker.ts +155 -18
  59. package/src/cli/context.ts +45 -14
  60. package/src/cli/desktop-pane-shot.ts +76 -7
  61. package/src/cli/earnings-calendar.ts +71 -0
  62. package/src/cli/errors.ts +7 -5
  63. package/src/cli/exit-codes.ts +8 -0
  64. package/src/cli/export-source.ts +58 -0
  65. package/src/cli/freshness.ts +18 -7
  66. package/src/cli/glossary.ts +483 -0
  67. package/src/cli/help.ts +10 -0
  68. package/src/cli/helpers.ts +2 -5
  69. package/src/cli/history-rows.ts +118 -7
  70. package/src/cli/index-roots.ts +7 -0
  71. package/src/cli/index.ts +29 -9
  72. package/src/cli/known-gaps.ts +84 -0
  73. package/src/cli/listing-arg.ts +551 -97
  74. package/src/cli/not-a-ticker.ts +24 -9
  75. package/src/cli/pane-functions/access-gate.ts +13 -2
  76. package/src/cli/pane-functions/capabilities.ts +4 -3
  77. package/src/cli/pane-functions/catalog.ts +214 -40
  78. package/src/cli/pane-functions/data.ts +42 -8
  79. package/src/cli/pane-functions/discovery.ts +1 -0
  80. package/src/cli/pane-functions/dom.ts +37 -8
  81. package/src/cli/pane-functions/freshness.ts +393 -49
  82. package/src/cli/pane-functions/function-help.ts +31 -15
  83. package/src/cli/pane-functions/headless.ts +98 -30
  84. package/src/cli/pane-functions/index.ts +101 -19
  85. package/src/cli/pane-functions/market-session.ts +22 -8
  86. package/src/cli/pane-functions/options.ts +71 -22
  87. package/src/cli/pane-functions/report-notices.ts +25 -7
  88. package/src/cli/pane-functions/report.ts +15 -8
  89. package/src/cli/pane-functions/resolver.ts +74 -19
  90. package/src/cli/pane-functions/screenshot.ts +250 -27
  91. package/src/cli/perpetual-contract.ts +60 -0
  92. package/src/cli/registry.ts +3 -1
  93. package/src/cli/report-tables.ts +26 -7
  94. package/src/cli/result.ts +45 -11
  95. package/src/cli/series-search.ts +111 -0
  96. package/src/cli/staged-tickers.ts +52 -0
  97. package/src/cli/symbol-args.ts +27 -0
  98. package/src/cli/symbol-list.ts +154 -0
  99. package/src/cli/symbol-rows.ts +154 -0
  100. package/src/cli/ticker-resolution.ts +311 -27
  101. package/src/cli/types.ts +5 -0
  102. package/src/components/chart/composite/axis-overlays.tsx +14 -3
  103. package/src/components/chart/composite/composite-chart.tsx +71 -11
  104. package/src/components/chart/composite/crosshair-readout.tsx +150 -0
  105. package/src/components/chart/composite/downsample.ts +1 -1
  106. package/src/components/chart/composite/format.ts +29 -0
  107. package/src/components/chart/composite/interactions.ts +9 -2
  108. package/src/components/chart/composite/legend.tsx +100 -33
  109. package/src/components/chart/composite/panel-bitmap.ts +70 -35
  110. package/src/components/chart/composite/panel-labels.ts +18 -17
  111. package/src/components/chart/composite/panel-series.ts +1 -0
  112. package/src/components/chart/composite/panel-surface.tsx +46 -21
  113. package/src/components/chart/composite/price-axis-labels.tsx +3 -1
  114. package/src/components/chart/composite/rasterizer.ts +50 -8
  115. package/src/components/chart/composite/scene.ts +2 -1
  116. package/src/components/chart/composite/time-scale.ts +26 -9
  117. package/src/components/chart/composite/types.ts +18 -0
  118. package/src/components/chart/composite/use-composite-viewport.ts +30 -2
  119. package/src/components/chart/native/raster/crosshair.ts +8 -3
  120. package/src/components/chart/native/raster/primitives.ts +85 -21
  121. package/src/components/chart/native/surface/manager.ts +33 -8
  122. package/src/components/chart/surface3d/chart.tsx +1 -1
  123. package/src/components/command-bar/action-runtime.ts +1 -1
  124. package/src/components/command-bar/commands/collection-list.ts +210 -0
  125. package/src/components/command-bar/commands/collection.ts +40 -1
  126. package/src/components/command-bar/commands/direct/index.ts +4 -0
  127. package/src/components/command-bar/commands/registry.ts +8 -0
  128. package/src/components/command-bar/panel/index.tsx +11 -3
  129. package/src/components/command-bar/panel/runtime.ts +3 -0
  130. package/src/components/command-bar/panel/types.ts +2 -0
  131. package/src/components/command-bar/routes/root/plugin-install.ts +4 -4
  132. package/src/components/command-bar/routes/root/provider-search.ts +4 -3
  133. package/src/components/command-bar/routes/ticker-search/results.ts +12 -11
  134. package/src/components/command-bar/routes/ticker-search/route.ts +4 -3
  135. package/src/components/command-bar/routing/actions.ts +1 -1
  136. package/src/components/command-bar/workflow/tickers.ts +42 -17
  137. package/src/components/layout/detached-pane-shell.tsx +68 -39
  138. package/src/components/layout/floating-pane.tsx +10 -1
  139. package/src/components/layout/header.tsx +25 -5
  140. package/src/components/layout/missing-pane.tsx +3 -3
  141. package/src/components/layout/pane/capture-stamp.ts +41 -0
  142. package/src/components/layout/pane/capture-status.ts +12 -0
  143. package/src/components/layout/pane/content.tsx +7 -13
  144. package/src/components/layout/pane/footer/index.tsx +6 -2
  145. package/src/components/layout/pane/footer/keyboard.ts +3 -0
  146. package/src/components/layout/pane/footer/model.ts +41 -1
  147. package/src/components/layout/pane/header.tsx +50 -1
  148. package/src/components/layout/pane/index.tsx +21 -3
  149. package/src/components/layout/pane/sidebar.tsx +88 -21
  150. package/src/components/layout/shell/active-drag.ts +21 -5
  151. package/src/components/layout/shell/cursor-occlusion.ts +2 -1
  152. package/src/components/layout/shell/drag/index.ts +39 -9
  153. package/src/components/layout/shell/drag/live.ts +61 -51
  154. package/src/components/layout/shell/drag/runtime.ts +54 -12
  155. package/src/components/layout/shell/index.tsx +84 -65
  156. package/src/components/layout/shell/menu.ts +14 -1
  157. package/src/components/layout/shell/native/pointer-runtime.ts +3 -1
  158. package/src/components/layout/shell/pane/actions.ts +32 -10
  159. package/src/components/layout/shell/pane/ask.ts +131 -0
  160. package/src/components/layout/shell/pane/capture.ts +162 -0
  161. package/src/components/layout/shell/pane/layers.tsx +218 -50
  162. package/src/components/layout/shell/pane/management-shortcuts.ts +46 -1
  163. package/src/components/layout/shell/shortcuts.ts +21 -4
  164. package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -0
  165. package/src/components/markdown-text.tsx +62 -20
  166. package/src/components/metric-treemap/heat-surface.tsx +8 -1
  167. package/src/components/onboarding/account-step/form-panel.tsx +1 -1
  168. package/src/components/onboarding/account-step/index.tsx +1 -1
  169. package/src/components/onboarding/account-step/qr-panel.tsx +1 -1
  170. package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
  171. package/src/components/onboarding/onboarding-keyboard.ts +1 -1
  172. package/src/components/onboarding/onboarding-wizard.tsx +2 -2
  173. package/src/components/onboarding/use-onboarding-upgrade.ts +3 -3
  174. package/src/components/onboarding/wizard-account.ts +2 -2
  175. package/src/components/pane-template-wizard.tsx +9 -1
  176. package/src/components/price-selector-dialog.tsx +11 -2
  177. package/src/components/reader/article-reader.tsx +642 -0
  178. package/src/components/reader/article-text.ts +527 -0
  179. package/src/components/sign-in-gate.tsx +3 -3
  180. package/src/components/ticker/list-table-view.tsx +43 -2
  181. package/src/components/ui/action-row.tsx +2 -1
  182. package/src/components/ui/button.tsx +7 -1
  183. package/src/components/ui/choice-dialog.tsx +6 -4
  184. package/src/components/ui/confirm-dialog.tsx +28 -18
  185. package/src/components/ui/data-table/index.tsx +18 -6
  186. package/src/components/ui/data-table/opentui/index.tsx +37 -6
  187. package/src/components/ui/data-table/types.ts +12 -0
  188. package/src/components/ui/dialog-actions.tsx +64 -0
  189. package/src/components/ui/display.tsx +17 -3
  190. package/src/components/ui/frame.tsx +35 -2
  191. package/src/components/ui/icon.tsx +6 -1
  192. package/src/components/ui/query-bar.tsx +10 -1
  193. package/src/components/ui/text-prompt-dialog.tsx +11 -9
  194. package/src/data/cached-query.ts +2 -0
  195. package/src/data/config/store/migrations.ts +7 -0
  196. package/src/data/config/store/normalize.ts +7 -2
  197. package/src/data/config/store/portfolio-as-of-column.ts +57 -0
  198. package/src/data/ticker-repository.ts +5 -0
  199. package/src/data/ticker-store.ts +15 -0
  200. package/src/docs/content.ts +215 -0
  201. package/src/docs/load.ts +139 -0
  202. package/src/docs/requests.ts +39 -0
  203. package/src/docs/snapshot.chunk.ts +8 -0
  204. package/src/docs/snapshot.json +7555 -0
  205. package/src/docs/topics.ts +216 -0
  206. package/src/i18n/es.ts +65 -5
  207. package/src/i18n/ja.ts +65 -5
  208. package/src/i18n/ko.ts +65 -5
  209. package/src/i18n/zh-cn.ts +65 -5
  210. package/src/i18n/zh-tw.ts +65 -5
  211. package/src/layout/desks.ts +1 -1
  212. package/src/layout/pane-manager/dock-tree.ts +18 -0
  213. package/src/layout/pane-manager/index.ts +1 -0
  214. package/src/layout-marketplace/gallery.tsx +1 -1
  215. package/src/market-data/coordinator/chart.ts +10 -4
  216. package/src/market-data/coordinator/index.ts +6 -3
  217. package/src/{plugins/builtin/futures/contracts.ts → market-data/futures-board.ts} +81 -28
  218. package/src/market-data/futures-contract.ts +151 -0
  219. package/src/market-data/hooks.tsx +10 -2
  220. package/src/market-data/market/format.ts +39 -21
  221. package/src/market-data/market/freshness.ts +84 -20
  222. package/src/market-data/market/session-close-note.ts +3 -2
  223. package/src/market-data/market/status.ts +19 -23
  224. package/src/market-data/published-apac-sessions.ts +23 -1
  225. package/src/market-data/quotes/contributions.ts +5 -0
  226. package/src/market-data/quotes/metadata.ts +19 -24
  227. package/src/market-data/quotes/resolution.ts +5 -0
  228. package/src/market-data/quotes/screener-live-quotes.ts +5 -4
  229. package/src/market-data/result-types.ts +2 -0
  230. package/src/notifications/app-notifier.ts +17 -1
  231. package/src/notifications/notification-log.ts +180 -0
  232. package/src/plugins/auto-update-node.ts +2 -2
  233. package/src/plugins/auto-update.ts +2 -2
  234. package/src/plugins/builtin/account-management/index.tsx +1 -0
  235. package/src/plugins/builtin/account-management/model.ts +1 -56
  236. package/src/plugins/builtin/account-management/pane.tsx +6 -4
  237. package/src/plugins/builtin/account-management/password-dialog.tsx +1 -1
  238. package/src/plugins/builtin/alerts/catalysts.ts +1 -1
  239. package/src/plugins/builtin/alerts/cli.ts +313 -47
  240. package/src/plugins/builtin/alerts/events-pane.tsx +45 -7
  241. package/src/plugins/builtin/alerts/events.ts +23 -2
  242. package/src/plugins/builtin/alerts/focus.ts +27 -0
  243. package/src/plugins/builtin/alerts/history-pane.tsx +7 -2
  244. package/src/plugins/builtin/alerts/history.ts +2 -0
  245. package/src/plugins/builtin/alerts/index.tsx +47 -11
  246. package/src/plugins/builtin/alerts/pane.tsx +27 -1
  247. package/src/plugins/builtin/alerts/research-builder.ts +8 -3
  248. package/src/plugins/builtin/alerts/research-rules.ts +18 -2
  249. package/src/plugins/builtin/alerts/scheduled-check.ts +122 -0
  250. package/src/plugins/builtin/alerts/scheduled-sources.ts +25 -0
  251. package/src/plugins/builtin/alerts/scheduled.ts +254 -0
  252. package/src/plugins/builtin/alerts/targets.ts +92 -0
  253. package/src/plugins/builtin/analytics/index.tsx +8 -3
  254. package/src/plugins/builtin/analytics/risk-headless.ts +60 -27
  255. package/src/plugins/builtin/analytics/risk-math.ts +91 -27
  256. package/src/plugins/builtin/analytics/risk-model.ts +35 -5
  257. package/src/plugins/builtin/analytics/risk-pane.tsx +15 -8
  258. package/src/plugins/builtin/attention/headless.ts +1 -1
  259. package/src/plugins/builtin/attention/index.tsx +2 -0
  260. package/src/plugins/builtin/attention/pane.tsx +3 -1
  261. package/src/plugins/builtin/attention/series.ts +26 -0
  262. package/src/plugins/builtin/awards/headless.ts +88 -18
  263. package/src/plugins/builtin/awards/index.tsx +2 -0
  264. package/src/plugins/builtin/awards/model.ts +41 -1
  265. package/src/plugins/builtin/awards/pane.tsx +22 -13
  266. package/src/plugins/builtin/awards/series.ts +29 -0
  267. package/src/plugins/builtin/backtest/headless.ts +2 -2
  268. package/src/plugins/builtin/bond-calculator/model.ts +2 -1
  269. package/src/plugins/builtin/broker-manager/index.tsx +1 -0
  270. package/src/plugins/builtin/catalysts/headless.ts +1 -1
  271. package/src/plugins/builtin/catalysts/pane.tsx +3 -1
  272. package/src/plugins/builtin/cds/client.ts +49 -12
  273. package/src/plugins/builtin/cds/headless.ts +119 -19
  274. package/src/plugins/builtin/cds/index.tsx +3 -1
  275. package/src/plugins/builtin/cds/model.ts +214 -32
  276. package/src/plugins/builtin/cds/pane.tsx +58 -14
  277. package/src/plugins/builtin/cds/series.ts +19 -0
  278. package/src/plugins/builtin/central-bank-rates/client.ts +4 -0
  279. package/src/plugins/builtin/central-bank-rates/headless.ts +46 -16
  280. package/src/plugins/builtin/central-bank-rates/index.tsx +3 -1
  281. package/src/plugins/builtin/central-bank-rates/model.ts +99 -0
  282. package/src/plugins/builtin/central-bank-rates/pane.tsx +1 -1
  283. package/src/plugins/builtin/central-bank-rates/series.ts +36 -0
  284. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +193 -255
  285. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +84 -46
  286. package/src/plugins/builtin/chart-composer/editor.tsx +5 -4
  287. package/src/plugins/builtin/chart-composer/field-series.ts +40 -0
  288. package/src/plugins/builtin/chart-composer/headless-schema.ts +1 -1
  289. package/src/plugins/builtin/chart-composer/headless.ts +70 -5
  290. package/src/plugins/builtin/chart-composer/index.tsx +15 -3
  291. package/src/plugins/builtin/chart-composer/pane.tsx +81 -38
  292. package/src/plugins/builtin/chart-composer/series-catalog.ts +58 -50
  293. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -10
  294. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +59 -3
  295. package/src/plugins/builtin/chart-composer/user-series.ts +84 -0
  296. package/src/plugins/builtin/chat/content/composer-runtime.ts +6 -1
  297. package/src/plugins/builtin/chat/content/composer.tsx +5 -1
  298. package/src/plugins/builtin/chat/content/footer.tsx +12 -0
  299. package/src/plugins/builtin/chat/content/index.tsx +89 -5
  300. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +10 -2
  301. package/src/plugins/builtin/chat/content/new-messages.tsx +89 -0
  302. package/src/plugins/builtin/chat/content/row-activity.ts +132 -0
  303. package/src/plugins/builtin/chat/content/scroll.ts +127 -27
  304. package/src/plugins/builtin/chat/content/shortcuts.ts +2 -2
  305. package/src/plugins/builtin/chat/content/transcript.tsx +145 -78
  306. package/src/plugins/builtin/chat/content/types.ts +1 -0
  307. package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
  308. package/src/plugins/builtin/chat/controller/index.ts +123 -1
  309. package/src/plugins/builtin/chat/controller/message-loading.ts +3 -0
  310. package/src/plugins/builtin/chat/controller/messages.ts +7 -2
  311. package/src/plugins/builtin/chat/controller/realtime.ts +10 -1
  312. package/src/plugins/builtin/chat/controller/send.ts +61 -1
  313. package/src/plugins/builtin/chat/controller/state.ts +8 -0
  314. package/src/plugins/builtin/chat/ghost-user.ts +20 -0
  315. package/src/plugins/builtin/chat/index.tsx +23 -5
  316. package/src/plugins/builtin/chat/layout.ts +78 -5
  317. package/src/plugins/builtin/chat/message/ai-badge.tsx +18 -0
  318. package/src/plugins/builtin/chat/message/desktop.tsx +55 -6
  319. package/src/plugins/builtin/chat/message/header.tsx +16 -4
  320. package/src/plugins/builtin/chat/message/profile-popover.tsx +5 -1
  321. package/src/plugins/builtin/chat/message/reactions.tsx +210 -0
  322. package/src/plugins/builtin/chat/message/render-state.ts +18 -2
  323. package/src/plugins/builtin/chat/message/terminal.tsx +43 -4
  324. package/src/plugins/builtin/chat/message/types.ts +12 -0
  325. package/src/plugins/builtin/chat/reactions.ts +197 -0
  326. package/src/plugins/builtin/chat/share/flow.tsx +87 -0
  327. package/src/plugins/builtin/chat/share/targets.ts +27 -0
  328. package/src/plugins/builtin/chat/status-widget.tsx +6 -3
  329. package/src/plugins/builtin/chat/unread-inbox-pane.tsx +148 -27
  330. package/src/plugins/builtin/chat/unread-inbox.ts +22 -0
  331. package/src/plugins/builtin/cloud/askg/attached-pane.tsx +69 -0
  332. package/src/plugins/builtin/cloud/askg/controller.ts +111 -19
  333. package/src/plugins/builtin/cloud/askg/executor.ts +57 -3
  334. package/src/plugins/builtin/cloud/askg/manifest.ts +32 -7
  335. package/src/plugins/builtin/cloud/askg/model.ts +27 -8
  336. package/src/plugins/builtin/cloud/askg/pane-attachment.ts +94 -0
  337. package/src/plugins/builtin/cloud/askg/pane.tsx +141 -12
  338. package/src/plugins/builtin/cloud/askg/pending-question.ts +11 -0
  339. package/src/plugins/builtin/cloud/askg/protocol.ts +10 -1
  340. package/src/plugins/builtin/cloud/askg/tool-display.ts +3 -0
  341. package/src/plugins/builtin/cloud/askg/undo.ts +2 -0
  342. package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
  343. package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
  344. package/src/plugins/builtin/cloud/auth-dialog.tsx +3 -3
  345. package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
  346. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +3 -0
  347. package/src/plugins/builtin/cloud/plugin.tsx +19 -2
  348. package/src/plugins/builtin/cloud/team/model.ts +5 -0
  349. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  350. package/src/plugins/builtin/cloud/team/store.ts +8 -3
  351. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +77 -9
  352. package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +6 -1
  353. package/src/plugins/builtin/cloud/terminal-relay/policy.ts +9 -0
  354. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +35 -11
  355. package/src/plugins/builtin/cloud/thesis/exposure.ts +1 -1
  356. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  357. package/src/plugins/builtin/cloud/thesis/prompts.tsx +2 -1
  358. package/src/plugins/builtin/company-attention/app-rank.tsx +1 -1
  359. package/src/plugins/builtin/company-attention/headless.ts +21 -7
  360. package/src/plugins/builtin/company-attention/index.tsx +2 -0
  361. package/src/plugins/builtin/company-attention/model.ts +26 -7
  362. package/src/plugins/builtin/company-attention/pane.tsx +12 -9
  363. package/src/plugins/builtin/company-attention/series.ts +52 -0
  364. package/src/plugins/builtin/company-kpis/headless.ts +97 -10
  365. package/src/plugins/builtin/company-kpis/model.ts +24 -2
  366. package/src/plugins/builtin/company-kpis/pane.tsx +17 -16
  367. package/src/plugins/builtin/composite-plugins.ts +19 -13
  368. package/src/plugins/builtin/connections/index.ts +1 -0
  369. package/src/plugins/builtin/cot/headless.ts +1 -1
  370. package/src/plugins/builtin/cot/index.tsx +3 -1
  371. package/src/plugins/builtin/cot/model.ts +40 -11
  372. package/src/plugins/builtin/cot/series.ts +27 -0
  373. package/src/plugins/builtin/cpi/headless.ts +3 -3
  374. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +10 -1
  375. package/src/plugins/builtin/credit-boards/client.ts +6 -2
  376. package/src/plugins/builtin/credit-boards/headless.ts +108 -31
  377. package/src/plugins/builtin/credit-boards/index.tsx +2 -0
  378. package/src/plugins/builtin/credit-boards/model.ts +11 -1
  379. package/src/plugins/builtin/credit-boards/series.ts +66 -0
  380. package/src/plugins/builtin/credit-conditions/client.ts +12 -9
  381. package/src/plugins/builtin/credit-conditions/headless.ts +13 -2
  382. package/src/plugins/builtin/credit-conditions/index.tsx +18 -9
  383. package/src/plugins/builtin/credit-conditions/model.ts +19 -11
  384. package/src/plugins/builtin/credit-conditions/series.ts +16 -0
  385. package/src/plugins/builtin/credit-documents/headless.ts +33 -3
  386. package/src/plugins/builtin/credit-documents/pane.tsx +3 -1
  387. package/src/plugins/builtin/crypto-board/headless.ts +2 -3
  388. package/src/plugins/builtin/crypto-board/index.tsx +2 -0
  389. package/src/plugins/builtin/crypto-board/model.ts +12 -0
  390. package/src/plugins/builtin/crypto-board/pane.tsx +19 -12
  391. package/src/plugins/builtin/crypto-board/series.ts +48 -0
  392. package/src/plugins/builtin/custom-view/live-quotes.ts +2 -2
  393. package/src/plugins/builtin/debt-maturities/headless.ts +17 -11
  394. package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
  395. package/src/plugins/builtin/debt-maturities/series.ts +45 -0
  396. package/src/plugins/builtin/dividend-yield/client.ts +3 -0
  397. package/src/plugins/builtin/dividend-yield/headless.ts +7 -4
  398. package/src/plugins/builtin/dividend-yield/index.tsx +3 -1
  399. package/src/plugins/builtin/dividend-yield/pane.tsx +3 -1
  400. package/src/plugins/builtin/dividend-yield/series.ts +20 -0
  401. package/src/plugins/builtin/dividend-yield/types.ts +2 -0
  402. package/src/plugins/builtin/docs/blocks.tsx +181 -0
  403. package/src/plugins/builtin/docs/index.tsx +68 -0
  404. package/src/plugins/builtin/docs/pane.tsx +426 -0
  405. package/src/plugins/builtin/docs/targets.ts +72 -0
  406. package/src/plugins/builtin/docs/use-docs.ts +60 -0
  407. package/src/plugins/builtin/doe/headless.ts +12 -8
  408. package/src/plugins/builtin/doe/index.tsx +2 -0
  409. package/src/plugins/builtin/doe/series.ts +62 -0
  410. package/src/plugins/builtin/earnings/client.ts +3 -2
  411. package/src/plugins/builtin/earnings/format.ts +1 -5
  412. package/src/plugins/builtin/earnings/headless.ts +58 -6
  413. package/src/plugins/builtin/earnings/history-model.ts +15 -1
  414. package/src/plugins/builtin/earnings/history-table.ts +13 -2
  415. package/src/plugins/builtin/earnings/history.tsx +7 -3
  416. package/src/plugins/builtin/earnings/index.tsx +9 -0
  417. package/src/plugins/builtin/earnings-calls/headless.ts +28 -2
  418. package/src/plugins/builtin/earnings-calls/index.tsx +1 -1
  419. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -0
  420. package/src/plugins/builtin/econ/fred-catalog.ts +198 -0
  421. package/src/plugins/builtin/econ/fred-series-map.ts +0 -46
  422. package/src/plugins/builtin/econ/index.tsx +2 -0
  423. package/src/plugins/builtin/econ-statistics/defs.ts +5 -0
  424. package/src/plugins/builtin/econ-statistics/headless.ts +19 -4
  425. package/src/plugins/builtin/econ-statistics/stats.ts +1 -0
  426. package/src/plugins/builtin/equity-screener/headless.ts +3 -3
  427. package/src/plugins/builtin/equity-screener/pane.tsx +4 -11
  428. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -3
  429. package/src/plugins/builtin/exposure/drivers.ts +13 -0
  430. package/src/plugins/builtin/exposure/headless.ts +205 -13
  431. package/src/plugins/builtin/exposure/holdings.ts +1 -1
  432. package/src/plugins/builtin/exposure/index.tsx +1 -0
  433. package/src/plugins/builtin/exposure/model.ts +23 -3
  434. package/src/plugins/builtin/exposure/pane.tsx +14 -12
  435. package/src/plugins/builtin/fear-greed/index.tsx +18 -10
  436. package/src/plugins/builtin/fear-greed/series.ts +52 -0
  437. package/src/plugins/builtin/futures/index.tsx +43 -3
  438. package/src/plugins/builtin/futures/model.ts +1 -1
  439. package/src/plugins/builtin/futures/returns.ts +1 -1
  440. package/src/plugins/builtin/futures/series.ts +13 -0
  441. package/src/plugins/builtin/futures/table.tsx +1 -1
  442. package/src/plugins/builtin/futures/use-front-returns.ts +1 -1
  443. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  444. package/src/plugins/builtin/futures-curve/headless.ts +71 -10
  445. package/src/plugins/builtin/futures-curve/index.tsx +1 -1
  446. package/src/plugins/builtin/futures-curve/model.ts +66 -11
  447. package/src/plugins/builtin/futures-curve/pane.tsx +52 -18
  448. package/src/plugins/builtin/fx-matrix/client.ts +63 -0
  449. package/src/plugins/builtin/fx-matrix/export.ts +2 -1
  450. package/src/plugins/builtin/fx-matrix/headless.ts +154 -0
  451. package/src/plugins/builtin/fx-matrix/index.tsx +4 -4
  452. package/src/plugins/builtin/gpu/board.tsx +13 -10
  453. package/src/plugins/builtin/gpu/changes.tsx +4 -4
  454. package/src/plugins/builtin/gpu/client.ts +19 -1
  455. package/src/plugins/builtin/gpu/equities.tsx +14 -10
  456. package/src/plugins/builtin/gpu/headless.ts +58 -27
  457. package/src/plugins/builtin/gpu/history.tsx +3 -3
  458. package/src/plugins/builtin/gpu/index.tsx +2 -0
  459. package/src/plugins/builtin/gpu/model.ts +101 -16
  460. package/src/plugins/builtin/gpu/pane.tsx +28 -12
  461. package/src/plugins/builtin/gpu/series.ts +38 -0
  462. package/src/plugins/builtin/help/function-card.tsx +25 -6
  463. package/src/plugins/builtin/help/function-index.ts +2 -0
  464. package/src/plugins/builtin/help/index.tsx +31 -9
  465. package/src/plugins/builtin/holders/beneficial-model.ts +90 -3
  466. package/src/plugins/builtin/holders/beneficial-report.ts +57 -5
  467. package/src/plugins/builtin/holders/beneficial-view.tsx +55 -11
  468. package/src/plugins/builtin/holders/client.ts +22 -3
  469. package/src/plugins/builtin/holders/format.ts +18 -3
  470. package/src/plugins/builtin/holders/headless.ts +36 -133
  471. package/src/plugins/builtin/holders/pane.tsx +11 -4
  472. package/src/plugins/builtin/holders/report-header.ts +40 -5
  473. package/src/plugins/builtin/holders/report-rows.ts +240 -0
  474. package/src/plugins/builtin/insider/client.ts +35 -20
  475. package/src/plugins/builtin/insider/headless.ts +41 -11
  476. package/src/plugins/builtin/insider/index.tsx +26 -9
  477. package/src/plugins/builtin/insider/insider-data.ts +10 -0
  478. package/src/plugins/builtin/insider/issuer.ts +49 -0
  479. package/src/plugins/builtin/insider/model.ts +3 -0
  480. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -1
  481. package/src/plugins/builtin/iv-history/client.ts +20 -6
  482. package/src/plugins/builtin/iv-history/format.ts +9 -0
  483. package/src/plugins/builtin/iv-history/headless.ts +56 -21
  484. package/src/plugins/builtin/iv-history/index.tsx +2 -0
  485. package/src/plugins/builtin/iv-history/model.ts +143 -8
  486. package/src/plugins/builtin/iv-history/screen-pane.tsx +5 -9
  487. package/src/plugins/builtin/iv-history/series.ts +29 -0
  488. package/src/plugins/builtin/jobs/headless.ts +26 -3
  489. package/src/plugins/builtin/jobs/index.tsx +3 -1
  490. package/src/plugins/builtin/jobs/series.ts +19 -0
  491. package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
  492. package/src/plugins/builtin/kelly-sizer/pane.tsx +2 -1
  493. package/src/plugins/builtin/kelly-sizer/portfolio.ts +0 -39
  494. package/src/plugins/builtin/macro-day/client.ts +44 -3
  495. package/src/plugins/builtin/macro-day/headless.ts +13 -10
  496. package/src/plugins/builtin/macro-day/model.ts +56 -10
  497. package/src/plugins/builtin/macro-day/pane.tsx +30 -20
  498. package/src/plugins/builtin/market-heatmap/headless.ts +20 -5
  499. package/src/plugins/builtin/market-heatmap/index.tsx +6 -0
  500. package/src/plugins/builtin/market-heatmap/model.ts +19 -11
  501. package/src/plugins/builtin/market-heatmap/portfolio.ts +2 -2
  502. package/src/plugins/builtin/market-movers/client.ts +7 -5
  503. package/src/plugins/builtin/market-movers/index.tsx +3 -2
  504. package/src/plugins/builtin/market-movers/model.ts +30 -0
  505. package/src/plugins/builtin/market-movers/screener.ts +31 -0
  506. package/src/plugins/builtin/market-valuation/chart-series.ts +29 -69
  507. package/src/plugins/builtin/market-valuation/index.tsx +3 -3
  508. package/src/plugins/builtin/market-valuation/indicators.ts +0 -5
  509. package/src/plugins/builtin/members/headless.ts +8 -3
  510. package/src/plugins/builtin/members/model.ts +31 -3
  511. package/src/plugins/builtin/members/pane.tsx +6 -8
  512. package/src/plugins/builtin/mna/distress/headless.ts +4 -4
  513. package/src/plugins/builtin/mna/headless.ts +18 -6
  514. package/src/plugins/builtin/money-markets/headless.ts +5 -4
  515. package/src/plugins/builtin/money-markets/index.tsx +2 -0
  516. package/src/plugins/builtin/money-markets/series.ts +41 -0
  517. package/src/plugins/builtin/news/index.tsx +0 -2
  518. package/src/plugins/builtin/news/wire/news/detail-view.tsx +53 -104
  519. package/src/plugins/builtin/news/wire/news/footer.ts +2 -25
  520. package/src/plugins/builtin/news/wire/news/preset-pane.tsx +0 -2
  521. package/src/plugins/builtin/notes/cli.ts +12 -7
  522. package/src/plugins/builtin/notes/index.tsx +1 -0
  523. package/src/plugins/builtin/options/index.tsx +3 -0
  524. package/src/plugins/builtin/options/view.tsx +1 -1
  525. package/src/plugins/builtin/options-calculator/inputs.ts +2 -1
  526. package/src/plugins/builtin/options-positioning/client.ts +7 -3
  527. package/src/plugins/builtin/options-positioning/headless.ts +4 -3
  528. package/src/plugins/builtin/options-positioning/pane.tsx +2 -2
  529. package/src/plugins/builtin/options-scenario/client.ts +2 -1
  530. package/src/plugins/builtin/options-scenario/headless.ts +1 -0
  531. package/src/plugins/builtin/options-scenario/hedge.ts +2 -1
  532. package/src/plugins/builtin/perps/client.ts +90 -16
  533. package/src/plugins/builtin/perps/equity-row.tsx +52 -17
  534. package/src/plugins/builtin/perps/freshness.ts +66 -0
  535. package/src/plugins/builtin/perps/headless.ts +47 -32
  536. package/src/plugins/builtin/perps/index.tsx +23 -4
  537. package/src/plugins/builtin/perps/list-perpetuals.ts +118 -0
  538. package/src/plugins/builtin/perps/model.ts +20 -5
  539. package/src/plugins/builtin/perps/open-market.ts +15 -0
  540. package/src/plugins/builtin/perps/pane.tsx +76 -20
  541. package/src/plugins/builtin/perps/series.ts +76 -0
  542. package/src/plugins/builtin/plugin-marketplace/index.tsx +1 -1
  543. package/src/plugins/builtin/plugin-marketplace/pane.tsx +73 -67
  544. package/src/plugins/builtin/plugin-module.ts +3 -0
  545. package/src/plugins/builtin/portfolio-list/account-metrics.ts +1 -1
  546. package/src/plugins/builtin/portfolio-list/allocation.ts +5 -4
  547. package/src/plugins/builtin/portfolio-list/cell-version.ts +8 -1
  548. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +161 -0
  549. package/src/plugins/builtin/portfolio-list/cli/import-13f.ts +109 -0
  550. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +384 -74
  551. package/src/plugins/builtin/portfolio-list/cli/render.ts +437 -71
  552. package/src/plugins/builtin/portfolio-list/cli/shared.ts +21 -4
  553. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +121 -47
  554. package/src/plugins/builtin/portfolio-list/column-values.ts +104 -26
  555. package/src/plugins/builtin/portfolio-list/grid.tsx +1 -1
  556. package/src/plugins/builtin/portfolio-list/headless.ts +84 -18
  557. package/src/plugins/builtin/portfolio-list/imported-from.ts +8 -0
  558. package/src/plugins/builtin/portfolio-list/index.tsx +5 -1
  559. package/src/plugins/builtin/portfolio-list/live-valuation.ts +6 -2
  560. package/src/plugins/builtin/portfolio-list/mutations.ts +2 -9
  561. package/src/plugins/builtin/portfolio-list/pane/data.ts +5 -1
  562. package/src/plugins/builtin/portfolio-list/pane/index.tsx +52 -9
  563. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +33 -11
  564. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +21 -1
  565. package/src/plugins/builtin/portfolio-list/settings.ts +17 -0
  566. package/src/plugins/builtin/portfolio-list/summary/index.tsx +12 -0
  567. package/src/plugins/builtin/portfolio-list/summary/totals.ts +9 -4
  568. package/src/plugins/builtin/portfolio-list/table.tsx +37 -7
  569. package/src/plugins/builtin/power/client.ts +16 -0
  570. package/src/plugins/builtin/power/evidence.ts +63 -10
  571. package/src/plugins/builtin/power/headless.ts +77 -9
  572. package/src/plugins/builtin/power/index.tsx +28 -3
  573. package/src/plugins/builtin/power/model.ts +73 -2
  574. package/src/plugins/builtin/power/pane.tsx +37 -9
  575. package/src/plugins/builtin/power/prices-client.ts +139 -0
  576. package/src/plugins/builtin/power/prices-headless.ts +137 -0
  577. package/src/plugins/builtin/power/prices-model.ts +103 -0
  578. package/src/plugins/builtin/power/prices.tsx +179 -0
  579. package/src/plugins/builtin/rate-path/headless.ts +46 -18
  580. package/src/plugins/builtin/realized-vol/headless.ts +5 -0
  581. package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
  582. package/src/plugins/builtin/research/corporate-actions-pane.tsx +5 -2
  583. package/src/plugins/builtin/research/event-model.ts +68 -24
  584. package/src/plugins/builtin/research/events-headless.ts +2 -1
  585. package/src/plugins/builtin/research/headless.ts +2 -1
  586. package/src/plugins/builtin/research/index.tsx +2 -0
  587. package/src/plugins/builtin/research-search/article.ts +65 -0
  588. package/src/plugins/builtin/research-search/document-view.tsx +33 -215
  589. package/src/plugins/builtin/research-search/model.ts +0 -9
  590. package/src/plugins/builtin/research-search/pane.tsx +41 -30
  591. package/src/plugins/builtin/research-search/snippet.ts +0 -29
  592. package/src/plugins/builtin/revenue-breakdown/headless.ts +18 -6
  593. package/src/plugins/builtin/seasonality/client.ts +15 -7
  594. package/src/plugins/builtin/seasonality/headless.ts +36 -12
  595. package/src/plugins/builtin/seasonality/index.tsx +2 -2
  596. package/src/plugins/builtin/seasonality/model.ts +119 -0
  597. package/src/plugins/builtin/seasonality/pane.tsx +108 -37
  598. package/src/plugins/builtin/sec/headless.ts +25 -3
  599. package/src/plugins/builtin/sec/index.tsx +2 -1
  600. package/src/plugins/builtin/series-inventory.ts +93 -0
  601. package/src/plugins/builtin/shared/cloud-denied.ts +15 -0
  602. package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -1
  603. package/src/plugins/builtin/shared/command-tab.ts +30 -12
  604. package/src/plugins/builtin/shared/earnings-report.ts +55 -0
  605. package/src/plugins/builtin/shared/fred-points.ts +20 -0
  606. package/src/plugins/builtin/shared/free-preview.ts +47 -0
  607. package/src/plugins/builtin/shared/fx-rate-freshness.ts +101 -0
  608. package/src/plugins/builtin/shared/open-description.ts +29 -0
  609. package/src/plugins/builtin/shared/report-freshness.ts +12 -1
  610. package/src/plugins/builtin/shared/series-warning.ts +5 -0
  611. package/src/plugins/builtin/shared/volatility/options.ts +4 -1
  612. package/src/plugins/builtin/short-interest/headless.ts +1 -0
  613. package/src/plugins/builtin/short-interest/index.tsx +2 -0
  614. package/src/plugins/builtin/short-interest/series.ts +36 -0
  615. package/src/plugins/builtin/short-interest/watch-headless.ts +3 -2
  616. package/src/plugins/builtin/short-interest/watch-model.ts +9 -5
  617. package/src/plugins/builtin/short-volume/headless.ts +2 -1
  618. package/src/plugins/builtin/short-volume/index.tsx +2 -0
  619. package/src/plugins/builtin/short-volume/series.ts +23 -0
  620. package/src/plugins/builtin/social-mentions/headless.ts +1 -1
  621. package/src/plugins/builtin/social-mentions/index.tsx +2 -0
  622. package/src/plugins/builtin/social-mentions/series.ts +23 -0
  623. package/src/plugins/builtin/supply-chain/graph-pane.tsx +3 -2
  624. package/src/plugins/builtin/supply-chain/headless.ts +43 -11
  625. package/src/plugins/builtin/supply-chain/model.ts +13 -0
  626. package/src/plugins/builtin/supply-chain/pane.tsx +8 -6
  627. package/src/plugins/builtin/themes/headless.ts +74 -10
  628. package/src/plugins/builtin/themes/model.ts +71 -4
  629. package/src/plugins/builtin/themes/pane.tsx +22 -5
  630. package/src/plugins/builtin/thirteenf/api.ts +1 -0
  631. package/src/plugins/builtin/thirteenf/data.ts +6 -4
  632. package/src/plugins/builtin/thirteenf/headless.ts +217 -36
  633. package/src/plugins/builtin/thirteenf/model.ts +39 -1
  634. package/src/plugins/builtin/thirteenf/overlap.ts +75 -0
  635. package/src/plugins/builtin/thirteenf/pane.tsx +10 -1
  636. package/src/plugins/builtin/thirteenf/report-notes.ts +103 -1
  637. package/src/plugins/builtin/thirteenf/types.ts +2 -0
  638. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +114 -0
  639. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +57 -2
  640. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +19 -55
  641. package/src/plugins/builtin/ticker-detail/headless-schema.ts +30 -0
  642. package/src/plugins/builtin/ticker-detail/headless.ts +86 -0
  643. package/src/plugins/builtin/ticker-detail/index.tsx +26 -11
  644. package/src/plugins/builtin/ticker-detail/overview/components.tsx +1 -1
  645. package/src/plugins/builtin/ticker-detail/overview/futures-contract.ts +31 -0
  646. package/src/plugins/builtin/ticker-detail/overview/model.ts +3 -3
  647. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -1
  648. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +49 -5
  649. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +13 -3
  650. package/src/plugins/builtin/time-sales/headless.ts +2 -1
  651. package/src/plugins/builtin/time-sales/index.tsx +2 -1
  652. package/src/plugins/builtin/treasury-auctions/headless.ts +16 -2
  653. package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
  654. package/src/plugins/builtin/treasury-auctions/model.ts +8 -0
  655. package/src/plugins/builtin/vol-surface/evidence.ts +7 -1
  656. package/src/plugins/builtin/vol-surface/headless.ts +51 -17
  657. package/src/plugins/builtin/vol-surface/heat-grid.tsx +113 -0
  658. package/src/plugins/builtin/vol-surface/model.ts +39 -6
  659. package/src/plugins/builtin/vol-surface/pane.tsx +14 -13
  660. package/src/plugins/builtin/vol-surface/stored.ts +63 -3
  661. package/src/plugins/builtin/vol-surface/surface.tsx +30 -2
  662. package/src/plugins/builtin/volatility/index.tsx +2 -0
  663. package/src/plugins/builtin/volatility/series.ts +84 -0
  664. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +6 -5
  665. package/src/plugins/builtin/world-venue-map/basemap.ts +6 -3
  666. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +2 -1
  667. package/src/plugins/builtin/world-venue-map/geo-series.ts +26 -1
  668. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +6 -6
  669. package/src/plugins/builtin/world-venue-map/headless.ts +4 -1
  670. package/src/plugins/builtin/world-venue-map/index.ts +2 -1
  671. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +24 -13
  672. package/src/plugins/builtin/world-venue-map/layers.ts +29 -0
  673. package/src/plugins/builtin/world-venue-map/map.tsx +144 -13
  674. package/src/plugins/builtin/world-venue-map/model.ts +56 -19
  675. package/src/plugins/builtin/world-venue-map/pane.tsx +5 -2
  676. package/src/plugins/builtin/yield-curve/chart.ts +2 -2
  677. package/src/plugins/builtin/yield-curve/curves.ts +21 -8
  678. package/src/plugins/builtin/yield-curve/headless.ts +71 -18
  679. package/src/plugins/builtin/yield-curve/index.tsx +4 -2
  680. package/src/plugins/builtin/yield-curve/series.ts +86 -0
  681. package/src/plugins/catalog-browser.ts +2 -1
  682. package/src/plugins/installer.ts +2 -2
  683. package/src/plugins/loader.ts +15 -0
  684. package/src/plugins/manager-node.ts +1 -1
  685. package/src/plugins/{builtin/plugin-marketplace → marketplace}/feed.ts +2 -2
  686. package/src/plugins/{builtin/plugin-marketplace → marketplace}/model.ts +6 -6
  687. package/src/plugins/{builtin/plugin-marketplace → marketplace}/store.ts +1 -1
  688. package/src/plugins/registry/host-actions.ts +11 -0
  689. package/src/plugins/registry/index.ts +89 -4
  690. package/src/portfolio/collection-name.ts +31 -0
  691. package/src/{plugins/builtin/portfolio-list → portfolio}/position-metrics.ts +6 -6
  692. package/src/portfolio/position-value.ts +40 -0
  693. package/src/portfolio/valuation-basis.ts +79 -0
  694. package/src/public/__snapshots__/public-api.test.ts.snap +7 -0
  695. package/src/public/time-series.ts +17 -0
  696. package/src/react/auto-refresh.ts +13 -3
  697. package/src/react/input.ts +33 -1
  698. package/src/react/key-repeat.ts +86 -0
  699. package/src/remote/app-host.tsx +20 -4
  700. package/src/remote/confirm-change.tsx +85 -0
  701. package/src/remote/controller-utils.ts +8 -1
  702. package/src/remote/controller.ts +144 -7
  703. package/src/remote/pane-screenshot.ts +47 -0
  704. package/src/remote/schema.ts +65 -2
  705. package/src/remote/types.ts +30 -0
  706. package/src/remote/watchlist.ts +306 -0
  707. package/src/renderers/browser/main.tsx +4 -3
  708. package/src/renderers/browser/research-entry.ts +4 -2
  709. package/src/renderers/cloudflare/worker.ts +1 -1
  710. package/src/renderers/dom/data-table/frozen-column.ts +3 -1
  711. package/src/renderers/dom/data-table/index.tsx +33 -6
  712. package/src/renderers/dom/data-table/row.tsx +30 -1
  713. package/src/renderers/dom/desktop/control-styles.ts +63 -1
  714. package/src/renderers/dom/desktop/controls.tsx +30 -23
  715. package/src/renderers/dom/desktop/dialog-actions.tsx +170 -0
  716. package/src/renderers/dom/desktop/icons.tsx +16 -0
  717. package/src/renderers/dom/dom-ui-host.tsx +3 -0
  718. package/src/renderers/dom/host/block-glyph-canvas.tsx +6 -3
  719. package/src/renderers/dom/host/box.tsx +8 -0
  720. package/src/renderers/dom/host/chart-surface.tsx +33 -2
  721. package/src/renderers/dom/host/live-frame.ts +6 -2
  722. package/src/renderers/dom/host/overflow-fade.ts +14 -1
  723. package/src/renderers/dom/host/scroll-box.tsx +32 -0
  724. package/src/renderers/dom/host/size-observer.ts +41 -0
  725. package/src/renderers/dom/host/sticky-scroll.ts +128 -0
  726. package/src/renderers/dom/host/style.ts +1 -1
  727. package/src/renderers/dom/host/surface-3d.tsx +19 -7
  728. package/src/renderers/dom/host/surface-fit.ts +406 -0
  729. package/src/renderers/dom/host/text.tsx +1 -1
  730. package/src/renderers/dom/input-host.tsx +1 -0
  731. package/src/renderers/dom/styles.css +102 -5
  732. package/src/renderers/electrobun/bun/application-menu/click.ts +18 -0
  733. package/src/renderers/electrobun/bun/index.ts +3 -2
  734. package/src/renderers/electrobun/shared/protocol.ts +1 -1
  735. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +29 -2
  736. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +63 -20
  737. package/src/renderers/electrobun/view/cli-pane-shot-health.ts +10 -26
  738. package/src/renderers/electrobun/view/main.tsx +5 -3
  739. package/src/renderers/electrobun/view/remote/asset-data-client.ts +2 -0
  740. package/src/renderers/opentui/chart-surface.tsx +1 -0
  741. package/src/renderers/opentui/frame-capture.ts +33 -0
  742. package/src/renderers/opentui/host.tsx +10 -13
  743. package/src/renderers/opentui/pane-image/glyphs-license.txt +107 -0
  744. package/src/renderers/opentui/pane-image/glyphs.json +1 -0
  745. package/src/renderers/opentui/pane-image/index.ts +107 -0
  746. package/src/renderers/opentui/pane-image/raster.ts +428 -0
  747. package/src/renderers/opentui/start.tsx +3 -3
  748. package/src/renderers/opentui/test-utils.tsx +3 -0
  749. package/src/renderers/opentui/ui-host.tsx +29 -1
  750. package/src/series/capability.ts +75 -0
  751. package/src/series/csv.ts +160 -0
  752. package/src/series/files.ts +107 -0
  753. package/src/series/registry.ts +198 -0
  754. package/src/series/resolve.ts +108 -0
  755. package/src/series/standalone.ts +48 -0
  756. package/src/series/types.ts +153 -0
  757. package/src/series/validate.ts +171 -0
  758. package/src/shares/chat.ts +34 -0
  759. package/src/shares/dialog.tsx +295 -0
  760. package/src/shares/flow.tsx +56 -0
  761. package/src/shares/live.ts +14 -22
  762. package/src/shares/pane-image.ts +152 -0
  763. package/src/shares/personal-pane.ts +64 -0
  764. package/src/shares/portable-layout.ts +4 -2
  765. package/src/shares/prepare.ts +20 -0
  766. package/src/sources/gloomberb-cloud/index.ts +109 -10
  767. package/src/sources/gloomberb-cloud/normalizers.ts +3 -0
  768. package/src/sources/gloomberb-cloud/perpetuals.ts +249 -0
  769. package/src/sources/history-result.ts +1 -0
  770. package/src/sources/history-retention.ts +11 -0
  771. package/src/sources/listing-symbols.ts +4 -1
  772. package/src/sources/listing-target.ts +4 -0
  773. package/src/sources/provider-router/batches.ts +4 -1
  774. package/src/sources/provider-router/cache.ts +4 -2
  775. package/src/sources/provider-router/cached-routes.ts +1 -1
  776. package/src/sources/provider-router/financial-routes.ts +1 -0
  777. package/src/sources/provider-router/financials.ts +13 -0
  778. package/src/sources/provider-router/history.ts +43 -25
  779. package/src/sources/provider-router/index.ts +14 -0
  780. package/src/sources/provider-router/search.ts +1 -0
  781. package/src/state/hooks/inline-tickers.ts +49 -11
  782. package/src/sync/core-contributors.ts +1 -0
  783. package/src/test-support/shell-pane-keys.tsx +1 -0
  784. package/src/theme/theme-context.tsx +15 -1
  785. package/src/tickers/company-name.ts +75 -0
  786. package/src/tickers/instrument-kind.ts +34 -1
  787. package/src/tickers/listing-name.ts +34 -0
  788. package/src/tickers/listing-venues.ts +132 -0
  789. package/src/tickers/open-target.ts +13 -4
  790. package/src/tickers/perpetual-listing.ts +151 -0
  791. package/src/tickers/prediction-listing.ts +26 -0
  792. package/src/tickers/search/index.ts +72 -11
  793. package/src/tickers/search/ranking.ts +98 -20
  794. package/src/tickers/search/types.ts +7 -1
  795. package/src/tickers/ticker-changes.ts +213 -0
  796. package/src/tickers/us-listing.ts +34 -0
  797. package/src/time-series/economic.ts +2 -6
  798. package/src/time-series/hooks.ts +9 -0
  799. package/src/time-series/ice-credit.ts +39 -0
  800. package/src/time-series/resolve.ts +211 -29
  801. package/src/time-series/studies.ts +1 -0
  802. package/src/time-series/types.ts +12 -2
  803. package/src/time-series/use-chart-resolution.ts +32 -0
  804. package/src/types/config.ts +10 -2
  805. package/src/types/data-provider.ts +11 -0
  806. package/src/types/financials.ts +62 -1
  807. package/src/types/headless.ts +113 -0
  808. package/src/types/instrument.ts +4 -0
  809. package/src/types/plugin.ts +52 -2
  810. package/src/types/price-history.ts +7 -0
  811. package/src/types/ticker-changes.ts +26 -0
  812. package/src/types/ticker.ts +14 -0
  813. package/src/ui/context-menu.tsx +13 -1
  814. package/src/ui/host.tsx +57 -3
  815. package/src/ui/live-resize.ts +91 -0
  816. package/src/ui/live-stretch.ts +153 -0
  817. package/src/ui/measured-cells.ts +58 -0
  818. package/src/ui/sticky-scroll.ts +7 -0
  819. package/src/utils/basis-points.ts +17 -0
  820. package/src/utils/central-banks.ts +76 -0
  821. package/src/utils/cli-output.ts +131 -15
  822. package/src/utils/concurrency.ts +25 -0
  823. package/src/utils/crypto-pair.ts +20 -0
  824. package/src/utils/currency-pair.ts +19 -0
  825. package/src/utils/currency-units.ts +11 -0
  826. package/src/utils/datetime-format.ts +27 -6
  827. package/src/utils/decimal-comma.ts +19 -0
  828. package/src/utils/dom-screenshot-css.ts +265 -0
  829. package/src/utils/dom-screenshot-rasters.ts +276 -0
  830. package/src/utils/dom-screenshot.ts +439 -52
  831. package/src/utils/double-escape-close.ts +15 -1
  832. package/src/utils/exchange-rate-snapshot.ts +6 -2
  833. package/src/utils/exchanges.ts +143 -1
  834. package/src/utils/format.ts +35 -5
  835. package/src/utils/forward-dividend.ts +14 -0
  836. package/src/utils/fundamentals.ts +66 -0
  837. package/src/utils/futures-generic.ts +6 -12
  838. package/src/utils/fx-market-hours.ts +15 -5
  839. package/src/utils/fx-status.ts +6 -1
  840. package/src/utils/inline-content-tokenizer.ts +22 -3
  841. package/src/utils/market-capitalization.ts +8 -0
  842. package/src/utils/one-shot.ts +73 -0
  843. package/src/utils/options.ts +37 -8
  844. package/src/utils/price-history.ts +99 -42
  845. package/src/utils/sec-eps-basis.ts +24 -11
  846. package/src/utils/sec.ts +61 -7
  847. package/src/utils/utc-time.ts +63 -4
  848. package/src/plugins/builtin/fx-matrix/freshness.ts +0 -65
  849. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/activation.ts +0 -0
  850. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/ids.ts +0 -0
  851. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/packs.ts +0 -0
  852. /package/src/{plugins/builtin/cloud → tickers}/starter-symbols.ts +0 -0
@@ -0,0 +1,52 @@
1
+ import type { AppAttentionPayload } from "../../../api-client/app-attention";
2
+ import type { HiringPayload } from "../../../api-client/hiring";
3
+ import type { SeriesDefinition } from "../../../series/types";
4
+ import { fetchAttention } from "./client";
5
+
6
+ const DAY_MS = 86_400_000;
7
+
8
+ /** The app history window a chart asks for, in the days the server takes (7 to 730). */
9
+ function appHistoryDays(start: Date | undefined): number {
10
+ if (!start) return 730;
11
+ return Math.min(730, Math.max(7, Math.ceil((Date.now() - start.getTime()) / DAY_MS)));
12
+ }
13
+
14
+ /**
15
+ * The company signals HIRE and APPS chart: observed open roles each week and
16
+ * the app attention score each day. Pro readings: the free preview carries no
17
+ * history, so they fail with the pane's own words.
18
+ */
19
+ export const COMPANY_ATTENTION_SERIES: readonly SeriesDefinition[] = [
20
+ {
21
+ id: "hiring:open-roles",
22
+ name: "Observed open roles",
23
+ unit: "jobs",
24
+ frequency: "weekly",
25
+ group: "Alternative data",
26
+ tags: ["hiring", "hiring momentum", "roles", "requisitions", "careers"],
27
+ description: "Requisitions observed on public career boards each week, subsidiaries rolled up through evidenced ownership, as HIRE charts them. Needs Pro.",
28
+ input: "ticker",
29
+ load: async ({ ticker, signal }) => {
30
+ const data = await fetchAttention("hiring", ticker!, {}, undefined, signal) as HiringPayload;
31
+ if (data.preview) throw new Error("Full hiring history requires Pro.");
32
+ if (!data.series.length) throw new Error("History is accumulating from the first capture.");
33
+ return data.series.map((point) => ({ date: point.week, value: point.openCount }));
34
+ },
35
+ },
36
+ {
37
+ id: "app-attention:score",
38
+ name: "App attention score",
39
+ unit: "score",
40
+ frequency: "daily",
41
+ group: "Alternative data",
42
+ tags: ["apps", "app attention", "mobile", "app ranks", "ratings"],
43
+ description: "A 0 to 100 summary of the public chart ranks of the company's apps across countries, as APPS charts it. Needs Pro.",
44
+ input: "ticker",
45
+ load: async ({ ticker, start, signal }) => {
46
+ const data = await fetchAttention("apps", ticker!, { days: appHistoryDays(start) }, undefined, signal) as AppAttentionPayload;
47
+ if (data.access === "preview") throw new Error("Full app history requires Pro.");
48
+ if (!data.history.length) throw new Error("History is accumulating from the first capture.");
49
+ return data.history.map((point) => ({ date: point.date, value: point.attentionScore }));
50
+ },
51
+ },
52
+ ];
@@ -1,6 +1,80 @@
1
- import type { HeadlessPaneDefinition } from "../../../types/plugin";
1
+ import type { DataTableColumn } from "../../../components";
2
+ import type { HeadlessBundleSection, HeadlessPaneColumn, HeadlessPaneDefinition } from "../../../types/plugin";
3
+ import { withoutQuietColumns } from "../shared/research-cells";
2
4
  import { resolveHeadlessIssuerListing } from "../shared/headless-market-data";
3
- import { companyQuery, fetchCompanyData, type CompanyMode } from "./client";
5
+ import { companyQuery, fetchCompanyData, type CompanyDataset, type CompanyMode } from "./client";
6
+ import { allGuidance, allObservations, companyCellText, companyColumns, companyPreviewNote, QUIET_COLUMNS, type CompanyRow } from "./model";
7
+ import type { KpiObservation } from "../../../api-client/company-kpis";
8
+
9
+ /** What the server takes as a metric; anything else is not a metric id and is not sent. */
10
+ const METRIC_ID = /^[a-z0-9_]{1,80}$/;
11
+ /** Filters the free preview ignores: it is fixed at the latest disclosures. */
12
+ const PRO_FILTERS = ["basis", "from", "to", "asOf"] as const;
13
+ /** The row field behind each pane column, where there is one; exports keep that field's value. */
14
+ const ROW_KEYS: Record<string, string> = { scope: "dimensions", issued: "issuedDate" };
15
+
16
+ /**
17
+ * The pane's table columns, printed as the pane prints them: fiscal labels
18
+ * (FY2024), compact values with their unit (12.48B USD), the scope in words,
19
+ * and Basis and Scope only when a row is not the reported, consolidated
20
+ * figure. Each row's disclosure date follows. The rows keep every field the
21
+ * server sent for exports.
22
+ */
23
+ function reportColumns(mode: CompanyMode, history: boolean, revisions: boolean, rows: CompanyRow[], observations: KpiObservation[]): HeadlessPaneColumn[] {
24
+ const columns: DataTableColumn[] = [...companyColumns(mode === "guidance", false, history),
25
+ ...(revisions ? [{ id: "revision", label: "Revision", width: 12, align: "left" as const }] : [])];
26
+ return [...withoutQuietColumns(columns, rows, (row, id) => companyCellText(row, id, observations), QUIET_COLUMNS).map((column): HeadlessPaneColumn => ({
27
+ key: column.id === "value" && mode === "guidance" ? "rangeText" : ROW_KEYS[column.id] ?? column.id, header: column.label, align: column.align === "right" ? "right" : "left",
28
+ format: (_value, row) => companyCellText(row as unknown as CompanyRow, column.id, observations),
29
+ })), { key: "asOf", header: "As of", format: (value) => typeof value === "string" ? value.slice(0, 10) : "--" }];
30
+ }
31
+
32
+ function datasetRows(data: CompanyDataset): CompanyRow[] {
33
+ return "series" in data ? allObservations(data) : allGuidance(data);
34
+ }
35
+
36
+ /** The metrics a report has rows for, `revenue (Revenue)`, in the order the server lists them. */
37
+ function metricList(rows: CompanyRow[]): string {
38
+ return [...new Map(rows.map((row) => [row.metricId, `${row.metricId} (${row.metric.name})`])).values()].join(", ");
39
+ }
40
+
41
+ /**
42
+ * The free preview is fixed, so a metric asked for is picked out of it here,
43
+ * never answered with another metric's rows. An id the dictionary does not
44
+ * know fails naming the ones this company has. A known metric the preview has
45
+ * no rows for may be among the values it holds back, so that case gives the
46
+ * preview's own counts; only a company with nothing held back has none.
47
+ */
48
+ function metricFilter(requested: string, data: CompanyDataset, mode: CompanyMode): { keep: (row: CompanyRow) => boolean; empty?: string } {
49
+ if (!requested) return { keep: () => true };
50
+ const rows = datasetRows(data);
51
+ const whose = data.access === "preview" ? `${data.symbol}'s free preview` : data.symbol;
52
+ const offered = metricList(rows);
53
+ const has = offered ? `${whose} has ${offered}` : `${whose} has no ${mode === "kpis" ? "KPI" : "guidance"} disclosures`;
54
+ const known = data.dictionary.find((metric) => metric.id === requested) ?? rows.find((row) => row.metricId === requested)?.metric;
55
+ if (!known) throw new Error(`${requested} is not a known metric id. ${has}.`);
56
+ const keep = (row: CompanyRow) => row.metricId === requested;
57
+ if (rows.some(keep)) return { keep };
58
+ if (data.access === "preview" && data.lockedRows > 0) {
59
+ const shown = Math.max(0, data.totalRows - data.lockedRows);
60
+ const noun = (count: number) => `${mode === "kpis" ? "KPI value" : "guidance figure"}${count === 1 ? "" : "s"}`;
61
+ const all = `Gloom Pro shows all ${data.totalRows.toLocaleString("en-US")}`;
62
+ return { keep, empty: shown === 0 ? `The free preview shows no ${noun(0)}; ${all}.`
63
+ : `${known.name} is not ${shown === 1 ? "the" : "among the"} ${shown.toLocaleString("en-US")} free ${noun(shown)}; ${all}.` };
64
+ }
65
+ return { keep, empty: `${data.symbol} has no ${known.name} (${known.id}) ${mode === "kpis" ? "disclosures" : "guidance"}${offered ? `; it has ${offered}` : ""}.` };
66
+ }
67
+
68
+ /**
69
+ * How old a free preview's rows are: the footer dates the company's newest
70
+ * disclosure, which the fixed preview may not show.
71
+ */
72
+ function ageNote(data: CompanyDataset, latest: CompanyRow[], mode: CompanyMode): string | null {
73
+ const shown = latest.map((row) => row.asOf.slice(0, 10)).sort().at(-1);
74
+ const newest = data.asOf?.slice(0, 10);
75
+ if (data.access !== "preview" || !shown || !newest || newest <= shown) return null;
76
+ return `The free preview's latest ${mode === "kpis" ? "KPIs are" : "guidance is"} as of ${shown}, older than ${data.symbol}'s newest disclosure (${newest}).`;
77
+ }
4
78
 
5
79
  export function companyHeadless(mode: CompanyMode): HeadlessPaneDefinition<"bundle"> {
6
80
  return {
@@ -8,10 +82,10 @@ export function companyHeadless(mode: CompanyMode): HeadlessPaneDefinition<"bund
8
82
  freshness: { source: "Company filings and calls", status: "not-a-feed", basis: "reported data" },
9
83
  argument: { kind: "ticker", description: "Listed company ticker, including exchange-qualified global symbols.", placeholder: "ticker" },
10
84
  discovery: { aliases: [mode === "kpis" ? "KPIS" : "GUIDE"], dataRequirements: ["Gloom Cloud company disclosures"],
11
- limitations: ["Pro dataset with a fixed latest preview on Free", "Coverage follows available company disclosures; missing data is not zero", "Compare matching definition, period, currency, basis and scope", "Fiscal labels without explicit calendar dates are retained without inferred dates"] },
85
+ limitations: ["Pro dataset with a fixed latest preview on Free.", "Coverage follows available company disclosures; missing data is not zero.", "Compare matching definition, period, currency, basis and scope.", "Fiscal labels without explicit calendar dates are retained without inferred dates."] },
12
86
  options: [
13
87
  { key: "tab", type: "enum", settingKey: "tab", defaultValue: "table", values: [{ value: "table" }, { value: "chart" }, ...(mode === "guidance" ? [{ value: "history" }] : []), { value: "evidence" }], description: "The pane section to render." },
14
- { key: "metric", type: "string", settingKey: "metric", description: "Canonical metric ID, such as arr or subscribers." },
88
+ { key: "metric", type: "string", settingKey: "metric", description: "Canonical metric ID, such as arr or subscribers.", normalize: (value) => value.trim().toLowerCase() },
15
89
  { key: "basis", type: "enum", values: [{ value: "reported" }, { value: "adjusted" }, { value: "constant_currency" }, { value: "organic" }], description: "Accounting basis filter (Pro)." },
16
90
  { key: "from", type: "string", description: "First calendar period end, YYYY-MM-DD (Pro)." },
17
91
  { key: "to", type: "string", description: "Last calendar period end, YYYY-MM-DD (Pro)." },
@@ -19,15 +93,28 @@ export function companyHeadless(mode: CompanyMode): HeadlessPaneDefinition<"bund
19
93
  ],
20
94
  describe: (args) => `${mode === "kpis" ? "Company KPIs" : "Company guidance"} | ${args.symbols[0]}`,
21
95
  async load(args, ctx) {
22
- const options = companyQuery(args.options);
96
+ const requested = typeof args.options.metric === "string" && args.options.metric !== "all" ? args.options.metric.trim().toLowerCase() : "";
97
+ const options = companyQuery({ ...args.options, metric: METRIC_ID.test(requested) ? requested : undefined });
23
98
  const symbol = args.symbols[0]!;
24
99
  const data = await fetchCompanyData(mode, symbol, options, ctx.apiClient, await resolveHeadlessIssuerListing(ctx, symbol));
25
- return { complete: !data.truncated, errors: data.truncated ? [data.access === "preview" ? "Full disclosures and history require Gloom Pro" : "Response limit reached; narrow the metric or date range"] : [],
100
+ const { keep, empty } = metricFilter(requested, data, mode);
101
+ const observations = "series" in data ? allObservations(data) : [];
102
+ // A metric with no rows says why once, in the first section.
103
+ const section = (title: string, rows: CompanyRow[], { history = false, revisions = false, first = false } = {}): HeadlessBundleSection => {
104
+ const shown = rows.filter(keep);
105
+ return { title, columns: reportColumns(mode, history, revisions, shown, observations), rows: shown.map((row) => ({ ...row })), ...(empty && first ? { empty } : {}) };
106
+ };
107
+ const latest = ("series" in data ? data.series.map((series) => series.latest) : data.guidance).filter(keep);
108
+ const ignored = data.access === "preview" ? PRO_FILTERS.filter((key) => typeof args.options[key] === "string" && args.options[key] !== "") : [];
109
+ const notes = [ageNote(data, latest, mode),
110
+ ignored.length ? `The free preview is fixed: ${ignored.map((key) => `--${key}`).join(", ")} ${ignored.length > 1 ? "need" : "needs"} Gloom Pro.` : null].filter((note): note is string => !!note);
111
+ return { complete: !data.truncated, errors: data.truncated ? [data.access === "preview" ? companyPreviewNote(data, mode === "guidance") : "Response limit reached; narrow the metric or date range"] : [],
112
+ ...(notes.length ? { notes } : {}),
26
113
  sections: "series" in data ? [
27
- { title: "Latest KPIs", rows: data.series.map((series) => ({ ...series.latest })) },
28
- { title: "KPI history", rows: data.series.flatMap((series) => series.observations.map((row) => ({ ...row }))) },
29
- { title: "Revisions and conflicts", rows: data.revisions.map((row) => ({ ...row })) },
30
- ] : [{ title: "Current guidance", rows: data.guidance.map((row) => ({ ...row })) }, { title: "Guidance history", rows: data.history.map((row) => ({ ...row })) }],
114
+ section("Latest KPIs", data.series.map((series) => series.latest), { first: true }),
115
+ section("KPI history", data.series.flatMap((series) => series.observations)),
116
+ section("Revisions and conflicts", data.revisions, { revisions: true }),
117
+ ] : [section("Current guidance", data.guidance, { first: true }), section("Guidance history", data.history, { history: true })],
31
118
  metadata: { symbol: data.symbol, asOf: data.asOf, access: data.access, coverage: data.coverage, dictionary: data.dictionary,
32
119
  lockedRows: data.lockedRows, totalRows: data.totalRows, methodology: data.methodology } };
33
120
  },
@@ -3,6 +3,7 @@ import type { DataTableColumn } from "../../../components";
3
3
  import { scalarPoint, staticSeries } from "../../../components/chart/static/series";
4
4
  import type { CompositeChartXAxis } from "../../../components/chart/composite/types";
5
5
  import { formatCompact, formatNumber } from "../../../utils/format";
6
+ import { freePreviewNote } from "../shared/free-preview";
6
7
 
7
8
  export type CompanyRow = KpiObservation | KpiGuidance;
8
9
  export const isGuidance = (row: CompanyRow): row is KpiGuidance => "issuedDate" in row;
@@ -29,7 +30,7 @@ export const rangeText = (row: KpiGuidance, withUnit = true) => row.status === "
29
30
  : row.low !== null ? `${row.hedge === "greater_than" ? ">" : "≥"} ${valueText(row, row.low, withUnit)}`
30
31
  : row.high !== null ? `${row.hedge === "less_than" ? "<" : "≤"} ${valueText(row, row.high, withUnit)}` : row.rangeText;
31
32
  /** The unit a value cell carries after its number; percent, bp and x are already in the number. */
32
- export function unitSuffix(row: Pick<CompanyRow, "unit" | "currency" | "dimensions">): string {
33
+ function unitSuffix(row: Pick<CompanyRow, "unit" | "currency" | "dimensions">): string {
33
34
  if (row.unit === "currency") return row.currency ? ` ${row.currency}` : "";
34
35
  if (row.unit === "currency_per_share") return ` ${row.currency ?? ""}/sh`.replace(" /", " ");
35
36
  if (row.unit === "currency_per_unit" || row.unit === "volume") return ` ${unitLabel(row)}`;
@@ -68,7 +69,7 @@ export function observationChange(row: KpiObservation, observations: KpiObservat
68
69
  return { value: (row.value - prior.value) / Math.abs(prior.value) * 100, unit: "%" };
69
70
  }
70
71
  export const changeText = (change: { value: number | null; unit: string }) => change.value === null ? "--" : `${change.value > 0 ? "+" : ""}${formatNumber(change.value, 2)}${change.unit}`;
71
- export const fiscalLabel = (row: CompanyRow) => row.period.fiscalYear === null ? row.period.label
72
+ export const fiscalLabel = (row: Pick<CompanyRow, "period">) => row.period.fiscalYear === null ? row.period.label
72
73
  : row.period.kind === "year" ? `FY${row.period.fiscalYear}`
73
74
  : row.period.fiscalQuarter !== null ? `Q${row.period.fiscalQuarter} FY${row.period.fiscalYear}${row.period.kind === "ytd" ? " YTD" : ""}` : row.period.label;
74
75
  export const periodOrder = (row: CompanyRow) => row.period.fiscalYear !== null
@@ -104,6 +105,19 @@ export function guidanceSeries(rows: KpiGuidance[], selected: KpiGuidance | unde
104
105
  if (actual && series.length) series.push(staticSeries(timeline.map((row) => scalarPoint(new Date(row.issuedDate), actual.value)), { id: "actual", label: "Later actual", color: colors.actual, calendarSpaced: true }));
105
106
  return series;
106
107
  }
108
+ /** Columns that say nothing while every row is the company's consolidated, as-reported figure. */
109
+ export const QUIET_COLUMNS = { basis: ["Reported"], scope: ["Consolidated"] };
110
+ /** The text of a table cell as the pane draws it; the report prints the same words. */
111
+ export function companyCellText(row: CompanyRow, column: string, observations: KpiObservation[]): string {
112
+ const guide = isGuidance(row) ? row : null;
113
+ if (column === "change") return guide ? directionLabel(guide.direction) : changeText(observationChange(row as KpiObservation, observations));
114
+ return column === "metric" ? row.metric.name : column === "period" ? fiscalLabel(row) : column === "value" ? `${guide ? rangeText(guide) : observationValue(row as KpiObservation)}${guide?.status === "withdrawn" || guide?.hedge === "qualitative" ? "" : unitSuffix(row)}`
115
+ : column === "unit" ? unitLabel(row)
116
+ : column === "basis" ? basisLabel(row.basis) : column === "scope" ? dimensionLabel(row.dimensions) || "Consolidated"
117
+ : column === "issued" ? guide?.issuedDate ?? "--" : column === "actual" ? guide?.actual ? `${valueText(row, guide.actual.value)}${unitSuffix(row)}` : "--"
118
+ : column === "outcome" ? guide ? outcomeLabel(guide) : "--" : column === "published" ? row.evidence[0]!.publishedAt.slice(0, 10)
119
+ : column === "confidence" ? `${Math.round(row.confidence * 100)}%` : column === "revision" ? `${row.revision} ${row.current ? "current" : "superseded"}` : row.evidence[0]!.quote;
120
+ }
107
121
  export function companyColumns(guidance: boolean, evidence: boolean, history: boolean, trend = false): DataTableColumn[] {
108
122
  const columns: DataTableColumn[] = [
109
123
  { id: "metric", label: "Metric", width: 27, flexGrow: 1, align: "left" },
@@ -122,3 +136,11 @@ export function companyColumns(guidance: boolean, evidence: boolean, history: bo
122
136
  : history ? ["metric", "period", "actual", "outcome", "value", "issued", "change", "basis", "scope"] : null;
123
137
  return order ? columns.sort((a, b) => order.indexOf(a.id) - order.indexOf(b.id)) : columns;
124
138
  }
139
+
140
+ /** The lock line of a free preview, in the same words in the pane and `fn KPIS` / `fn GUIDE`. */
141
+ export function companyPreviewNote(data: Pick<KpisPayload, "lockedRows" | "totalRows" | "coverage">, guidance: boolean): string {
142
+ const count = (value: number) => value.toLocaleString("en-US");
143
+ const rows = `${count(data.totalRows)} ${guidance ? "guidance figures" : "KPI values"}`;
144
+ return freePreviewNote({ shows: data.lockedRows > 0 ? `${count(Math.max(0, data.totalRows - data.lockedRows))} of ${rows}` : rows,
145
+ adds: data.lockedRows > 0 ? `the other ${count(data.lockedRows)}` : null, historyFrom: data.coverage.firstPeriod });
146
+ }
@@ -13,21 +13,22 @@ import type { PaneProps } from "../../../types/plugin";
13
13
  import { Box, Text, useRendererHost, useUiCapabilities, type ScrollBoxRenderable } from "../../../ui";
14
14
  import { SignInWall } from "../cloud/auth-actions";
15
15
  import { CLOUD_PLAN_KEY, useCloudUpgradeAction } from "../shared/cloud-upgrade";
16
+ import { useOpenDescription } from "../shared/open-description";
16
17
  import { Blurred, LockedOverlay, UpgradeLabel } from "../shared/locked-rows";
17
18
  import { isCloudSessionRequired, useResearchCloudSession } from "../shared/research-cloud-session";
18
19
  import { cachedCompanyData, loadCompanyData, KPI_UNAVAILABLE, validateCompanyData, type CompanyDataset, type CompanyMode } from "./client";
19
20
  import { useCompanyEvidence } from "./screenshot-evidence";
20
- import { allGuidance, allObservations, basisLabel, changeText, changeTone, companyColumns, dimensionLabel, directionLabel, directionTone, guideGroupKey, guidanceSeries, fiscalLabel,
21
- isGuidance, exactObservation, observationValue, observationChange, observationChart, periodOrder, outcomeLabel, rangeText, seriesLabel, unitLabel, unitSuffix, valueText, type CompanyRow } from "./model";
21
+ import { allGuidance, allObservations, basisLabel, changeText, changeTone, companyCellText, companyColumns, dimensionLabel, directionLabel, directionTone, guideGroupKey, guidanceSeries, fiscalLabel,
22
+ isGuidance, exactObservation, observationValue, observationChange, observationChart, periodOrder, outcomeLabel, QUIET_COLUMNS, rangeText, seriesLabel, unitLabel, valueText, companyPreviewNote,
23
+ type CompanyRow } from "./model";
22
24
  import { PriceSparkline } from "../../../components/price-sparkline/view";
23
25
  import type { PricePoint } from "../../../types/financials";
24
26
  import { toneColor, withoutQuietColumns } from "../shared/research-cells";
25
27
 
26
- /** Columns that say nothing while every row is the company's consolidated, as-reported figure. */
27
- const QUIET_COLUMNS = { basis: ["Reported"], scope: ["Consolidated"] };
28
-
29
- type Item = { id: string; row: CompanyRow } | { id: string; row: null };
28
+ /** A locked placeholder, or with `note` the line above them saying what free shows and what Pro adds. */
29
+ type Item = { id: string; row: CompanyRow } | { id: string; row: null; note?: string };
30
30
  const getId = (item: Item) => item.id;
31
+ const isNote = (item: Item) => "note" in item && !!item.note;
31
32
  function DisclosureEvidence({ row, sourceId, onSource, width }: { row: CompanyRow; sourceId: string | null; onSource: (id: string) => void; width: number }) {
32
33
  const colors = useThemeColors();
33
34
  const evidence = row.evidence.find((entry) => entry.id === sourceId) ?? row.evidence[0]!;
@@ -77,6 +78,7 @@ function CompanyView({ symbol, exchange, name, mode, width, height, focused }: P
77
78
  const host = useRendererHost();
78
79
  const desktop = !!useUiCapabilities().nativePaneChrome;
79
80
  const { createPaneFromTemplate } = usePluginAppActions();
81
+ const openDescription = useOpenDescription();
80
82
  const session = useResearchCloudSession();
81
83
  const access = usePlanAccess();
82
84
  const accessKey = `${session.requestKey}:${access.hasProAccess ? "full" : "preview"}`;
@@ -132,7 +134,9 @@ function CompanyView({ symbol, exchange, name, mode, width, height, focused }: P
132
134
  const activeRow = openRow ?? selected;
133
135
  const preview = data?.access === "preview" && data.lockedRows > 0;
134
136
  const lockedCount = preview ? Math.min(3, data.lockedRows) : 0;
135
- const items = useMemo<Item[]>(() => [...rows.map((row) => ({ id: row.id, row })), ...Array.from({ length: lockedCount }, (_, index) => ({ id: `locked:${index}`, row: null }))], [rows, lockedCount]);
137
+ const previewNote = preview ? companyPreviewNote(data, mode === "guidance") : null;
138
+ const items = useMemo<Item[]>(() => [...rows.map((row) => ({ id: row.id, row })), ...(previewNote ? [{ id: "note:preview", row: null, note: previewNote }] : []),
139
+ ...Array.from({ length: lockedCount }, (_, index) => ({ id: `locked:${index}`, row: null }))], [rows, lockedCount, previewNote]);
136
140
  // One trend per series beside its latest value, once a series has three comparable points.
137
141
  const trends = useMemo(() => {
138
142
  const map = new Map<string, PricePoint[]>();
@@ -165,10 +169,10 @@ function CompanyView({ symbol, exchange, name, mode, width, height, focused }: P
165
169
  ...(preview ? [{ id: "upgrade", key: CLOUD_PLAN_KEY, label: "upgrade", title: "Upgrade to Pro", onPress: openUpgrade }] : []),
166
170
  ];
167
171
  usePaneMenuItems("company-disclosures:research", () => symbol ? [
168
- { id: "description", label: "Description (DES)", onSelect: () => createPaneFromTemplate("new-ticker-detail-pane", { symbol }) },
172
+ { id: "description", label: "Description (DES)", onSelect: () => openDescription(symbol) },
169
173
  { id: "financials", label: "Financial Analysis (FA)", onSelect: () => createPaneFromTemplate("financial-analysis-pane", { symbol }) },
170
174
  { id: "price-chart", label: "Price Chart (G)", onSelect: () => createPaneFromTemplate("chart-composer-pane", { arg: symbol }) },
171
- ] : null, [symbol, createPaneFromTemplate]);
175
+ ] : null, [symbol, createPaneFromTemplate, openDescription]);
172
176
  usePaneStatusFooter({ registrationId: "company-kpis", loading: resource.loading, error: data ? resource.error : null, stale: resource.data?.stale,
173
177
  info: data?.asOf ? [{ id: "as-of", parts: [{ text: `as of ${data.asOf.slice(0, 10)}`, tone: "muted" as const }] }] : [], hints });
174
178
  usePaneNoticeFooter({ registrationId: "company-kpis:notices", focused, notices: [resource.data?.refreshError,
@@ -183,6 +187,7 @@ function CompanyView({ symbol, exchange, name, mode, width, height, focused }: P
183
187
  const renderCell = (item: Item, column: (typeof columns)[number]): DataTableCell => {
184
188
  const row = item.row;
185
189
  if (!row) {
190
+ if (isNote(item)) return { text: "" };
186
191
  if (!desktop && column.id === "metric" && item.id === "locked:0") return { text: "Unlock with Pro", content: <UpgradeLabel text="Unlock with Pro" onPress={openUpgrade} />, onMouseDown: openUpgrade };
187
192
  return desktop ? { text: "", content: <Blurred><Text fg={colors.textDim}>{column.id === "metric" ? "Additional disclosure" : "Hidden"}</Text></Blurred> } : { text: "░░░░░", color: colors.textDim };
188
193
  }
@@ -199,12 +204,7 @@ function CompanyView({ symbol, exchange, name, mode, width, height, focused }: P
199
204
  const change = observationChange(row as KpiObservation, observations);
200
205
  return { text: changeText(change), value: change.value, color: toneColor(changeTone(row as KpiObservation, change.value), colors) };
201
206
  }
202
- const text = column.id === "metric" ? row.metric.name : column.id === "period" ? fiscalLabel(row) : column.id === "value" ? `${guide ? rangeText(guide) : observationValue(row as KpiObservation)}${guide?.status === "withdrawn" || guide?.hedge === "qualitative" ? "" : unitSuffix(row)}`
203
- : column.id === "unit" ? unitLabel(row)
204
- : column.id === "basis" ? basisLabel(row.basis) : column.id === "scope" ? dimensionLabel(row.dimensions) || "Consolidated"
205
- : column.id === "issued" ? guide?.issuedDate ?? "--" : column.id === "actual" ? guide?.actual ? `${valueText(row, guide.actual.value)}${unitSuffix(row)}` : "--"
206
- : column.id === "outcome" ? guide ? outcomeLabel(guide) : "--" : column.id === "published" ? row.evidence[0]!.publishedAt.slice(0, 10)
207
- : column.id === "confidence" ? `${Math.round(row.confidence * 100)}%` : column.id === "revision" ? `${row.revision} ${row.current ? "current" : "superseded"}` : row.evidence[0]!.quote;
207
+ const text = companyCellText(row, column.id, observations);
208
208
  return { text, ...(column.id === "value" && !guide ? { value: exactObservation(row as KpiObservation) ? (row as KpiObservation).value : observationValue(row as KpiObservation) } : column.id === "actual" ? { value: guide?.actual?.value } : {}),
209
209
  color: column.id === "metric" ? colors.textBright : column.id === "value" || column.id === "actual" ? colors.textBright
210
210
  : column.id === "outcome" && guide?.actual ? guide.actual.favorable === "beat" ? colors.positive : guide.actual.favorable === "miss" ? colors.negative : colors.text
@@ -217,7 +217,8 @@ function CompanyView({ symbol, exchange, name, mode, width, height, focused }: P
217
217
  empty={!data && resource.error === KPI_UNAVAILABLE} emptyTitle={KPI_UNAVAILABLE} subject="company disclosures">
218
218
  {data ? <DataTableStackView<Item> focused={focused} rootWidth={width} rootHeight={bodyHeight} columns={columns} items={items} getItemKey={getId}
219
219
  selection={{ kind: "id", selectedId: selected?.id ?? null, getId, onChange: setSelected }}
220
- onActivate={(item) => item.row ? setOpen(item.row.id) : openUpgrade()} renderCell={renderCell} freezeFirstColumn selectedTextOverridesCellColor showHorizontalScrollbar
220
+ onActivate={(item) => item.row ? setOpen(item.row.id) : isNote(item) ? undefined : openUpgrade()} renderCell={renderCell}
221
+ isNavigable={(item) => !isNote(item)} renderSectionHeader={(item) => "note" in item && item.note ? { text: item.note } : null} freezeFirstColumn selectedTextOverridesCellColor showHorizontalScrollbar
221
222
  detailOpen={!!openRow} onBack={() => setOpen(null)} detailTitle={openRow ? `${openRow.metric.name} · ${fiscalLabel(openRow)}` : undefined}
222
223
  detailScrollRef={detailScrollRef} detailContent={openRow ? <DetailScrollBody ref={detailScrollRef} resetScrollKey={openRow.id}><DisclosureEvidence row={openRow} sourceId={sourceId} onSource={setSource} width={width} /></DetailScrollBody> : null}
223
224
  sortColumnId={sort.column} sortDirection={sort.direction} onHeaderClick={(column) => setSort((previous) => ({ column, direction: previous.column === column && previous.direction === "desc" ? "asc" : "desc" }))}
@@ -32,6 +32,7 @@ import { cotModule } from "./cot";
32
32
  import { doeModule } from "./doe";
33
33
  import { gpuModule } from "./gpu";
34
34
  import { fxMatrixModule } from "./fx-matrix";
35
+ import { docsModule } from "./docs";
35
36
  import { helpModule } from "./help";
36
37
  import { positionSizerModule } from "./kelly-sizer";
37
38
  import { layoutManagerModule } from "./layout-manager";
@@ -57,6 +58,7 @@ import { socialMentionsModule } from "./social-mentions";
57
58
  import { timeSalesModule } from "./time-sales";
58
59
  import { estimateRevisionsModule } from "./estimate-revisions";
59
60
  import { chartComposerModule } from "./chart-composer";
61
+ import { userSeriesModule } from "./chart-composer/user-series";
60
62
  import { congressResearchModule } from "./congress-trades";
61
63
  import { dividendYieldModule } from "./dividend-yield";
62
64
  import { executivesModule } from "./executives";
@@ -104,7 +106,7 @@ import {
104
106
 
105
107
  export const applicationPlugin = composeBuiltinPlugin({
106
108
  ...applicationPluginMeta,
107
- modules: [layoutManagerModule, pluginMarketplaceModule, helpModule, changelogModule, connectionsModule],
109
+ modules: [layoutManagerModule, pluginMarketplaceModule, helpModule, changelogModule, connectionsModule, docsModule],
108
110
  });
109
111
 
110
112
  export const portfolioPlugin = composeBuiltinPlugin({
@@ -121,18 +123,22 @@ const tickerResearchModule = (module: PluginModule) => ({ module, stateId: "tick
121
123
  export const tickerCorePlugin = composeBuiltinPlugin({
122
124
  ...tickerCorePluginMeta,
123
125
  modules: [
124
- tickerDetailModule,
125
- chartComposerModule,
126
- researchModule,
127
- estimateRevisionsModule,
128
- companyKpisModule,
129
- revenueBreakdownModule,
130
- dividendYieldModule,
131
- reverseDcfModule,
132
- peBandModule,
133
- executivesModule,
134
- timeSalesModule,
135
- ].map(rendererOnly),
126
+ ...[
127
+ tickerDetailModule,
128
+ chartComposerModule,
129
+ researchModule,
130
+ estimateRevisionsModule,
131
+ companyKpisModule,
132
+ revenueBreakdownModule,
133
+ dividendYieldModule,
134
+ reverseDcfModule,
135
+ peBandModule,
136
+ executivesModule,
137
+ timeSalesModule,
138
+ ].map(rendererOnly),
139
+ // Reads the profile's series folder, so it runs where the disk is: the desktop backend too.
140
+ userSeriesModule,
141
+ ],
136
142
  });
137
143
 
138
144
  export const optionsVolatilityPlugin = composeBuiltinPlugin({
@@ -33,6 +33,7 @@ export const connectionsModule: PluginModule = {
33
33
  panes: [{
34
34
  id: "connections",
35
35
  name: "Connections",
36
+ personalData: "account",
36
37
  icon: "C",
37
38
  component: ConnectionsPane,
38
39
  defaultPosition: "right",
@@ -32,7 +32,7 @@ export const cotHeadless: HeadlessPaneDefinition<"bundle"> = {
32
32
  options: [{ key: "report", type: "enum", values: [{ value: "legacy" }, { value: "disaggregated" }], defaultValue: "legacy", description: "CFTC report family." },
33
33
  { key: "traderClass", type: "enum", values: ["noncommercial", "commercial", "producer", "swap", "managed-money", "other-reportable", "nonreportable"].map((value) => ({ value })), description: "Trader class for the extremes board; defaults by report family." },
34
34
  { key: "scope", type: "enum", values: COT_SCOPES.map(({ value }) => ({ value })), defaultValue: "major", description: "Markets on the extremes board, as in the pane." }],
35
- discovery: { aliases: ["COT", "CFTC"], dataRequirements: ["Gloom Cloud CFTC history"], limitations: ["Futures-only positions aggregate all maturities", "Legacy and disaggregated classes differ", "Observation date is not publication date", "Some markets have short or suppressed histories"] },
35
+ discovery: { aliases: ["COT", "CFTC"], dataRequirements: ["Gloom Cloud CFTC history"], limitations: ["Futures-only positions aggregate all maturities.", "Legacy and disaggregated classes differ.", "Observation date is not publication date.", "Some markets have short or suppressed histories."] },
36
36
  describe: "CFTC positioning",
37
37
  async load(args, ctx) {
38
38
  const family = args.options.report === "disaggregated" ? "disaggregated" : "legacy";
@@ -3,14 +3,16 @@ import { cotBoardCache } from "./client";
3
3
  import { cotHeadless } from "./headless";
4
4
  import { COT_ROOT_OPTIONS, cotContractCode, cotContractCodeForTicker, cotRoot, cotUnknownMarketMessage } from "./model";
5
5
  import { CotPane } from "./pane";
6
+ import { COT_SERIES } from "./series";
6
7
 
7
8
  export const cotModule: PluginModule = {
9
+ series: COT_SERIES,
8
10
  panes: [{ id: "cot", name: "CFTC Positioning", icon: "P", component: CotPane,
9
11
  defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 106, height: 30 },
10
12
  tableExport: true, headless: cotHeadless }],
11
13
  paneTemplates: [{ id: "cot-cot", paneId: "cot", label: "CFTC Positioning",
12
14
  description: "Weekly futures positioning, changes, historical percentiles and cross-market extremes.",
13
- keywords: ["cot", "cftc", "positioning", "commitments", "managed money", "net spec"],
15
+ keywords: ["cot", "cftc", "positioning", "commitments", "managed money", "net spec", "crude oil", "natural gas"],
14
16
  shortcut: { prefix: "COT", aliases: ["CFTC"], argKind: "text" as const, argPlaceholder: "code or root", argOptional: true,
15
17
  argOptions: () => COT_ROOT_OPTIONS }, headless: cotHeadless,
16
18
  createInstance: (context, options) => {
@@ -5,6 +5,7 @@ import type { PricePoint } from "../../../types/financials";
5
5
  import { formatPriceObservation } from "../../../market-data/market/format";
6
6
  import { cleanFloat32Price } from "../../../cli/history-rows";
7
7
  import { cryptoPairCoin, isFuturesSymbol } from "../shared/crypto-pair";
8
+ import { FUTURES_CONTRACTS, futuresBoardContract, futuresBoardContractForTicker, type FuturesContract } from "../../../market-data/futures-board";
8
9
 
9
10
  export const COT_CLASSES: Record<CotFamily, Array<{ value: CotClass; label: string }>> = {
10
11
  legacy: [{ value: "noncommercial", label: "Noncommercial" }, { value: "commercial", label: "Commercial" }, { value: "nonreportable", label: "Nonreportable" }],
@@ -29,7 +30,7 @@ const ROOTS: Record<string, { code: string; exchange: string; priceSymbol: strin
29
30
  SOL: { code: "177741", exchange: "CME", priceSymbol: null, name: "Solana", crypto: true },
30
31
  XRP: { code: "176740", exchange: "CME", priceSymbol: null, name: "XRP", crypto: true },
31
32
  };
32
- /** The roots `cotContractCode` accepts, labeled "ZQ 30-Day Fed Funds". */
33
+ /** The verified root aliases, labeled "ZQ 30-Day Fed Funds"; `cotContractCode` also takes every FUT board root the CFTC reports. */
33
34
  export const COT_ROOT_OPTIONS = Object.entries(ROOTS).map(([root, row]) => ({ value: root, label: root === row.name ? root : `${root} ${row.name}` }));
34
35
  /** The crypto roots named for a coin, which a coin pair (BTC-USD) can stand for. The micros have no pair. */
35
36
  const COIN_PAIR_ROOTS: ReadonlySet<string> = new Set(["BTC", "ETH", "SOL", "XRP"]);
@@ -37,9 +38,12 @@ const COIN_PAIR_ROOTS: ReadonlySet<string> = new Set(["BTC", "ETH", "SOL", "XRP"
37
38
  * Front-month price overlays for major markets without a root alias, each
38
39
  * checked to return five years of daily history (2026-09-24). Keyed by CFTC
39
40
  * code, never added to ROOTS: an alias would also claim the equity ticker under
40
- * the cursor (ZM, ZS, PL). No cash index stands in, so the dollar index has none.
41
- * Bitcoin and ether are in ROOTS, where `cotContractCodeForTicker` keeps the
42
- * same guard for their aliases.
41
+ * the cursor (ZM, ZS, PL). A FUT board root typed as an argument finds its
42
+ * market here through its price symbol (NG is NG=F, so 023651). No cash index
43
+ * stands in, so the dollar index has none. Orange juice and lumber were added
44
+ * on 2026-10-11 so their board roots open a market; lumber's contract (LBR)
45
+ * started in August 2022, so its price begins there. Bitcoin and ether are in
46
+ * ROOTS, where `cotContractCodeForTicker` keeps the same guard for their aliases.
43
47
  */
44
48
  const PRICE_OVERLAYS: Record<string, { exchange: string; priceSymbol: string }> = {
45
49
  "209742": { exchange: "CME", priceSymbol: "NQ=F" }, "239742": { exchange: "CME", priceSymbol: "RTY=F" },
@@ -60,9 +64,16 @@ const PRICE_OVERLAYS: Record<string, { exchange: string; priceSymbol: string }>
60
64
  "007601": { exchange: "CBT", priceSymbol: "ZL=F" }, "026603": { exchange: "CBT", priceSymbol: "ZM=F" },
61
65
  "083731": { exchange: "NYB", priceSymbol: "KC=F" }, "080732": { exchange: "NYB", priceSymbol: "SB=F" },
62
66
  "033661": { exchange: "NYB", priceSymbol: "CT=F" }, "073732": { exchange: "NYB", priceSymbol: "CC=F" },
67
+ "040701": { exchange: "NYB", priceSymbol: "OJ=F" }, "058644": { exchange: "CME", priceSymbol: "LBR=F" },
63
68
  "057642": { exchange: "CME", priceSymbol: "LE=F" }, "054642": { exchange: "CME", priceSymbol: "HE=F" },
64
69
  "061641": { exchange: "CME", priceSymbol: "GF=F" },
65
70
  };
71
+ /** The CFTC market a FUT board root reports under, by its price symbol; null for one the CFTC does not report (TTF). */
72
+ function boardMarketCode(contract: FuturesContract): string | null {
73
+ return Object.values(ROOTS).find((row) => row.priceSymbol === contract.symbol)?.code
74
+ ?? Object.entries(PRICE_OVERLAYS).find(([, row]) => row.priceSymbol === contract.symbol)?.[0]
75
+ ?? null;
76
+ }
66
77
  /**
67
78
  * The markets most readers mean by "positioning", verified against the live
68
79
  * CFTC boards on 2026-09-22. A code missing from a report family simply does
@@ -90,14 +101,26 @@ export const COT_SCOPES = [{ value: "major", label: "Major markets" }, { value:
90
101
  export type CotScope = typeof COT_SCOPES[number]["value"];
91
102
  export function cotScope(value: unknown): CotScope { return value === "all" ? "all" : "major"; }
92
103
 
93
- /** A CFTC code or root typed as an argument or stored in a pane: every alias, crypto included. */
104
+ const rootAlias = (input: string) => ROOTS[input === "VIX" ? "VX" : input]?.code ?? null;
105
+ const marketCode = (input: string) => /^[0-9A-Z]{5}[0-9A-Z+]$/.test(input) ? input : null;
106
+ /**
107
+ * A CFTC code or root typed as an argument or stored in a pane: every alias,
108
+ * crypto included, and every FUT board root the CFTC reports. A typed root is
109
+ * always the future, so ZM here is soybean meal, never Zoom.
110
+ */
94
111
  export function cotContractCode(value: unknown): string | null {
95
112
  if (typeof value !== "string") return null;
96
113
  const input = value.trim().toUpperCase().replace(/=F$/, "");
97
- return ROOTS[input === "VIX" ? "VX" : input]?.code ?? (/^[0-9A-Z]{5}[0-9A-Z+]$/.test(input) ? input : null);
114
+ const board = futuresBoardContract(value);
115
+ return rootAlias(input) ?? (board ? boardMarketCode(board) : null) ?? marketCode(input);
98
116
  }
99
- /** What a market that is neither a root nor a CFTC code is told, with ones that work. */
117
+ /**
118
+ * What a market `cotContractCode` does not know is told: a FUT board root the
119
+ * CFTC does not report says so; anything else gets roots and a code that work.
120
+ */
100
121
  export function cotUnknownMarketMessage(value: unknown): string {
122
+ const board = futuresBoardContract(value);
123
+ if (board) return `${board.code} (${board.name}) is not reported in the CFTC COT.`;
101
124
  const roots = ["ES", "CL", "GC", "ZN"].filter((root) => ROOTS[root]);
102
125
  return `Unknown market "${String(value)}". Try ${roots.join(", ")} or a CFTC market code such as ${ROOTS.GC!.code}.`;
103
126
  }
@@ -106,18 +129,24 @@ export function cotUnknownMarketMessage(value: unknown): string {
106
129
  * argument. The crypto aliases are also US ticker symbols (Grayscale's mini
107
130
  * trusts are BTC and ETH, MetLife is MET), so a bare one is the equity's and
108
131
  * never claims the market: only a futures symbol (BTC=F) or a coin pair
109
- * (BTC-USD) does.
132
+ * (BTC-USD) does. A FUT board root claims it the same way: as its futures
133
+ * symbol (NG=F) or a code no security uses (ZW), never a bare code a security
134
+ * keeps (ZM is Zoom).
110
135
  */
111
136
  export function cotContractCodeForTicker(ticker: unknown): string | null {
112
137
  if (typeof ticker !== "string") return null;
113
138
  const coin = cryptoPairCoin(ticker);
114
139
  if (coin) return COIN_PAIR_ROOTS.has(coin) ? ROOTS[coin]!.code : null;
115
140
  const input = ticker.trim().toUpperCase().replace(/=F$/, "");
116
- return ROOTS[input]?.crypto && !isFuturesSymbol(ticker) ? null : cotContractCode(ticker);
141
+ if (ROOTS[input]?.crypto && !isFuturesSymbol(ticker)) return null;
142
+ const board = futuresBoardContractForTicker(ticker);
143
+ return rootAlias(input) ?? (board ? boardMarketCode(board) : null) ?? marketCode(input);
117
144
  }
118
- /** The verified futures root a CFTC code belongs to, for titles readers recognize. */
145
+ /** The futures root a CFTC code belongs to, for titles readers recognize: a verified alias, else its FUT board root. */
119
146
  export function cotRoot(code: string): string | null {
120
- return Object.entries(ROOTS).find(([, row]) => row.code === code)?.[0] ?? null;
147
+ return Object.entries(ROOTS).find(([, row]) => row.code === code)?.[0]
148
+ ?? FUTURES_CONTRACTS.find((contract) => boardMarketCode(contract) === code)?.code
149
+ ?? null;
121
150
  }
122
151
  export function cotPriceMapping(code: string) { return Object.values(ROOTS).find((row) => row.code === code) ?? PRICE_OVERLAYS[code] ?? null; }
123
152
  export function cotClass(family: CotFamily, value: unknown): CotClass {
@@ -0,0 +1,27 @@
1
+ import type { SeriesDefinition } from "../../../series/types";
2
+ import { fetchCotContract } from "./client";
3
+ import { COT_ROOT_OPTIONS, cotContractCode, cotNetPoints } from "./model";
4
+
5
+ /**
6
+ * Speculative (noncommercial) net positioning for each market the COT pane
7
+ * names by root, from the legacy report every market is in. The pane's other
8
+ * trader classes and markets stay in the pane.
9
+ */
10
+ export const COT_SERIES: readonly SeriesDefinition[] = COT_ROOT_OPTIONS.flatMap((option): SeriesDefinition[] => {
11
+ const code = cotContractCode(option.value);
12
+ if (!code) return [];
13
+ const market = option.label.startsWith(`${option.value} `) ? option.label.slice(option.value.length + 1) : option.label;
14
+ return [{
15
+ id: `cot:${option.value.toLowerCase()}-noncommercial-net`,
16
+ name: `${market}: noncommercial net position`,
17
+ unit: "contracts",
18
+ frequency: "weekly",
19
+ group: "Positioning",
20
+ tags: ["COT", "commitments of traders", "speculators", "net spec", option.value],
21
+ publisher: "CFTC",
22
+ load: async () => {
23
+ const payload = await fetchCotContract(code, "legacy");
24
+ return { points: cotNetPoints(payload.history, "noncommercial").map((point) => ({ date: point.date, value: point.value })) };
25
+ },
26
+ }];
27
+ });
@@ -42,9 +42,9 @@ export const cpiHeadless: HeadlessPaneDefinition<"bundle"> = {
42
42
  argument: { kind: "free-text", optional: true, placeholder: "component", description: "A component such as shelter, core, gasoline or supercore; omit for the table." },
43
43
  options: [],
44
44
  discovery: { aliases: ["CPI", "ECAN"], dataRequirements: ["Gloom Cloud US consumer price history"],
45
- limitations: ["Monthly data, published by BLS at 08:30 ET on its release schedule",
46
- "Weights and contributions are BLS's for the month; services ex shelter is computed from two BLS series",
47
- "No October 2025 index was published, so changes that need it are empty"] },
45
+ limitations: ["Monthly data, published by BLS at 08:30 ET on its release schedule.",
46
+ "Weights and contributions are BLS's for the month; services ex shelter is computed from two BLS series.",
47
+ "No October 2025 index was published, so changes that need it are empty."] },
48
48
  describe: "US consumer prices by component",
49
49
  async load(args) {
50
50
  const data = await fetchCpiBoard();