@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,129 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { useFetch } from "../internal/useFetch.js";
|
|
5
|
+
import type { WorkspaceEntry } from "./useWorkspaceEntries.js";
|
|
6
|
+
import type {
|
|
7
|
+
WorkspaceFileContent,
|
|
8
|
+
WorkspaceFileReader,
|
|
9
|
+
} from "./WorkspaceFileReader.js";
|
|
10
|
+
|
|
11
|
+
/** Options for {@link useWorkspaceFileContent}. */
|
|
12
|
+
export interface UseWorkspaceFileContentOptions {
|
|
13
|
+
/** The workspace entry that owns the file, or `null` when nothing is open. */
|
|
14
|
+
readonly entry: WorkspaceEntry | null;
|
|
15
|
+
/** Repo-relative (git) or root-relative (local) path, or `null` when nothing is open. */
|
|
16
|
+
readonly path: string | null;
|
|
17
|
+
/**
|
|
18
|
+
* Platform-injected content reader. `undefined` when the host app injects
|
|
19
|
+
* no reader at all (e.g. web with no GitHub token) — surfaced as
|
|
20
|
+
* {@link UseWorkspaceFileContentReturn.isUnsupported}, not an error.
|
|
21
|
+
*/
|
|
22
|
+
readonly reader: WorkspaceFileReader | undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Return value of {@link useWorkspaceFileContent}. */
|
|
26
|
+
export interface UseWorkspaceFileContentReturn {
|
|
27
|
+
/**
|
|
28
|
+
* The decoded file content (+ metadata), or `null` while the request is
|
|
29
|
+
* in-flight, skipped, failed, or the substrate is unsupported. A present
|
|
30
|
+
* object with `text === null` is a real file that is binary, too large, or
|
|
31
|
+
* undecodable — distinct from `isUnsupported`.
|
|
32
|
+
*/
|
|
33
|
+
readonly content: WorkspaceFileContent | null;
|
|
34
|
+
/** `true` only on the first load, before any content has arrived. */
|
|
35
|
+
readonly isLoading: boolean;
|
|
36
|
+
/** `true` while a background refetch is in flight and stale content is shown. */
|
|
37
|
+
readonly isRefetching: boolean;
|
|
38
|
+
/** Error from the last failed read (a reader throw), or `null` when healthy. */
|
|
39
|
+
readonly error: Error | null;
|
|
40
|
+
/**
|
|
41
|
+
* `true` when no reader can serve this file — either no reader was injected
|
|
42
|
+
* or the reader reported the entry's substrate as unsupported (git-on-desktop,
|
|
43
|
+
* local-on-web, missing token). This is the honest "not available here" state,
|
|
44
|
+
* never an error.
|
|
45
|
+
*/
|
|
46
|
+
readonly isUnsupported: boolean;
|
|
47
|
+
/** Imperatively re-read the current file. Stale content stays visible. */
|
|
48
|
+
readonly refetch: () => void;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Wrapping the resolved `WorkspaceFileContent | null` in an object lets
|
|
53
|
+
* `useFetch` distinguish "resolved to unsupported" (`content: null`) from its
|
|
54
|
+
* own `initialData` sentinel without the two colliding — the object reference
|
|
55
|
+
* is always present after a completed fetch.
|
|
56
|
+
*/
|
|
57
|
+
interface FileContentData {
|
|
58
|
+
readonly content: WorkspaceFileContent | null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const EMPTY_CONTENT: FileContentData = { content: null };
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Behavior hook that reads a single workspace file's content on demand.
|
|
65
|
+
*
|
|
66
|
+
* The byte-reading peer of {@link useWorkspaceFiles}
|
|
67
|
+
* (which lists the tree), built on the same {@link useFetch} engine as the
|
|
68
|
+
* content-fetch family ({@link useArtifactContent},
|
|
69
|
+
* `useToolOutputContent`, `useFileChangeContent`) so it inherits their
|
|
70
|
+
* stale-while-revalidate, cancellation, and `refetch` semantics for free.
|
|
71
|
+
*
|
|
72
|
+
* Deliberately passes **no** `cacheKey`: file bodies (up to
|
|
73
|
+
* {@link MAX_WORKSPACE_FILE_READ_BYTES})
|
|
74
|
+
* do not belong in the cross-mount metadata cache, which is sized for small,
|
|
75
|
+
* hot resources. Re-opening a file re-reads it — the correct trade for a
|
|
76
|
+
* read-only viewer.
|
|
77
|
+
*
|
|
78
|
+
* Maps the reader's two failure axes onto distinct states:
|
|
79
|
+
* - reader resolves `null` (unsupported substrate) -> {@link UseWorkspaceFileContentReturn.isUnsupported}
|
|
80
|
+
* - reader **throws** (404, network, unreadable) -> {@link UseWorkspaceFileContentReturn.error}
|
|
81
|
+
*
|
|
82
|
+
* Pass `null` for `entry`/`path` (or an `undefined` reader) to stay idle —
|
|
83
|
+
* the established `useFetch` convention.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```tsx
|
|
87
|
+
* const { content, isLoading, error, isUnsupported } = useWorkspaceFileContent({
|
|
88
|
+
* entry,
|
|
89
|
+
* path: "src/index.ts",
|
|
90
|
+
* reader: workspaceFileReader,
|
|
91
|
+
* });
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export function useWorkspaceFileContent({
|
|
95
|
+
entry,
|
|
96
|
+
path,
|
|
97
|
+
reader,
|
|
98
|
+
}: UseWorkspaceFileContentOptions): UseWorkspaceFileContentReturn {
|
|
99
|
+
// The fetch runs only when a reader, an entry, and a path are all present.
|
|
100
|
+
const enabled = !!(reader && entry && path);
|
|
101
|
+
|
|
102
|
+
const { data, isLoading, isRefetching, error, refetch } =
|
|
103
|
+
useFetch<FileContentData>(
|
|
104
|
+
enabled
|
|
105
|
+
? () => reader(entry, path).then((c) => ({ content: c }))
|
|
106
|
+
: null,
|
|
107
|
+
// Identity deps: a change to any of these is a different file to read.
|
|
108
|
+
[entry?.id ?? null, path ?? null, reader],
|
|
109
|
+
EMPTY_CONTENT,
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
// Unsupported = no reader at all, or a completed fetch that resolved to null
|
|
113
|
+
// (the reader's "this substrate isn't mine" signal). In-flight and error
|
|
114
|
+
// states are excluded so the viewer shows loading/error, not "unavailable".
|
|
115
|
+
const isUnsupported =
|
|
116
|
+
!reader || (enabled && !isLoading && !error && data.content === null);
|
|
117
|
+
|
|
118
|
+
return useMemo(
|
|
119
|
+
() => ({
|
|
120
|
+
content: data.content,
|
|
121
|
+
isLoading,
|
|
122
|
+
isRefetching,
|
|
123
|
+
error,
|
|
124
|
+
isUnsupported,
|
|
125
|
+
refetch,
|
|
126
|
+
}),
|
|
127
|
+
[data.content, isLoading, isRefetching, error, isUnsupported, refetch],
|
|
128
|
+
);
|
|
129
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { toError } from "../internal/toError.js";
|
|
5
|
+
import type { WorkspaceEntry } from "./useWorkspaceEntries.js";
|
|
6
|
+
import type { WorkspaceFileLister } from "./WorkspaceFileLister.js";
|
|
7
|
+
import { loadEntryFiles, type WorkspaceListing } from "./workspaceListingCache.js";
|
|
8
|
+
import { matchWorkspaceFiles, type WorkspaceFileMatch } from "./matchWorkspaceFiles.js";
|
|
9
|
+
|
|
10
|
+
/** Options for {@link useWorkspaceFileSearch}. */
|
|
11
|
+
export interface UseWorkspaceFileSearchOptions {
|
|
12
|
+
/** All workspace entries to search across. */
|
|
13
|
+
readonly entries: readonly WorkspaceEntry[];
|
|
14
|
+
/** Platform-injected file lister. `undefined` → nothing is searchable. */
|
|
15
|
+
readonly lister: WorkspaceFileLister | undefined;
|
|
16
|
+
/** Current search query. Empty/whitespace yields no matches (search shows a hint). */
|
|
17
|
+
readonly query: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Matches (and per-entry status) for one workspace entry. */
|
|
21
|
+
export interface WorkspaceFileSearchGroup {
|
|
22
|
+
/** The workspace entry these matches belong to. */
|
|
23
|
+
readonly entry: WorkspaceEntry;
|
|
24
|
+
/** Ranked matches within this entry, best-first. */
|
|
25
|
+
readonly matches: readonly WorkspaceFileMatch[];
|
|
26
|
+
/** `true` when this entry's listing was truncated (repository too large). */
|
|
27
|
+
readonly truncated: boolean;
|
|
28
|
+
/** Listing error for this entry, if any (isolated — other entries still resolve). */
|
|
29
|
+
readonly error: Error | null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Return value of {@link useWorkspaceFileSearch}. */
|
|
33
|
+
export interface UseWorkspaceFileSearchReturn {
|
|
34
|
+
/** Entries with something to show (matches, an error, or a truncation notice). */
|
|
35
|
+
readonly groups: readonly WorkspaceFileSearchGroup[];
|
|
36
|
+
/** Total matches across all groups (for a "showing N of M" affordance). */
|
|
37
|
+
readonly totalMatches: number;
|
|
38
|
+
/** `true` while any entry's listing is still loading. */
|
|
39
|
+
readonly isLoading: boolean;
|
|
40
|
+
/** `true` when no substrate can be searched (no lister, or every entry unsupported). */
|
|
41
|
+
readonly isUnsupported: boolean;
|
|
42
|
+
/** First per-entry error, for a top-level fallback message. `null` when none. */
|
|
43
|
+
readonly error: Error | null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Per-entry listing status held while the hook loads across entries. */
|
|
47
|
+
interface EntryListingState {
|
|
48
|
+
readonly status: "loading" | "ready" | "error" | "unsupported";
|
|
49
|
+
readonly listing?: WorkspaceListing;
|
|
50
|
+
readonly error?: Error;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const EMPTY_GROUPS: readonly WorkspaceFileSearchGroup[] = [];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Behavior hook powering workspace-wide filename/path search.
|
|
57
|
+
*
|
|
58
|
+
* Loads each entry's listing through the shared
|
|
59
|
+
* {@link loadEntryFiles} cache (warm from
|
|
60
|
+
* Files browsing → usually free), then ranks matches per entry with the pure
|
|
61
|
+
* {@link matchWorkspaceFiles}. Fetching is keyed by the set of entry ids, so a
|
|
62
|
+
* query change re-ranks the already-loaded listings without re-fetching. Errors
|
|
63
|
+
* are isolated per entry (one failing repo never blanks the rest), and a stale
|
|
64
|
+
* generation's late resolutions are ignored.
|
|
65
|
+
*
|
|
66
|
+
* Meant to be consumed by a component mounted only while Search is active
|
|
67
|
+
* (`WorkspaceFileSearch`), so the Files view incurs no search fetching.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```tsx
|
|
71
|
+
* const { groups, totalMatches, isLoading } = useWorkspaceFileSearch({
|
|
72
|
+
* entries: workspace.entries,
|
|
73
|
+
* lister: workspaceFileLister,
|
|
74
|
+
* query,
|
|
75
|
+
* });
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export function useWorkspaceFileSearch({
|
|
79
|
+
entries,
|
|
80
|
+
lister,
|
|
81
|
+
query,
|
|
82
|
+
}: UseWorkspaceFileSearchOptions): UseWorkspaceFileSearchReturn {
|
|
83
|
+
const [states, setStates] = useState<Record<string, EntryListingState>>({});
|
|
84
|
+
|
|
85
|
+
// Latest entries read inside the effect without widening its dependency to the
|
|
86
|
+
// (possibly per-render) array identity — the effect keys on the id set instead.
|
|
87
|
+
const entriesRef = useRef(entries);
|
|
88
|
+
entriesRef.current = entries;
|
|
89
|
+
const entriesKey = entries.map((entry) => entry.id).join("\u0000");
|
|
90
|
+
|
|
91
|
+
// Ignore resolutions from a superseded entry set (id set or lister changed).
|
|
92
|
+
const generationRef = useRef(0);
|
|
93
|
+
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
if (!lister) {
|
|
96
|
+
setStates({});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const currentEntries = entriesRef.current;
|
|
101
|
+
const generation = ++generationRef.current;
|
|
102
|
+
|
|
103
|
+
// Seed loading for not-yet-known entries; drop states for removed ones.
|
|
104
|
+
setStates((prev) => {
|
|
105
|
+
const next: Record<string, EntryListingState> = {};
|
|
106
|
+
for (const entry of currentEntries) {
|
|
107
|
+
next[entry.id] = prev[entry.id] ?? { status: "loading" };
|
|
108
|
+
}
|
|
109
|
+
return next;
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
for (const entry of currentEntries) {
|
|
113
|
+
loadEntryFiles(entry, lister)
|
|
114
|
+
.then((listing) => {
|
|
115
|
+
if (generationRef.current !== generation) return;
|
|
116
|
+
setStates((prev) => ({
|
|
117
|
+
...prev,
|
|
118
|
+
[entry.id]:
|
|
119
|
+
listing === null
|
|
120
|
+
? { status: "unsupported" }
|
|
121
|
+
: { status: "ready", listing },
|
|
122
|
+
}));
|
|
123
|
+
})
|
|
124
|
+
.catch((err) => {
|
|
125
|
+
if (generationRef.current !== generation) return;
|
|
126
|
+
setStates((prev) => ({
|
|
127
|
+
...prev,
|
|
128
|
+
[entry.id]: { status: "error", error: toError(err) },
|
|
129
|
+
}));
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}, [entriesKey, lister]);
|
|
133
|
+
|
|
134
|
+
return useMemo<UseWorkspaceFileSearchReturn>(() => {
|
|
135
|
+
if (!lister) {
|
|
136
|
+
return {
|
|
137
|
+
groups: EMPTY_GROUPS,
|
|
138
|
+
totalMatches: 0,
|
|
139
|
+
isLoading: false,
|
|
140
|
+
isUnsupported: true,
|
|
141
|
+
error: null,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const groups: WorkspaceFileSearchGroup[] = [];
|
|
146
|
+
let totalMatches = 0;
|
|
147
|
+
let isLoading = false;
|
|
148
|
+
let firstError: Error | null = null;
|
|
149
|
+
let unsupportedCount = 0;
|
|
150
|
+
|
|
151
|
+
for (const entry of entries) {
|
|
152
|
+
const state = states[entry.id];
|
|
153
|
+
|
|
154
|
+
if (!state || state.status === "loading") {
|
|
155
|
+
isLoading = true;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (state.status === "unsupported") {
|
|
159
|
+
unsupportedCount += 1;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const error = state.status === "error" ? state.error ?? null : null;
|
|
164
|
+
if (error && !firstError) firstError = error;
|
|
165
|
+
|
|
166
|
+
const truncated = state.listing?.truncated ?? false;
|
|
167
|
+
const matches = state.listing
|
|
168
|
+
? matchWorkspaceFiles(state.listing.files, query)
|
|
169
|
+
: [];
|
|
170
|
+
totalMatches += matches.length;
|
|
171
|
+
|
|
172
|
+
// A group is worth showing only when it carries matches, an error, or a
|
|
173
|
+
// truncation notice — otherwise it is silent.
|
|
174
|
+
if (matches.length > 0 || error || truncated) {
|
|
175
|
+
groups.push({ entry, matches, truncated, error });
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const isUnsupported =
|
|
180
|
+
entries.length > 0 && unsupportedCount === entries.length;
|
|
181
|
+
|
|
182
|
+
return { groups, totalMatches, isLoading, isUnsupported, error: firstError };
|
|
183
|
+
}, [entries, states, query, lister]);
|
|
184
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
-
import {
|
|
4
|
+
import type { TreeNode } from "../internal/file-tree/index.js";
|
|
5
5
|
import { toError } from "../internal/toError.js";
|
|
6
6
|
import type { WorkspaceEntry } from "./useWorkspaceEntries.js";
|
|
7
|
-
import type {
|
|
7
|
+
import type { WorkspaceFileLister } from "./WorkspaceFileLister.js";
|
|
8
|
+
import { loadEntryFiles, peekEntryListing } from "./workspaceListingCache.js";
|
|
8
9
|
|
|
9
10
|
/** Options for {@link useWorkspaceFiles}. */
|
|
10
11
|
export interface UseWorkspaceFilesOptions {
|
|
@@ -22,39 +23,34 @@ export interface UseWorkspaceFilesReturn {
|
|
|
22
23
|
readonly isLoading: boolean;
|
|
23
24
|
/** Error from the lister, if any. */
|
|
24
25
|
readonly error: Error | null;
|
|
26
|
+
/**
|
|
27
|
+
* `true` when the listing was truncated by the backend (repository too large).
|
|
28
|
+
* The advisory entry is excluded from `tree`; callers render an incomplete-results
|
|
29
|
+
* banner from this flag instead (DD-11).
|
|
30
|
+
*/
|
|
31
|
+
readonly truncated: boolean;
|
|
25
32
|
/** Re-fetch the file listing for the current entry (cache-bust). */
|
|
26
33
|
readonly refresh: () => void;
|
|
27
34
|
}
|
|
28
35
|
|
|
29
|
-
interface CacheEntry {
|
|
30
|
-
files: WorkspaceFileEntry[];
|
|
31
|
-
tree: TreeNode[];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
36
|
const EMPTY_TREE: readonly TreeNode[] = [];
|
|
35
37
|
|
|
36
|
-
/**
|
|
37
|
-
* Module-level cache shared across all component instances. This ensures
|
|
38
|
-
* that switching between tabs (e.g., Workspace tab unmount/remount) doesn't
|
|
39
|
-
* re-fetch file listings that were already loaded. Entries are keyed by
|
|
40
|
-
* the workspace entry's stable ID.
|
|
41
|
-
*/
|
|
42
|
-
const sharedCache = new Map<string, CacheEntry>();
|
|
43
|
-
|
|
44
38
|
/**
|
|
45
39
|
* Behavior hook that fetches and caches a file listing for a single
|
|
46
40
|
* workspace entry, converting it into a {@link TreeNode} hierarchy.
|
|
47
41
|
*
|
|
48
|
-
* - Calls the platform-injected `lister`
|
|
49
|
-
*
|
|
50
|
-
*
|
|
42
|
+
* - Calls the platform-injected `lister` (via the shared
|
|
43
|
+
* {@link loadEntryFiles} cache) when the
|
|
44
|
+
* entry changes.
|
|
45
|
+
* - Reads the shared listing cache so tab switches, re-expands, and the search
|
|
46
|
+
* surface are instant without re-fetching (one cache, keyed by `entry.id`).
|
|
51
47
|
* - Returns an empty tree and skips the call when `lister` is
|
|
52
48
|
* `undefined` (graceful degradation — DD-011 opt-in).
|
|
53
49
|
* - Memoizes the return value for referential stability (DD-010).
|
|
54
50
|
*
|
|
55
51
|
* @example
|
|
56
52
|
* ```tsx
|
|
57
|
-
* const { tree, isLoading, error, refresh } = useWorkspaceFiles({
|
|
53
|
+
* const { tree, isLoading, error, truncated, refresh } = useWorkspaceFiles({
|
|
58
54
|
* entry: selectedEntry,
|
|
59
55
|
* lister: workspaceFileLister,
|
|
60
56
|
* });
|
|
@@ -67,6 +63,7 @@ export function useWorkspaceFiles({
|
|
|
67
63
|
const [isLoading, setIsLoading] = useState(false);
|
|
68
64
|
const [error, setError] = useState<Error | null>(null);
|
|
69
65
|
const [tree, setTree] = useState<readonly TreeNode[]>(EMPTY_TREE);
|
|
66
|
+
const [truncated, setTruncated] = useState(false);
|
|
70
67
|
|
|
71
68
|
const fetchIdRef = useRef(0);
|
|
72
69
|
|
|
@@ -75,9 +72,10 @@ export function useWorkspaceFiles({
|
|
|
75
72
|
if (!lister) return;
|
|
76
73
|
|
|
77
74
|
if (!bustCache) {
|
|
78
|
-
const cached =
|
|
75
|
+
const cached = peekEntryListing(target.id);
|
|
79
76
|
if (cached) {
|
|
80
77
|
setTree(cached.tree);
|
|
78
|
+
setTruncated(cached.truncated);
|
|
81
79
|
setError(null);
|
|
82
80
|
setIsLoading(false);
|
|
83
81
|
return;
|
|
@@ -89,24 +87,25 @@ export function useWorkspaceFiles({
|
|
|
89
87
|
setError(null);
|
|
90
88
|
|
|
91
89
|
try {
|
|
92
|
-
const
|
|
90
|
+
const listing = await loadEntryFiles(target, lister, { bustCache });
|
|
93
91
|
|
|
94
92
|
if (fetchIdRef.current !== id) return;
|
|
95
93
|
|
|
96
|
-
if (
|
|
94
|
+
if (listing === null) {
|
|
97
95
|
setTree(EMPTY_TREE);
|
|
96
|
+
setTruncated(false);
|
|
98
97
|
setIsLoading(false);
|
|
99
98
|
return;
|
|
100
99
|
}
|
|
101
100
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
setTree(built);
|
|
101
|
+
setTree(listing.tree);
|
|
102
|
+
setTruncated(listing.truncated);
|
|
105
103
|
setIsLoading(false);
|
|
106
104
|
} catch (err) {
|
|
107
105
|
if (fetchIdRef.current !== id) return;
|
|
108
106
|
setError(toError(err));
|
|
109
107
|
setTree(EMPTY_TREE);
|
|
108
|
+
setTruncated(false);
|
|
110
109
|
setIsLoading(false);
|
|
111
110
|
}
|
|
112
111
|
},
|
|
@@ -116,6 +115,7 @@ export function useWorkspaceFiles({
|
|
|
116
115
|
useEffect(() => {
|
|
117
116
|
if (!entry || !lister) {
|
|
118
117
|
setTree(EMPTY_TREE);
|
|
118
|
+
setTruncated(false);
|
|
119
119
|
setIsLoading(false);
|
|
120
120
|
setError(null);
|
|
121
121
|
return;
|
|
@@ -130,7 +130,7 @@ export function useWorkspaceFiles({
|
|
|
130
130
|
}, [entry, lister, fetchFiles]);
|
|
131
131
|
|
|
132
132
|
return useMemo(
|
|
133
|
-
() => ({ tree, isLoading, error, refresh }),
|
|
134
|
-
[tree, isLoading, error, refresh],
|
|
133
|
+
() => ({ tree, isLoading, error, truncated, refresh }),
|
|
134
|
+
[tree, isLoading, error, truncated, refresh],
|
|
135
135
|
);
|
|
136
136
|
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// Single source of truth for a workspace entry's file listing.
|
|
2
|
+
//
|
|
3
|
+
// Both surfaces that need a listing read through here: the Files accordion
|
|
4
|
+
// (`useWorkspaceFiles`, one entry) and workspace search (`useWorkspaceFileSearch`,
|
|
5
|
+
// many entries). Keeping one module-level cache — keyed by the stable-within-page
|
|
6
|
+
// `entry.id` — guarantees the two never double-fetch or drift, and lets one fetch
|
|
7
|
+
// produce every shape a consumer needs (flat files for search, a tree for the
|
|
8
|
+
// accordion, and the truncation flag for the banner).
|
|
9
|
+
|
|
10
|
+
import { buildFileTree, type TreeNode } from "../internal/file-tree/index.js";
|
|
11
|
+
import type { WorkspaceEntry } from "./useWorkspaceEntries.js";
|
|
12
|
+
import type {
|
|
13
|
+
WorkspaceFileEntry,
|
|
14
|
+
WorkspaceFileLister,
|
|
15
|
+
} from "./WorkspaceFileLister.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A processed listing for one workspace entry.
|
|
19
|
+
*
|
|
20
|
+
* Advisory `notice` entries (e.g. GitHub's "tree truncated" marker) are removed
|
|
21
|
+
* from {@link WorkspaceListing.files} and never enter {@link WorkspaceListing.tree};
|
|
22
|
+
* their presence is collapsed into {@link WorkspaceListing.truncated} so both the
|
|
23
|
+
* accordion and search render one honest "results may be incomplete" banner
|
|
24
|
+
* instead of a fake, clickable row (DD-11).
|
|
25
|
+
*/
|
|
26
|
+
export interface WorkspaceListing {
|
|
27
|
+
/** Openable entries (files and directories); advisory notices removed. */
|
|
28
|
+
readonly files: readonly WorkspaceFileEntry[];
|
|
29
|
+
/** Hierarchy of the openable files (directories excluded), ready for `FileTreeNode`. */
|
|
30
|
+
readonly tree: readonly TreeNode[];
|
|
31
|
+
/** `true` when the lister signalled the listing was incomplete (too many files). */
|
|
32
|
+
readonly truncated: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Options for {@link loadEntryFiles}. */
|
|
36
|
+
export interface LoadEntryFilesOptions {
|
|
37
|
+
/** Skip the cache and re-call the lister (the accordion's Refresh action). */
|
|
38
|
+
readonly bustCache?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const sharedCache = new Map<string, WorkspaceListing>();
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Returns a cached {@link WorkspaceListing} for an entry synchronously, or
|
|
45
|
+
* `undefined` when nothing is cached. Lets a consumer render a warm listing
|
|
46
|
+
* instantly (no loading flash) before deciding whether to fetch.
|
|
47
|
+
*/
|
|
48
|
+
export function peekEntryListing(entryId: string): WorkspaceListing | undefined {
|
|
49
|
+
return sharedCache.get(entryId);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Loads and caches the processed listing for a single workspace entry.
|
|
54
|
+
*
|
|
55
|
+
* Returns the cached listing when present (unless `bustCache`), otherwise calls
|
|
56
|
+
* the platform-injected `lister`, processes the raw entries once, and caches the
|
|
57
|
+
* result. Returns `null` when the lister returns `null` (substrate unsupported
|
|
58
|
+
* for this entry) — the honest "unavailable here" signal, not cached.
|
|
59
|
+
*/
|
|
60
|
+
export async function loadEntryFiles(
|
|
61
|
+
entry: WorkspaceEntry,
|
|
62
|
+
lister: WorkspaceFileLister,
|
|
63
|
+
options: LoadEntryFilesOptions = {},
|
|
64
|
+
): Promise<WorkspaceListing | null> {
|
|
65
|
+
if (!options.bustCache) {
|
|
66
|
+
const cached = sharedCache.get(entry.id);
|
|
67
|
+
if (cached) return cached;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const raw = await lister(entry);
|
|
71
|
+
if (raw === null) return null;
|
|
72
|
+
|
|
73
|
+
const listing = buildListing(raw);
|
|
74
|
+
sharedCache.set(entry.id, listing);
|
|
75
|
+
return listing;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Processes a raw lister result into a {@link WorkspaceListing}. */
|
|
79
|
+
function buildListing(raw: readonly WorkspaceFileEntry[]): WorkspaceListing {
|
|
80
|
+
const truncated = raw.some((entry) => entry.notice === true);
|
|
81
|
+
const files = raw.filter((entry) => !entry.notice);
|
|
82
|
+
const tree = buildFileTree(files.filter((entry) => !entry.isDirectory));
|
|
83
|
+
return { files, tree, truncated };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Clears the shared cache. Test-only seam for deterministic isolation.
|
|
88
|
+
*
|
|
89
|
+
* @internal
|
|
90
|
+
*/
|
|
91
|
+
export function __clearWorkspaceListingCache(): void {
|
|
92
|
+
sharedCache.clear();
|
|
93
|
+
}
|