@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.
- package/README.md +247 -2
- package/dist/HistoryRoom.d.ts +98 -0
- package/dist/HistoryRoom.js +440 -0
- package/dist/TranscriptReader.d.ts +22 -0
- package/dist/TranscriptReader.js +72 -0
- package/dist/components/ColdStart.d.ts +4 -0
- package/dist/components/ColdStart.js +5 -0
- package/dist/components/FilterChips.d.ts +4 -0
- package/dist/components/FilterChips.js +5 -0
- package/dist/components/HostAct.d.ts +9 -0
- package/dist/components/HostAct.js +16 -0
- package/dist/components/HostMenu.d.ts +41 -0
- package/dist/components/HostMenu.js +216 -0
- package/dist/components/IngestStatus.d.ts +4 -0
- package/dist/components/IngestStatus.js +20 -0
- package/dist/components/ListActivityNotice.d.ts +5 -0
- package/dist/components/ListActivityNotice.js +4 -0
- package/dist/components/ListSections.d.ts +20 -0
- package/dist/components/ListSections.js +39 -0
- package/dist/components/RenameHeading.d.ts +9 -0
- package/dist/components/RenameHeading.js +75 -0
- package/dist/components/SearchStrip.d.ts +5 -0
- package/dist/components/SearchStrip.js +8 -0
- package/dist/components/SummaryMetrics.d.ts +13 -0
- package/dist/components/SummaryMetrics.js +9 -0
- package/dist/components/SummaryPanels.d.ts +35 -0
- package/dist/components/SummaryPanels.js +117 -0
- package/dist/components/Transcript.d.ts +46 -0
- package/dist/components/Transcript.js +358 -0
- package/dist/components/charts/ActivityChartDetail.d.ts +13 -0
- package/dist/components/charts/ActivityChartDetail.js +78 -0
- package/dist/components/charts/CalendarHeatmap.d.ts +16 -0
- package/dist/components/charts/CalendarHeatmap.js +55 -0
- package/dist/components/charts/DayActivityChart.d.ts +8 -0
- package/dist/components/charts/DayActivityChart.js +71 -0
- package/dist/components/charts/ModelsChartDetail.d.ts +7 -0
- package/dist/components/charts/ModelsChartDetail.js +19 -0
- package/dist/components/charts/ProjectChartDialog.d.ts +19 -0
- package/dist/components/charts/ProjectChartDialog.js +39 -0
- package/dist/components/charts/Streamgraph.d.ts +16 -0
- package/dist/components/charts/Streamgraph.js +94 -0
- package/dist/components/charts/Treemap.d.ts +26 -0
- package/dist/components/charts/Treemap.js +81 -0
- package/dist/components/charts/index.d.ts +9 -0
- package/dist/components/charts/index.js +4 -0
- package/dist/components/charts/streamgraph-layout.d.ts +23 -0
- package/dist/components/charts/streamgraph-layout.js +114 -0
- package/dist/components/charts/treemap-layout.d.ts +32 -0
- package/dist/components/charts/treemap-layout.js +140 -0
- package/dist/components/charts/types.d.ts +65 -0
- package/dist/components/charts/types.js +8 -0
- package/dist/components/file-viewer/FileViewerBrowsers.d.ts +10 -0
- package/dist/components/file-viewer/FileViewerBrowsers.js +65 -0
- package/dist/components/file-viewer/FileViewerDialog.d.ts +33 -0
- package/dist/components/file-viewer/FileViewerDialog.js +82 -0
- package/dist/components/file-viewer/FileViewerHeader.d.ts +26 -0
- package/dist/components/file-viewer/FileViewerHeader.js +17 -0
- package/dist/components/file-viewer/ImageGalleryDialog.d.ts +14 -0
- package/dist/components/file-viewer/ImageGalleryDialog.js +98 -0
- package/dist/components/file-viewer/diff/index.d.ts +2 -0
- package/dist/components/file-viewer/diff/index.js +2 -0
- package/dist/components/file-viewer/diff/parse.d.ts +2 -0
- package/dist/components/file-viewer/diff/parse.js +164 -0
- package/dist/components/file-viewer/diff/types.d.ts +44 -0
- package/dist/components/file-viewer/diff/types.js +7 -0
- package/dist/components/file-viewer/gallery-source.d.ts +11 -0
- package/dist/components/file-viewer/gallery-source.js +75 -0
- package/dist/components/file-viewer/image-resource.d.ts +19 -0
- package/dist/components/file-viewer/image-resource.js +60 -0
- package/dist/components/file-viewer/index.d.ts +5 -0
- package/dist/components/file-viewer/index.js +8 -0
- package/dist/components/file-viewer/markdown/blocks.d.ts +2 -0
- package/dist/components/file-viewer/markdown/blocks.js +277 -0
- package/dist/components/file-viewer/markdown/index.d.ts +4 -0
- package/dist/components/file-viewer/markdown/index.js +35 -0
- package/dist/components/file-viewer/markdown/inline.d.ts +10 -0
- package/dist/components/file-viewer/markdown/inline.js +178 -0
- package/dist/components/file-viewer/markdown/render.d.ts +9 -0
- package/dist/components/file-viewer/markdown/render.js +78 -0
- package/dist/components/file-viewer/markdown/types.d.ts +57 -0
- package/dist/components/file-viewer/markdown/types.js +11 -0
- package/dist/components/file-viewer/minimap/CodeMinimap.d.ts +10 -0
- package/dist/components/file-viewer/minimap/CodeMinimap.js +296 -0
- package/dist/components/file-viewer/minimap/layout.d.ts +60 -0
- package/dist/components/file-viewer/minimap/layout.js +117 -0
- package/dist/components/file-viewer/minimap/palette.d.ts +2 -0
- package/dist/components/file-viewer/minimap/palette.js +73 -0
- package/dist/components/file-viewer/minimap/raster.d.ts +19 -0
- package/dist/components/file-viewer/minimap/raster.js +122 -0
- package/dist/components/file-viewer/registry.d.ts +25 -0
- package/dist/components/file-viewer/registry.js +182 -0
- package/dist/components/file-viewer/syntax/grammars.d.ts +16 -0
- package/dist/components/file-viewer/syntax/grammars.js +221 -0
- package/dist/components/file-viewer/syntax/index.d.ts +8 -0
- package/dist/components/file-viewer/syntax/index.js +9 -0
- package/dist/components/file-viewer/syntax/languages.d.ts +14 -0
- package/dist/components/file-viewer/syntax/languages.js +115 -0
- package/dist/components/file-viewer/syntax/tokenize-config.d.ts +2 -0
- package/dist/components/file-viewer/syntax/tokenize-config.js +132 -0
- package/dist/components/file-viewer/syntax/tokenize-css.d.ts +2 -0
- package/dist/components/file-viewer/syntax/tokenize-css.js +169 -0
- package/dist/components/file-viewer/syntax/tokenize-markup.d.ts +2 -0
- package/dist/components/file-viewer/syntax/tokenize-markup.js +124 -0
- package/dist/components/file-viewer/syntax/tokenize.d.ts +9 -0
- package/dist/components/file-viewer/syntax/tokenize.js +289 -0
- package/dist/components/file-viewer/syntax/types.d.ts +74 -0
- package/dist/components/file-viewer/syntax/types.js +13 -0
- package/dist/components/file-viewer/types.d.ts +111 -0
- package/dist/components/file-viewer/types.js +8 -0
- package/dist/components/file-viewer/use-file-content.d.ts +26 -0
- package/dist/components/file-viewer/use-file-content.js +144 -0
- package/dist/components/file-viewer/views/BinaryView.d.ts +2 -0
- package/dist/components/file-viewer/views/BinaryView.js +34 -0
- package/dist/components/file-viewer/views/CodeView.d.ts +2 -0
- package/dist/components/file-viewer/views/CodeView.js +46 -0
- package/dist/components/file-viewer/views/DiffBody.d.ts +7 -0
- package/dist/components/file-viewer/views/DiffBody.js +77 -0
- package/dist/components/file-viewer/views/DiffView.d.ts +2 -0
- package/dist/components/file-viewer/views/DiffView.js +11 -0
- package/dist/components/file-viewer/views/ImageView.d.ts +9 -0
- package/dist/components/file-viewer/views/ImageView.js +28 -0
- package/dist/components/file-viewer/views/MarkdownView.d.ts +9 -0
- package/dist/components/file-viewer/views/MarkdownView.js +20 -0
- package/dist/components/file-viewer/views/SvgView.d.ts +9 -0
- package/dist/components/file-viewer/views/SvgView.js +10 -0
- package/dist/components/git/ChangeTree.d.ts +20 -0
- package/dist/components/git/ChangeTree.js +35 -0
- package/dist/components/git/CommitViewer.d.ts +12 -0
- package/dist/components/git/CommitViewer.js +85 -0
- package/dist/components/git/GitChanges.d.ts +17 -0
- package/dist/components/git/GitChanges.js +70 -0
- package/dist/components/git/GitHistory.d.ts +9 -0
- package/dist/components/git/GitHistory.js +58 -0
- package/dist/components/git/co-author.d.ts +14 -0
- package/dist/components/git/co-author.js +55 -0
- package/dist/components/git/git-file-source.d.ts +18 -0
- package/dist/components/git/git-file-source.js +53 -0
- package/dist/components/git/git-host.d.ts +24 -0
- package/dist/components/git/git-host.js +130 -0
- package/dist/components/git/index.d.ts +10 -0
- package/dist/components/git/index.js +12 -0
- package/dist/components/git/path-tree.d.ts +23 -0
- package/dist/components/git/path-tree.js +73 -0
- package/dist/components/git/session-files.d.ts +9 -0
- package/dist/components/git/session-files.js +50 -0
- package/dist/components/git/types.d.ts +92 -0
- package/dist/components/git/types.js +9 -0
- package/dist/components/projects/ProjectActivitySparkline.d.ts +6 -0
- package/dist/components/projects/ProjectActivitySparkline.js +12 -0
- package/dist/components/projects/ProjectList.d.ts +25 -0
- package/dist/components/projects/ProjectList.js +43 -0
- package/dist/components/projects/ProjectListItem.d.ts +19 -0
- package/dist/components/projects/ProjectListItem.js +78 -0
- package/dist/components/projects/ProjectsColumn.d.ts +19 -0
- package/dist/components/projects/ProjectsColumn.js +36 -0
- package/dist/components/projects/index.d.ts +8 -0
- package/dist/components/projects/index.js +4 -0
- package/dist/components/search/MatchStepper.d.ts +9 -0
- package/dist/components/search/MatchStepper.js +14 -0
- package/dist/components/search/SearchLauncher.d.ts +12 -0
- package/dist/components/search/SearchLauncher.js +13 -0
- package/dist/components/search/SearchSheet.d.ts +29 -0
- package/dist/components/search/SearchSheet.js +230 -0
- package/dist/components/search/index.d.ts +8 -0
- package/dist/components/search/index.js +4 -0
- package/dist/components/search/shortcut.d.ts +25 -0
- package/dist/components/search/shortcut.js +32 -0
- package/dist/components/sessions/SessionList.d.ts +24 -0
- package/dist/components/sessions/SessionList.js +76 -0
- package/dist/components/sessions/SessionListItem.d.ts +13 -0
- package/dist/components/sessions/SessionListItem.js +58 -0
- package/dist/components/sessions/SessionsColumn.d.ts +26 -0
- package/dist/components/sessions/SessionsColumn.js +32 -0
- package/dist/components/sessions/index.d.ts +9 -0
- package/dist/components/sessions/index.js +4 -0
- package/dist/components/sessions/session-display.d.ts +8 -0
- package/dist/components/sessions/session-display.js +18 -0
- package/dist/components/sessions/types.d.ts +7 -0
- package/dist/components/sessions/types.js +1 -0
- package/dist/components/transcript/Activity.d.ts +45 -0
- package/dist/components/transcript/Activity.js +75 -0
- package/dist/components/transcript/Anchor.d.ts +8 -0
- package/dist/components/transcript/Anchor.js +23 -0
- package/dist/components/transcript/Attachments.d.ts +21 -0
- package/dist/components/transcript/Attachments.js +138 -0
- package/dist/components/transcript/AuthoredMessage.d.ts +19 -0
- package/dist/components/transcript/AuthoredMessage.js +17 -0
- package/dist/components/transcript/Compaction.d.ts +9 -0
- package/dist/components/transcript/Compaction.js +50 -0
- package/dist/components/transcript/DayPill.d.ts +38 -0
- package/dist/components/transcript/DayPill.js +68 -0
- package/dist/components/transcript/Document.d.ts +32 -0
- package/dist/components/transcript/Document.js +503 -0
- package/dist/components/transcript/Favicon.d.ts +32 -0
- package/dist/components/transcript/Favicon.js +71 -0
- package/dist/components/transcript/HeadOfDocument.d.ts +19 -0
- package/dist/components/transcript/HeadOfDocument.js +44 -0
- package/dist/components/transcript/Ledger.d.ts +53 -0
- package/dist/components/transcript/Ledger.js +182 -0
- package/dist/components/transcript/LineDetail.d.ts +24 -0
- package/dist/components/transcript/LineDetail.js +81 -0
- package/dist/components/transcript/Marker.d.ts +33 -0
- package/dist/components/transcript/Marker.js +21 -0
- package/dist/components/transcript/MessagePreview.d.ts +12 -0
- package/dist/components/transcript/MessagePreview.js +58 -0
- package/dist/components/transcript/Prompt.d.ts +20 -0
- package/dist/components/transcript/Prompt.js +55 -0
- package/dist/components/transcript/Prose.d.ts +19 -0
- package/dist/components/transcript/Prose.js +109 -0
- package/dist/components/transcript/ReceiptPill.d.ts +10 -0
- package/dist/components/transcript/ReceiptPill.js +10 -0
- package/dist/components/transcript/ResponseHead.d.ts +9 -0
- package/dist/components/transcript/ResponseHead.js +36 -0
- package/dist/components/transcript/Subthread.d.ts +19 -0
- package/dist/components/transcript/Subthread.js +96 -0
- package/dist/components/transcript/Team.d.ts +53 -0
- package/dist/components/transcript/Team.js +185 -0
- package/dist/components/transcript/Thinking.d.ts +24 -0
- package/dist/components/transcript/Thinking.js +50 -0
- package/dist/components/transcript/TimelineMeta.d.ts +9 -0
- package/dist/components/transcript/TimelineMeta.js +161 -0
- package/dist/components/transcript/TranscriptLoading.d.ts +10 -0
- package/dist/components/transcript/TranscriptLoading.js +10 -0
- package/dist/components/transcript/WebDetail.d.ts +8 -0
- package/dist/components/transcript/WebDetail.js +29 -0
- package/dist/components/transcript/Workflow.d.ts +12 -0
- package/dist/components/transcript/Workflow.js +208 -0
- package/dist/components/transcript/activity-plan.d.ts +84 -0
- package/dist/components/transcript/activity-plan.js +209 -0
- package/dist/components/transcript/attachment-file-source.d.ts +23 -0
- package/dist/components/transcript/attachment-file-source.js +103 -0
- package/dist/components/transcript/attachment-gallery.d.ts +12 -0
- package/dist/components/transcript/attachment-gallery.js +33 -0
- package/dist/components/transcript/detail-parts.d.ts +50 -0
- package/dist/components/transcript/detail-parts.js +295 -0
- package/dist/components/transcript/disclosure-state.d.ts +6 -0
- package/dist/components/transcript/disclosure-state.js +32 -0
- package/dist/components/transcript/disclosure-store.d.ts +8 -0
- package/dist/components/transcript/disclosure-store.js +31 -0
- package/dist/components/transcript/document-model.d.ts +15 -0
- package/dist/components/transcript/document-model.js +104 -0
- package/dist/components/transcript/document-plan.d.ts +28 -0
- package/dist/components/transcript/document-plan.js +145 -0
- package/dist/components/transcript/fold-preference.d.ts +17 -0
- package/dist/components/transcript/fold-preference.js +63 -0
- package/dist/components/transcript/glyphs.d.ts +15 -0
- package/dist/components/transcript/glyphs.js +47 -0
- package/dist/components/transcript/index.d.ts +23 -0
- package/dist/components/transcript/index.js +22 -0
- package/dist/components/transcript/message-file-source.d.ts +15 -0
- package/dist/components/transcript/message-file-source.js +31 -0
- package/dist/components/transcript/message-preview.d.ts +9 -0
- package/dist/components/transcript/message-preview.js +46 -0
- package/dist/components/transcript/read-file-source.d.ts +7 -0
- package/dist/components/transcript/read-file-source.js +34 -0
- package/dist/components/transcript/reader-context.d.ts +13 -0
- package/dist/components/transcript/reader-context.js +55 -0
- package/dist/components/transcript/reading-identity.d.ts +2 -0
- package/dist/components/transcript/reading-identity.js +52 -0
- package/dist/components/transcript/scroll-to-row.d.ts +2 -0
- package/dist/components/transcript/scroll-to-row.js +13 -0
- package/dist/components/transcript/thread-index.d.ts +14 -0
- package/dist/components/transcript/thread-index.js +40 -0
- package/dist/components/transcript/thread-navigation.d.ts +5 -0
- package/dist/components/transcript/thread-navigation.js +3 -0
- package/dist/components/transcript/timeline-meta-file-source.d.ts +6 -0
- package/dist/components/transcript/timeline-meta-file-source.js +55 -0
- package/dist/components/transcript/timeline-meta-state.d.ts +12 -0
- package/dist/components/transcript/timeline-meta-state.js +24 -0
- package/dist/components/ui/ColumnHeading.d.ts +27 -0
- package/dist/components/ui/ColumnHeading.js +7 -0
- package/dist/components/ui/ConfirmDialog.d.ts +14 -0
- package/dist/components/ui/ConfirmDialog.js +22 -0
- package/dist/components/ui/DialogShell.d.ts +18 -0
- package/dist/components/ui/DialogShell.js +40 -0
- package/dist/components/ui/EmptyState.d.ts +10 -0
- package/dist/components/ui/EmptyState.js +6 -0
- package/dist/components/ui/ListSummaryHeader.d.ts +9 -0
- package/dist/components/ui/ListSummaryHeader.js +6 -0
- package/dist/components/ui/ListToolbar.d.ts +6 -0
- package/dist/components/ui/ListToolbar.js +5 -0
- package/dist/components/ui/ResultGroupHeader.d.ts +9 -0
- package/dist/components/ui/ResultGroupHeader.js +5 -0
- package/dist/components/ui/SegmentedControl.d.ts +16 -0
- package/dist/components/ui/SegmentedControl.js +9 -0
- package/dist/components/ui/SummaryMetric.d.ts +13 -0
- package/dist/components/ui/SummaryMetric.js +10 -0
- package/dist/components/ui/Veil.d.ts +7 -0
- package/dist/components/ui/Veil.js +5 -0
- package/dist/components/ui/index.d.ts +20 -0
- package/dist/components/ui/index.js +10 -0
- package/dist/components/worktree/WorktreeColumn.d.ts +22 -0
- package/dist/components/worktree/WorktreeColumn.js +170 -0
- package/dist/components/worktree/WorktreeFileTree.d.ts +19 -0
- package/dist/components/worktree/WorktreeFileTree.js +60 -0
- package/dist/components/worktree/WorktreeHeader.d.ts +32 -0
- package/dist/components/worktree/WorktreeHeader.js +81 -0
- package/dist/components/worktree/WorktreeList.d.ts +8 -0
- package/dist/components/worktree/WorktreeList.js +12 -0
- package/dist/components/worktree/index.d.ts +12 -0
- package/dist/components/worktree/index.js +7 -0
- package/dist/components/worktree/types.d.ts +17 -0
- package/dist/components/worktree/types.js +3 -0
- package/dist/components/worktree/use-worktree-guest.d.ts +21 -0
- package/dist/components/worktree/use-worktree-guest.js +92 -0
- package/dist/components/worktree/worktree-file-commands.d.ts +19 -0
- package/dist/components/worktree/worktree-file-commands.js +112 -0
- package/dist/components/worktree/worktree-file-source.d.ts +15 -0
- package/dist/components/worktree/worktree-file-source.js +75 -0
- package/dist/components/worktree/worktree-host.d.ts +31 -0
- package/dist/components/worktree/worktree-host.js +242 -0
- package/dist/fixtures/index.d.ts +24 -0
- package/dist/fixtures/index.js +292 -0
- package/dist/host-inputs.d.ts +231 -0
- package/dist/host-inputs.js +35 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +14 -0
- package/dist/lib/activity-details.d.ts +23 -0
- package/dist/lib/activity-details.js +78 -0
- package/dist/lib/activity-order.d.ts +32 -0
- package/dist/lib/activity-order.js +86 -0
- package/dist/lib/agent-paths.d.ts +6 -0
- package/dist/lib/agent-paths.js +19 -0
- package/dist/lib/agents.d.ts +15 -0
- package/dist/lib/agents.js +60 -0
- package/dist/lib/catalog-status.d.ts +3 -0
- package/dist/lib/catalog-status.js +10 -0
- package/dist/lib/chart-data.d.ts +14 -0
- package/dist/lib/chart-data.js +151 -0
- package/dist/lib/day-activity.d.ts +21 -0
- package/dist/lib/day-activity.js +56 -0
- package/dist/lib/format.d.ts +24 -0
- package/dist/lib/format.js +116 -0
- package/dist/lib/hooks.d.ts +118 -0
- package/dist/lib/hooks.js +608 -0
- package/dist/lib/icons.d.ts +21 -0
- package/dist/lib/icons.js +49 -0
- package/dist/lib/image-media.d.ts +6 -0
- package/dist/lib/image-media.js +30 -0
- package/dist/lib/ingest-activity.d.ts +50 -0
- package/dist/lib/ingest-activity.js +151 -0
- package/dist/lib/ingest.d.ts +25 -0
- package/dist/lib/ingest.js +70 -0
- package/dist/lib/model-labels.d.ts +5 -0
- package/dist/lib/model-labels.js +28 -0
- package/dist/lib/model.d.ts +73 -0
- package/dist/lib/model.js +141 -0
- package/dist/lib/motion.d.ts +13 -0
- package/dist/lib/motion.js +80 -0
- package/dist/lib/room-storage.d.ts +13 -0
- package/dist/lib/room-storage.js +40 -0
- package/dist/lib/search-results.d.ts +27 -0
- package/dist/lib/search-results.js +83 -0
- package/dist/lib/search-sheet.d.ts +119 -0
- package/dist/lib/search-sheet.js +282 -0
- package/dist/lib/sections.d.ts +19 -0
- package/dist/lib/sections.js +36 -0
- package/dist/lib/session-activity.d.ts +5 -0
- package/dist/lib/session-activity.js +15 -0
- package/dist/lib/session-leases.d.ts +15 -0
- package/dist/lib/session-leases.js +61 -0
- package/dist/lib/spend.d.ts +42 -0
- package/dist/lib/spend.js +112 -0
- package/dist/lib/tint.d.ts +9 -0
- package/dist/lib/tint.js +53 -0
- package/dist/lib/transcript/collaboration.d.ts +97 -0
- package/dist/lib/transcript/collaboration.js +423 -0
- package/dist/lib/transcript/families.d.ts +212 -0
- package/dist/lib/transcript/families.js +906 -0
- package/dist/lib/transcript/favicons.d.ts +54 -0
- package/dist/lib/transcript/favicons.js +183 -0
- package/dist/lib/transcript/head-of-document.d.ts +27 -0
- package/dist/lib/transcript/head-of-document.js +274 -0
- package/dist/lib/transcript/head-state.d.ts +182 -0
- package/dist/lib/transcript/head-state.js +305 -0
- package/dist/lib/transcript/history-window.d.ts +13 -0
- package/dist/lib/transcript/history-window.js +52 -0
- package/dist/lib/transcript/images.d.ts +8 -0
- package/dist/lib/transcript/images.js +60 -0
- package/dist/lib/transcript/index.d.ts +15 -0
- package/dist/lib/transcript/index.js +8 -0
- package/dist/lib/transcript/ledger.d.ts +143 -0
- package/dist/lib/transcript/ledger.js +513 -0
- package/dist/lib/transcript/protocol.d.ts +23 -0
- package/dist/lib/transcript/protocol.js +1 -0
- package/dist/lib/transcript/sittings.d.ts +75 -0
- package/dist/lib/transcript/sittings.js +147 -0
- package/dist/lib/transcript/tail-scroll.d.ts +36 -0
- package/dist/lib/transcript/tail-scroll.js +167 -0
- package/dist/lib/transcript/tail-state.d.ts +17 -0
- package/dist/lib/transcript/tail-state.js +30 -0
- package/dist/lib/transcript/turns.d.ts +192 -0
- package/dist/lib/transcript/turns.js +576 -0
- package/dist/lib/transcript/use-transcript-opening.d.ts +12 -0
- package/dist/lib/transcript/use-transcript-opening.js +31 -0
- package/dist/lib/transcript/use-transcript-tail.d.ts +25 -0
- package/dist/lib/transcript/use-transcript-tail.js +158 -0
- package/dist/lib/transcript/vocabulary.d.ts +119 -0
- package/dist/lib/transcript/vocabulary.js +293 -0
- package/dist/lib/transcript/web-address.d.ts +6 -0
- package/dist/lib/transcript/web-address.js +18 -0
- package/dist/lib/transcript/workflow.d.ts +31 -0
- package/dist/lib/transcript/workflow.js +133 -0
- package/dist/lib/use-activity-order.d.ts +2 -0
- package/dist/lib/use-activity-order.js +23 -0
- package/dist/lib/use-day-usage.d.ts +8 -0
- package/dist/lib/use-day-usage.js +31 -0
- package/dist/lib/use-deferred-list-order.d.ts +26 -0
- package/dist/lib/use-deferred-list-order.js +142 -0
- package/dist/lib/use-ingest-activity.d.ts +2 -0
- package/dist/lib/use-ingest-activity.js +49 -0
- package/dist/lib/use-list-motion.d.ts +4 -0
- package/dist/lib/use-list-motion.js +67 -0
- package/dist/ports.d.ts +222 -0
- package/dist/ports.js +3 -0
- package/dist/room-context.d.ts +60 -0
- package/dist/room-context.js +87 -0
- package/dist/styles/activity-chart.css +127 -0
- package/dist/styles/attachments.css +29 -0
- package/dist/styles/favicon.css +73 -0
- package/dist/styles/history-room.css +18 -0
- package/dist/styles/host-inputs.css +250 -0
- package/dist/styles/image-gallery.css +30 -0
- package/dist/styles/ingest.css +51 -0
- package/dist/styles/message-preview.css +34 -0
- package/dist/styles/models-chart.css +66 -0
- package/dist/styles/project-chart.css +19 -0
- package/dist/styles/reader.css +33 -0
- package/dist/styles/room.css +1411 -0
- package/dist/styles/search.css +252 -0
- package/dist/styles/transcript-activity.css +70 -0
- package/dist/styles/transcript-head.css +220 -0
- package/dist/styles/transcript-loading.css +57 -0
- package/dist/styles/transcript.css +1226 -0
- package/package.json +61 -4
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// The History room, behind the ports a host hands it (`ports.ts`): it opens
|
|
3
|
+
// no socket and no fetch of its own. Columns change content, never geometry
|
|
4
|
+
// (H-2); the ledger's scale is global and stable whatever the filter says. Search is a
|
|
5
|
+
// tool held over the room, not a mode that replaces it (search record,
|
|
6
|
+
// 2026-09-09): the launcher in the strip opens a sheet, a hit lands in the
|
|
7
|
+
// transcript, and the four columns never change what they hold for it. The
|
|
8
|
+
// worktree column is a guest and the measure is not (H-3) — see
|
|
9
|
+
// `components/worktree/use-worktree-guest`, which owns that rule and the
|
|
10
|
+
// engine lifecycle behind it.
|
|
11
|
+
import { forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
12
|
+
import { HostInputsProvider, hostInputsOf, useHostInputs } from "./host-inputs.js";
|
|
13
|
+
import { tildePath } from "./lib/format.js";
|
|
14
|
+
import { MenuLayerProvider } from "./components/HostMenu.js";
|
|
15
|
+
import { RoomProvider, useRoom, useRoomOverlayOpen } from "./room-context.js";
|
|
16
|
+
import { ColdStartPanel } from "./components/ColdStart.js";
|
|
17
|
+
import { ProjectsColumn } from "./components/projects/index.js";
|
|
18
|
+
import { SearchLauncher, SearchSheet, emptyTranscriptPrompt, searchKeyLegend } from "./components/search/index.js";
|
|
19
|
+
import { SessionsColumn } from "./components/sessions/index.js";
|
|
20
|
+
import { TranscriptColumn } from "./components/Transcript.js";
|
|
21
|
+
import { EmptyState } from "./components/ui/index.js";
|
|
22
|
+
import { sessionFilePaths } from "./components/git/index.js";
|
|
23
|
+
import { useWorktreeGuest, WorktreeColumn } from "./components/worktree/index.js";
|
|
24
|
+
import { useDaemonStatus, useMeta, useProjectStats, useProjectUsage, useSearch, useTimeline, } from "./lib/hooks.js";
|
|
25
|
+
import { useIngestActivity } from "./lib/use-ingest-activity.js";
|
|
26
|
+
import { isIngestActive } from "./lib/ingest.js";
|
|
27
|
+
import { UNASSIGNED_PROJECT_ID, buildProjectViewModel, getActivityGridStartTimestamp, projectKey, unassignedProject, } from "./lib/model.js";
|
|
28
|
+
import { compareOrderedSessions } from "./lib/activity-order.js";
|
|
29
|
+
import { useActivityOrder } from "./lib/use-activity-order.js";
|
|
30
|
+
import { createSearchResultsViewModel } from "./lib/search-results.js";
|
|
31
|
+
import { DEFAULT_SEARCH_FILTERS, hitsInReadingOrder, rememberQuery, sessionResultOf, } from "./lib/search-sheet.js";
|
|
32
|
+
import { spendOf } from "./lib/spend.js";
|
|
33
|
+
function useNow(refreshKey) {
|
|
34
|
+
const [tick, setTick] = useState(() => Date.now());
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const refresh = () => setTick(Date.now());
|
|
37
|
+
const t = setInterval(refresh, 30_000);
|
|
38
|
+
window.addEventListener("focus", refresh);
|
|
39
|
+
document.addEventListener("visibilitychange", refresh);
|
|
40
|
+
return () => {
|
|
41
|
+
clearInterval(t);
|
|
42
|
+
window.removeEventListener("focus", refresh);
|
|
43
|
+
document.removeEventListener("visibilitychange", refresh);
|
|
44
|
+
};
|
|
45
|
+
}, []);
|
|
46
|
+
// Incoming metadata gets a fresh clock in the same render. Keep it stable
|
|
47
|
+
// for unrelated UI changes so project aggregates do not recompute per keypress.
|
|
48
|
+
return useMemo(() => Date.now(), [tick, refreshKey]);
|
|
49
|
+
}
|
|
50
|
+
function insetStyle(inset) {
|
|
51
|
+
if (inset === undefined)
|
|
52
|
+
return {};
|
|
53
|
+
const sides = typeof inset === "number" ? { top: inset, right: inset, bottom: inset, left: inset } : inset;
|
|
54
|
+
return Object.fromEntries(["top", "right", "bottom", "left"]
|
|
55
|
+
.filter((side) => sides[side] !== undefined)
|
|
56
|
+
.map((side) => [`--ah-inset-${side}`, `${sides[side]}px`]));
|
|
57
|
+
}
|
|
58
|
+
/** The element's laid-out width, before the first paint and on every resize;
|
|
59
|
+
* a transform (the stage receding) does not change it. */
|
|
60
|
+
function useLayoutWidth(ref) {
|
|
61
|
+
const [width, setWidth] = useState(null);
|
|
62
|
+
useLayoutEffect(() => {
|
|
63
|
+
const node = ref.current;
|
|
64
|
+
if (node === null)
|
|
65
|
+
return;
|
|
66
|
+
setWidth(node.clientWidth);
|
|
67
|
+
const observer = new ResizeObserver((entries) => {
|
|
68
|
+
const entry = entries[0];
|
|
69
|
+
if (entry !== undefined)
|
|
70
|
+
setWidth(entry.contentRect.width);
|
|
71
|
+
});
|
|
72
|
+
observer.observe(node);
|
|
73
|
+
return () => observer.disconnect();
|
|
74
|
+
}, [ref]);
|
|
75
|
+
return width;
|
|
76
|
+
}
|
|
77
|
+
/** The room. A host hands it its ports; everything inside reads them from context. */
|
|
78
|
+
export const HistoryRoom = forwardRef(function HistoryRoom(props, ref) {
|
|
79
|
+
const { catalog, sessions, assets, host } = props;
|
|
80
|
+
const ports = useMemo(() => ({ catalog, sessions, assets, ...(host === undefined ? {} : { host }) }), [catalog, sessions, assets, host]);
|
|
81
|
+
return (_jsx(RoomProvider, { ports: ports, options: {
|
|
82
|
+
initialSummaryTab: props.initialSummaryTab,
|
|
83
|
+
portalContainer: props.portalContainer,
|
|
84
|
+
storagePrefix: props.storagePrefix,
|
|
85
|
+
storage: props.storage,
|
|
86
|
+
}, children: _jsx(HostInputsProvider, { value: hostInputsOf(props), children: _jsx(RoomBody, { handle: ref, surface: props.surface ?? "paper", search: props.search ?? null, unavailable: props.unavailable ?? null, consent: props.consent ?? null, emptyPrompt: props.emptyPrompt, onSelect: props.onSelect, frameStyle: {
|
|
87
|
+
...insetStyle(props.edgeInset),
|
|
88
|
+
...(props.scrollFoot === undefined ? {} : { "--ah-scroll-foot": props.scrollFoot }),
|
|
89
|
+
...(props.floatingFoot === undefined ? {} : { "--ah-floating-foot": props.floatingFoot }),
|
|
90
|
+
} }) }) }));
|
|
91
|
+
});
|
|
92
|
+
function RoomBody({ handle, surface, search: searchOption, unavailable, consent, emptyPrompt, onSelect, frameStyle, }) {
|
|
93
|
+
const { catalog, sessions, host, storage, tints } = useRoom();
|
|
94
|
+
const { projectTint: hostTint, sessionRow: hostSessionRow, projectActs: hostProjectActs, projectCard: hostProjectCard, sessionActs: hostSessionActs, folders: hostFoldersOf, } = useHostInputs();
|
|
95
|
+
const overlayOpen = useRoomOverlayOpen();
|
|
96
|
+
// The room's root, where a host's menus are drawn over every column.
|
|
97
|
+
const [frameElement, setFrameElement] = useState(null);
|
|
98
|
+
const { meta, snapshotVersion, status: metaStatus } = useMeta(catalog);
|
|
99
|
+
const nowMs = useNow(meta);
|
|
100
|
+
const daemonStatus = useDaemonStatus(catalog);
|
|
101
|
+
const { connectionError, canonicalReady, searchReadiness: readiness, searchProgress, ingest, } = daemonStatus;
|
|
102
|
+
const activity = useIngestActivity(daemonStatus);
|
|
103
|
+
const ingestActive = isIngestActive(ingest);
|
|
104
|
+
const activityOrder = useActivityOrder(meta, snapshotVersion, metaStatus === "live" && canonicalReady === true && !ingestActive, canonicalReady !== true || ingestActive, nowMs);
|
|
105
|
+
const [query, setQuery] = useState(() => searchOption?.initialQuery ?? "");
|
|
106
|
+
// The key the launcher prints and the empty transcript names: only one the
|
|
107
|
+
// host binds (RO-14).
|
|
108
|
+
const searchKey = searchKeyLegend(searchOption);
|
|
109
|
+
const sheetOpen = searchOption?.open ?? false;
|
|
110
|
+
const setSheetOpen = (open) => searchOption?.onOpenChange(open);
|
|
111
|
+
const [filters, setFilters] = useState(DEFAULT_SEARCH_FILTERS);
|
|
112
|
+
const [stepper, setStepper] = useState(null);
|
|
113
|
+
const [sort, setSort] = useState("recent");
|
|
114
|
+
const [projectId, setProjectId] = useState(null);
|
|
115
|
+
const [sessionId, setSessionId] = useState(null);
|
|
116
|
+
const [inspectedThread, setInspectedThread] = useState(null);
|
|
117
|
+
const [focus, setFocus] = useState(null);
|
|
118
|
+
const [receipt, setReceipt] = useState(null);
|
|
119
|
+
// "This project" is only a scope while there is one; the unassigned
|
|
120
|
+
// pseudo-project names no project the index could select by.
|
|
121
|
+
const scopedProjectId = filters.scope === "project" && projectId !== null && projectId !== UNASSIGNED_PROJECT_ID
|
|
122
|
+
? projectId
|
|
123
|
+
: null;
|
|
124
|
+
const search = useSearch(catalog, query, {
|
|
125
|
+
project: scopedProjectId,
|
|
126
|
+
kind: filters.kind === "any" ? null : filters.kind,
|
|
127
|
+
agent: filters.agent,
|
|
128
|
+
});
|
|
129
|
+
const projectIds = useMemo(() => {
|
|
130
|
+
const ids = (meta?.projects ?? []).map((p) => p.id);
|
|
131
|
+
if ((meta?.sessions ?? []).some((session) => session.project_id === null)) {
|
|
132
|
+
ids.push(UNASSIGNED_PROJECT_ID);
|
|
133
|
+
}
|
|
134
|
+
return ids.sort();
|
|
135
|
+
}, [meta]);
|
|
136
|
+
// Cross-session figures wait for canonical publication. Metadata and
|
|
137
|
+
// completed timelines remain progressive; aggregate scans never compete
|
|
138
|
+
// with the sole cold writer for the shared RAM projection.
|
|
139
|
+
const stats = useProjectStats(catalog, projectIds, canonicalReady === true);
|
|
140
|
+
const projectRows = useMemo(() => {
|
|
141
|
+
const rows = [...(meta?.projects ?? [])];
|
|
142
|
+
if ((meta?.sessions ?? []).some((session) => session.project_id === null)) {
|
|
143
|
+
rows.push(unassignedProject());
|
|
144
|
+
}
|
|
145
|
+
return rows;
|
|
146
|
+
}, [meta]);
|
|
147
|
+
const kindOf = useMemo(() => {
|
|
148
|
+
const byId = new Map((meta?.runtimes ?? []).map((r) => [r.id, r.kind]));
|
|
149
|
+
return (runtimeId) => byId.get(runtimeId) ?? runtimeId;
|
|
150
|
+
}, [meta]);
|
|
151
|
+
const home = useMemo(() => {
|
|
152
|
+
// The desktop shell knows the home directory outright. The daemon only
|
|
153
|
+
// knows agent data roots, and it now reports them already shortened
|
|
154
|
+
// (`~/.claude`) — a string that names no home — so derive from one only
|
|
155
|
+
// when it is still absolute, and otherwise show paths in full.
|
|
156
|
+
const fromShell = host?.homeDir ?? null;
|
|
157
|
+
if (fromShell !== null)
|
|
158
|
+
return fromShell;
|
|
159
|
+
const root = meta?.runtimes[0]?.data_root ?? null;
|
|
160
|
+
if (root === null || !root.startsWith("/"))
|
|
161
|
+
return null;
|
|
162
|
+
return root.replace(/\/\.[^/]+$/, "");
|
|
163
|
+
}, [meta, host]);
|
|
164
|
+
// R1: the host's colour for a project when it gives one, else the dealt one.
|
|
165
|
+
const tintOf = useMemo(() => (hostTint === undefined ? tints.projectTint : (id) => hostTint(id) ?? tints.projectTint(id)), [hostTint, tints]);
|
|
166
|
+
const projectViewModels = useMemo(() => projectRows.map((p) => buildProjectViewModel(p, meta?.sessions ?? [], stats.get(p.id), kindOf, nowMs, tintOf)), [projectRows, meta, stats, kindOf, nowMs, tintOf]);
|
|
167
|
+
const projectById = useMemo(() => new Map(projectViewModels.map((project) => [project.row.id, project])), [projectViewModels]);
|
|
168
|
+
// Per-session facts (tokens + messages) from every loaded contribution.
|
|
169
|
+
const facts = useMemo(() => {
|
|
170
|
+
const out = new Map();
|
|
171
|
+
for (const s of stats.values()) {
|
|
172
|
+
for (const row of s.contribution) {
|
|
173
|
+
out.set(row.session_id, {
|
|
174
|
+
tokens: row.tokens,
|
|
175
|
+
messages: row.messages,
|
|
176
|
+
spend: spendOf(row),
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return out;
|
|
181
|
+
}, [stats]);
|
|
182
|
+
// Selection is always an explicit reader act. Metadata may invalidate an
|
|
183
|
+
// existing selection, but arriving data never chooses a project for them.
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
if (projectId !== null && !projectById.has(projectId)) {
|
|
186
|
+
setProjectId(null);
|
|
187
|
+
setSessionId(null);
|
|
188
|
+
}
|
|
189
|
+
}, [projectById, projectId]);
|
|
190
|
+
const projectSessions = useMemo(() => {
|
|
191
|
+
if (projectId === null)
|
|
192
|
+
return [];
|
|
193
|
+
return (meta?.sessions ?? [])
|
|
194
|
+
.filter((s) => projectKey(s) === projectId &&
|
|
195
|
+
s.parent_session_id === null)
|
|
196
|
+
.sort((left, right) => compareOrderedSessions(left, right, activityOrder));
|
|
197
|
+
}, [meta, projectId, activityOrder]);
|
|
198
|
+
useEffect(() => {
|
|
199
|
+
if (sessionId !== null && !projectSessions.some((s) => s.id === sessionId)) {
|
|
200
|
+
setSessionId(null);
|
|
201
|
+
}
|
|
202
|
+
}, [projectSessions, sessionId]);
|
|
203
|
+
const viewedSessionId = inspectedThread?.rootId === sessionId ? inspectedThread.id : sessionId;
|
|
204
|
+
const session = useMemo(() => (meta?.sessions ?? []).find((s) => s.id === viewedSessionId) ?? null, [meta, viewedSessionId]);
|
|
205
|
+
const openThread = useCallback((id) => {
|
|
206
|
+
if (sessionId !== null)
|
|
207
|
+
setInspectedThread({ rootId: sessionId, id });
|
|
208
|
+
}, [sessionId]);
|
|
209
|
+
// Attention-directed ingestion: opening a not-yet-indexed session moves
|
|
210
|
+
// its queued work to the front of the backfill queue. Under slicing the
|
|
211
|
+
// common case is "streaming" — the starter landed and the completion
|
|
212
|
+
// remainder is still queued — and that remainder is exactly what the
|
|
213
|
+
// click promotes; "pending" covers a session no pass has reached at all.
|
|
214
|
+
// Advisory — a session with nothing queued is a no-op, an old daemon just
|
|
215
|
+
// keeps its order, and the ledger dedupes repeats.
|
|
216
|
+
const sessionState = session?.stream_state ?? null;
|
|
217
|
+
useEffect(() => {
|
|
218
|
+
if (viewedSessionId === null || sessionState === null || sessionState === "indexed")
|
|
219
|
+
return;
|
|
220
|
+
if (ingest?.phase !== "backfilling")
|
|
221
|
+
return;
|
|
222
|
+
catalog.boost?.(viewedSessionId).catch(() => { });
|
|
223
|
+
}, [catalog, viewedSessionId, sessionState, ingest?.phase]);
|
|
224
|
+
const feed = useTimeline(sessions, viewedSessionId);
|
|
225
|
+
const usage = useProjectUsage(catalog, projectId, canonicalReady === true);
|
|
226
|
+
// The selected thread (its root), as a host's acts would continue it.
|
|
227
|
+
const selected = useMemo(() => (sessionId === null ? null : ((meta?.sessions ?? []).find((s) => s.id === sessionId) ?? null)), [meta, sessionId]);
|
|
228
|
+
const projectRoot = useMemo(() => {
|
|
229
|
+
if (projectId === null)
|
|
230
|
+
return null;
|
|
231
|
+
const roots = projectById.get(projectId)?.row.root_paths ?? [];
|
|
232
|
+
if (session?.cwd) {
|
|
233
|
+
const matching = roots
|
|
234
|
+
.filter((root) => session.cwd === root || session.cwd?.startsWith(`${root}/`))
|
|
235
|
+
.sort((a, b) => b.length - a.length)[0];
|
|
236
|
+
if (matching)
|
|
237
|
+
return matching;
|
|
238
|
+
}
|
|
239
|
+
return roots[0] ?? null;
|
|
240
|
+
}, [projectId, projectById, session]);
|
|
241
|
+
/* ── R6: ③'s folder, when the host lists the project's folders ───────
|
|
242
|
+
The host keys them (two machines spell paths alike). ③ shows the
|
|
243
|
+
reader's pick while the session stays, else the folder the selected
|
|
244
|
+
session ran in, else the host's usual place, else the folder at the
|
|
245
|
+
room's own root; one the host marks elsewhere is never opened here. */
|
|
246
|
+
const hostFolders = useMemo(() => (projectId === null || hostFoldersOf === undefined ? null : (hostFoldersOf(projectId) ?? null)), [projectId, hostFoldersOf]);
|
|
247
|
+
const [pickedFolder, setPickedFolder] = useState(null);
|
|
248
|
+
// A pick lasts while its session does: choosing a session again follows it.
|
|
249
|
+
useEffect(() => setPickedFolder(null), [projectId, sessionId]);
|
|
250
|
+
const shownFolder = useMemo(() => {
|
|
251
|
+
if (hostFolders === null)
|
|
252
|
+
return null;
|
|
253
|
+
const all = hostFolders.groups.flatMap((group) => group.folders);
|
|
254
|
+
const byKey = (key) => key === null || key === undefined ? null : (all.find((folder) => folder.key === key) ?? null);
|
|
255
|
+
const picked = pickedFolder !== null && pickedFolder.projectId === projectId && pickedFolder.sessionId === sessionId
|
|
256
|
+
? byKey(pickedFolder.key)
|
|
257
|
+
: null;
|
|
258
|
+
return picked
|
|
259
|
+
?? (selected !== null ? byKey(hostFolders.of?.(selected)) : byKey(hostFolders.initial))
|
|
260
|
+
?? all.find((folder) => folder.path === projectRoot && folder.elsewhere === undefined)
|
|
261
|
+
?? null;
|
|
262
|
+
}, [hostFolders, pickedFolder, projectId, sessionId, selected, projectRoot]);
|
|
263
|
+
const shownFolderKey = shownFolder?.key ?? null;
|
|
264
|
+
// The root ③ reads: the shown folder's, none for one elsewhere, else the room's.
|
|
265
|
+
const worktreeRoot = shownFolder === null ? projectRoot : shownFolder.elsewhere === undefined ? shownFolder.path : null;
|
|
266
|
+
const onShowFolder = useRef(hostFolders?.onShow);
|
|
267
|
+
onShowFolder.current = hostFolders?.onShow;
|
|
268
|
+
const listsFolders = hostFolders !== null;
|
|
269
|
+
useEffect(() => {
|
|
270
|
+
if (listsFolders)
|
|
271
|
+
onShowFolder.current?.(shownFolderKey);
|
|
272
|
+
}, [listsFolders, projectId, shownFolderKey]);
|
|
273
|
+
const folderMenu = useMemo(() => {
|
|
274
|
+
if (hostFolders === null || projectId === null)
|
|
275
|
+
return null;
|
|
276
|
+
return {
|
|
277
|
+
label: "Folders",
|
|
278
|
+
filterAfter: hostFolders.filterAfter,
|
|
279
|
+
filterPlaceholder: hostFolders.filterPlaceholder,
|
|
280
|
+
groups: hostFolders.groups.map((group) => ({
|
|
281
|
+
key: group.key,
|
|
282
|
+
title: group.title,
|
|
283
|
+
items: group.folders.map((folder) => ({
|
|
284
|
+
key: folder.key,
|
|
285
|
+
mark: folder.mark,
|
|
286
|
+
label: folder.label ?? tildePath(folder.path, home),
|
|
287
|
+
detail: folder.detail,
|
|
288
|
+
aside: folder.aside,
|
|
289
|
+
depth: folder.depth,
|
|
290
|
+
checked: folder.key === shownFolderKey,
|
|
291
|
+
filterText: folder.path,
|
|
292
|
+
onSelect: () => setPickedFolder({ projectId, sessionId, key: folder.key }),
|
|
293
|
+
act: folder.act,
|
|
294
|
+
})),
|
|
295
|
+
})),
|
|
296
|
+
};
|
|
297
|
+
}, [hostFolders, projectId, sessionId, shownFolderKey, home]);
|
|
298
|
+
// Which files this session touched — the one fact a git client cannot show.
|
|
299
|
+
// Empty until the typed tool projection ships `file_change` actions, which
|
|
300
|
+
// draws no marks rather than guessing at them.
|
|
301
|
+
const sessionPaths = useMemo(() => sessionFilePaths(feed.rows, worktreeRoot), [feed.rows, worktreeRoot]);
|
|
302
|
+
/* ── column ③, a guest per H-3 ──────────────────────────────────────────
|
|
303
|
+
Files, changes and history are one column now, so the room is back to
|
|
304
|
+
one guest and the record's original rule applies unchanged: below a
|
|
305
|
+
1360px frame it closes rather than squeeze the transcript. */
|
|
306
|
+
const roomRef = useRef(null);
|
|
307
|
+
const roomWidth = useLayoutWidth(roomRef);
|
|
308
|
+
const worktree = useWorktreeGuest(worktreeRoot, roomWidth);
|
|
309
|
+
// The host hears which session is selected — what its own acts (Resume)
|
|
310
|
+
// would continue — on mount and whenever it changes.
|
|
311
|
+
const onSelectRef = useRef(onSelect);
|
|
312
|
+
onSelectRef.current = onSelect;
|
|
313
|
+
// R4: the host's key rides out with the selection, never read here.
|
|
314
|
+
const hostKey = selected === null ? undefined : hostSessionRow?.(selected)?.hostKey;
|
|
315
|
+
const selectionKey = selected === null
|
|
316
|
+
? null
|
|
317
|
+
: `${selected.id}\u0000${selected.native_session_id}\u0000${selected.cwd ?? ""}${hostKey === undefined ? "" : `\u0000${hostKey}`}`;
|
|
318
|
+
useEffect(() => {
|
|
319
|
+
onSelectRef.current?.(selected === null
|
|
320
|
+
? null
|
|
321
|
+
: {
|
|
322
|
+
sessionId: selected.id,
|
|
323
|
+
nativeSessionId: selected.native_session_id,
|
|
324
|
+
folder: selected.cwd,
|
|
325
|
+
...(hostKey === undefined ? {} : { hostKey }),
|
|
326
|
+
});
|
|
327
|
+
// `selectionKey` is the selection's identity; `selected` is read with it.
|
|
328
|
+
}, [selectionKey]);
|
|
329
|
+
/* ── search: one view model, held over the room ─────────────────────── */
|
|
330
|
+
const searchResults = useMemo(() => {
|
|
331
|
+
if (search.query === "" || search.response === null || meta === null)
|
|
332
|
+
return null;
|
|
333
|
+
return createSearchResultsViewModel(search.response.hits, meta.sessions, projectById);
|
|
334
|
+
}, [search.query, search.response, meta, projectById]);
|
|
335
|
+
// Opening a hit is a continuation, not a navigation: the sheet leaves, the
|
|
336
|
+
// room opens the thread, the transcript lands on the message, and the
|
|
337
|
+
// stepper remembers the session's other matches.
|
|
338
|
+
const openHit = (rootSession, hit) => {
|
|
339
|
+
rememberQuery(storage, query);
|
|
340
|
+
setSheetOpen(false);
|
|
341
|
+
setProjectId(projectKey(rootSession));
|
|
342
|
+
setSessionId(rootSession.id);
|
|
343
|
+
setInspectedThread(null);
|
|
344
|
+
setFocus({ sessionId: hit.session_id, timelineId: hit.timeline_id });
|
|
345
|
+
const result = searchResults === null ? null : sessionResultOf(searchResults, rootSession.id);
|
|
346
|
+
const hits = result === null ? [hit] : hitsInReadingOrder(result.hits);
|
|
347
|
+
const at = hits.findIndex((h) => h.timeline_id === hit.timeline_id && h.session_id === hit.session_id);
|
|
348
|
+
setStepper({ sessionId: rootSession.id, hits, at: Math.max(0, at) });
|
|
349
|
+
};
|
|
350
|
+
const stepMatch = useCallback((delta) => {
|
|
351
|
+
setStepper((current) => {
|
|
352
|
+
if (current === null || current.hits.length === 0)
|
|
353
|
+
return current;
|
|
354
|
+
const at = (current.at + delta + current.hits.length) % current.hits.length;
|
|
355
|
+
const hit = current.hits[at];
|
|
356
|
+
setInspectedThread(null);
|
|
357
|
+
setFocus({ sessionId: hit.session_id, timelineId: hit.timeline_id });
|
|
358
|
+
return { ...current, at };
|
|
359
|
+
});
|
|
360
|
+
}, []);
|
|
361
|
+
// A host's "open this": the thread the session belongs to, in its project,
|
|
362
|
+
// landed on the message when one is named. It waits for the index to
|
|
363
|
+
// deliver the session, and says so when the index does not have it.
|
|
364
|
+
const [pendingOpen, setPendingOpen] = useState(null);
|
|
365
|
+
useEffect(() => {
|
|
366
|
+
if (pendingOpen === null || meta === null)
|
|
367
|
+
return;
|
|
368
|
+
const target = meta.sessions.find((s) => s.id === pendingOpen.sessionId) ?? null;
|
|
369
|
+
if (target === null) {
|
|
370
|
+
if (metaStatus !== "live")
|
|
371
|
+
return;
|
|
372
|
+
setPendingOpen(null);
|
|
373
|
+
showReceipt("That session is not in this index");
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
const root = target.parent_session_id === null
|
|
377
|
+
? target
|
|
378
|
+
: (meta.sessions.find((s) => s.id === target.root_session_id) ?? target);
|
|
379
|
+
setPendingOpen(null);
|
|
380
|
+
setProjectId(projectKey(root));
|
|
381
|
+
setSessionId(root.id);
|
|
382
|
+
setInspectedThread(null);
|
|
383
|
+
setStepper(null);
|
|
384
|
+
const timelineId = pendingOpen.timelineId ?? null;
|
|
385
|
+
setFocus(timelineId === null ? null : { sessionId: target.id, timelineId });
|
|
386
|
+
}, [pendingOpen, meta, metaStatus]);
|
|
387
|
+
// ⌘G / ⇧⌘G belong to the host's window; it asks the room to walk.
|
|
388
|
+
const stepping = useRef(false);
|
|
389
|
+
stepping.current = stepper !== null;
|
|
390
|
+
useImperativeHandle(handle, () => ({
|
|
391
|
+
stepMatch(delta) {
|
|
392
|
+
if (!stepping.current)
|
|
393
|
+
return false;
|
|
394
|
+
stepMatch(delta);
|
|
395
|
+
return true;
|
|
396
|
+
},
|
|
397
|
+
openAt(target) {
|
|
398
|
+
setPendingOpen({ sessionId: target.sessionId, timelineId: target.timelineId ?? null });
|
|
399
|
+
},
|
|
400
|
+
}), [stepMatch]);
|
|
401
|
+
// The stepper belongs to the session it was born in.
|
|
402
|
+
useEffect(() => {
|
|
403
|
+
if (stepper !== null && stepper.sessionId !== sessionId)
|
|
404
|
+
setStepper(null);
|
|
405
|
+
}, [sessionId, stepper]);
|
|
406
|
+
const clearSearch = () => {
|
|
407
|
+
setQuery("");
|
|
408
|
+
setStepper(null);
|
|
409
|
+
};
|
|
410
|
+
const showReceipt = (text) => {
|
|
411
|
+
setReceipt(text);
|
|
412
|
+
window.setTimeout(() => setReceipt(null), 2600);
|
|
413
|
+
};
|
|
414
|
+
const kinds = useMemo(() => (meta?.runtimes ?? []).map((r) => r.kind), [meta]);
|
|
415
|
+
const threadCount = useMemo(() => (meta?.sessions ?? []).filter((s) => s.parent_session_id === null).length, [meta]);
|
|
416
|
+
// The launcher states the scope in a breath; the sheet's foot states it in
|
|
417
|
+
// full — the strip is always honest and never furniture (Q5, answered).
|
|
418
|
+
const launcherPlaceholder = meta === null || threadCount === 0
|
|
419
|
+
? "Search your whole agentic past"
|
|
420
|
+
: `Search ${threadCount.toLocaleString("en-US")} sessions across ${kinds.length} ${kinds.length === 1 ? "agent" : "agents"}`;
|
|
421
|
+
const stepperState = stepper === null || stepper.sessionId !== sessionId
|
|
422
|
+
? null
|
|
423
|
+
: { query: search.query, at: stepper.at, total: stepper.hits.length };
|
|
424
|
+
const disconnected = meta === null;
|
|
425
|
+
// The roll call: discovery is on the board and nothing has been read.
|
|
426
|
+
const awaitingConsent = ingest?.phase === "awaiting_consent";
|
|
427
|
+
// The first run before its first metadata batch: the daemon answers and
|
|
428
|
+
// meters move, but there is not yet a canonical project to render. Once
|
|
429
|
+
// RAM metadata arrives the ordinary room takes over progressively.
|
|
430
|
+
const coldStarting = projectRows.length === 0 && ingestActive && ingest !== null && !awaitingConsent;
|
|
431
|
+
return (_jsx("div", { className: "ah-frame is-tall", "data-ah-surface": surface, "data-ah-overlay": overlayOpen ? "" : undefined, style: frameStyle, ref: setFrameElement, children: _jsxs(MenuLayerProvider, { value: frameElement, children: [_jsxs("div", { className: "ah-room", ref: roomRef, children: [searchOption !== null && (_jsxs("div", { className: "ah-searchbar", children: [_jsx(SearchLauncher, { query: search.query, placeholder: launcherPlaceholder, shortcut: searchKey, onOpen: () => setSheetOpen(true), onClear: clearSearch }), searchOption.accessory] })), disconnected && !coldStarting ? (_jsx(EmptyState, { style: { flex: 1 }, title: metaStatus === "closed"
|
|
432
|
+
? "rosettad is not answering"
|
|
433
|
+
: "Connecting to rosettad", description: connectionError ?? unavailable, children: _jsx("div", { className: "ah-meter", children: _jsx("i", { style: { width: metaStatus === "connecting" ? "30%" : "8%" } }) }) })) : awaitingConsent ? (consent ?? (_jsx(EmptyState, { style: { flex: 1 }, title: "Waiting for consent", description: "The index has found agents on this machine and reads nothing until it is told which ones to read." }))) : coldStarting ? (_jsx(ColdStartPanel, { activity: activity })) : (_jsxs("div", { className: "ah-cols", "data-rail": worktree.visible ? "on" : "off", children: [_jsx(ProjectsColumn, { projects: projectViewModels, activityOrder: activityOrder, selectedProjectId: projectId, sort: sort, onSortChange: setSort, homeDirectory: home, currentTimestamp: nowMs, ingest: ingest, activity: activity, onProjectSelect: (id) => {
|
|
434
|
+
setProjectId(id);
|
|
435
|
+
setSessionId(null);
|
|
436
|
+
setInspectedThread(null);
|
|
437
|
+
} }), _jsx(SessionsColumn, { project: projectId ? (projectById.get(projectId) ?? null) : null, sessions: projectSessions, factsBySessionId: facts, getRuntimeKind: kindOf, selectedSessionId: sessionId, usage: usage, activityGridStartTimestamp: getActivityGridStartTimestamp(nowMs), currentTimestamp: nowMs, ingest: ingest, isWorktreeVisible: worktree.available && projectRoot !== null ? worktree.visible : null, onToggleWorktree: worktree.toggle, onSessionSelect: (selectedSession) => { setSessionId(selectedSession.id); setInspectedThread(null); }, hostActs: projectId === null ? null : (hostProjectActs?.(projectId, { folder: shownFolderKey }) ?? null), hostCard: projectId === null || hostProjectCard === undefined ? null : hostProjectCard(projectId) }), _jsx(WorktreeColumn, { projectRoot: worktreeRoot, folders: folderMenu === null ? null : { menu: folderMenu, shown: shownFolder }, tint: projectId ? (projectById.get(projectId)?.tint ?? null) : null, homeDirectory: home, sessionPaths: sessionPaths, currentTimestamp: nowMs, onReceipt: showReceipt, requestError: worktree.error, onRetry: worktree.retry }), _jsx(TranscriptColumn, { session: session, duringBackfill: ingestActive, sessions: meta?.sessions ?? [], project: session ? (projectById.get(projectKey(session)) ?? null) : null, feed: feed, focus: focus, onFocusConsumed: () => setFocus(null), onReceipt: showReceipt, emptyPrompt: emptyPrompt === undefined ? emptyTranscriptPrompt(searchKey) : emptyPrompt, stepper: stepperState, onStepMatch: stepMatch, onDismissStepper: () => setStepper(null), getRuntimeKind: kindOf, homeDirectory: home, onOpenThread: openThread, onBackToParent: session?.parent_session_id == null ? null : () => openThread(session.parent_session_id), headActs: session === null ? null : (hostSessionActs?.(session) ?? null) })] }))] }), searchOption !== null && _jsx(SearchSheet, { open: sheetOpen, onClose: () => setSheetOpen(false), query: query, onQuery: setQuery, filters: filters, onFilters: setFilters, feed: search, results: searchResults, readiness: readiness, progress: searchProgress, canonicalReady: canonicalReady, ingestPaused: ingest?.phase === "metadata_ready", agentKinds: kinds, currentProject: projectId !== null && projectId !== UNASSIGNED_PROJECT_ID
|
|
438
|
+
? (projectById.get(projectId) ?? null)
|
|
439
|
+
: null, homeDirectory: home, nowMs: nowMs, getRuntimeKind: kindOf, onOpenHit: openHit }), receipt !== null && _jsx("div", { className: "ah-receipt", children: receipt })] }) }));
|
|
440
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { RoomPorts } from "./ports.js";
|
|
2
|
+
import type { KeyValueStore } from "./lib/room-storage.js";
|
|
3
|
+
/** Where the reader opens: a session, one of its messages, and the words
|
|
4
|
+
* that matched there. */
|
|
5
|
+
export interface ReaderAddress {
|
|
6
|
+
readonly sessionId: string;
|
|
7
|
+
/** The line to land on and keep marked; absent, the session's latest. */
|
|
8
|
+
readonly timelineId?: string | null | undefined;
|
|
9
|
+
/** The search that found it: its words are marked in the prose. */
|
|
10
|
+
readonly query?: string | null | undefined;
|
|
11
|
+
}
|
|
12
|
+
export interface TranscriptReaderProps extends RoomPorts {
|
|
13
|
+
/** Read by value: a new session or line lands again; the same one does not. */
|
|
14
|
+
readonly at: ReaderAddress;
|
|
15
|
+
/** As the room's: `paper` paints the room's ground; `host` paints none. */
|
|
16
|
+
readonly surface?: "paper" | "host" | undefined;
|
|
17
|
+
/** As the room's: the fold preference and the site icons are kept here. */
|
|
18
|
+
readonly storagePrefix?: string | undefined;
|
|
19
|
+
readonly storage?: KeyValueStore | null | undefined;
|
|
20
|
+
}
|
|
21
|
+
/** One session's transcript, read-only, at a line. */
|
|
22
|
+
export declare function TranscriptReader(props: TranscriptReaderProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// The reader: one session's transcript, read-only, landed on a line — what a
|
|
3
|
+
// host shows BEFORE it opens the room there (VibeField's Peek). It reads
|
|
4
|
+
// through the same ports as the room and draws the room's own document, with
|
|
5
|
+
// nothing around it: no head band, no acts, no dialogs, no keys. It writes
|
|
6
|
+
// nothing back to any room; a host that wants the session opened opens the
|
|
7
|
+
// room at the same place (`HistoryRoomHandle.openAt`).
|
|
8
|
+
//
|
|
9
|
+
// The landing stays marked rather than fading, because here it is the point:
|
|
10
|
+
// the line, and the words the search matched in it. How the mark looks is the
|
|
11
|
+
// host's (three tokens, `--ah-match`, `--ah-match-weight` and
|
|
12
|
+
// `--ah-match-line`, set on any element around the reader); unset, it is the
|
|
13
|
+
// room's own neutral match.
|
|
14
|
+
import { useCallback, useMemo, useState } from "react";
|
|
15
|
+
import { RoomProvider, useRoom } from "./room-context.js";
|
|
16
|
+
import { TranscriptColumn } from "./components/Transcript.js";
|
|
17
|
+
import { MatchTermsProvider, ReaderModeProvider, matchTermsOf } from "./components/transcript/reader-context.js";
|
|
18
|
+
import { EmptyState } from "./components/ui/index.js";
|
|
19
|
+
import { useMeta, useTimeline } from "./lib/hooks.js";
|
|
20
|
+
/** One session's transcript, read-only, at a line. */
|
|
21
|
+
export function TranscriptReader(props) {
|
|
22
|
+
const { catalog, sessions, assets, host } = props;
|
|
23
|
+
const ports = useMemo(() => ({ catalog, sessions, assets, ...(host === undefined ? {} : { host }) }), [catalog, sessions, assets, host]);
|
|
24
|
+
return (_jsx(RoomProvider, { ports: ports, options: { storagePrefix: props.storagePrefix, storage: props.storage }, children: _jsx(ReaderBody, { at: props.at, surface: props.surface ?? "paper" }) }));
|
|
25
|
+
}
|
|
26
|
+
function focusOf(at) {
|
|
27
|
+
const timelineId = at.timelineId ?? null;
|
|
28
|
+
return timelineId === null ? null : { sessionId: at.sessionId, timelineId };
|
|
29
|
+
}
|
|
30
|
+
function ReaderBody({ at, surface }) {
|
|
31
|
+
const { catalog, sessions, host } = useRoom();
|
|
32
|
+
const { meta, status } = useMeta(catalog);
|
|
33
|
+
// The thread the session belongs to, as the room opens it: a delegated
|
|
34
|
+
// thread is read inside its root, landed where its line is.
|
|
35
|
+
const target = useMemo(() => meta?.sessions.find((s) => s.id === at.sessionId) ?? null, [meta, at.sessionId]);
|
|
36
|
+
const root = useMemo(() => {
|
|
37
|
+
if (target === null || target.parent_session_id === null)
|
|
38
|
+
return target;
|
|
39
|
+
return meta?.sessions.find((s) => s.id === target.root_session_id) ?? target;
|
|
40
|
+
}, [meta, target]);
|
|
41
|
+
const feed = useTimeline(sessions, root?.id ?? null);
|
|
42
|
+
// The landing, by value: a new line lands again, a re-render does not.
|
|
43
|
+
const landingKey = `${at.sessionId}\u0000${at.timelineId ?? ""}`;
|
|
44
|
+
const [landing, setLanding] = useState(() => ({ key: landingKey, focus: focusOf(at) }));
|
|
45
|
+
if (landing.key !== landingKey)
|
|
46
|
+
setLanding({ key: landingKey, focus: focusOf(at) });
|
|
47
|
+
const focus = landing.key === landingKey ? landing.focus : focusOf(at);
|
|
48
|
+
const consumed = useCallback(() => setLanding((current) => ({ ...current, focus: null })), []);
|
|
49
|
+
const terms = useMemo(() => matchTermsOf(at.query), [at.query]);
|
|
50
|
+
const [receipt, setReceipt] = useState(null);
|
|
51
|
+
const showReceipt = useCallback((text) => {
|
|
52
|
+
setReceipt(text);
|
|
53
|
+
window.setTimeout(() => setReceipt((current) => (current === text ? null : current)), 2600);
|
|
54
|
+
}, []);
|
|
55
|
+
const kindOf = useMemo(() => {
|
|
56
|
+
const byId = new Map((meta?.runtimes ?? []).map((r) => [r.id, r.kind]));
|
|
57
|
+
return (runtimeId) => byId.get(runtimeId) ?? runtimeId;
|
|
58
|
+
}, [meta]);
|
|
59
|
+
// As the room reads it: the desktop's home, else one an index root still names.
|
|
60
|
+
const home = useMemo(() => {
|
|
61
|
+
const fromShell = host?.homeDir ?? null;
|
|
62
|
+
if (fromShell !== null)
|
|
63
|
+
return fromShell;
|
|
64
|
+
const dataRoot = meta?.runtimes[0]?.data_root ?? null;
|
|
65
|
+
if (dataRoot === null || !dataRoot.startsWith("/"))
|
|
66
|
+
return null;
|
|
67
|
+
return dataRoot.replace(/\/\.[^/]+$/, "");
|
|
68
|
+
}, [meta, host]);
|
|
69
|
+
return (_jsxs("div", { className: "ah-frame ah-reader", "data-ah-surface": surface, children: [root === null ? (_jsx(EmptyState, { style: { flex: 1 }, title: meta === null
|
|
70
|
+
? status === "closed" ? "The index is not answering" : "Opening the session"
|
|
71
|
+
: status === "live" ? "That session is not in this index" : "Opening the session", description: meta === null && status === "closed" ? (catalog.unavailable?.() ?? null) : null })) : (_jsx(ReaderModeProvider, { value: true, children: _jsx(MatchTermsProvider, { value: terms, children: _jsx(TranscriptColumn, { session: root, duringBackfill: false, sessions: meta?.sessions ?? [], project: null, feed: feed, focus: focus, onFocusConsumed: consumed, onReceipt: showReceipt, emptyPrompt: null, stepper: null, onStepMatch: () => undefined, onDismissStepper: () => undefined, getRuntimeKind: kindOf, homeDirectory: home, reader: true }) }) })), receipt !== null && _jsx("div", { className: "ah-receipt", children: receipt })] }));
|
|
72
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { IngestStatus } from "./IngestStatus.js";
|
|
3
|
+
export function ColdStartPanel({ activity }) {
|
|
4
|
+
return (_jsxs("div", { className: "ah-empty ah-cold-start", children: [_jsx("strong", { children: "Bringing your history together" }), _jsx("p", { children: "Your projects will appear here as we discover your conversations." }), _jsx(IngestStatus, { activity: activity })] }));
|
|
5
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { HostMenuButton } from "./HostMenu.js";
|
|
3
|
+
export function FilterChips({ filters }) {
|
|
4
|
+
return (_jsx("span", { className: "ah-chips", children: filters.map((filter) => (_jsx(HostMenuButton, { menu: filter.menu, className: "ah-chipselect ah-chip", label: filter.accessibleLabel, align: "start", data: { "data-filter": filter.key, "data-set": filter.set === true ? "" : undefined }, children: _jsx("span", { className: "ah-chip__label", children: filter.label }) }, filter.key))) }));
|
|
5
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RoomAct } from "../host-inputs.js";
|
|
2
|
+
/** Where an act sits, which decides its face: a session row's quiet act
|
|
3
|
+
* (a 20px pill under the pointer), ②'s head (the room's 26px icon button;
|
|
4
|
+
* its one primary on the go fill), or ④'s head (a pill, the stepper's). */
|
|
5
|
+
export type HostActPlace = "row" | "head" | "pill";
|
|
6
|
+
export declare function HostAct({ act, place }: {
|
|
7
|
+
readonly act: RoomAct;
|
|
8
|
+
readonly place: HostActPlace;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { HostMenuButton } from "./HostMenu.js";
|
|
3
|
+
export function HostAct({ act, place }) {
|
|
4
|
+
const className = place === "head" ? "ah-iconbtn ah-hostact" : "ah-hostact";
|
|
5
|
+
const primary = place === "head" && act.primary === true ? "" : undefined;
|
|
6
|
+
// Its rows are drawn over the columns (`HostMenu`), so a row's act may open
|
|
7
|
+
// them as well as a head's.
|
|
8
|
+
if (act.menu !== undefined) {
|
|
9
|
+
return (_jsx(HostMenuButton, { menu: act.menu, className: className, label: act.label, title: act.label, disabled: act.disabled, align: "end", data: { "data-place": place, "data-act": act.key, "data-primary": primary }, children: act.content }));
|
|
10
|
+
}
|
|
11
|
+
return (_jsx("button", { type: "button", className: className, "data-place": place, "data-act": act.key, "data-primary": primary, title: act.label, "aria-label": act.label, disabled: act.disabled === true, onClick: (event) => {
|
|
12
|
+
// The act is the host's; whatever lies under it stays as it was.
|
|
13
|
+
event.stopPropagation();
|
|
14
|
+
act.onPress?.();
|
|
15
|
+
}, children: act.content }));
|
|
16
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { RoomMenu } from "../host-inputs.js";
|
|
3
|
+
export declare const MenuLayerProvider: import("react").Provider<HTMLElement | null>;
|
|
4
|
+
export interface MenuBox {
|
|
5
|
+
readonly left: number;
|
|
6
|
+
readonly top: number;
|
|
7
|
+
readonly right: number;
|
|
8
|
+
readonly bottom: number;
|
|
9
|
+
}
|
|
10
|
+
export interface MenuPlacement {
|
|
11
|
+
readonly left: number;
|
|
12
|
+
readonly top: number;
|
|
13
|
+
readonly width: number;
|
|
14
|
+
/** The most height the rows may take on their side. */
|
|
15
|
+
readonly room: number;
|
|
16
|
+
readonly side: "below" | "above";
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Where the rows go, in the box's own coordinates: under their control
|
|
20
|
+
* (or over it, when there is more room there and not enough below), from the
|
|
21
|
+
* control's start or end edge, and never past the box's edges less a margin.
|
|
22
|
+
*/
|
|
23
|
+
export declare function placeMenu(control: MenuBox, box: MenuBox, menu: {
|
|
24
|
+
readonly width: number;
|
|
25
|
+
readonly height: number;
|
|
26
|
+
}, align: "start" | "end"): MenuPlacement;
|
|
27
|
+
export interface HostMenuButtonProps {
|
|
28
|
+
readonly menu: RoomMenu;
|
|
29
|
+
/** The control's own class and face; the room's look for its slot. */
|
|
30
|
+
readonly className: string;
|
|
31
|
+
readonly label: string;
|
|
32
|
+
readonly title?: string | undefined;
|
|
33
|
+
readonly disabled?: boolean | undefined;
|
|
34
|
+
/** Data attributes the slot marks its control with. */
|
|
35
|
+
readonly data?: Readonly<Record<`data-${string}`, string | undefined>> | undefined;
|
|
36
|
+
/** Which edge of the control the rows hang from. */
|
|
37
|
+
readonly align?: "start" | "end" | undefined;
|
|
38
|
+
readonly children: ReactNode;
|
|
39
|
+
}
|
|
40
|
+
/** A control that opens the host's rows. */
|
|
41
|
+
export declare function HostMenuButton({ menu, className, label, title, disabled, data, align, children }: HostMenuButtonProps): import("react").JSX.Element;
|