@digithings-ai/ui 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (424) hide show
  1. package/README.md +48 -2
  2. package/package.json +143 -4
  3. package/src/components/NavShell.tsx +776 -0
  4. package/src/components/SocialRow.tsx +87 -0
  5. package/src/components/Spinner.tsx +27 -0
  6. package/src/components/StackLogo.tsx +40 -0
  7. package/src/components/Terminal.tsx +110 -0
  8. package/src/components/TerminalManifest.tsx +212 -0
  9. package/src/components/ThemeProvider.tsx +271 -0
  10. package/src/components/account/AuthCard.tsx +309 -0
  11. package/src/components/assistant-ui/elements/mermaid-diagram.aui.tsx +63 -0
  12. package/src/components/assistant-ui/elements/mermaid-diagram.tsx +340 -0
  13. package/src/components/brand/BrandWordmark.tsx +32 -0
  14. package/src/components/changelog/ReleaseRail.tsx +81 -0
  15. package/src/components/changelog/index.ts +1 -0
  16. package/src/components/chat/ChatCodeBlock.tsx +67 -0
  17. package/src/components/chat/ChatMarkdown.tsx +66 -0
  18. package/src/components/chat/ChatMarkdownSource.tsx +203 -0
  19. package/src/components/chat/ChatMermaidBlock.tsx +202 -0
  20. package/src/components/chat/ChatMessage.tsx +77 -0
  21. package/src/components/chat/ChatPlayback.tsx +422 -0
  22. package/src/components/chat/ChatStreamCursor.tsx +25 -0
  23. package/src/components/chat/ChatThinking.tsx +113 -0
  24. package/src/components/chat/ChatToolCall.tsx +190 -0
  25. package/src/components/chat/ChatTranscript.tsx +60 -0
  26. package/src/components/chat/ChatWidgetFrame.tsx +107 -0
  27. package/src/components/chat/DigichatBootLoader.tsx +683 -0
  28. package/src/components/chat/DigichatLauncher.tsx +361 -0
  29. package/src/components/chat/DigichatThread.tsx +118 -0
  30. package/src/components/chat/DigichatThreadList.tsx +54 -0
  31. package/src/components/chat/DigichatWordmark.tsx +24 -0
  32. package/src/components/chat/DotMatrix.tsx +650 -0
  33. package/src/components/chat/boot-lab.tsx +766 -0
  34. package/src/components/chat/boot-signal.ts +144 -0
  35. package/src/components/chat/chat-surfaces.ts +52 -0
  36. package/src/components/chat/connection-status.ts +40 -0
  37. package/src/components/chat/digichat-wordmark.ts +355 -0
  38. package/src/components/chat/disclosure-chevron.tsx +49 -0
  39. package/src/components/chat/followable-href.ts +9 -0
  40. package/src/components/chat/gallery-thread/action-icons.tsx +25 -0
  41. package/src/components/chat/gallery-thread/attachment.aui.tsx +262 -0
  42. package/src/components/chat/gallery-thread/block-caret.tsx +439 -0
  43. package/src/components/chat/gallery-thread/cn.ts +1 -0
  44. package/src/components/chat/gallery-thread/composer-keyboard.ts +106 -0
  45. package/src/components/chat/gallery-thread/composer-trigger-popover.aui.tsx +235 -0
  46. package/src/components/chat/gallery-thread/css.d.ts +6 -0
  47. package/src/components/chat/gallery-thread/file.tsx +238 -0
  48. package/src/components/chat/gallery-thread/follow-up-suggestions.aui.tsx +92 -0
  49. package/src/components/chat/gallery-thread/format-json-dump.ts +112 -0
  50. package/src/components/chat/gallery-thread/hooks/use-attachment-src.ts +46 -0
  51. package/src/components/chat/gallery-thread/hooks/use-copy-to-clipboard.ts +9 -0
  52. package/src/components/chat/gallery-thread/image.tsx +519 -0
  53. package/src/components/chat/gallery-thread/markdown-text.tsx +278 -0
  54. package/src/components/chat/gallery-thread/message-error.aui.tsx +105 -0
  55. package/src/components/chat/gallery-thread/message-timing.aui.tsx +143 -0
  56. package/src/components/chat/gallery-thread/private-work-step.tsx +188 -0
  57. package/src/components/chat/gallery-thread/reasoning.tsx +332 -0
  58. package/src/components/chat/gallery-thread/scroll-mode.ts +174 -0
  59. package/src/components/chat/gallery-thread/source.tsx +76 -0
  60. package/src/components/chat/gallery-thread/thread.aui.tsx +1619 -0
  61. package/src/components/chat/gallery-thread/tooltip-icon-button.tsx +53 -0
  62. package/src/components/chat/gallery-thread/typed-welcome-copy.tsx +18 -0
  63. package/src/components/chat/gallery-thread/ui/tooltip.tsx +22 -0
  64. package/src/components/chat/gallery-thread/work-chain-summary.tsx +48 -0
  65. package/src/components/chat/gallery-thread/work-chain.tsx +110 -0
  66. package/src/components/chat/gallery-thread/work-status.ts +66 -0
  67. package/src/components/chat/overlay-scrollbar.tsx +86 -0
  68. package/src/components/chat/sanitize-mermaid-svg.ts +38 -0
  69. package/src/components/chat/skins/SOURCE.md +36 -0
  70. package/src/components/chat/skins/base/attachment.aui.tsx +287 -0
  71. package/src/components/chat/skins/base/aui-default/README.md +45 -0
  72. package/src/components/chat/skins/base/aui-default/collapsible-root.tsx +19 -0
  73. package/src/components/chat/skins/base/aui-default/collapsible.tsx +21 -0
  74. package/src/components/chat/skins/base/aui-default/reasoning.aui.tsx +120 -0
  75. package/src/components/chat/skins/base/aui-default/reasoning.tsx +331 -0
  76. package/src/components/chat/skins/base/aui-default/surfaces.ts +7 -0
  77. package/src/components/chat/skins/base/aui-default/tool-fallback.aui.tsx +772 -0
  78. package/src/components/chat/skins/base/aui-default/tool-group.aui.tsx +241 -0
  79. package/src/components/chat/skins/base/docs-model-options.ts +6 -0
  80. package/src/components/chat/skins/base/elements/assistant-trace.aui.tsx +169 -0
  81. package/src/components/chat/skins/base/elements/composer-trigger-popover.aui.tsx +271 -0
  82. package/src/components/chat/skins/base/elements/directive-text.aui.tsx +29 -0
  83. package/src/components/chat/skins/base/elements/directive-text.tsx +76 -0
  84. package/src/components/chat/skins/base/elements/message-timing.aui.tsx +104 -0
  85. package/src/components/chat/skins/base/elements/model-selector.aui.tsx +140 -0
  86. package/src/components/chat/skins/base/elements/model-selector.tsx +720 -0
  87. package/src/components/chat/skins/base/elements/quote.aui.tsx +290 -0
  88. package/src/components/chat/skins/base/elements/work-chain.tsx +100 -0
  89. package/src/components/chat/skins/base/markdown-text.tsx +294 -0
  90. package/src/components/chat/skins/base/model.ts +1 -0
  91. package/src/components/chat/skins/base/thread.tsx +1050 -0
  92. package/src/components/chat/skins/base/tooltip-icon-button.tsx +56 -0
  93. package/src/components/chat/skins/base/ui/avatar.tsx +115 -0
  94. package/src/components/chat/skins/base/ui/badge.tsx +51 -0
  95. package/src/components/chat/skins/base/ui/button.tsx +67 -0
  96. package/src/components/chat/skins/base/ui/command.tsx +185 -0
  97. package/src/components/chat/skins/base/ui/dialog.tsx +168 -0
  98. package/src/components/chat/skins/base/ui/dot-matrix.tsx +267 -0
  99. package/src/components/chat/skins/base/ui/popover.tsx +97 -0
  100. package/src/components/chat/skins/base/ui/skeleton.tsx +20 -0
  101. package/src/components/chat/skins/base/ui/textarea.tsx +24 -0
  102. package/src/components/chat/skins/base/ui/tooltip.tsx +73 -0
  103. package/src/components/chat/skins/base-assistant-ui/config-provider.tsx +90 -0
  104. package/src/components/chat/skins/base-assistant-ui/defaults.ts +419 -0
  105. package/src/components/chat/skins/base-assistant-ui/index.tsx +44 -0
  106. package/src/components/chat/skins/chatgpt.tsx +448 -0
  107. package/src/components/chat/skins/claude.tsx +380 -0
  108. package/src/components/chat/skins/digichat-composer-toolbar.tsx +151 -0
  109. package/src/components/chat/skins/digichat-context-meter-shares.ts +158 -0
  110. package/src/components/chat/skins/digichat-context-meter.tsx +243 -0
  111. package/src/components/chat/skins/digichat-meter-tone.ts +26 -0
  112. package/src/components/chat/skins/digichat-usage-meter.tsx +103 -0
  113. package/src/components/chat/skins/digichat.tsx +144 -0
  114. package/src/components/chat/skins/expo-react-native.tsx +29 -0
  115. package/src/components/chat/skins/gemini.tsx +322 -0
  116. package/src/components/chat/skins/grok-icon.tsx +34 -0
  117. package/src/components/chat/skins/grok.tsx +369 -0
  118. package/src/components/chat/skins/index.ts +46 -0
  119. package/src/components/chat/skins/perplexity.tsx +462 -0
  120. package/src/components/chat/skins/product-page-assistant/assistant-modal.tsx +73 -0
  121. package/src/components/chat/skins/product-page-assistant/index.tsx +19 -0
  122. package/src/components/chat/skins/product-page-assistant/product-dashboard.tsx +164 -0
  123. package/src/components/chat/skins/react-ink.tsx +97 -0
  124. package/src/components/chat/skins/thread-skin-host-contract.ts +102 -0
  125. package/src/components/chat/skins/thread-skin-view.tsx +156 -0
  126. package/src/components/chat/skins/thread-skins.ts +143 -0
  127. package/src/components/chat/skins/tooltip-icon-button.tsx +35 -0
  128. package/src/components/chat/skins/ui/dropdown-menu.tsx +272 -0
  129. package/src/components/chat/skins/webpage-assistant/assistant-config.ts +238 -0
  130. package/src/components/chat/skins/webpage-assistant/assistant-modal.tsx +78 -0
  131. package/src/components/chat/skins/webpage-assistant/config-provider.tsx +132 -0
  132. package/src/components/chat/skins/webpage-assistant/docs-app.tsx +106 -0
  133. package/src/components/chat/skins/webpage-assistant/docs-article.tsx +109 -0
  134. package/src/components/chat/skins/webpage-assistant/docs-assistant.tsx +73 -0
  135. package/src/components/chat/skins/webpage-assistant/docs-nav.tsx +81 -0
  136. package/src/components/chat/skins/webpage-assistant/host-ui.ts +79 -0
  137. package/src/components/chat/skins/webpage-assistant/index.tsx +12 -0
  138. package/src/components/chat/skins/webpage-assistant/markdown-page.tsx +11 -0
  139. package/src/components/chat/skins/webpage-assistant/pages.ts +9 -0
  140. package/src/components/chat/skins/webpage-assistant/types.ts +178 -0
  141. package/src/components/chat/skins/webpage-assistant/use-mobile.ts +19 -0
  142. package/src/components/chat/stock/SOURCE.md +90 -0
  143. package/src/components/chat/stock/artifacts-panel.tsx +305 -0
  144. package/src/components/chat/stock/attachment.aui.tsx +280 -0
  145. package/src/components/chat/stock/chat-notice.tsx +143 -0
  146. package/src/components/chat/stock/chat-private-mode.tsx +64 -0
  147. package/src/components/chat/stock/deploy-ui-context.tsx +89 -0
  148. package/src/components/chat/stock/embed-chat-prefs.tsx +471 -0
  149. package/src/components/chat/stock/file.tsx +265 -0
  150. package/src/components/chat/stock/follow-up-suggestions.aui.tsx +83 -0
  151. package/src/components/chat/stock/image.tsx +531 -0
  152. package/src/components/chat/stock/index.ts +129 -0
  153. package/src/components/chat/stock/json-view.tsx +140 -0
  154. package/src/components/chat/stock/markdown-text.tsx +319 -0
  155. package/src/components/chat/stock/message-error.aui.tsx +96 -0
  156. package/src/components/chat/stock/message-export-menu.tsx +156 -0
  157. package/src/components/chat/stock/palette-row-preview.tsx +26 -0
  158. package/src/components/chat/stock/reasoning.aui.tsx +120 -0
  159. package/src/components/chat/stock/reasoning.tsx +335 -0
  160. package/src/components/chat/stock/skin-chrome.tsx +81 -0
  161. package/src/components/chat/stock/skin-credit.tsx +63 -0
  162. package/src/components/chat/stock/skin-palette-bridge.tsx +235 -0
  163. package/src/components/chat/stock/skin-palette-context.ts +16 -0
  164. package/src/components/chat/stock/skin-runtime.tsx +52 -0
  165. package/src/components/chat/stock/skin-slash-palette.tsx +393 -0
  166. package/src/components/chat/stock/skin-types.ts +217 -0
  167. package/src/components/chat/stock/stock-chat-prefs-host.tsx +501 -0
  168. package/src/components/chat/stock/stock-send-gate.tsx +94 -0
  169. package/src/components/chat/stock/stock-shape.tsx +39 -0
  170. package/src/components/chat/stock/thread.aui.tsx +645 -0
  171. package/src/components/chat/stock/tool-display.ts +6 -0
  172. package/src/components/chat/stock/tool-fallback.aui.tsx +866 -0
  173. package/src/components/chat/stock/tool-group.aui.tsx +244 -0
  174. package/src/components/chat/stock/tool-surface.ts +120 -0
  175. package/src/components/chat/stock/tooltip-icon-button.tsx +49 -0
  176. package/src/components/chat/stock/ui/avatar.tsx +108 -0
  177. package/src/components/chat/stock/ui/button.tsx +81 -0
  178. package/src/components/chat/stock/ui/collapsible.tsx +21 -0
  179. package/src/components/chat/stock/ui/dialog.tsx +163 -0
  180. package/src/components/chat/stock/ui/skeleton.tsx +13 -0
  181. package/src/components/chat/stock/ui/textarea.tsx +20 -0
  182. package/src/components/chat/stock/ui/tooltip.tsx +68 -0
  183. package/src/components/chat/stock/use-attachment-src.ts +42 -0
  184. package/src/components/chat/stock/use-copy-to-clipboard.ts +29 -0
  185. package/src/components/chat/strip-model-boilerplate.ts +42 -0
  186. package/src/components/chat/suggestion-cycle.tsx +230 -0
  187. package/src/components/chat/suggestion-scroll-row.tsx +81 -0
  188. package/src/components/chat/trace-grouping/chain-group-by.ts +44 -0
  189. package/src/components/chat/trace-grouping/chain-state.ts +141 -0
  190. package/src/components/chat/trace-grouping/index.ts +32 -0
  191. package/src/components/chat/trace-grouping/tool-row.ts +74 -0
  192. package/src/components/chat/trace-grouping/use-deploy-work-disclosure.ts +35 -0
  193. package/src/components/chat/trace-grouping/use-work-chain.ts +103 -0
  194. package/src/components/chat/trace-i18n/core.ts +48 -0
  195. package/src/components/chat/trace-i18n/index.tsx +23 -0
  196. package/src/components/chat/trace-i18n/locales/en.ts +24 -0
  197. package/src/components/chat/trace-i18n/locales/fr.ts +28 -0
  198. package/src/components/chat/trace-i18n/types.ts +35 -0
  199. package/src/components/chat/trace-spacing.ts +249 -0
  200. package/src/components/chat/transcript/activity-view.ts +375 -0
  201. package/src/components/chat/transcript/chat-export.ts +133 -0
  202. package/src/components/chat/transcript/index.ts +10 -0
  203. package/src/components/chat/transcript/save-file.ts +209 -0
  204. package/src/components/chat/transcript/transcript-markdown.ts +428 -0
  205. package/src/components/chat/transcript/types.ts +81 -0
  206. package/src/components/chat/turn-outcome.ts +52 -0
  207. package/src/components/chat/use-warmup-phase.ts +18 -0
  208. package/src/components/chat/work-status-lead.tsx +49 -0
  209. package/src/components/chrome.tsx +264 -0
  210. package/src/components/command-palette/CommandPalette.tsx +404 -0
  211. package/src/components/command-palette/index.ts +6 -0
  212. package/src/components/contact/ContactMailto.tsx +112 -0
  213. package/src/components/contact/index.ts +5 -0
  214. package/src/components/conviction/ConvictionMeter.tsx +40 -0
  215. package/src/components/conviction/SignedConvictionBadge.tsx +26 -0
  216. package/src/components/conviction/index.ts +7 -0
  217. package/src/components/data-layout/BentoGrid.tsx +52 -0
  218. package/src/components/data-layout/CardRail.tsx +150 -0
  219. package/src/components/data-layout/DotMatrixStat.tsx +65 -0
  220. package/src/components/data-layout/FeatureCell.tsx +80 -0
  221. package/src/components/data-layout/MediaFrame.tsx +125 -0
  222. package/src/components/data-layout/ModuleGrid.tsx +735 -0
  223. package/src/components/data-layout/Odometer.tsx +149 -0
  224. package/src/components/data-layout/ProductFrame.tsx +79 -0
  225. package/src/components/data-layout/TestimonialWall.tsx +139 -0
  226. package/src/components/data-layout/index.ts +19 -0
  227. package/src/components/data-layout/treemap.ts +368 -0
  228. package/src/components/deck/DeckStack.tsx +243 -0
  229. package/src/components/desk/DataTable.tsx +373 -0
  230. package/src/components/desk/KpiGrid.tsx +80 -0
  231. package/src/components/desk/Sparkline.tsx +63 -0
  232. package/src/components/desk/StateBlock.tsx +132 -0
  233. package/src/components/desk/index.ts +18 -0
  234. package/src/components/diagrams/ArchitectureDiagram.tsx +350 -0
  235. package/src/components/diagrams/ArchitectureTour.tsx +912 -0
  236. package/src/components/diagrams/TerminalSchematic.tsx +192 -0
  237. package/src/components/diagrams/architecture-svg.tsx +384 -0
  238. package/src/components/diagrams/index.ts +30 -0
  239. package/src/components/diagrams/mermaid-theme.ts +115 -0
  240. package/src/components/diagrams/tour-camera.ts +171 -0
  241. package/src/components/docs/CodeTabs.tsx +90 -0
  242. package/src/components/docs/CopyCommand.tsx +151 -0
  243. package/src/components/docs/DocsLayout.tsx +197 -0
  244. package/src/components/docs/DocsSearch.tsx +97 -0
  245. package/src/components/docs/Endpoint.tsx +135 -0
  246. package/src/components/document/DocumentFrame.tsx +43 -0
  247. package/src/components/document/GlyphList.tsx +51 -0
  248. package/src/components/document/PageTitle.tsx +44 -0
  249. package/src/components/document/Prose.tsx +38 -0
  250. package/src/components/document/Section.tsx +55 -0
  251. package/src/components/document/index.ts +13 -0
  252. package/src/components/effects-chrome/AnnouncementBar.tsx +88 -0
  253. package/src/components/effects-chrome/HorizontalScrollTrack.tsx +461 -0
  254. package/src/components/effects-chrome/Pipeline.tsx +226 -0
  255. package/src/components/effects-chrome/RotatingPrompts.tsx +116 -0
  256. package/src/components/effects-chrome/StackingPanels.tsx +101 -0
  257. package/src/components/effects-chrome/TabStrip.tsx +232 -0
  258. package/src/components/effects-chrome/ToastStack.tsx +201 -0
  259. package/src/components/effects-chrome/horizontal-track-core.ts +70 -0
  260. package/src/components/effects-chrome/index.ts +35 -0
  261. package/src/components/emblems.tsx +188 -0
  262. package/src/components/faviconTheme.ts +23 -0
  263. package/src/components/figure/Figure.tsx +38 -0
  264. package/src/components/figure/index.ts +2 -0
  265. package/src/components/finance-charts/DrawdownPlot.tsx +76 -0
  266. package/src/components/finance-charts/EquityCurve.tsx +71 -0
  267. package/src/components/finance-charts/PriceChart.tsx +119 -0
  268. package/src/components/finance-charts/chart-host.tsx +236 -0
  269. package/src/components/finance-charts/chart-scale.ts +93 -0
  270. package/src/components/finance-charts/demo-data.ts +88 -0
  271. package/src/components/finance-charts/index.ts +46 -0
  272. package/src/components/finance-charts/lw-chart.tsx +292 -0
  273. package/src/components/finance-composites/MarketBar.tsx +243 -0
  274. package/src/components/finance-composites/OrderBook.tsx +133 -0
  275. package/src/components/finance-composites/PerformanceDashboard.tsx +185 -0
  276. package/src/components/finance-composites/SortableTable.tsx +144 -0
  277. package/src/components/finance-composites/StockTicker.tsx +65 -0
  278. package/src/components/finance-composites/SyncedTearsheet.tsx +226 -0
  279. package/src/components/finance-composites/index.ts +28 -0
  280. package/src/components/finance-tearsheet/KpiStrip.tsx +49 -0
  281. package/src/components/finance-tearsheet/LiveBadge.tsx +29 -0
  282. package/src/components/finance-tearsheet/ReturnsMatrix.tsx +321 -0
  283. package/src/components/finance-tearsheet/StrategyTearsheet.tsx +99 -0
  284. package/src/components/finance-tearsheet/TearsheetCard.tsx +54 -0
  285. package/src/components/finance-tearsheet/TradeLogTable.tsx +73 -0
  286. package/src/components/finance-tearsheet/charts.tsx +2624 -0
  287. package/src/components/finance-tearsheet/demo-data.ts +177 -0
  288. package/src/components/finance-tearsheet/format.ts +41 -0
  289. package/src/components/finance-tearsheet/index.ts +120 -0
  290. package/src/components/finance-tearsheet/print.ts +52 -0
  291. package/src/components/finance-tearsheet/risk-bands.ts +48 -0
  292. package/src/components/finance-tearsheet/stats.ts +35 -0
  293. package/src/components/finance-tearsheet/strategy-sheet-model.ts +238 -0
  294. package/src/components/finance-tearsheet/types.ts +58 -0
  295. package/src/components/footer/FooterCells.tsx +109 -0
  296. package/src/components/footer/index.ts +6 -0
  297. package/src/components/graph.tsx +158 -0
  298. package/src/components/icons.tsx +98 -0
  299. package/src/components/landing/PixelWordmark.tsx +36 -0
  300. package/src/components/logos.ts +39 -0
  301. package/src/components/marquee/Marquee.tsx +204 -0
  302. package/src/components/metrics/PerfMetrics.tsx +68 -0
  303. package/src/components/metrics/StatCounter.tsx +104 -0
  304. package/src/components/page-geometry.tsx +177 -0
  305. package/src/components/pricing/Pricing.tsx +174 -0
  306. package/src/components/pricing/PricingMatrix.tsx +219 -0
  307. package/src/components/prose/index.ts +2 -0
  308. package/src/components/prose/prose.tsx +86 -0
  309. package/src/components/repo-activity/RepoActivity.tsx +599 -0
  310. package/src/components/repo-activity/RepoHeatmap.tsx +225 -0
  311. package/src/components/repo-activity/demo.ts +201 -0
  312. package/src/components/repo-activity/fetch.ts +211 -0
  313. package/src/components/repo-activity/heatmap.ts +123 -0
  314. package/src/components/repo-activity/index.ts +28 -0
  315. package/src/components/repo-activity/types.ts +99 -0
  316. package/src/components/stages/NumberedStages.tsx +116 -0
  317. package/src/components/symbols/marks.tsx +116 -0
  318. package/src/components/symbols/terminal-lockup.tsx +136 -0
  319. package/src/components/symbols/terminal-marks.tsx +226 -0
  320. package/src/components/terminal/ChatResponseLoader.tsx +67 -0
  321. package/src/components/terminal/ContainerBootLoader.tsx +82 -0
  322. package/src/components/terminal/TerminalStepCaret.tsx +202 -0
  323. package/src/components/themeInit.ts +24 -0
  324. package/src/components/typography/MotionReveal.tsx +108 -0
  325. package/src/components/typography/TypewriterReveal.tsx +101 -0
  326. package/src/components/typography/WordReveal.tsx +143 -0
  327. package/src/data/modules.ts +378 -0
  328. package/src/data/subsystems.ts +101 -0
  329. package/src/index.ts +587 -0
  330. package/src/lib/base-path.ts +60 -0
  331. package/src/lib/cx.ts +25 -0
  332. package/src/lib/gloomberb.ts +69 -0
  333. package/src/lib/record.ts +19 -0
  334. package/src/lib/stub-payload.ts +183 -0
  335. package/src/lib/useBodyScrollLock.ts +44 -0
  336. package/src/lib/utils.ts +6 -0
  337. package/src/motion/primitives.tsx +105 -0
  338. package/src/motion/scroll-glide.ts +62 -0
  339. package/src/motion/scrolly-core.ts +38 -0
  340. package/src/motion/scrolly.tsx +95 -0
  341. package/src/navigation/HashScrollManager.tsx +167 -0
  342. package/src/navigation/hashScroll.ts +78 -0
  343. package/src/replay/browser.ts +280 -0
  344. package/src/replay/chat-export-run.ts +121 -0
  345. package/src/replay/export-format.ts +25 -0
  346. package/src/replay/export-mount.ts +32 -0
  347. package/src/replay/filename.ts +54 -0
  348. package/src/replay/index.ts +21 -0
  349. package/src/replay/redact-dom.ts +178 -0
  350. package/src/replay/redact.ts +113 -0
  351. package/src/replay/snapshot.ts +659 -0
  352. package/src/styles/account-auth.css +339 -0
  353. package/src/styles/brand-wordmark.css +11 -0
  354. package/src/styles/card-rail.css +120 -0
  355. package/src/styles/chat-aui.css +1143 -0
  356. package/src/styles/chat-core.css +469 -0
  357. package/src/styles/chat-digichat.css +2531 -0
  358. package/src/styles/chat-math.css +70 -0
  359. package/src/styles/chat-skin-palette.css +138 -0
  360. package/src/styles/chat-stock-menu.css +37 -0
  361. package/src/styles/chat-widgets.css +190 -0
  362. package/src/styles/command-palette.css +372 -0
  363. package/src/styles/controls-core.css +2261 -0
  364. package/src/styles/controls-overlay.css +603 -0
  365. package/src/styles/data-layout.css +288 -0
  366. package/src/styles/deck.css +141 -0
  367. package/src/styles/diagrams.css +1860 -0
  368. package/src/styles/digichat-app-theme.css +250 -0
  369. package/src/styles/digichat-boot-loader.css +487 -0
  370. package/src/styles/digichat-launcher.css +377 -0
  371. package/src/styles/docs.css +165 -0
  372. package/src/styles/effects-chrome.css +888 -0
  373. package/src/styles/finance-composites.css +214 -0
  374. package/src/styles/finance-tearsheet-overlay.css +90 -0
  375. package/src/styles/finance-tearsheet.css +945 -0
  376. package/src/styles/marquee.css +168 -0
  377. package/src/styles/metrics.css +82 -0
  378. package/src/styles/nav-shell.css +551 -0
  379. package/src/styles/pricing.css +79 -0
  380. package/src/styles/repo-activity.css +575 -0
  381. package/src/styles/stages.css +69 -0
  382. package/src/styles/terminal-loaders.css +122 -0
  383. package/src/styles/terminal-manifest.css +228 -0
  384. package/src/styles/web-theme.css +1007 -0
  385. package/src/styles/word-reveal.css +204 -0
  386. package/src/theme/apply-theme.ts +214 -0
  387. package/src/theme/index.ts +27 -0
  388. package/src/theme/palette-registry.ts +855 -0
  389. package/src/theme/tui-prefs.ts +64 -0
  390. package/src/ui/alert.tsx +78 -0
  391. package/src/ui/avatar.tsx +104 -0
  392. package/src/ui/badge.tsx +75 -0
  393. package/src/ui/breadcrumb.tsx +61 -0
  394. package/src/ui/button.tsx +67 -0
  395. package/src/ui/card.tsx +139 -0
  396. package/src/ui/checkbox.tsx +27 -0
  397. package/src/ui/collapsible.tsx +32 -0
  398. package/src/ui/date-pager.tsx +325 -0
  399. package/src/ui/dialog.tsx +157 -0
  400. package/src/ui/dropdown-menu.tsx +267 -0
  401. package/src/ui/empty-state.tsx +165 -0
  402. package/src/ui/field.tsx +104 -0
  403. package/src/ui/form.tsx +36 -0
  404. package/src/ui/icon-button.tsx +36 -0
  405. package/src/ui/index.ts +34 -0
  406. package/src/ui/input.tsx +33 -0
  407. package/src/ui/kbd.tsx +30 -0
  408. package/src/ui/label.tsx +32 -0
  409. package/src/ui/pager.tsx +119 -0
  410. package/src/ui/pagination.tsx +126 -0
  411. package/src/ui/radio-group.tsx +51 -0
  412. package/src/ui/search-bar.tsx +85 -0
  413. package/src/ui/segmented-control.tsx +76 -0
  414. package/src/ui/select.tsx +257 -0
  415. package/src/ui/separator.tsx +24 -0
  416. package/src/ui/sheet.tsx +141 -0
  417. package/src/ui/skeleton.tsx +76 -0
  418. package/src/ui/slider.tsx +76 -0
  419. package/src/ui/switch.tsx +31 -0
  420. package/src/ui/table.tsx +179 -0
  421. package/src/ui/tabs.tsx +89 -0
  422. package/src/ui/tags-input.tsx +168 -0
  423. package/src/ui/textarea.tsx +17 -0
  424. package/src/ui/tooltip.tsx +71 -0
