@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,43 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useListMotion } from "../../lib/use-list-motion.js";
|
|
3
|
+
import { useDeferredListOrder } from "../../lib/use-deferred-list-order.js";
|
|
4
|
+
import { ListActivityNotice } from "../ListActivityNotice.js";
|
|
5
|
+
import { FoldLine, SectionHead, useOpenFolds } from "../ListSections.js";
|
|
6
|
+
import { EmptyState } from "../ui/index.js";
|
|
7
|
+
import { ProjectListItem } from "./ProjectListItem.js";
|
|
8
|
+
const projectId = (project) => project.row.id;
|
|
9
|
+
export function ProjectList({ projects, orderScope = "projects", selectedProjectId, maximumLifetimeCost, homeDirectory, currentTimestamp, ingestActive, runtimes, projectBackfills, pending, onProjectSelect, sections = null, }) {
|
|
10
|
+
const folds = useOpenFolds(sections, projectId, selectedProjectId);
|
|
11
|
+
// A folded section's rows are the reader's to open, so they never wait on
|
|
12
|
+
// the held geometry: only the open runs go through it.
|
|
13
|
+
const positions = sections === null
|
|
14
|
+
? projects.map(project => ({ id: project.row.id, day: null }))
|
|
15
|
+
: sections.flatMap(entry => entry.section.fold !== undefined ? [] :
|
|
16
|
+
entry.rows.map(project => ({ id: project.row.id, day: null, section: entry.index })));
|
|
17
|
+
const layout = useDeferredListOrder(positions, orderScope);
|
|
18
|
+
const motionRef = useListMotion(JSON.stringify(layout.items), orderScope, layout.scrollRef);
|
|
19
|
+
const byId = new Map(projects.map(project => [project.row.id, project]));
|
|
20
|
+
const visible = layout.items.flatMap(item => byId.get(item.id) ?? []);
|
|
21
|
+
const drawRow = (project) => (_jsx(ProjectListItem, { project: project, maximumLifetimeCost: maximumLifetimeCost, isSelected: project.row.id === selectedProjectId, homeDirectory: homeDirectory, currentTimestamp: currentTimestamp, ingestActive: ingestActive, runtimeStates: runtimes?.filter((runtime) => project.agents.some((agent) => agent.kind === runtime.kind)).map((runtime) => runtime.state), backfill: projectBackfills.get(project.row.id) ?? null, onProjectSelect: onProjectSelect }, project.row.id));
|
|
22
|
+
const sectioned = sections === null ? null : sections.flatMap((entry) => {
|
|
23
|
+
if (entry.section.fold !== undefined) {
|
|
24
|
+
if (entry.rows.length === 0 && entry.section.fold.count === undefined)
|
|
25
|
+
return [];
|
|
26
|
+
const open = folds.isOpen(entry.section.key);
|
|
27
|
+
return [
|
|
28
|
+
_jsx(FoldLine, { arranged: entry, open: open, onToggle: () => folds.toggle(entry.section.key) }, `section:${entry.section.key}`),
|
|
29
|
+
...(open ? entry.rows.map(drawRow) : []),
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
const rows = layout.items.flatMap(position => position.section === entry.index ? byId.get(position.id) ?? [] : []);
|
|
33
|
+
if (rows.length === 0)
|
|
34
|
+
return [];
|
|
35
|
+
return [
|
|
36
|
+
...(entry.section.title === undefined ? [] : [
|
|
37
|
+
_jsx(SectionHead, { sectionKey: entry.section.key, children: entry.section.title }, `section:${entry.section.key}`),
|
|
38
|
+
]),
|
|
39
|
+
...rows.map(drawRow),
|
|
40
|
+
];
|
|
41
|
+
});
|
|
42
|
+
return (_jsxs("div", { className: "ah-list-view", ...layout.hostProps, children: [_jsxs("div", { className: "ah-scroll ah-motion-list", ref: motionRef, onScroll: layout.onScroll, children: [sectioned ?? visible.map(drawRow), projects.length === 0 && !pending && (_jsx(EmptyState, { title: "No projects yet", description: "rosettad has not indexed any project yet \u2014 leave it serving and this fills in." }))] }), _jsx(ListActivityNotice, { pending: layout.pending, onShow: layout.apply, noun: "projects" })] }));
|
|
43
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ProjectBackfill, BackfillState } from "@vibefield/rosetta-protocol";
|
|
2
|
+
import type { ProjectViewModel } from "../../lib/model.js";
|
|
3
|
+
export interface ProjectListItemProps {
|
|
4
|
+
readonly project: ProjectViewModel;
|
|
5
|
+
/** Maximum lifetime estimated spend (micro-USD) across the complete
|
|
6
|
+
* project collection, not a filtered subset. */
|
|
7
|
+
readonly maximumLifetimeCost: number;
|
|
8
|
+
readonly isSelected: boolean;
|
|
9
|
+
readonly homeDirectory: string | null;
|
|
10
|
+
readonly currentTimestamp: number;
|
|
11
|
+
/** Canonical publication is still pending, so aggregate figures wait. */
|
|
12
|
+
readonly ingestActive: boolean;
|
|
13
|
+
readonly runtimeStates?: readonly BackfillState[] | undefined;
|
|
14
|
+
/** This project's row in the daemon's per-project backfill fold; null
|
|
15
|
+
* before the plan settles, and on a daemon too old to carry it. */
|
|
16
|
+
readonly backfill: ProjectBackfill | null;
|
|
17
|
+
readonly onProjectSelect: (projectId: string) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare function ProjectListItem({ project, maximumLifetimeCost, isSelected, homeDirectory, currentTimestamp, ingestActive, runtimeStates, backfill, onProjectSelect, }: ProjectListItemProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { AgentBadges } from "../../lib/agents.js";
|
|
3
|
+
import { progressBytes } from "../../lib/ingest-activity.js";
|
|
4
|
+
import { projectBackfillProgress } from "../../lib/ingest.js";
|
|
5
|
+
import { lastActive, tildePath, tokenText } from "../../lib/format.js";
|
|
6
|
+
import { coverage, fmtUsd, spendDescription } from "../../lib/spend.js";
|
|
7
|
+
import { useHostInputs } from "../../host-inputs.js";
|
|
8
|
+
import { HostAct } from "../HostAct.js";
|
|
9
|
+
import { ProjectActivitySparkline } from "./ProjectActivitySparkline.js";
|
|
10
|
+
/** The row's "how much": estimated spend (§4.1.3). A partial figure is a
|
|
11
|
+
* lower bound and says so with `+`; usage with no list price at all reads
|
|
12
|
+
* `n/p` rather than a claimed $0. */
|
|
13
|
+
function SpendFigure({ spend, unknown, description, }) {
|
|
14
|
+
const state = coverage(spend);
|
|
15
|
+
const figure = spend.costMicroUsd === null ? null : fmtUsd(spend.costMicroUsd);
|
|
16
|
+
return (_jsxs("span", { className: "ah-project-list-item__token-figure", "data-coverage": state, title: unknown ? undefined : description, children: [_jsx("b", { children: unknown ? "—" : figure === null ? (state === "unavailable" ? "n/p" : "—") : figure.n }), _jsx("i", { children: unknown || figure === null ? "" : `${figure.u}${state === "partial" ? "+" : ""}` })] }));
|
|
17
|
+
}
|
|
18
|
+
export function ProjectListItem({ project, maximumLifetimeCost, isSelected, homeDirectory, currentTimestamp, ingestActive, runtimeStates, backfill, onProjectSelect, }) {
|
|
19
|
+
// The cooking card: identity (name, path, agents) renders as itself from
|
|
20
|
+
// the first skim; only the quantitative slots carry the processing state.
|
|
21
|
+
const isCooking = ingestActive || !project.statsReady;
|
|
22
|
+
// Fill the accent from observed bytes when the source plan has a known
|
|
23
|
+
// total. Unknown work keeps a quiet accent and an explicit stage label.
|
|
24
|
+
const ingestFill = isCooking && backfill !== null
|
|
25
|
+
? projectBackfillProgress(backfill)
|
|
26
|
+
: null;
|
|
27
|
+
const cookingLabel = isCooking
|
|
28
|
+
? backfill !== null
|
|
29
|
+
? backfill.sessions_done >= backfill.sessions_total
|
|
30
|
+
? "Preparing activity summaries"
|
|
31
|
+
: runtimeStates?.includes("streaming")
|
|
32
|
+
? ingestFill !== null
|
|
33
|
+
? `Reading conversations · ${Math.floor(ingestFill * 100)}%`
|
|
34
|
+
: `Reading conversations · ${progressBytes(backfill.bytes_streamed)}`
|
|
35
|
+
: runtimeStates?.some((state) => state === "preparing" || state === "applying")
|
|
36
|
+
? "Organizing conversations" : "Waiting for conversations"
|
|
37
|
+
: project.readiness === "ready" ? "Preparing activity summaries" : "Waiting for conversations"
|
|
38
|
+
: null;
|
|
39
|
+
const lifetimeCost = project.lifetimeSpend.costMicroUsd ?? 0;
|
|
40
|
+
const spendShare = maximumLifetimeCost > 0
|
|
41
|
+
? (lifetimeCost / maximumLifetimeCost) * 100
|
|
42
|
+
: 0;
|
|
43
|
+
const spendLabel = spendDescription(project.lifetimeSpend, tokenText);
|
|
44
|
+
const lastActiveLabel = project.lastActiveMs === null
|
|
45
|
+
? null
|
|
46
|
+
: lastActive(project.lastActiveMs, currentTimestamp);
|
|
47
|
+
const workspacePath = project.row.root_paths[0]
|
|
48
|
+
? tildePath(project.row.root_paths[0], homeDirectory)
|
|
49
|
+
: "No workspace recorded";
|
|
50
|
+
// R2: the host's marks, second line and live count, drawn and never read.
|
|
51
|
+
const decoration = useHostInputs().projectRow?.(project.row.id) ?? null;
|
|
52
|
+
const marks = decoration?.marks ?? null;
|
|
53
|
+
const line = decoration?.line ?? null;
|
|
54
|
+
const live = decoration?.live !== undefined && decoration.live > 0 ? decoration.live : null;
|
|
55
|
+
// H4: the host's act at the row's end (pin, hide), or its rows.
|
|
56
|
+
const act = decoration?.act ?? null;
|
|
57
|
+
const className = `ah-project-list-item${isSelected ? " is-selected" : ""}`;
|
|
58
|
+
const style = {
|
|
59
|
+
"--project-color": project.tint,
|
|
60
|
+
"--spend-share": `${spendShare.toFixed(2)}%`,
|
|
61
|
+
...(ingestFill !== null
|
|
62
|
+
? { "--ingest-fill": `${(ingestFill * 100).toFixed(1)}%` }
|
|
63
|
+
: {}),
|
|
64
|
+
};
|
|
65
|
+
const accessibleName = `${project.row.name} · ${isCooking && project.lifetimeTokens === 0
|
|
66
|
+
? "activity summaries pending"
|
|
67
|
+
: `${spendLabel} · ${tokenText(project.lifetimeTokens)} lifetime tokens`}${lastActiveLabel ? ` · last active ${lastActiveLabel}` : ""}${live !== null ? ` · ${live} live` : ""}${cookingLabel ? ` · ${cookingLabel}` : ""}`;
|
|
68
|
+
// With an act the row holds two buttons, and a button cannot hold another:
|
|
69
|
+
// the row becomes a box, one button covers it (the selection, named as the
|
|
70
|
+
// row always was), and the act sits above it. The rest is drawn for the eye.
|
|
71
|
+
const shown = act === null ? undefined : true;
|
|
72
|
+
const time = live !== null ? (_jsxs("span", { className: "ah-last", "data-live": "", title: `${live} live now`, "aria-hidden": shown, children: [live, " live"] })) : lastActiveLabel !== null && (_jsx("span", { className: "ah-last", "data-live": lastActiveLabel === "now" ? "" : undefined, title: `Last active ${lastActiveLabel}`, "aria-hidden": shown, children: lastActiveLabel }));
|
|
73
|
+
const body = (_jsxs(_Fragment, { children: [_jsx("i", { className: "ah-project-list-item__accent" }), _jsxs("span", { className: "ah-project-list-item__header", "aria-hidden": shown, children: [_jsx("strong", { title: project.row.name, children: project.row.name }), _jsx(AgentBadges, { shares: project.agents })] }), _jsxs("span", { className: "ah-project-list-item__path", "data-marks": marks !== null ? "" : undefined, "aria-hidden": shown, children: [marks !== null && _jsx("span", { className: "ah-project-list-item__marks", children: marks }), _jsx("small", { title: workspacePath, children: workspacePath })] }), line !== null && _jsx("span", { className: "ah-project-list-item__line", "aria-hidden": shown, children: line }), cookingLabel && _jsx("span", { className: "ah-project-list-item__progress", "aria-hidden": shown, children: cookingLabel }), _jsxs("span", { className: "ah-project-list-item__footer", children: [_jsxs("span", { className: "ah-project-list-item__metrics", "data-cooking": isCooking ? "" : undefined, title: cookingLabel ?? undefined, "aria-hidden": shown, children: [_jsx(ProjectActivitySparkline, { values: project.recentTokenBuckets }), _jsx(SpendFigure, { spend: project.lifetimeSpend, unknown: isCooking && project.lifetimeTokens === 0, description: `${spendLabel} · ${tokenText(project.lifetimeTokens)} tokens` })] }), act === null ? time : (_jsxs("span", { className: "ah-project-list-item__end", children: [_jsx(HostAct, { act: act, place: "row" }), time] }))] })] }));
|
|
74
|
+
if (act === null) {
|
|
75
|
+
return (_jsx("button", { type: "button", className: className, "data-motion-key": project.row.id, "data-cooking": isCooking ? "" : undefined, "data-fill": ingestFill !== null ? "" : undefined, "data-line": line !== null ? "" : undefined, style: style, "aria-current": isSelected ? "true" : undefined, "aria-label": accessibleName, onClick: () => onProjectSelect(project.row.id), children: body }));
|
|
76
|
+
}
|
|
77
|
+
return (_jsxs("div", { className: className, "data-motion-key": project.row.id, "data-cooking": isCooking ? "" : undefined, "data-fill": ingestFill !== null ? "" : undefined, "data-line": line !== null ? "" : undefined, "data-host-act": "", style: style, children: [_jsx("button", { type: "button", className: "ah-project-list-item__hit", "aria-current": isSelected ? "true" : undefined, "aria-label": accessibleName, onClick: () => onProjectSelect(project.row.id) }), body] }));
|
|
78
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { IngestProgress } from "@vibefield/rosetta-protocol";
|
|
2
|
+
import type { ProjectViewModel } from "../../lib/model.js";
|
|
3
|
+
import type { ActivityOrder } from "../../lib/activity-order.js";
|
|
4
|
+
import type { IngestActivity } from "../../lib/ingest-activity.js";
|
|
5
|
+
export type ProjectSort = "recent" | "token";
|
|
6
|
+
export interface ProjectsColumnProps {
|
|
7
|
+
readonly projects: readonly ProjectViewModel[];
|
|
8
|
+
readonly activityOrder: ActivityOrder;
|
|
9
|
+
readonly selectedProjectId: string | null;
|
|
10
|
+
readonly sort: ProjectSort;
|
|
11
|
+
readonly onSortChange: (sort: ProjectSort) => void;
|
|
12
|
+
readonly homeDirectory: string | null;
|
|
13
|
+
readonly currentTimestamp: number;
|
|
14
|
+
/** The daemon's cold-start block; null on a daemon too old to carry it. */
|
|
15
|
+
readonly ingest: IngestProgress | null;
|
|
16
|
+
readonly activity: IngestActivity | null;
|
|
17
|
+
readonly onProjectSelect: (projectId: string) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare function ProjectsColumn({ projects, activityOrder, selectedProjectId, sort, onSortChange, homeDirectory, currentTimestamp, ingest, activity, onProjectSelect, }: ProjectsColumnProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { isCensusRunning, isIngestActive, projectBackfills } from "../../lib/ingest.js";
|
|
4
|
+
import { UNASSIGNED_PROJECT_ID } from "../../lib/model.js";
|
|
5
|
+
import { compareActivityRanks } from "../../lib/activity-order.js";
|
|
6
|
+
import { PortfolioSummaryPanel } from "../SummaryPanels.js";
|
|
7
|
+
import { ListSummaryHeader, ListToolbar, SegmentedControl } from "../ui/index.js";
|
|
8
|
+
import { IngestStatus } from "../IngestStatus.js";
|
|
9
|
+
import { ProjectList } from "./ProjectList.js";
|
|
10
|
+
import { useHostInputs } from "../../host-inputs.js";
|
|
11
|
+
import { arrangeSections } from "../../lib/sections.js";
|
|
12
|
+
import { FilterChips } from "../FilterChips.js";
|
|
13
|
+
const PROJECT_SORT_OPTIONS = [
|
|
14
|
+
{ value: "recent", label: "recent" },
|
|
15
|
+
{ value: "token", label: "token" },
|
|
16
|
+
];
|
|
17
|
+
export function ProjectsColumn({ projects, activityOrder, selectedProjectId, sort, onSortChange, homeDirectory, currentTimestamp, ingest, activity, onProjectSelect, }) {
|
|
18
|
+
const ingestActive = isIngestActive(ingest);
|
|
19
|
+
// Metadata can arrive progressively; the status panel explains this
|
|
20
|
+
// without covering projects that are already available.
|
|
21
|
+
const censusRunning = isCensusRunning(ingest);
|
|
22
|
+
// The daemon's per-project fold: each cooking card draws its own byte
|
|
23
|
+
// meter from this, so progress reads at the row you actually care about.
|
|
24
|
+
const backfills = useMemo(() => projectBackfills(ingest), [ingest]);
|
|
25
|
+
// "Spend" is estimated USD (§4.1.3); tokens only break ties, so wholly
|
|
26
|
+
// unpriced projects still order among themselves.
|
|
27
|
+
const maximumLifetimeCost = useMemo(() => projects.reduce((maximum, project) => Math.max(maximum, project.lifetimeSpend.costMicroUsd ?? 0), 0), [projects]);
|
|
28
|
+
const visibleProjects = useMemo(() => [...projects].sort((left, right) => sort === "recent"
|
|
29
|
+
? compareActivityRanks(activityOrder.projects.get(left.row.id === UNASSIGNED_PROJECT_ID ? null : left.row.id)?.rankAt ?? null, activityOrder.projects.get(right.row.id === UNASSIGNED_PROJECT_ID ? null : right.row.id)?.rankAt ?? null, left.row.id, right.row.id)
|
|
30
|
+
: (right.lifetimeSpend.costMicroUsd ?? 0) - (left.lifetimeSpend.costMicroUsd ?? 0)
|
|
31
|
+
|| right.lifetimeTokens - left.lifetimeTokens || left.row.id.localeCompare(right.row.id)), [projects, sort, activityOrder]);
|
|
32
|
+
// R3: the host's sections over the room's own order.
|
|
33
|
+
const { projectSections, projectFilters } = useHostInputs();
|
|
34
|
+
const sections = useMemo(() => (projectSections === undefined ? null : arrangeSections(projectSections, visibleProjects, (p) => p.row.id)), [projectSections, visibleProjects]);
|
|
35
|
+
return (_jsxs("div", { className: "ah-col", children: [activity !== null ? (_jsx(ListSummaryHeader, { label: "Projects", count: projects.length, singularNoun: "project" })) : (_jsx(PortfolioSummaryPanel, { projects: projects, selectedProjectId: selectedProjectId, ingestActive: ingestActive, censusRunning: censusRunning, onProjectSelect: onProjectSelect })), _jsx(IngestStatus, { activity: activity }), _jsxs(ListToolbar, { children: [projectFilters !== undefined && projectFilters.length > 0 && _jsx(FilterChips, { filters: projectFilters }), _jsx(SegmentedControl, { value: sort, options: PROJECT_SORT_OPTIONS, accessibleLabel: "Rank projects by", className: "ah-sortseg", onValueChange: onSortChange })] }), _jsx("div", { className: "ah-veilhost", children: _jsx(ProjectList, { projects: visibleProjects, orderScope: `projects:${sort}`, selectedProjectId: selectedProjectId, maximumLifetimeCost: maximumLifetimeCost, homeDirectory: homeDirectory, currentTimestamp: currentTimestamp, ingestActive: ingestActive, runtimes: ingest?.runtimes, projectBackfills: backfills, pending: censusRunning, onProjectSelect: onProjectSelect, sections: sections }) })] }));
|
|
36
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { ProjectActivitySparkline } from "./ProjectActivitySparkline.js";
|
|
2
|
+
export type { ProjectActivitySparklineProps } from "./ProjectActivitySparkline.js";
|
|
3
|
+
export { ProjectList } from "./ProjectList.js";
|
|
4
|
+
export type { ProjectListProps } from "./ProjectList.js";
|
|
5
|
+
export { ProjectListItem } from "./ProjectListItem.js";
|
|
6
|
+
export type { ProjectListItemProps } from "./ProjectListItem.js";
|
|
7
|
+
export { ProjectsColumn } from "./ProjectsColumn.js";
|
|
8
|
+
export type { ProjectSort, ProjectsColumnProps } from "./ProjectsColumn.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface MatchStepperProps {
|
|
2
|
+
readonly query: string;
|
|
3
|
+
/** Zero-based position of the current match. */
|
|
4
|
+
readonly at: number;
|
|
5
|
+
readonly total: number;
|
|
6
|
+
readonly onStep: (delta: 1 | -1) => void;
|
|
7
|
+
readonly onDismiss: () => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function MatchStepper({ query, at, total, onStep, onDismiss }: MatchStepperProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// The stepper — what the sheet leaves behind when a hit lands. The head of
|
|
3
|
+
// the transcript says what the reader is doing (`debounce · 3 of 7`) and lets
|
|
4
|
+
// them walk the session's other matches without reopening the sheet, the way
|
|
5
|
+
// an editor's find bar walks a file. ⌘G / ⇧⌘G are the platform's own
|
|
6
|
+
// find-next / find-previous; the arrows are the same acts with a pointer.
|
|
7
|
+
import { CloseGlyph } from "../../lib/icons.js";
|
|
8
|
+
import { shortcutLabel } from "./shortcut.js";
|
|
9
|
+
function Chevron({ direction }) {
|
|
10
|
+
return (_jsx("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: _jsx("path", { d: direction === "up" ? "M4 10l4-4 4 4" : "M4 6l4 4 4-4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
11
|
+
}
|
|
12
|
+
export function MatchStepper({ query, at, total, onStep, onDismiss }) {
|
|
13
|
+
return (_jsxs("div", { className: "ah-stepper", role: "group", "aria-label": `${total} ${total === 1 ? "match" : "matches"} for ${query} in this session`, children: [_jsx("b", { title: query, children: query }), _jsxs("span", { className: "tnum", "aria-live": "polite", children: [at + 1, " of ", total] }), _jsx("button", { type: "button", "aria-label": `Previous match (${shortcutLabel("G", true)})`, title: `Previous match · ${shortcutLabel("G", true)}`, disabled: total <= 1, onClick: () => onStep(-1), children: _jsx(Chevron, { direction: "up" }) }), _jsx("button", { type: "button", "aria-label": `Next match (${shortcutLabel("G")})`, title: `Next match · ${shortcutLabel("G")}`, disabled: total <= 1, onClick: () => onStep(1), children: _jsx(Chevron, { direction: "down" }) }), _jsx("button", { type: "button", "aria-label": "Stop stepping through matches", title: "Done", onClick: onDismiss, children: _jsx(CloseGlyph, {}) })] }));
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface SearchLauncherProps {
|
|
2
|
+
/** The remembered query, or "" when nothing is being searched. */
|
|
3
|
+
readonly query: string;
|
|
4
|
+
/** The honest scope, e.g. `Search 6,720 sessions across 9 agents`. */
|
|
5
|
+
readonly placeholder: string;
|
|
6
|
+
/** The key the host binds to open the sheet, as printed (`searchKeyLegend`);
|
|
7
|
+
* null prints none — the room never names a key the host does not bind. */
|
|
8
|
+
readonly shortcut: string | null;
|
|
9
|
+
readonly onOpen: () => void;
|
|
10
|
+
readonly onClear: () => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function SearchLauncher({ query, placeholder, shortcut, onOpen, onClear }: SearchLauncherProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// The launcher — the door in the strip. It looks like the field it replaced
|
|
3
|
+
// (same pill, same glyph, same words) and sits where DESIGN.md §10 seats the
|
|
4
|
+
// file pill: centred in the drag strip, clear of the traffic lights. It does
|
|
5
|
+
// not take text; pressing it grows it into the sheet. When a search is
|
|
6
|
+
// active it says so in primary ink, because a filtered room should never
|
|
7
|
+
// look like an unfiltered one (design record §09: the scope of a search is
|
|
8
|
+
// not the reader's to guess).
|
|
9
|
+
import { SearchGlyph } from "../../lib/icons.js";
|
|
10
|
+
export function SearchLauncher({ query, placeholder, shortcut, onOpen, onClear }) {
|
|
11
|
+
const active = query !== "";
|
|
12
|
+
return (_jsxs("div", { className: "ah-launcher", "data-active": active || undefined, children: [_jsxs("button", { type: "button", className: "ah-launcher__open", "aria-haspopup": "dialog", "aria-label": active ? `Searching for ${query} — press to change` : placeholder, title: active ? `Searching for ${query}` : undefined, onClick: onOpen, children: [_jsx(SearchGlyph, {}), _jsx("span", { className: "ah-launcher__text", children: active ? query : placeholder }), shortcut !== null && (_jsx("kbd", { className: "ah-kbd", "aria-hidden": "true", children: shortcut }))] }), active && (_jsx("button", { type: "button", className: "ah-launcher__clear", "aria-label": "Clear the search", onClick: onClear, children: "\u00D7" }))] }));
|
|
13
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { SearchBuildProgress, SearchHit, SearchReadiness, SessionRow } from "@vibefield/rosetta-protocol";
|
|
2
|
+
import type { SearchFeed } from "../../lib/hooks.js";
|
|
3
|
+
import type { ProjectViewModel } from "../../lib/model.js";
|
|
4
|
+
import type { SearchResultsViewModel } from "../../lib/search-results.js";
|
|
5
|
+
import type { SearchFilters } from "../../lib/search-sheet.js";
|
|
6
|
+
export interface SearchSheetProps {
|
|
7
|
+
readonly open: boolean;
|
|
8
|
+
readonly onClose: () => void;
|
|
9
|
+
readonly query: string;
|
|
10
|
+
readonly onQuery: (query: string) => void;
|
|
11
|
+
readonly filters: SearchFilters;
|
|
12
|
+
readonly onFilters: (filters: SearchFilters) => void;
|
|
13
|
+
readonly feed: SearchFeed;
|
|
14
|
+
readonly results: SearchResultsViewModel | null;
|
|
15
|
+
readonly readiness: SearchReadiness | null;
|
|
16
|
+
readonly progress: SearchBuildProgress | null;
|
|
17
|
+
readonly canonicalReady: boolean | null;
|
|
18
|
+
readonly ingestPaused: boolean;
|
|
19
|
+
/** Runtime families the daemon reads, for the agent chip and the scope line. */
|
|
20
|
+
readonly agentKinds: readonly string[];
|
|
21
|
+
/** The selected project, so the sheet can offer to stay inside it. */
|
|
22
|
+
readonly currentProject: ProjectViewModel | null;
|
|
23
|
+
readonly homeDirectory: string | null;
|
|
24
|
+
readonly nowMs: number;
|
|
25
|
+
readonly getRuntimeKind: (runtimeId: string) => string;
|
|
26
|
+
readonly onOpenHit: (session: SessionRow, hit: SearchHit) => void;
|
|
27
|
+
}
|
|
28
|
+
export declare function headDomId(sessionId: string): string;
|
|
29
|
+
export declare function SearchSheet({ open, onClose, query, onQuery, filters, onFilters, feed, results, readiness, progress, canonicalReady, ingestPaused, agentKinds, currentProject, homeDirectory, nowMs, getRuntimeKind, onOpenHit, }: SearchSheetProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
// The search sheet — the door in the strip, grown into the tool it opens.
|
|
3
|
+
//
|
|
4
|
+
// A top-attached sheet (DESIGN.md §8's docs explorer, one level wider): the
|
|
5
|
+
// field where the launcher was, a scope row that says what is being searched,
|
|
6
|
+
// a list the keyboard walks, and a foot that tells the truth with numbers.
|
|
7
|
+
// Radix owns what a dialog must not get wrong — the portal, the focus trap,
|
|
8
|
+
// Escape, the outside press — and the input owns the cursor, APG combobox
|
|
9
|
+
// style: focus never leaves the field; `aria-activedescendant` names the row.
|
|
10
|
+
//
|
|
11
|
+
// What lands where is `lib/search-sheet.ts`; this file only draws it.
|
|
12
|
+
import * as Dialog from "@radix-ui/react-dialog";
|
|
13
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
14
|
+
import { AgentMark, agentLabel } from "../../lib/agents.js";
|
|
15
|
+
import { dayLabel } from "../../lib/format.js";
|
|
16
|
+
import { sessionLastActive } from "../../lib/session-activity.js";
|
|
17
|
+
import { SEARCH_LIMIT } from "../../lib/hooks.js";
|
|
18
|
+
import { SearchGlyph } from "../../lib/icons.js";
|
|
19
|
+
import { parseSnippet } from "../../lib/model.js";
|
|
20
|
+
import { KIND_FILTER_OPTIONS, buildSheetLines, cleanSnippet, forgetQuery, hitWhen, isCursorKey, kindWord, moveCursor, moveSection, readRecentQueries, sessionCrumb, stateSentence, } from "../../lib/search-sheet.js";
|
|
21
|
+
import { ActivityGlyph } from "../transcript/glyphs.js";
|
|
22
|
+
import { SegmentedControl } from "../ui/index.js";
|
|
23
|
+
import { hasPrimaryModifier } from "./shortcut.js";
|
|
24
|
+
import { useRoom, useRoomOverlay, useRoomPortal } from "../../room-context.js";
|
|
25
|
+
const LIST_ID = "ah-sheet-listbox";
|
|
26
|
+
/** Who said it, drawn the way the transcript draws them: the prompt is the
|
|
27
|
+
* one filled shape, a reply wears the agent's mark, activity the ledger's
|
|
28
|
+
* glyph, and everything else a quiet dot. */
|
|
29
|
+
function WhoGlyph({ kind, runtimeKind }) {
|
|
30
|
+
switch (kind) {
|
|
31
|
+
case "user":
|
|
32
|
+
return _jsx("i", { className: "ah-sheet__you" });
|
|
33
|
+
case "agent":
|
|
34
|
+
return _jsx(AgentMark, { kind: runtimeKind });
|
|
35
|
+
case "tool_use":
|
|
36
|
+
return _jsx(ActivityGlyph, {});
|
|
37
|
+
case "thinking":
|
|
38
|
+
return (_jsxs("svg", { viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true", children: [_jsx("circle", { cx: "3.5", cy: "8", r: "1.4" }), _jsx("circle", { cx: "8", cy: "8", r: "1.4" }), _jsx("circle", { cx: "12.5", cy: "8", r: "1.4" })] }));
|
|
39
|
+
default:
|
|
40
|
+
return _jsx("i", { className: "ah-sheet__dot" });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function headDomId(sessionId) {
|
|
44
|
+
return `ah-sheet-head-${sessionId}`;
|
|
45
|
+
}
|
|
46
|
+
function HeadLine({ head, runtimeKind, nowMs, }) {
|
|
47
|
+
const crumb = sessionCrumb(head.session);
|
|
48
|
+
return (_jsxs("div", { id: headDomId(head.session.id), className: "ah-sheet__head", role: "presentation", style: { "--tint": head.project.tint }, children: [_jsx("i", { "aria-hidden": "true" }), _jsxs("span", { className: "ah-sheet__crumb", children: [_jsx("b", { children: head.project.row.name }), _jsx("i", { "aria-hidden": "true", children: "\u203A" }), _jsx("span", { "data-mono": crumb.mono || undefined, title: crumb.mono ? `Native session ${head.session.native_session_id}` : crumb.text, children: crumb.text })] }), _jsx(AgentMark, { kind: runtimeKind }), _jsxs("span", { className: "ah-sheet__headmeta", children: [_jsxs("span", { children: [head.hitCount, " ", head.hitCount === 1 ? "hit" : "hits"] }), _jsx("span", { "aria-hidden": "true", children: "\u00B7" }), _jsx("span", { children: dayLabel(sessionLastActive(head.session), nowMs) })] })] }));
|
|
49
|
+
}
|
|
50
|
+
function OptionRow({ option, active, home, nowMs, runtimeKind, onHover, onOpen, }) {
|
|
51
|
+
const { hit, project, session } = option;
|
|
52
|
+
const parts = parseSnippet(cleanSnippet(hit.snippet, home));
|
|
53
|
+
const who = kindWord(hit.kind, agentLabel(runtimeKind));
|
|
54
|
+
const when = hitWhen(hit.at, nowMs);
|
|
55
|
+
const crumb = sessionCrumb(session);
|
|
56
|
+
const spoken = parts.map((part) => part.text).join("");
|
|
57
|
+
return (_jsxs("div", { id: option.id, role: "option", "aria-selected": active, "aria-label": `${who}: ${spoken} · ${when} · ${project.row.name} › ${crumb.text}`, className: "ah-sheet__row", onPointerMove: onHover, onClick: onOpen, children: [_jsx("span", { className: "ah-sheet__who", title: who, "aria-hidden": "true", children: _jsx(WhoGlyph, { kind: hit.kind, runtimeKind: runtimeKind }) }), _jsx("p", { className: "ah-sheet__snippet", children: parts.map((part, at) => part.mark ? _jsx("mark", { children: part.text }, at) : _jsx("span", { children: part.text }, at)) }), _jsx("span", { className: "ah-sheet__when", children: when })] }));
|
|
58
|
+
}
|
|
59
|
+
function Quiet({ title, children }) {
|
|
60
|
+
return (_jsxs("div", { className: "ah-sheet__quiet", role: "presentation", children: [_jsx("strong", { children: title }), _jsx("p", { children: children })] }));
|
|
61
|
+
}
|
|
62
|
+
const GRAMMAR_HINT = (_jsxs(_Fragment, { children: ["Every word must match. Put a phrase in quotes to match it exactly \u2014 ", _jsx("code", { children: "\"cargo test\"" }), ". Opening a result lands the transcript on that message."] }));
|
|
63
|
+
export function SearchSheet({ open, onClose, query, onQuery, filters, onFilters, feed, results, readiness, progress, canonicalReady, ingestPaused, agentKinds, currentProject, homeDirectory, nowMs, getRuntimeKind, onOpenHit, }) {
|
|
64
|
+
useRoomOverlay(open);
|
|
65
|
+
const container = useRoomPortal();
|
|
66
|
+
const { storage } = useRoom();
|
|
67
|
+
const inputRef = useRef(null);
|
|
68
|
+
const { lines, options } = useMemo(() => buildSheetLines(results), [results]);
|
|
69
|
+
const emptyQuery = query.trim() === "";
|
|
70
|
+
const [recent, setRecent] = useState([]);
|
|
71
|
+
const [active, setActive] = useState(-1);
|
|
72
|
+
// A keyboard move scrolls the cursor into view; a pointer move must not,
|
|
73
|
+
// or the list would crawl under a resting mouse.
|
|
74
|
+
const movedBy = useRef("keyboard");
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (open)
|
|
77
|
+
setRecent(readRecentQueries(storage));
|
|
78
|
+
}, [open]);
|
|
79
|
+
// New rows → the first one is the cursor, so Enter lands at once. Keyed on
|
|
80
|
+
// the rows' identities, not the array: the model is rebuilt on every clock
|
|
81
|
+
// tick, and a cursor that jumped home every thirty seconds would be a bug.
|
|
82
|
+
const walking = emptyQuery ? recent.length : options.length;
|
|
83
|
+
const rowsKey = emptyQuery ? `recent\n${recent.join("\n")}` : options.map((o) => o.id).join("\n");
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
movedBy.current = "keyboard";
|
|
86
|
+
setActive(rowsKey === "" || rowsKey === "recent\n" ? -1 : 0);
|
|
87
|
+
}, [rowsKey]);
|
|
88
|
+
const listRef = useRef(null);
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
if (movedBy.current !== "keyboard" || active < 0)
|
|
91
|
+
return;
|
|
92
|
+
const id = emptyQuery ? `ah-sheet-recent-${active}` : options[active]?.id;
|
|
93
|
+
const list = listRef.current;
|
|
94
|
+
const row = id === undefined ? null : document.getElementById(id);
|
|
95
|
+
if (list === null || row === null)
|
|
96
|
+
return;
|
|
97
|
+
// The list scrolls itself; `scrollIntoView` would also nudge the sheet.
|
|
98
|
+
const frame = list.getBoundingClientRect();
|
|
99
|
+
const rect = row.getBoundingClientRect();
|
|
100
|
+
const top = rect.top - frame.top + list.scrollTop;
|
|
101
|
+
const headroom = 30; // a pinned head sits over the first rows
|
|
102
|
+
if (rect.top < frame.top + headroom)
|
|
103
|
+
list.scrollTop = top - headroom;
|
|
104
|
+
else if (rect.bottom > frame.bottom)
|
|
105
|
+
list.scrollTop = top - (list.clientHeight - rect.height) + 4;
|
|
106
|
+
}, [active, emptyQuery, options]);
|
|
107
|
+
const hover = (index) => {
|
|
108
|
+
if (index === active)
|
|
109
|
+
return;
|
|
110
|
+
movedBy.current = "pointer";
|
|
111
|
+
setActive(index);
|
|
112
|
+
};
|
|
113
|
+
// A chip is pressed with the pointer and then forgotten: the field takes
|
|
114
|
+
// focus back, so the next keystroke searches and Enter still opens a row.
|
|
115
|
+
const narrow = (next) => {
|
|
116
|
+
onFilters(next);
|
|
117
|
+
inputRef.current?.focus();
|
|
118
|
+
};
|
|
119
|
+
const onKeyDown = (event) => {
|
|
120
|
+
// ⌘↑ / ⌘↓ jump a whole session, the way VS Code's sticky separators and
|
|
121
|
+
// Raycast's sections let the keyboard past a long group.
|
|
122
|
+
if (!emptyQuery &&
|
|
123
|
+
hasPrimaryModifier(event) &&
|
|
124
|
+
(event.key === "ArrowDown" || event.key === "ArrowUp")) {
|
|
125
|
+
if (options.length === 0)
|
|
126
|
+
return;
|
|
127
|
+
event.preventDefault();
|
|
128
|
+
movedBy.current = "keyboard";
|
|
129
|
+
const direction = event.key === "ArrowDown" ? 1 : -1;
|
|
130
|
+
setActive((current) => moveSection(current, direction, options));
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (isCursorKey(event.key)) {
|
|
134
|
+
if (walking === 0)
|
|
135
|
+
return;
|
|
136
|
+
event.preventDefault();
|
|
137
|
+
movedBy.current = "keyboard";
|
|
138
|
+
const key = event.key;
|
|
139
|
+
setActive((current) => moveCursor(current, key, walking));
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (event.key !== "Enter" || event.nativeEvent.isComposing)
|
|
143
|
+
return;
|
|
144
|
+
event.preventDefault();
|
|
145
|
+
if (emptyQuery) {
|
|
146
|
+
const remembered = recent[active];
|
|
147
|
+
if (remembered !== undefined)
|
|
148
|
+
onQuery(remembered);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const option = options[active];
|
|
152
|
+
if (option !== undefined)
|
|
153
|
+
onOpenHit(option.session, option.hit);
|
|
154
|
+
};
|
|
155
|
+
const building = readiness !== null && readiness !== "ready";
|
|
156
|
+
const sentence = stateSentence({
|
|
157
|
+
query: feed.query,
|
|
158
|
+
error: feed.error,
|
|
159
|
+
readiness,
|
|
160
|
+
progress,
|
|
161
|
+
canonicalReady,
|
|
162
|
+
ingestPaused,
|
|
163
|
+
counts: results?.counts ?? null,
|
|
164
|
+
limit: SEARCH_LIMIT,
|
|
165
|
+
});
|
|
166
|
+
const meter = building && progress !== null && progress.documents_total > 0
|
|
167
|
+
? `${Math.min(100, Math.max(2, (100 * progress.documents_done) / progress.documents_total)).toFixed(1)}%`
|
|
168
|
+
: building
|
|
169
|
+
? "8%"
|
|
170
|
+
: null;
|
|
171
|
+
const scopeLine = agentKinds.length === 0 ? "your whole agentic past" : `across ${agentKinds.join(" · ")}`;
|
|
172
|
+
const activeId = emptyQuery
|
|
173
|
+
? active >= 0 && recent[active] !== undefined
|
|
174
|
+
? `ah-sheet-recent-${active}`
|
|
175
|
+
: undefined
|
|
176
|
+
: options[active]?.id;
|
|
177
|
+
const scopeOptions = useMemo(() => {
|
|
178
|
+
if (currentProject === null)
|
|
179
|
+
return null;
|
|
180
|
+
const tint = { "--tint": currentProject.tint };
|
|
181
|
+
return [
|
|
182
|
+
{ value: "everywhere", label: "everywhere" },
|
|
183
|
+
{
|
|
184
|
+
value: "project",
|
|
185
|
+
label: (_jsxs(_Fragment, { children: [_jsx("i", { style: tint, "aria-hidden": "true" }), currentProject.row.name] })),
|
|
186
|
+
accessibleLabel: `only ${currentProject.row.name}`,
|
|
187
|
+
},
|
|
188
|
+
];
|
|
189
|
+
}, [currentProject]);
|
|
190
|
+
let body;
|
|
191
|
+
if (emptyQuery) {
|
|
192
|
+
body = (_jsxs(_Fragment, { children: [recent.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "ah-sheet__recent-head", role: "presentation", children: "Recent searches" }), recent.map((remembered, index) => (_jsxs("div", { id: `ah-sheet-recent-${index}`, role: "option", "aria-selected": index === active, className: "ah-sheet__recent", onPointerMove: () => hover(index), onClick: () => onQuery(remembered), children: [_jsx(SearchGlyph, {}), _jsx("span", { children: remembered }), _jsx("button", { type: "button", className: "ah-sheet__forget", "aria-label": `Forget ${remembered}`, tabIndex: -1, onClick: (event) => {
|
|
193
|
+
event.stopPropagation();
|
|
194
|
+
setRecent(forgetQuery(storage, remembered));
|
|
195
|
+
}, children: "\u00D7" })] }, remembered)))] })), _jsx(Quiet, { title: recent.length > 0 ? "Or search for something new" : "Search your whole agentic past", children: GRAMMAR_HINT })] }));
|
|
196
|
+
}
|
|
197
|
+
else if (lines.length === 0) {
|
|
198
|
+
body = feed.error !== null ? (_jsx(Quiet, { title: "Search failed", children: feed.error })) : building && results === null ? (_jsx(Quiet, { title: canonicalReady ? "Search is still being prepared" : "History is still being imported", children: sentence })) : results !== null ? (_jsxs(Quiet, { title: "Nothing matched", children: ["No indexed message contains every word of ", _jsx("code", { children: feed.query }), ". Try fewer words, or a phrase in quotes."] })) : null;
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
// One labelled group per session: the head names it for assistive
|
|
202
|
+
// technology, and bounding the sticky head to its group is what lets the
|
|
203
|
+
// next session's head push it away instead of painting over it.
|
|
204
|
+
const groups = [];
|
|
205
|
+
for (const line of lines) {
|
|
206
|
+
if (line.type === "head")
|
|
207
|
+
groups.push({ head: line, rows: [] });
|
|
208
|
+
else
|
|
209
|
+
groups[groups.length - 1]?.rows.push(line);
|
|
210
|
+
}
|
|
211
|
+
body = groups.map(({ head, rows }) => (_jsxs("div", { role: "group", "aria-labelledby": headDomId(head.session.id), className: "ah-sheet__group", children: [_jsx(HeadLine, { head: head, runtimeKind: getRuntimeKind(head.session.runtime_id), nowMs: nowMs }), rows.map((line) => (_jsx(OptionRow, { option: line, active: line.index === active, home: homeDirectory, nowMs: nowMs, runtimeKind: getRuntimeKind(line.session.runtime_id), onHover: () => hover(line.index), onOpen: () => onOpenHit(line.session, line.hit) }, line.key)))] }, head.key)));
|
|
212
|
+
}
|
|
213
|
+
return (_jsx(Dialog.Root, { open: open, onOpenChange: (next) => {
|
|
214
|
+
if (!next)
|
|
215
|
+
onClose();
|
|
216
|
+
}, children: _jsxs(Dialog.Portal, { container: container, children: [_jsx(Dialog.Overlay, { className: "ah-layer ah-sheet__backdrop", "data-ah-sheet": "" }), _jsxs(Dialog.Content, { className: "ah-layer ah-sheet", "aria-describedby": undefined, onOpenAutoFocus: (event) => {
|
|
217
|
+
// The field takes focus with its remembered text selected, so
|
|
218
|
+
// typing replaces the last search and the arrows edit it.
|
|
219
|
+
event.preventDefault();
|
|
220
|
+
const input = inputRef.current;
|
|
221
|
+
input?.focus();
|
|
222
|
+
input?.select();
|
|
223
|
+
}, children: [_jsx(Dialog.Title, { className: "ah-visually-hidden", children: "Search your whole agentic past" }), _jsxs("div", { className: "ah-sheet__field", children: [_jsx(SearchGlyph, {}), _jsx("input", { ref: inputRef, type: "text", enterKeyHint: "search", role: "combobox", "aria-expanded": "true", "aria-controls": LIST_ID, "aria-activedescendant": activeId, "aria-autocomplete": "list", "aria-label": "Search your whole agentic past", placeholder: "Search your whole agentic past", autoComplete: "off", spellCheck: false, value: query, onChange: (event) => onQuery(event.target.value), onKeyDown: onKeyDown }), query !== "" && (_jsx("button", { type: "button", className: "ah-sheet__clear", "aria-label": "Clear the search", onClick: () => {
|
|
224
|
+
onQuery("");
|
|
225
|
+
inputRef.current?.focus();
|
|
226
|
+
}, children: "\u00D7" })), _jsx("kbd", { className: "ah-kbd", "aria-hidden": "true", children: "esc" })] }), _jsxs("div", { className: "ah-sheet__scope", children: [scopeOptions !== null && (_jsx(SegmentedControl, { value: filters.scope, options: scopeOptions, accessibleLabel: "Where to search", onValueChange: (scope) => narrow({ ...filters, scope }) })), _jsx(SegmentedControl, { value: filters.kind, options: KIND_FILTER_OPTIONS, accessibleLabel: "Which kind of message", onValueChange: (kind) => narrow({ ...filters, kind }) }), agentKinds.length > 1 && (_jsxs("select", { className: "ah-chipselect", "data-set": filters.agent !== null || undefined, "aria-label": "Which agent", value: filters.agent ?? "", onChange: (event) => narrow({
|
|
227
|
+
...filters,
|
|
228
|
+
agent: event.target.value === "" ? null : event.target.value,
|
|
229
|
+
}), children: [_jsx("option", { value: "", children: "any agent" }), agentKinds.map((kind) => (_jsx("option", { value: kind, children: agentLabel(kind) }, kind)))] }))] }), _jsx("div", { ref: listRef, className: "ah-sheet__list", id: LIST_ID, role: "listbox", "aria-label": emptyQuery ? "Recent searches" : "Search results", "data-stale": feed.searching && results !== null ? "" : undefined, children: body }), _jsxs("div", { className: "ah-sheet__foot", children: [meter !== null && (_jsx("div", { className: "ah-meter", "aria-hidden": "true", children: _jsx("i", { style: { width: meter } }) })), _jsx("span", { className: "ah-sheet__count", role: "status", "aria-live": "polite", "data-tone": feed.error !== null ? "warn" : undefined, children: feed.searching && results === null && !emptyQuery ? "searching…" : sentence }), _jsx("span", { className: "ah-sheet__scopeline", title: scopeLine, children: scopeLine }), _jsxs("span", { className: "ah-sheet__keys", "aria-hidden": "true", children: [_jsxs("span", { children: [_jsx("kbd", { className: "ah-kbd", children: "\u2191\u2193" }), " move"] }), _jsxs("span", { children: [_jsx("kbd", { className: "ah-kbd", children: "\u21B5" }), " open"] }), _jsxs("span", { children: [_jsx("kbd", { className: "ah-kbd", children: "esc" }), " close"] })] })] })] })] }) }));
|
|
230
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { SearchSheet } from "./SearchSheet.js";
|
|
2
|
+
export type { SearchSheetProps } from "./SearchSheet.js";
|
|
3
|
+
export { SearchLauncher } from "./SearchLauncher.js";
|
|
4
|
+
export type { SearchLauncherProps } from "./SearchLauncher.js";
|
|
5
|
+
export { MatchStepper } from "./MatchStepper.js";
|
|
6
|
+
export type { MatchStepperProps } from "./MatchStepper.js";
|
|
7
|
+
export { emptyTranscriptPrompt, hasPrimaryModifier, searchKeyLegend, shortcutLabel } from "./shortcut.js";
|
|
8
|
+
export type { SearchShortcut } from "./shortcut.js";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** `⌘K` on a Mac, `Ctrl K` elsewhere — the label follows the modifier the
|
|
2
|
+
* handler actually listens for. */
|
|
3
|
+
export declare function isMacPlatform(): boolean;
|
|
4
|
+
export declare function shortcutLabel(key: string, shift?: boolean): string;
|
|
5
|
+
/** The primary modifier of a keyboard event on this platform. */
|
|
6
|
+
export declare function hasPrimaryModifier(event: KeyboardEvent | {
|
|
7
|
+
metaKey: boolean;
|
|
8
|
+
ctrlKey: boolean;
|
|
9
|
+
}): boolean;
|
|
10
|
+
/** What a host says about the key that opens its search sheet (RO-14). The
|
|
11
|
+
* room binds no key of its own — the host's window does (rosetta's app binds
|
|
12
|
+
* ⌘K) — so the room prints only what the host says it binds: undefined, the
|
|
13
|
+
* room's own label for ⌘K (`shortcutLabel("K")`); a label, that label; null,
|
|
14
|
+
* no key at all. */
|
|
15
|
+
export type SearchShortcut = {
|
|
16
|
+
readonly label: string;
|
|
17
|
+
} | null | undefined;
|
|
18
|
+
/** The legend the launcher prints, or null for none: no search, or a host
|
|
19
|
+
* that binds no key. */
|
|
20
|
+
export declare function searchKeyLegend(search: {
|
|
21
|
+
readonly shortcut?: SearchShortcut;
|
|
22
|
+
} | null): string | null;
|
|
23
|
+
/** The empty transcript's own sentence: it names a key only when the
|
|
24
|
+
* launcher prints one, so it never names a key the host does not bind. */
|
|
25
|
+
export declare function emptyTranscriptPrompt(legend: string | null): string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** `⌘K` on a Mac, `Ctrl K` elsewhere — the label follows the modifier the
|
|
2
|
+
* handler actually listens for. */
|
|
3
|
+
export function isMacPlatform() {
|
|
4
|
+
if (typeof navigator === "undefined")
|
|
5
|
+
return true;
|
|
6
|
+
return /Mac|iPhone|iPad/.test(navigator.platform) || /Mac/.test(navigator.userAgent);
|
|
7
|
+
}
|
|
8
|
+
export function shortcutLabel(key, shift = false) {
|
|
9
|
+
const mac = isMacPlatform();
|
|
10
|
+
const parts = [mac ? "⌘" : "Ctrl", shift ? (mac ? "⇧" : "Shift") : null, key].filter((part) => part !== null);
|
|
11
|
+
return mac ? parts.join("") : parts.join(" ");
|
|
12
|
+
}
|
|
13
|
+
/** The primary modifier of a keyboard event on this platform. */
|
|
14
|
+
export function hasPrimaryModifier(event) {
|
|
15
|
+
return isMacPlatform() ? event.metaKey : event.ctrlKey;
|
|
16
|
+
}
|
|
17
|
+
/** The legend the launcher prints, or null for none: no search, or a host
|
|
18
|
+
* that binds no key. */
|
|
19
|
+
export function searchKeyLegend(search) {
|
|
20
|
+
if (search === null)
|
|
21
|
+
return null;
|
|
22
|
+
if (search.shortcut === undefined)
|
|
23
|
+
return shortcutLabel("K");
|
|
24
|
+
return search.shortcut === null ? null : search.shortcut.label;
|
|
25
|
+
}
|
|
26
|
+
/** The empty transcript's own sentence: it names a key only when the
|
|
27
|
+
* launcher prints one, so it never names a key the host does not bind. */
|
|
28
|
+
export function emptyTranscriptPrompt(legend) {
|
|
29
|
+
return legend === null
|
|
30
|
+
? "Pick a session."
|
|
31
|
+
: `Pick a session — or press ${legend} to search, which is the front door.`;
|
|
32
|
+
}
|