@vibefield/rosetta-room 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 (435) hide show
  1. package/README.md +247 -2
  2. package/dist/HistoryRoom.d.ts +98 -0
  3. package/dist/HistoryRoom.js +440 -0
  4. package/dist/TranscriptReader.d.ts +22 -0
  5. package/dist/TranscriptReader.js +72 -0
  6. package/dist/components/ColdStart.d.ts +4 -0
  7. package/dist/components/ColdStart.js +5 -0
  8. package/dist/components/FilterChips.d.ts +4 -0
  9. package/dist/components/FilterChips.js +5 -0
  10. package/dist/components/HostAct.d.ts +9 -0
  11. package/dist/components/HostAct.js +16 -0
  12. package/dist/components/HostMenu.d.ts +41 -0
  13. package/dist/components/HostMenu.js +216 -0
  14. package/dist/components/IngestStatus.d.ts +4 -0
  15. package/dist/components/IngestStatus.js +20 -0
  16. package/dist/components/ListActivityNotice.d.ts +5 -0
  17. package/dist/components/ListActivityNotice.js +4 -0
  18. package/dist/components/ListSections.d.ts +20 -0
  19. package/dist/components/ListSections.js +39 -0
  20. package/dist/components/RenameHeading.d.ts +9 -0
  21. package/dist/components/RenameHeading.js +75 -0
  22. package/dist/components/SearchStrip.d.ts +5 -0
  23. package/dist/components/SearchStrip.js +8 -0
  24. package/dist/components/SummaryMetrics.d.ts +13 -0
  25. package/dist/components/SummaryMetrics.js +9 -0
  26. package/dist/components/SummaryPanels.d.ts +35 -0
  27. package/dist/components/SummaryPanels.js +117 -0
  28. package/dist/components/Transcript.d.ts +46 -0
  29. package/dist/components/Transcript.js +358 -0
  30. package/dist/components/charts/ActivityChartDetail.d.ts +13 -0
  31. package/dist/components/charts/ActivityChartDetail.js +78 -0
  32. package/dist/components/charts/CalendarHeatmap.d.ts +16 -0
  33. package/dist/components/charts/CalendarHeatmap.js +55 -0
  34. package/dist/components/charts/DayActivityChart.d.ts +8 -0
  35. package/dist/components/charts/DayActivityChart.js +71 -0
  36. package/dist/components/charts/ModelsChartDetail.d.ts +7 -0
  37. package/dist/components/charts/ModelsChartDetail.js +19 -0
  38. package/dist/components/charts/ProjectChartDialog.d.ts +19 -0
  39. package/dist/components/charts/ProjectChartDialog.js +39 -0
  40. package/dist/components/charts/Streamgraph.d.ts +16 -0
  41. package/dist/components/charts/Streamgraph.js +94 -0
  42. package/dist/components/charts/Treemap.d.ts +26 -0
  43. package/dist/components/charts/Treemap.js +81 -0
  44. package/dist/components/charts/index.d.ts +9 -0
  45. package/dist/components/charts/index.js +4 -0
  46. package/dist/components/charts/streamgraph-layout.d.ts +23 -0
  47. package/dist/components/charts/streamgraph-layout.js +114 -0
  48. package/dist/components/charts/treemap-layout.d.ts +32 -0
  49. package/dist/components/charts/treemap-layout.js +140 -0
  50. package/dist/components/charts/types.d.ts +65 -0
  51. package/dist/components/charts/types.js +8 -0
  52. package/dist/components/file-viewer/FileViewerBrowsers.d.ts +10 -0
  53. package/dist/components/file-viewer/FileViewerBrowsers.js +65 -0
  54. package/dist/components/file-viewer/FileViewerDialog.d.ts +33 -0
  55. package/dist/components/file-viewer/FileViewerDialog.js +82 -0
  56. package/dist/components/file-viewer/FileViewerHeader.d.ts +26 -0
  57. package/dist/components/file-viewer/FileViewerHeader.js +17 -0
  58. package/dist/components/file-viewer/ImageGalleryDialog.d.ts +14 -0
  59. package/dist/components/file-viewer/ImageGalleryDialog.js +98 -0
  60. package/dist/components/file-viewer/diff/index.d.ts +2 -0
  61. package/dist/components/file-viewer/diff/index.js +2 -0
  62. package/dist/components/file-viewer/diff/parse.d.ts +2 -0
  63. package/dist/components/file-viewer/diff/parse.js +164 -0
  64. package/dist/components/file-viewer/diff/types.d.ts +44 -0
  65. package/dist/components/file-viewer/diff/types.js +7 -0
  66. package/dist/components/file-viewer/gallery-source.d.ts +11 -0
  67. package/dist/components/file-viewer/gallery-source.js +75 -0
  68. package/dist/components/file-viewer/image-resource.d.ts +19 -0
  69. package/dist/components/file-viewer/image-resource.js +60 -0
  70. package/dist/components/file-viewer/index.d.ts +5 -0
  71. package/dist/components/file-viewer/index.js +8 -0
  72. package/dist/components/file-viewer/markdown/blocks.d.ts +2 -0
  73. package/dist/components/file-viewer/markdown/blocks.js +277 -0
  74. package/dist/components/file-viewer/markdown/index.d.ts +4 -0
  75. package/dist/components/file-viewer/markdown/index.js +35 -0
  76. package/dist/components/file-viewer/markdown/inline.d.ts +10 -0
  77. package/dist/components/file-viewer/markdown/inline.js +178 -0
  78. package/dist/components/file-viewer/markdown/render.d.ts +9 -0
  79. package/dist/components/file-viewer/markdown/render.js +78 -0
  80. package/dist/components/file-viewer/markdown/types.d.ts +57 -0
  81. package/dist/components/file-viewer/markdown/types.js +11 -0
  82. package/dist/components/file-viewer/minimap/CodeMinimap.d.ts +10 -0
  83. package/dist/components/file-viewer/minimap/CodeMinimap.js +296 -0
  84. package/dist/components/file-viewer/minimap/layout.d.ts +60 -0
  85. package/dist/components/file-viewer/minimap/layout.js +117 -0
  86. package/dist/components/file-viewer/minimap/palette.d.ts +2 -0
  87. package/dist/components/file-viewer/minimap/palette.js +73 -0
  88. package/dist/components/file-viewer/minimap/raster.d.ts +19 -0
  89. package/dist/components/file-viewer/minimap/raster.js +122 -0
  90. package/dist/components/file-viewer/registry.d.ts +25 -0
  91. package/dist/components/file-viewer/registry.js +182 -0
  92. package/dist/components/file-viewer/syntax/grammars.d.ts +16 -0
  93. package/dist/components/file-viewer/syntax/grammars.js +221 -0
  94. package/dist/components/file-viewer/syntax/index.d.ts +8 -0
  95. package/dist/components/file-viewer/syntax/index.js +9 -0
  96. package/dist/components/file-viewer/syntax/languages.d.ts +14 -0
  97. package/dist/components/file-viewer/syntax/languages.js +115 -0
  98. package/dist/components/file-viewer/syntax/tokenize-config.d.ts +2 -0
  99. package/dist/components/file-viewer/syntax/tokenize-config.js +132 -0
  100. package/dist/components/file-viewer/syntax/tokenize-css.d.ts +2 -0
  101. package/dist/components/file-viewer/syntax/tokenize-css.js +169 -0
  102. package/dist/components/file-viewer/syntax/tokenize-markup.d.ts +2 -0
  103. package/dist/components/file-viewer/syntax/tokenize-markup.js +124 -0
  104. package/dist/components/file-viewer/syntax/tokenize.d.ts +9 -0
  105. package/dist/components/file-viewer/syntax/tokenize.js +289 -0
  106. package/dist/components/file-viewer/syntax/types.d.ts +74 -0
  107. package/dist/components/file-viewer/syntax/types.js +13 -0
  108. package/dist/components/file-viewer/types.d.ts +111 -0
  109. package/dist/components/file-viewer/types.js +8 -0
  110. package/dist/components/file-viewer/use-file-content.d.ts +26 -0
  111. package/dist/components/file-viewer/use-file-content.js +144 -0
  112. package/dist/components/file-viewer/views/BinaryView.d.ts +2 -0
  113. package/dist/components/file-viewer/views/BinaryView.js +34 -0
  114. package/dist/components/file-viewer/views/CodeView.d.ts +2 -0
  115. package/dist/components/file-viewer/views/CodeView.js +46 -0
  116. package/dist/components/file-viewer/views/DiffBody.d.ts +7 -0
  117. package/dist/components/file-viewer/views/DiffBody.js +77 -0
  118. package/dist/components/file-viewer/views/DiffView.d.ts +2 -0
  119. package/dist/components/file-viewer/views/DiffView.js +11 -0
  120. package/dist/components/file-viewer/views/ImageView.d.ts +9 -0
  121. package/dist/components/file-viewer/views/ImageView.js +28 -0
  122. package/dist/components/file-viewer/views/MarkdownView.d.ts +9 -0
  123. package/dist/components/file-viewer/views/MarkdownView.js +20 -0
  124. package/dist/components/file-viewer/views/SvgView.d.ts +9 -0
  125. package/dist/components/file-viewer/views/SvgView.js +10 -0
  126. package/dist/components/git/ChangeTree.d.ts +20 -0
  127. package/dist/components/git/ChangeTree.js +35 -0
  128. package/dist/components/git/CommitViewer.d.ts +12 -0
  129. package/dist/components/git/CommitViewer.js +85 -0
  130. package/dist/components/git/GitChanges.d.ts +17 -0
  131. package/dist/components/git/GitChanges.js +70 -0
  132. package/dist/components/git/GitHistory.d.ts +9 -0
  133. package/dist/components/git/GitHistory.js +58 -0
  134. package/dist/components/git/co-author.d.ts +14 -0
  135. package/dist/components/git/co-author.js +55 -0
  136. package/dist/components/git/git-file-source.d.ts +18 -0
  137. package/dist/components/git/git-file-source.js +53 -0
  138. package/dist/components/git/git-host.d.ts +24 -0
  139. package/dist/components/git/git-host.js +130 -0
  140. package/dist/components/git/index.d.ts +10 -0
  141. package/dist/components/git/index.js +12 -0
  142. package/dist/components/git/path-tree.d.ts +23 -0
  143. package/dist/components/git/path-tree.js +73 -0
  144. package/dist/components/git/session-files.d.ts +9 -0
  145. package/dist/components/git/session-files.js +50 -0
  146. package/dist/components/git/types.d.ts +92 -0
  147. package/dist/components/git/types.js +9 -0
  148. package/dist/components/projects/ProjectActivitySparkline.d.ts +6 -0
  149. package/dist/components/projects/ProjectActivitySparkline.js +12 -0
  150. package/dist/components/projects/ProjectList.d.ts +25 -0
  151. package/dist/components/projects/ProjectList.js +43 -0
  152. package/dist/components/projects/ProjectListItem.d.ts +19 -0
  153. package/dist/components/projects/ProjectListItem.js +78 -0
  154. package/dist/components/projects/ProjectsColumn.d.ts +19 -0
  155. package/dist/components/projects/ProjectsColumn.js +36 -0
  156. package/dist/components/projects/index.d.ts +8 -0
  157. package/dist/components/projects/index.js +4 -0
  158. package/dist/components/search/MatchStepper.d.ts +9 -0
  159. package/dist/components/search/MatchStepper.js +14 -0
  160. package/dist/components/search/SearchLauncher.d.ts +12 -0
  161. package/dist/components/search/SearchLauncher.js +13 -0
  162. package/dist/components/search/SearchSheet.d.ts +29 -0
  163. package/dist/components/search/SearchSheet.js +230 -0
  164. package/dist/components/search/index.d.ts +8 -0
  165. package/dist/components/search/index.js +4 -0
  166. package/dist/components/search/shortcut.d.ts +25 -0
  167. package/dist/components/search/shortcut.js +32 -0
  168. package/dist/components/sessions/SessionList.d.ts +24 -0
  169. package/dist/components/sessions/SessionList.js +76 -0
  170. package/dist/components/sessions/SessionListItem.d.ts +13 -0
  171. package/dist/components/sessions/SessionListItem.js +58 -0
  172. package/dist/components/sessions/SessionsColumn.d.ts +26 -0
  173. package/dist/components/sessions/SessionsColumn.js +32 -0
  174. package/dist/components/sessions/index.d.ts +9 -0
  175. package/dist/components/sessions/index.js +4 -0
  176. package/dist/components/sessions/session-display.d.ts +8 -0
  177. package/dist/components/sessions/session-display.js +18 -0
  178. package/dist/components/sessions/types.d.ts +7 -0
  179. package/dist/components/sessions/types.js +1 -0
  180. package/dist/components/transcript/Activity.d.ts +45 -0
  181. package/dist/components/transcript/Activity.js +75 -0
  182. package/dist/components/transcript/Anchor.d.ts +8 -0
  183. package/dist/components/transcript/Anchor.js +23 -0
  184. package/dist/components/transcript/Attachments.d.ts +21 -0
  185. package/dist/components/transcript/Attachments.js +138 -0
  186. package/dist/components/transcript/AuthoredMessage.d.ts +19 -0
  187. package/dist/components/transcript/AuthoredMessage.js +17 -0
  188. package/dist/components/transcript/Compaction.d.ts +9 -0
  189. package/dist/components/transcript/Compaction.js +50 -0
  190. package/dist/components/transcript/DayPill.d.ts +38 -0
  191. package/dist/components/transcript/DayPill.js +68 -0
  192. package/dist/components/transcript/Document.d.ts +32 -0
  193. package/dist/components/transcript/Document.js +503 -0
  194. package/dist/components/transcript/Favicon.d.ts +32 -0
  195. package/dist/components/transcript/Favicon.js +71 -0
  196. package/dist/components/transcript/HeadOfDocument.d.ts +19 -0
  197. package/dist/components/transcript/HeadOfDocument.js +44 -0
  198. package/dist/components/transcript/Ledger.d.ts +53 -0
  199. package/dist/components/transcript/Ledger.js +182 -0
  200. package/dist/components/transcript/LineDetail.d.ts +24 -0
  201. package/dist/components/transcript/LineDetail.js +81 -0
  202. package/dist/components/transcript/Marker.d.ts +33 -0
  203. package/dist/components/transcript/Marker.js +21 -0
  204. package/dist/components/transcript/MessagePreview.d.ts +12 -0
  205. package/dist/components/transcript/MessagePreview.js +58 -0
  206. package/dist/components/transcript/Prompt.d.ts +20 -0
  207. package/dist/components/transcript/Prompt.js +55 -0
  208. package/dist/components/transcript/Prose.d.ts +19 -0
  209. package/dist/components/transcript/Prose.js +109 -0
  210. package/dist/components/transcript/ReceiptPill.d.ts +10 -0
  211. package/dist/components/transcript/ReceiptPill.js +10 -0
  212. package/dist/components/transcript/ResponseHead.d.ts +9 -0
  213. package/dist/components/transcript/ResponseHead.js +36 -0
  214. package/dist/components/transcript/Subthread.d.ts +19 -0
  215. package/dist/components/transcript/Subthread.js +96 -0
  216. package/dist/components/transcript/Team.d.ts +53 -0
  217. package/dist/components/transcript/Team.js +185 -0
  218. package/dist/components/transcript/Thinking.d.ts +24 -0
  219. package/dist/components/transcript/Thinking.js +50 -0
  220. package/dist/components/transcript/TimelineMeta.d.ts +9 -0
  221. package/dist/components/transcript/TimelineMeta.js +161 -0
  222. package/dist/components/transcript/TranscriptLoading.d.ts +10 -0
  223. package/dist/components/transcript/TranscriptLoading.js +10 -0
  224. package/dist/components/transcript/WebDetail.d.ts +8 -0
  225. package/dist/components/transcript/WebDetail.js +29 -0
  226. package/dist/components/transcript/Workflow.d.ts +12 -0
  227. package/dist/components/transcript/Workflow.js +208 -0
  228. package/dist/components/transcript/activity-plan.d.ts +84 -0
  229. package/dist/components/transcript/activity-plan.js +209 -0
  230. package/dist/components/transcript/attachment-file-source.d.ts +23 -0
  231. package/dist/components/transcript/attachment-file-source.js +103 -0
  232. package/dist/components/transcript/attachment-gallery.d.ts +12 -0
  233. package/dist/components/transcript/attachment-gallery.js +33 -0
  234. package/dist/components/transcript/detail-parts.d.ts +50 -0
  235. package/dist/components/transcript/detail-parts.js +295 -0
  236. package/dist/components/transcript/disclosure-state.d.ts +6 -0
  237. package/dist/components/transcript/disclosure-state.js +32 -0
  238. package/dist/components/transcript/disclosure-store.d.ts +8 -0
  239. package/dist/components/transcript/disclosure-store.js +31 -0
  240. package/dist/components/transcript/document-model.d.ts +15 -0
  241. package/dist/components/transcript/document-model.js +104 -0
  242. package/dist/components/transcript/document-plan.d.ts +28 -0
  243. package/dist/components/transcript/document-plan.js +145 -0
  244. package/dist/components/transcript/fold-preference.d.ts +17 -0
  245. package/dist/components/transcript/fold-preference.js +63 -0
  246. package/dist/components/transcript/glyphs.d.ts +15 -0
  247. package/dist/components/transcript/glyphs.js +47 -0
  248. package/dist/components/transcript/index.d.ts +23 -0
  249. package/dist/components/transcript/index.js +22 -0
  250. package/dist/components/transcript/message-file-source.d.ts +15 -0
  251. package/dist/components/transcript/message-file-source.js +31 -0
  252. package/dist/components/transcript/message-preview.d.ts +9 -0
  253. package/dist/components/transcript/message-preview.js +46 -0
  254. package/dist/components/transcript/read-file-source.d.ts +7 -0
  255. package/dist/components/transcript/read-file-source.js +34 -0
  256. package/dist/components/transcript/reader-context.d.ts +13 -0
  257. package/dist/components/transcript/reader-context.js +55 -0
  258. package/dist/components/transcript/reading-identity.d.ts +2 -0
  259. package/dist/components/transcript/reading-identity.js +52 -0
  260. package/dist/components/transcript/scroll-to-row.d.ts +2 -0
  261. package/dist/components/transcript/scroll-to-row.js +13 -0
  262. package/dist/components/transcript/thread-index.d.ts +14 -0
  263. package/dist/components/transcript/thread-index.js +40 -0
  264. package/dist/components/transcript/thread-navigation.d.ts +5 -0
  265. package/dist/components/transcript/thread-navigation.js +3 -0
  266. package/dist/components/transcript/timeline-meta-file-source.d.ts +6 -0
  267. package/dist/components/transcript/timeline-meta-file-source.js +55 -0
  268. package/dist/components/transcript/timeline-meta-state.d.ts +12 -0
  269. package/dist/components/transcript/timeline-meta-state.js +24 -0
  270. package/dist/components/ui/ColumnHeading.d.ts +27 -0
  271. package/dist/components/ui/ColumnHeading.js +7 -0
  272. package/dist/components/ui/ConfirmDialog.d.ts +14 -0
  273. package/dist/components/ui/ConfirmDialog.js +22 -0
  274. package/dist/components/ui/DialogShell.d.ts +18 -0
  275. package/dist/components/ui/DialogShell.js +40 -0
  276. package/dist/components/ui/EmptyState.d.ts +10 -0
  277. package/dist/components/ui/EmptyState.js +6 -0
  278. package/dist/components/ui/ListSummaryHeader.d.ts +9 -0
  279. package/dist/components/ui/ListSummaryHeader.js +6 -0
  280. package/dist/components/ui/ListToolbar.d.ts +6 -0
  281. package/dist/components/ui/ListToolbar.js +5 -0
  282. package/dist/components/ui/ResultGroupHeader.d.ts +9 -0
  283. package/dist/components/ui/ResultGroupHeader.js +5 -0
  284. package/dist/components/ui/SegmentedControl.d.ts +16 -0
  285. package/dist/components/ui/SegmentedControl.js +9 -0
  286. package/dist/components/ui/SummaryMetric.d.ts +13 -0
  287. package/dist/components/ui/SummaryMetric.js +10 -0
  288. package/dist/components/ui/Veil.d.ts +7 -0
  289. package/dist/components/ui/Veil.js +5 -0
  290. package/dist/components/ui/index.d.ts +20 -0
  291. package/dist/components/ui/index.js +10 -0
  292. package/dist/components/worktree/WorktreeColumn.d.ts +22 -0
  293. package/dist/components/worktree/WorktreeColumn.js +170 -0
  294. package/dist/components/worktree/WorktreeFileTree.d.ts +19 -0
  295. package/dist/components/worktree/WorktreeFileTree.js +60 -0
  296. package/dist/components/worktree/WorktreeHeader.d.ts +32 -0
  297. package/dist/components/worktree/WorktreeHeader.js +81 -0
  298. package/dist/components/worktree/WorktreeList.d.ts +8 -0
  299. package/dist/components/worktree/WorktreeList.js +12 -0
  300. package/dist/components/worktree/index.d.ts +12 -0
  301. package/dist/components/worktree/index.js +7 -0
  302. package/dist/components/worktree/types.d.ts +17 -0
  303. package/dist/components/worktree/types.js +3 -0
  304. package/dist/components/worktree/use-worktree-guest.d.ts +21 -0
  305. package/dist/components/worktree/use-worktree-guest.js +92 -0
  306. package/dist/components/worktree/worktree-file-commands.d.ts +19 -0
  307. package/dist/components/worktree/worktree-file-commands.js +112 -0
  308. package/dist/components/worktree/worktree-file-source.d.ts +15 -0
  309. package/dist/components/worktree/worktree-file-source.js +75 -0
  310. package/dist/components/worktree/worktree-host.d.ts +31 -0
  311. package/dist/components/worktree/worktree-host.js +242 -0
  312. package/dist/fixtures/index.d.ts +24 -0
  313. package/dist/fixtures/index.js +292 -0
  314. package/dist/host-inputs.d.ts +231 -0
  315. package/dist/host-inputs.js +35 -0
  316. package/dist/index.d.ts +18 -0
  317. package/dist/index.js +14 -0
  318. package/dist/lib/activity-details.d.ts +23 -0
  319. package/dist/lib/activity-details.js +78 -0
  320. package/dist/lib/activity-order.d.ts +32 -0
  321. package/dist/lib/activity-order.js +86 -0
  322. package/dist/lib/agent-paths.d.ts +6 -0
  323. package/dist/lib/agent-paths.js +19 -0
  324. package/dist/lib/agents.d.ts +15 -0
  325. package/dist/lib/agents.js +60 -0
  326. package/dist/lib/catalog-status.d.ts +3 -0
  327. package/dist/lib/catalog-status.js +10 -0
  328. package/dist/lib/chart-data.d.ts +14 -0
  329. package/dist/lib/chart-data.js +151 -0
  330. package/dist/lib/day-activity.d.ts +21 -0
  331. package/dist/lib/day-activity.js +56 -0
  332. package/dist/lib/format.d.ts +24 -0
  333. package/dist/lib/format.js +116 -0
  334. package/dist/lib/hooks.d.ts +118 -0
  335. package/dist/lib/hooks.js +608 -0
  336. package/dist/lib/icons.d.ts +21 -0
  337. package/dist/lib/icons.js +49 -0
  338. package/dist/lib/image-media.d.ts +6 -0
  339. package/dist/lib/image-media.js +30 -0
  340. package/dist/lib/ingest-activity.d.ts +50 -0
  341. package/dist/lib/ingest-activity.js +151 -0
  342. package/dist/lib/ingest.d.ts +25 -0
  343. package/dist/lib/ingest.js +70 -0
  344. package/dist/lib/model-labels.d.ts +5 -0
  345. package/dist/lib/model-labels.js +28 -0
  346. package/dist/lib/model.d.ts +73 -0
  347. package/dist/lib/model.js +141 -0
  348. package/dist/lib/motion.d.ts +13 -0
  349. package/dist/lib/motion.js +80 -0
  350. package/dist/lib/room-storage.d.ts +13 -0
  351. package/dist/lib/room-storage.js +40 -0
  352. package/dist/lib/search-results.d.ts +27 -0
  353. package/dist/lib/search-results.js +83 -0
  354. package/dist/lib/search-sheet.d.ts +119 -0
  355. package/dist/lib/search-sheet.js +282 -0
  356. package/dist/lib/sections.d.ts +19 -0
  357. package/dist/lib/sections.js +36 -0
  358. package/dist/lib/session-activity.d.ts +5 -0
  359. package/dist/lib/session-activity.js +15 -0
  360. package/dist/lib/session-leases.d.ts +15 -0
  361. package/dist/lib/session-leases.js +61 -0
  362. package/dist/lib/spend.d.ts +42 -0
  363. package/dist/lib/spend.js +112 -0
  364. package/dist/lib/tint.d.ts +9 -0
  365. package/dist/lib/tint.js +53 -0
  366. package/dist/lib/transcript/collaboration.d.ts +97 -0
  367. package/dist/lib/transcript/collaboration.js +423 -0
  368. package/dist/lib/transcript/families.d.ts +212 -0
  369. package/dist/lib/transcript/families.js +906 -0
  370. package/dist/lib/transcript/favicons.d.ts +54 -0
  371. package/dist/lib/transcript/favicons.js +183 -0
  372. package/dist/lib/transcript/head-of-document.d.ts +27 -0
  373. package/dist/lib/transcript/head-of-document.js +274 -0
  374. package/dist/lib/transcript/head-state.d.ts +182 -0
  375. package/dist/lib/transcript/head-state.js +305 -0
  376. package/dist/lib/transcript/history-window.d.ts +13 -0
  377. package/dist/lib/transcript/history-window.js +52 -0
  378. package/dist/lib/transcript/images.d.ts +8 -0
  379. package/dist/lib/transcript/images.js +60 -0
  380. package/dist/lib/transcript/index.d.ts +15 -0
  381. package/dist/lib/transcript/index.js +8 -0
  382. package/dist/lib/transcript/ledger.d.ts +143 -0
  383. package/dist/lib/transcript/ledger.js +513 -0
  384. package/dist/lib/transcript/protocol.d.ts +23 -0
  385. package/dist/lib/transcript/protocol.js +1 -0
  386. package/dist/lib/transcript/sittings.d.ts +75 -0
  387. package/dist/lib/transcript/sittings.js +147 -0
  388. package/dist/lib/transcript/tail-scroll.d.ts +36 -0
  389. package/dist/lib/transcript/tail-scroll.js +167 -0
  390. package/dist/lib/transcript/tail-state.d.ts +17 -0
  391. package/dist/lib/transcript/tail-state.js +30 -0
  392. package/dist/lib/transcript/turns.d.ts +192 -0
  393. package/dist/lib/transcript/turns.js +576 -0
  394. package/dist/lib/transcript/use-transcript-opening.d.ts +12 -0
  395. package/dist/lib/transcript/use-transcript-opening.js +31 -0
  396. package/dist/lib/transcript/use-transcript-tail.d.ts +25 -0
  397. package/dist/lib/transcript/use-transcript-tail.js +158 -0
  398. package/dist/lib/transcript/vocabulary.d.ts +119 -0
  399. package/dist/lib/transcript/vocabulary.js +293 -0
  400. package/dist/lib/transcript/web-address.d.ts +6 -0
  401. package/dist/lib/transcript/web-address.js +18 -0
  402. package/dist/lib/transcript/workflow.d.ts +31 -0
  403. package/dist/lib/transcript/workflow.js +133 -0
  404. package/dist/lib/use-activity-order.d.ts +2 -0
  405. package/dist/lib/use-activity-order.js +23 -0
  406. package/dist/lib/use-day-usage.d.ts +8 -0
  407. package/dist/lib/use-day-usage.js +31 -0
  408. package/dist/lib/use-deferred-list-order.d.ts +26 -0
  409. package/dist/lib/use-deferred-list-order.js +142 -0
  410. package/dist/lib/use-ingest-activity.d.ts +2 -0
  411. package/dist/lib/use-ingest-activity.js +49 -0
  412. package/dist/lib/use-list-motion.d.ts +4 -0
  413. package/dist/lib/use-list-motion.js +67 -0
  414. package/dist/ports.d.ts +222 -0
  415. package/dist/ports.js +3 -0
  416. package/dist/room-context.d.ts +60 -0
  417. package/dist/room-context.js +87 -0
  418. package/dist/styles/activity-chart.css +127 -0
  419. package/dist/styles/attachments.css +29 -0
  420. package/dist/styles/favicon.css +73 -0
  421. package/dist/styles/history-room.css +18 -0
  422. package/dist/styles/host-inputs.css +250 -0
  423. package/dist/styles/image-gallery.css +30 -0
  424. package/dist/styles/ingest.css +51 -0
  425. package/dist/styles/message-preview.css +34 -0
  426. package/dist/styles/models-chart.css +66 -0
  427. package/dist/styles/project-chart.css +19 -0
  428. package/dist/styles/reader.css +33 -0
  429. package/dist/styles/room.css +1411 -0
  430. package/dist/styles/search.css +252 -0
  431. package/dist/styles/transcript-activity.css +70 -0
  432. package/dist/styles/transcript-head.css +220 -0
  433. package/dist/styles/transcript-loading.css +57 -0
  434. package/dist/styles/transcript.css +1226 -0
  435. package/package.json +61 -4