@@ -0,0 +1,225 @@
1
+ "use client";
2
+
3
+ import { useEffect, useRef, useState } from "react";
4
+ import * as HeatGraph from "heat-graph";
5
+
6
+ import { bucketContributions, levelFor, type HeatDay } from "./heatmap";
7
+ import { grouped, type RepoPullItem } from "./types";
8
+
9
+ export type RepoHeatmapProps = {
10
+ pulls: RepoPullItem[];
11
+ /** Extra contribution sources: commit timestamps (ISO) and closed-issue timestamps (ISO). */
12
+ commits?: Array<string | null | undefined>;
13
+ closedIssues?: Array<string | null | undefined>;
14
+ /** Pre-bucketed daily contributions (snapshot path). Overrides pulls/commits/issues when set. */
15
+ data?: HeatDay[];
16
+ /** Weeks of history, oldest week left. Defaults to 53 (a full year, GitHub-style). */
17
+ weeks?: number;
18
+ /** Window end (UTC day). Defaults to today. Test seam only. */
19
+ end?: Date;
20
+ /**
21
+ * Grow the squares to fill the container instead of scrolling it. The cell
22
+ * size is normally a fixed 10px and `.ra-heat-body` scrolls when the history
23
+ * is wider than its column; with `fit` the grid takes 100% of the column and
24
+ * each cell keeps a 1:1 aspect ratio, so the squares get bigger as the column
25
+ * widens and smaller as it narrows — the count still picks how many weeks are
26
+ * drawn (see `weeks`), the layout picks how large they are drawn.
27
+ */
28
+ fit?: boolean;
29
+ /**
30
+ * Build the cubes and the month names left to right, once, when the graph
31
+ * scrolls into view. Off by default so existing heatmaps stay settled.
32
+ */
33
+ build?: boolean;
34
+ className?: string;
35
+ };
36
+
37
+ /**
38
+ * RepoHeatmap — repo-level contributions over the last year, GitHub
39
+ * profile-graph style, via assistant-ui's headless `heat-graph`.
40
+ * DigiWeb livery: perfect squares (no radius), categorical accent steps
41
+ * via `var(--accent)` — flat fills only, no gradients. Month row on top,
42
+ * Mon/Wed/Fri day labels, Less/More legend, per-cell title tooltip.
43
+ */
44
+ const COLOR_SCALE = [
45
+ "color-mix(in srgb, var(--ink) 9%, transparent)",
46
+ "color-mix(in srgb, var(--accent) 28%, transparent)",
47
+ "color-mix(in srgb, var(--accent) 52%, transparent)",
48
+ "color-mix(in srgb, var(--accent) 76%, transparent)",
49
+ "var(--accent)",
50
+ ];
51
+
52
+ const DAY_LABELS = new Set(["Mon", "Wed", "Fri"]);
53
+
54
+ /** One column of cubes, then the next. A year of weeks stays under ~1.2s. */
55
+ const BUILD_COLUMN_MS = 22;
56
+
57
+ /**
58
+ * Hover text for one square. States the day, the total, and — when the caller
59
+ * bucketed the sources — the split behind it, because "5 contributions" and
60
+ * "5 commits" are different facts and the graph alone cannot tell them apart.
61
+ */
62
+ function cellTitle(date: string, count: number, day: HeatDay | undefined): string {
63
+ const noun = count === 1 ? "contribution" : "contributions";
64
+ if (day && (day.commits != null || day.pulls != null || day.issues != null)) {
65
+ const parts: string[] = [];
66
+ if (day.commits) parts.push(`${day.commits} commit${day.commits === 1 ? "" : "s"}`);
67
+ if (day.pulls) parts.push(`${day.pulls} PR${day.pulls === 1 ? "" : "s"}`);
68
+ if (day.issues) parts.push(`${day.issues} issue${day.issues === 1 ? "" : "s"}`);
69
+ if (parts.length) return `${date} — ${count} ${noun}: ${parts.join(", ")}`;
70
+ }
71
+ return `${date} — ${count} ${noun}`;
72
+ }
73
+
74
+ export function RepoHeatmap({
75
+ pulls,
76
+ commits = [],
77
+ closedIssues = [],
78
+ data,
79
+ weeks = 53,
80
+ end,
81
+ fit = false,
82
+ build = false,
83
+ className,
84
+ }: RepoHeatmapProps) {
85
+ const days: HeatDay[] =
86
+ data ?? bucketContributions(pulls, commits, closedIssues, weeks, end ?? new Date());
87
+ const total = days.reduce((m, d) => m + d.count, 0);
88
+ const rootRef = useRef<HTMLDivElement>(null);
89
+ const [armed, setArmed] = useState(!build);
90
+ useEffect(() => {
91
+ if (!build) return;
92
+ const el = rootRef.current;
93
+ if (!el || typeof IntersectionObserver === "undefined") {
94
+ setArmed(true);
95
+ return;
96
+ }
97
+ const reduced = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
98
+ if (reduced) {
99
+ setArmed(true);
100
+ return;
101
+ }
102
+ // IntersectionObserver(callback, options) is the real DOM signature —
103
+ // the threshold option below is required behaviour, not a superfluous
104
+ // argument (CodeQL #3016 flagged for dismissal in GitHub UI).
105
+ const observer = new IntersectionObserver(
106
+ (entries) => {
107
+ if (!entries.some((entry) => entry.isIntersecting)) return;
108
+ setArmed(true);
109
+ observer.disconnect();
110
+ },
111
+ { threshold: 0.35 },
112
+ );
113
+ observer.observe(el);
114
+ return () => observer.disconnect();
115
+ }, [build]);
116
+ const cls = [
117
+ "ra-heat",
118
+ fit ? "ra-heat--fit" : "",
119
+ build ? "ra-heat--build" : "",
120
+ build && armed ? "is-armed" : "",
121
+ className ?? "",
122
+ ]
123
+ .filter(Boolean)
124
+ .join(" ");
125
+ const range = weeks >= 50 ? "the last year" : `the last ${weeks} weeks`;
126
+ const points = days.map((d) => ({ date: d.date, count: d.count }));
127
+ // The grid hands back its own cells, so the per-day split is looked up by
128
+ // date to build the hover title.
129
+ const byDate = new Map(days.map((d) => [d.date, d]));
130
+
131
+ return (
132
+ <div className={cls} ref={rootRef}>
133
+ <p className="ra-heat-total">
134
+ {grouped(total)} contributions in {range}
135
+ </p>
136
+ <HeatGraph.Root
137
+ data={points}
138
+ start={days[0]?.date ?? points[0]?.date}
139
+ end={days[days.length - 1]?.date ?? new Date()}
140
+ weekStart="sunday"
141
+ colorScale={COLOR_SCALE}
142
+ classify={(counts) => {
143
+ const max = counts.reduce((m, c) => Math.max(m, c), 0);
144
+ return (count: number) => levelFor(count, max);
145
+ }}
146
+ className="ra-heat-graph"
147
+ role="img"
148
+ aria-label={`${grouped(total)} contributions in ${range}.`}
149
+ >
150
+ <div className="ra-heat-body">
151
+ {/* One max-content frame holds the month row, the cell row and the
152
+ legend, so the month-label coordinate space is exactly the grid
153
+ width. Without it .ra-heat-months spans the full body width while
154
+ .ra-heat-grid is only max-content wide, and the %-positioned
155
+ labels drift right of their columns (last label ~172px past the
156
+ last cell at 1440). The frame is max-content at every viewport;
157
+ .ra-heat-body scrolls when it does not fit. */}
158
+ <div className="ra-heat-frame">
159
+ <div className="ra-heat-months" aria-hidden="true">
160
+ <HeatGraph.MonthLabels>
161
+ {({ label, totalWeeks }) => (
162
+ <span
163
+ key={`${label.month}-${label.column}`}
164
+ className="ra-heat-month"
165
+ style={{
166
+ left: `${(label.column / totalWeeks) * 100}%`,
167
+ ...(build ? { animationDelay: `${label.column * BUILD_COLUMN_MS}ms` } : {}),
168
+ }}
169
+ >
170
+ {HeatGraph.MONTH_SHORT[label.month]}
171
+ </span>
172
+ )}
173
+ </HeatGraph.MonthLabels>
174
+ </div>
175
+ <div className="ra-heat-row">
176
+ <div className="ra-heat-days" aria-hidden="true">
177
+ <HeatGraph.DayLabels>
178
+ {({ label }) => {
179
+ const name = HeatGraph.DAY_SHORT[label.dayOfWeek];
180
+ if (!DAY_LABELS.has(name))
181
+ return <span key={label.row} className="ra-heat-day" />;
182
+ return (
183
+ <span key={label.row} className="ra-heat-day">
184
+ {name}
185
+ </span>
186
+ );
187
+ }}
188
+ </HeatGraph.DayLabels>
189
+ </div>
190
+ <HeatGraph.Grid className="ra-heat-grid">
191
+ {({ cell }) => {
192
+ const date = cell.date.toISOString().slice(0, 10);
193
+ const n = cell.count;
194
+ return (
195
+ <HeatGraph.Cell
196
+ key={`${cell.column}-${cell.row}`}
197
+ className="ra-heat-cell"
198
+ data-level={cell.level}
199
+ title={cellTitle(date, n, byDate.get(date))}
200
+ style={
201
+ build
202
+ ? { animationDelay: `${cell.column * BUILD_COLUMN_MS}ms` }
203
+ : undefined
204
+ }
205
+ />
206
+ );
207
+ }}
208
+ </HeatGraph.Grid>
209
+ </div>
210
+ <div className="ra-heat-foot">
211
+ <span />
212
+ <div className="ra-heat-legend" aria-hidden="true">
213
+ <span>Less</span>
214
+ <HeatGraph.Legend>
215
+ {() => <HeatGraph.LegendLevel className="ra-heat-cell" />}
216
+ </HeatGraph.Legend>
217
+ <span>More</span>
218
+ </div>
219
+ </div>
220
+ </div>
221
+ </div>
222
+ </HeatGraph.Root>
223
+ </div>
224
+ );
225
+ }
@@ -0,0 +1,201 @@
1
+ import type { RepoActivitySnapshot } from "./types";
2
+
3
+ /** Realistic fixture for the design-reference specimens. Not live data. */
4
+ export const REPO_ACTIVITY_DEMO: RepoActivitySnapshot = {
5
+ generatedAt: "2026-08-24T07:15:49Z",
6
+ windowDays: 30,
7
+ branch: "main",
8
+ commits: 940,
9
+ pullsMerged: 546,
10
+ issuesClosed: 605,
11
+ pullsOpen: 4,
12
+ issuesOpen: 6,
13
+ latestRelease: {
14
+ tag: "digichat-v1.3.1",
15
+ name: "digichat: v1.3.1",
16
+ publishedAt: "2026-08-21T00:49:33Z",
17
+ url: "https://github.com/digithings-ai/digithings/releases/tag/digichat-v1.3.1",
18
+ },
19
+ mergedPulls: [
20
+ {
21
+ number: 2574,
22
+ title: "trade idea continuity, levels ladder, formatting",
23
+ url: "https://github.com/digithings-ai/digithings/pull/2574",
24
+ mergedAt: "2026-08-21T17:35:10Z",
25
+ },
26
+ {
27
+ number: 1081,
28
+ title: "wrap SDCA engine as NautilusTrader strategy",
29
+ url: "https://github.com/digithings-ai/digithings/pull/1081",
30
+ mergedAt: "2026-08-20T22:32:46Z",
31
+ },
32
+ {
33
+ number: 2519,
34
+ title: "add SDCA core engine (composite-risk + accum/dist curve + backtest)",
35
+ url: "https://github.com/digithings-ai/digithings/pull/2519",
36
+ mergedAt: "2026-08-20T13:47:08Z",
37
+ },
38
+ {
39
+ number: 2489,
40
+ title: "book paper fills from the order ledger at the open",
41
+ url: "https://github.com/digithings-ai/digithings/pull/2489",
42
+ mergedAt: "2026-08-19T22:29:27Z",
43
+ },
44
+ {
45
+ number: 2482,
46
+ title: "make H9 append the authoritative commit chain",
47
+ url: "https://github.com/digithings-ai/digithings/pull/2482",
48
+ mergedAt: "2026-08-19T16:06:51Z",
49
+ },
50
+ {
51
+ number: 2432,
52
+ title: "add append-only portfolio lineage ledger schema",
53
+ url: "https://github.com/digithings-ai/digithings/pull/2432",
54
+ mergedAt: "2026-08-17T19:24:40Z",
55
+ },
56
+ {
57
+ number: 2398,
58
+ title: "rate-limit live refresh behind a shared budget",
59
+ url: "https://github.com/digithings-ai/digithings/pull/2398",
60
+ mergedAt: "2026-08-14T11:02:19Z",
61
+ },
62
+ {
63
+ number: 2381,
64
+ title: "collapse two-column activity on narrow screens",
65
+ url: "https://github.com/digithings-ai/digithings/pull/2381",
66
+ mergedAt: "2026-08-11T15:44:52Z",
67
+ },
68
+ {
69
+ number: 2377,
70
+ title: "hairline lists for merged PRs and open issues",
71
+ url: "https://github.com/digithings-ai/digithings/pull/2377",
72
+ mergedAt: "2026-08-11T09:18:03Z",
73
+ },
74
+ {
75
+ number: 2355,
76
+ title: "snapshot-first velocity with atomic live swap",
77
+ url: "https://github.com/digithings-ai/digithings/pull/2355",
78
+ mergedAt: "2026-08-06T20:31:47Z",
79
+ },
80
+ {
81
+ number: 2319,
82
+ title: "mono numerals with tabular figures",
83
+ url: "https://github.com/digithings-ai/digithings/pull/2319",
84
+ mergedAt: "2026-07-30T14:09:55Z",
85
+ },
86
+ {
87
+ number: 2314,
88
+ title: "kicker grammar across data specimens",
89
+ url: "https://github.com/digithings-ai/digithings/pull/2314",
90
+ mergedAt: "2026-07-29T18:52:36Z",
91
+ },
92
+ {
93
+ number: 2290,
94
+ title: "clone-box geometry that keeps beating utilities",
95
+ url: "https://github.com/digithings-ai/digithings/pull/2290",
96
+ mergedAt: "2026-07-24T10:27:11Z",
97
+ },
98
+ {
99
+ number: 2271,
100
+ title: "design tokens bridge for reference and web",
101
+ url: "https://github.com/digithings-ai/digithings/pull/2271",
102
+ mergedAt: "2026-07-17T16:40:28Z",
103
+ },
104
+ {
105
+ number: 2244,
106
+ title: "no stars, forks, or watchers on activity",
107
+ url: "https://github.com/digithings-ai/digithings/pull/2244",
108
+ mergedAt: "2026-07-10T12:14:59Z",
109
+ },
110
+ {
111
+ number: 2210,
112
+ title: "compact card for portfolio surfaces",
113
+ url: "https://github.com/digithings-ai/digithings/pull/2210",
114
+ mergedAt: "2026-07-02T09:33:22Z",
115
+ },
116
+ {
117
+ number: 2187,
118
+ title: "detailed view with backlog split",
119
+ url: "https://github.com/digithings-ai/digithings/pull/2187",
120
+ mergedAt: "2026-06-25T21:48:07Z",
121
+ },
122
+ {
123
+ number: 2179,
124
+ title: "release link with honest timestamps",
125
+ url: "https://github.com/digithings-ai/digithings/pull/2179",
126
+ mergedAt: "2026-06-25T08:05:41Z",
127
+ },
128
+ {
129
+ number: 2152,
130
+ title: "copy button for the clone command",
131
+ url: "https://github.com/digithings-ai/digithings/pull/2152",
132
+ mergedAt: "2026-06-18T13:57:30Z",
133
+ },
134
+ {
135
+ number: 2118,
136
+ title: "first activity snapshot fixture",
137
+ url: "https://github.com/digithings-ai/digithings/pull/2118",
138
+ mergedAt: "2026-06-11T17:22:54Z",
139
+ },
140
+ ],
141
+ openIssues: [
142
+ {
143
+ number: 3445,
144
+ title: "website: progressively enhance repository section with live GitHub data",
145
+ url: "https://github.com/digithings-ai/digithings/issues/3445",
146
+ updatedAt: "2026-09-02T19:57:46Z",
147
+ },
148
+ {
149
+ number: 3291,
150
+ title: "chore(website): refresh repository activity snapshot",
151
+ url: "https://github.com/digithings-ai/digithings/issues/3291",
152
+ updatedAt: "2026-08-31T09:12:00Z",
153
+ },
154
+ {
155
+ number: 2547,
156
+ title: "worktree task must branch from origin base, not a stale local develop",
157
+ url: "https://github.com/digithings-ai/digithings/issues/2547",
158
+ updatedAt: "2026-08-20T11:04:00Z",
159
+ },
160
+ {
161
+ number: 1981,
162
+ title: "lint and type-check the design-reference workspace in CI",
163
+ url: "https://github.com/digithings-ai/digithings/issues/1981",
164
+ updatedAt: "2026-08-18T16:40:00Z",
165
+ },
166
+ {
167
+ number: 1450,
168
+ title: "promote F1 component families into @digithings-ai/ui",
169
+ url: "https://github.com/digithings-ai/digithings/issues/1450",
170
+ updatedAt: "2026-08-12T08:22:00Z",
171
+ },
172
+ {
173
+ number: 1310,
174
+ title: "frontend scoring exception for presentation-only surfaces",
175
+ url: "https://github.com/digithings-ai/digithings/issues/1310",
176
+ updatedAt: "2026-08-08T14:01:00Z",
177
+ },
178
+ ],
179
+ /** Synthetic 14-day series so the specimen shows graded cells. Not live data. */
180
+ dailyContributions: [
181
+ { date: "2026-08-11", count: 1 },
182
+ { date: "2026-08-12", count: 3 },
183
+ { date: "2026-08-13", count: 2 },
184
+ { date: "2026-08-14", count: 6 },
185
+ { date: "2026-08-15", count: 1 },
186
+ { date: "2026-08-16", count: 4 },
187
+ { date: "2026-08-17", count: 8 },
188
+ { date: "2026-08-18", count: 2 },
189
+ { date: "2026-08-19", count: 5 },
190
+ { date: "2026-08-20", count: 3 },
191
+ { date: "2026-08-21", count: 9 },
192
+ { date: "2026-08-22", count: 1 },
193
+ { date: "2026-08-23", count: 4 },
194
+ { date: "2026-08-24", count: 7 },
195
+ ],
196
+ };
197
+
198
+ export const REPO_ACTIVITY_DEMO_URL = "https://github.com/digithings-ai/digithings";
199
+ export const REPO_ACTIVITY_DEMO_CLONE = "git clone https://github.com/digithings-ai/digithings";
200
+ export const REPO_ACTIVITY_DEMO_CONTRIBUTING =
201
+ "https://github.com/digithings-ai/digithings/blob/main/CONTRIBUTING.md";
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Unauthenticated GitHub refresh for repository activity.
3
+ *
4
+ * All requests must succeed and validate before a result is returned. The
5
+ * caller (RepoActivity) applies that result atomically or keeps the snapshot.
6
+ * Commits are counted on the configured branch via the Link last-page trick
7
+ * (per_page=1); Search supplies the four issue/PR totals plus list rows.
8
+ * `/repos/{owner}/{repo}` is never fetched — that payload carries stars/forks.
9
+ */
10
+
11
+ import {
12
+ DEFAULT_LIVE_TIMEOUT_MS,
13
+ type RepoActivityLiveConfig,
14
+ type RepoActivitySnapshot,
15
+ type RepoIssueItem,
16
+ type RepoPullItem,
17
+ type RepoRelease,
18
+ } from "./types";
19
+
20
+ export type FetchRepoActivityLiveOptions = RepoActivityLiveConfig & {
21
+ fetch?: typeof globalThis.fetch;
22
+ now?: () => Date;
23
+ };
24
+
25
+ type LiveResult = Omit<RepoActivitySnapshot, "features" | "modules">;
26
+
27
+ const API = "https://api.github.com";
28
+
29
+ export async function fetchRepoActivityLive(
30
+ options: FetchRepoActivityLiveOptions,
31
+ ): Promise<LiveResult> {
32
+ const owner = options.owner.trim();
33
+ const repo = options.repo.trim();
34
+ if (!/^[A-Za-z0-9_.-]+$/.test(owner) || !/^[A-Za-z0-9_.-]+$/.test(repo)) {
35
+ throw new Error("malformed repo activity: invalid owner/repo");
36
+ }
37
+ const branch = options.branch?.trim() || "main";
38
+ const windowDays = options.windowDays ?? 30;
39
+ const timeoutMs = options.timeoutMs ?? DEFAULT_LIVE_TIMEOUT_MS;
40
+ const fetchFn = options.fetch ?? globalThis.fetch;
41
+ const now = options.now ?? (() => new Date());
42
+ const generatedAt = toIsoZ(now());
43
+ const since = new Date(Date.parse(generatedAt) - windowDays * 86_400_000);
44
+ const sinceIso = toIsoZ(since);
45
+ const sinceDay = sinceIso.slice(0, 10);
46
+ const slug = `${owner}/${repo}`;
47
+
48
+ const controller = new AbortController();
49
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
50
+ const get = (path: string) =>
51
+ fetchJson(fetchFn, `${API}${path}`, controller.signal);
52
+
53
+ try {
54
+ const [commitsRes, merged, closed, openPrs, openIssues, releases] = await Promise.all([
55
+ get(`/repos/${slug}/commits?sha=${encodeURIComponent(branch)}&since=${sinceIso}&per_page=1`),
56
+ get(
57
+ `/search/issues?q=repo:${slug}+is:pr+is:merged+merged:>=${sinceDay}&per_page=6&sort=updated`,
58
+ ),
59
+ get(`/search/issues?q=repo:${slug}+is:issue+is:closed+closed:>=${sinceDay}&per_page=1`),
60
+ get(`/search/issues?q=repo:${slug}+is:pr+is:open&per_page=1`),
61
+ get(`/search/issues?q=repo:${slug}+is:issue+is:open&per_page=6&sort=updated`),
62
+ get(`/repos/${slug}/releases?per_page=1`),
63
+ ]);
64
+
65
+ return {
66
+ generatedAt,
67
+ windowDays,
68
+ branch,
69
+ commits: commitCount(commitsRes),
70
+ pullsMerged: searchTotal(merged.body),
71
+ issuesClosed: searchTotal(closed.body),
72
+ pullsOpen: searchTotal(openPrs.body),
73
+ issuesOpen: searchTotal(openIssues.body),
74
+ latestRelease: parseLatestRelease(releases.body),
75
+ mergedPulls: parsePullItems(merged.body),
76
+ openIssues: parseIssueItems(openIssues.body),
77
+ };
78
+ } catch (err) {
79
+ if (isAbort(err)) throw new Error("repo activity timeout");
80
+ throw err;
81
+ } finally {
82
+ clearTimeout(timer);
83
+ }
84
+ }
85
+
86
+ type Fetched = { body: unknown; headers: Headers };
87
+
88
+ async function fetchJson(
89
+ fetchFn: typeof globalThis.fetch,
90
+ url: string,
91
+ signal: AbortSignal,
92
+ ): Promise<Fetched> {
93
+ let res: Response;
94
+ try {
95
+ res = await fetchFn(url, { signal });
96
+ } catch (err) {
97
+ if (isAbort(err)) throw new Error("repo activity timeout");
98
+ throw err;
99
+ }
100
+ if (!res.ok) {
101
+ throw new Error(`repo activity HTTP ${res.status}`);
102
+ }
103
+ let body: unknown;
104
+ try {
105
+ body = await res.json();
106
+ } catch {
107
+ throw new Error("malformed repo activity");
108
+ }
109
+ return { body, headers: res.headers };
110
+ }
111
+
112
+ function commitCount(res: Fetched): number {
113
+ const last = lastPage(res.headers.get("Link") ?? res.headers.get("link"));
114
+ if (last != null) return last;
115
+ if (!Array.isArray(res.body)) throw new Error("malformed repo activity");
116
+ return res.body.length;
117
+ }
118
+
119
+ function lastPage(link: string | null): number | null {
120
+ if (!link) return null;
121
+ for (const part of link.split(",")) {
122
+ if (!part.includes('rel="last"')) continue;
123
+ const m = /[?&]page=(\d+)/.exec(part);
124
+ if (m) return Number(m[1]);
125
+ }
126
+ return null;
127
+ }
128
+
129
+ function searchTotal(body: unknown): number {
130
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
131
+ throw new Error("malformed repo activity");
132
+ }
133
+ const count = (body as { total_count?: unknown }).total_count;
134
+ return intCount(count);
135
+ }
136
+
137
+ function parsePullItems(body: unknown): RepoPullItem[] {
138
+ return searchItems(body).map((item) => ({
139
+ number: intCount(item.number, { min: 1 }),
140
+ title: str(item.title),
141
+ url: githubUrl(item.html_url),
142
+ mergedAt: stamp(item.closed_at) ?? stamp(item.updated_at),
143
+ }));
144
+ }
145
+
146
+ function parseIssueItems(body: unknown): RepoIssueItem[] {
147
+ return searchItems(body).map((item) => ({
148
+ number: intCount(item.number, { min: 1 }),
149
+ title: str(item.title),
150
+ url: githubUrl(item.html_url),
151
+ updatedAt: stamp(item.updated_at),
152
+ }));
153
+ }
154
+
155
+ function searchItems(body: unknown): Record<string, unknown>[] {
156
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
157
+ throw new Error("malformed repo activity");
158
+ }
159
+ const items = (body as { items?: unknown }).items;
160
+ if (items == null) return [];
161
+ if (!Array.isArray(items)) throw new Error("malformed repo activity");
162
+ return items.filter((it): it is Record<string, unknown> => !!it && typeof it === "object");
163
+ }
164
+
165
+ function parseLatestRelease(body: unknown): RepoRelease | null {
166
+ if (!Array.isArray(body)) throw new Error("malformed repo activity");
167
+ const first = body[0];
168
+ if (!first || typeof first !== "object") return null;
169
+ const row = first as Record<string, unknown>;
170
+ return {
171
+ tag: str(row.tag_name),
172
+ name: row.name == null ? null : str(row.name),
173
+ publishedAt: str(row.published_at),
174
+ url: githubUrl(row.html_url),
175
+ };
176
+ }
177
+
178
+ function intCount(v: unknown, opts: { min?: number } = {}): number {
179
+ if (typeof v !== "number" || !Number.isInteger(v) || !Number.isFinite(v) || v < (opts.min ?? 0)) {
180
+ throw new Error("malformed repo activity");
181
+ }
182
+ return v;
183
+ }
184
+
185
+ function str(v: unknown): string {
186
+ if (typeof v !== "string" || !v.trim()) throw new Error("malformed repo activity");
187
+ return v;
188
+ }
189
+
190
+ function githubUrl(v: unknown): string {
191
+ const url = str(v);
192
+ if (!url.startsWith("https://github.com/")) throw new Error("malformed repo activity");
193
+ return url;
194
+ }
195
+
196
+ function stamp(v: unknown): string | null {
197
+ if (v == null) return null;
198
+ if (typeof v !== "string") throw new Error("malformed repo activity");
199
+ return v;
200
+ }
201
+
202
+ function toIsoZ(d: Date): string {
203
+ return d.toISOString().replace(/\.\d{3}Z$/, "Z");
204
+ }
205
+
206
+ function isAbort(err: unknown): boolean {
207
+ return (
208
+ (err instanceof DOMException && err.name === "AbortError") ||
209
+ (err instanceof Error && (err.name === "AbortError" || /aborted/i.test(err.message)))
210
+ );
211
+ }