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
@@ -6,16 +6,30 @@ import type {
6
6
  } from "../../../types/plugin";
7
7
  import { formatShortDate } from "../../../utils/datetime-format";
8
8
  import { normalizeCik } from "./api";
9
- import { buildFundOverlap, overlapPeriod } from "./overlap";
9
+ import { buildFundOverlap, buildManagerEtfOverlap, overlapPeriod } from "./overlap";
10
+ import type { FundMembersPayload, MemberFundsPayload } from "../../../api-client/members";
11
+ import { fetchFunds, fetchMembers } from "../members/client";
12
+ import { coveredFund } from "../members/model";
10
13
  import { appendTickerHoldings, loadCrowding, loadTickerHoldings, type CrowdingRow, type TickerHoldings } from "./signals";
11
14
  import {
12
15
  AS_FILED_VALUE,
13
16
  compareCrowding,
14
17
  crowdingForTicker,
15
18
  cutText,
16
- periodText,
19
+ filedPeriodText,
20
+ filingDayText,
21
+ filingLagDays,
22
+ isOptionType,
23
+ isStaleFiling,
24
+ markedPositionType,
25
+ OPTION_ROWS_NOTE,
26
+ restatedValuesText,
27
+ staleFilingText,
28
+ staleFundsText,
17
29
  summarizeTickerHoldings,
30
+ THIRTEENF_LIMITS,
18
31
  THIRTEENF_MAX_LIMIT,
32
+ THIRTEENF_OPTIONS_NOTE,
19
33
  } from "./report-notes";
