@vibefield/rosetta-room 0.0.0-stage → 0.1.1

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,906 @@
1
+ import { clockShort, duration } from "../format.js";
2
+ import { webAddress } from "./web-address.js";
3
+ import { FAMILY_GLYPH, canonicalText, firstLine, part, pathParts, resourceDisplay, resourceLabel, splitPath, } from "./vocabulary.js";
4
+ /** The command row is a glanceable label, not a second source viewer. Keep
5
+ * its omission marker inside the 42-character contract. `Array.from` counts
6
+ * Unicode code points, matching Rust's projection boundary. */
7
+ export const COMMAND_PREVIEW_CHARACTER_LIMIT = 42;
8
+ const COMMAND_PREVIEW_OMISSION = "...";
9
+ const COMMAND_PREVIEW_CONTENT_LIMIT = COMMAND_PREVIEW_CHARACTER_LIMIT - COMMAND_PREVIEW_OMISSION.length;
10
+ export function commandPreviewText(text, sourceTruncated) {
11
+ const lines = text.split(/\r?\n/);
12
+ const line = lines.find((candidate) => candidate.trim() !== "") ?? "";
13
+ const characters = Array.from(line);
14
+ const omitted = sourceTruncated || lines.length > 1 || characters.length > COMMAND_PREVIEW_CHARACTER_LIMIT;
15
+ if (!omitted)
16
+ return characters.join("");
17
+ return `${characters.slice(0, COMMAND_PREVIEW_CONTENT_LIMIT).join("")}${COMMAND_PREVIEW_OMISSION}`;
18
+ }
19
+ /** Directory context gets one compact badge on the detail frame. A mixed fold
20
+ * is named honestly rather than borrowing the first command's cwd for every
21
+ * member. */
22
+ export function commandDirectoryContext(commands) {
23
+ const known = commands.filter((command) => command.cwd !== null);
24
+ if (known.length === 0)
25
+ return null;
26
+ const directories = [...new Set(known.map((command) => command.cwd))];
27
+ if (directories.length === 1) {
28
+ return {
29
+ label: directories[0],
30
+ title: `Working directory: ${directories[0]}`,
31
+ };
32
+ }
33
+ return {
34
+ label: `${directories.length} folders`,
35
+ title: `Working directories: ${directories.join(", ")}`,
36
+ };
37
+ }
38
+ function isSessionCwd(resource, context) {
39
+ if (context.cwd === null || context.cwd === undefined)
40
+ return false;
41
+ if (resource.type !== "file" && resource.type !== "directory")
42
+ return false;
43
+ const source = resourceLabel(resource).replace(/\/+$/, "");
44
+ const session = context.cwd.replace(/\/+$/, "");
45
+ return source === session;
46
+ }
47
+ /** The open task row is a status glimpse first; the reader can disclose the
48
+ * complete recorded board without turning every task event into a wall. */
49
+ export const TASK_PREVIEW_LIMIT = 3;
50
+ /** Pin the task this event changed to the bottom, where the eye lands after
51
+ * reading the board. The compact form keeps its two nearest preceding peers
52
+ * above it (filling from following peers only at the start of a board); the
53
+ * full form retains every other recorded task in its original relative order. */
54
+ export function taskDisplayRows(tasks, changedTaskId, full) {
55
+ const currentAt = changedTaskId === null ? -1 : tasks.findIndex((task) => task.task_id === changedTaskId);
56
+ const ordered = currentAt < 0
57
+ ? [...tasks]
58
+ : [...tasks.slice(0, currentAt), ...tasks.slice(currentAt + 1), tasks[currentAt]];
59
+ if (full || ordered.length <= TASK_PREVIEW_LIMIT)
60
+ return ordered;
61
+ if (currentAt < 0)
62
+ return ordered.slice(-TASK_PREVIEW_LIMIT);
63
+ const peerLimit = TASK_PREVIEW_LIMIT - 1;
64
+ const before = tasks.slice(Math.max(0, currentAt - peerLimit), currentAt);
65
+ const after = tasks.slice(currentAt + 1, currentAt + 1 + (peerLimit - before.length));
66
+ return [...before, ...after, tasks[currentAt]];
67
+ }
68
+ const NO_DETAIL = { kind: "none" };
69
+ /* ── small shared shapes ─────────────────────────────────────────────────── */
70
+ function plural(count, one, many = `${one}s`) {
71
+ return `${count} ${count === 1 ? one : many}`;
72
+ }
73
+ function pathFact(resource, context, read, range) {
74
+ const label = resourceDisplay(resource, context);
75
+ const { dir, name } = splitPath(label);
76
+ return {
77
+ label,
78
+ dir,
79
+ name,
80
+ resource,
81
+ ...(range === undefined ? {} : { range }),
82
+ ...(read === undefined ? {} : { read }),
83
+ };
84
+ }
85
+ function pathFacts(resources, context, source = null) {
86
+ return resources.map((resource, targetIndex) => pathFact(resource, context, source !== null && resource.type === "file" ? { ...source, targetIndex } : undefined));
87
+ }
88
+ function sameResource(left, right) {
89
+ return left.type === right.type && resourceLabel(left) === resourceLabel(right);
90
+ }
91
+ /** Keep the renderer and `/file` target indices deterministic: workflow
92
+ * script first, then each distinct result resource in native order. */
93
+ function workflowPathFacts(action, context, source) {
94
+ const scriptResource = action.run?.script_path ?? action.path;
95
+ const resources = [];
96
+ if (scriptResource !== null)
97
+ resources.push(scriptResource);
98
+ for (const resource of action.run?.resources ?? []) {
99
+ if (!resources.some((existing) => sameResource(existing, resource)))
100
+ resources.push(resource);
101
+ }
102
+ const facts = pathFacts(resources, context, source);
103
+ return {
104
+ script: scriptResource === null ? null : (facts[0] ?? null),
105
+ resources: scriptResource === null ? facts : facts.slice(1),
106
+ };
107
+ }
108
+ function workflowPhaseAside(action) {
109
+ if ((action.attempt ?? 1) > 1 || action.resume_id !== null) {
110
+ return `attempt ${action.attempt ?? 2}, same run`;
111
+ }
112
+ const run = action.run ?? null;
113
+ if (run === null || run.phases.length === 0) {
114
+ return action.objective === null || action.objective === undefined
115
+ ? null
116
+ : firstLine(canonicalText(action.objective), 68);
117
+ }
118
+ const active = run.workers.find((worker) => worker.state === "progress");
119
+ const observed = active?.phase_index ?? Math.max(0, ...run.workers
120
+ .filter((worker) => worker.state !== "start" && worker.phase_index !== null)
121
+ .map((worker) => worker.phase_index ?? 0));
122
+ if (observed > 0 && run.status !== "completed") {
123
+ return `phase ${observed} of ${run.phases.length}`;
124
+ }
125
+ const objective = action.objective ?? run.summary;
126
+ return objective === null ? null : firstLine(canonicalText(objective), 68);
127
+ }
128
+ function workflowResult(action) {
129
+ const run = action.run ?? null;
130
+ if (run === null)
131
+ return action.background ? "in background" : null;
132
+ const total = run.workers.length;
133
+ const done = run.workers.filter((worker) => worker.state === "done").length;
134
+ const status = run.status === "unknown" ? "status unknown" : run.status;
135
+ return total === 0 ? status : `${status} · ${done}/${total}`;
136
+ }
137
+ /** `L1–180` · `p3–4`, carried by the exact file target it describes. */
138
+ function rangeText(range) {
139
+ const mark = range.unit === "line" ? "L" : "p";
140
+ const end = range.count === null ? null : range.start + range.count - 1;
141
+ return end === null || end <= range.start
142
+ ? `${mark}${range.start}`
143
+ : `${mark}${range.start}–${end}`;
144
+ }
145
+ function joined(pieces) {
146
+ const kept = pieces.filter((piece) => piece !== null && piece !== "");
147
+ return kept.length === 0 ? null : kept.join(" · ");
148
+ }
149
+ function displayScalarText(value) {
150
+ switch (value.type) {
151
+ case "text":
152
+ case "number":
153
+ return value.value;
154
+ case "boolean":
155
+ return value.value ? "yes" : "no";
156
+ }
157
+ }
158
+ function displayValueText(value) {
159
+ switch (value.type) {
160
+ case "text":
161
+ case "number":
162
+ return value.value;
163
+ case "boolean":
164
+ return value.value ? "yes" : "no";
165
+ case "resource":
166
+ return resourceLabel(value.value);
167
+ case "list":
168
+ return value.value.map(displayScalarText).join(", ");
169
+ }
170
+ }
171
+ const SEARCH_QUALIFIER = {
172
+ name: "for files",
173
+ glob: "for files",
174
+ content: "in files",
175
+ regex: "in files",
176
+ mixed: "in files",
177
+ };
178
+ const PROCESS_VERB = {
179
+ wait: "Waited for",
180
+ input: "Sent input to",
181
+ stop: "Stopped",
182
+ inspect: "Inspected",
183
+ };
184
+ const EXEC_CHILD_LABEL = {
185
+ exec_command: { verb: "Ran", noun: "command" },
186
+ write_stdin: { verb: "Sent input to", noun: "process", many: "processes" },
187
+ apply_patch: { verb: "Applied", noun: "patch", many: "patches" },
188
+ mcp__node_repl__js: { verb: "Ran", noun: "script" },
189
+ update_plan: { verb: "Updated", noun: "plan" },
190
+ web__run: { verb: "Browsed", noun: "web request" },
191
+ view_image: { verb: "Viewed", noun: "image" },
192
+ get_goal: { verb: "Checked", noun: "goal" },
193
+ };
194
+ const CHANGE_VERB = {
195
+ create: "Created",
196
+ update: "Edited",
197
+ delete: "Deleted",
198
+ move: "Moved",
199
+ };
200
+ const SCHEDULE_VERB = {
201
+ create: "Scheduled a wake-up",
202
+ delete: "Cancelled",
203
+ wake: "Woke",
204
+ list: "Listed schedules",
205
+ };
206
+ const ARTIFACT_VERB = {
207
+ create: "Made an artifact",
208
+ edit: "Edited an artifact",
209
+ send: "Sent an artifact",
210
+ };
211
+ const COLLABORATE_VERB = {
212
+ send: "Sent to",
213
+ request_stop: "Asked to stop",
214
+ respond_stop: "Responded to stop",
215
+ create: "Created",
216
+ delete: "Deleted",
217
+ list: "Listed",
218
+ };
219
+ const SEVERITY_ORDER = ["info", "low", "medium", "high", "critical"];
220
+ function taskChange(operation, status) {
221
+ if (operation === "create")
222
+ return "added";
223
+ if (operation !== "update")
224
+ return null;
225
+ switch (status) {
226
+ case "in_progress":
227
+ return "started";
228
+ case "completed":
229
+ return "done";
230
+ case "pending":
231
+ return "reopened";
232
+ case "failed":
233
+ return "failed";
234
+ case "cancelled":
235
+ return "cancelled";
236
+ default:
237
+ return "updated";
238
+ }
239
+ }
240
+ function taskVerb(operation, status) {
241
+ if (operation === "create")
242
+ return "Added";
243
+ if (operation === "list")
244
+ return "Checked";
245
+ if (operation === "get" || operation === "output")
246
+ return "Checked";
247
+ if (operation === "stop")
248
+ return "Stopped";
249
+ switch (status) {
250
+ case "in_progress":
251
+ return "Started";
252
+ case "completed":
253
+ return "Completed";
254
+ case "pending":
255
+ return "Reopened";
256
+ case "failed":
257
+ return "Marked failed";
258
+ case "cancelled":
259
+ return "Cancelled";
260
+ default:
261
+ return "Updated";
262
+ }
263
+ }
264
+ /**
265
+ * The §04 table as one function. `native` is only read by the `unknown` family,
266
+ * whose whole point is to name the tool the projector could not read.
267
+ */
268
+ export function projectAction(action, native, context = {}, source = null) {
269
+ const base = {
270
+ family: action.type,
271
+ glyph: FAMILY_GLYPH[action.type],
272
+ resultMuted: false,
273
+ openByDefault: false,
274
+ };
275
+ switch (action.type) {
276
+ /* ── Looking ─────────────────────────────────────────────────────────── */
277
+ case "file_read": {
278
+ const facts = action.targets.map((target, targetIndex) => pathFact(target.resource, context, source !== null && target.resource.type === "file"
279
+ ? { ...source, targetIndex }
280
+ : undefined, target.range === null ? undefined : rangeText(target.range)));
281
+ const media = action.targets.find((target) => target.media_kind !== null)?.media_kind ?? null;
282
+ const object = facts.length > 0
283
+ ? [part(facts.map((fact) => fact.name || fact.label).join(", "))]
284
+ : [part("no target recorded", "aside")];
285
+ return {
286
+ ...base,
287
+ verb: "Read",
288
+ object,
289
+ result: joined([
290
+ action.outcome?.truncated ? "truncated" : null,
291
+ media,
292
+ ]),
293
+ // Read content stays out of the projection. The exact target address
294
+ // lets an explicit click ask for the live file through the viewer.
295
+ detail: facts.length > 0 ? { kind: "paths", paths: facts, total: facts.length } : NO_DETAIL,
296
+ };
297
+ }
298
+ case "file_list": {
299
+ const label = resourceDisplay(action.directory, context);
300
+ return {
301
+ ...base,
302
+ verb: "Listed",
303
+ object: pathParts(label),
304
+ result: action.outcome === null ? null : plural(action.outcome.entry_count, "entry", "entries"),
305
+ detail: NO_DETAIL,
306
+ };
307
+ }
308
+ case "file_search": {
309
+ const outcome = action.outcome;
310
+ const facts = pathFacts(outcome?.paths ?? [], context);
311
+ return {
312
+ ...base,
313
+ verb: "Searched",
314
+ object: [part(action.query, "query"), part(` ${SEARCH_QUALIFIER[action.mode]}`, "aside")],
315
+ result: outcome === null
316
+ ? null
317
+ : outcome.match_count === 0
318
+ ? // §04's own word when the source is honest about zero. When the
319
+ // source instead REPORTS zero as a failure (Grok does), the
320
+ // failure summary wins in `ledger.ts` and the line goes red.
321
+ "found nothing"
322
+ : joined([
323
+ plural(outcome.match_count, "match", "matches"),
324
+ outcome.file_count > 0 ? plural(outcome.file_count, "file") : null,
325
+ ]),
326
+ detail: facts.length === 0
327
+ ? NO_DETAIL
328
+ : { kind: "paths", paths: facts, total: outcome?.total_paths ?? facts.length },
329
+ };
330
+ }
331
+ case "code_lookup": {
332
+ const outcome = action.outcome;
333
+ return {
334
+ ...base,
335
+ verb: "Looked up",
336
+ object: [part(action.query, "query"), part(` ${action.operation}`, "aside")],
337
+ result: outcome === null ? null : plural(outcome.total_count, "location"),
338
+ detail: outcome === null || outcome.locations.length === 0
339
+ ? NO_DETAIL
340
+ : { kind: "locations", locations: outcome.locations, total: outcome.total_count },
341
+ };
342
+ }
343
+ case "web_search": {
344
+ const outcome = action.outcome;
345
+ const sources = (outcome?.sources ?? []).map((source) => ({
346
+ url: source.url,
347
+ title: source.title?.trim() || null,
348
+ host: webAddress(source.url)?.host ?? null,
349
+ }));
350
+ const query = action.query ?? action.allowed_domains.join(", ");
351
+ return {
352
+ ...base,
353
+ verb: "Searched the web",
354
+ object: query ? [part(query, "query")] : [part("no query recorded", "aside")],
355
+ result: outcome === null ? null : plural(outcome.total_count, "source"),
356
+ detail: { kind: "sources", sources, total: outcome?.total_count ?? null },
357
+ };
358
+ }
359
+ case "web_fetch": {
360
+ const label = resourceLabel(action.url);
361
+ const outcome = action.outcome;
362
+ const status = outcome?.http_status ?? null;
363
+ const finalUrl = outcome?.final_url ?? (action.url.type === "url" ? action.url.url : null);
364
+ return {
365
+ ...base,
366
+ verb: "Fetched",
367
+ object: pathParts(label),
368
+ result: status === null ? null : `HTTP ${status}`,
369
+ detail: {
370
+ kind: "fetch",
371
+ fetch: {
372
+ url: finalUrl,
373
+ title: outcome?.title ?? null,
374
+ status: outcome?.http_status ?? null,
375
+ host: webAddress(finalUrl)?.host ?? null,
376
+ },
377
+ },
378
+ };
379
+ }
380
+ case "web_navigate": {
381
+ const label = action.url ? resourceLabel(action.url) : (action.pattern ?? "");
382
+ const outcome = action.outcome;
383
+ const status = outcome?.http_status ?? null;
384
+ const finalUrl = outcome?.final_url ?? (action.url?.type === "url" ? action.url.url : null);
385
+ return {
386
+ ...base,
387
+ verb: action.operation === "find_in_page" ? "Found in page" : "Opened",
388
+ object: action.operation === "find_in_page" && action.pattern
389
+ ? [
390
+ part(action.pattern, "query"),
391
+ ...(action.url ? [part(" in ", "aside"), ...pathParts(label)] : []),
392
+ ]
393
+ : label ? pathParts(label) : [part("no target recorded", "aside")],
394
+ result: status === null ? null : `HTTP ${status}`,
395
+ detail: {
396
+ kind: "fetch",
397
+ fetch: {
398
+ url: finalUrl,
399
+ title: outcome?.title ?? null,
400
+ status: outcome?.http_status ?? null,
401
+ host: webAddress(finalUrl)?.host ?? null,
402
+ },
403
+ },
404
+ };
405
+ }
406
+ case "tool_discovery":
407
+ return {
408
+ ...base,
409
+ verb: "Searched tools",
410
+ object: [part(action.query, "query")],
411
+ result: `${action.matches.length} of ${action.total_count}`,
412
+ detail: action.matches.length === 0
413
+ ? NO_DETAIL
414
+ : { kind: "names", names: action.matches, total: action.total_count },
415
+ };
416
+ /* ── Acts ────────────────────────────────────────────────────────────── */
417
+ case "file_change": {
418
+ const changes = action.changes;
419
+ const operations = new Set(changes.map((change) => change.operation));
420
+ const only = operations.size === 1 ? [...operations][0] : null;
421
+ // `Changed` is the honest verb when the source could not prove which
422
+ // operation ran, or when one row mixed several.
423
+ const verb = only === null || only === undefined ? "Changed" : CHANGE_VERB[only];
424
+ const added = sumOrNull(changes.map((change) => change.lines_added));
425
+ const removed = sumOrNull(changes.map((change) => change.lines_removed));
426
+ const stat = diffstatText(added, removed);
427
+ const hasDiff = changes.some((change) => change.diff !== null);
428
+ const first = changes[0] ?? null;
429
+ const object = changes.length > 1
430
+ ? [part(plural(changes.length, "file"))]
431
+ : first === null
432
+ ? [part("no path recorded", "aside")]
433
+ : [
434
+ ...pathParts(resourceDisplay(first.path, context)),
435
+ ...(first.destination === null
436
+ ? []
437
+ : [part(` → ${resourceDisplay(first.destination, context)}`, "aside")]),
438
+ ];
439
+ return {
440
+ ...base,
441
+ verb,
442
+ object,
443
+ // Absence is stated, never faked with a zero (§06).
444
+ result: stat ?? (hasDiff ? null : "no diff recorded"),
445
+ detail: {
446
+ kind: "diff",
447
+ deltas: changes,
448
+ diffstat: { added, removed, fileCount: changes.length },
449
+ },
450
+ };
451
+ }
452
+ case "shell": {
453
+ const command = firstLine(canonicalText(action.command));
454
+ return {
455
+ ...base,
456
+ verb: "Ran",
457
+ object: [
458
+ part(command),
459
+ ...(action.background ? [part(" in background", "aside")] : []),
460
+ ],
461
+ result: null,
462
+ detail: {
463
+ kind: "command",
464
+ commands: [
465
+ {
466
+ command: canonicalText(action.command),
467
+ cwd: action.cwd === null ? null : resourceDisplay(action.cwd, context),
468
+ cwdIsSessionRoot: action.cwd === null ? false : isSessionCwd(action.cwd, context),
469
+ language: null,
470
+ background: action.background,
471
+ sourceTruncated: action.source_truncated === true,
472
+ sessionId: source?.sessionId ?? null,
473
+ timelineId: source?.timelineId ?? null,
474
+ },
475
+ ],
476
+ },
477
+ };
478
+ }
479
+ case "code_execute": {
480
+ const code = firstLine(canonicalText(action.code));
481
+ return {
482
+ ...base,
483
+ verb: "Ran",
484
+ object: [
485
+ ...(action.language === null ? [] : [part(`${action.language} `, "aside")]),
486
+ part(code),
487
+ ],
488
+ result: null,
489
+ detail: {
490
+ kind: "code",
491
+ commands: [
492
+ {
493
+ command: canonicalText(action.code),
494
+ cwd: action.cwd === null ? null : resourceDisplay(action.cwd, context),
495
+ cwdIsSessionRoot: action.cwd === null ? false : isSessionCwd(action.cwd, context),
496
+ language: action.language,
497
+ background: false,
498
+ sourceTruncated: action.source_truncated === true,
499
+ sessionId: source?.sessionId ?? null,
500
+ timelineId: source?.timelineId ?? null,
501
+ },
502
+ ],
503
+ },
504
+ };
505
+ }
506
+ case "process": {
507
+ const input = action.input === null ? null : canonicalText(action.input);
508
+ return {
509
+ ...base,
510
+ verb: PROCESS_VERB[action.operation],
511
+ object: [part(action.process_id)],
512
+ result: action.outcome?.state ?? null,
513
+ detail: input === null ? NO_DETAIL : { kind: "text", text: input },
514
+ };
515
+ }
516
+ case "orchestration": {
517
+ const unavailable = action.trace === "unavailable";
518
+ const childLabels = action.executed_children.map((child) => EXEC_CHILD_LABEL[child] ?? null);
519
+ const firstChild = childLabels[0] ?? null;
520
+ const oneKnownKind = firstChild !== null &&
521
+ childLabels.every((child) => child !== null &&
522
+ child.verb === firstChild.verb &&
523
+ child.noun === firstChild.noun &&
524
+ child.many === firstChild.many);
525
+ const childCount = action.executed_child_count ??
526
+ (action.trace === "complete" ? action.executed_children.length : null);
527
+ if (oneKnownKind) {
528
+ return {
529
+ ...base,
530
+ verb: firstChild.verb,
531
+ object: [
532
+ part(childCount === null
533
+ ? (firstChild.many ?? `${firstChild.noun}s`)
534
+ : plural(childCount, firstChild.noun, firstChild.many)),
535
+ ],
536
+ result: null,
537
+ detail: action.executed_children.length === 0
538
+ ? NO_DETAIL
539
+ : {
540
+ kind: "names",
541
+ names: action.executed_children,
542
+ total: action.executed_child_count ?? action.executed_children.length,
543
+ },
544
+ };
545
+ }
546
+ if (action.runtime === "functions.exec") {
547
+ const kinds = [
548
+ ...new Set(action.executed_children.map((child, index) => {
549
+ const label = childLabels[index];
550
+ return label?.noun ?? child.replaceAll("_", " ");
551
+ })),
552
+ ];
553
+ return {
554
+ ...base,
555
+ verb: "Ran",
556
+ object: [part("tool batch")],
557
+ result: kinds.length === 0 ? "trace unavailable" : kinds.slice(0, 3).join(" · "),
558
+ resultMuted: kinds.length === 0,
559
+ detail: action.executed_children.length === 0
560
+ ? NO_DETAIL
561
+ : {
562
+ kind: "names",
563
+ names: action.executed_children,
564
+ total: action.executed_child_count ?? action.executed_children.length,
565
+ },
566
+ };
567
+ }
568
+ return {
569
+ ...base,
570
+ verb: "Executed",
571
+ object: [part(action.runtime ?? "children")],
572
+ result: action.executed_child_count === null
573
+ ? unavailable
574
+ ? "trace unavailable"
575
+ : null
576
+ : plural(action.executed_child_count, "child", "children"),
577
+ resultMuted: unavailable && action.executed_child_count === null,
578
+ detail: action.executed_children.length === 0
579
+ ? NO_DETAIL
580
+ : {
581
+ kind: "names",
582
+ names: action.executed_children,
583
+ total: action.executed_child_count ?? action.executed_children.length,
584
+ },
585
+ };
586
+ }
587
+ case "delegate": {
588
+ const objective = firstLine(canonicalText(action.objective));
589
+ const label = action.name ?? action.agent_kind;
590
+ return {
591
+ ...base,
592
+ verb: action.resume_id === null ? "Delegated" : "Resumed",
593
+ object: [
594
+ ...(label === null ? [] : [part(label)]),
595
+ part(label === null ? objective : ` · ${objective}`, "aside"),
596
+ ],
597
+ // `14 messages · 48s` needs the CHILD, which only the component can
598
+ // resolve; the projection states what it can prove and no more.
599
+ result: action.background ? "in background" : null,
600
+ detail: {
601
+ kind: "delegate",
602
+ delegate: {
603
+ childSessionId: action.child_session_id,
604
+ agentKind: action.agent_kind,
605
+ name: action.name,
606
+ model: action.model,
607
+ team: action.team,
608
+ color: action.color,
609
+ resumeId: action.resume_id,
610
+ objective: canonicalText(action.objective),
611
+ background: action.background,
612
+ orphanSummary: action.orphan_result_summary === null
613
+ ? null
614
+ : canonicalText(action.orphan_result_summary),
615
+ },
616
+ },
617
+ };
618
+ }
619
+ case "collaborate": {
620
+ const target = action.recipient ?? action.team;
621
+ const summary = action.summary ?? (action.body ? firstLine(canonicalText(action.body)) : null);
622
+ return {
623
+ ...base,
624
+ verb: COLLABORATE_VERB[action.operation],
625
+ object: [
626
+ ...(target === null ? [] : [part(target)]),
627
+ ...(summary === null
628
+ ? []
629
+ : [part(target === null ? summary : ` · ${summary}`, "aside")]),
630
+ ],
631
+ result: action.outcome === null ? null : plural(action.outcome.total_count, "participant"),
632
+ detail: action.outcome === null
633
+ ? action.body === null
634
+ ? NO_DETAIL
635
+ : { kind: "text", text: canonicalText(action.body) }
636
+ : {
637
+ kind: "participants",
638
+ participants: action.outcome.participants,
639
+ total: action.outcome.total_count,
640
+ body: action.body === null ? null : canonicalText(action.body),
641
+ },
642
+ };
643
+ }
644
+ case "question": {
645
+ const prompt = action.questions[0] ? firstLine(canonicalText(action.questions[0].prompt)) : "";
646
+ return {
647
+ ...base,
648
+ verb: "Asked",
649
+ object: [part(prompt || "a question", "aside")],
650
+ result: action.answers.length > 0 ? "answered" : null,
651
+ // Conversation, so it opens by default.
652
+ openByDefault: true,
653
+ detail: { kind: "questions", questions: action.questions, answers: action.answers },
654
+ };
655
+ }
656
+ case "skill":
657
+ return {
658
+ ...base,
659
+ verb: "Used skill",
660
+ object: [part(action.name)],
661
+ result: null,
662
+ detail: action.arguments === null
663
+ ? NO_DETAIL
664
+ : { kind: "text", text: canonicalText(action.arguments) },
665
+ };
666
+ case "workflow": {
667
+ const label = action.name ?? (action.path === null ? null : resourceDisplay(action.path, context));
668
+ const run = action.run ?? null;
669
+ const objective = action.objective ?? run?.summary ?? null;
670
+ const paths = workflowPathFacts(action, context, source);
671
+ const aside = workflowPhaseAside(action);
672
+ return {
673
+ ...base,
674
+ // A hydrated workflow is itself a small document: its attempts,
675
+ // phases, workers, and result are the useful message. Keeping that
676
+ // whole document behind the generic ledger disclosure made the real
677
+ // UI disagree with the open workflow state in the design, and left
678
+ // the nested worker-thread disclosure practically undiscoverable.
679
+ // Readers can still close it, but a fresh transcript must expose its
680
+ // structure without requiring a first, unlabeled click.
681
+ openByDefault: run !== null,
682
+ glyph: run !== null && ["killed", "cancelled", "stopped"].includes(run.status)
683
+ ? "clock"
684
+ : base.glyph,
685
+ verb: (action.attempt ?? 1) > 1 || action.resume_id !== null
686
+ ? "Resumed workflow"
687
+ : "Ran workflow",
688
+ object: [
689
+ ...(label === null ? [part("dynamic workflow", "aside")] : pathParts(label)),
690
+ ...(aside === null ? [] : [part(` · ${aside}`, "aside")]),
691
+ ],
692
+ result: workflowResult(action),
693
+ detail: {
694
+ kind: "workflow",
695
+ workflow: {
696
+ action,
697
+ objective: objective === null ? null : canonicalText(objective),
698
+ script: paths.script,
699
+ resources: paths.resources,
700
+ },
701
+ },
702
+ };
703
+ }
704
+ case "schedule":
705
+ return {
706
+ ...base,
707
+ verb: SCHEDULE_VERB[action.operation],
708
+ object: [part(action.reason ?? action.schedule_id ?? "a wake-up", "aside")],
709
+ result: action.delay_ms !== null
710
+ ? `in ${duration(0, action.delay_ms)}`
711
+ : action.due_at !== null
712
+ ? `at ${clockShort(action.due_at)}`
713
+ : null,
714
+ detail: action.objective === null
715
+ ? NO_DETAIL
716
+ : { kind: "text", text: canonicalText(action.objective) },
717
+ };
718
+ case "artifact": {
719
+ const media = action.media;
720
+ const resources = pathFacts(action.resources, context, source);
721
+ return {
722
+ ...base,
723
+ verb: ARTIFACT_VERB[action.operation],
724
+ object: [
725
+ part(action.name ?? action.artifact_kind),
726
+ ...(action.name === null ? [] : [part(` · ${action.artifact_kind}`, "aside")]),
727
+ ],
728
+ result: media !== null && media.width !== null && media.height !== null
729
+ ? `${media.width}×${media.height}`
730
+ : action.resources.length > 0
731
+ ? plural(action.resources.length, "file")
732
+ : null,
733
+ detail: resources.length > 0
734
+ ? {
735
+ kind: "paths",
736
+ paths: resources,
737
+ total: resources.length,
738
+ ...(action.description === null
739
+ ? {}
740
+ : { description: canonicalText(action.description) }),
741
+ }
742
+ : action.description === null
743
+ ? NO_DETAIL
744
+ : { kind: "text", text: canonicalText(action.description) },
745
+ };
746
+ }
747
+ case "notification":
748
+ return {
749
+ ...base,
750
+ verb: "Notified",
751
+ object: [
752
+ part(action.channel ?? "a channel"),
753
+ ...(action.destination === null ? [] : [part(` → ${action.destination}`, "aside")]),
754
+ ],
755
+ result: null,
756
+ detail: { kind: "text", text: canonicalText(action.summary) },
757
+ };
758
+ case "mode":
759
+ return {
760
+ ...base,
761
+ verb: action.operation === "enter" ? "Entered" : "Left",
762
+ object: [
763
+ part(`${action.mode} mode`),
764
+ ...(action.workspace === null
765
+ ? []
766
+ : [part(` · ${resourceDisplay(action.workspace, context)}`, "aside")]),
767
+ ],
768
+ result: null,
769
+ // The matching `mode_changed` notice is the marker; this line is not
770
+ // repeated there and there is nothing more to open.
771
+ detail: NO_DETAIL,
772
+ };
773
+ /* ── Structure ───────────────────────────────────────────────────────── */
774
+ case "task": {
775
+ const snapshot = action.snapshot;
776
+ const changed = snapshot === null || action.task_id === null
777
+ ? null
778
+ : (snapshot.tasks.find((task) => task.task_id === action.task_id) ?? null);
779
+ const subject = action.subject ??
780
+ changed?.subject ??
781
+ (action.description === null ? null : firstLine(canonicalText(action.description)));
782
+ const isList = action.operation === "list";
783
+ const completed = snapshot?.tasks.filter((task) => task.status === "completed").length ?? 0;
784
+ return {
785
+ ...base,
786
+ verb: taskVerb(action.operation, action.status),
787
+ object: isList
788
+ ? [part("task list", "aside")]
789
+ : [
790
+ part(subject ?? (action.task_id === null ? "task" : `task #${action.task_id}`), subject === null ? "aside" : "plain"),
791
+ ],
792
+ result: snapshot === null
793
+ ? action.status === null
794
+ ? null
795
+ : action.status.replaceAll("_", " ")
796
+ : snapshot.total_count === 0
797
+ ? "no tasks"
798
+ : snapshot.total_count === snapshot.tasks.length
799
+ ? `${completed} of ${snapshot.total_count} done`
800
+ : plural(snapshot.total_count, "task"),
801
+ openByDefault: true,
802
+ detail: snapshot !== null
803
+ ? {
804
+ kind: "tasks",
805
+ tasks: snapshot.tasks,
806
+ total: snapshot.total_count,
807
+ changedTaskId: action.task_id,
808
+ change: taskChange(action.operation, action.status),
809
+ }
810
+ : action.description === null
811
+ ? NO_DETAIL
812
+ : { kind: "text", text: canonicalText(action.description) },
813
+ };
814
+ }
815
+ case "plan":
816
+ return {
817
+ ...base,
818
+ verb: "Plan",
819
+ object: [
820
+ part(`${action.operation} `, "dir"),
821
+ part(action.title ?? action.plan_id ?? "", action.title === null ? "aside" : "plain"),
822
+ ],
823
+ result: action.step_count === null ? null : plural(action.step_count, "step"),
824
+ detail: action.summary === null
825
+ ? NO_DETAIL
826
+ : { kind: "text", text: canonicalText(action.summary) },
827
+ };
828
+ case "finding": {
829
+ const worst = action.findings.reduce((highest, item) => SEVERITY_ORDER.indexOf(item.severity) > SEVERITY_ORDER.indexOf(highest)
830
+ ? item.severity
831
+ : highest, "info");
832
+ return {
833
+ ...base,
834
+ verb: "Reported",
835
+ object: [part(plural(action.total_count, "finding"))],
836
+ result: action.findings.length === 0 ? null : worst,
837
+ openByDefault: true,
838
+ detail: { kind: "findings", findings: action.findings, total: action.total_count },
839
+ };
840
+ }
841
+ case "structured_output": {
842
+ const document = action.document;
843
+ const title = document.title ??
844
+ (document.type === "member"
845
+ ? document.preview
846
+ : document.summary === null
847
+ ? null
848
+ : firstLine(canonicalText(document.summary)));
849
+ return {
850
+ ...base,
851
+ verb: "Produced",
852
+ object: [part(title ?? "a document", title === null ? "aside" : "plain")],
853
+ result: null,
854
+ openByDefault: true,
855
+ detail: { kind: "document", document },
856
+ };
857
+ }
858
+ case "external": {
859
+ const outcome = action.fields.find((field) => field.role === "outcome");
860
+ return {
861
+ ...base,
862
+ verb: action.provider ?? "External",
863
+ object: [
864
+ part(`${action.operation} `, "dir"),
865
+ part(action.subject ?? "", action.subject === null ? "aside" : "plain"),
866
+ ],
867
+ result: outcome === undefined ? null : firstLine(displayValueText(outcome.value), 44),
868
+ detail: action.fields.length === 0 && action.resources.length === 0
869
+ ? NO_DETAIL
870
+ : {
871
+ kind: "fields",
872
+ fields: action.fields,
873
+ resources: pathFacts(action.resources, context),
874
+ },
875
+ };
876
+ }
877
+ case "unknown":
878
+ // Honest, and the row that tells you a projector is missing. The native
879
+ // name is the verb; `ledger.ts` appends the status word to the object and
880
+ // sets the muted state that italicises it.
881
+ return {
882
+ ...base,
883
+ verb: native.name,
884
+ object: [part("no detail recorded")],
885
+ result: null,
886
+ detail: NO_DETAIL,
887
+ };
888
+ }
889
+ }
890
+ /* ── diffstat ────────────────────────────────────────────────────────────── */
891
+ function sumOrNull(values) {
892
+ const known = values.filter((value) => value !== null);
893
+ return known.length === 0 ? null : known.reduce((total, value) => total + value, 0);
894
+ }
895
+ /**
896
+ * `+18 −4`, and `+412` when nothing was removed — the record never writes a
897
+ * zero it did not measure. Null when the source kept no counts at all, which
898
+ * the caller renders as `no diff recorded`.
899
+ */
900
+ export function diffstatText(added, removed) {
901
+ const plus = added !== null && added > 0 ? `+${added}` : null;
902
+ const minus = removed !== null && removed > 0 ? `−${removed}` : null;
903
+ if (plus === null && minus === null)
904
+ return null;
905
+ return [plus, minus].filter((piece) => piece !== null).join(" ");
906
+ }