@stigmer/react 3.1.1 → 3.1.2
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/composer/SessionComposer.d.ts +24 -1
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +19 -8
- package/composer/SessionComposer.js.map +1 -1
- package/execution/ArtifactContentRenderer.d.ts +11 -1
- package/execution/ArtifactContentRenderer.d.ts.map +1 -1
- package/execution/ArtifactContentRenderer.js +39 -15
- package/execution/ArtifactContentRenderer.js.map +1 -1
- package/execution/FilePathContext.d.ts +8 -1
- package/execution/FilePathContext.d.ts.map +1 -1
- package/execution/FilePathContext.js.map +1 -1
- package/execution/FilePathLink.d.ts.map +1 -1
- package/execution/FilePathLink.js +21 -6
- package/execution/FilePathLink.js.map +1 -1
- package/execution/MessageEntry.d.ts +29 -0
- package/execution/MessageEntry.d.ts.map +1 -1
- package/execution/MessageEntry.js +29 -5
- package/execution/MessageEntry.js.map +1 -1
- package/execution/MessageThread.d.ts +76 -13
- package/execution/MessageThread.d.ts.map +1 -1
- package/execution/MessageThread.js +178 -24
- package/execution/MessageThread.js.map +1 -1
- package/execution/PlanArtifactCard.d.ts +27 -18
- package/execution/PlanArtifactCard.d.ts.map +1 -1
- package/execution/PlanArtifactCard.js +13 -23
- package/execution/PlanArtifactCard.js.map +1 -1
- package/execution/PlanDocumentMessage.d.ts +32 -0
- package/execution/PlanDocumentMessage.d.ts.map +1 -0
- package/execution/PlanDocumentMessage.js +37 -0
- package/execution/PlanDocumentMessage.js.map +1 -0
- package/execution/PlanStreamingCard.d.ts +45 -0
- package/execution/PlanStreamingCard.d.ts.map +1 -0
- package/execution/PlanStreamingCard.js +35 -0
- package/execution/PlanStreamingCard.js.map +1 -0
- package/execution/index.d.ts +5 -1
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +2 -0
- package/execution/index.js.map +1 -1
- package/execution/useCreateAgentExecution.d.ts +10 -0
- package/execution/useCreateAgentExecution.d.ts.map +1 -1
- package/execution/useCreateAgentExecution.js +5 -1
- package/execution/useCreateAgentExecution.js.map +1 -1
- package/github/decodeGitHubContent.d.ts +29 -0
- package/github/decodeGitHubContent.d.ts.map +1 -0
- package/github/decodeGitHubContent.js +72 -0
- package/github/decodeGitHubContent.js.map +1 -0
- package/github/index.d.ts +1 -0
- package/github/index.d.ts.map +1 -1
- package/github/index.js +1 -0
- package/github/index.js.map +1 -1
- package/github/useGitHubFileReader.d.ts +26 -0
- package/github/useGitHubFileReader.d.ts.map +1 -0
- package/github/useGitHubFileReader.js +106 -0
- package/github/useGitHubFileReader.js.map +1 -0
- package/github/useGitHubTreeLister.d.ts.map +1 -1
- package/github/useGitHubTreeLister.js +6 -2
- package/github/useGitHubTreeLister.js.map +1 -1
- package/index.d.ts +9 -9
- package/index.d.ts.map +1 -1
- package/index.js +5 -5
- package/index.js.map +1 -1
- package/internal/ResizableSplit.d.ts +72 -22
- package/internal/ResizableSplit.d.ts.map +1 -1
- package/internal/ResizableSplit.js +96 -38
- package/internal/ResizableSplit.js.map +1 -1
- package/internal/VirtualizedThread.d.ts +5 -3
- package/internal/VirtualizedThread.d.ts.map +1 -1
- package/internal/VirtualizedThread.js +6 -4
- package/internal/VirtualizedThread.js.map +1 -1
- package/internal/file-icons/index.d.ts +17 -0
- package/internal/file-icons/index.d.ts.map +1 -0
- package/internal/file-icons/index.js +60 -0
- package/internal/file-icons/index.js.map +1 -0
- package/internal/file-tree/FileTreeNode.d.ts +18 -1
- package/internal/file-tree/FileTreeNode.d.ts.map +1 -1
- package/internal/file-tree/FileTreeNode.js +11 -2
- package/internal/file-tree/FileTreeNode.js.map +1 -1
- package/internal/markdown-components.d.ts +38 -1
- package/internal/markdown-components.d.ts.map +1 -1
- package/internal/markdown-components.js +86 -11
- package/internal/markdown-components.js.map +1 -1
- package/{workflow → internal}/motion-preference.d.ts +7 -4
- package/internal/motion-preference.d.ts.map +1 -0
- package/{workflow → internal}/motion-preference.js +7 -4
- package/internal/motion-preference.js.map +1 -0
- package/internal/store/index.d.ts +33 -0
- package/internal/store/index.d.ts.map +1 -1
- package/internal/store/index.js +59 -0
- package/internal/store/index.js.map +1 -1
- package/internal/store/workspace-editors-store.d.ts +145 -0
- package/internal/store/workspace-editors-store.d.ts.map +1 -0
- package/internal/store/workspace-editors-store.js +208 -0
- package/internal/store/workspace-editors-store.js.map +1 -0
- package/internal/store/workspace-file-selection-store.d.ts +38 -0
- package/internal/store/workspace-file-selection-store.d.ts.map +1 -0
- package/internal/store/workspace-file-selection-store.js +62 -0
- package/internal/store/workspace-file-selection-store.js.map +1 -0
- package/internal/useRevealLine.d.ts +49 -0
- package/internal/useRevealLine.d.ts.map +1 -0
- package/internal/useRevealLine.js +43 -0
- package/internal/useRevealLine.js.map +1 -0
- package/library/detect-plan-artifact.d.ts +21 -0
- package/library/detect-plan-artifact.d.ts.map +1 -1
- package/library/detect-plan-artifact.js +20 -0
- package/library/detect-plan-artifact.js.map +1 -1
- package/library/detect-streaming-plan.d.ts +45 -0
- package/library/detect-streaming-plan.d.ts.map +1 -0
- package/library/detect-streaming-plan.js +83 -0
- package/library/detect-streaming-plan.js.map +1 -0
- package/library/index.d.ts +4 -1
- package/library/index.d.ts.map +1 -1
- package/library/index.js +2 -1
- package/library/index.js.map +1 -1
- package/package.json +4 -4
- package/session/NewSessionViewer.d.ts +19 -4
- package/session/NewSessionViewer.d.ts.map +1 -1
- package/session/NewSessionViewer.js +52 -25
- package/session/NewSessionViewer.js.map +1 -1
- package/session/PlanEditor.d.ts +55 -0
- package/session/PlanEditor.d.ts.map +1 -0
- package/session/PlanEditor.js +88 -0
- package/session/PlanEditor.js.map +1 -0
- package/session/PlanStreamingDocument.d.ts +30 -0
- package/session/PlanStreamingDocument.d.ts.map +1 -0
- package/session/PlanStreamingDocument.js +37 -0
- package/session/PlanStreamingDocument.js.map +1 -0
- package/session/SessionPanelChip.d.ts +26 -0
- package/session/SessionPanelChip.d.ts.map +1 -0
- package/session/SessionPanelChip.js +40 -0
- package/session/SessionPanelChip.js.map +1 -0
- package/session/SessionViewer.d.ts +34 -7
- package/session/SessionViewer.d.ts.map +1 -1
- package/session/SessionViewer.js +315 -33
- package/session/SessionViewer.js.map +1 -1
- package/session/{inspector → facets}/ArtifactsTab.d.ts +10 -2
- package/session/facets/ArtifactsTab.d.ts.map +1 -0
- package/session/{inspector → facets}/ArtifactsTab.js +8 -3
- package/session/facets/ArtifactsTab.js.map +1 -0
- package/session/{inspector → facets}/ChangesTab.d.ts +3 -3
- package/session/facets/ChangesTab.d.ts.map +1 -0
- package/session/{inspector → facets}/ChangesTab.js +3 -3
- package/session/facets/ChangesTab.js.map +1 -0
- package/session/facets/InspectTab.d.ts.map +1 -0
- package/session/facets/InspectTab.js.map +1 -0
- package/session/{inspector → facets}/SetupTab.d.ts +11 -2
- package/session/facets/SetupTab.d.ts.map +1 -0
- package/session/{inspector → facets}/SetupTab.js +4 -3
- package/session/facets/SetupTab.js.map +1 -0
- package/session/{inspector → facets}/UsageTab.d.ts +1 -1
- package/session/facets/UsageTab.d.ts.map +1 -0
- package/session/{inspector → facets}/UsageTab.js +1 -1
- package/session/facets/UsageTab.js.map +1 -0
- package/session/{inspector → facets}/index.d.ts +0 -6
- package/session/facets/index.d.ts.map +1 -0
- package/session/{inspector → facets}/index.js +0 -3
- package/session/facets/index.js.map +1 -0
- package/session/index.d.ts +11 -2
- package/session/index.d.ts.map +1 -1
- package/session/index.js +15 -2
- package/session/index.js.map +1 -1
- package/session/plan-document.d.ts +9 -0
- package/session/plan-document.d.ts.map +1 -0
- package/session/plan-document.js +17 -0
- package/session/plan-document.js.map +1 -0
- package/session/useOpenFileChange.d.ts +20 -0
- package/session/useOpenFileChange.d.ts.map +1 -0
- package/session/useOpenFileChange.js +31 -0
- package/session/useOpenFileChange.js.map +1 -0
- package/session/usePlanDraft.d.ts +52 -0
- package/session/usePlanDraft.d.ts.map +1 -0
- package/session/usePlanDraft.js +63 -0
- package/session/usePlanDraft.js.map +1 -0
- package/session/useSessionConversation.d.ts +6 -0
- package/session/useSessionConversation.d.ts.map +1 -1
- package/session/useSessionConversation.js +1 -0
- package/session/useSessionConversation.js.map +1 -1
- package/session/useSessionPageFlow.d.ts.map +1 -1
- package/session/useSessionPageFlow.js +1 -0
- package/session/useSessionPageFlow.js.map +1 -1
- package/session/useSessionPanel.d.ts +120 -0
- package/session/useSessionPanel.d.ts.map +1 -0
- package/session/useSessionPanel.js +130 -0
- package/session/useSessionPanel.js.map +1 -0
- package/session/useSessionRailViews.d.ts +45 -0
- package/session/useSessionRailViews.d.ts.map +1 -0
- package/session/useSessionRailViews.js +105 -0
- package/session/useSessionRailViews.js.map +1 -0
- package/src/composer/SessionComposer.tsx +52 -10
- package/src/composer/__tests__/SessionComposer-contract.test.tsx +58 -4
- package/src/execution/ArtifactContentRenderer.tsx +101 -24
- package/src/execution/FilePathContext.tsx +8 -1
- package/src/execution/FilePathLink.tsx +22 -6
- package/src/execution/MessageEntry.tsx +111 -1
- package/src/execution/MessageThread.tsx +291 -36
- package/src/execution/PlanArtifactCard.tsx +63 -31
- package/src/execution/PlanDocumentMessage.tsx +96 -0
- package/src/execution/PlanStreamingCard.tsx +137 -0
- package/src/execution/__tests__/ArtifactContentRenderer.test.tsx +80 -1
- package/src/execution/__tests__/FilePathLink.test.tsx +87 -0
- package/src/execution/__tests__/MessageThread.test.tsx +101 -0
- package/src/execution/__tests__/PlanArtifactCard.test.tsx +66 -12
- package/src/execution/__tests__/PlanDocumentMessage.test.tsx +55 -0
- package/src/execution/__tests__/PlanStreamingCard.test.tsx +49 -0
- package/src/execution/__tests__/buildThreadItems-plan-completion.test.ts +504 -22
- package/src/execution/__tests__/message-entry.test.tsx +48 -0
- package/src/execution/__tests__/useCreateAgentExecution.test.tsx +85 -0
- package/src/execution/index.ts +7 -1
- package/src/execution/useCreateAgentExecution.ts +16 -1
- package/src/github/__tests__/decodeGitHubContent.test.ts +102 -0
- package/src/github/__tests__/useGitHubFileReader.test.ts +183 -0
- package/src/github/decodeGitHubContent.ts +83 -0
- package/src/github/index.ts +1 -0
- package/src/github/useGitHubFileReader.ts +152 -0
- package/src/github/useGitHubTreeLister.ts +6 -2
- package/src/index.ts +63 -9
- package/src/internal/ResizableSplit.tsx +184 -51
- package/src/internal/VirtualizedThread.tsx +12 -4
- package/src/internal/__tests__/ResizableSplit.test.tsx +125 -3
- package/src/internal/__tests__/markdown-components.test.tsx +68 -0
- package/src/internal/__tests__/useRevealLine.test.tsx +97 -0
- package/src/internal/file-icons/__tests__/file-icons.test.tsx +35 -0
- package/src/internal/file-icons/index.tsx +137 -0
- package/src/internal/file-tree/FileTreeNode.tsx +43 -3
- package/src/internal/file-tree/__tests__/FileTreeNode-explorer.test.tsx +86 -0
- package/src/internal/markdown-components.tsx +116 -11
- package/src/{workflow → internal}/motion-preference.ts +7 -4
- package/src/internal/store/__tests__/workspace-editors-store.test.ts +216 -0
- package/src/internal/store/__tests__/workspace-file-selection-store.test.ts +118 -0
- package/src/internal/store/index.ts +94 -0
- package/src/internal/store/workspace-editors-store.ts +315 -0
- package/src/internal/store/workspace-file-selection-store.ts +88 -0
- package/src/internal/useRevealLine.ts +81 -0
- package/src/library/__tests__/detect-plan-artifact.test.ts +48 -0
- package/src/library/__tests__/detect-streaming-plan.test.ts +234 -0
- package/src/library/detect-plan-artifact.ts +35 -0
- package/src/library/detect-streaming-plan.ts +108 -0
- package/src/library/index.ts +5 -0
- package/src/session/NewSessionViewer.tsx +123 -55
- package/src/session/PlanEditor.tsx +361 -0
- package/src/session/PlanStreamingDocument.tsx +97 -0
- package/src/session/SessionPanelChip.tsx +103 -0
- package/src/session/SessionViewer.tsx +617 -90
- package/src/session/__tests__/NewSessionViewer.test.tsx +148 -0
- package/src/session/__tests__/PlanEditor.test.tsx +217 -0
- package/src/session/__tests__/PlanStreamingDocument.test.tsx +50 -0
- package/src/session/__tests__/SessionPanelChip.test.tsx +42 -0
- package/src/session/__tests__/SessionViewer-fileReviewDock.test.tsx +9 -4
- package/src/session/__tests__/SessionViewer-transcriptFileOpen.test.tsx +205 -0
- package/src/session/__tests__/audienceWiring.test.tsx +55 -19
- package/src/session/__tests__/useOpenFileChange.test.tsx +82 -0
- package/src/session/__tests__/usePlanDraft.test.ts +102 -0
- package/src/session/__tests__/useSessionPanel.test.ts +298 -0
- package/src/session/__tests__/useSessionRailViews.test.tsx +124 -0
- package/src/session/{inspector → facets}/ArtifactsTab.tsx +27 -5
- package/src/session/{inspector → facets}/ChangesTab.tsx +3 -3
- package/src/session/{inspector → facets}/SetupTab.tsx +13 -1
- package/src/session/{inspector → facets}/UsageTab.tsx +1 -1
- package/src/session/{inspector → facets}/__tests__/ArtifactsTab.test.tsx +35 -1
- package/src/session/facets/__tests__/SetupTab.test.tsx +44 -0
- package/src/session/{inspector → facets}/index.ts +0 -16
- package/src/session/index.ts +30 -13
- package/src/session/plan-document.ts +19 -0
- package/src/session/useOpenFileChange.ts +53 -0
- package/src/session/usePlanDraft.ts +109 -0
- package/src/session/useSessionConversation.ts +7 -0
- package/src/session/useSessionPageFlow.ts +1 -0
- package/src/session/useSessionPanel.ts +288 -0
- package/src/session/useSessionRailViews.tsx +200 -0
- package/src/workflow/WorkflowExecutionGraph.tsx +1 -1
- package/src/workflow/index.ts +1 -1
- package/src/workflow/useFollowExecution.ts +1 -1
- package/src/workspace/EditorTabs.tsx +145 -0
- package/src/workspace/ExplorerTree.tsx +247 -0
- package/src/workspace/FileViewer.tsx +516 -0
- package/src/workspace/WorkspaceContentSearch.tsx +478 -0
- package/src/workspace/WorkspaceContentSearcher.ts +70 -0
- package/src/workspace/WorkspaceFileLister.ts +11 -0
- package/src/workspace/WorkspaceFileReader.ts +57 -0
- package/src/workspace/WorkspaceFileSearch.tsx +429 -0
- package/src/workspace/WorkspaceSurface.tsx +781 -0
- package/src/workspace/__tests__/EditorTabs.test.tsx +100 -0
- package/src/workspace/__tests__/ExplorerTree.test.tsx +152 -0
- package/src/workspace/__tests__/FileViewer.test.tsx +421 -0
- package/src/workspace/__tests__/WorkspaceContentSearch.test.tsx +196 -0
- package/src/workspace/__tests__/WorkspaceFileSearch.test.tsx +206 -0
- package/src/workspace/__tests__/WorkspaceSurface.test.tsx +348 -0
- package/src/workspace/__tests__/findChangeForSelection.test.ts +132 -0
- package/src/workspace/__tests__/matchContentPreview.test.ts +55 -0
- package/src/workspace/__tests__/matchWorkspaceFiles.test.ts +104 -0
- package/src/workspace/__tests__/resolveWorkspaceFileSelection.test.ts +135 -0
- package/src/workspace/__tests__/useWorkspaceContentSearch.test.tsx +196 -0
- package/src/workspace/__tests__/useWorkspaceFileContent.test.tsx +190 -0
- package/src/workspace/__tests__/useWorkspaceFileSearch.test.tsx +162 -0
- package/src/workspace/findChangeForSelection.ts +61 -0
- package/src/workspace/index.ts +56 -2
- package/src/workspace/matchContentPreview.ts +51 -0
- package/src/workspace/matchWorkspaceFiles.ts +86 -0
- package/src/workspace/resolveWorkspaceFileSelection.ts +119 -0
- package/src/workspace/useWorkspaceContentSearch.ts +228 -0
- package/src/workspace/useWorkspaceFileContent.ts +129 -0
- package/src/workspace/useWorkspaceFileSearch.ts +184 -0
- package/src/workspace/useWorkspaceFiles.ts +27 -27
- package/src/workspace/workspaceListingCache.ts +93 -0
- package/styles.css +1 -1
- package/workflow/WorkflowExecutionGraph.js +1 -1
- package/workflow/WorkflowExecutionGraph.js.map +1 -1
- package/workflow/index.d.ts +1 -1
- package/workflow/index.d.ts.map +1 -1
- package/workflow/index.js +1 -1
- package/workflow/index.js.map +1 -1
- package/workflow/useFollowExecution.js +1 -1
- package/workflow/useFollowExecution.js.map +1 -1
- package/workspace/EditorTabs.d.ts +29 -0
- package/workspace/EditorTabs.d.ts.map +1 -0
- package/workspace/EditorTabs.js +66 -0
- package/workspace/EditorTabs.js.map +1 -0
- package/workspace/ExplorerTree.d.ts +32 -0
- package/workspace/ExplorerTree.d.ts.map +1 -0
- package/workspace/ExplorerTree.js +45 -0
- package/workspace/ExplorerTree.js.map +1 -0
- package/workspace/FileViewer.d.ts +93 -0
- package/workspace/FileViewer.d.ts.map +1 -0
- package/workspace/FileViewer.js +182 -0
- package/workspace/FileViewer.js.map +1 -0
- package/workspace/WorkspaceContentSearch.d.ts +41 -0
- package/workspace/WorkspaceContentSearch.d.ts.map +1 -0
- package/workspace/WorkspaceContentSearch.js +195 -0
- package/workspace/WorkspaceContentSearch.js.map +1 -0
- package/workspace/WorkspaceContentSearcher.d.ts +59 -0
- package/workspace/WorkspaceContentSearcher.d.ts.map +1 -0
- package/workspace/WorkspaceContentSearcher.js +7 -0
- package/workspace/WorkspaceContentSearcher.js.map +1 -0
- package/workspace/WorkspaceFileLister.d.ts +11 -0
- package/workspace/WorkspaceFileLister.d.ts.map +1 -1
- package/workspace/WorkspaceFileReader.d.ts +48 -0
- package/workspace/WorkspaceFileReader.d.ts.map +1 -0
- package/workspace/WorkspaceFileReader.js +11 -0
- package/workspace/WorkspaceFileReader.js.map +1 -0
- package/workspace/WorkspaceFileSearch.d.ts +32 -0
- package/workspace/WorkspaceFileSearch.d.ts.map +1 -0
- package/workspace/WorkspaceFileSearch.js +155 -0
- package/workspace/WorkspaceFileSearch.js.map +1 -0
- package/workspace/WorkspaceSurface.d.ts +151 -0
- package/workspace/WorkspaceSurface.d.ts.map +1 -0
- package/workspace/WorkspaceSurface.js +184 -0
- package/workspace/WorkspaceSurface.js.map +1 -0
- package/workspace/findChangeForSelection.d.ts +19 -0
- package/workspace/findChangeForSelection.d.ts.map +1 -0
- package/workspace/findChangeForSelection.js +46 -0
- package/workspace/findChangeForSelection.js.map +1 -0
- package/workspace/index.d.ts +24 -2
- package/workspace/index.d.ts.map +1 -1
- package/workspace/index.js +13 -1
- package/workspace/index.js.map +1 -1
- package/workspace/matchContentPreview.d.ts +21 -0
- package/workspace/matchContentPreview.d.ts.map +1 -0
- package/workspace/matchContentPreview.js +36 -0
- package/workspace/matchContentPreview.js.map +1 -0
- package/workspace/matchWorkspaceFiles.d.ts +30 -0
- package/workspace/matchWorkspaceFiles.d.ts.map +1 -0
- package/workspace/matchWorkspaceFiles.js +58 -0
- package/workspace/matchWorkspaceFiles.js.map +1 -0
- package/workspace/resolveWorkspaceFileSelection.d.ts +19 -0
- package/workspace/resolveWorkspaceFileSelection.d.ts.map +1 -0
- package/workspace/resolveWorkspaceFileSelection.js +115 -0
- package/workspace/resolveWorkspaceFileSelection.js.map +1 -0
- package/workspace/useWorkspaceContentSearch.d.ts +69 -0
- package/workspace/useWorkspaceContentSearch.d.ts.map +1 -0
- package/workspace/useWorkspaceContentSearch.js +154 -0
- package/workspace/useWorkspaceContentSearch.js.map +1 -0
- package/workspace/useWorkspaceFileContent.d.ts +73 -0
- package/workspace/useWorkspaceFileContent.d.ts.map +1 -0
- package/workspace/useWorkspaceFileContent.js +57 -0
- package/workspace/useWorkspaceFileContent.js.map +1 -0
- package/workspace/useWorkspaceFileSearch.d.ts +61 -0
- package/workspace/useWorkspaceFileSearch.d.ts.map +1 -0
- package/workspace/useWorkspaceFileSearch.js +119 -0
- package/workspace/useWorkspaceFileSearch.js.map +1 -0
- package/workspace/useWorkspaceFiles.d.ts +13 -5
- package/workspace/useWorkspaceFiles.d.ts.map +1 -1
- package/workspace/useWorkspaceFiles.js +18 -19
- package/workspace/useWorkspaceFiles.js.map +1 -1
- package/workspace/workspaceListingCache.d.ts +47 -0
- package/workspace/workspaceListingCache.d.ts.map +1 -0
- package/workspace/workspaceListingCache.js +55 -0
- package/workspace/workspaceListingCache.js.map +1 -0
- package/session/inspector/ArtifactsTab.d.ts.map +0 -1
- package/session/inspector/ArtifactsTab.js.map +0 -1
- package/session/inspector/ChangesTab.d.ts.map +0 -1
- package/session/inspector/ChangesTab.js.map +0 -1
- package/session/inspector/InspectTab.d.ts.map +0 -1
- package/session/inspector/InspectTab.js.map +0 -1
- package/session/inspector/SessionInspector.d.ts +0 -64
- package/session/inspector/SessionInspector.d.ts.map +0 -1
- package/session/inspector/SessionInspector.js +0 -53
- package/session/inspector/SessionInspector.js.map +0 -1
- package/session/inspector/SetupTab.d.ts.map +0 -1
- package/session/inspector/SetupTab.js.map +0 -1
- package/session/inspector/UsageTab.d.ts.map +0 -1
- package/session/inspector/UsageTab.js.map +0 -1
- package/session/inspector/WorkspaceTab.d.ts +0 -35
- package/session/inspector/WorkspaceTab.d.ts.map +0 -1
- package/session/inspector/WorkspaceTab.js +0 -75
- package/session/inspector/WorkspaceTab.js.map +0 -1
- package/session/inspector/index.d.ts.map +0 -1
- package/session/inspector/index.js.map +0 -1
- package/session/inspector/useSessionInspector.d.ts +0 -49
- package/session/inspector/useSessionInspector.d.ts.map +0 -1
- package/session/inspector/useSessionInspector.js +0 -122
- package/session/inspector/useSessionInspector.js.map +0 -1
- package/src/session/inspector/SessionInspector.tsx +0 -162
- package/src/session/inspector/WorkspaceTab.tsx +0 -245
- package/src/session/inspector/__tests__/useSessionInspector.test.ts +0 -251
- package/src/session/inspector/useSessionInspector.ts +0 -178
- package/src/workspace/WorkspaceEntryFiles.tsx +0 -196
- package/workflow/motion-preference.d.ts.map +0 -1
- package/workflow/motion-preference.js.map +0 -1
- package/workspace/WorkspaceEntryFiles.d.ts +0 -22
- package/workspace/WorkspaceEntryFiles.d.ts.map +0 -1
- package/workspace/WorkspaceEntryFiles.js +0 -58
- package/workspace/WorkspaceEntryFiles.js.map +0 -1
- /package/session/{inspector → facets}/InspectTab.d.ts +0 -0
- /package/session/{inspector → facets}/InspectTab.js +0 -0
- /package/src/{workflow → internal}/__tests__/motion-preference.test.ts +0 -0
- /package/src/session/{inspector → facets}/InspectTab.tsx +0 -0
- /package/src/session/{inspector → facets}/__tests__/ChangesTab.test.tsx +0 -0
|
@@ -0,0 +1,781 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useRef, useState, type KeyboardEvent, type ReactNode } from "react";
|
|
4
|
+
import { cn } from "@stigmer/theme";
|
|
5
|
+
import type { FileChange } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
|
|
6
|
+
import { ResizableSplit } from "../internal/ResizableSplit.js";
|
|
7
|
+
import {
|
|
8
|
+
editorKey,
|
|
9
|
+
type OpenEditor,
|
|
10
|
+
type OpenFileOptions,
|
|
11
|
+
type SelectedWorkspaceFile,
|
|
12
|
+
} from "../internal/store/index.js";
|
|
13
|
+
import type { RevealTarget } from "../internal/useRevealLine.js";
|
|
14
|
+
import type { WorkspaceEntry } from "./useWorkspaceEntries.js";
|
|
15
|
+
import type { WorkspaceFileLister } from "./WorkspaceFileLister.js";
|
|
16
|
+
import type { WorkspaceFileReader } from "./WorkspaceFileReader.js";
|
|
17
|
+
import type { WorkspaceContentSearcher } from "./WorkspaceContentSearcher.js";
|
|
18
|
+
import { WorkspaceFileSearch } from "./WorkspaceFileSearch.js";
|
|
19
|
+
import { WorkspaceContentSearch } from "./WorkspaceContentSearch.js";
|
|
20
|
+
import { FileViewer, type FileViewerHandle } from "./FileViewer.js";
|
|
21
|
+
import { EditorTabs } from "./EditorTabs.js";
|
|
22
|
+
import { ExplorerTree } from "./ExplorerTree.js";
|
|
23
|
+
|
|
24
|
+
/** The built-in rail views every surface has. */
|
|
25
|
+
const BUILT_IN_VIEWS = ["files", "search"] as const;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A host-injected rail view: an icon in the activity rail whose content
|
|
29
|
+
* renders in the sidebar pane when active.
|
|
30
|
+
*
|
|
31
|
+
* This is how session facets (Config, Changes, Artifacts, …) join the built-in
|
|
32
|
+
* Explorer/Search views without the surface knowing any session domain — the
|
|
33
|
+
* same composition philosophy as the injected lister/reader capabilities
|
|
34
|
+
* (DD-004). The surface stays an embeddable, domain-pure workspace organism;
|
|
35
|
+
* hosts extend its rail.
|
|
36
|
+
*/
|
|
37
|
+
export interface SurfaceRailView {
|
|
38
|
+
/** Unique view id. Must not collide with the built-in `"files"`/`"search"`. */
|
|
39
|
+
readonly id: string;
|
|
40
|
+
/** Accessible label; also rendered as the sidebar heading. */
|
|
41
|
+
readonly label: string;
|
|
42
|
+
/** Monochrome rail icon (tinted via `currentColor`, DD-005). */
|
|
43
|
+
readonly icon: ReactNode;
|
|
44
|
+
/** Optional count badge rendered over the rail icon (hidden when 0). */
|
|
45
|
+
readonly badge?: number;
|
|
46
|
+
/** Sidebar content rendered while this view is active. */
|
|
47
|
+
readonly content: ReactNode;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* A host-injected virtual document: an editor tab whose content is not a
|
|
52
|
+
* workspace file — the session's `plan.md` today; execution artifacts are the
|
|
53
|
+
* anticipated next family.
|
|
54
|
+
*
|
|
55
|
+
* The editor-area counterpart of {@link SurfaceRailView}'s rail injection
|
|
56
|
+
* (DD-004): virtual documents share the tab group with file tabs (identical
|
|
57
|
+
* open / pin / close / activate semantics through the same editors store),
|
|
58
|
+
* and only the *body* rendering diverges — the surface renders `content`
|
|
59
|
+
* instead of breadcrumbs + `FileViewer`. The surface stays domain-pure: it
|
|
60
|
+
* matches tabs to virtual documents by identity and knows nothing about what
|
|
61
|
+
* the document is.
|
|
62
|
+
*
|
|
63
|
+
* `entryId` must come from `virtualEntryId(kind)` so it can never alias a
|
|
64
|
+
* real workspace entry; `path` doubles as the tab label's source (its
|
|
65
|
+
* basename), matching file-tab behavior.
|
|
66
|
+
*/
|
|
67
|
+
export interface SurfaceVirtualDocument {
|
|
68
|
+
/** Virtual entry id (from `virtualEntryId`) — the tab's owning "entry". */
|
|
69
|
+
readonly entryId: string;
|
|
70
|
+
/** Tab identity within the entry; its basename is the tab label. */
|
|
71
|
+
readonly path: string;
|
|
72
|
+
/** Editor-area content rendered while this document's tab is active. */
|
|
73
|
+
readonly content: ReactNode;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Props for {@link WorkspaceSurface}. */
|
|
77
|
+
export interface WorkspaceSurfaceProps {
|
|
78
|
+
/** The workspace entries whose files are browsable (multi-root). */
|
|
79
|
+
readonly entries: readonly WorkspaceEntry[];
|
|
80
|
+
/** Platform-injected file lister. `undefined` disables explorer + search. */
|
|
81
|
+
readonly lister: WorkspaceFileLister | undefined;
|
|
82
|
+
/** Platform-injected content reader for the editor. */
|
|
83
|
+
readonly reader: WorkspaceFileReader | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* Platform-injected content (text) searcher. When provided, the Search pane
|
|
86
|
+
* gains a `Name | Text` toggle offering full-text search; `undefined` (web/git
|
|
87
|
+
* today) keeps the Search pane filename-only (DD-09). Mirrors the lister's
|
|
88
|
+
* null contract — the honest "unavailable here" state.
|
|
89
|
+
*/
|
|
90
|
+
readonly searcher?: WorkspaceContentSearcher;
|
|
91
|
+
/**
|
|
92
|
+
* The active rail view id (`"files"`, `"search"`, or an {@link SurfaceRailView.id}).
|
|
93
|
+
* Provide together with `onViewChange` to control the rail from the host;
|
|
94
|
+
* omit for internal (uncontrolled) view state. An id that matches no view
|
|
95
|
+
* (e.g. a contextual extra view that disappeared) falls back to `"files"`.
|
|
96
|
+
*/
|
|
97
|
+
readonly view?: string;
|
|
98
|
+
/** Called when the user picks a rail view. */
|
|
99
|
+
readonly onViewChange?: (viewId: string) => void;
|
|
100
|
+
/**
|
|
101
|
+
* Host-injected rail views, rendered after the built-in Explorer/Search.
|
|
102
|
+
* Their `content` renders in the sidebar pane; the editor area stays for
|
|
103
|
+
* files (the VS Code model).
|
|
104
|
+
*/
|
|
105
|
+
readonly extraViews?: readonly SurfaceRailView[];
|
|
106
|
+
/**
|
|
107
|
+
* Host-injected virtual documents (see {@link SurfaceVirtualDocument}).
|
|
108
|
+
* A tab whose identity matches one of these renders its `content` in the
|
|
109
|
+
* editor area instead of the file viewer. The host opens/activates the tab
|
|
110
|
+
* through the same editors-store seams as files.
|
|
111
|
+
*/
|
|
112
|
+
readonly virtualDocuments?: readonly SurfaceVirtualDocument[];
|
|
113
|
+
/**
|
|
114
|
+
* Detach a workspace entry. When provided, explorer root headers carry a
|
|
115
|
+
* remove control (VS Code's "Remove Folder from Workspace").
|
|
116
|
+
*/
|
|
117
|
+
readonly onRemoveEntry?: (entryId: string) => void;
|
|
118
|
+
/**
|
|
119
|
+
* Attach a local folder (host opens its native picker and adds the entry).
|
|
120
|
+
* When provided, the explorer renders an "Add Folder" footer action —
|
|
121
|
+
* desktop hosts wire this; web hosts omit it (no native picker).
|
|
122
|
+
*/
|
|
123
|
+
readonly onAddLocalFolder?: () => void;
|
|
124
|
+
/** Open editor tabs in order (VS Code open-editors model). */
|
|
125
|
+
readonly editors: readonly OpenEditor[];
|
|
126
|
+
/** The active editor's file, or `null`. Highlighted in the tree and shown. */
|
|
127
|
+
readonly selectedFile: SelectedWorkspaceFile | null;
|
|
128
|
+
/**
|
|
129
|
+
* Opens a file as a preview (single click) from the explorer or search. The
|
|
130
|
+
* same seam the tree/search uses; the owner routes it to the editors store.
|
|
131
|
+
* `options.line` (content-search hits) requests a jump-to-line reveal.
|
|
132
|
+
*/
|
|
133
|
+
readonly onOpenFile: (
|
|
134
|
+
entryId: string,
|
|
135
|
+
path: string,
|
|
136
|
+
options?: OpenFileOptions,
|
|
137
|
+
) => void;
|
|
138
|
+
/** Focuses an already-open editor (tab single click). */
|
|
139
|
+
readonly onActivateEditor: (entryId: string, path: string) => void;
|
|
140
|
+
/** Pins an editor (tab double-click) so it stops being the preview tab. */
|
|
141
|
+
readonly onPinEditor: (entryId: string, path: string) => void;
|
|
142
|
+
/** Closes an editor (tab close control or middle click). */
|
|
143
|
+
readonly onCloseEditor: (entryId: string, path: string) => void;
|
|
144
|
+
/** Collapses the surface back to the chat-dominant layout. */
|
|
145
|
+
readonly onCollapse: () => void;
|
|
146
|
+
/**
|
|
147
|
+
* The session {@link FileChange} that touched the open file, when it was
|
|
148
|
+
* changed this session. When present the editor defaults to the authoritative
|
|
149
|
+
* `baseline→candidate` diff (DD-06), matching the inspector's Viewer tab.
|
|
150
|
+
*/
|
|
151
|
+
readonly change?: FileChange;
|
|
152
|
+
/**
|
|
153
|
+
* Jump-to-line reveal for the **active** editor (already scoped by the owner
|
|
154
|
+
* to `reveal.key === activeKey`), or `undefined`. Forwarded to the editor's
|
|
155
|
+
* viewer, which opens in File view and scrolls to / highlights the line.
|
|
156
|
+
*/
|
|
157
|
+
readonly reveal?: RevealTarget;
|
|
158
|
+
/** Additional CSS classes for the root element. */
|
|
159
|
+
readonly className?: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* A VS Code / Cursor-inspired read-only workspace surface: a slim activity rail
|
|
164
|
+
* (Explorer / Search), a resizable sidebar, and a large editor area.
|
|
165
|
+
*
|
|
166
|
+
* This is the workspace-dominant counterpart to the inspector's cramped Viewer
|
|
167
|
+
* tab. The session viewer flips its layout to give this surface the majority of
|
|
168
|
+
* the screen while chat becomes a narrow column (see `SessionViewer`). It is a
|
|
169
|
+
* self-contained organism: given `entries`, a `lister`, a `reader`, and the
|
|
170
|
+
* open-file selection, it renders identically inside the Console or embedded in
|
|
171
|
+
* a third-party host (DD-004). Explicitly read-only — no editing, no commit UI.
|
|
172
|
+
*
|
|
173
|
+
* All visual properties flow through `--stgm-*` tokens (DD-005).
|
|
174
|
+
*/
|
|
175
|
+
export function WorkspaceSurface({
|
|
176
|
+
entries,
|
|
177
|
+
lister,
|
|
178
|
+
reader,
|
|
179
|
+
searcher,
|
|
180
|
+
view,
|
|
181
|
+
onViewChange,
|
|
182
|
+
extraViews,
|
|
183
|
+
virtualDocuments,
|
|
184
|
+
onRemoveEntry,
|
|
185
|
+
onAddLocalFolder,
|
|
186
|
+
editors,
|
|
187
|
+
selectedFile,
|
|
188
|
+
onOpenFile,
|
|
189
|
+
onActivateEditor,
|
|
190
|
+
onPinEditor,
|
|
191
|
+
onCloseEditor,
|
|
192
|
+
onCollapse,
|
|
193
|
+
change,
|
|
194
|
+
reveal,
|
|
195
|
+
className,
|
|
196
|
+
}: WorkspaceSurfaceProps) {
|
|
197
|
+
// Optionally controlled (standard React pattern): a host that owns view
|
|
198
|
+
// routing (e.g. the session panel's auto-view logic) passes `view` +
|
|
199
|
+
// `onViewChange`; standalone embedders get internal state for free.
|
|
200
|
+
const [uncontrolledView, setUncontrolledView] = useState<string>("files");
|
|
201
|
+
const requestedView = view ?? uncontrolledView;
|
|
202
|
+
const handleViewChange = useCallback(
|
|
203
|
+
(next: string) => {
|
|
204
|
+
setUncontrolledView(next);
|
|
205
|
+
onViewChange?.(next);
|
|
206
|
+
},
|
|
207
|
+
[onViewChange],
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
// A stale id (e.g. a contextual extra view that disappeared) degrades to the
|
|
211
|
+
// explorer rather than an empty sidebar.
|
|
212
|
+
const isKnownView =
|
|
213
|
+
(BUILT_IN_VIEWS as readonly string[]).includes(requestedView) ||
|
|
214
|
+
(extraViews?.some((v) => v.id === requestedView) ?? false);
|
|
215
|
+
const activeView = isKnownView ? requestedView : "files";
|
|
216
|
+
const activeExtraView = extraViews?.find((v) => v.id === activeView);
|
|
217
|
+
|
|
218
|
+
return (
|
|
219
|
+
<div className={cn("flex h-full min-h-0", className)}>
|
|
220
|
+
<ActivityRail
|
|
221
|
+
view={activeView}
|
|
222
|
+
onViewChange={handleViewChange}
|
|
223
|
+
extraViews={extraViews}
|
|
224
|
+
/>
|
|
225
|
+
<ResizableSplit
|
|
226
|
+
resizablePane="primary"
|
|
227
|
+
defaultSize={288}
|
|
228
|
+
minSize={200}
|
|
229
|
+
maxSize={560}
|
|
230
|
+
storageKey="stgm-workspace-sidebar-width"
|
|
231
|
+
ariaLabel="Resize sidebar"
|
|
232
|
+
// min-w-0: the split is a flex-row child of the surface; without it,
|
|
233
|
+
// the fixed-width sidebar sub-pane gives the whole surface a hard
|
|
234
|
+
// minimum width and content overflow escapes to the session panel.
|
|
235
|
+
className="min-h-0 min-w-0 flex-1"
|
|
236
|
+
primary={
|
|
237
|
+
activeExtraView ? (
|
|
238
|
+
<ExtraViewSidebar view={activeExtraView} />
|
|
239
|
+
) : activeView === "search" ? (
|
|
240
|
+
<SearchSidebar
|
|
241
|
+
entries={entries}
|
|
242
|
+
lister={lister}
|
|
243
|
+
searcher={searcher}
|
|
244
|
+
selectedFile={selectedFile}
|
|
245
|
+
onOpenFile={onOpenFile}
|
|
246
|
+
/>
|
|
247
|
+
) : (
|
|
248
|
+
<ExplorerSidebar
|
|
249
|
+
entries={entries}
|
|
250
|
+
lister={lister}
|
|
251
|
+
selectedFile={selectedFile}
|
|
252
|
+
onOpenFile={onOpenFile}
|
|
253
|
+
onActivateFile={onPinEditor}
|
|
254
|
+
onRemoveEntry={onRemoveEntry}
|
|
255
|
+
onAddLocalFolder={onAddLocalFolder}
|
|
256
|
+
/>
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
secondary={
|
|
260
|
+
<EditorArea
|
|
261
|
+
entries={entries}
|
|
262
|
+
reader={reader}
|
|
263
|
+
editors={editors}
|
|
264
|
+
selectedFile={selectedFile}
|
|
265
|
+
virtualDocuments={virtualDocuments}
|
|
266
|
+
change={change}
|
|
267
|
+
reveal={reveal}
|
|
268
|
+
onActivateEditor={onActivateEditor}
|
|
269
|
+
onPinEditor={onPinEditor}
|
|
270
|
+
onCloseEditor={onCloseEditor}
|
|
271
|
+
onCollapse={onCollapse}
|
|
272
|
+
/>
|
|
273
|
+
}
|
|
274
|
+
/>
|
|
275
|
+
</div>
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// ---------------------------------------------------------------------------
|
|
280
|
+
// Activity rail — built-in views + host-injected extras (VS Code activity bar)
|
|
281
|
+
// ---------------------------------------------------------------------------
|
|
282
|
+
|
|
283
|
+
interface RailItem {
|
|
284
|
+
readonly id: string;
|
|
285
|
+
readonly label: string;
|
|
286
|
+
readonly icon: ReactNode;
|
|
287
|
+
readonly badge?: number;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function ActivityRail({
|
|
291
|
+
view,
|
|
292
|
+
onViewChange,
|
|
293
|
+
extraViews,
|
|
294
|
+
}: {
|
|
295
|
+
readonly view: string;
|
|
296
|
+
readonly onViewChange: (next: string) => void;
|
|
297
|
+
readonly extraViews: readonly SurfaceRailView[] | undefined;
|
|
298
|
+
}) {
|
|
299
|
+
const items: readonly RailItem[] = [
|
|
300
|
+
{ id: "files", label: "Explorer", icon: <FilesIcon /> },
|
|
301
|
+
{ id: "search", label: "Search", icon: <SearchIcon /> },
|
|
302
|
+
...(extraViews ?? []),
|
|
303
|
+
];
|
|
304
|
+
|
|
305
|
+
// Roving selection: arrows move relative to the *focused* item's position,
|
|
306
|
+
// so the rail scales to any number of injected views.
|
|
307
|
+
const handleKeyDown = useCallback(
|
|
308
|
+
(e: KeyboardEvent<HTMLButtonElement>, index: number) => {
|
|
309
|
+
let nextIndex: number | null = null;
|
|
310
|
+
if (e.key === "ArrowDown" || e.key === "ArrowRight") {
|
|
311
|
+
nextIndex = Math.min(index + 1, items.length - 1);
|
|
312
|
+
} else if (e.key === "ArrowUp" || e.key === "ArrowLeft") {
|
|
313
|
+
nextIndex = Math.max(index - 1, 0);
|
|
314
|
+
}
|
|
315
|
+
if (nextIndex === null || nextIndex === index) return;
|
|
316
|
+
e.preventDefault();
|
|
317
|
+
onViewChange(items[nextIndex].id);
|
|
318
|
+
},
|
|
319
|
+
[items, onViewChange],
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
return (
|
|
323
|
+
<div
|
|
324
|
+
role="radiogroup"
|
|
325
|
+
aria-label="Workspace view"
|
|
326
|
+
aria-orientation="vertical"
|
|
327
|
+
className="flex w-11 shrink-0 flex-col items-center gap-1 border-r border-border bg-muted-faint py-2"
|
|
328
|
+
>
|
|
329
|
+
{items.map((item, index) => {
|
|
330
|
+
const isSelected = view === item.id;
|
|
331
|
+
const showBadge = item.badge != null && item.badge > 0;
|
|
332
|
+
return (
|
|
333
|
+
<button
|
|
334
|
+
key={item.id}
|
|
335
|
+
type="button"
|
|
336
|
+
role="radio"
|
|
337
|
+
aria-checked={isSelected}
|
|
338
|
+
aria-label={showBadge ? `${item.label} (${item.badge})` : item.label}
|
|
339
|
+
title={item.label}
|
|
340
|
+
tabIndex={isSelected ? 0 : -1}
|
|
341
|
+
onClick={() => onViewChange(item.id)}
|
|
342
|
+
onKeyDown={(e) => handleKeyDown(e, index)}
|
|
343
|
+
className={cn(
|
|
344
|
+
"relative flex h-9 w-9 items-center justify-center rounded-md transition-colors",
|
|
345
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
346
|
+
isSelected
|
|
347
|
+
? "bg-accent text-foreground"
|
|
348
|
+
: "text-muted-foreground hover:bg-accent-hover hover:text-foreground",
|
|
349
|
+
)}
|
|
350
|
+
>
|
|
351
|
+
{item.icon}
|
|
352
|
+
{showBadge && (
|
|
353
|
+
<span
|
|
354
|
+
aria-hidden="true"
|
|
355
|
+
className="absolute -right-0.5 -top-0.5 inline-flex min-w-[0.875rem] items-center justify-center rounded-full bg-primary px-1 py-px text-[9px] font-medium leading-none text-primary-foreground"
|
|
356
|
+
>
|
|
357
|
+
{item.badge}
|
|
358
|
+
</span>
|
|
359
|
+
)}
|
|
360
|
+
</button>
|
|
361
|
+
);
|
|
362
|
+
})}
|
|
363
|
+
</div>
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// ---------------------------------------------------------------------------
|
|
368
|
+
// Explorer sidebar — multi-root file tree
|
|
369
|
+
// ---------------------------------------------------------------------------
|
|
370
|
+
|
|
371
|
+
function ExplorerSidebar({
|
|
372
|
+
entries,
|
|
373
|
+
lister,
|
|
374
|
+
selectedFile,
|
|
375
|
+
onOpenFile,
|
|
376
|
+
onActivateFile,
|
|
377
|
+
onRemoveEntry,
|
|
378
|
+
onAddLocalFolder,
|
|
379
|
+
}: {
|
|
380
|
+
readonly entries: readonly WorkspaceEntry[];
|
|
381
|
+
readonly lister: WorkspaceFileLister | undefined;
|
|
382
|
+
readonly selectedFile: SelectedWorkspaceFile | null;
|
|
383
|
+
readonly onOpenFile: (entryId: string, path: string) => void;
|
|
384
|
+
readonly onActivateFile: (entryId: string, path: string) => void;
|
|
385
|
+
readonly onRemoveEntry?: (entryId: string) => void;
|
|
386
|
+
readonly onAddLocalFolder?: () => void;
|
|
387
|
+
}) {
|
|
388
|
+
return (
|
|
389
|
+
<div className="flex h-full min-h-0 flex-col border-r border-border">
|
|
390
|
+
<SidebarHeader title="Explorer" />
|
|
391
|
+
<div className="min-h-0 flex-1 overflow-y-auto py-1.5">
|
|
392
|
+
{!lister || entries.length === 0 ? (
|
|
393
|
+
<SidebarEmpty>No workspace attached.</SidebarEmpty>
|
|
394
|
+
) : (
|
|
395
|
+
<ExplorerTree
|
|
396
|
+
entries={entries}
|
|
397
|
+
lister={lister}
|
|
398
|
+
selectedFile={selectedFile}
|
|
399
|
+
onOpenFile={onOpenFile}
|
|
400
|
+
onActivateFile={onActivateFile}
|
|
401
|
+
onRemoveEntry={onRemoveEntry}
|
|
402
|
+
/>
|
|
403
|
+
)}
|
|
404
|
+
</div>
|
|
405
|
+
{onAddLocalFolder && (
|
|
406
|
+
<div className="shrink-0 border-t border-border-muted p-1.5">
|
|
407
|
+
<button
|
|
408
|
+
type="button"
|
|
409
|
+
onClick={onAddLocalFolder}
|
|
410
|
+
className="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-xs text-foreground transition-colors hover:bg-accent-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
411
|
+
>
|
|
412
|
+
<FolderPlusIcon />
|
|
413
|
+
<span className="flex-1 text-left">Add Folder</span>
|
|
414
|
+
</button>
|
|
415
|
+
</div>
|
|
416
|
+
)}
|
|
417
|
+
</div>
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// ---------------------------------------------------------------------------
|
|
422
|
+
// Search sidebar — reuses the workspace-wide search surface
|
|
423
|
+
// ---------------------------------------------------------------------------
|
|
424
|
+
|
|
425
|
+
type SearchMode = "name" | "text";
|
|
426
|
+
|
|
427
|
+
function SearchSidebar({
|
|
428
|
+
entries,
|
|
429
|
+
lister,
|
|
430
|
+
searcher,
|
|
431
|
+
selectedFile,
|
|
432
|
+
onOpenFile,
|
|
433
|
+
}: {
|
|
434
|
+
readonly entries: readonly WorkspaceEntry[];
|
|
435
|
+
readonly lister: WorkspaceFileLister | undefined;
|
|
436
|
+
readonly searcher: WorkspaceContentSearcher | undefined;
|
|
437
|
+
readonly selectedFile: SelectedWorkspaceFile | null;
|
|
438
|
+
readonly onOpenFile: (
|
|
439
|
+
entryId: string,
|
|
440
|
+
path: string,
|
|
441
|
+
options?: OpenFileOptions,
|
|
442
|
+
) => void;
|
|
443
|
+
}) {
|
|
444
|
+
// Filename search is the default: cached, instant, and always available.
|
|
445
|
+
// Content (text) search is opt-in and only offered when a searcher exists.
|
|
446
|
+
const [mode, setMode] = useState<SearchMode>("name");
|
|
447
|
+
|
|
448
|
+
return (
|
|
449
|
+
<div className="flex h-full min-h-0 flex-col border-r border-border">
|
|
450
|
+
<SidebarHeader title="Search" />
|
|
451
|
+
{searcher && <SearchModeToggle value={mode} onChange={setMode} />}
|
|
452
|
+
{searcher && mode === "text" ? (
|
|
453
|
+
<WorkspaceContentSearch
|
|
454
|
+
entries={entries}
|
|
455
|
+
searcher={searcher}
|
|
456
|
+
onOpenFile={onOpenFile}
|
|
457
|
+
selectedFile={selectedFile}
|
|
458
|
+
className="min-h-0 flex-1"
|
|
459
|
+
/>
|
|
460
|
+
) : (
|
|
461
|
+
<WorkspaceFileSearch
|
|
462
|
+
entries={entries}
|
|
463
|
+
lister={lister}
|
|
464
|
+
onOpenFile={onOpenFile}
|
|
465
|
+
selectedFile={selectedFile}
|
|
466
|
+
className="min-h-0 flex-1"
|
|
467
|
+
/>
|
|
468
|
+
)}
|
|
469
|
+
</div>
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* `Name | Text` search-mode selector, mirroring `FileViewer`'s `Diff | File`
|
|
475
|
+
* radiogroup (roving `tabindex`, arrow-key roving, `role="radio"`). Shown only
|
|
476
|
+
* when a content searcher is injected.
|
|
477
|
+
*/
|
|
478
|
+
function SearchModeToggle({
|
|
479
|
+
value,
|
|
480
|
+
onChange,
|
|
481
|
+
}: {
|
|
482
|
+
readonly value: SearchMode;
|
|
483
|
+
readonly onChange: (next: SearchMode) => void;
|
|
484
|
+
}) {
|
|
485
|
+
const options: readonly { readonly value: SearchMode; readonly label: string }[] = [
|
|
486
|
+
{ value: "name", label: "Name" },
|
|
487
|
+
{ value: "text", label: "Text" },
|
|
488
|
+
];
|
|
489
|
+
|
|
490
|
+
const handleKeyDown = useCallback(
|
|
491
|
+
(e: KeyboardEvent<HTMLButtonElement>) => {
|
|
492
|
+
if (e.key === "ArrowRight" || e.key === "ArrowLeft") {
|
|
493
|
+
e.preventDefault();
|
|
494
|
+
onChange(value === "name" ? "text" : "name");
|
|
495
|
+
}
|
|
496
|
+
},
|
|
497
|
+
[value, onChange],
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
return (
|
|
501
|
+
<div className="shrink-0 border-b border-border px-2 py-1.5">
|
|
502
|
+
<div
|
|
503
|
+
role="radiogroup"
|
|
504
|
+
aria-label="Search mode"
|
|
505
|
+
className="inline-flex rounded-md bg-muted p-0.5"
|
|
506
|
+
>
|
|
507
|
+
{options.map((option) => {
|
|
508
|
+
const isSelected = value === option.value;
|
|
509
|
+
return (
|
|
510
|
+
<button
|
|
511
|
+
key={option.value}
|
|
512
|
+
type="button"
|
|
513
|
+
role="radio"
|
|
514
|
+
aria-checked={isSelected}
|
|
515
|
+
tabIndex={isSelected ? 0 : -1}
|
|
516
|
+
onClick={() => onChange(option.value)}
|
|
517
|
+
onKeyDown={handleKeyDown}
|
|
518
|
+
className={cn(
|
|
519
|
+
"rounded px-2.5 py-0.5 text-[0.7rem] font-medium transition-colors",
|
|
520
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
521
|
+
isSelected
|
|
522
|
+
? "bg-background text-foreground shadow-sm"
|
|
523
|
+
: "text-muted-foreground hover:text-foreground",
|
|
524
|
+
)}
|
|
525
|
+
>
|
|
526
|
+
{option.label}
|
|
527
|
+
</button>
|
|
528
|
+
);
|
|
529
|
+
})}
|
|
530
|
+
</div>
|
|
531
|
+
</div>
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// ---------------------------------------------------------------------------
|
|
536
|
+
// Extra-view sidebar — host-injected facet content (Config, Changes, …)
|
|
537
|
+
// ---------------------------------------------------------------------------
|
|
538
|
+
|
|
539
|
+
function ExtraViewSidebar({ view }: { readonly view: SurfaceRailView }) {
|
|
540
|
+
return (
|
|
541
|
+
<div className="flex h-full min-h-0 flex-col border-r border-border">
|
|
542
|
+
<SidebarHeader title={view.label} />
|
|
543
|
+
{/* Same scroll + padding envelope the inspector gave these components,
|
|
544
|
+
so facet content drops in unchanged. */}
|
|
545
|
+
<div className="min-h-0 flex-1 overflow-y-auto px-3 py-3">
|
|
546
|
+
{view.content}
|
|
547
|
+
</div>
|
|
548
|
+
</div>
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// ---------------------------------------------------------------------------
|
|
553
|
+
// Editor area — collapse control + tab strip + read-only FileViewer
|
|
554
|
+
// ---------------------------------------------------------------------------
|
|
555
|
+
|
|
556
|
+
function EditorArea({
|
|
557
|
+
entries,
|
|
558
|
+
reader,
|
|
559
|
+
editors,
|
|
560
|
+
selectedFile,
|
|
561
|
+
virtualDocuments,
|
|
562
|
+
change,
|
|
563
|
+
reveal,
|
|
564
|
+
onActivateEditor,
|
|
565
|
+
onPinEditor,
|
|
566
|
+
onCloseEditor,
|
|
567
|
+
onCollapse,
|
|
568
|
+
}: {
|
|
569
|
+
readonly entries: readonly WorkspaceEntry[];
|
|
570
|
+
readonly reader: WorkspaceFileReader | undefined;
|
|
571
|
+
readonly editors: readonly OpenEditor[];
|
|
572
|
+
readonly selectedFile: SelectedWorkspaceFile | null;
|
|
573
|
+
readonly virtualDocuments?: readonly SurfaceVirtualDocument[];
|
|
574
|
+
readonly change?: FileChange;
|
|
575
|
+
readonly reveal?: RevealTarget;
|
|
576
|
+
readonly onActivateEditor: (entryId: string, path: string) => void;
|
|
577
|
+
readonly onPinEditor: (entryId: string, path: string) => void;
|
|
578
|
+
readonly onCloseEditor: (entryId: string, path: string) => void;
|
|
579
|
+
readonly onCollapse: () => void;
|
|
580
|
+
}) {
|
|
581
|
+
const viewerRef = useRef<FileViewerHandle>(null);
|
|
582
|
+
const activeKey = selectedFile
|
|
583
|
+
? editorKey(selectedFile.entryId, selectedFile.path)
|
|
584
|
+
: null;
|
|
585
|
+
// The active tab is a virtual document when its identity matches an injected
|
|
586
|
+
// one — the body renders the document's content instead of the file viewer.
|
|
587
|
+
const activeVirtualDocument =
|
|
588
|
+
activeKey !== null
|
|
589
|
+
? virtualDocuments?.find(
|
|
590
|
+
(d) => editorKey(d.entryId, d.path) === activeKey,
|
|
591
|
+
)
|
|
592
|
+
: undefined;
|
|
593
|
+
const activeEntryName = selectedFile
|
|
594
|
+
? entries.find((e) => e.id === selectedFile.entryId)?.name
|
|
595
|
+
: undefined;
|
|
596
|
+
|
|
597
|
+
return (
|
|
598
|
+
<div className="flex h-full min-h-0 flex-col">
|
|
599
|
+
{/* Collapse control + tab strip. The far right is kept clear (pr-24):
|
|
600
|
+
the session viewer floats its top-right controls (host
|
|
601
|
+
`headerActions` and the panel chip) over this region. */}
|
|
602
|
+
<div className="flex shrink-0 items-stretch border-b border-border pr-24">
|
|
603
|
+
<button
|
|
604
|
+
type="button"
|
|
605
|
+
onClick={onCollapse}
|
|
606
|
+
aria-label="Back to chat"
|
|
607
|
+
title="Back to chat"
|
|
608
|
+
className="flex shrink-0 items-center border-r border-border px-2 text-muted-foreground transition-colors hover:bg-accent-hover hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
|
|
609
|
+
>
|
|
610
|
+
<ChevronLeftIcon />
|
|
611
|
+
</button>
|
|
612
|
+
{editors.length > 0 && (
|
|
613
|
+
<EditorTabs
|
|
614
|
+
editors={editors}
|
|
615
|
+
activeKey={activeKey}
|
|
616
|
+
onActivate={onActivateEditor}
|
|
617
|
+
onPin={onPinEditor}
|
|
618
|
+
onClose={onCloseEditor}
|
|
619
|
+
className="min-w-0 flex-1 border-b-0"
|
|
620
|
+
/>
|
|
621
|
+
)}
|
|
622
|
+
</div>
|
|
623
|
+
{activeVirtualDocument ? (
|
|
624
|
+
// A virtual document owns its body wholesale: no breadcrumbs (there is
|
|
625
|
+
// no filesystem location) and no FileViewer (there is no reader-backed
|
|
626
|
+
// file). Keyed like files so switching documents resets cleanly.
|
|
627
|
+
// Vertical-only scrolling: a lone overflow-y-auto would compute
|
|
628
|
+
// overflow-x to auto too, giving the pane a horizontal scrollbar the
|
|
629
|
+
// moment any child refuses to shrink — documents must reflow instead.
|
|
630
|
+
<div
|
|
631
|
+
key={activeKey ?? undefined}
|
|
632
|
+
className="min-h-0 min-w-0 flex-1 overflow-y-auto overflow-x-hidden"
|
|
633
|
+
>
|
|
634
|
+
{activeVirtualDocument.content}
|
|
635
|
+
</div>
|
|
636
|
+
) : selectedFile ? (
|
|
637
|
+
<>
|
|
638
|
+
<Breadcrumbs
|
|
639
|
+
entryName={activeEntryName}
|
|
640
|
+
path={selectedFile.path}
|
|
641
|
+
onRefresh={reader ? () => viewerRef.current?.refresh() : undefined}
|
|
642
|
+
/>
|
|
643
|
+
{/* Per-file remount (key) resets scroll and view-mode state cleanly.
|
|
644
|
+
The tab strip + breadcrumbs own the file identity, close, and
|
|
645
|
+
refresh, so the viewer is chrome-less; Escape still collapses. */}
|
|
646
|
+
<FileViewer
|
|
647
|
+
ref={viewerRef}
|
|
648
|
+
key={activeKey ?? undefined}
|
|
649
|
+
selectedFile={selectedFile}
|
|
650
|
+
entries={entries}
|
|
651
|
+
reader={reader}
|
|
652
|
+
change={change}
|
|
653
|
+
reveal={reveal}
|
|
654
|
+
onClose={onCollapse}
|
|
655
|
+
showHeader={false}
|
|
656
|
+
className="min-h-0 flex-1"
|
|
657
|
+
/>
|
|
658
|
+
</>
|
|
659
|
+
) : (
|
|
660
|
+
<div className="flex flex-1 items-center justify-center p-8 text-center text-xs text-muted-foreground">
|
|
661
|
+
Select a file to view its contents.
|
|
662
|
+
</div>
|
|
663
|
+
)}
|
|
664
|
+
</div>
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Location breadcrumb for the active file: entry › folder › … › file, with an
|
|
670
|
+
* optional refresh. Display-only orientation (clickable navigation is a future
|
|
671
|
+
* enhancement); the refresh re-fetches the live file content.
|
|
672
|
+
*/
|
|
673
|
+
function Breadcrumbs({
|
|
674
|
+
entryName,
|
|
675
|
+
path,
|
|
676
|
+
onRefresh,
|
|
677
|
+
}: {
|
|
678
|
+
readonly entryName: string | undefined;
|
|
679
|
+
readonly path: string;
|
|
680
|
+
readonly onRefresh?: () => void;
|
|
681
|
+
}) {
|
|
682
|
+
const segments = path.split("/").filter(Boolean);
|
|
683
|
+
const crumbs = entryName ? [entryName, ...segments] : segments;
|
|
684
|
+
|
|
685
|
+
return (
|
|
686
|
+
<div className="flex shrink-0 items-center gap-1 border-b border-border-muted px-3 py-1 text-[0.65rem] text-muted-foreground">
|
|
687
|
+
<nav aria-label="File location" className="flex min-w-0 flex-1 items-center gap-1">
|
|
688
|
+
{crumbs.map((crumb, i) => {
|
|
689
|
+
const isLast = i === crumbs.length - 1;
|
|
690
|
+
return (
|
|
691
|
+
<span key={i} className="flex min-w-0 items-center gap-1">
|
|
692
|
+
{i > 0 && <span className="text-muted-foreground-subtle" aria-hidden="true">›</span>}
|
|
693
|
+
<span className={cn("truncate", isLast && "text-foreground")}>
|
|
694
|
+
{crumb}
|
|
695
|
+
</span>
|
|
696
|
+
</span>
|
|
697
|
+
);
|
|
698
|
+
})}
|
|
699
|
+
</nav>
|
|
700
|
+
{onRefresh && (
|
|
701
|
+
<button
|
|
702
|
+
type="button"
|
|
703
|
+
onClick={onRefresh}
|
|
704
|
+
aria-label="Reload file"
|
|
705
|
+
title="Reload file"
|
|
706
|
+
className="shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
707
|
+
>
|
|
708
|
+
<RefreshIcon />
|
|
709
|
+
</button>
|
|
710
|
+
)}
|
|
711
|
+
</div>
|
|
712
|
+
);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// ---------------------------------------------------------------------------
|
|
716
|
+
// Shared sidebar chrome
|
|
717
|
+
// ---------------------------------------------------------------------------
|
|
718
|
+
|
|
719
|
+
function SidebarHeader({ title }: { readonly title: string }) {
|
|
720
|
+
return (
|
|
721
|
+
<div className="shrink-0 border-b border-border px-3 py-2 text-[0.65rem] font-semibold uppercase tracking-wide text-muted-foreground">
|
|
722
|
+
{title}
|
|
723
|
+
</div>
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
function SidebarEmpty({ children }: { readonly children: React.ReactNode }) {
|
|
728
|
+
return (
|
|
729
|
+
<div className="px-2 py-6 text-center text-xs text-muted-foreground">
|
|
730
|
+
{children}
|
|
731
|
+
</div>
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// ---------------------------------------------------------------------------
|
|
736
|
+
// Inline SVG icons (SDK independence — no lucide dependency)
|
|
737
|
+
// ---------------------------------------------------------------------------
|
|
738
|
+
|
|
739
|
+
function FilesIcon() {
|
|
740
|
+
return (
|
|
741
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
742
|
+
<path d="M13 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
|
|
743
|
+
<path d="M13 3v5h5" />
|
|
744
|
+
</svg>
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
function SearchIcon() {
|
|
749
|
+
return (
|
|
750
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
751
|
+
<circle cx="11" cy="11" r="7" />
|
|
752
|
+
<path d="M21 21l-4.3-4.3" />
|
|
753
|
+
</svg>
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
function FolderPlusIcon() {
|
|
758
|
+
return (
|
|
759
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" className="shrink-0 text-muted-foreground" aria-hidden="true">
|
|
760
|
+
<path d="M1.5 3.5V11a1 1 0 001 1h9a1 1 0 001-1V5.5a1 1 0 00-1-1H7L5.5 3H2.5a1 1 0 00-1 .5z" />
|
|
761
|
+
<path d="M7 7v3M5.5 8.5h3" />
|
|
762
|
+
</svg>
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
function ChevronLeftIcon() {
|
|
767
|
+
return (
|
|
768
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
769
|
+
<path d="M10 3L5 8L10 13" />
|
|
770
|
+
</svg>
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
function RefreshIcon() {
|
|
775
|
+
return (
|
|
776
|
+
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
777
|
+
<path d="M1.5 6a4.5 4.5 0 017.794-3.073M10.5 6a4.5 4.5 0 01-7.794 3.073" />
|
|
778
|
+
<path d="M9.5 1v2.5H7M2.5 11V8.5H5" />
|
|
779
|
+
</svg>
|
|
780
|
+
);
|
|
781
|
+
}
|