20
34
  import {
21
35
  loadBrowserRows,
@@ -31,9 +45,9 @@ import {
31
45
  buildTimelineRows,
32
46
  inferBrowserTabFromQuery,
33
47
  hasComparable13FQuarter,
34
- THIRTEENF_OPTIONS_NOTE,
35
48
  isCikQuery,
36
49
  positionType,
50
+ quartersBehindLatest,
37
51
  sortBrowserRows,
38
52
  sortHoldingRows,
39
53
  sortTimelineRows,
@@ -87,9 +101,16 @@ const BROWSER_COLUMNS: HeadlessPaneColumn[] = [
87
101
  },
88
102
  ];
89
103
 
104
+ /** What a 13F position report notes after its table: the filing's limits, and what the option marker means when option rows are shown. */
105
+ function positionNotes(rows: readonly { type?: unknown }[]): string[] {
106
+ return [THIRTEENF_LIMITS, ...(rows.some((row) => isOptionType(row.type)) ? [OPTION_ROWS_NOTE] : [])];
107
+ }
108
+
109
+ const TYPE_COLUMN: HeadlessPaneColumn = { key: "type", header: "Type", textFormat: markedPositionType };
110
+
90
111
  const HOLDING_COLUMNS: HeadlessPaneColumn[] = [
91
112
  { key: "ticker", header: "Ticker" },
92
- { key: "type", header: "Type" },
113
+ TYPE_COLUMN,
93
114
  { key: "issuer", header: "Issuer" },
94
115
  {
95
116
  key: "value",
@@ -175,9 +196,13 @@ export interface ThirteenFHeadlessDependencies {
175
196
  args: HeadlessPaneLoadArgs,
176
197
  ctx: HeadlessPaneContext,
177
198
  ): Promise<FundDetailData>;
199
+ /** The ETFs whose holdings files MEMB serves. */
200
+ loadEtfFunds?(ctx: HeadlessPaneContext): Promise<MemberFundsPayload["funds"]>;
201
+ /** One covered ETF's holdings file, as `fn MEMB` reads it. */
202
+ loadEtfHoldings?(ticker: string, ctx: HeadlessPaneContext): Promise<FundMembersPayload>;
178
203
  }
179
204
 
180
- const defaultDependencies: ThirteenFHeadlessDependencies = {
205
+ const defaultDependencies: Required<ThirteenFHeadlessDependencies> = {
181
206
  loadBrowser: (tab, query, limit, _args, ctx) => loadBrowserRows(
182
207
  tab,
183
208
  query,
@@ -185,6 +210,8 @@ const defaultDependencies: ThirteenFHeadlessDependencies = {
185
210
  { limit },
186
211
  ),
187
212
  loadDetail: (cik, name, _args, ctx) => loadFundDetail(cik, name, ctx.signal),
213
+ loadEtfFunds: async (ctx) => (await fetchFunds(ctx.apiClient)).funds,
214
+ loadEtfHoldings: (ticker, ctx) => fetchMembers(ticker, ctx.apiClient),
188
215
  };
189
216
 
190
217
  const VIEW_TITLES: Record<string, string> = {
@@ -217,18 +244,22 @@ function browserTab(view: HeadlessThirteenFView, query: string): ThirteenFBrowse
217
244
  return inferBrowserTabFromQuery(query);
218
245
  }
219
246
 
220
- async function resolveFund(
247
+ /**
248
+ * The manager a fund name or CIK names: a CIK as given, else the one fund
249
+ * whose name matches exactly, else the only match. `search` lists funds by
250
+ * name, as the 13F browser does.
251
+ */
252
+ async function findThirteenFFund(
221
253
  query: string,
222
- args: HeadlessPaneLoadArgs,
223
- ctx: HeadlessPaneContext,
224
- dependencies: ThirteenFHeadlessDependencies,
225
- ): Promise<{ cik: string; name: string }> {
226
- if (!query) throw new Error("13F holdings and filings require a fund name or CIK.");
254
+ search: (query: string, limit: number) => Promise<BrowserLoadResult>,
255
+ { exactOnly = false }: { exactOnly?: boolean } = {},
256
+ ): Promise<{ cik: string; name: string } | null> {
227
257
  if (isCikQuery(query)) return { cik: normalizeCik(query), name: query };
228
258
  // A small output limit must not hide other matching managers during lookup.
229
- const result = await dependencies.loadBrowser("funds", query, 25, args, ctx);
259
+ const result = await search(query, 25);
230
260
  const candidates = [...new Map(result.rows.map((row) => [row.cik, row])).values()];
231
261
  const exact = candidates.filter((row) => row.name.toLocaleLowerCase() === query.toLocaleLowerCase());
262
+ if (exactOnly) return exact.length === 1 ? { cik: exact[0]!.cik, name: exact[0]!.name } : null;
232
263
  const fund = exact.length === 1 ? exact[0]
233
264
  : candidates.length === 1 && !result.hasMore ? candidates[0] : undefined;
234
265
  if (candidates.length === 0) throw new Error(`No 13F fund found for "${query}".`);
@@ -239,12 +270,67 @@ async function resolveFund(
239
270
  return { cik: fund.cik, name: fund.name };
240
271
  }
241
272
 
273
+ async function resolveFund(
274
+ query: string,
275
+ args: HeadlessPaneLoadArgs,
276
+ ctx: HeadlessPaneContext,
277
+ dependencies: ThirteenFHeadlessDependencies,
278
+ ): Promise<{ cik: string; name: string }> {
279
+ if (!query) throw new Error("13F holdings and filings require a fund name or CIK.");
280
+ return (await findThirteenFFund(query, (text, limit) => dependencies.loadBrowser("funds", text, limit, args, ctx)))!;
281
+ }
282
+
283
+ /** A word that reads as a ticker (SPY, BRK.B), not a manager's name or a CIK. */
284
+ const TICKER_WORD = /^\$?[A-Za-z]{1,5}(?:[.-][A-Za-z])?$/;
285
+
286
+ type OverlapComparison =
287
+ | { kind: "fund"; cik: string; name: string }
288
+ | { kind: "etf"; symbol: string; ticker: string; name: string };
289
+
290
+ /** "IVV (also SPY, SPX), IJH": the covered funds and the aliases each answers to. */
291
+ const coveredEtfs = (funds: MemberFundsPayload["funds"]) => funds
292
+ .map((fund) => fund.aliases.length ? `${fund.ticker} (also ${fund.aliases.join(", ")})` : fund.ticker).join(", ");
293
+
294
+ /**
295
+ * What `--compare` names. A ticker-like word is an ETF when MEMB has its
296
+ * holdings file, else a 13F manager only by its exact name; it is never
297
+ * matched to a manager by a partial name (SPY is not Spyglass Capital).
298
+ * Anything else, a CIK or a longer name, is a 13F manager as before.
299
+ */
300
+ async function resolveComparison(
301
+ text: string,
302
+ args: HeadlessPaneLoadArgs,
303
+ ctx: HeadlessPaneContext,
304
+ dependencies: Required<ThirteenFHeadlessDependencies>,
305
+ ): Promise<OverlapComparison> {
306
+ if (isCikQuery(text) || !TICKER_WORD.test(text)) return { kind: "fund", ...await resolveFund(text, args, ctx, dependencies) };
307
+ const symbol = text.replace(/^\$/, "").toUpperCase();
308
+ let funds: MemberFundsPayload["funds"] | null = null;
309
+ let failure = "";
310
+ try {
311
+ funds = await dependencies.loadEtfFunds(ctx);
312
+ } catch (error) {
313
+ if (ctx.signal.aborted) throw error;
314
+ failure = error instanceof Error ? error.message : String(error);
315
+ }
316
+ const etf = funds ? coveredFund(funds, symbol) : undefined;
317
+ if (etf) return { kind: "etf", symbol, ticker: etf.ticker, name: etf.name };
318
+ const manager = await findThirteenFFund(text, (query, limit) => dependencies.loadBrowser("funds", query, limit, args, ctx), { exactOnly: true });
319
+ if (manager) return { kind: "fund", ...manager };
320
+ const etfs = funds ? `${symbol} is not an ETF MEMB covers (covered: ${coveredEtfs(funds)})` : `${symbol} could not be checked against MEMB's ETFs (${failure})`;
321
+ throw new Error(`${etfs}, and no 13F manager is named "${text}". For a manager, use its CIK or full name.`);
322
+ }
323
+
324
+ const percentText = (value: number) => `${(value * 100).toFixed(1)}%`;
325
+
242
326
  export function createThirteenFHeadless(
243
- dependencies: ThirteenFHeadlessDependencies = defaultDependencies,
327
+ overrides: ThirteenFHeadlessDependencies = defaultDependencies,
244
328
  ): HeadlessPaneDefinition<"rows"> {
329
+ const dependencies: Required<ThirteenFHeadlessDependencies> = { ...defaultDependencies, ...overrides };
245
330
  return {
246
331
  shape: "rows",
247
332
  freshness: { ...SEC_FILINGS, basis: "13F filings", observedKey: "filedAsOfDate" },
333
+ discovery: { limitations: [THIRTEENF_LIMITS] },
248
334
  argument: {
249
335
  kind: "free-text",
250
336
  placeholder: "fund, ticker, or CIK",
@@ -252,9 +338,10 @@ export function createThirteenFHeadless(
252
338
  optional: true,
253
339
  },
254
340
  options: [
255
- { key: "rank", description: "Crowding order.", type: "enum", values: [{ value: "new" }, { value: "exits" }, { value: "increases" }, { value: "decreases" }], defaultValue: "new" },
256
- { key: "compare", description: "Second fund name or CIK for overlap.", type: "string" },
257
- { key: "offset", description: "Fund offset for ticker-holdings.", type: "integer", defaultValue: 0, minimum: 0, maximum: 100000 },
341
+ // No defaults on view-specific options, so a flag the view does not use can be named as ignored.
342
+ { key: "rank", description: "Crowding order (crowding view; new when left out).", type: "enum", values: [{ value: "new" }, { value: "exits" }, { value: "increases" }, { value: "decreases" }] },
343
+ { key: "compare", description: "Second fund name or CIK, or an ETF ticker MEMB covers such as SPY; implies the overlap view.", type: "string" },
344
+ { key: "offset", description: "Fund offset for ticker-holdings (0 when left out).", type: "integer", minimum: 0, maximum: 100000 },
258
345
  {
259
346
  key: "view",
260
347
  description: "Fund browser mode or detail tab.",
@@ -287,20 +374,80 @@ export function createThirteenFHeadless(
287
374
  async load(args, ctx) {
288
375
  const query = typeof args.argument === "string" ? args.argument.trim() : "";
289
376
  const requestedView = String(args.options.view) as HeadlessThirteenFView;
377
+ const compare = typeof args.options.compare === "string" ? args.options.compare.trim() : "";
378
+ if (compare && requestedView !== "auto" && requestedView !== "overlap") {
379
+ throw new Error(`--compare is for the overlap view; --view ${requestedView} does not use it. Drop --view, or use --view overlap.`);
380
+ }
290
381
  // A ticker's holders with their positions, not the holders' whole books.
291
- const view = requestedView !== "auto" ? requestedView
292
- : isCikQuery(query) ? "holdings"
293
- : inferBrowserTabFromQuery(query) === "byTicker" ? "ticker-holdings"
294
- : requestedView;
382
+ const view = compare ? "overlap"
383
+ : requestedView !== "auto" ? requestedView
384
+ : isCikQuery(query) ? "holdings"
385
+ : inferBrowserTabFromQuery(query) === "byTicker" ? "ticker-holdings"
386
+ : requestedView;
387
+ // A flag the view does not use is named, never dropped without a word.
388
+ const flagNotices = [
389
+ compare && requestedView === "auto" ? "--compare implies --view overlap" : "",
390
+ args.options.rank != null && view !== "crowding" ? "--rank orders --view crowding only; ignored here" : "",
391
+ args.options.offset != null && view !== "ticker-holdings" ? "--offset pages a ticker's holders only; ignored here" : "",
392
+ query && (view === "latest" || view === "performance") ? `--view ${view} lists every manager; "${query}" is not used` : "",
393
+ ].filter(Boolean);
295
394
  const limit = Number(args.options.limit);
296
395
  if (view === "overlap") {
396
+ if (!compare) throw new Error(`13F overlap compares two holdings: add --compare <fund name, CIK or ETF ticker>, as in fn 13F ${query || "<fund or CIK>"} --compare SPY.`);
397
+ if (!query) throw new Error("13F overlap needs a fund name or CIK first: fn 13F <fund or CIK> --compare <fund, CIK or ETF ticker>.");
297
398
  const fund = await resolveFund(query, args, ctx, dependencies);
298
- const other = await resolveFund(String(args.options.compare ?? ""), args, ctx, dependencies);
399
+ const other = await resolveComparison(compare, args, ctx, dependencies);
400
+ if (other.kind === "etf") {
401
+ const [first, etf] = await Promise.all([dependencies.loadDetail(fund.cik, fund.name, args, ctx), dependencies.loadEtfHoldings(other.ticker, ctx)]);
402
+ const overlap = buildManagerEtfOverlap(first, etf.members);
403
+ const period = first.latestForm?.periodOfReport ?? null;
404
+ const filed = first.latestForm?.filedAsOfDate ?? null;
405
+ const rows = overlap?.rows ?? [];
406
+ const cut = cutText(rows.length, limit, "positions");
407
+ const missing = overlap?.missing ?? [];
408
+ const missingNames = missing.slice(0, 5).map((row) => `${row.ticker || row.issuer} ${weight(row.weight)}`).join(", ");
409
+ const leftOut = overlap ? [overlap.leftOut.options ? `${overlap.leftOut.options} option line${overlap.leftOut.options === 1 ? "" : "s"}` : "", overlap.leftOut.principal ? `${overlap.leftOut.principal} principal-amount line${overlap.leftOut.principal === 1 ? "" : "s"}` : ""].filter(Boolean) : [];
410
+ const etfWeight = (value: unknown, row: Record<string, unknown>) => row.etfWeight == null ? "no ticker" : value === 0 ? "not held" : weight(value);
411
+ return {
412
+ columns: [{ key: "ticker", header: "Ticker" }, { key: "issuer", header: "Issuer" }, { key: "weight", header: "13F weight", align: "right", format: weight }, { key: "etfWeight", header: `${other.symbol} weight`, align: "right", format: etfWeight }, { key: "shared", header: "Shared", align: "right", format: weight }],
413
+ rows: rows.slice(0, limit).map((row) => ({ ...row })),
414
+ errors: [
415
+ ...(first.warnings ?? []),
416
+ ...(first.latestReport?.complete === false ? [`The 13F for ${period} did not load completely; weights cover the lines that did.`] : []),
417
+ ...(etf.stale ? [`The ${other.ticker} holdings file is stale.`] : []),
418
+ ...(!overlap ? ["No share positions or ETF weights to compare."] : []),
419
+ ],
420
+ freshness: { source: "SEC EDGAR and Gloom Cloud", ...(period ? { asOf: period } : {}) },
421
+ metadata: {
422
+ view, comparedWith: "etf", firstFund: first.name, cik: first.cik, secondFund: other.symbol,
423
+ etf: { symbol: other.symbol, ticker: other.ticker, name: other.name, asOf: etf.asOf },
424
+ comparedPeriod: period, filed,
425
+ overlap: overlap?.overlap ?? null, activeShare: overlap?.activeShare ?? null,
426
+ missing: missing.map((row) => ({ ticker: row.ticker || null, issuer: row.issuer, weight: row.weight, reason: row.etfWeight == null ? "no ticker" : "not held" })),
427
+ missingWeight: overlap?.missingWeight ?? null,
428
+ leftOut: overlap?.leftOut ?? null,
429
+ shown: Math.min(rows.length, limit), total: rows.length, truncated: rows.length > limit,
430
+ notices: [
431
+ ...flagNotices,
432
+ `${other.symbol} read as an ETF: ${other.name} holdings${other.ticker !== other.symbol ? ` (${other.ticker} file)` : ""}, as fn MEMB ${other.symbol} shows`,
433
+ ...(overlap ? [`Overlap ${percentText(overlap.overlap)} (sum of the smaller weight per name) | Active share ${percentText(overlap.activeShare)}`] : []),
434
+ [
435
+ period ? `Quarter compared: ${filingDayText(period)}${filed ? `, filed ${filingDayText(filed)}` : ""}` : "",
436
+ `${other.symbol} holdings as of ${filingDayText(etf.asOf.slice(0, 10))}`,
437
+ leftOut.length ? `13F weights leave out ${leftOut.join(" and ")}` : "",
438
+ ].filter(Boolean).join(" | "),
439
+ ...(overlap ? [missing.length ? `Not in ${other.symbol}: ${missing.length} of ${rows.length} positions, ${percentText(overlap.missingWeight)} of the 13F | ${missingNames}${missing.length > 5 ? ", ..." : ""}` : `${other.symbol} holds every position in the 13F`] : []),
440
+ ...(cut ? [`${cut[0]!.toUpperCase()}${cut.slice(1)}`] : []),
441
+ ].filter(Boolean),
442
+ },
443
+ };
444
+ }
299
445
  const [first, second] = await Promise.all([dependencies.loadDetail(fund.cik, fund.name, args, ctx), dependencies.loadDetail(other.cik, other.name, args, ctx)]);
300
446
  const comparedPeriod = overlapPeriod(first, second);
301
447
  const rows = buildFundOverlap(first, second);
302
448
  const cut = cutText(rows.length, limit, "positions");
303
- return { columns: [{ key: "ticker", header: "Ticker" }, { key: "type", header: "Type" }, { key: "issuer", header: "Issuer" }, { key: "weight", header: "First weight", align: "right", format: weight }, { key: "comparedWeight", header: "Second weight", align: "right", format: weight }], rows: rows.slice(0, limit).map(row => ({ ...row })), errors: [...(first.warnings ?? []), ...(second.warnings ?? []), ...(!comparedPeriod ? ["No reporting quarter is loaded for both funds."] : [])], metadata: { view, firstFund: first.name, secondFund: second.name, firstPeriod: first.latestForm?.periodOfReport ?? null, secondPeriod: second.latestForm?.periodOfReport ?? null, comparedPeriod, shown: Math.min(rows.length, limit), total: rows.length, truncated: rows.length > limit, notices: [[comparedPeriod ? `Quarter compared: ${comparedPeriod}` : "", cut].filter(Boolean).join(" | ")].filter(Boolean) } };
449
+ const read = `${compare} read as the 13F manager ${second.name} (CIK ${second.cik})`;
450
+ return { columns: [{ key: "ticker", header: "Ticker" }, { key: "type", header: "Type" }, { key: "issuer", header: "Issuer" }, { key: "weight", header: "First weight", align: "right", format: weight }, { key: "comparedWeight", header: "Second weight", align: "right", format: weight }], rows: rows.slice(0, limit).map(row => ({ ...row })), errors: [...(first.warnings ?? []), ...(second.warnings ?? []), ...(!comparedPeriod ? ["No reporting quarter is loaded for both funds."] : [])], metadata: { view, comparedWith: "fund", firstFund: first.name, secondFund: second.name, firstPeriod: first.latestForm?.periodOfReport ?? null, secondPeriod: second.latestForm?.periodOfReport ?? null, comparedPeriod, shown: Math.min(rows.length, limit), total: rows.length, truncated: rows.length > limit, notices: [...flagNotices, read, [comparedPeriod ? `Quarter compared: ${comparedPeriod}` : "", cut].filter(Boolean).join(" | ")].filter(Boolean) } };
304
451
  }
305
452
  if (view === "crowding") {
306
453
  const { rows: sourceRows, ...metadata } = await loadCrowding(ctx.signal);
@@ -314,7 +461,7 @@ export function createThirteenFHeadless(
314
461
  const columns: HeadlessPaneColumn[] = [{ key: "ticker", header: "Ticker" }, { key: "issuer", header: "Issuer" }, { key: "type", header: "Type" }, { key: "holderCount", header: "Funds", align: "right" }, { key: "newCount", header: "New", align: "right" }, { key: "exitCount", header: "Exits", align: "right" }, { key: "weightChange", header: "Weight change", align: "right", format: weightPoints }, { key: "comparedFunds", header: "Compared", align: "right" }, { key: "totalValue", header: "Value (USD)", align: "right", format: money }];
315
462
  const cut = cutText(rows.length, limit, "securities");
316
463
  return { columns: focus ? [{ key: "rank", header: "Rank", align: "right" }, ...columns] : columns, rows: rows.slice(0, limit).map(row => ({ ...row })),
317
- metadata: { ...metadata, view, rank, ...(ticker ? { ticker, found: rows.length > 0, rankedSecurities: ranked.length } : {}), shown: Math.min(rows.length, limit), total: rows.length, truncated: rows.length > limit, notices: [[sample, cut].filter(Boolean).join(" | "), ...(focus ? [focus.notice] : [])] },
464
+ metadata: { ...metadata, view, rank, ...(ticker ? { ticker, found: rows.length > 0, rankedSecurities: ranked.length } : {}), shown: Math.min(rows.length, limit), total: rows.length, truncated: rows.length > limit, notices: [...flagNotices, [sample, cut].filter(Boolean).join(" | "), ...(focus ? [focus.notice] : [])] },
318
465
  freshness: { asOf: metadata.period }, errors: metadata.warnings };
319
466
  }
320
467
  let holdings: TickerHoldings | null = null;
@@ -336,9 +483,11 @@ export function createThirteenFHeadless(
336
483
  const { rows, ...metadata } = holdings;
337
484
  const offset = Number(args.options.offset ?? 0);
338
485
  const summary = summarizeTickerHoldings({ ...metadata, offset, limit, loaded: rows });
486
+ const shown = rows.slice(0, limit).map(row => ({ ...row }));
339
487
  return {
340
- columns: [{ key: "fund", header: "Fund" }, { key: "cik", header: "CIK" }, { key: "type", header: "Type" }, { key: "value", header: "Value (USD)", align: "right", format: money }, { key: "shares", header: "Shares", align: "right", format: shares }, { key: "weight", header: "13F weight", align: "right", format: weight }, { key: "action", header: "Action" }],
341
- rows: rows.slice(0, limit).map(row => ({ ...row })),
488
+ columns: [{ key: "fund", header: "Fund" }, { key: "cik", header: "CIK" }, TYPE_COLUMN, { key: "value", header: "Value (USD)", align: "right", format: money }, { key: "shares", header: "Shares", align: "right", format: shares }, { key: "weight", header: "13F weight", align: "right", format: weight }, { key: "action", header: "Action" }],
489
+ rows: shown,
490
+ notes: positionNotes(shown),
342
491
  metadata: {
343
492
  ...metadata,
344
493
  view,
@@ -353,7 +502,7 @@ export function createThirteenFHeadless(
353
502
  totalValue: summary.shownValue,
354
503
  valueScope: "shown funds",
355
504
  valueBasis: "as reported at period end",
356
- notices: summary.notices,
505
+ notices: [...flagNotices, ...summary.notices],
357
506
  },
358
507
  freshness: { asOf: metadata.period },
359
508
  errors: metadata.warnings,
@@ -370,6 +519,8 @@ export function createThirteenFHeadless(
370
519
  .slice(0, limit)
371
520
  .map((row) => ({ ...row }));
372
521
  const cut = cutText(all.length, limit, "filings");
522
+ const shownFilings = new Set(rows.map((row) => row.accessionNumber));
523
+ const restated = restatedValuesText(detail.forms.filter((form) => shownFilings.has(form.accessionNumber)));
373
524
  return {
374
525
  columns: FILING_COLUMNS,
375
526
  rows,
@@ -382,7 +533,7 @@ export function createThirteenFHeadless(
382
533
  shown: rows.length,
383
534
  total: all.length,
384
535
  truncated: all.length > limit,
385
- notices: [[`CIK ${detail.cik}`, cut].filter(Boolean).join(" | ")],
536
+ notices: [...flagNotices, [`CIK ${detail.cik}`, cut].filter(Boolean).join(" | "), ...(restated ? [restated] : [])],
386
537
  },
387
538
  };
388
539
  }
@@ -391,7 +542,17 @@ export function createThirteenFHeadless(
391
542
  DEFAULT_HOLDING_SORT,
392
543
  );
393
544
  const previousPeriod = detail.previousForm?.periodOfReport ?? null;
545
+ const comparable = hasComparable13FQuarter(detail);
546
+ const filed = detail.latestForm?.filedAsOfDate || null;
547
+ const quartersBehind = quartersBehindLatest(latestPeriod);
394
548
  const cut = cutText(all.length, limit, "positions, exits included");
549
+ // Values, weights and Est P&L read both compared quarters' filings.
550
+ const reportForms = (report: typeof detail.latestReport, form: typeof detail.latestForm) =>
551
+ report?.filings ?? (form ? [form] : []);
552
+ const restated = restatedValuesText([
553
+ ...reportForms(detail.latestReport, detail.latestForm),
554
+ ...(comparable ? reportForms(detail.previousReport, detail.previousForm) : []),
555
+ ]);
395
556
  const rows = all
396
557
  .slice(0, limit)
397
558
  .map((row) => ({
@@ -403,22 +564,33 @@ export function createThirteenFHeadless(
403
564
  columns: HOLDING_COLUMNS,
404
565
  rows,
405
566
  ...(detail.warnings?.length ? { errors: detail.warnings } : {}),
406
- // Positions as of the quarter they report; the rows carry no filing date.
407
- ...(latestPeriod ? { freshness: { asOf: latestPeriod } } : {}),
567
+ notes: positionNotes(rows),
568
+ // Dated by the filing that made the positions public, with the quarter they report beside it.
569
+ ...(latestPeriod ? { freshness: {
570
+ asOf: filed ?? latestPeriod,
571
+ basis: `13F filing for the quarter ended ${filingDayText(latestPeriod)}`,
572
+ } } : {}),
408
573
  metadata: {
409
574
  view,
410
575
  cik: detail.cik,
411
576
  fund: detail.name,
412
577
  latestPeriod,
578
+ latestFiled: filed,
579
+ filingLagDays: filingLagDays(latestPeriod, filed),
580
+ quartersBehind,
413
581
  previousPeriod,
414
582
  shown: rows.length,
415
583
  total: all.length,
416
584
  truncated: all.length > limit,
417
585
  notices: [
418
- [`CIK ${detail.cik}`, periodText(latestPeriod, hasComparable13FQuarter(detail) ? previousPeriod : null), AS_FILED_VALUE].filter(Boolean).join(" | "),
586
+ ...flagNotices,
587
+ [`CIK ${detail.cik}`, filedPeriodText(latestPeriod, filed, comparable ? previousPeriod : null)].filter(Boolean).join(" | "),
588
+ AS_FILED_VALUE,
589
+ ...(restated ? [restated] : []),
590
+ ...(isStaleFiling(quartersBehind) ? [staleFilingText(quartersBehind)] : []),
419
591
  ...(cut ? [`${cut[0]!.toUpperCase()}${cut.slice(1)}`] : []),
420
592
  ],
421
- comparisonAvailable: hasComparable13FQuarter(detail),
593
+ comparisonAvailable: comparable,
422
594
  currentFilings: detail.latestReport?.filings.map((form) => form.accessionNumber) ?? [],
423
595
  previousFilings: detail.previousReport?.filings.map((form) => form.accessionNumber) ?? [],
424
596
  currentReportedValue: detail.latestReport?.complete ? detail.latestReport.tableValueTotal : null,
@@ -432,11 +604,18 @@ export function createThirteenFHeadless(
432
604
  const tab = browserTab(view === "ticker-holdings" ? requestedView : view, query);
433
605
  const result = await dependencies.loadBrowser(tab, query, limit, args, ctx);
434
606
  const more = result.hasMore || result.rows.length > limit;
607
+ const browserRows = sortBrowserRows(result.rows, browserSortFor(DEFAULT_BROWSER_SORT, tab)).slice(0, limit);
608
+ // A search finds managers that stopped filing; say which, since the Period column alone reads like any other.
609
+ const stale = tab === "funds"
610
+ ? browserRows.flatMap((row) => {
611
+ const quarters = quartersBehindLatest(row.periodOfReport);
612
+ return isStaleFiling(quarters) ? [{ name: row.name, quarters }] : [];
613
+ })
614
+ : [];
435
615
  return {
436
616
  columns: result.rows[0]?.priorReturns?.length ? [...BROWSER_COLUMNS.filter(column => !["filedAsOfDate", "tableEntryTotal"].includes(column.key)), ...result.rows[0].priorReturns.map((point, index) => ({ key: `return${index + 1}`, header: point.quarter, align: "right" as const, format: (value: unknown) => formatRawPercentMaybe(typeof value === "number" ? value : null) }))]
437
617
  : tab === "performance" ? BROWSER_COLUMNS : BROWSER_COLUMNS.filter(column => column.key !== "estQuarterReturn"),
438
- rows: sortBrowserRows(result.rows, browserSortFor(DEFAULT_BROWSER_SORT, tab))
439
- .slice(0, limit)
618
+ rows: browserRows
440
619
  .map((row) => ({ ...row, ...Object.fromEntries((row.priorReturns ?? []).map((point, index) => [`return${index + 1}`, point.value])) })),
441
620
  ...(result.warning ? { errors: [result.warning] } : {}),
442
621
  metadata: {
@@ -447,9 +626,11 @@ export function createThirteenFHeadless(
447
626
  hasMore: result.hasMore ?? false,
448
627
  shown: Math.min(result.rows.length, limit),
449
628
  truncated: more,
450
- notices: more
451
- ? [[`Showing the first ${Math.min(result.rows.length, limit)}`, limit < THIRTEENF_MAX_LIMIT ? `more: --limit ${THIRTEENF_MAX_LIMIT}` : ""].filter(Boolean).join(" | ")]
452
- : [],
629
+ notices: [
630
+ ...flagNotices,
631
+ ...(more ? [[`Showing the first ${Math.min(result.rows.length, limit)}`, limit < THIRTEENF_MAX_LIMIT ? `more: --limit ${THIRTEENF_MAX_LIMIT}` : ""].filter(Boolean).join(" | ")] : []),
632
+ ...(stale.length ? [staleFundsText(stale)] : []),
633
+ ],
453
634
  },
454
635
  };
455
636
  },
@@ -26,7 +26,6 @@ import type {
26
26
 
27
27
  export const THIRTEENF_PANE_ID = "thirteenf-funds";
28
28
  export const THIRTEENF_TEMPLATE_ID = "thirteenf-funds-pane";
29
- export const THIRTEENF_OPTIONS_NOTE = "Option values and shares refer to the underlying; 13F % is share of reported value.";
30
29
 
31
30
  export const FUND_DETAIL_TABS: Array<{ label: string; value: ThirteenFDetailTab }> = [
32
31
  { label: "Holdings", value: "holdings" },
@@ -96,6 +95,45 @@ export function latestLikely13FQuarter(now = new Date()): string {
96
95
  return "";
97
96
  }
98
97
 
98
+ function quarterIndex(period: string): number | null {
99
+ const match = /^(\d{4})-(\d{2})-\d{2}$/.exec(period) ?? /^(\d{4})Q([1-4])$/.exec(period);
100
+ if (!match) return null;
101
+ const year = Number(match[1]);
102
+ const part = Number(match[2]);
103
+ return year * 4 + (period.includes("Q") ? part - 1 : Math.floor((part - 1) / 3));
104
+ }
105
+
106
+ /**
107
+ * How many quarters a fund's latest report period trails the latest quarter
108
+ * filers have had time to report (`latestLikely13FQuarter`); 0 when it is
109
+ * current or ahead, null without a readable period.
110
+ */
111
+ export function quartersBehindLatest(period: string | null | undefined, now = new Date()): number | null {
112
+ const latest = quarterIndex(latestLikely13FQuarter(now));
113
+ const own = period ? quarterIndex(period) : null;
114
+ return latest == null || own == null ? null : Math.max(0, latest - own);
115
+ }
116
+
117
+ /**
118
+ * The fund search lists a manager once for each name it has filed under
119
+ * ("PERSHING SQUARE HOLDCO, L.P." and "PERSHING SQUARE INC." share a CIK).
120
+ * One row per CIK: a renamed manager takes the name on its latest loaded
121
+ * filing, else the longest of its names.
122
+ */
123
+ export function oneFundPerCik(
124
+ funds: readonly ThirteenFFund[],
125
+ reports?: ReadonlyMap<string, ThirteenFPeriodReport>,
126
+ ): ThirteenFFund[] {
127
+ const byCik = new Map<string, ThirteenFFund[]>();
128
+ for (const fund of funds) byCik.set(fund.cik, [...(byCik.get(fund.cik) ?? []), fund]);
129
+ return [...byCik.values()].map((names) => {
130
+ if (names.length === 1) return names[0]!;
131
+ const filed = reports?.get(names[0]!.cik)?.filings.at(-1)?.companyName;
132
+ const longest = names.reduce((best, fund) => (fund.name.length > best.name.length ? fund : best));
133
+ return { ...longest, name: filed || longest.name };
134
+ });
135
+ }
136
+
99
137
  export function buildBrowserRows(options: {
100
138
  funds?: ThirteenFFund[];
101
139
  topFunds?: ThirteenFTopFund[];
@@ -34,6 +34,81 @@ function atPeriod(data: FundDetailData, period: string): FundDetailData | null {
34
34
  return { ...data, latestForm: data.previousForm, latestReport: data.previousReport, latestHoldings: data.previousHoldings, previousForm: null, previousReport: undefined, previousHoldings: [] };
35
35
  }
36
36
 
37
+ /** One line of an ETF's holdings file, as MEMB lists it: weight is a fraction of the fund. */
38
+ export interface EtfHoldingLine {
39
+ symbol: string | null;
40
+ weight: number | null;
41
+ }
42
+
43
+ interface ManagerEtfRow {
44
+ id: string;
45
+ ticker: string;
46
+ issuer: string;
47
+ /** Share of the manager's 13F share positions. */
48
+ weight: number;
49
+ /** Share of the ETF: 0 when it does not hold the name, null when the 13F line has no ticker to match. */
50
+ etfWeight: number | null;
51
+ /** The smaller of the two weights: how much of this position the ETF already holds. */
52
+ shared: number;
53
+ }
54
+
55
+ export interface ManagerEtfOverlap {
56
+ /** The manager's share positions, largest first. */
57
+ rows: ManagerEtfRow[];
58
+ /** Sum of the smaller weight per name. */
59
+ overlap: number;
60
+ /** Half the summed absolute weight differences over every name either holds. */
61
+ activeShare: number;
62
+ /** The manager's positions the ETF does not hold, or that have no ticker to match, largest first. */
63
+ missing: ManagerEtfRow[];
64
+ missingWeight: number;
65
+ /** 13F lines left out of the weights: options, and principal amounts that are not shares. */
66
+ leftOut: { options: number; principal: number };
67
+ }
68
+
69
+ /** BRK.B in a 13F and BRK-B in a holdings file are one share class. */
70
+ const symbolKey = (symbol: string) => symbol.trim().toUpperCase().replace(/[./\s]+/g, "-");
71
+
72
+ /**
73
+ * A manager's latest 13F against an ETF's holdings file. The manager's weights
74
+ * cover its share positions (options and principal amounts left out), the
75
+ * ETF's its whole file (cash and lines without a ticker included), so both sum
76
+ * to one and active share is one minus the overlap.
77
+ */
78
+ export function buildManagerEtfOverlap(manager: FundDetailData, etf: readonly EtfHoldingLine[]): ManagerEtfOverlap | null {
79
+ const lines = buildFundHoldingRows(manager).filter((row) => row.action !== "exit" && row.value != null && row.value > 0);
80
+ const leftOut = { options: 0, principal: 0 };
81
+ const positions = new Map<string, { id: string; ticker: string; issuer: string; value: number }>();
82
+ for (const row of lines) {
83
+ if (row.putCall) { leftOut.options += 1; continue; }
84
+ if (row.shareType.toUpperCase() === "PRN") { leftOut.principal += 1; continue; }
85
+ const key = row.ticker ? symbolKey(row.ticker) : `cusip:${row.cusip || row.id}`;
86
+ const position = positions.get(key);
87
+ if (position) position.value += row.value!;
88
+ else positions.set(key, { id: row.id, ticker: row.ticker, issuer: row.issuer, value: row.value! });
89
+ }
90
+ const total = [...positions.values()].reduce((sum, row) => sum + row.value, 0);
91
+ const etfWeights = new Map<string, number>();
92
+ let etfTotal = 0;
93
+ for (const line of etf) {
94
+ if (line.weight == null || !Number.isFinite(line.weight) || line.weight <= 0) continue;
95
+ etfTotal += line.weight;
96
+ if (line.symbol) etfWeights.set(symbolKey(line.symbol), (etfWeights.get(symbolKey(line.symbol)) ?? 0) + line.weight);
97
+ }
98
+ if (!(total > 0) || !(etfTotal > 0)) return null;
99
+ const rows = [...positions].map(([key, row]): ManagerEtfRow => {
100
+ const weight = row.value / total;
101
+ const etfWeight = row.ticker ? (etfWeights.get(key) ?? 0) / etfTotal : null;
102
+ return { id: row.id, ticker: row.ticker, issuer: row.issuer, weight, etfWeight, shared: Math.min(weight, etfWeight ?? 0) };
103
+ }).sort((a, b) => b.weight - a.weight);
104
+ const overlap = rows.reduce((sum, row) => sum + row.shared, 0);
105
+ // The ETF's weight in names the manager does not hold, cash and untickered lines included.
106
+ const etfOnly = 1 - rows.reduce((sum, row) => sum + (row.etfWeight ?? 0), 0);
107
+ const activeShare = (rows.reduce((sum, row) => sum + Math.abs(row.weight - (row.etfWeight ?? 0)), 0) + Math.max(0, etfOnly)) / 2;
108
+ const missing = rows.filter((row) => !row.etfWeight);
109
+ return { rows, overlap, activeShare, missing, missingWeight: missing.reduce((sum, row) => sum + row.weight, 0), leftOut };
110
+ }
111
+
37
112
  export function buildFundOverlap(first: FundDetailData, second: FundDetailData): FundOverlapRow[] {
38
113
  const period = overlapPeriod(first, second);
39
114
  const left = period ? atPeriod(first, period) : null;
@@ -46,12 +46,14 @@ import {
46
46
  buildTimelineColumns,
47
47
  buildTimelineRows,
48
48
  inferBrowserTabFromQuery,
49
+ quartersBehindLatest,
49
50
  selectedIndexById,
50
51
  sortBrowserRows,
51
52
  sortFilingPositionRows,
52
53
  sortHoldingRows,
53
54
  sortTimelineRows,
54
55
  } from "./model";
56
+ import { isOptionType, isStaleFiling, quartersOldText } from "./report-notes";
55
57
  import {
56
58
  renderBrowserCell,
57
59
  renderFilingPositionCell,
@@ -479,15 +481,22 @@ export function FundDetailView({
479
481
  }
480
482
  });
481
483
 
484
+ const quartersBehind = quartersBehindLatest(data?.latestForm?.periodOfReport);
485
+ const staleFiling = isStaleFiling(quartersBehind);
482
486
  const holdingStats: StatItem[] = [
483
487
  { id: "reported", label: "Reported", value: data?.latestForm?.periodOfReport ?? "--",
484
- detail: `filed ${data?.latestForm?.filedAsOfDate || "--"}${data?.latestForm && amendmentKind(data.latestForm) === "restatement" ? ", restated" : ""}` },
488
+ detail: `filed ${data?.latestForm?.filedAsOfDate || "--"}${data?.latestForm && amendmentKind(data.latestForm) === "restatement" ? ", restated" : ""}${staleFiling ? `, ${quartersOldText(quartersBehind)}` : ""}`,
489
+ ...(staleFiling ? { tone: "warning" as const } : {}) },
485
490
  data && hasComparable13FQuarter(data)
486
491
  ? { id: "compared", label: "Compared with", value: data.previousForm!.periodOfReport }
487
492
  : { id: "compared", label: "Compared with", value: "No prior quarter", tone: "muted" },
488
493
  ...(data?.latestReport && data.latestReport.filings.length > 1
489
494
  ? [{ id: "combined", label: "Combined", value: `${data.latestReport.filings.length} filings` }]
490
495
  : []),
496
+ // The value basis of option rows, like a unit: only for a fund that holds them.
497
+ ...(holdingRows.some((row) => isOptionType(row.putCall))
498
+ ? [{ id: "options", label: "CALL/PUT", value: "underlying value", tone: "muted" as const }]
499
+ : []),
491
500
  ];
492
501
 
493
502
  usePaneNoticeFooter({