gloomberb 0.16.3 → 0.16.5

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 (820) hide show
  1. package/README.md +14 -91
  2. package/package.json +7 -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 +42 -17
  11. package/src/account/upgrade-personalization.ts +57 -0
  12. package/src/account/upgrade-tickers.ts +124 -0
  13. package/src/{plugins/builtin/cloud → account}/verification-panel.tsx +6 -6
  14. package/src/api-client/askg.ts +43 -0
  15. package/src/api-client/auth.ts +15 -0
  16. package/src/api-client/beneficial-owners.ts +4 -0
  17. package/src/api-client/chat.ts +19 -0
  18. package/src/api-client/company-kpis.ts +14 -2
  19. package/src/api-client/data.ts +58 -18
  20. package/src/api-client/earnings.ts +6 -0
  21. package/src/api-client/futures-curve.ts +56 -0
  22. package/src/api-client/index.ts +16 -1
  23. package/src/api-client/market-discovery.ts +10 -1
  24. package/src/api-client/normalizers.ts +27 -0
  25. package/src/api-client/paths.ts +95 -23
  26. package/src/api-client/request.ts +2 -1
  27. package/src/api-client/research-activity.ts +46 -10
  28. package/src/api-client/socket.ts +39 -8
  29. package/src/api-client/types.ts +74 -2
  30. package/src/api-client/upgrade-experiment.ts +90 -0
  31. package/src/api-client/yield-curves.ts +8 -0
  32. package/src/app/global-shortcuts.ts +26 -2
  33. package/src/app/keybindings/actions.ts +10 -0
  34. package/src/app/pane-runtime/index.tsx +8 -0
  35. package/src/app/pane-runtime/pane-template-runtime.ts +5 -0
  36. package/src/app/pane-runtime/plugin-bindings.ts +65 -25
  37. package/src/app/pane-runtime/ticker-inspector-runtime.ts +12 -0
  38. package/src/app/pane-runtime/ticker-open-runtime.ts +25 -4
  39. package/src/app/runtime/desktop-deeplink.ts +5 -0
  40. package/src/app/star-prompt/model.ts +98 -0
  41. package/src/app/star-prompt/runtime.ts +41 -0
  42. package/src/app/star-prompt/status-line.tsx +190 -0
  43. package/src/app.tsx +13 -7
  44. package/src/architecture/core-builtin-allowlist.json +61 -0
  45. package/src/brokers/signed-in/adapter.ts +33 -2
  46. package/src/brokers/signed-in/client.ts +10 -0
  47. package/src/brokers/signed-in/sign-in-dialog.tsx +34 -14
  48. package/src/brokers/signed-in/sign-in.ts +62 -5
  49. package/src/capabilities/chart-series.ts +11 -1
  50. package/src/capabilities/registry.ts +8 -1
  51. package/src/capabilities/types.ts +2 -0
  52. package/src/cli/commands/crypto-hints.ts +19 -4
  53. package/src/cli/commands/fred-series.ts +61 -0
  54. package/src/cli/commands/market.ts +744 -181
  55. package/src/cli/commands/news-hints.ts +62 -0
  56. package/src/cli/commands/news-search.ts +53 -0
  57. package/src/cli/commands/options-chain.ts +172 -0
  58. package/src/cli/commands/options-leaps.ts +425 -0
  59. package/src/cli/commands/overview.ts +251 -40
  60. package/src/cli/commands/remote.ts +2 -1
  61. package/src/cli/commands/search.ts +109 -15
  62. package/src/cli/commands/system.ts +151 -24
  63. package/src/cli/commands/themes.ts +64 -0
  64. package/src/cli/commands/ticker.ts +149 -40
  65. package/src/cli/context.ts +45 -14
  66. package/src/cli/desktop-pane-shot.ts +150 -17
  67. package/src/cli/earnings-calendar.ts +71 -0
  68. package/src/cli/errors.ts +25 -2
  69. package/src/cli/freshness.ts +22 -8
  70. package/src/cli/fx-pair.ts +57 -0
  71. package/src/cli/glossary.ts +429 -0
  72. package/src/cli/help.ts +14 -1
  73. package/src/cli/history-rows.ts +48 -7
  74. package/src/cli/index-roots.ts +58 -0
  75. package/src/cli/index.ts +29 -12
  76. package/src/cli/known-gaps.ts +27 -0
  77. package/src/cli/listing-arg.ts +595 -26
  78. package/src/cli/not-a-ticker.ts +44 -0
  79. package/src/cli/options.ts +50 -6
  80. package/src/cli/pane-functions/access-gate.ts +5 -0
  81. package/src/cli/pane-functions/capabilities.ts +11 -4
  82. package/src/cli/pane-functions/catalog.ts +48 -7
  83. package/src/cli/pane-functions/data.ts +48 -13
  84. package/src/cli/pane-functions/discovery.ts +1 -0
  85. package/src/cli/pane-functions/dom.ts +41 -19
  86. package/src/cli/pane-functions/freshness.ts +531 -32
  87. package/src/cli/pane-functions/function-help.ts +77 -25
  88. package/src/cli/pane-functions/headless.ts +50 -21
  89. package/src/cli/pane-functions/index.ts +66 -10
  90. package/src/cli/pane-functions/market-session.ts +147 -0
  91. package/src/cli/pane-functions/options.ts +77 -25
  92. package/src/cli/pane-functions/report-notices.ts +81 -0
  93. package/src/cli/pane-functions/report.ts +19 -8
  94. package/src/cli/pane-functions/resolver.ts +53 -18
  95. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  96. package/src/cli/pane-functions/screenshot.ts +199 -30
  97. package/src/cli/registry.ts +2 -1
  98. package/src/cli/report-tables.ts +3 -0
  99. package/src/cli/result.ts +53 -13
  100. package/src/cli/row-window.ts +76 -0
  101. package/src/cli/scroll-truncation.ts +34 -0
  102. package/src/cli/staged-tickers.ts +52 -0
  103. package/src/cli/symbol-args.ts +9 -0
  104. package/src/cli/symbol-list.ts +172 -0
  105. package/src/cli/ticker-resolution.ts +223 -30
  106. package/src/cli/types.ts +5 -0
  107. package/src/components/chart/composite/axis-overlays.tsx +6 -2
  108. package/src/components/chart/composite/composite-chart.tsx +83 -10
  109. package/src/components/chart/composite/legend.tsx +88 -8
  110. package/src/components/chart/composite/panel-surface.tsx +44 -17
  111. package/src/components/chart/composite/price-axis-labels.tsx +3 -1
  112. package/src/components/chart/composite/rasterizer.ts +64 -4
  113. package/src/components/chart/composite/series-cues.ts +71 -0
  114. package/src/components/chart/composite/text-renderer.ts +16 -8
  115. package/src/components/chart/composite/types.ts +3 -0
  116. package/src/components/command-bar/commands/direct/index.ts +9 -1
  117. package/src/components/command-bar/commands/plugin/items.ts +3 -1
  118. package/src/components/command-bar/commands/registry.ts +7 -0
  119. package/src/components/command-bar/layout-items/focused-pane.ts +38 -0
  120. package/src/components/command-bar/pane-templates/workflow.ts +5 -0
  121. package/src/components/command-bar/panel/index.tsx +11 -3
  122. package/src/components/command-bar/panel/runtime.ts +3 -0
  123. package/src/components/command-bar/panel/types.ts +2 -0
  124. package/src/components/command-bar/routes/root/command-items.ts +2 -0
  125. package/src/components/command-bar/routes/root/plugin-turn-on.ts +92 -0
  126. package/src/components/command-bar/routes/root/provider-search.ts +4 -3
  127. package/src/components/command-bar/routes/root/results.ts +40 -10
  128. package/src/components/command-bar/routes/root/runtime.ts +8 -0
  129. package/src/components/command-bar/routes/root/search-providers.ts +97 -14
  130. package/src/components/command-bar/routes/ticker-search/results.ts +12 -11
  131. package/src/components/command-bar/routes/ticker-search/route.ts +4 -3
  132. package/src/components/command-bar/surface/index.tsx +18 -4
  133. package/src/components/command-bar/theme-picker.tsx +48 -13
  134. package/src/components/command-bar/workflow/ops.ts +5 -3
  135. package/src/components/command-bar/workflow/tickers.ts +23 -4
  136. package/src/components/data-table/view.tsx +28 -9
  137. package/src/components/layout/detached-pane-shell.tsx +9 -0
  138. package/src/components/layout/floating-pane.tsx +9 -2
  139. package/src/components/layout/header.tsx +20 -5
  140. package/src/components/layout/market-summary.ts +23 -9
  141. package/src/components/layout/pane/content.tsx +40 -29
  142. package/src/components/layout/pane/cycle-order.ts +2 -11
  143. package/src/components/layout/pane/footer/index.tsx +6 -2
  144. package/src/components/layout/pane/footer/model.ts +35 -1
  145. package/src/components/layout/pane/header.tsx +26 -2
  146. package/src/components/layout/pane/index.tsx +12 -2
  147. package/src/components/layout/pane/sidebar.tsx +78 -10
  148. package/src/components/layout/pane/title.ts +1 -1
  149. package/src/components/layout/presentation.ts +22 -0
  150. package/src/components/layout/shell/active-drag.ts +21 -5
  151. package/src/components/layout/shell/drag/index.ts +43 -9
  152. package/src/components/layout/shell/drag/live.ts +87 -6
  153. package/src/components/layout/shell/drag/runtime.ts +62 -20
  154. package/src/components/layout/shell/index.tsx +71 -12
  155. package/src/components/layout/shell/layout-state.ts +5 -11
  156. package/src/components/layout/shell/menu.ts +33 -1
  157. package/src/components/layout/shell/native/pointer-runtime.ts +3 -1
  158. package/src/components/layout/shell/pane/actions.ts +2 -1
  159. package/src/components/layout/shell/pane/layers.tsx +216 -28
  160. package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
  161. package/src/components/layout/shell/pane/new-layout.ts +116 -0
  162. package/src/components/layout/shell/shortcuts.ts +5 -2
  163. package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -0
  164. package/src/components/layout/shell/visible-layout.ts +44 -1
  165. package/src/components/layout/status-bar.tsx +4 -1
  166. package/src/components/markdown-text.tsx +69 -23
  167. package/src/components/metric-treemap/heat-surface.tsx +37 -9
  168. package/src/components/metric-treemap/heat-tiles.ts +48 -17
  169. package/src/components/onboarding/account-step/form-panel.tsx +1 -1
  170. package/src/components/onboarding/account-step/index.tsx +1 -1
  171. package/src/components/onboarding/account-step/qr-panel.tsx +1 -1
  172. package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
  173. package/src/components/onboarding/onboarding-frame.tsx +33 -10
  174. package/src/components/onboarding/onboarding-keyboard.ts +1 -1
  175. package/src/components/onboarding/onboarding-wizard.tsx +50 -41
  176. package/src/components/onboarding/portfolio-step/positions-panel.tsx +5 -2
  177. package/src/components/onboarding/pro-step-layout.ts +86 -0
  178. package/src/components/onboarding/use-onboarding-upgrade.ts +8 -4
  179. package/src/components/onboarding/wizard-account.ts +2 -2
  180. package/src/components/pane-template-wizard.tsx +9 -1
  181. package/src/components/price-selector-dialog.tsx +11 -2
  182. package/src/components/sign-in-gate.tsx +3 -3
  183. package/src/components/ticker/list-table-view.tsx +24 -1
  184. package/src/components/ui/action-row.tsx +2 -1
  185. package/src/components/ui/button.tsx +17 -1
  186. package/src/components/ui/choice-dialog.tsx +6 -4
  187. package/src/components/ui/confirm-dialog.tsx +28 -18
  188. package/src/components/ui/data-table/index.tsx +49 -0
  189. package/src/components/ui/data-table/opentui/index.tsx +37 -6
  190. package/src/components/ui/data-table/types.ts +20 -1
  191. package/src/components/ui/data-table/visible-range.ts +2 -0
  192. package/src/components/ui/dialog-actions.tsx +64 -0
  193. package/src/components/ui/display.tsx +17 -3
  194. package/src/components/ui/frame.tsx +35 -2
  195. package/src/components/ui/icon.tsx +13 -2
  196. package/src/components/ui/index.ts +1 -1
  197. package/src/components/ui/text-prompt-dialog.tsx +11 -9
  198. package/src/core/connection-health.ts +1 -1
  199. package/src/core/state/app/layout-reducer.ts +89 -3
  200. package/src/core/state/app/state.ts +8 -5
  201. package/src/core/state/app/types.ts +13 -2
  202. package/src/data/cached-query.ts +2 -0
  203. package/src/data/config/layout.ts +55 -21
  204. package/src/data/config/store/fold-panes.ts +149 -0
  205. package/src/data/config/store/migrations.ts +7 -0
  206. package/src/data/config/store/node.ts +27 -6
  207. package/src/data/config/store/normalize.ts +44 -5
  208. package/src/data/ticker-repository.ts +5 -0
  209. package/src/data/ticker-store.ts +15 -0
  210. package/src/docs/content.ts +215 -0
  211. package/src/docs/load.ts +139 -0
  212. package/src/docs/requests.ts +39 -0
  213. package/src/docs/snapshot.chunk.ts +8 -0
  214. package/src/docs/snapshot.json +7416 -0
  215. package/src/docs/topics.ts +216 -0
  216. package/src/i18n/es.ts +75 -5
  217. package/src/i18n/ja.ts +75 -5
  218. package/src/i18n/ko.ts +75 -5
  219. package/src/i18n/zh-cn.ts +75 -5
  220. package/src/i18n/zh-tw.ts +75 -5
  221. package/src/layout/desks.ts +2 -3
  222. package/src/layout/pane-layout-move.ts +264 -0
  223. package/src/layout/pane-manager/dock-tree.ts +18 -0
  224. package/src/layout/pane-manager/hidden-panes.ts +160 -0
  225. package/src/layout/pane-manager/index.ts +2 -0
  226. package/src/market-data/coordinator/chart.ts +10 -4
  227. package/src/market-data/coordinator/entries.ts +7 -1
  228. package/src/market-data/coordinator/index.ts +6 -3
  229. package/src/market-data/coordinator/quotes.ts +2 -2
  230. package/src/{plugins/builtin/futures/contracts.ts → market-data/futures-board.ts} +81 -28
  231. package/src/market-data/futures-contract.ts +151 -0
  232. package/src/market-data/hooks.tsx +10 -2
  233. package/src/market-data/market/format.ts +39 -21
  234. package/src/market-data/market/freshness.ts +193 -30
  235. package/src/market-data/market/status.ts +59 -23
  236. package/src/market-data/options-alternatives.ts +69 -0
  237. package/src/market-data/published-apac-sessions.ts +23 -1
  238. package/src/market-data/quotes/contributions.ts +22 -2
  239. package/src/market-data/quotes/metadata.ts +8 -9
  240. package/src/market-data/quotes/resolution.ts +2 -0
  241. package/src/market-data/quotes/screener-live-quotes.ts +61 -9
  242. package/src/market-data/result-types.ts +2 -0
  243. package/src/plugins/builtin/account-management/keyboard.ts +3 -0
  244. package/src/plugins/builtin/account-management/model.ts +2 -56
  245. package/src/plugins/builtin/account-management/navigation.ts +1 -1
  246. package/src/plugins/builtin/account-management/pane.tsx +37 -8
  247. package/src/plugins/builtin/account-management/password-dialog.tsx +1 -1
  248. package/src/plugins/builtin/alerts/cli.ts +313 -47
  249. package/src/plugins/builtin/alerts/events-pane.tsx +45 -7
  250. package/src/plugins/builtin/alerts/events.ts +23 -2
  251. package/src/plugins/builtin/alerts/history-pane.tsx +7 -2
  252. package/src/plugins/builtin/alerts/history.ts +2 -0
  253. package/src/plugins/builtin/alerts/index.tsx +41 -9
  254. package/src/plugins/builtin/alerts/pane.tsx +8 -0
  255. package/src/plugins/builtin/alerts/quotes.ts +3 -0
  256. package/src/plugins/builtin/alerts/research-builder.ts +8 -3
  257. package/src/plugins/builtin/alerts/research-rules.ts +18 -2
  258. package/src/plugins/builtin/alerts/scheduled-check.ts +122 -0
  259. package/src/plugins/builtin/alerts/scheduled-sources.ts +25 -0
  260. package/src/plugins/builtin/alerts/scheduled.ts +254 -0
  261. package/src/plugins/builtin/alerts/targets.ts +92 -0
  262. package/src/plugins/builtin/analytics/index.tsx +4 -2
  263. package/src/plugins/builtin/analytics/risk-headless.ts +33 -13
  264. package/src/plugins/builtin/analytics/risk-math.ts +91 -27
  265. package/src/plugins/builtin/analytics/risk-model.ts +71 -12
  266. package/src/plugins/builtin/analytics/risk-pane.tsx +23 -12
  267. package/src/plugins/builtin/attention/index.tsx +2 -0
  268. package/src/plugins/builtin/attention/pane.tsx +3 -1
  269. package/src/plugins/builtin/attention/series.ts +26 -0
  270. package/src/plugins/builtin/awards/index.tsx +2 -0
  271. package/src/plugins/builtin/awards/pane.tsx +3 -1
  272. package/src/plugins/builtin/awards/series.ts +29 -0
  273. package/src/plugins/builtin/backtest/pane.tsx +1 -1
  274. package/src/plugins/builtin/bond-calculator/model.ts +2 -1
  275. package/src/plugins/builtin/broker-manager/detail.tsx +4 -0
  276. package/src/plugins/builtin/broker-manager/index.tsx +7 -3
  277. package/src/plugins/builtin/broker-manager/model.ts +8 -0
  278. package/src/plugins/builtin/broker-manager/pane-actions.tsx +8 -2
  279. package/src/plugins/builtin/broker-manager/sign-in-end.ts +82 -0
  280. package/src/plugins/builtin/broker-manager/table.ts +5 -0
  281. package/src/plugins/builtin/builtin-plugin-meta.ts +121 -11
  282. package/src/plugins/builtin/catalysts/pane.tsx +3 -1
  283. package/src/plugins/builtin/cds/client.ts +70 -13
  284. package/src/plugins/builtin/cds/headless.ts +116 -19
  285. package/src/plugins/builtin/cds/index.tsx +3 -1
  286. package/src/plugins/builtin/cds/model.ts +193 -31
  287. package/src/plugins/builtin/cds/pane.tsx +56 -14
  288. package/src/plugins/builtin/cds/series.ts +19 -0
  289. package/src/plugins/builtin/central-bank-rates/index.tsx +2 -0
  290. package/src/plugins/builtin/central-bank-rates/series.ts +42 -0
  291. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +192 -255
  292. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +84 -46
  293. package/src/plugins/builtin/chart-composer/editor.tsx +5 -4
  294. package/src/plugins/builtin/chart-composer/field-series.ts +40 -0
  295. package/src/plugins/builtin/chart-composer/headless.ts +8 -3
  296. package/src/plugins/builtin/chart-composer/index.tsx +9 -2
  297. package/src/plugins/builtin/chart-composer/pane.tsx +1 -1
  298. package/src/plugins/builtin/chart-composer/series-catalog.ts +58 -50
  299. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -10
  300. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +59 -3
  301. package/src/plugins/builtin/chart-composer/user-series.ts +84 -0
  302. package/src/plugins/builtin/chat/channels.ts +34 -36
  303. package/src/plugins/builtin/chat/command-bar.ts +138 -0
  304. package/src/plugins/builtin/chat/composer-commands.ts +21 -1
  305. package/src/plugins/builtin/chat/content/composer-runtime.ts +11 -1
  306. package/src/plugins/builtin/chat/content/footer.tsx +5 -3
  307. package/src/plugins/builtin/chat/content/index.tsx +21 -1
  308. package/src/plugins/builtin/chat/content/mentions.ts +2 -1
  309. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +10 -2
  310. package/src/plugins/builtin/chat/content/user-map.ts +3 -1
  311. package/src/plugins/builtin/chat/controller/index.ts +50 -0
  312. package/src/plugins/builtin/chat/conversations.ts +256 -0
  313. package/src/plugins/builtin/chat/discord-command.ts +91 -0
  314. package/src/plugins/builtin/chat/edit-window.ts +12 -6
  315. package/src/plugins/builtin/chat/ghost-user.ts +14 -0
  316. package/src/plugins/builtin/chat/index.tsx +40 -2
  317. package/src/plugins/builtin/chat/layout.ts +2 -0
  318. package/src/plugins/builtin/chat/message/desktop.tsx +2 -1
  319. package/src/plugins/builtin/chat/message/header.tsx +24 -15
  320. package/src/plugins/builtin/chat/message/profile-popover.tsx +2 -1
  321. package/src/plugins/builtin/chat/message/render-state.ts +3 -0
  322. package/src/plugins/builtin/chat/pane-requests.ts +60 -0
  323. package/src/plugins/builtin/chat/pane-state.ts +32 -2
  324. package/src/plugins/builtin/chat/pane.tsx +8 -0
  325. package/src/plugins/builtin/cloud/askg/controller.ts +223 -23
  326. package/src/plugins/builtin/cloud/askg/conversation-store.ts +21 -0
  327. package/src/plugins/builtin/cloud/askg/executor.ts +57 -3
  328. package/src/plugins/builtin/cloud/askg/manifest.ts +33 -7
  329. package/src/plugins/builtin/cloud/askg/model.ts +156 -78
  330. package/src/plugins/builtin/cloud/askg/pane.tsx +772 -377
  331. package/src/plugins/builtin/cloud/askg/protocol.ts +50 -3
  332. package/src/plugins/builtin/cloud/askg/tool-display.ts +440 -0
  333. package/src/plugins/builtin/cloud/askg/tool-timeline.tsx +403 -0
  334. package/src/plugins/builtin/cloud/askg/undo.ts +2 -0
  335. package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
  336. package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
  337. package/src/plugins/builtin/cloud/auth-dialog.tsx +3 -3
  338. package/src/plugins/builtin/cloud/company-picker.tsx +1 -9
  339. package/src/plugins/builtin/cloud/mcp-connect/command.ts +24 -0
  340. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +363 -0
  341. package/src/plugins/builtin/cloud/mcp-connect/model.ts +135 -0
  342. package/src/plugins/builtin/cloud/mcp-connect/sections.ts +62 -0
  343. package/src/plugins/builtin/cloud/plugin.tsx +36 -1
  344. package/src/plugins/builtin/cloud/terminal-relay/acm-tab.tsx +89 -0
  345. package/src/plugins/builtin/cloud/terminal-relay/client.ts +97 -0
  346. package/src/plugins/builtin/cloud/terminal-relay/connect-section.tsx +57 -0
  347. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +734 -0
  348. package/src/plugins/builtin/cloud/terminal-relay/grants.ts +137 -0
  349. package/src/plugins/builtin/cloud/terminal-relay/host.tsx +81 -0
  350. package/src/plugins/builtin/cloud/terminal-relay/indicator.tsx +82 -0
  351. package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +239 -0
  352. package/src/plugins/builtin/cloud/terminal-relay/policy.ts +162 -0
  353. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +192 -0
  354. package/src/plugins/builtin/cloud/terminal-relay/redact.ts +73 -0
  355. package/src/plugins/builtin/cloud/terminal-relay/summary.ts +62 -0
  356. package/src/plugins/builtin/cloud/thesis/exposure.ts +1 -1
  357. package/src/plugins/builtin/cloud/thesis/prompts.tsx +2 -1
  358. package/src/plugins/builtin/comment-letters/client.ts +1 -3
  359. package/src/plugins/builtin/company-attention/app-rank.tsx +1 -1
  360. package/src/plugins/builtin/company-attention/headless.ts +19 -5
  361. package/src/plugins/builtin/company-attention/index.tsx +2 -0
  362. package/src/plugins/builtin/company-attention/model.ts +26 -7
  363. package/src/plugins/builtin/company-attention/pane.tsx +12 -9
  364. package/src/plugins/builtin/company-attention/series.ts +52 -0
  365. package/src/plugins/builtin/company-kpis/client.ts +23 -8
  366. package/src/plugins/builtin/company-kpis/headless.ts +3 -1
  367. package/src/plugins/builtin/company-kpis/pane.tsx +19 -9
  368. package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +10 -3
  369. package/src/plugins/builtin/composite-plugins.ts +116 -67
  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/credit-boards/cdx-pane.tsx +4 -4
  374. package/src/plugins/builtin/credit-boards/index.tsx +23 -21
  375. package/src/plugins/builtin/credit-boards/model.ts +0 -1
  376. package/src/plugins/builtin/credit-boards/pane.tsx +30 -0
  377. package/src/plugins/builtin/credit-boards/series.ts +66 -0
  378. package/src/plugins/builtin/credit-boards/sovr-pane.tsx +4 -4
  379. package/src/plugins/builtin/credit-conditions/index.tsx +2 -0
  380. package/src/plugins/builtin/credit-conditions/series.ts +26 -0
  381. package/src/plugins/builtin/credit-documents/headless.ts +31 -1
  382. package/src/plugins/builtin/credit-documents/pane.tsx +3 -1
  383. package/src/plugins/builtin/crypto-board/headless.ts +2 -3
  384. package/src/plugins/builtin/crypto-board/index.tsx +2 -0
  385. package/src/plugins/builtin/crypto-board/model.ts +12 -0
  386. package/src/plugins/builtin/crypto-board/pane.tsx +19 -12
  387. package/src/plugins/builtin/crypto-board/series.ts +48 -0
  388. package/src/plugins/builtin/custom-view/live-quotes.ts +2 -2
  389. package/src/plugins/builtin/debt-maturities/client.ts +37 -9
  390. package/src/plugins/builtin/debt-maturities/headless.ts +3 -1
  391. package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
  392. package/src/plugins/builtin/debt-maturities/pane.tsx +5 -4
  393. package/src/plugins/builtin/debt-maturities/series.ts +45 -0
  394. package/src/plugins/builtin/dividend-yield/headless.ts +2 -2
  395. package/src/plugins/builtin/dividend-yield/index.tsx +3 -1
  396. package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
  397. package/src/plugins/builtin/dividend-yield/series.ts +20 -0
  398. package/src/plugins/builtin/docs/blocks.tsx +181 -0
  399. package/src/plugins/builtin/docs/index.tsx +68 -0
  400. package/src/plugins/builtin/docs/pane.tsx +426 -0
  401. package/src/plugins/builtin/docs/targets.ts +72 -0
  402. package/src/plugins/builtin/docs/use-docs.ts +60 -0
  403. package/src/plugins/builtin/doe/index.tsx +2 -0
  404. package/src/plugins/builtin/doe/series.ts +62 -0
  405. package/src/plugins/builtin/earnings/client.ts +3 -2
  406. package/src/plugins/builtin/earnings/format.ts +1 -5
  407. package/src/plugins/builtin/earnings/headless.ts +58 -6
  408. package/src/plugins/builtin/earnings/history-model.ts +15 -1
  409. package/src/plugins/builtin/earnings/history-table.ts +13 -2
  410. package/src/plugins/builtin/earnings/history.tsx +7 -3
  411. package/src/plugins/builtin/earnings-calls/data.ts +28 -7
  412. package/src/plugins/builtin/earnings-calls/headless.ts +3 -2
  413. package/src/plugins/builtin/earnings-calls/pane.tsx +10 -5
  414. package/src/plugins/builtin/econ/calendar-model.ts +42 -17
  415. package/src/plugins/builtin/econ/detail-view.tsx +2 -2
  416. package/src/plugins/builtin/econ/fred-catalog.ts +189 -0
  417. package/src/plugins/builtin/econ/fred-series-map.ts +0 -46
  418. package/src/plugins/builtin/econ/index.tsx +70 -22
  419. package/src/plugins/builtin/econ-statistics/defs.ts +5 -0
  420. package/src/plugins/builtin/econ-statistics/headless.ts +30 -5
  421. package/src/plugins/builtin/econ-statistics/pane.tsx +1 -1
  422. package/src/plugins/builtin/econ-statistics/stats.ts +1 -0
  423. package/src/plugins/builtin/econ-statistics/view.ts +17 -0
  424. package/src/plugins/builtin/equity-screener/pane.tsx +4 -11
  425. package/src/plugins/builtin/executives/data.ts +17 -6
  426. package/src/plugins/builtin/executives/pane.tsx +16 -7
  427. package/src/plugins/builtin/exposure/holdings.ts +1 -1
  428. package/src/plugins/builtin/exposure/pane.tsx +3 -1
  429. package/src/plugins/builtin/fear-greed/index.tsx +4 -0
  430. package/src/plugins/builtin/fear-greed/series.ts +52 -0
  431. package/src/plugins/builtin/filing-events/pane.tsx +22 -5
  432. package/src/plugins/builtin/futures/index.tsx +43 -3
  433. package/src/plugins/builtin/futures/model.ts +1 -1
  434. package/src/plugins/builtin/futures/returns.ts +1 -1
  435. package/src/plugins/builtin/futures/series.ts +13 -0
  436. package/src/plugins/builtin/futures/table.tsx +1 -1
  437. package/src/plugins/builtin/futures/use-front-returns.ts +1 -1
  438. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  439. package/src/plugins/builtin/futures-curve/headless.ts +70 -9
  440. package/src/plugins/builtin/futures-curve/index.tsx +1 -1
  441. package/src/plugins/builtin/futures-curve/model.ts +66 -11
  442. package/src/plugins/builtin/futures-curve/pane.tsx +52 -18
  443. package/src/plugins/builtin/fx-matrix/index.tsx +22 -1
  444. package/src/plugins/builtin/fx-matrix/pairs.ts +1 -1
  445. package/src/plugins/builtin/fx-matrix/settings.ts +42 -2
  446. package/src/plugins/builtin/gpu/board.tsx +13 -10
  447. package/src/plugins/builtin/gpu/changes.tsx +4 -4
  448. package/src/plugins/builtin/gpu/client.ts +19 -1
  449. package/src/plugins/builtin/gpu/equities.tsx +14 -10
  450. package/src/plugins/builtin/gpu/headless.ts +64 -27
  451. package/src/plugins/builtin/gpu/history.tsx +3 -3
  452. package/src/plugins/builtin/gpu/index.tsx +2 -0
  453. package/src/plugins/builtin/gpu/model.ts +114 -20
  454. package/src/plugins/builtin/gpu/pane.tsx +28 -12
  455. package/src/plugins/builtin/gpu/series.ts +38 -0
  456. package/src/plugins/builtin/help/function-card.tsx +25 -6
  457. package/src/plugins/builtin/help/index.tsx +18 -8
  458. package/src/plugins/builtin/holders/beneficial-client.ts +29 -7
  459. package/src/plugins/builtin/holders/beneficial-model.ts +90 -3
  460. package/src/plugins/builtin/holders/beneficial-report.ts +57 -5
  461. package/src/plugins/builtin/holders/beneficial-view.tsx +62 -14
  462. package/src/plugins/builtin/holders/client.ts +22 -3
  463. package/src/plugins/builtin/holders/format.ts +18 -3
  464. package/src/plugins/builtin/holders/headless.ts +42 -134
  465. package/src/plugins/builtin/holders/pane.tsx +14 -4
  466. package/src/plugins/builtin/holders/report-header.ts +40 -5
  467. package/src/plugins/builtin/holders/report-rows.ts +240 -0
  468. package/src/plugins/builtin/insider/client.ts +35 -20
  469. package/src/plugins/builtin/insider/headless.ts +41 -11
  470. package/src/plugins/builtin/insider/index.tsx +27 -10
  471. package/src/plugins/builtin/insider/insider-data.ts +10 -0
  472. package/src/plugins/builtin/insider/issuer.ts +49 -0
  473. package/src/plugins/builtin/insider/model.ts +3 -0
  474. package/src/plugins/builtin/iv-history/charts.tsx +21 -7
  475. package/src/plugins/builtin/iv-history/client.ts +26 -6
  476. package/src/plugins/builtin/iv-history/format.ts +33 -2
  477. package/src/plugins/builtin/iv-history/headless.ts +27 -12
  478. package/src/plugins/builtin/iv-history/index.tsx +5 -3
  479. package/src/plugins/builtin/iv-history/model.ts +172 -20
  480. package/src/plugins/builtin/iv-history/pane.tsx +11 -3
  481. package/src/plugins/builtin/iv-history/screen-pane.tsx +45 -25
  482. package/src/plugins/builtin/iv-history/series.ts +29 -0
  483. package/src/plugins/builtin/jobs/headless.ts +28 -3
  484. package/src/plugins/builtin/jobs/index.tsx +3 -1
  485. package/src/plugins/builtin/jobs/pane.tsx +1 -1
  486. package/src/plugins/builtin/jobs/series.ts +19 -0
  487. package/src/plugins/builtin/kelly-sizer/headless.ts +149 -0
  488. package/src/plugins/builtin/kelly-sizer/history.ts +80 -0
  489. package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
  490. package/src/plugins/builtin/kelly-sizer/pane.tsx +111 -40
  491. package/src/plugins/builtin/kelly-sizer/portfolio.ts +0 -39
  492. package/src/plugins/builtin/kelly-sizer/sections.tsx +14 -0
  493. package/src/plugins/builtin/kelly-sizer/types.ts +9 -1
  494. package/src/plugins/builtin/layout-manager/index.tsx +9 -1
  495. package/src/plugins/builtin/macro-day/client.ts +68 -3
  496. package/src/plugins/builtin/macro-day/headless.ts +18 -12
  497. package/src/plugins/builtin/macro-day/index.tsx +3 -0
  498. package/src/plugins/builtin/macro-day/model.ts +66 -15
  499. package/src/plugins/builtin/macro-day/pane.tsx +34 -20
  500. package/src/plugins/builtin/macro-day/release-table.ts +40 -0
  501. package/src/plugins/builtin/macro-day/releases.ts +62 -44
  502. package/src/plugins/builtin/market-heatmap/data.ts +25 -5
  503. package/src/plugins/builtin/market-heatmap/evidence.ts +90 -0
  504. package/src/plugins/builtin/market-heatmap/index.tsx +144 -63
  505. package/src/plugins/builtin/market-heatmap/model.ts +102 -3
  506. package/src/plugins/builtin/market-heatmap/portfolio.ts +12 -2
  507. package/src/plugins/builtin/market-movers/client.ts +7 -5
  508. package/src/plugins/builtin/market-movers/headless.ts +31 -4
  509. package/src/plugins/builtin/market-movers/index.tsx +11 -3
  510. package/src/plugins/builtin/market-movers/model.ts +101 -17
  511. package/src/plugins/builtin/market-movers/screener.ts +31 -0
  512. package/src/plugins/builtin/market-movers/table.ts +50 -23
  513. package/src/plugins/builtin/market-valuation/chart-series.ts +29 -69
  514. package/src/plugins/builtin/market-valuation/index.tsx +3 -3
  515. package/src/plugins/builtin/market-valuation/indicators.ts +0 -5
  516. package/src/plugins/builtin/members/headless.ts +7 -2
  517. package/src/plugins/builtin/members/model.ts +31 -3
  518. package/src/plugins/builtin/members/pane.tsx +3 -6
  519. package/src/plugins/builtin/mna/headless.ts +15 -3
  520. package/src/plugins/builtin/money-markets/index.tsx +2 -0
  521. package/src/plugins/builtin/money-markets/series.ts +41 -0
  522. package/src/plugins/builtin/news/headless.ts +9 -2
  523. package/src/plugins/builtin/news/wire/news/footer.ts +10 -0
  524. package/src/plugins/builtin/notes/cli.ts +12 -7
  525. package/src/plugins/builtin/openfda/client.ts +1 -1
  526. package/src/plugins/builtin/options/carry.ts +95 -0
  527. package/src/plugins/builtin/options/index.tsx +58 -5
  528. package/src/plugins/builtin/options/strike-window.ts +183 -0
  529. package/src/plugins/builtin/options/table.ts +55 -3
  530. package/src/plugins/builtin/options/types.ts +8 -1
  531. package/src/plugins/builtin/options/view.tsx +162 -13
  532. package/src/plugins/builtin/options-calculator/inputs.ts +2 -1
  533. package/src/plugins/builtin/options-positioning/client.ts +7 -3
  534. package/src/plugins/builtin/options-positioning/headless.ts +5 -2
  535. package/src/plugins/builtin/options-positioning/pane.tsx +2 -2
  536. package/src/plugins/builtin/options-scenario/charts.tsx +2 -2
  537. package/src/plugins/builtin/options-scenario/client.ts +75 -18
  538. package/src/plugins/builtin/options-scenario/headless.ts +72 -24
  539. package/src/plugins/builtin/options-scenario/hedge.ts +285 -0
  540. package/src/plugins/builtin/options-scenario/index.tsx +9 -2
  541. package/src/plugins/builtin/options-scenario/model.ts +33 -0
  542. package/src/plugins/builtin/options-scenario/pane.tsx +40 -16
  543. package/src/plugins/builtin/pe-band/model.ts +2 -2
  544. package/src/plugins/builtin/pe-band/report-dates.ts +11 -7
  545. package/src/plugins/builtin/perps/client.ts +40 -6
  546. package/src/plugins/builtin/perps/equity-row.tsx +33 -8
  547. package/src/plugins/builtin/perps/freshness.ts +66 -0
  548. package/src/plugins/builtin/perps/headless.ts +45 -30
  549. package/src/plugins/builtin/perps/index.tsx +18 -1
  550. package/src/plugins/builtin/perps/model.ts +32 -6
  551. package/src/plugins/builtin/perps/pane.tsx +76 -20
  552. package/src/plugins/builtin/perps/series.ts +76 -0
  553. package/src/plugins/builtin/plugin-marketplace/model.ts +64 -21
  554. package/src/plugins/builtin/plugin-marketplace/packs.ts +118 -0
  555. package/src/plugins/builtin/plugin-marketplace/pane.tsx +357 -39
  556. package/src/plugins/builtin/plugin-marketplace/store.ts +7 -1
  557. package/src/plugins/builtin/plugin-module.ts +90 -4
  558. package/src/plugins/builtin/portfolio-list/account-metrics.ts +1 -1
  559. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +273 -0
  560. package/src/plugins/builtin/portfolio-list/cli/import-13f.ts +109 -0
  561. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +400 -99
  562. package/src/plugins/builtin/portfolio-list/cli/render.ts +281 -43
  563. package/src/plugins/builtin/portfolio-list/cli/shared.ts +26 -16
  564. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +120 -47
  565. package/src/plugins/builtin/portfolio-list/column-values.ts +1 -1
  566. package/src/plugins/builtin/portfolio-list/grid.tsx +1 -1
  567. package/src/plugins/builtin/portfolio-list/headless.ts +70 -9
  568. package/src/plugins/builtin/portfolio-list/imported-from.ts +8 -0
  569. package/src/plugins/builtin/portfolio-list/live-valuation.ts +6 -2
  570. package/src/plugins/builtin/portfolio-list/pane/index.tsx +6 -1
  571. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +17 -1
  572. package/src/plugins/builtin/portfolio-list/summary/totals.ts +1 -1
  573. package/src/plugins/builtin/portfolio-list/table.tsx +7 -1
  574. package/src/plugins/builtin/power/client.ts +16 -0
  575. package/src/plugins/builtin/power/evidence.ts +6 -2
  576. package/src/plugins/builtin/power/headless.ts +71 -7
  577. package/src/plugins/builtin/power/index.tsx +4 -1
  578. package/src/plugins/builtin/power/model.ts +72 -1
  579. package/src/plugins/builtin/power/pane.tsx +32 -9
  580. package/src/plugins/builtin/rate-path/headless.ts +11 -3
  581. package/src/plugins/builtin/realized-vol/headless.ts +8 -0
  582. package/src/plugins/builtin/realized-vol/pane.tsx +1 -1
  583. package/src/plugins/builtin/research/corporate-actions-pane.tsx +7 -4
  584. package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +1 -1
  585. package/src/plugins/builtin/research/event-model.ts +68 -24
  586. package/src/plugins/builtin/research/events-headless.ts +2 -1
  587. package/src/plugins/builtin/research/headless.ts +2 -1
  588. package/src/plugins/builtin/revenue-breakdown/client.ts +13 -6
  589. package/src/plugins/builtin/revenue-breakdown/headless.ts +4 -1
  590. package/src/plugins/builtin/revenue-breakdown/pane.tsx +7 -4
  591. package/src/plugins/builtin/reverse-dcf/headless.ts +5 -1
  592. package/src/plugins/builtin/reverse-dcf/pane.tsx +1 -1
  593. package/src/plugins/builtin/risk-factors/data.ts +23 -9
  594. package/src/plugins/builtin/risk-factors/headless.ts +5 -2
  595. package/src/plugins/builtin/risk-factors/pane.tsx +6 -5
  596. package/src/plugins/builtin/seasonality/client.ts +15 -7
  597. package/src/plugins/builtin/seasonality/headless.ts +36 -12
  598. package/src/plugins/builtin/seasonality/index.tsx +2 -2
  599. package/src/plugins/builtin/seasonality/model.ts +119 -0
  600. package/src/plugins/builtin/seasonality/pane.tsx +108 -37
  601. package/src/plugins/builtin/sec/index.tsx +5 -5
  602. package/src/plugins/builtin/sectors/client.ts +10 -2
  603. package/src/plugins/builtin/sectors/headless.ts +35 -6
  604. package/src/plugins/builtin/sectors/index.tsx +18 -1
  605. package/src/plugins/builtin/sectors/sector-model.ts +150 -41
  606. package/src/plugins/builtin/series-inventory.ts +91 -0
  607. package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -1
  608. package/src/plugins/builtin/shared/command-tab.ts +69 -0
  609. package/src/plugins/builtin/shared/earnings-report.ts +55 -0
  610. package/src/plugins/builtin/shared/fred-points.ts +20 -0
  611. package/src/plugins/builtin/shared/fx-rate-freshness.ts +101 -0
  612. package/src/plugins/builtin/shared/headless-market-data.ts +33 -1
  613. package/src/plugins/builtin/shared/members-menu.tsx +4 -4
  614. package/src/plugins/builtin/shared/open-description.ts +29 -0
  615. package/src/plugins/builtin/shared/report-freshness.ts +59 -2
  616. package/src/plugins/builtin/shared/series-warning.ts +5 -0
  617. package/src/plugins/builtin/shared/ticker-request.ts +25 -1
  618. package/src/plugins/builtin/shared/use-quote-board.ts +25 -5
  619. package/src/plugins/builtin/shared/volatility/options.ts +1 -46
  620. package/src/plugins/builtin/short-interest/headless.ts +1 -0
  621. package/src/plugins/builtin/short-interest/index.tsx +21 -4
  622. package/src/plugins/builtin/short-interest/series.ts +36 -0
  623. package/src/plugins/builtin/short-interest/surface.tsx +4 -4
  624. package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
  625. package/src/plugins/builtin/short-interest/watch-model.ts +9 -5
  626. package/src/plugins/builtin/short-volume/headless.ts +1 -0
  627. package/src/plugins/builtin/short-volume/index.tsx +3 -10
  628. package/src/plugins/builtin/short-volume/series.ts +23 -0
  629. package/src/plugins/builtin/social-mentions/index.tsx +2 -0
  630. package/src/plugins/builtin/social-mentions/series.ts +23 -0
  631. package/src/plugins/builtin/supply-chain/graph-pane.tsx +3 -2
  632. package/src/plugins/builtin/supply-chain/model.ts +1 -1
  633. package/src/plugins/builtin/supply-chain/pane.tsx +3 -1
  634. package/src/plugins/builtin/thirteenf/api.ts +1 -0
  635. package/src/plugins/builtin/thirteenf/data.ts +6 -4
  636. package/src/plugins/builtin/thirteenf/headless.ts +217 -36
  637. package/src/plugins/builtin/thirteenf/model.ts +39 -1
  638. package/src/plugins/builtin/thirteenf/overlap.ts +75 -0
  639. package/src/plugins/builtin/thirteenf/pane.tsx +10 -1
  640. package/src/plugins/builtin/thirteenf/report-notes.ts +103 -1
  641. package/src/plugins/builtin/thirteenf/types.ts +2 -0
  642. package/src/plugins/builtin/ticker-detail/headless.ts +43 -21
  643. package/src/plugins/builtin/ticker-detail/index.tsx +3 -0
  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 +48 -4
  649. package/src/plugins/builtin/ticker-detail/pane.tsx +4 -5
  650. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +94 -6
  651. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +13 -3
  652. package/src/plugins/builtin/time-sales/headless.ts +1 -0
  653. package/src/plugins/builtin/treasury-auctions/cache.ts +5 -2
  654. package/src/plugins/builtin/treasury-auctions/client.ts +22 -8
  655. package/src/plugins/builtin/treasury-auctions/headless.ts +56 -6
  656. package/src/plugins/builtin/treasury-auctions/index.tsx +12 -9
  657. package/src/plugins/builtin/treasury-auctions/model.ts +205 -30
  658. package/src/plugins/builtin/treasury-auctions/pane.tsx +35 -11
  659. package/src/plugins/builtin/treasury-auctions/types.ts +11 -1
  660. package/src/plugins/builtin/vol-surface/charts.tsx +1 -3
  661. package/src/plugins/builtin/vol-surface/client.ts +6 -2
  662. package/src/plugins/builtin/vol-surface/evidence.ts +11 -6
  663. package/src/plugins/builtin/vol-surface/headless.ts +125 -20
  664. package/src/plugins/builtin/vol-surface/model.ts +23 -11
  665. package/src/plugins/builtin/vol-surface/pane.tsx +38 -27
  666. package/src/plugins/builtin/vol-surface/tables.ts +124 -0
  667. package/src/plugins/builtin/volatility/index.tsx +2 -0
  668. package/src/plugins/builtin/volatility/series.ts +84 -0
  669. package/src/plugins/builtin/world-indices/client.ts +22 -4
  670. package/src/plugins/builtin/world-indices/headless.ts +54 -27
  671. package/src/plugins/builtin/world-indices/model.ts +4 -2
  672. package/src/plugins/builtin/world-indices/table.tsx +13 -2
  673. package/src/plugins/builtin/world-venue-map/geo-series.ts +27 -2
  674. package/src/plugins/builtin/world-venue-map/headless.ts +4 -1
  675. package/src/plugins/builtin/world-venue-map/index.ts +3 -2
  676. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +8 -4
  677. package/src/plugins/builtin/world-venue-map/layers.ts +29 -0
  678. package/src/plugins/builtin/yield-curve/chart.ts +2 -2
  679. package/src/plugins/builtin/yield-curve/curves.ts +21 -8
  680. package/src/plugins/builtin/yield-curve/headless.ts +71 -18
  681. package/src/plugins/builtin/yield-curve/index.tsx +4 -2
  682. package/src/plugins/builtin/yield-curve/series.ts +86 -0
  683. package/src/plugins/builtin-editorial.ts +126 -0
  684. package/src/plugins/catalog-backend.ts +16 -9
  685. package/src/plugins/catalog-browser.ts +129 -64
  686. package/src/plugins/catalog-manifest.ts +73 -40
  687. package/src/plugins/catalog-ui.ts +26 -6
  688. package/src/plugins/extracted-plugins.ts +7 -1
  689. package/src/plugins/ownership.ts +150 -7
  690. package/src/plugins/plugin-functions.ts +54 -0
  691. package/src/plugins/plugin-off.ts +36 -0
  692. package/src/plugins/registry/host-actions.ts +16 -0
  693. package/src/plugins/registry/index.ts +173 -28
  694. package/src/plugins/registry/plugin-state.ts +25 -1
  695. package/src/plugins/runtime/context.tsx +29 -0
  696. package/src/{plugins/builtin/portfolio-list → portfolio}/position-metrics.ts +6 -6
  697. package/src/portfolio/position-value.ts +40 -0
  698. package/src/public/__snapshots__/public-api.test.ts.snap +7 -0
  699. package/src/public/time-series.ts +17 -0
  700. package/src/react/auto-refresh.ts +13 -3
  701. package/src/react/input.ts +48 -1
  702. package/src/remote/app-host.tsx +25 -4
  703. package/src/remote/confirm-change.tsx +85 -0
  704. package/src/remote/controller-utils.ts +8 -1
  705. package/src/remote/controller.ts +126 -59
  706. package/src/remote/matching.ts +69 -0
  707. package/src/remote/pane-screenshot.ts +47 -0
  708. package/src/remote/schema.ts +63 -1
  709. package/src/remote/semantic-tree.tsx +14 -0
  710. package/src/remote/types.ts +32 -0
  711. package/src/remote/watchlist.ts +306 -0
  712. package/src/renderers/browser/main.tsx +3 -2
  713. package/src/renderers/cloudflare/worker.ts +1 -1
  714. package/src/renderers/dom/data-table/frozen-column.ts +3 -1
  715. package/src/renderers/dom/data-table/index.tsx +33 -6
  716. package/src/renderers/dom/data-table/row.tsx +27 -1
  717. package/src/renderers/dom/desktop/control-styles.ts +63 -1
  718. package/src/renderers/dom/desktop/controls.tsx +30 -23
  719. package/src/renderers/dom/desktop/dialog-actions.tsx +170 -0
  720. package/src/renderers/dom/desktop/icons.tsx +21 -0
  721. package/src/renderers/dom/desktop/query-bar.tsx +59 -32
  722. package/src/renderers/dom/dom-ui-host.tsx +3 -0
  723. package/src/renderers/dom/host/box.tsx +4 -1
  724. package/src/renderers/dom/host/chart-surface.tsx +6 -2
  725. package/src/renderers/dom/host/drag-shield.ts +17 -6
  726. package/src/renderers/dom/host/live-frame.ts +14 -2
  727. package/src/renderers/dom/host/overflow-fade.ts +14 -1
  728. package/src/renderers/dom/host/size-observer.ts +26 -0
  729. package/src/renderers/dom/host/surface-3d.tsx +7 -2
  730. package/src/renderers/dom/host/text.tsx +1 -1
  731. package/src/renderers/dom/input-host.tsx +6 -1
  732. package/src/renderers/dom/styles.css +74 -0
  733. package/src/renderers/electrobun/bun/desktop/backend.ts +5 -1
  734. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
  735. package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -1
  736. package/src/renderers/electrobun/shared/protocol.ts +2 -0
  737. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +18 -3
  738. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +109 -5
  739. package/src/renderers/electrobun/view/cli-pane-shot-health.ts +10 -26
  740. package/src/renderers/electrobun/view/main.tsx +6 -1
  741. package/src/renderers/opentui/input-host.tsx +6 -1
  742. package/src/renderers/opentui/start.tsx +9 -0
  743. package/src/series/capability.ts +75 -0
  744. package/src/series/csv.ts +160 -0
  745. package/src/series/files.ts +107 -0
  746. package/src/series/registry.ts +198 -0
  747. package/src/series/resolve.ts +107 -0
  748. package/src/series/standalone.ts +48 -0
  749. package/src/series/types.ts +145 -0
  750. package/src/series/validate.ts +171 -0
  751. package/src/shares/portable-layout.ts +16 -6
  752. package/src/sources/gloomberb-cloud/index.ts +26 -17
  753. package/src/sources/gloomberb-cloud/normalizers.ts +5 -1
  754. package/src/sources/history-result.ts +1 -0
  755. package/src/sources/listing-symbols.ts +14 -5
  756. package/src/sources/provider-errors.ts +88 -3
  757. package/src/sources/provider-router/batches.ts +4 -1
  758. package/src/sources/provider-router/cache.ts +4 -2
  759. package/src/sources/provider-router/cached-routes.ts +9 -5
  760. package/src/sources/provider-router/financial-routes.ts +12 -5
  761. package/src/sources/provider-router/financials.ts +55 -15
  762. package/src/sources/provider-router/history.ts +68 -34
  763. package/src/sources/provider-router/index.ts +1 -1
  764. package/src/sources/provider-router/primary.ts +23 -5
  765. package/src/sources/provider-router/search.ts +1 -0
  766. package/src/sources/sec-edgar.ts +68 -8
  767. package/src/sync/core-contributors.ts +5 -3
  768. package/src/test-support/cli-context.ts +2 -1
  769. package/src/test-support/data-provider.ts +34 -0
  770. package/src/test-support/shell-pane-keys.tsx +1 -0
  771. package/src/theme/series-colors.ts +46 -0
  772. package/src/theme/themes.ts +149 -0
  773. package/src/tickers/company-name.ts +75 -0
  774. package/src/tickers/instrument-kind.ts +25 -0
  775. package/src/tickers/open-target.ts +3 -2
  776. package/src/tickers/search/index.ts +67 -9
  777. package/src/tickers/search/ranking.ts +78 -18
  778. package/src/tickers/search/types.ts +10 -2
  779. package/src/tickers/starter-symbols.ts +8 -0
  780. package/src/tickers/us-listing.ts +34 -0
  781. package/src/time-series/hooks.ts +9 -0
  782. package/src/time-series/resolve.ts +96 -30
  783. package/src/time-series/types.ts +4 -2
  784. package/src/time-series/use-chart-resolution.ts +32 -0
  785. package/src/types/config.ts +67 -1
  786. package/src/types/data-provider.ts +5 -0
  787. package/src/types/financials.ts +52 -1
  788. package/src/types/headless.ts +72 -0
  789. package/src/types/instrument.ts +8 -0
  790. package/src/types/plugin.ts +68 -3
  791. package/src/types/price-history.ts +7 -0
  792. package/src/types/ticker.ts +14 -0
  793. package/src/ui/host.tsx +26 -4
  794. package/src/ui/index.tsx +2 -0
  795. package/src/ui/live-resize.ts +81 -0
  796. package/src/ui/live-stretch.ts +121 -0
  797. package/src/ui/measured-cells.ts +58 -0
  798. package/src/ui/pane-fill.ts +11 -0
  799. package/src/utils/basis-points.ts +17 -0
  800. package/src/utils/cli-output.ts +21 -2
  801. package/src/utils/concurrency.ts +25 -0
  802. package/src/utils/crypto-pair.ts +20 -0
  803. package/src/utils/currency-pair.ts +19 -0
  804. package/src/utils/decimal-comma.ts +19 -0
  805. package/src/utils/dom-screenshot-css.ts +265 -0
  806. package/src/utils/dom-screenshot-rasters.ts +276 -0
  807. package/src/utils/dom-screenshot.ts +437 -52
  808. package/src/utils/exchange-rate-snapshot.ts +6 -2
  809. package/src/utils/exchanges.ts +120 -1
  810. package/src/utils/format.ts +17 -3
  811. package/src/utils/fundamentals.ts +66 -0
  812. package/src/utils/futures-generic.ts +6 -12
  813. package/src/utils/fx-market-hours.ts +44 -0
  814. package/src/utils/option-expiry.ts +126 -0
  815. package/src/utils/price-history.ts +130 -40
  816. package/src/utils/rpc-timeout-error.ts +6 -2
  817. package/src/utils/sec-eps-basis.ts +178 -36
  818. package/src/utils/sec.ts +98 -40
  819. package/src/utils/throttled-fetch.ts +51 -22
  820. package/src/utils/utc-time.ts +51 -4