@@ -0,0 +1,46 @@
1
+ import type { ReactNode } from "react";
2
+ import type { SessionRow } from "@vibefield/rosetta-protocol";
3
+ import type { TimelineFeed } from "../lib/hooks.js";
4
+ import type { ProjectViewModel } from "../lib/model.js";
5
+ import type { ThreadFocus } from "./transcript/thread-index.js";
6
+ import type { RoomHeadActs } from "../host-inputs.js";
7
+ export type { ThreadFocus } from "./transcript/thread-index.js";
8
+ /** The stepper's face: the query, where the reader is, how many there are. */
9
+ export interface MatchStepperState {
10
+ readonly query: string;
11
+ readonly at: number;
12
+ readonly total: number;
13
+ }
14
+ export interface TranscriptColumnProps {
15
+ readonly session: SessionRow | null;
16
+ /** The cold backfill is running — threaded to every watermark. */
17
+ readonly duringBackfill: boolean;
18
+ /** Full metadata topology. Only roots are navigable, but descendants are
19
+ * needed here to build the embedded thread tree. */
20
+ readonly sessions: readonly SessionRow[];
21
+ readonly project: ProjectViewModel | null;
22
+ readonly feed: TimelineFeed;
23
+ readonly focus: ThreadFocus | null;
24
+ readonly onFocusConsumed: () => void;
25
+ readonly onReceipt: (text: string) => void;
26
+ /** The sentence under "No session open": the host's, or the room's own,
27
+ * which names a search key only when the host binds one (RO-14). */
28
+ readonly emptyPrompt: ReactNode;
29
+ /** The search sheet's tail: this session's matches, walked from the head. */
30
+ readonly stepper: MatchStepperState | null;
31
+ readonly onStepMatch: (delta: 1 | -1) => void;
32
+ readonly onDismissStepper: () => void;
33
+ /** The session's runtime, for the reply's mark and name (T-4). */
34
+ readonly getRuntimeKind: (runtimeId: string) => string;
35
+ readonly homeDirectory: string | null;
36
+ readonly onOpenThread?: (sessionId: string) => void;
37
+ readonly onBackToParent?: (() => void) | null;
38
+ /** The reader (PK3): the document alone, read-only. No head band and no
39
+ * acts — no session work, no day menu, no "Latest", no dialog — and a
40
+ * landing stays marked rather than fading. */
41
+ readonly reader?: boolean | undefined;
42
+ /** R5: the host's acts in the head, before the activity act, or its reason
43
+ * after the range. */
44
+ readonly headActs?: RoomHeadActs | null | undefined;
45
+ }
46
+ export declare function TranscriptColumn(props: TranscriptColumnProps): import("react").JSX.Element;
@@ -0,0 +1,358 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Column ④ — the transcript: a document, not a chat log.
3
+ //
4
+ // The column is the frame; the document inside it is `components/transcript`.
5
+ // What lives here is what belongs to the COLUMN rather than to the reading:
6
+ // the head band and its two acts, the scroller and the four things pinned to
7
+ // it (the top fade, the day pill's menu, the earlier receipt, the live tail's
8
+ // notice), the match stepper the search sheet leaves in the head, and the
9
+ // focus landing that brings a search hit home.
10
+ //
11
+ // Its props are App.tsx's contract and have not moved, except for the two
12
+ // facts the record's own drawing needs: the session's runtime (the reply's
13
+ // mark and name, T-4) and the viewer's home directory (a path is drawn
14
+ // relative to the session's cwd, then home-relative — never the eleven leading
15
+ // characters that are the same on every line).
16
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
17
+ import { clockShort } from "../lib/format.js";
18
+ import { useHeadOfDocument } from "../lib/transcript/head-of-document.js";
19
+ import { useTranscriptTail } from "../lib/transcript/use-transcript-tail.js";
20
+ import { useTranscriptOpening } from "../lib/transcript/use-transcript-opening.js";
21
+ import { prefersReducedMotion } from "../lib/motion.js";
22
+ import { MatchStepper } from "./search/index.js";
23
+ import { getSessionTitle } from "./sessions/session-display.js";
24
+ import { DayMenu, markStuckPills } from "./transcript/DayPill.js";
25
+ import { TranscriptDocument } from "./transcript/Document.js";
26
+ import { TranscriptLoading } from "./transcript/TranscriptLoading.js";
27
+ import { useTranscriptModel } from "./transcript/document-model.js";
28
+ import { useFoldPreference } from "./transcript/fold-preference.js";
29
+ import { MessageViewerContext } from "./transcript/MessagePreview.js";
30
+ import { ThreadNavigationContext } from "./transcript/thread-navigation.js";
31
+ import { handleForMessage, messageFileSource } from "./transcript/message-file-source.js";
32
+ import { attachmentStatus } from "./transcript/Attachments.js";
33
+ import { AuthoredMessage } from "./transcript/AuthoredMessage.js";
34
+ import { ActivityGlyph } from "./transcript/glyphs.js";
35
+ import { HeadOfDocument, TopFade } from "./transcript/HeadOfDocument.js";
36
+ import { ReceiptPill } from "./transcript/ReceiptPill.js";
37
+ import { TimelineMeta } from "./transcript/TimelineMeta.js";
38
+ import { buildThreadIndex, messageDomId } from "./transcript/thread-index.js";
39
+ import { ColumnHeading, EmptyState } from "./ui/index.js";
40
+ import { FileViewerDialog } from "./file-viewer/index.js";
41
+ import { ImageGalleryDialog } from "./file-viewer/ImageGalleryDialog.js";
42
+ import { useAttachmentReader } from "./transcript/attachment-file-source.js";
43
+ import { attachmentGallery, createAttachmentGallerySource } from "./transcript/attachment-gallery.js";
44
+ import { handleForReadPath, transcriptReadFileSource, } from "./transcript/read-file-source.js";
45
+ import { handleForTimelineMetaArtifact, handleForTimelineMetaPlan, timelineMetaFileSource, } from "./transcript/timeline-meta-file-source.js";
46
+ import { scrollRowTo } from "./transcript/scroll-to-row.js";
47
+ import { HostAct } from "./HostAct.js";
48
+ import { activityCuts } from "./transcript/activity-plan.js";
49
+ import { ReadingSessionProvider, useRoom } from "../room-context.js";
50
+ /** The receipt lands beneath a pinned day pill, never over it (§08).
51
+ * Measured rather than guessed: the scroller starts 46px down (the head band),
52
+ * a pinned pill occupies 58–80, and the first pill still in the flow starts at
53
+ * 124. 88 is the one band that clears both. */
54
+ const RECEIPT_TOP = 88;
55
+ export function TranscriptColumn(props) {
56
+ // Selection owns the document's disclosures, overlays and opening state.
57
+ // Reset them in the selection commit, before the previous session can paint.
58
+ return (_jsx(ReadingSessionProvider, { value: props.session?.id ?? null, children: _jsx(SessionTranscript, { ...props }, props.session?.id ?? "no-session") }));
59
+ }
60
+ function SessionTranscript({ session, duringBackfill, sessions, project, feed, focus, onFocusConsumed, onReceipt, emptyPrompt, stepper, onStepMatch, onDismissStepper, getRuntimeKind, homeDirectory, onOpenThread, onBackToParent, reader = false, headActs = null, }) {
61
+ const { sessions: leases, host } = useRoom();
62
+ const listBrowsers = useMemo(() => host?.browsers?.bind(host), [host]);
63
+ const openInBrowser = useMemo(() => (host === null ? null : (name, bytes, browserId) => host.openInBrowser(name, bytes, browserId)), [host]);
64
+ const attachments = useAttachmentReader();
65
+ const gallerySource = useMemo(() => createAttachmentGallerySource(attachments), [attachments]);
66
+ const threadNavigation = useMemo(() => ({ depth: 0, open: onOpenThread ?? null }), [onOpenThread]);
67
+ const scrollRef = useRef(null);
68
+ const focusAfterOpening = useRef(false);
69
+ const [highlightedTimelineId, setHighlightedTimelineId] = useState(null);
70
+ const [menu, setMenu] = useState(null);
71
+ const [viewerTarget, setViewerTarget] = useState(null);
72
+ const [imageGallery, setImageGallery] = useState(null);
73
+ const [metaFocus, setMetaFocus] = useState(null);
74
+ const viewerRequest = useRef(0);
75
+ const anchorRequest = useRef(0);
76
+ const focusTries = useRef(0);
77
+ // One exact read per landing target, before any blind walk.
78
+ const anchorTried = useRef(null);
79
+ const index = useMemo(() => buildThreadIndex(sessions), [sessions]);
80
+ const fold = useFoldPreference();
81
+ const requestedTimelineId = focus !== null && focus.sessionId === session?.id ? focus.timelineId : null;
82
+ const targetTimelineId = requestedTimelineId ?? metaFocus?.timelineId ?? null;
83
+ const targetIsMeta = requestedTimelineId === null && metaFocus !== null;
84
+ const cuts = useMemo(() => activityCuts(feed.rows, feed.watermark), [feed.rows, feed.watermark]);
85
+ const model = useTranscriptModel(feed.rows, session, homeDirectory, Date.now(), { cutBefore: cuts.cutBefore });
86
+ const opening = useTranscriptOpening(feed.snapshotReady, focus !== null || metaFocus !== null);
87
+ const loading = session !== null && opening.visible;
88
+ useEffect(() => {
89
+ if (loading || !focusAfterOpening.current)
90
+ return;
91
+ focusAfterOpening.current = false;
92
+ scrollRef.current?.focus({ preventScroll: true });
93
+ }, [loading]);
94
+ // §08 — the head of the document: approach fetches and holds, the pull
95
+ // reveals, and the landing keeps the reader exactly where they were.
96
+ const headOfDocument = useHeadOfDocument(scrollRef, feed, {
97
+ enabled: session !== null && !loading,
98
+ });
99
+ const tail = useTranscriptTail(scrollRef, session?.id ?? null, session !== null, focus !== null || metaFocus !== null, loading);
100
+ const displayedLayout = useRef(null);
101
+ const onTimelineLayout = useCallback((layout) => {
102
+ displayedLayout.current = layout;
103
+ tail.onLayout(layout);
104
+ opening.onLayout(layout);
105
+ }, [tail.onLayout, opening.onLayout, loading]);
106
+ useEffect(() => () => {
107
+ // A keyed session change unmounts this scope; invalidate any exact reads
108
+ // that could otherwise deliver a receipt after the reader has moved on.
109
+ viewerRequest.current += 1;
110
+ anchorRequest.current += 1;
111
+ }, []);
112
+ const openAttachment = (fact, row) => {
113
+ // The reader opens nothing over its host: it shows the document as it is.
114
+ if (reader)
115
+ return;
116
+ viewerRequest.current += 1;
117
+ if (!attachments.canOpen(fact)) {
118
+ onReceipt(attachmentStatus(fact));
119
+ return;
120
+ }
121
+ if (viewerTarget?.message === undefined)
122
+ setViewerTarget(null);
123
+ setImageGallery(attachmentGallery(attachments, fact, row));
124
+ };
125
+ const openMessage = useCallback((message) => {
126
+ viewerRequest.current += 1;
127
+ setViewerTarget({ handle: handleForMessage(message),
128
+ source: message.recordedText?.type === "member" ? attachments.fileSource : messageFileSource, message });
129
+ }, [attachments]);
130
+ const openReadPath = (path, previewBytes, name) => {
131
+ if (reader)
132
+ return;
133
+ const request = (viewerRequest.current += 1);
134
+ void handleForReadPath(leases, path, previewBytes, name)
135
+ .then((handle) => {
136
+ if (request !== viewerRequest.current)
137
+ return;
138
+ if (handle === null) {
139
+ onReceipt("That row did not record an openable file");
140
+ return;
141
+ }
142
+ setViewerTarget({ handle, source: transcriptReadFileSource });
143
+ })
144
+ .catch((error) => {
145
+ if (request !== viewerRequest.current)
146
+ return;
147
+ onReceipt(error instanceof Error ? error.message : "Could not open that recorded file");
148
+ });
149
+ };
150
+ const openMetaFile = (load, unavailable) => {
151
+ const request = (viewerRequest.current += 1);
152
+ void load()
153
+ .then((handle) => {
154
+ if (request !== viewerRequest.current)
155
+ return;
156
+ setViewerTarget({ handle, source: timelineMetaFileSource });
157
+ })
158
+ .catch((error) => {
159
+ if (request !== viewerRequest.current)
160
+ return;
161
+ onReceipt(error instanceof Error ? error.message : unavailable);
162
+ });
163
+ };
164
+ const openMetaPlan = (plan) => {
165
+ if (session === null)
166
+ return;
167
+ openMetaFile(() => handleForTimelineMetaPlan(leases, session.id, plan), "Could not open that recorded plan");
168
+ };
169
+ const openMetaArtifact = (artifact) => {
170
+ if (session === null)
171
+ return;
172
+ openMetaFile(() => handleForTimelineMetaArtifact(leases, session.id, artifact), "Could not open that recorded artifact");
173
+ };
174
+ const openMetaTimeline = (timelineId, label, kind) => {
175
+ if (timelineId === null) {
176
+ onReceipt(`That ${kind} has no recorded message anchor`);
177
+ return;
178
+ }
179
+ const land = () => {
180
+ focusTries.current = 0;
181
+ setMetaFocus({ timelineId, label, kind });
182
+ };
183
+ if (model.representatives.has(timelineId)) {
184
+ land();
185
+ return;
186
+ }
187
+ const request = (anchorRequest.current += 1);
188
+ void feed.loadAnchor(timelineId)
189
+ .then((loaded) => {
190
+ if (request !== anchorRequest.current || !loaded)
191
+ return;
192
+ land();
193
+ })
194
+ .catch((error) => {
195
+ if (request !== anchorRequest.current)
196
+ return;
197
+ onReceipt(error instanceof Error ? error.message : `Could not load that ${kind} message`);
198
+ });
199
+ };
200
+ const openMetaTask = (task) => {
201
+ openMetaTimeline(task.timeline_id, task.subject, "task");
202
+ };
203
+ const openMetaWorkflow = (workflow) => {
204
+ openMetaTimeline(workflow.timeline_id, workflow.name, "workflow");
205
+ };
206
+ useEffect(() => {
207
+ focusTries.current = 0;
208
+ anchorTried.current = null;
209
+ // Only a NEW target clears the ring. Consuming the focus sets the target
210
+ // to null, and clearing on that would wipe the ring in the same frame it
211
+ // was drawn — the landing would scroll and then show nothing.
212
+ if (targetTimelineId !== null)
213
+ setHighlightedTimelineId(null);
214
+ }, [targetTimelineId]);
215
+ useEffect(() => {
216
+ // Wait for the subscription to have DELIVERED, not merely opened: a feed
217
+ // that has not had its first snapshot reports nothing above it, and acting
218
+ // on that would tell the reader a row is older than the loaded history
219
+ // one frame before the history exists.
220
+ if (targetTimelineId === null ||
221
+ session === null ||
222
+ !feed.snapshotReady ||
223
+ (feed.status !== "live" && feed.status !== "resyncing")) {
224
+ return;
225
+ }
226
+ // A fold draws several rows as one line, so the landing goes to the
227
+ // element that CONTAINS the row rather than failing to find its own.
228
+ const drawnBy = model.representatives.get(targetTimelineId) ?? null;
229
+ if (drawnBy !== null) {
230
+ const displayed = displayedLayout.current?.sessionId === session.id ? displayedLayout.current : null;
231
+ const element = displayed?.elementForAnchor?.(targetTimelineId)
232
+ ?? document.getElementById(messageDomId(session.id, drawnBy));
233
+ const scroller = scrollRef.current;
234
+ if (element && scroller) {
235
+ tail.pause();
236
+ // Scroll the transcript's own scroller, never `scrollIntoView`: that
237
+ // walks every ancestor, and the room's overflow-hidden frame would
238
+ // quietly scroll the search strip out of the window (seen 2026-09-09).
239
+ if (element.getClientRects().length > 0)
240
+ scrollRowTo(scroller, element, "center");
241
+ setHighlightedTimelineId(element.dataset.timelineId ?? drawnBy);
242
+ if (targetIsMeta) {
243
+ onReceipt(`Landed on the ${metaFocus.kind} message · ${metaFocus.label}`);
244
+ setMetaFocus(null);
245
+ }
246
+ else {
247
+ onFocusConsumed();
248
+ }
249
+ if (!reader)
250
+ window.setTimeout(() => setHighlightedTimelineId(null), 1500);
251
+ }
252
+ return;
253
+ }
254
+ // timeline_meta resolves exact anchors before setting focus.
255
+ if (targetIsMeta) {
256
+ const kind = metaFocus.kind;
257
+ setMetaFocus(null);
258
+ onReceipt(`That ${kind} message is no longer available`);
259
+ return;
260
+ }
261
+ // A search landing asks for its row exactly, once — the same read the
262
+ // work index uses — and only walks blindly if that row lands but no line
263
+ // draws it yet.
264
+ if (anchorTried.current !== targetTimelineId) {
265
+ anchorTried.current = targetTimelineId;
266
+ const request = (anchorRequest.current += 1);
267
+ void feed.loadAnchor(targetTimelineId)
268
+ .then((loaded) => {
269
+ if (request !== anchorRequest.current || loaded)
270
+ return;
271
+ onFocusConsumed();
272
+ onReceipt("That message is no longer available");
273
+ })
274
+ .catch((error) => {
275
+ if (request !== anchorRequest.current)
276
+ return;
277
+ onFocusConsumed();
278
+ onReceipt(error instanceof Error ? error.message : "Could not load that message");
279
+ });
280
+ return;
281
+ }
282
+ if (feed.earlier.kind !== "none" && focusTries.current < 8) {
283
+ focusTries.current += 1;
284
+ feed.loadEarlier();
285
+ }
286
+ else if (feed.earlier.kind === "none") {
287
+ if (targetIsMeta)
288
+ setMetaFocus(null);
289
+ else
290
+ onFocusConsumed();
291
+ onReceipt("That message is older than the loaded history");
292
+ }
293
+ }, [targetTimelineId, targetIsMeta, metaFocus, session, feed, model, onFocusConsumed, onReceipt, reader]);
294
+ // The pill pins while the reader is inside its day, and returns to its
295
+ // hairline the moment that day scrolls back into view.
296
+ useEffect(() => {
297
+ markStuckPills(scrollRef.current);
298
+ }, [model.plan]);
299
+ const range = (() => {
300
+ if (!session)
301
+ return "";
302
+ if (!session.activity)
303
+ return "Activity time unknown";
304
+ return `${clockShort(session.activity.first_at)} → ${clockShort(session.activity.last_at)}`;
305
+ })();
306
+ const jumpToDay = (day) => {
307
+ setMenu(null);
308
+ const scroller = scrollRef.current;
309
+ if (scroller === null)
310
+ return;
311
+ const target = scroller.querySelector(`[data-sitting-key="${CSS.escape(day.firstSittingKey)}"]`);
312
+ if (target === null)
313
+ return;
314
+ // Section-relative offsets do not survive a sticky pill; the rects do.
315
+ tail.pause();
316
+ scroller.scrollTo({
317
+ top: target.getBoundingClientRect().top - scroller.getBoundingClientRect().top + scroller.scrollTop - 4,
318
+ behavior: prefersReducedMotion() ? "instant" : "smooth",
319
+ });
320
+ const prompt = target.querySelector(".tr-prompt");
321
+ if (prompt === null)
322
+ return;
323
+ prompt.classList.add("is-landed");
324
+ window.setTimeout(() => prompt.classList.remove("is-landed"), 1400);
325
+ };
326
+ return (_jsx(ThreadNavigationContext.Provider, { value: threadNavigation, children: _jsx(MessageViewerContext.Provider, { value: reader ? null : openMessage, children: _jsxs("div", { className: "ah-col ah-col--measure", style: { position: "relative" }, "data-fold": fold.folded ? "on" : "off", children: [!reader && _jsxs("header", { children: [onBackToParent && _jsx("button", { type: "button", className: "tr-parent-link", title: "Back to parent transcript", "aria-label": "Back to parent transcript", onClick: onBackToParent, children: "\u2190" }), session === null ? (_jsx("div", { className: "ah-colhead", children: _jsx("span", { className: "ah-eyebrow", children: "Transcript" }) })) : (_jsx(ColumnHeading, { name: getSessionTitle(session), tint: project?.tint ?? null, count: loading ? null : feed.rows.length, countTitle: `${feed.rows.length} messages loaded` })), _jsxs("span", { className: "ah-headacts", children: [stepper !== null && session !== null ? (_jsx(MatchStepper, { query: stepper.query, at: stepper.at, total: stepper.total, onStep: onStepMatch, onDismiss: onDismissStepper })) : (_jsx("span", { className: "ah-caption tnum", children: range })), session !== null && headActs !== null && headActs.reason !== undefined && headActs.reason !== null && (_jsx("span", { className: "ah-caption ah-headreason", children: headActs.reason })), session !== null && headActs?.acts?.map((act) => _jsx(HostAct, { act: act, place: "pill" }, act.key)), session !== null && (
327
+ // §05 — the activity act, beside the range. Folded is the default;
328
+ // the reader who wants the build log gets it in one press, and the
329
+ // preference is per room, not per run.
330
+ _jsx("button", { type: "button", className: "ah-iconbtn", "aria-pressed": fold.folded, title: fold.folded
331
+ ? "Activity: conversation — show activity"
332
+ : "Activity: showing activity — return to conversation", onClick: fold.toggle, children: _jsx(ActivityGlyph, {}) }))] })] }), _jsxs("div", { className: "tr-stage", "data-ready": !loading || undefined, children: [_jsxs("div", { className: "tr-surface", inert: loading, "aria-hidden": loading || undefined, children: [!reader && session !== null && feed.timelineMeta !== null && (_jsx(TimelineMeta, { meta: feed.timelineMeta, onOpenTask: openMetaTask, onOpenWorkflow: openMetaWorkflow, onOpenPlan: openMetaPlan, onOpenArtifact: openMetaArtifact })), _jsxs("div", { className: "ah-scroll tr-scroll", "data-flush": "", ref: scrollRef, tabIndex: 0, role: "region", "aria-label": "Session messages", "aria-busy": loading, onScroll: () => markStuckPills(scrollRef.current), children: [_jsx(TopFade, {}), session === null ? (_jsx(EmptyState, { title: "No session open", description: emptyPrompt })) : (_jsx("div", { className: "tr-col", children: _jsx("div", { className: "tr", children: _jsx(TranscriptDocument, { session: session, model: model, feed: feed, duringBackfill: duringBackfill, index: index, focus: focus, highlightedTimelineId: highlightedTimelineId, onFocusConsumed: onFocusConsumed, onReceipt: onReceipt, onOpenAttachment: openAttachment, onOpenPath: openReadPath, getRuntimeKind: getRuntimeKind, homeDirectory: homeDirectory, onTimelineLayout: onTimelineLayout, onPillPress: reader ? null : (element, dayKey) => {
333
+ const frame = element.closest(".ah-col");
334
+ if (frame === null)
335
+ return;
336
+ const top = element.getBoundingClientRect().bottom - frame.getBoundingClientRect().top + 6;
337
+ setMenu((open) => (open === null ? { top, dayKey } : null));
338
+ }, head: _jsx(HeadOfDocument, { feed: feed, pull: headOfDocument.pull, startedAt: session.activity?.first_at ?? null, finding: targetTimelineId === null ? null : "an anchor" }) }) }) }))] })] }), loading && _jsx(TranscriptLoading, { error: feed.snapshotReady ? null : feed.error ?? null, waitingForTeam: opening.waitingForTeam, seeking: focus !== null, canContinue: feed.snapshotReady && (opening.waitingForTeam || focus !== null), indexing: duringBackfill && session.stream_state !== "indexed", onRetry: () => { focusAfterOpening.current = true; feed.retry(); }, onContinue: () => {
339
+ focusAfterOpening.current = true;
340
+ if (focus !== null)
341
+ onFocusConsumed();
342
+ tail.latest();
343
+ opening.continueReading();
344
+ } })] }), menu !== null && (_jsx(DayMenu, { days: model.days, currentDayKey: menu.dayKey, top: menu.top, onJump: jumpToDay, onDismiss: () => setMenu(null) })), _jsx(ReceiptPill, { receipt: headOfDocument.receipt, top: RECEIPT_TOP }), !reader && session !== null && (_jsxs("button", { type: "button", className: "ah-newpill", "data-visible": (!loading && tail.away) || undefined, "data-unread": tail.unseen > 0 || undefined, inert: loading || !tail.away, "aria-hidden": loading || !tail.away, "aria-label": tail.unseen > 0
345
+ ? `Scroll to latest · ${tail.unseen} new ${tail.unseen === 1 ? "message" : "messages"}`
346
+ : "Scroll to latest message", onClick: () => {
347
+ // Keep keyboard navigation on the reading surface after the
348
+ // button fades, instead of leaving focus on an inert control.
349
+ scrollRef.current?.focus({ preventScroll: true });
350
+ tail.latest();
351
+ }, children: [_jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: _jsx("path", { d: "M8 3v10m-4-4 4 4 4-4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }), _jsx("span", { children: tail.unseen > 0 ? `${tail.unseen} new ${tail.unseen === 1 ? "message" : "messages"}` : "Latest" }), tail.unseen > 0 && _jsx("i", { "aria-hidden": "true" })] })), !reader && _jsx("span", { className: "ah-tail-announcement", role: "status", "aria-live": "polite", "aria-atomic": "true", children: tail.away && tail.unseen > 0
352
+ ? `${tail.unseen} new ${tail.unseen === 1 ? "message" : "messages"}. Scroll to latest to read.`
353
+ : "" }), !reader && _jsx(FileViewerDialog, { renderMarkdown: viewerTarget?.message === undefined ? undefined : (text) => _jsx(AuthoredMessage, { text: text, messageKey: viewerTarget.message.key, role: viewerTarget.message.role, preview: false, attachments: viewerTarget.message.attachments ?? [], onOpenAttachment: openAttachment, onReceipt: onReceipt }), handle: viewerTarget?.handle ?? null, source: viewerTarget?.source ?? attachments.fileSource, tint: project?.tint ?? null, homeDirectory: homeDirectory, onClose: () => {
354
+ viewerRequest.current += 1;
355
+ setViewerTarget(null);
356
+ setImageGallery(null);
357
+ }, onReceipt: onReceipt, listBrowsers: listBrowsers, openInBrowser: openInBrowser }), !reader && imageGallery && _jsx(ImageGalleryDialog, { ...imageGallery, source: gallerySource, tint: project?.tint ?? null, homeDirectory: homeDirectory, onClose: () => setImageGallery(null), onReceipt: onReceipt, listBrowsers: listBrowsers, openInBrowser: openInBrowser })] }) }) }));
358
+ }
@@ -0,0 +1,13 @@
1
+ import type { CalendarHeatmapData } from "./types.js";
2
+ import "../../styles/activity-chart.css";
3
+ export interface ActivityChartDetailProps {
4
+ readonly projectId: string;
5
+ readonly name: string;
6
+ readonly color: string;
7
+ readonly data: CalendarHeatmapData;
8
+ readonly today: string;
9
+ readonly offsetMinutes: number;
10
+ readonly currentTimestamp: number;
11
+ readonly modelColors: Readonly<Record<string, string>>;
12
+ }
13
+ export declare function ActivityChartDetail({ projectId, name, color, data, today, offsetMinutes, currentTimestamp, modelColors, }: ActivityChartDetailProps): import("react").JSX.Element;
@@ -0,0 +1,78 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useLayoutEffect, useMemo, useState } from "react";
3
+ import { CalendarHeatmap } from "./CalendarHeatmap.js";
4
+ import { DayActivityChart } from "./DayActivityChart.js";
5
+ import { createActivityDetails } from "../../lib/activity-details.js";
6
+ import { useDayUsage } from "../../lib/use-day-usage.js";
7
+ import { tokenText } from "../../lib/format.js";
8
+ import "../../styles/activity-chart.css";
9
+ const WEEKDAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
10
+ function dateLabel(key, weekday = false, year = false) {
11
+ return new Date(`${key}T12:00:00`).toLocaleDateString("en-US", {
12
+ ...(weekday ? { weekday: "short" } : {}),
13
+ ...(weekday || year ? { year: "numeric" } : {}),
14
+ month: "short", day: "numeric",
15
+ });
16
+ }
17
+ export function ActivityChartDetail({ projectId, name, color, data, today, offsetMinutes, currentTimestamp, modelColors, }) {
18
+ const [selectedId, setSelectedId] = useState(null);
19
+ const [preview, setPreview] = useState(null);
20
+ const [calendarElement, setCalendarElement] = useState(null);
21
+ const [calendarWidth, setCalendarWidth] = useState(1000);
22
+ const [calendarPage, setCalendarPage] = useState(null);
23
+ useLayoutEffect(() => {
24
+ const node = calendarElement;
25
+ if (!node)
26
+ return;
27
+ // A visited tab stays mounted while hidden; retain its calendar page layout.
28
+ const measure = () => { if (node.clientWidth > 0)
29
+ setCalendarWidth(node.clientWidth); };
30
+ measure();
31
+ const observer = new ResizeObserver(measure);
32
+ observer.observe(node);
33
+ return () => observer.disconnect();
34
+ }, [calendarElement]);
35
+ const details = useMemo(() => createActivityDetails(data, today), [data, today]);
36
+ const currentIsBest = Boolean(details.currentRun && details.currentRun.start === details.bestRun?.start);
37
+ const availableDays = details.days.filter(day => day.value !== null);
38
+ const selectedDay = availableDays.find(day => day.id === selectedId)
39
+ ?? availableDays.filter(day => day.value > 0).at(-1) ?? availableDays.at(-1) ?? null;
40
+ const selectedIndex = availableDays.findIndex(day => day.id === selectedDay?.id);
41
+ // Page weeks only when the window cannot keep the day targets readable.
42
+ // Day selection and the previous/next-day actions follow their calendar page.
43
+ const maxWeeks = Math.max(1, Math.floor((calendarWidth - 30) / 16));
44
+ const pageCount = Math.max(1, Math.ceil(details.calendar.weeks.length / maxWeeks));
45
+ const weeksPerPage = Math.max(1, Math.ceil(details.calendar.weeks.length / pageCount));
46
+ const selectedWeek = details.calendar.weeks.findIndex(week => week.days.some(day => day.id === selectedDay?.id));
47
+ const page = Math.min(pageCount - 1, calendarPage ?? Math.floor(Math.max(0, selectedWeek) / weeksPerPage));
48
+ const visibleCalendar = { weeks: details.calendar.weeks.slice(page * weeksPerPage, (page + 1) * weeksPerPage) };
49
+ const calendarLayoutWidth = Math.min(calendarWidth, Math.max(300, visibleCalendar.weeks.length * 16 + 30));
50
+ const usage = useDayUsage(projectId, selectedDay?.id ?? null, offsetMinutes);
51
+ const modelRows = usage.data?.models ?? [];
52
+ const hourlyTotal = modelRows.reduce((sum, row) => sum + row.tokens, 0);
53
+ const selectDay = (day) => { setSelectedId(day.id); setPreview(null); setCalendarPage(null); };
54
+ const markers = {};
55
+ for (const day of details.days) {
56
+ const current = details.currentRun && day.id >= details.currentRun.start && day.id <= details.currentRun.end;
57
+ const best = details.bestRun && day.id >= details.bestRun.start && day.id <= details.bestRun.end;
58
+ if (current || best)
59
+ markers[day.id] = current && best ? "both" : current ? "current" : "best";
60
+ }
61
+ const jumpToRun = (run) => {
62
+ setSelectedId(run.end);
63
+ setPreview(null);
64
+ setCalendarPage(null);
65
+ };
66
+ return _jsxs("div", { className: "ah-activity", style: { "--activity-color": color }, children: [_jsxs("section", { className: "ah-activity__calendar", "aria-labelledby": "activity-calendar-title", children: [_jsxs("div", { className: "ah-activity__toolbar", children: [_jsxs("div", { children: [_jsx("h2", { id: "activity-calendar-title", children: "Daily activity" }), _jsxs("p", { children: [dateLabel(details.start, false, true), " \u2013 ", dateLabel(details.end, false, true), " \u00B7 ", details.activeDayCount, " active days"] })] }), pageCount > 1 && _jsxs("div", { className: "ah-activity__calendar-nav", "aria-label": "Calendar pages", children: [_jsx("button", { type: "button", "aria-label": "Earlier calendar weeks", disabled: page === 0, onClick: () => { setCalendarPage(page - 1); setPreview(null); }, children: "\u2190" }), _jsxs("span", { children: [page + 1, "/", pageCount] }), _jsx("button", { type: "button", "aria-label": "Later calendar weeks", disabled: page === pageCount - 1, onClick: () => { setCalendarPage(page + 1); setPreview(null); }, children: "\u2192" })] })] }), _jsx("div", { className: "ah-activity__calendar-scroll", ref: setCalendarElement, children: _jsxs("div", { className: "ah-activity__calendar-layout", style: {
67
+ "--activity-weeks": visibleCalendar.weeks.length,
68
+ "--activity-footer-width": `${Math.max(0, calendarLayoutWidth - 30)}px`,
69
+ width: calendarLayoutWidth,
70
+ }, children: [_jsx("div", { className: "ah-activity__weekdays", "aria-hidden": "true", children: WEEKDAYS.map(day => _jsx("span", { children: day }, day)) }), _jsx(CalendarHeatmap, { data: visibleCalendar, color: color, ariaLabel: `Daily token activity for ${name}. Use arrow keys to navigate days.`, summary: preview ? `${dateLabel(preview.id)} · ${tokenText(preview.value)} tokens`
71
+ : "Select a day", selectedDayId: selectedDay?.id, onDaySelect: selectDay, onDayPreview: setPreview, dayMarkers: markers })] }) }), _jsxs("div", { className: "ah-activity__runs", "aria-label": "Activity runs in the 53-week history", children: [details.currentRun && _jsxs("button", { type: "button", className: "ah-activity__run", "data-run-link": "current", title: `${dateLabel(details.currentRun.start, false, true)} – ${dateLabel(details.currentRun.end, false, true)}`, onClick: () => jumpToRun(details.currentRun), children: [_jsx("i", { "data-kind": currentIsBest ? "both" : "current" }), _jsxs("span", { children: [currentIsBest ? "Current & longest run" : "Current run", " ", _jsxs("b", { children: [details.currentRun.length, " days"] })] }), _jsxs("small", { children: [dateLabel(details.currentRun.start), " \u2013 ", dateLabel(details.currentRun.end)] })] }), details.bestRun && !currentIsBest && _jsxs("button", { type: "button", className: "ah-activity__run", "data-run-link": "best", title: `${dateLabel(details.bestRun.start, false, true)} – ${dateLabel(details.bestRun.end, false, true)}`, onClick: () => jumpToRun(details.bestRun), children: [_jsx("i", { "data-kind": "best" }), _jsxs("span", { children: ["Longest run ", _jsxs("b", { children: [details.bestRun.length, " days"] })] }), _jsxs("small", { children: [dateLabel(details.bestRun.start), " \u2013 ", dateLabel(details.bestRun.end)] })] }), details.busiestDay && _jsxs("button", { type: "button", className: "ah-activity__jump", onClick: () => selectDay(details.busiestDay), children: ["Busiest day ", _jsx("span", { children: dateLabel(details.busiestDay.id) })] })] })] }), _jsxs("section", { className: "ah-activity__day", "aria-labelledby": "activity-day-title", "aria-busy": Boolean(selectedDay && usage.status === "loading"), children: [_jsxs("div", { className: "ah-activity__dayhead", children: [_jsxs("div", { children: [_jsx("h2", { id: "activity-day-title", children: selectedDay ? dateLabel(selectedDay.id, true) : "No recorded days" }), _jsx("p", { children: selectedDay ? `${tokenText(usage.status === "ready" && hourlyTotal > 0 ? hourlyTotal : selectedDay.value)} tokens · hourly activity by model · local time`
72
+ : "Activity will appear here when usage is recorded." })] }), _jsxs("div", { className: "ah-activity__daynav", children: [_jsx("button", { type: "button", "aria-label": "Previous recorded day", disabled: selectedIndex <= 0, onClick: () => selectDay(availableDays[selectedIndex - 1]), children: "\u2190" }), _jsx("button", { type: "button", "aria-label": "Next recorded day", disabled: selectedIndex < 0 || selectedIndex >= availableDays.length - 1, onClick: () => selectDay(availableDays[selectedIndex + 1]), children: "\u2192" })] })] }), !selectedDay ? _jsx("div", { className: "ah-activity__empty", children: "Choose a recorded day in the calendar to explore it." })
73
+ : usage.status === "loading" ? _jsx("div", { className: "ah-activity__empty", role: "status", children: "Loading hourly activity\u2026" })
74
+ : usage.status === "error" ? _jsxs("div", { className: "ah-activity__empty", role: "status", children: [_jsx("strong", { children: "Hourly activity couldn\u2019t be loaded" }), _jsx("span", { children: "Try loading this day again." }), _jsx("button", { type: "button", onClick: usage.retry, children: "Retry" })] })
75
+ : hourlyTotal === 0 ? _jsxs("div", { className: "ah-activity__empty", children: [_jsx("strong", { children: selectedDay.value === 0 ? "No token activity on this day" : "Hourly breakdown unavailable" }), _jsx("span", { children: selectedDay.value === 0 ? "Choose another day to see when and which models were used."
76
+ : "The calendar has a daily total, but no hourly usage was returned for this day." })] })
77
+ : _jsxs(_Fragment, { children: [_jsx(DayActivityChart, { rows: modelRows, modelColors: modelColors, lastHour: selectedDay.id === today ? new Date(currentTimestamp).getHours() : 23 }, selectedDay.id), hourlyTotal !== selectedDay.value && _jsx("p", { className: "ah-activity__updated", children: "Usage has changed since the calendar was loaded." })] })] })] });
78
+ }
@@ -0,0 +1,16 @@
1
+ import type { ReactNode } from "react";
2
+ import type { CalendarHeatmapCellData, CalendarHeatmapData } from "./types.js";
3
+ export interface CalendarHeatmapProps {
4
+ readonly data: CalendarHeatmapData;
5
+ readonly color: string;
6
+ readonly ariaLabel: string;
7
+ readonly summary?: ReactNode;
8
+ readonly lowIntensityLabel?: string;
9
+ readonly highIntensityLabel?: string;
10
+ /** Supplying a selection handler enables keyboard and pointer inspection. */
11
+ readonly selectedDayId?: string | undefined;
12
+ readonly onDaySelect?: (day: CalendarHeatmapCellData) => void;
13
+ readonly onDayPreview?: (day: CalendarHeatmapCellData | null) => void;
14
+ readonly dayMarkers?: Readonly<Record<string, "current" | "best" | "both">>;
15
+ }
16
+ export declare function CalendarHeatmap({ data, color, ariaLabel, summary, lowIntensityLabel, highIntensityLabel, selectedDayId, onDaySelect, onDayPreview, dayMarkers, }: CalendarHeatmapProps): import("react").JSX.Element;
@@ -0,0 +1,55 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ const MAX_INTENSITY_LEVEL = 4;
4
+ const INTENSITY_LEVELS = [0, 1, 2, 3, 4];
5
+ function getIntensityLevel(value, peak) {
6
+ if (!Number.isFinite(value) || value <= 0 || peak <= 0)
7
+ return 0;
8
+ const ratio = value / peak;
9
+ if (ratio > 0.66)
10
+ return 4;
11
+ if (ratio > 0.4)
12
+ return 3;
13
+ if (ratio > 0.18)
14
+ return 2;
15
+ return 1;
16
+ }
17
+ export function CalendarHeatmap({ data, color, ariaLabel, summary, lowIntensityLabel = "less", highIntensityLabel = "more", selectedDayId, onDaySelect, onDayPreview, dayMarkers, }) {
18
+ const availableDays = useMemo(() => data.weeks.flatMap((week) => week.days).filter((day) => day.value !== null), [data]);
19
+ const tabbableDayId = availableDays.find((day) => day.id === selectedDayId)?.id
20
+ ?? availableDays.at(-1)?.id;
21
+ const peak = useMemo(() => data.weeks.reduce((maximum, week) => week.days.reduce((weekMaximum, day) => day.value === null || !Number.isFinite(day.value)
22
+ ? weekMaximum
23
+ : Math.max(weekMaximum, day.value), maximum), 0), [data]);
24
+ return (_jsxs("div", { className: "ah-calendar-heatmap", style: { "--heatmap-color": color }, children: [_jsx("div", { className: "ah-calendar-heatmap__axis", "aria-hidden": "true", children: data.weeks.map((week, weekIndex) => week.label ? (_jsx("span", { style: { left: `${((weekIndex / data.weeks.length) * 100).toFixed(2)}%` }, children: week.label }, week.id)) : null) }), _jsx("div", { className: "ah-calendar-heatmap__grid", role: onDaySelect ? "group" : "img", "aria-label": ariaLabel, onMouseLeave: () => onDayPreview?.(null), children: data.weeks.map((week) => (_jsx("span", { className: "ah-calendar-heatmap__week", "aria-hidden": onDaySelect ? undefined : true, children: week.days.map((day) => {
25
+ const intensity = day.value === null ? 0 : getIntensityLevel(day.value, peak);
26
+ if (onDaySelect && day.value !== null) {
27
+ return (_jsx("button", { type: "button", className: "ah-calendar-heatmap__cell", "data-day": day.id, "data-run": dayMarkers?.[day.id], "data-empty": day.value === 0 ? "" : undefined, style: { "--heatmap-intensity": intensity }, "aria-label": day.label, "aria-pressed": selectedDayId === day.id, tabIndex: tabbableDayId === day.id ? 0 : -1, onClick: () => onDaySelect(day), onMouseEnter: () => onDayPreview?.(day), onFocus: () => onDayPreview?.(day), onBlur: () => onDayPreview?.(null), onKeyDown: (event) => {
28
+ const calendarDays = data.weeks.flatMap((week) => week.days);
29
+ const index = calendarDays.findIndex((entry) => entry.id === day.id);
30
+ const offsets = {
31
+ ArrowUp: -1, ArrowDown: 1, ArrowLeft: -7, ArrowRight: 7,
32
+ };
33
+ const targetIndex = event.key === "Home"
34
+ ? calendarDays.findIndex((entry) => entry.id === availableDays[0]?.id)
35
+ : event.key === "End"
36
+ ? calendarDays.findIndex((entry) => entry.id === availableDays.at(-1)?.id)
37
+ : event.key in offsets ? index + offsets[event.key] : null;
38
+ if (targetIndex === null)
39
+ return;
40
+ event.preventDefault();
41
+ const direction = targetIndex < index ? -1 : 1;
42
+ let target = Math.max(0, Math.min(calendarDays.length - 1, targetIndex));
43
+ while (calendarDays[target]?.value === null)
44
+ target += direction;
45
+ const next = calendarDays[target];
46
+ if (!next || next.value === null)
47
+ return;
48
+ onDaySelect(next);
49
+ event.currentTarget.closest(".ah-calendar-heatmap__grid")
50
+ ?.querySelector(`[data-day="${next.id}"]`)?.focus();
51
+ } }, day.id));
52
+ }
53
+ return (_jsx("span", { className: "ah-calendar-heatmap__cell", "data-empty": day.value === 0 ? "" : undefined, "data-unavailable": day.value === null ? "" : undefined, style: { "--heatmap-intensity": intensity }, title: day.label }, day.id));
54
+ }) }, week.id))) }), _jsxs("div", { className: "ah-calendar-heatmap__footer", children: [summary === undefined ? _jsx("span", {}) : _jsx("span", { children: summary }), _jsxs("span", { className: "ah-calendar-heatmap__legend", "aria-hidden": "true", children: [lowIntensityLabel, INTENSITY_LEVELS.map((level) => (_jsx("i", { "data-empty": level === 0 ? "" : undefined, style: { "--heatmap-intensity": Math.min(level, MAX_INTENSITY_LEVEL) } }, level))), highIntensityLabel] })] })] }));
55
+ }
@@ -0,0 +1,8 @@
1
+ import type { ModelHour } from "@vibefield/rosetta-protocol";
2
+ /** Smooth curves pass through the hourly samples on a shared token scale.
3
+ * Dashed future guides carry no estimated usage or gradient fill. */
4
+ export declare function DayActivityChart({ rows, lastHour, modelColors }: {
5
+ readonly rows: readonly ModelHour[];
6
+ readonly lastHour?: number;
7
+ readonly modelColors?: Readonly<Record<string, string>>;
8
+ }): import("react").JSX.Element;