@vibefield/rosetta-room 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,277 @@
|
|
|
1
|
+
// Block markdown: the structure a document is made of, read line by line.
|
|
2
|
+
//
|
|
3
|
+
// The subset is the one real documents are written in — headings, fences,
|
|
4
|
+
// lists, quotes, rules, GFM tables, paragraphs. What is deliberately absent
|
|
5
|
+
// is raw HTML: an HTML block is kept as the text it is, because rendering it
|
|
6
|
+
// would be the one thing `types.ts` says this parser must never do.
|
|
7
|
+
import { parseInline, parseInlineLines } from "./inline.js";
|
|
8
|
+
const ATX_HEADING = /^ {0,3}(#{1,6})(?:\s+(.*?))?\s*(?:\s#+)?$/;
|
|
9
|
+
const FENCE = /^ {0,3}(`{3,}|~{3,})\s*([^`\s]*)/;
|
|
10
|
+
const RULE = /^ {0,3}([-*_])[ \t]*(?:\1[ \t]*){2,}$/;
|
|
11
|
+
const QUOTE = /^ {0,3}> ?/;
|
|
12
|
+
const BULLET = /^(\s*)([-*+]|\d{1,9}[.)])(\s+|$)/;
|
|
13
|
+
const SETEXT = /^ {0,3}(=+|-+)\s*$/;
|
|
14
|
+
const TABLE_DELIMITER = /^\s*\|?(?:\s*:?-+:?\s*\|)+\s*:?-*:?\s*\|?\s*$/;
|
|
15
|
+
const isBlank = (line) => line.trim() === "";
|
|
16
|
+
const indentOf = (line) => line.length - line.trimStart().length;
|
|
17
|
+
/** Does a line interrupt the paragraph above it? */
|
|
18
|
+
function startsBlock(line) {
|
|
19
|
+
return (ATX_HEADING.test(line) ||
|
|
20
|
+
FENCE.test(line) ||
|
|
21
|
+
RULE.test(line) ||
|
|
22
|
+
QUOTE.test(line) ||
|
|
23
|
+
BULLET.test(line));
|
|
24
|
+
}
|
|
25
|
+
function bulletOf(line) {
|
|
26
|
+
const found = BULLET.exec(line);
|
|
27
|
+
// `- - -` is a rule wearing a bullet's clothes, and the rule reading wins.
|
|
28
|
+
if (found === null || RULE.test(line))
|
|
29
|
+
return null;
|
|
30
|
+
const [whole, lead, marker] = found;
|
|
31
|
+
return {
|
|
32
|
+
ordered: /\d/.test(marker),
|
|
33
|
+
start: /\d/.test(marker) ? Number.parseInt(marker, 10) : 1,
|
|
34
|
+
indent: lead.length,
|
|
35
|
+
contentIndent: whole.length,
|
|
36
|
+
content: line.slice(whole.length),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function splitRow(line) {
|
|
40
|
+
const cells = [];
|
|
41
|
+
let cell = "";
|
|
42
|
+
const body = line.trim().replace(/^\|/, "").replace(/\|$/, "");
|
|
43
|
+
for (let i = 0; i < body.length; i += 1) {
|
|
44
|
+
if (body[i] === "\\" && body[i + 1] === "|") {
|
|
45
|
+
cell += "|";
|
|
46
|
+
i += 1;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (body[i] === "|") {
|
|
50
|
+
cells.push(cell.trim());
|
|
51
|
+
cell = "";
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
cell += body[i];
|
|
55
|
+
}
|
|
56
|
+
cells.push(cell.trim());
|
|
57
|
+
return cells;
|
|
58
|
+
}
|
|
59
|
+
function alignmentOf(cell) {
|
|
60
|
+
const left = cell.startsWith(":");
|
|
61
|
+
const right = cell.endsWith(":");
|
|
62
|
+
if (left && right)
|
|
63
|
+
return "center";
|
|
64
|
+
if (right)
|
|
65
|
+
return "right";
|
|
66
|
+
if (left)
|
|
67
|
+
return "left";
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
// Keep source positions through cell trimming and escaped pipes. The inline
|
|
71
|
+
// parser owns unescaping, so a deleted escape never shifts later annotations.
|
|
72
|
+
function inlineCells(line, source) {
|
|
73
|
+
const cells = [];
|
|
74
|
+
const lead = line.length - line.trimStart().length;
|
|
75
|
+
const start = lead + (line[lead] === "|" ? 1 : 0);
|
|
76
|
+
const trimmedEnd = line.trimEnd().length;
|
|
77
|
+
const end = trimmedEnd - (line[trimmedEnd - 1] === "|" ? 1 : 0);
|
|
78
|
+
let cellStart = start;
|
|
79
|
+
const push = (to) => {
|
|
80
|
+
const raw = line.slice(cellStart, to);
|
|
81
|
+
const from = cellStart + raw.length - raw.trimStart().length;
|
|
82
|
+
const cell = raw.trim();
|
|
83
|
+
cells.push(parseInline(cell, false, source?.slice(from, from + cell.length)));
|
|
84
|
+
};
|
|
85
|
+
for (let i = start; i < end; i += 1) {
|
|
86
|
+
if (line[i] === "\\" && line[i + 1] === "|") {
|
|
87
|
+
i += 1;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (line[i] === "|") {
|
|
91
|
+
push(i);
|
|
92
|
+
cellStart = i + 1;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
push(end);
|
|
96
|
+
return cells;
|
|
97
|
+
}
|
|
98
|
+
export function parseBlocks(lines, sources) {
|
|
99
|
+
const out = [];
|
|
100
|
+
let index = 0;
|
|
101
|
+
while (index < lines.length) {
|
|
102
|
+
const line = lines[index];
|
|
103
|
+
const source = sources?.[index];
|
|
104
|
+
if (isBlank(line)) {
|
|
105
|
+
index += 1;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const fence = FENCE.exec(line);
|
|
109
|
+
if (fence !== null) {
|
|
110
|
+
const marker = fence[1][0];
|
|
111
|
+
const body = [];
|
|
112
|
+
index += 1;
|
|
113
|
+
while (index < lines.length) {
|
|
114
|
+
const closing = FENCE.exec(lines[index]);
|
|
115
|
+
if (closing !== null && closing[1][0] === marker && closing[1].length >= fence[1].length) {
|
|
116
|
+
index += 1;
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
body.push(lines[index]);
|
|
120
|
+
index += 1;
|
|
121
|
+
}
|
|
122
|
+
out.push({ type: "code", language: fence[2] === "" ? null : fence[2], text: body.join("\n") });
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const heading = ATX_HEADING.exec(line);
|
|
126
|
+
if (heading !== null) {
|
|
127
|
+
out.push({
|
|
128
|
+
type: "heading",
|
|
129
|
+
level: heading[1].length,
|
|
130
|
+
children: parseInline(heading[2] ?? "", false, source?.slice(line.indexOf(heading[2] ?? "", (line.length - line.trimStart().length) + heading[1].length))),
|
|
131
|
+
});
|
|
132
|
+
index += 1;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (RULE.test(line)) {
|
|
136
|
+
out.push({ type: "rule" });
|
|
137
|
+
index += 1;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (QUOTE.test(line)) {
|
|
141
|
+
const body = [];
|
|
142
|
+
const bodySources = [];
|
|
143
|
+
while (index < lines.length) {
|
|
144
|
+
if (QUOTE.test(lines[index])) {
|
|
145
|
+
bodySources.push(sources?.[index].slice(QUOTE.exec(lines[index])[0].length) ?? []);
|
|
146
|
+
body.push(lines[index].replace(QUOTE, ""));
|
|
147
|
+
index += 1;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
// A quote runs on through unmarked lines, the way a paragraph does,
|
|
151
|
+
// and stops at a blank one.
|
|
152
|
+
if (isBlank(lines[index]) || startsBlock(lines[index]))
|
|
153
|
+
break;
|
|
154
|
+
body.push(lines[index]);
|
|
155
|
+
bodySources.push(sources?.[index] ?? []);
|
|
156
|
+
index += 1;
|
|
157
|
+
}
|
|
158
|
+
out.push({ type: "quote", children: parseBlocks(body, sources === undefined ? undefined : bodySources) });
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (line.includes("|") &&
|
|
162
|
+
index + 1 < lines.length &&
|
|
163
|
+
TABLE_DELIMITER.test(lines[index + 1]) &&
|
|
164
|
+
splitRow(lines[index]).length === splitRow(lines[index + 1]).length) {
|
|
165
|
+
const head = inlineCells(lines[index], sources?.[index]);
|
|
166
|
+
const align = splitRow(lines[index + 1]).map(alignmentOf);
|
|
167
|
+
index += 2;
|
|
168
|
+
const rows = [];
|
|
169
|
+
while (index < lines.length && lines[index].includes("|") && !isBlank(lines[index])) {
|
|
170
|
+
rows.push(inlineCells(lines[index], sources?.[index]));
|
|
171
|
+
index += 1;
|
|
172
|
+
}
|
|
173
|
+
out.push({ type: "table", head, align, rows });
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const bullet = bulletOf(line);
|
|
177
|
+
if (bullet !== null) {
|
|
178
|
+
const items = [];
|
|
179
|
+
let tight = true;
|
|
180
|
+
let pendingBlank = false;
|
|
181
|
+
while (index < lines.length) {
|
|
182
|
+
if (isBlank(lines[index])) {
|
|
183
|
+
pendingBlank = true;
|
|
184
|
+
index += 1;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const next = bulletOf(lines[index]);
|
|
188
|
+
// A deeper bullet was already swallowed by the item above it, so
|
|
189
|
+
// anything at a different indent here closes this list. So does a
|
|
190
|
+
// change of marker kind: `1.` after `-` is a second list, not a
|
|
191
|
+
// seventh item.
|
|
192
|
+
if (next === null || next.indent !== bullet.indent || next.ordered !== bullet.ordered) {
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
if (items.length > 0 && pendingBlank)
|
|
196
|
+
tight = false;
|
|
197
|
+
pendingBlank = false;
|
|
198
|
+
const body = [next.content];
|
|
199
|
+
const bodySources = [sources?.[index].slice(next.contentIndent) ?? []];
|
|
200
|
+
index += 1;
|
|
201
|
+
while (index < lines.length) {
|
|
202
|
+
if (isBlank(lines[index])) {
|
|
203
|
+
let lookahead = index;
|
|
204
|
+
while (lookahead < lines.length && isBlank(lines[lookahead]))
|
|
205
|
+
lookahead += 1;
|
|
206
|
+
if (lookahead < lines.length &&
|
|
207
|
+
indentOf(lines[lookahead]) >= next.contentIndent &&
|
|
208
|
+
bulletOf(lines[lookahead])?.indent !== bullet.indent) {
|
|
209
|
+
body.push("");
|
|
210
|
+
bodySources.push([]);
|
|
211
|
+
index = lookahead;
|
|
212
|
+
tight = false;
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
if (indentOf(lines[index]) >= next.contentIndent) {
|
|
218
|
+
body.push(lines[index].slice(next.contentIndent));
|
|
219
|
+
bodySources.push(sources?.[index].slice(next.contentIndent) ?? []);
|
|
220
|
+
index += 1;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
// A wrapped line under a bullet needs no indent to belong to it.
|
|
224
|
+
if (!startsBlock(lines[index])) {
|
|
225
|
+
body.push(lines[index].trim());
|
|
226
|
+
bodySources.push(sources?.[index].slice(lines[index].length - lines[index].trimStart().length) ?? []);
|
|
227
|
+
index += 1;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
items.push(parseBlocks(body, sources === undefined ? undefined : bodySources));
|
|
233
|
+
}
|
|
234
|
+
out.push({ type: "list", ordered: bullet.ordered, start: bullet.start, tight, items });
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
// Four spaces of indent with no list above it is a code block.
|
|
238
|
+
if (/^ {4}/.test(line)) {
|
|
239
|
+
const body = [];
|
|
240
|
+
while (index < lines.length && (/^ {4}/.test(lines[index]) || isBlank(lines[index]))) {
|
|
241
|
+
body.push(lines[index].slice(4));
|
|
242
|
+
index += 1;
|
|
243
|
+
}
|
|
244
|
+
while (body.length > 0 && body[body.length - 1].trim() === "")
|
|
245
|
+
body.pop();
|
|
246
|
+
out.push({ type: "code", language: null, text: body.join("\n") });
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
const paragraph = [];
|
|
250
|
+
const paragraphSources = [];
|
|
251
|
+
while (index < lines.length && !isBlank(lines[index]) && !startsBlock(lines[index])) {
|
|
252
|
+
paragraph.push(lines[index]);
|
|
253
|
+
paragraphSources.push(sources?.[index] ?? []);
|
|
254
|
+
index += 1;
|
|
255
|
+
}
|
|
256
|
+
// A `===` or `---` under a paragraph makes it a heading after the fact,
|
|
257
|
+
// which is why the underline can only be recognised from here.
|
|
258
|
+
const underline = index < lines.length ? SETEXT.exec(lines[index]) : null;
|
|
259
|
+
if (underline !== null && paragraph.length > 0) {
|
|
260
|
+
index += 1;
|
|
261
|
+
out.push({
|
|
262
|
+
type: "heading",
|
|
263
|
+
level: underline[1][0] === "=" ? 1 : 2,
|
|
264
|
+
children: parseInlineLines(paragraph, sources === undefined ? undefined : paragraphSources),
|
|
265
|
+
});
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (paragraph.length > 0) {
|
|
269
|
+
out.push({ type: "paragraph", children: parseInlineLines(paragraph, sources === undefined ? undefined : paragraphSources) });
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
// Nothing claimed the line; take it as text so the loop always advances.
|
|
273
|
+
out.push({ type: "paragraph", children: parseInline(line, false, source) });
|
|
274
|
+
index += 1;
|
|
275
|
+
}
|
|
276
|
+
return out;
|
|
277
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Markdown, parsed to a tree. See `types.ts` for why it is never a string.
|
|
2
|
+
import { parseBlocks } from "./blocks.js";
|
|
3
|
+
/** Parse a whole document. Pure: no DOM, no network, no clock. */
|
|
4
|
+
export function parseMarkdown(text, trackSource = false) {
|
|
5
|
+
if (!trackSource) {
|
|
6
|
+
const lines = text.replace(/\r\n?/g, "\n").split("\n").map((line) => line.replace(/\t/g, " "));
|
|
7
|
+
return parseBlocks(lines);
|
|
8
|
+
}
|
|
9
|
+
// Maps use UTF-16 source offsets, matching JavaScript string slicing. They
|
|
10
|
+
// are optional: ordinary files pay no per-character mapping cost.
|
|
11
|
+
const lines = [];
|
|
12
|
+
const sources = [];
|
|
13
|
+
let line = "";
|
|
14
|
+
let positions = [];
|
|
15
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
16
|
+
const char = text[i];
|
|
17
|
+
if (char === "\r" || char === "\n") {
|
|
18
|
+
lines.push(line);
|
|
19
|
+
sources.push(positions);
|
|
20
|
+
line = "";
|
|
21
|
+
positions = [];
|
|
22
|
+
if (char === "\r" && text[i + 1] === "\n")
|
|
23
|
+
i += 1;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
const value = char === "\t" ? " " : char;
|
|
27
|
+
line += value;
|
|
28
|
+
for (let j = 0; j < value.length; j += 1)
|
|
29
|
+
positions.push(i);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
lines.push(line);
|
|
33
|
+
sources.push(positions);
|
|
34
|
+
return parseBlocks(lines, sources);
|
|
35
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Inline } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* @param insideLink Suppresses links inside a link's own label. `[https://x.dev](https://y.dev)`
|
|
4
|
+
* is a real and common way to write a README line, and autolinking the label
|
|
5
|
+
* puts an `<a>` inside an `<a>` — markup no browser is obliged to keep.
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseInline(text: string, insideLink?: boolean, source?: readonly number[]): readonly Inline[];
|
|
8
|
+
/** Split a paragraph's lines into inline nodes, honouring the two ways
|
|
9
|
+
* markdown spells a hard break. */
|
|
10
|
+
export declare function parseInlineLines(lines: readonly string[], sources?: readonly (readonly number[])[]): readonly Inline[];
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// Inline markdown: the marks inside one paragraph's worth of text.
|
|
2
|
+
//
|
|
3
|
+
// A left-to-right scanner rather than a chain of replacements. Replacement
|
|
4
|
+
// chains are how a naive renderer ends up emphasising the middle of a URL and
|
|
5
|
+
// bolding across a code span — the order of the passes decides the answer,
|
|
6
|
+
// and there is no order that is right for every document.
|
|
7
|
+
/**
|
|
8
|
+
* `[label](href)` and ``, with the optional "title" ignored.
|
|
9
|
+
*
|
|
10
|
+
* The href carries one level of balanced parentheses, because
|
|
11
|
+
* `…/wiki/Foo_(bar)` is a real link and stopping at the first `)` truncated
|
|
12
|
+
* it and left the other one loose in the prose. One level is what a regex can
|
|
13
|
+
* count and what every such URL actually uses.
|
|
14
|
+
*/
|
|
15
|
+
const LINK = /^!?\[((?:[^[\]\\]|\\.|\[[^\]]*\])*)\]\(\s*(<[^>]*>|(?:[^\s()]|\([^\s()]*\))*)(?:\s+"[^"]*")?\s*\)/;
|
|
16
|
+
const AUTOLINK = /^<((?:https?|mailto|file):[^>\s]+)>/;
|
|
17
|
+
const BARE_URL = /^https?:\/\/[^\s<>()[\]"']+[^\s<>()[\]"'.,;:!?]/;
|
|
18
|
+
/** A run of backticks opens a code span that the same run closes. */
|
|
19
|
+
const CODE_FENCE = /^`+/;
|
|
20
|
+
const DELIMITERS = [
|
|
21
|
+
{ mark: "***", type: "strong" },
|
|
22
|
+
{ mark: "___", type: "strong" },
|
|
23
|
+
{ mark: "**", type: "strong" },
|
|
24
|
+
{ mark: "__", type: "strong" },
|
|
25
|
+
{ mark: "~~", type: "strike" },
|
|
26
|
+
{ mark: "*", type: "emphasis" },
|
|
27
|
+
{ mark: "_", type: "emphasis" },
|
|
28
|
+
];
|
|
29
|
+
/** `_` inside `snake_case` is a word character, not an emphasis mark. The
|
|
30
|
+
* test is what surrounds the run, which is why it cannot be a regex on the
|
|
31
|
+
* mark alone. */
|
|
32
|
+
function opensRun(text, at, mark) {
|
|
33
|
+
const after = text[at + mark.length] ?? "";
|
|
34
|
+
if (after === "" || /\s/.test(after))
|
|
35
|
+
return false;
|
|
36
|
+
if (mark[0] !== "_")
|
|
37
|
+
return true;
|
|
38
|
+
const before = text[at - 1] ?? "";
|
|
39
|
+
return !/[A-Za-z0-9]/.test(before);
|
|
40
|
+
}
|
|
41
|
+
function closesRun(text, at, mark) {
|
|
42
|
+
const before = text[at - 1] ?? "";
|
|
43
|
+
if (before === "" || /\s/.test(before))
|
|
44
|
+
return false;
|
|
45
|
+
if (mark[0] !== "_")
|
|
46
|
+
return true;
|
|
47
|
+
const after = text[at + mark.length] ?? "";
|
|
48
|
+
return !/[A-Za-z0-9]/.test(after);
|
|
49
|
+
}
|
|
50
|
+
/** Where `mark` next closes a run opened at `from`, or -1. */
|
|
51
|
+
function findClose(text, from, mark) {
|
|
52
|
+
let at = from;
|
|
53
|
+
while (at < text.length) {
|
|
54
|
+
const next = text.indexOf(mark, at);
|
|
55
|
+
if (next === -1)
|
|
56
|
+
return -1;
|
|
57
|
+
if (text[next - 1] === "\\") {
|
|
58
|
+
at = next + mark.length;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (closesRun(text, next, mark))
|
|
62
|
+
return next;
|
|
63
|
+
at = next + mark.length;
|
|
64
|
+
}
|
|
65
|
+
return -1;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* @param insideLink Suppresses links inside a link's own label. `[https://x.dev](https://y.dev)`
|
|
69
|
+
* is a real and common way to write a README line, and autolinking the label
|
|
70
|
+
* puts an `<a>` inside an `<a>` — markup no browser is obliged to keep.
|
|
71
|
+
*/
|
|
72
|
+
export function parseInline(text, insideLink = false, source) {
|
|
73
|
+
const out = [];
|
|
74
|
+
let plain = "";
|
|
75
|
+
let positions = [];
|
|
76
|
+
let index = 0;
|
|
77
|
+
const flush = () => {
|
|
78
|
+
if (plain === "")
|
|
79
|
+
return;
|
|
80
|
+
out.push({ type: "text", value: plain, ...(source === undefined ? {} : { source: positions }) });
|
|
81
|
+
plain = "";
|
|
82
|
+
positions = [];
|
|
83
|
+
};
|
|
84
|
+
const push = (node) => {
|
|
85
|
+
flush();
|
|
86
|
+
out.push(node);
|
|
87
|
+
};
|
|
88
|
+
while (index < text.length) {
|
|
89
|
+
const rest = text.slice(index);
|
|
90
|
+
const char = text[index];
|
|
91
|
+
if (char === "\\" && index + 1 < text.length && /[\\`*_{}[\]()#+\-.!<>~|]/.test(text[index + 1])) {
|
|
92
|
+
plain += text[index + 1];
|
|
93
|
+
if (source !== undefined)
|
|
94
|
+
positions.push(source[index + 1]);
|
|
95
|
+
index += 2;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (char === "`") {
|
|
99
|
+
const fence = CODE_FENCE.exec(rest)?.[0] ?? "`";
|
|
100
|
+
const close = text.indexOf(fence, index + fence.length);
|
|
101
|
+
if (close !== -1) {
|
|
102
|
+
const body = text.slice(index + fence.length, close);
|
|
103
|
+
// CommonMark strips one space on each side, so `` ` `` can hold a
|
|
104
|
+
// backtick without the spaces becoming content.
|
|
105
|
+
const trimmed = body.length > 2 && body.startsWith(" ") && body.endsWith(" ") ? body.slice(1, -1) : body;
|
|
106
|
+
push({ type: "code", value: trimmed });
|
|
107
|
+
index = close + fence.length;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// An image inside a link label is legal markup — a linked thumbnail — so
|
|
112
|
+
// only the link half of this is suppressed.
|
|
113
|
+
if (char === "[" || (char === "!" && text[index + 1] === "[")) {
|
|
114
|
+
const found = LINK.exec(rest);
|
|
115
|
+
const isImage = found !== null && found[0].startsWith("!");
|
|
116
|
+
if (found !== null && (isImage || !insideLink)) {
|
|
117
|
+
const target = found[2].replace(/^<|>$/g, "");
|
|
118
|
+
if (isImage) {
|
|
119
|
+
push({ type: "image", src: target, alt: found[1] });
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
push({ type: "link", href: target, children: parseInline(found[1], true) });
|
|
123
|
+
}
|
|
124
|
+
index += found[0].length;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (char === "<" && !insideLink) {
|
|
129
|
+
const found = AUTOLINK.exec(rest);
|
|
130
|
+
if (found !== null) {
|
|
131
|
+
push({ type: "link", href: found[1], children: [{ type: "text", value: found[1] }] });
|
|
132
|
+
index += found[0].length;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (char === "h" && !insideLink && (index === 0 || /[\s(]/.test(text[index - 1] ?? " "))) {
|
|
137
|
+
const found = BARE_URL.exec(rest);
|
|
138
|
+
if (found !== null) {
|
|
139
|
+
push({ type: "link", href: found[0], children: [{ type: "text", value: found[0] }] });
|
|
140
|
+
index += found[0].length;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const delimiter = DELIMITERS.find((candidate) => rest.startsWith(candidate.mark) && opensRun(text, index, candidate.mark));
|
|
145
|
+
if (delimiter !== undefined) {
|
|
146
|
+
const close = findClose(text, index + delimiter.mark.length, delimiter.mark);
|
|
147
|
+
if (close !== -1) {
|
|
148
|
+
const inner = parseInline(text.slice(index + delimiter.mark.length, close), insideLink, source?.slice(index + delimiter.mark.length, close));
|
|
149
|
+
// `***bold italic***` is one mark carrying two, and nesting it here
|
|
150
|
+
// keeps the delimiter table flat.
|
|
151
|
+
push(delimiter.mark.length === 3
|
|
152
|
+
? { type: "strong", children: [{ type: "emphasis", children: inner }] }
|
|
153
|
+
: { type: delimiter.type, children: inner });
|
|
154
|
+
index = close + delimiter.mark.length;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
plain += char;
|
|
159
|
+
if (source !== undefined)
|
|
160
|
+
positions.push(source[index]);
|
|
161
|
+
index += 1;
|
|
162
|
+
}
|
|
163
|
+
flush();
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
/** Split a paragraph's lines into inline nodes, honouring the two ways
|
|
167
|
+
* markdown spells a hard break. */
|
|
168
|
+
export function parseInlineLines(lines, sources) {
|
|
169
|
+
const out = [];
|
|
170
|
+
lines.forEach((line, index) => {
|
|
171
|
+
const hard = /(?: {2,}|\\)$/.test(line);
|
|
172
|
+
out.push(...parseInline(hard ? line.replace(/(?: {2,}|\\)$/, "") : line.trimEnd(), false, sources?.[index]));
|
|
173
|
+
if (index === lines.length - 1)
|
|
174
|
+
return;
|
|
175
|
+
out.push(hard ? { type: "break" } : { type: "text", value: " " });
|
|
176
|
+
});
|
|
177
|
+
return out;
|
|
178
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { Block } from "./types.js";
|
|
3
|
+
export type InlineTextRenderer = (value: string, source?: readonly number[]) => ReactNode;
|
|
4
|
+
export declare function MarkdownBlocks({ blocks, renderText, }: {
|
|
5
|
+
readonly blocks: readonly Block[];
|
|
6
|
+
/** Optional decoration for plain text nodes. Code and link targets remain
|
|
7
|
+
* literal, so callers cannot accidentally nest an action inside a link. */
|
|
8
|
+
readonly renderText?: InlineTextRenderer | undefined;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// The markdown tree, as React elements.
|
|
3
|
+
//
|
|
4
|
+
// Two rules this file exists to keep:
|
|
5
|
+
//
|
|
6
|
+
// 1. **No `dangerouslySetInnerHTML`, anywhere.** The parser never produces
|
|
7
|
+
// markup and this never interprets any; a README in someone else's
|
|
8
|
+
// repository cannot reach the DOM as anything but text.
|
|
9
|
+
// 2. **No request leaves the machine.** An `` in an
|
|
10
|
+
// untrusted document is a tracking pixel with a caption, and a reader
|
|
11
|
+
// opening a file should not tell a third party they did. Images render as
|
|
12
|
+
// a labelled placeholder naming what they point at, which is also the
|
|
13
|
+
// honest answer for the `./diagram.png` case, where the viewer has no way
|
|
14
|
+
// to resolve a repository-relative path to something it may load.
|
|
15
|
+
import { Fragment } from "react";
|
|
16
|
+
import { highlight, languageFor, PLAIN_TEXT } from "../syntax/index.js";
|
|
17
|
+
/**
|
|
18
|
+
* The schemes the SHELL will actually open — no wider.
|
|
19
|
+
*
|
|
20
|
+
* `javascript:` and `data:` can do more than navigate, and they are the two a
|
|
21
|
+
* link in an untrusted document would want. `mailto:` is refused for the
|
|
22
|
+
* opposite reason: the room's window-open handler passes only http(s) to the
|
|
23
|
+
* OS, so a mailto link would render as a button that does nothing, and a dead
|
|
24
|
+
* promise is worse than plain text. In-document anchors and
|
|
25
|
+
* repository-relative paths point at nothing this viewer can reach.
|
|
26
|
+
*/
|
|
27
|
+
function safeHref(href) {
|
|
28
|
+
const trimmed = href.trim();
|
|
29
|
+
return /^https?:\/\//i.test(trimmed) ? trimmed : null;
|
|
30
|
+
}
|
|
31
|
+
function InlineNodes({ nodes, renderText, }) {
|
|
32
|
+
return (_jsx(_Fragment, { children: nodes.map((node, at) => (_jsx(Fragment, { children: node.type === "text" ? (renderText === undefined ? node.value : renderText(node.value, node.source)) : node.type === "code" ? (_jsx("code", { children: node.value })) : node.type === "strong" ? (_jsx("strong", { children: _jsx(InlineNodes, { nodes: node.children, renderText: renderText }) })) : node.type === "emphasis" ? (_jsx("em", { children: _jsx(InlineNodes, { nodes: node.children, renderText: renderText }) })) : node.type === "strike" ? (_jsx("s", { children: _jsx(InlineNodes, { nodes: node.children, renderText: renderText }) })) : node.type === "break" ? (_jsx("br", {})) : node.type === "image" ? (_jsx("span", { className: "ah-md__image", title: node.src, children: node.alt === "" ? node.src : node.alt })) : (_jsx(LinkOrText, { node: node })) }, at))) }));
|
|
33
|
+
}
|
|
34
|
+
/** A link the shell can open, or the text it was going to be. */
|
|
35
|
+
function LinkOrText({ node }) {
|
|
36
|
+
const href = safeHref(node.href);
|
|
37
|
+
if (href === null) {
|
|
38
|
+
return (_jsx("span", { className: "ah-md__deadlink", title: node.href, children: _jsx(InlineNodes, { nodes: node.children }) }));
|
|
39
|
+
}
|
|
40
|
+
// The shell's window-open handler sends http(s) to the browser; the room
|
|
41
|
+
// itself never navigates away.
|
|
42
|
+
return (_jsx("a", { href: href, target: "_blank", rel: "noreferrer", children: _jsx(InlineNodes, { nodes: node.children }) }));
|
|
43
|
+
}
|
|
44
|
+
function CodeFence({ language, text }) {
|
|
45
|
+
// A fence names its language the way a file name does, so the same table
|
|
46
|
+
// answers both — which is the whole reason the highlighter takes a language
|
|
47
|
+
// rather than a file.
|
|
48
|
+
const resolved = language === null ? PLAIN_TEXT : (languageFor(`x.${language}`) ?? PLAIN_TEXT);
|
|
49
|
+
const lines = highlight(text, resolved);
|
|
50
|
+
return (_jsx("pre", { className: "ah-md__code", "data-language": language ?? undefined, children: _jsx("code", { children: lines.map((line, row) => (_jsxs(Fragment, { children: [row > 0 && "\n", line.map((token, at) => token.kind === "plain" ? (_jsx(Fragment, { children: token.text }, at)) : (_jsx("span", { "data-t": token.kind, children: token.text }, at)))] }, row))) }) }));
|
|
51
|
+
}
|
|
52
|
+
export function MarkdownBlocks({ blocks, renderText, }) {
|
|
53
|
+
return (_jsx(_Fragment, { children: blocks.map((block, at) => {
|
|
54
|
+
switch (block.type) {
|
|
55
|
+
case "heading": {
|
|
56
|
+
const Tag = `h${Math.min(block.level, 6)}`;
|
|
57
|
+
return (_jsx(Tag, { children: _jsx(InlineNodes, { nodes: block.children, renderText: renderText }) }, at));
|
|
58
|
+
}
|
|
59
|
+
case "paragraph":
|
|
60
|
+
return (_jsx("p", { children: _jsx(InlineNodes, { nodes: block.children, renderText: renderText }) }, at));
|
|
61
|
+
case "code":
|
|
62
|
+
return _jsx(CodeFence, { language: block.language, text: block.text }, at);
|
|
63
|
+
case "quote":
|
|
64
|
+
return (_jsx("blockquote", { children: _jsx(MarkdownBlocks, { blocks: block.children, renderText: renderText }) }, at));
|
|
65
|
+
case "rule":
|
|
66
|
+
return _jsx("hr", {}, at);
|
|
67
|
+
case "list": {
|
|
68
|
+
const items = block.items.map((item, index) => (_jsx("li", { children: _jsx(MarkdownBlocks, { blocks: item, renderText: renderText }) }, index)));
|
|
69
|
+
return block.ordered ? (_jsx("ol", { start: block.start, "data-tight": block.tight ? "" : undefined, children: items }, at)) : (_jsx("ul", { "data-tight": block.tight ? "" : undefined, children: items }, at));
|
|
70
|
+
}
|
|
71
|
+
case "table":
|
|
72
|
+
return (
|
|
73
|
+
// A wide table scrolls inside its own box; the document's
|
|
74
|
+
// measure is not the table's to widen.
|
|
75
|
+
_jsx("div", { className: "ah-md__tablebox", children: _jsxs("table", { children: [_jsx("thead", { children: _jsx("tr", { children: block.head.map((cell, column) => (_jsx("th", { style: { textAlign: block.align[column] ?? undefined }, children: _jsx(InlineNodes, { nodes: cell, renderText: renderText }) }, column))) }) }), _jsx("tbody", { children: block.rows.map((row, index) => (_jsx("tr", { children: row.map((cell, column) => (_jsx("td", { style: { textAlign: block.align[column] ?? undefined }, children: _jsx(InlineNodes, { nodes: cell, renderText: renderText }) }, column))) }, index))) })] }) }, at));
|
|
76
|
+
}
|
|
77
|
+
}) }));
|
|
78
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export type Alignment = "left" | "center" | "right" | null;
|
|
2
|
+
export type Inline = {
|
|
3
|
+
readonly type: "text";
|
|
4
|
+
readonly value: string;
|
|
5
|
+
readonly source?: readonly number[];
|
|
6
|
+
} | {
|
|
7
|
+
readonly type: "code";
|
|
8
|
+
readonly value: string;
|
|
9
|
+
} | {
|
|
10
|
+
readonly type: "strong";
|
|
11
|
+
readonly children: readonly Inline[];
|
|
12
|
+
} | {
|
|
13
|
+
readonly type: "emphasis";
|
|
14
|
+
readonly children: readonly Inline[];
|
|
15
|
+
} | {
|
|
16
|
+
readonly type: "strike";
|
|
17
|
+
readonly children: readonly Inline[];
|
|
18
|
+
} | {
|
|
19
|
+
readonly type: "link";
|
|
20
|
+
readonly href: string;
|
|
21
|
+
readonly children: readonly Inline[];
|
|
22
|
+
} | {
|
|
23
|
+
readonly type: "image";
|
|
24
|
+
readonly src: string;
|
|
25
|
+
readonly alt: string;
|
|
26
|
+
} | {
|
|
27
|
+
readonly type: "break";
|
|
28
|
+
};
|
|
29
|
+
export type Block = {
|
|
30
|
+
readonly type: "heading";
|
|
31
|
+
readonly level: number;
|
|
32
|
+
readonly children: readonly Inline[];
|
|
33
|
+
} | {
|
|
34
|
+
readonly type: "paragraph";
|
|
35
|
+
readonly children: readonly Inline[];
|
|
36
|
+
} | {
|
|
37
|
+
readonly type: "code";
|
|
38
|
+
readonly language: string | null;
|
|
39
|
+
readonly text: string;
|
|
40
|
+
} | {
|
|
41
|
+
readonly type: "quote";
|
|
42
|
+
readonly children: readonly Block[];
|
|
43
|
+
} | {
|
|
44
|
+
readonly type: "rule";
|
|
45
|
+
} | {
|
|
46
|
+
readonly type: "list";
|
|
47
|
+
readonly ordered: boolean;
|
|
48
|
+
readonly start: number;
|
|
49
|
+
/** A list with no blank line between its items sets tighter. */
|
|
50
|
+
readonly tight: boolean;
|
|
51
|
+
readonly items: readonly (readonly Block[])[];
|
|
52
|
+
} | {
|
|
53
|
+
readonly type: "table";
|
|
54
|
+
readonly head: readonly (readonly Inline[])[];
|
|
55
|
+
readonly align: readonly Alignment[];
|
|
56
|
+
readonly rows: readonly (readonly (readonly Inline[])[])[];
|
|
57
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// The document shape a markdown file is parsed into. A TREE, never a string
|
|
2
|
+
// of HTML.
|
|
3
|
+
//
|
|
4
|
+
// That is a security boundary, not a style preference. A worktree is someone
|
|
5
|
+
// else's repository, and a README in it is untrusted input; `marked` plus
|
|
6
|
+
// `dangerouslySetInnerHTML` would let `<img src=x onerror=…>` in a checked-in
|
|
7
|
+
// file run inside a renderer that holds a preload bridge. Parsing to nodes
|
|
8
|
+
// and rendering them as React elements means there is no path from file
|
|
9
|
+
// content to executed markup at all — raw HTML in the source is shown as the
|
|
10
|
+
// text it is.
|
|
11
|
+
export {};
|