@@ -20,6 +20,16 @@ export interface HolderReportFacts {
20
20
  listingCurrency?: string | null;
21
21
  /** Left out when the report's closing line already carries it. */
22
22
  asOf?: string | null;
23
+ /**
24
+ * What the list is as of, in place of `asOf`: `as of <date>` when every
25
+ * row shares one report date, `latest period per holder` when they differ.
26
+ */
27
+ period?: string | null;
28
+ /**
29
+ * False when the list is not the source's largest holders but the few
30
+ * filers that report the line at all (a home line abroad): no "top".
31
+ */
32
+ ranked?: boolean;
23
33
  /** Rows printed. */
24
34
  shown: number;
25
35
  /** Rows the source returned, before any limit. */
@@ -34,15 +44,39 @@ export function moneyColumnHeader(label: string, currency?: string | null): stri
34
44
  return unit ? `${label} (${unit})` : label;
35
45
  }
36
46
 
37
- function holderCountText(shown: number, reported: number, total?: number | null): string {
47
+ function holderCountText(shown: number, reported: number, total?: number | null, ranked = true): string {
38
48
  if (total != null && Number.isFinite(total) && total >= reported) {
39
49
  return `${shown.toLocaleString("en-US")} of ${total.toLocaleString("en-US")} holders`;
40
50
  }
41
51
  if (reported === 0) return "none reported";
52
+ // A home line's few filers are all there is, not a top of anything.
53
+ if (!ranked) return shown < reported ? `${shown} of ${reported} reported` : `${reported} ${reported === 1 ? "holder" : "holders"} reported`;
42
54
  // Without a total the source's list is its largest holders, cut where it cuts it.
43
55
  return shown < reported ? `${shown} of top ${reported} reported` : `top ${reported} reported`;
44
56
  }
45
57
 
58
+ /**
59
+ * What a holder list is as of. Each holder's row is its latest filed
60
+ * period, so one date is claimed only when every row has it; rows of
61
+ * different quarters read `latest period per holder`, and an empty list
62
+ * keeps the source's date.
63
+ */
64
+ export function holderListPeriod(
65
+ rows: ReadonlyArray<{ reportDate?: unknown }>,
66
+ asOf?: string | null,
67
+ ): string | null {
68
+ const dates = new Set(rows.flatMap((row) => typeof row.reportDate === "string" && row.reportDate ? [row.reportDate] : []));
69
+ if (dates.size > 1) return "latest period per holder";
70
+ const [only] = dates;
71
+ const date = only ?? asOf;
72
+ return date ? `as of ${date}` : null;
73
+ }
74
+
75
+ /** Whether a holder list's rows are of more than one report date. */
76
+ export function holderPeriodsDiffer(rows: ReadonlyArray<{ reportDate?: unknown }>): boolean {
77
+ return holderListPeriod(rows) === "latest period per holder";
78
+ }
79
+
46
80
  /** A venue the app knows by its short name (NasdaqGS is NASDAQ); any other as the source wrote it. */
47
81
  function venueLabel(exchange?: string | null): string {
48
82
  const canonical = canonicalExchange(exchange ?? "");
@@ -51,15 +85,15 @@ function venueLabel(exchange?: string | null): string {
51
85
 
52
86
  /** What the list is, after the listing is named: its unit, date and how much of it is shown. */
53
87
  export function holderListFacts(
54
- facts: Pick<HolderReportFacts, "currency" | "listingCurrency" | "asOf" | "shown" | "reported" | "total">,
88
+ facts: Pick<HolderReportFacts, "currency" | "listingCurrency" | "asOf" | "period" | "shown" | "reported" | "total" | "ranked">,
55
89
  ): string[] {
56
90
  const unit = currencyUnitLabel(facts.currency);
57
91
  // Dollars on a London line: say they are the values' unit, not the listing's.
58
92
  const otherUnit = unit && facts.listingCurrency?.trim() && facts.listingCurrency.trim() !== facts.currency?.trim();
59
93
  return [
60
94
  otherUnit ? `values in ${unit}` : unit,
61
- facts.asOf ? `as of ${facts.asOf}` : "",
62
- holderCountText(facts.shown, facts.reported, facts.total),
95
+ facts.period ?? (facts.asOf ? `as of ${facts.asOf}` : ""),
96
+ holderCountText(facts.shown, facts.reported, facts.total, facts.ranked),
63
97
  ].filter(Boolean);
64
98
  }
65
99
 
@@ -132,5 +166,6 @@ export function nonUsHolderCaveat(exchange?: string | null, currency?: string |
132
166
  if (!isNonUsHolderListing(exchange, currency)) return null;
133
167
  const canonical = canonicalExchange(exchange ?? "");
134
168
  const venue = resolveExchangeTimeZone(canonical) ? canonical : "local";
135
- return `Positions come from institutional filings (mostly US 13F), not the ${venue} share register.`;
169
+ // Few filers report a line abroad, so a small position can lead the list.
170
+ return `Positions come from institutional filings (mostly US 13F), not the ${venue} share register, so the line's largest holders may be missing.`;
136
171
  }
@@ -0,0 +1,240 @@
1
+ import type { HeadlessPaneColumn } from "../../../types/plugin";
2
+ import type { HolderData, ShareBasis } from "../../../types/financials";
3
+ import { formatCompact, formatPercentRaw } from "../../../utils/format";
4
+ import {
5
+ displayDate,
6
+ formatMoneyCompact,
7
+ formatPercentHeld,
8
+ formatSignedCompact,
9
+ holderPercent,
10
+ holderValueCurrency,
11
+ resolveHolderOwnershipPercent,
12
+ } from "./format";
13
+ import {
14
+ holderListPeriod,
15
+ holderPeriodsDiffer,
16
+ holderShareBasisMarker,
17
+ holderShareBasisNote,
18
+ holderValueBasis,
19
+ holdersHeaderLine,
20
+ moneyColumnHeader,
21
+ nonUsHolderCaveat,
22
+ sharedReportDate,
23
+ } from "./report-header";
24
+ import { buildRows, DEFAULT_SORT, sortRows } from "./table-model";
25
+ import type { HolderColumnId, SortPreference } from "./types";
26
+
27
+ /**
28
+ * A holder as `holders` and `fn HDS` report it; the keys are the JSON
29
+ * contract. `value` is in `currency`, the values' own currency; the percents
30
+ * are in percent (0.59 is 0.59% of the shares outstanding, 13.15 a 13.15%
31
+ * change on the quarter). A figure the source did not give is null.
32
+ */
33
+ export interface HolderReportRow {
34
+ name: string;
35
+ ownerType: string;
36
+ value: number | null;
37
+ shares: number | null;
38
+ changeShares: number | null;
39
+ changePercent: number | null;
40
+ percentHeld: number | null;
41
+ reportDate: string | null;
42
+ currency: string;
43
+ shareBasis: ShareBasis | null;
44
+ [key: string]: unknown;
45
+ }
46
+
47
+ /** Columns a source fills only when it reports the quarter's change. */
48
+ const CHANGE_COLUMN_KEYS = new Set(["changeShares", "changePercent"]);
49
+ /** Shown only when some row is held as depositary receipts, as on a home line abroad. */
50
+ const BASIS_COLUMN_KEY = "shareBasis";
51
+ const num = (value: unknown) => (typeof value === "number" && Number.isFinite(value) ? value : null);
52
+
53
+ /**
54
+ * The HDS report's columns, which `holders --csv` and `--json` share. CSV
55
+ * reads `format`, so a value drawn as a plain figure exports its full number
56
+ * under a header naming the unit (`Mkt value (USD)`, `Held (%)`); the text
57
+ * report draws `textFormat`, with the currency sign and `<0.01%`.
58
+ */
59
+ export const HOLDER_REPORT_COLUMNS: HeadlessPaneColumn[] = [
60
+ { key: "name", header: "Holder" },
61
+ { key: "ownerType", header: "Type" },
62
+ {
63
+ key: "value",
64
+ header: "Mkt value",
65
+ align: "right",
66
+ format: (value) => num(value) == null ? "-" : formatCompact(num(value)!),
67
+ textFormat: (value, row) => formatMoneyCompact(num(value) ?? undefined, String(row.currency ?? "USD")),
68
+ },
69
+ {
70
+ key: "shares",
71
+ header: "Amount",
72
+ align: "right",
73
+ format: (value) => num(value) == null ? "-" : formatCompact(num(value)!),
74
+ },
75
+ {
76
+ key: BASIS_COLUMN_KEY,
77
+ header: "Basis",
78
+ format: (_value, row) => holderShareBasisMarker(row),
79
+ },
80
+ {
81
+ key: "changeShares",
82
+ header: "Chg",
83
+ align: "right",
84
+ format: (value) => formatSignedCompact(num(value) ?? undefined),
85
+ },
86
+ {
87
+ key: "changePercent",
88
+ header: "Chg%",
89
+ align: "right",
90
+ format: (value) => num(value) == null ? "-" : formatPercentRaw(num(value)!),
91
+ },
92
+ {
93
+ key: "percentHeld",
94
+ header: "Held",
95
+ align: "right",
96
+ format: (value) => num(value) == null ? "-" : `${num(value)!.toFixed(2)}%`,
97
+ textFormat: (value) => formatPercentHeld(num(value)),
98
+ },
99
+ {
100
+ key: "reportDate",
101
+ header: "Period",
102
+ format: (value) => displayDate(typeof value === "string" ? value : undefined),
103
+ },
104
+ ];
105
+
106
+ /** `--sort` values, the same for `holders` and `fn HDS`. */
107
+ export const HOLDER_SORT_KEYS: Record<string, HolderColumnId> = {
108
+ holder: "holder",
109
+ value: "value",
110
+ shares: "shares",
111
+ change: "changeShares",
112
+ "change-percent": "changePercent",
113
+ held: "percentHeld",
114
+ date: "reportDate",
115
+ };
116
+
117
+ /**
118
+ * Every holder of the list, largest value first unless another sort is
119
+ * asked for, with the stake and change in percent. A holder without a value
120
+ * sorts after those with one, whichever the direction. `ownerTypes` keeps
121
+ * only those kinds (`insider`, `13f`).
122
+ */
123
+ export function holderReportRows(
124
+ data: HolderData,
125
+ {
126
+ marketCap,
127
+ sort = DEFAULT_SORT,
128
+ ownerTypes,
129
+ }: { marketCap?: number; sort?: SortPreference; ownerTypes?: ReadonlySet<string> } = {},
130
+ ): HolderReportRow[] {
131
+ const holders = ownerTypes ? data.holders.filter((holder) => ownerTypes.has(holder.ownerType)) : data.holders;
132
+ // The values' own currency: dollars from the 13F filings on a London line.
133
+ const currency = holderValueCurrency(data, "USD")!;
134
+ return sortRows(buildRows({ ...data, holders }), sort, marketCap).map((row) => ({
135
+ name: row.name,
136
+ ownerType: row.ownerType,
137
+ value: row.value ?? null,
138
+ shares: row.shares ?? null,
139
+ changeShares: row.changeShares ?? null,
140
+ changePercent: holderPercent(row.changePercent),
141
+ percentHeld: holderPercent(resolveHolderOwnershipPercent(row, marketCap)),
142
+ reportDate: row.reportDate ?? null,
143
+ currency,
144
+ shareBasis: row.shareBasis ?? null,
145
+ }));
146
+ }
147
+
148
+ /** The report dates of the rows, newest first: one when the list is of one quarter. */
149
+ export function holderReportDates(rows: readonly HolderReportRow[]): string[] {
150
+ return [...new Set(rows.flatMap((row) => row.reportDate ? [row.reportDate] : []))].sort().reverse();
151
+ }
152
+
153
+ /** What the JSON rows' numbers are in, for `metadata.units`. */
154
+ export function holderReportUnits(valueCurrency: string): Record<string, string> {
155
+ return { value: valueCurrency, changePercent: "%", percentHeld: "%" };
156
+ }
157
+
158
+ /** Whether any holder carries the quarter's change; many sources report none. */
159
+ function holderChangeReported(rows: readonly HolderReportRow[]): boolean {
160
+ return rows.some((row) => row.changeShares != null || row.changePercent != null);
161
+ }
162
+
163
+ /**
164
+ * The report's columns for these rows: the change columns only when a row
165
+ * has a change, the basis column only when a row is held as receipts, and
166
+ * the value column named with its currency.
167
+ */
168
+ export function holderReportColumns(rows: readonly HolderReportRow[], valueCurrency: string | null | undefined): HeadlessPaneColumn[] {
169
+ const changeReported = holderChangeReported(rows);
170
+ const marked = rows.some((row) => holderShareBasisMarker(row));
171
+ return HOLDER_REPORT_COLUMNS
172
+ .filter((column) => changeReported || !CHANGE_COLUMN_KEYS.has(column.key))
173
+ .filter((column) => marked || column.key !== BASIS_COLUMN_KEY)
174
+ .map((column) => column.key === "value" ? { ...column, header: moneyColumnHeader(column.header, valueCurrency) } : column);
175
+ }
176
+
177
+ /**
178
+ * The lines above the HDS table, which `holders --csv` also closes with: the
179
+ * listing, unit and count, how a value was reached (and where the change is
180
+ * when the source gives none), and what the positions and shares are.
181
+ */
182
+ export function holderReportNotices({
183
+ data,
184
+ requested,
185
+ shown,
186
+ reported,
187
+ total,
188
+ sort = DEFAULT_SORT,
189
+ }: {
190
+ data: HolderData;
191
+ /** The symbol as asked for, which `fn 13F` takes. */
192
+ requested: string;
193
+ shown: readonly HolderReportRow[];
194
+ /** Holders on the list before a limit. */
195
+ reported: number;
196
+ total: number | null;
197
+ sort?: SortPreference;
198
+ }): { notices: string[]; valueBasis: string; positionsBasis: string | null; changeReported: boolean } {
199
+ const valueCurrency = holderValueCurrency(data, "USD")!;
200
+ const changeReported = holderChangeReported(shown);
201
+ const valueBasis = holderValueBasis(sharedReportDate(shown), data.valueBasis, valueCurrency);
202
+ const positionsBasis = shown.length > 0 ? nonUsHolderCaveat(data.exchange, data.currency ?? "USD") : null;
203
+ // The title names the ticker and the closing line carries the as-of date,
204
+ // which is one date only when every row has it.
205
+ const header = holdersHeaderLine({
206
+ name: data.name,
207
+ symbol: data.symbol && data.symbol !== requested ? data.symbol : null,
208
+ exchange: data.exchange,
209
+ currency: valueCurrency,
210
+ listingCurrency: data.currency,
211
+ period: holderPeriodsDiffer(shown) ? holderListPeriod(shown) : null,
212
+ shown: shown.length,
213
+ reported,
214
+ total,
215
+ ranked: !positionsBasis,
216
+ });
217
+ const basis = shown.length === 0 ? null : [
218
+ `Mkt value = ${valueBasis}.`,
219
+ changeReported ? "" : `Change vs prior quarter: not reported by this source; see fn 13F ${requested}`,
220
+ ].filter(Boolean).join(" ");
221
+ return {
222
+ notices: [header, basis, positionsBasis, holderShareBasisNote(data, shown), unvaluedHoldersNote(shown, sort)]
223
+ .filter((line): line is string => !!line),
224
+ valueBasis,
225
+ positionsBasis,
226
+ changeReported,
227
+ };
228
+ }
229
+
230
+ /**
231
+ * Holders the list gives no value for (a home line's position its filing
232
+ * could not tie to a priced security) sort after every valued one, and a
233
+ * value-ordered report says so rather than ranking them silently.
234
+ */
235
+ export function unvaluedHoldersNote(rows: readonly HolderReportRow[], sort: SortPreference = DEFAULT_SORT): string | null {
236
+ if (sort.columnId !== "value") return null;
237
+ const unvalued = rows.filter((row) => row.value == null).length;
238
+ if (unvalued === 0 || unvalued === rows.length) return null;
239
+ return `${unvalued} ${unvalued === 1 ? "holder has" : "holders have"} no value and ${unvalued === 1 ? "is" : "are"} listed last.`;
240
+ }
@@ -1,16 +1,19 @@
1
- import type { DataProvider, SecFilingItem } from "../../../types/data-provider";
1
+ import type { DataProvider } from "../../../types/data-provider";
2
2
  import { parseInsiderFiling, type ParsedInsiderFiling } from "./model";
3
3
  import { isInsiderForm } from "./insider-data";
4
+ import { filesAsForeignPrivateIssuer } from "./issuer";
4
5
 
5
- async function loadInsiderFilings(
6
- provider: DataProvider,
7
- symbol: string,
8
- count: number,
9
- exchange = "",
10
- ): Promise<SecFilingItem[]> {
11
- if (!provider.getSecFilings) throw new Error("Insider filing data unavailable");
12
- const filings = await provider.getSecFilings(symbol, count, exchange);
13
- return filings.filter((filing) => isInsiderForm(filing.form));
6
+ // Recent EDGAR dumps cap at 1,000 mixed forms; older archives are read until
7
+ // this many filings or the company's history ends.
8
+ const SEC_FILING_SCAN_LIMIT = 20_000;
9
+
10
+ export interface InsiderFilingsLoad {
11
+ /** The rows of the company's own Form 4 filings, newest first. */
12
+ parsed: ParsedInsiderFiling[];
13
+ /** Every Form 4 listed was read, none is the company's own, and it reports as a foreign private issuer. */
14
+ foreignPrivateIssuer: boolean;
15
+ /** The SEC lists no filing of any form for the company. */
16
+ noFilings: boolean;
14
17
  }
15
18
 
16
19
  function throwIfAborted(signal: AbortSignal | undefined): void {
@@ -18,29 +21,41 @@ function throwIfAborted(signal: AbortSignal | undefined): void {
18
21
  throw signal.reason instanceof Error ? signal.reason : new Error("Insider filing load was aborted.");
19
22
  }
20
23
 
24
+ /**
25
+ * Reads the company's Form 4 filings newest first, one at a time, until
26
+ * `limit` of them are its own. A form it filed as an owner of another
27
+ * company's shares is read and left out, so a list of only those is read to
28
+ * the end before it can say there are none.
29
+ */
21
30
  export async function loadParsedInsiderFilings(
22
31
  provider: DataProvider,
23
32
  symbol: string,
24
33
  options: { limit: number; exchange?: string; signal?: AbortSignal },
25
- ): Promise<ParsedInsiderFiling[]> {
34
+ ): Promise<InsiderFilingsLoad> {
35
+ if (!provider.getSecFilings) throw new Error("Insider filing data unavailable");
26
36
  if (!provider.getSecFilingContent) throw new Error("Insider filing content unavailable");
27
- const filings = (await loadInsiderFilings(
28
- provider,
29
- symbol,
30
- 20_000,
31
- options.exchange,
32
- )).slice(0, options.limit);
37
+ const filings = await provider.getSecFilings(symbol, SEC_FILING_SCAN_LIMIT, options.exchange ?? "");
33
38
 
34
39
  const parsed: ParsedInsiderFiling[] = [];
40
+ let own = 0;
35
41
  for (const filing of filings) {
42
+ if (own >= options.limit) break;
43
+ if (!isInsiderForm(filing.form)) continue;
36
44
  throwIfAborted(options.signal);
45
+ let content: string | null;
37
46
  try {
38
- const content = await provider.getSecFilingContent(filing);
39
- parsed.push(...parseInsiderFiling(filing, content));
47
+ content = await provider.getSecFilingContent(filing);
40
48
  } catch {
41
49
  throwIfAborted(options.signal);
50
+ // An unread filing may be the company's own; it stays as a row that says so.
42
51
  parsed.push({ filing, transaction: null, isLoading: false });
52
+ own += 1;
53
+ continue;
43
54
  }
55
+ const entries = parseInsiderFiling(filing, content);
56
+ if (entries.length === 0) continue;
57
+ parsed.push(...entries);
58
+ own += 1;
44
59
  }
45
- return parsed;
60
+ return { parsed, foreignPrivateIssuer: own === 0 && filesAsForeignPrivateIssuer(filings), noFilings: filings.length === 0 };
46
61
  }
@@ -3,9 +3,11 @@ import type {
3
3
  HeadlessPaneContext,
4
4
  HeadlessPaneDefinition,
5
5
  HeadlessPaneLoadArgs,
6
+ HeadlessPaneRow,
6
7
  } from "../../../types/plugin";
7
8
  import { formatCompact, formatCurrency } from "../../../utils/format";
8
- import { loadParsedInsiderFilings } from "./client";
9
+ import { loadParsedInsiderFilings, type InsiderFilingsLoad } from "./client";
10
+ import { insiderEmptyNotice } from "./issuer";
9
11
  import {
10
12
  buildInsiderRows,
11
13
  buildInsiderSummary,
@@ -15,9 +17,12 @@ import {
15
17
  matchesInsiderTypeFilter,
16
18
  type ParsedInsiderFiling,
17
19
  } from "./model";
18
- import { relevantInsiderAmendments } from "./amendments";
20
+ import { isAmendedInsiderFiling, relevantInsiderAmendments } from "./amendments";
19
21
  import { formatInsiderName } from "./display";
20
22
  import { SEC_FILINGS } from "../shared/report-freshness";
23
+ import { resolveHeadlessIssuerListing } from "../shared/headless-market-data";
24
+ import { noSecReportsNotice } from "../../../utils/sec";
25
+ import { parsePublicTickerKey } from "../../../utils/exchanges";
21
26
 
22
27
  const INSIDER_COLUMNS: HeadlessPaneColumn[] = [
23
28
  { key: "form", header: "Form" },
@@ -62,15 +67,23 @@ const INSIDER_COLUMNS: HeadlessPaneColumn[] = [
62
67
  align: "right",
63
68
  format: (value) => value == null ? "-" : `$${formatCompact(Number(value))}`,
64
69
  },
70
+ // An amendment's original date, remarks and footnotes, under the amendment's own row.
71
+ { key: "note", header: "Note", underRow: true, format: (value) => typeof value === "string" ? value : "" },
65
72
  ];
66
73
 
74
+ /** What a Form 4/A says about itself, for its last row in the report. */
75
+ function amendmentNote(entry: ParsedInsiderFiling): string {
76
+ const original = entry.disclosure?.originalFilingDate;
77
+ return [original ? `Original filed ${original}` : "", ...buildInsiderDisclosureText(entry).split("\n")].filter(Boolean).join("\n");
78
+ }
79
+
67
80
  export interface InsiderHeadlessDependencies {
68
81
  loadParsed(
69
82
  symbol: string,
70
83
  limit: number,
71
84
  args: HeadlessPaneLoadArgs,
72
85
  ctx: HeadlessPaneContext,
73
- ): Promise<ParsedInsiderFiling[]>;
86
+ ): Promise<InsiderFilingsLoad>;
74
87
  }
75
88
 
76
89
  const defaultDependencies: InsiderHeadlessDependencies = {
@@ -80,6 +93,17 @@ const defaultDependencies: InsiderHeadlessDependencies = {
80
93
  }),
81
94
  };
82
95
 
96
+ /**
97
+ * "CAR Group (ASX) files no SEC reports." for a listing abroad the SEC lists
98
+ * nothing for, as `filings` says it; null for a US listing or a symbol with no
99
+ * venue, whose empty list is only no Form 4.
100
+ */
101
+ async function noSecReportsEmpty(ctx: HeadlessPaneContext, key: string): Promise<string | null> {
102
+ const listing = await resolveHeadlessIssuerListing(ctx, key);
103
+ if (!listing.exchange) return null;
104
+ return noSecReportsNotice({ symbol: parsePublicTickerKey(key).symbol, exchange: listing.exchange, name: listing.name ?? null });
105
+ }
106
+
83
107
  export function createInsiderHeadless(
84
108
  dependencies: InsiderHeadlessDependencies = defaultDependencies,
85
109
  ): HeadlessPaneDefinition<"rows"> {
@@ -113,7 +137,7 @@ export function createInsiderHeadless(
113
137
  {
114
138
  key: "limit",
115
139
  aliases: ["count", "rows"],
116
- description: "Maximum Form 4 and Form 4/A filings to parse.",
140
+ description: "Maximum of the company's own Form 4 and Form 4/A filings to parse.",
117
141
  type: "integer",
118
142
  defaultValue: 20,
119
143
  minimum: 1,
@@ -125,7 +149,9 @@ export function createInsiderHeadless(
125
149
  async load(args, ctx) {
126
150
  const symbol = args.symbols[0]!;
127
151
  const limit = Number(args.options.limit);
128
- const parsed = await dependencies.loadParsed(symbol, limit, args, ctx);
152
+ const { parsed, foreignPrivateIssuer, noFilings } = await dependencies.loadParsed(symbol, limit, args, ctx);
153
+ const empty = parsed.length > 0 ? null
154
+ : (noFilings ? await noSecReportsEmpty(ctx, symbol) : null) ?? insiderEmptyNotice(foreignPrivateIssuer);
129
155
  const name = String(args.options.name ?? "").trim().toLocaleLowerCase();
130
156
  const type = isInsiderTypeFilter(args.options.type) ? args.options.type : "all";
131
157
  const owned = name
@@ -136,8 +162,16 @@ export function createInsiderHeadless(
136
162
  const incomplete = [...new Set(buildInsiderRows(parsed)
137
163
  .filter((row) => row.status !== "parsed" && row.status !== "disclosure")
138
164
  .map((row) => row.accessionNumber))];
165
+ // A filing's lines sit together, so its note goes once, under the last of them.
166
+ const rows: HeadlessPaneRow[] = buildInsiderRows(filtered, parsed).map((row, index) => {
167
+ const entry = filtered[index]!;
168
+ const last = filtered[index + 1]?.filing.accessionNumber !== entry.filing.accessionNumber;
169
+ return isAmendedInsiderFiling(entry) && last ? { ...row, note: amendmentNote(entry) || null } : row;
170
+ });
139
171
  return {
140
- rows: buildInsiderRows(filtered, parsed),
172
+ rows,
173
+ // Nothing at all: the company has no Form 4 of its own, which is the whole answer.
174
+ ...(empty ? { empty, unavailableSymbols: [] } : {}),
141
175
  errors: [
142
176
  ...incomplete.map((accessionNumber) => `${accessionNumber}: Form 4 transactions are unavailable or incomplete.`),
143
177
  ...amendments.map((scope) => `${scope.accessionNumber}: Form 4/A is unreconciled; affected transaction totals are unavailable.`),
@@ -146,11 +180,7 @@ export function createInsiderHeadless(
146
180
  symbol,
147
181
  summary: buildInsiderSummary(owned, Date.now(), parsed),
148
182
  amendments,
149
- notices: amendments.map((scope) => {
150
- const entry = parsed.find(({ filing }) => filing.accessionNumber === scope.accessionNumber)!;
151
- return [`Form 4/A ${scope.accessionNumber}${scope.originalFilingDate ? ` | Original filed ${scope.originalFilingDate}` : ""}`,
152
- buildInsiderDisclosureText(entry)].filter(Boolean).join("\n");
153
- }),
183
+ foreignPrivateIssuer,
154
184
  parsed: new Set(parsed.filter(({ transaction }) => transaction != null).map(({ filing }) => filing.accessionNumber)).size,
155
185
  transactions: filtered.filter(({ transaction }) => transaction != null).length,
156
186
  requested: limit,
@@ -22,7 +22,8 @@ import {
22
22
  type StatItem,
23
23
  } from "../../../components";
24
24
  import { useDebouncedPluginPaneState, usePluginPaneState } from "../../runtime";
25
- import { isUsEquityTicker } from "../../../utils/sec";
25
+ import { mayBeSecEquityListing, mayBeUsEquityTicker, noSecReportsNotice, nonUsSecListingVenue } from "../../../utils/sec";
26
+ import { parsePublicTickerKey } from "../../../utils/exchanges";
26
27
  import { formatCompact } from "../../../utils/format";
27
28
  import { nextHeaderSort } from "../../../utils/sort-values";
28
29
  import { formatShortDate } from "../../../utils/datetime-format";
@@ -48,6 +49,7 @@ import {
48
49
  import { formatInsiderName } from "./display";
49
50
  import { insiderHeadless } from "./headless";
50
51
  import { isInsiderForm } from "./insider-data";
52
+ import { filesAsForeignPrivateIssuer, insiderEmptyNotice, isOtherIssuerFiling } from "./issuer";
51
53
  import { relevantInsiderAmendments } from "./amendments";
52
54
  import { usePaneTickerIdentity } from "../../../state/hooks/pane-ticker";
53
55
  import {
@@ -130,7 +132,9 @@ function InsiderView({ width, height, focused }: { width: number; height: number
130
132
  [setOpenItemIdState],
131
133
  );
132
134
  const [sort, setSort] = useState<StackSortPreference<InsiderColumnId>>({ columnId: "date", direction: "desc" });
133
- const eligibleTicker = isUsEquityTicker(ticker);
135
+ const eligibleTicker = mayBeSecEquityListing(ticker);
136
+ // A listing abroad is looked up by its company; an empty list means it files nothing with the SEC.
137
+ const abroadVenue = ticker ? nonUsSecListingVenue(ticker.metadata.ticker, ticker.metadata.exchange) : null;
134
138
  const instrument = instrumentFromTicker(ticker, ticker?.metadata.ticker ?? null);
135
139
 
136
140
  const filingsEntry = useSecFilingsQuery(
@@ -185,6 +189,17 @@ function InsiderView({ width, height, focused }: { width: number; height: number
185
189
  scopeKey: `${ticker?.metadata.ticker ?? "none"}:${ticker?.metadata.exchange ?? ""}`,
186
190
  targets: visibleForm4Filings,
187
191
  });
192
+ // The list also holds the Form 4s the company filed as an owner of another
193
+ // company's shares, which only their documents tell apart. Until one of its
194
+ // own is read, the pages are read on to the end, so a list of none says so.
195
+ const ownerFilingsShown = useMemo(() => visibleForm4Filings.some((filing) => (
196
+ isOtherIssuerFiling(filing, contentMap.get(filing.accessionNumber))
197
+ )), [contentMap, visibleForm4Filings]);
198
+ const ownFilingShown = useMemo(() => visibleForm4Filings.some((filing) => (
199
+ contentMap.has(filing.accessionNumber) && !isOtherIssuerFiling(filing, contentMap.get(filing.accessionNumber))
200
+ )), [contentMap, visibleForm4Filings]);
201
+ const searchingOwn = !ownFilingShown && pendingCount === 0 && shownCount < form4Filings.length;
202
+ const noOwnFilings = !loading && !ownFilingShown && pendingCount === 0 && shownCount >= form4Filings.length;
188
203
 
189
204
  const allParsed: ParsedFiling[] = useMemo(() => visibleForm4Filings.flatMap((filing) => {
190
205
  const hasContent = contentMap.has(filing.accessionNumber);
@@ -223,13 +238,13 @@ function InsiderView({ width, height, focused }: { width: number; height: number
223
238
  // load here until it fills a page, back to a year at most.
224
239
  const oldestShown = visibleForm4Filings[visibleForm4Filings.length - 1]?.filingDate;
225
240
  const oldestShownTime = oldestShown ? new Date(oldestShown).getTime() : Number.NaN;
226
- const wantsOlderFilings = (typeFilter !== "all" || nameFilter != null)
241
+ const wantsOlderFilings = (typeFilter !== "all" || nameFilter != null || ownerFilingsShown)
227
242
  && shown.length < Math.max(FORM4_PAGE_SIZE, height)
228
243
  && shownCount < Math.min(form4Filings.length, AUTO_FILL_FILING_CAP)
229
244
  && oldestShownTime >= Date.now() - AUTO_FILL_DAYS * DAY_MS;
230
245
  useEffect(() => {
231
- if (wantsOlderFilings && pendingCount === 0) loadNextPage();
232
- }, [loadNextPage, pendingCount, shownCount, wantsOlderFilings]);
246
+ if (searchingOwn || (wantsOlderFilings && pendingCount === 0)) loadNextPage();
247
+ }, [loadNextPage, pendingCount, searchingOwn, shownCount, wantsOlderFilings]);
233
248
 
234
249
  const summary = useMemo(() => buildInsiderSummaryFigures(parsed, Date.now(), allParsed), [parsed, allParsed]);
235
250
  // A page loading in on scroll clears the totals until it is read; the last
@@ -353,15 +368,17 @@ function InsiderView({ width, height, focused }: { width: number; height: number
353
368
  if (authWall) return <SignInWall placement="insider-signin" action="view insider transactions" needsVerification={cloudSession.needsVerification} />;
354
369
  if (loading && allFilings.length === 0) return <Spinner label="Loading insider filings..." />;
355
370
  if (error && allFilings.length === 0) return <EmptyState title="Insider filings unavailable." message={error} />;
356
- if (!loading && form4Filings.length === 0) {
357
- return renderFilingNotice(`No Form 4 filings found for ${ticker.metadata.ticker}.`, width);
371
+ if (noOwnFilings) {
372
+ return renderFilingNotice(abroadVenue && allFilings.length === 0
373
+ ? noSecReportsNotice({ symbol: parsePublicTickerKey(ticker.metadata.ticker).symbol, exchange: abroadVenue, name: ticker.metadata.name ?? null })
374
+ : insiderEmptyNotice(filesAsForeignPrivateIssuer(allFilings)), width);
358
375
  }
359
376
 
360
377
  // Until a filing is read there is nothing to say; after that the empty
361
378
  // list says how far back the filings it has read go, while older ones load.
362
379
  const oldestRead = allParsed.findLast((entry) => !entry.isLoading)?.filing.filingDate;
363
380
  const since = oldestRead ? ` since ${formatShortDate(oldestRead, { utc: true })}` : "";
364
- const emptyTitle = typeCounts.all === 0 && (pendingCount > 0 || wantsOlderFilings)
381
+ const emptyTitle = typeCounts.all === 0 && (pendingCount > 0 || wantsOlderFilings || searchingOwn)
365
382
  ? "Loading Form 4 transactions..."
366
383
  : typeFilter === "trades"
367
384
  ? `No open-market buys or sells${nameFilter ? " by this insider" : ""}${since}.`
@@ -458,7 +475,7 @@ export const insiderModule: PluginModule = {
458
475
  description: "Insider transaction activity for the selected ticker.",
459
476
  keywords: ["insider", "form 4", "ownership", "transactions", "ins"],
460
477
  shortcut: "INS",
461
- canCreate: (_context, options) => !options?.ticker || isUsEquityTicker(options.ticker),
478
+ canCreate: (_context, options) => !options?.ticker || mayBeSecEquityListing(options.ticker),
462
479
  }),
463
480
  headless: insiderHeadless,
464
481
  },
@@ -471,7 +488,7 @@ export const insiderModule: PluginModule = {
471
488
  order: 47,
472
489
  component: InsiderView,
473
490
  instruments: ["equity"],
474
- isVisible: ({ ticker }) => isUsEquityTicker(ticker),
491
+ isVisible: ({ ticker }) => mayBeUsEquityTicker(ticker),
475
492
  });
476
493
  },
477
494
  };
@@ -104,6 +104,16 @@ function disclosureText(xml: string): string {
104
104
  return decodeHtmlEntities(xml.replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g, "$1").replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim());
105
105
  }
106
106
 
107
+ /**
108
+ * The CIK of the company whose shares the form reports, without leading
109
+ * zeros, or null when the document is not a Form 4 or names none.
110
+ */
111
+ export function parseForm4IssuerCik(xml: string): string | null {
112
+ if (!/<(?:[\w.-]+:)?ownershipDocument(?:\s|>)/i.test(xml)) return null;
113
+ const cik = tagText(tagContent(xml, "issuer") ?? "", "issuerCik").replace(/^0+/, "");
114
+ return /^\d+$/.test(cik) ? cik : null;
115
+ }
116
+
107
117
  export function parseForm4Disclosure(xml: string): InsiderFilingDisclosure | null {
108
118
  if (!/<(?:[\w.-]+:)?ownershipDocument(?:\s|>)/i.test(xml)) return null;
109
119
  const original = tagText(xml, "dateOfOriginalSubmission");