@stigmer/react 3.1.1 → 3.1.3
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 +25 -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/ArtifactPreviewModal.d.ts +5 -5
- package/execution/ArtifactPreviewModal.js +4 -4
- package/execution/ArtifactPreviewModal.js.map +1 -1
- package/execution/FileChangeProgressBar.d.ts +47 -0
- package/execution/FileChangeProgressBar.d.ts.map +1 -0
- package/execution/FileChangeProgressBar.js +49 -0
- package/execution/FileChangeProgressBar.js.map +1 -0
- package/execution/FileChangesView.d.ts.map +1 -1
- package/execution/FileChangesView.js +19 -4
- package/execution/FileChangesView.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/FileReviewAtoms.d.ts +27 -0
- package/execution/FileReviewAtoms.d.ts.map +1 -0
- package/execution/FileReviewAtoms.js +64 -0
- package/execution/FileReviewAtoms.js.map +1 -0
- package/execution/FileReviewCard.d.ts +2 -2
- package/execution/FileReviewCard.d.ts.map +1 -1
- package/execution/FileReviewCard.js +32 -62
- package/execution/FileReviewCard.js.map +1 -1
- package/execution/MessageEntry.d.ts +20 -0
- package/execution/MessageEntry.d.ts.map +1 -1
- package/execution/MessageEntry.js +19 -5
- package/execution/MessageEntry.js.map +1 -1
- package/execution/MessageThread.d.ts +75 -13
- package/execution/MessageThread.d.ts.map +1 -1
- package/execution/MessageThread.js +195 -27
- package/execution/MessageThread.js.map +1 -1
- package/execution/PlanArtifactCard.d.ts +36 -21
- package/execution/PlanArtifactCard.d.ts.map +1 -1
- package/execution/PlanArtifactCard.js +39 -25
- package/execution/PlanArtifactCard.js.map +1 -1
- package/execution/PlanCompletionCard.d.ts +4 -4
- package/execution/PlanCompletionCard.d.ts.map +1 -1
- package/execution/PlanCompletionCard.js +4 -4
- package/execution/PlanCompletionCard.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 +50 -0
- package/execution/PlanStreamingCard.d.ts.map +1 -0
- package/execution/PlanStreamingCard.js +40 -0
- package/execution/PlanStreamingCard.js.map +1 -0
- package/execution/index.d.ts +9 -1
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +4 -0
- package/execution/index.js.map +1 -1
- package/execution/use-build-from-plan-hotkey.d.ts +1 -1
- package/execution/use-build-from-plan-hotkey.js +1 -1
- package/execution/useArtifactCopy.d.ts +51 -0
- package/execution/useArtifactCopy.d.ts.map +1 -0
- package/execution/useArtifactCopy.js +75 -0
- package/execution/useArtifactCopy.js.map +1 -0
- package/execution/useArtifactDownload.d.ts.map +1 -1
- package/execution/useArtifactDownload.js +17 -5
- package/execution/useArtifactDownload.js.map +1 -1
- package/execution/useCreateAgentExecution.d.ts +12 -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 +43 -4
- package/library/detect-plan-artifact.d.ts.map +1 -1
- package/library/detect-plan-artifact.js +45 -5
- 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 +334 -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 +21 -0
- package/session/plan-document.d.ts.map +1 -0
- package/session/plan-document.js +28 -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 +14 -1
- package/session/useSessionConversation.d.ts.map +1 -1
- package/session/useSessionConversation.js +20 -2
- 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 +53 -10
- package/src/composer/__tests__/SessionComposer-contract.test.tsx +58 -4
- package/src/execution/ArtifactContentRenderer.tsx +101 -24
- package/src/execution/ArtifactPreviewModal.tsx +9 -9
- package/src/execution/FileChangeProgressBar.tsx +121 -0
- package/src/execution/FileChangesView.tsx +18 -4
- package/src/execution/FilePathContext.tsx +8 -1
- package/src/execution/FilePathLink.tsx +22 -6
- package/src/execution/FileReviewAtoms.tsx +89 -0
- package/src/execution/FileReviewCard.tsx +57 -90
- package/src/execution/MessageEntry.tsx +49 -1
- package/src/execution/MessageThread.tsx +308 -39
- package/src/execution/PlanArtifactCard.tsx +174 -64
- package/src/execution/PlanCompletionCard.tsx +5 -5
- package/src/execution/PlanDocumentMessage.tsx +96 -0
- package/src/execution/PlanStreamingCard.tsx +141 -0
- package/src/execution/__tests__/ArtifactContentRenderer.test.tsx +80 -1
- package/src/execution/__tests__/ArtifactPreviewModal.test.tsx +6 -6
- package/src/execution/__tests__/FileChangeProgressBar.test.tsx +125 -0
- package/src/execution/__tests__/FilePathLink.test.tsx +87 -0
- package/src/execution/__tests__/FileReviewCard.test.tsx +66 -7
- package/src/execution/__tests__/MessageThread.test.tsx +102 -1
- package/src/execution/__tests__/PlanArtifactCard.test.tsx +114 -26
- package/src/execution/__tests__/PlanCompletionCard.test.tsx +2 -2
- package/src/execution/__tests__/PlanDocumentMessage.test.tsx +55 -0
- package/src/execution/__tests__/PlanStreamingCard.test.tsx +56 -0
- package/src/execution/__tests__/buildThreadItems-plan-completion.test.ts +600 -22
- package/src/execution/__tests__/message-entry.test.tsx +17 -0
- package/src/execution/__tests__/useArtifactCopy.test.tsx +90 -0
- package/src/execution/__tests__/useArtifactDownload.test.tsx +2 -0
- package/src/execution/__tests__/useCreateAgentExecution.test.tsx +85 -0
- package/src/execution/index.ts +13 -1
- package/src/execution/use-build-from-plan-hotkey.ts +1 -1
- package/src/execution/useArtifactCopy.ts +109 -0
- package/src/execution/useArtifactDownload.ts +17 -5
- package/src/execution/useCreateAgentExecution.ts +18 -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 +69 -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 +56 -5
- 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 +69 -0
- package/src/library/__tests__/detect-streaming-plan.test.ts +234 -0
- package/src/library/detect-plan-artifact.ts +62 -5
- package/src/library/detect-streaming-plan.ts +108 -0
- package/src/library/index.ts +7 -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 +655 -96
- 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 +66 -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__/useSessionConversation.test.tsx +44 -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 +42 -8
- 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 +30 -0
- package/src/session/useOpenFileChange.ts +53 -0
- package/src/session/usePlanDraft.ts +109 -0
- package/src/session/useSessionConversation.ts +38 -3
- 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 +174 -0
- package/src/workspace/ExplorerTree.tsx +253 -0
- package/src/workspace/FileViewer.tsx +537 -0
- package/src/workspace/WorkspaceContentSearch.tsx +502 -0
- package/src/workspace/WorkspaceContentSearcher.ts +70 -0
- package/src/workspace/WorkspaceEditor.tsx +19 -16
- package/src/workspace/WorkspaceFileLister.ts +11 -0
- package/src/workspace/WorkspaceFileReader.ts +57 -0
- package/src/workspace/WorkspaceFileSearch.tsx +452 -0
- package/src/workspace/WorkspaceSurface.tsx +839 -0
- package/src/workspace/__tests__/EditorTabs.test.tsx +102 -0
- package/src/workspace/__tests__/ExplorerTree.test.tsx +204 -0
- package/src/workspace/__tests__/FileViewer.test.tsx +439 -0
- package/src/workspace/__tests__/WorkspaceContentSearch.test.tsx +229 -0
- package/src/workspace/__tests__/WorkspaceEditor-initialPanel.test.tsx +19 -0
- package/src/workspace/__tests__/WorkspaceFileSearch.test.tsx +227 -0
- package/src/workspace/__tests__/WorkspaceSurface.test.tsx +418 -0
- package/src/workspace/__tests__/a11y/harness.tsx +140 -0
- package/src/workspace/__tests__/a11y/mock-capabilities.ts +138 -0
- package/src/workspace/__tests__/a11y/workspace-editor.a11y.test.tsx +65 -0
- package/src/workspace/__tests__/a11y/workspace-explorer-search.a11y.test.tsx +112 -0
- package/src/workspace/__tests__/a11y/workspace-viewer-tabs.a11y.test.tsx +69 -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 +47 -0
- package/workspace/EditorTabs.d.ts.map +1 -0
- package/workspace/EditorTabs.js +78 -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 +49 -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 +193 -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 +216 -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/WorkspaceEditor.d.ts.map +1 -1
- package/workspace/WorkspaceEditor.js +8 -10
- package/workspace/WorkspaceEditor.js.map +1 -1
- 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 +175 -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 +220 -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
|
@@ -43,6 +43,14 @@ export function stripFrontmatter(content: string): string {
|
|
|
43
43
|
const ENCLOSING_MARKDOWN_FENCE_RE =
|
|
44
44
|
/^(`{3,})[ \t]*(?:markdown|md)[ \t]*\r?\n([\s\S]*?)\r?\n\1[ \t]*$/i;
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Matches content whose ENTIRE body is a single fenced code block with an
|
|
48
|
+
* EMPTY info string (no language tag). Only meaningful for surfaces that know
|
|
49
|
+
* the body is markdown by contract (a Plan-mode plan) — see
|
|
50
|
+
* {@link unwrapEnclosingMarkdownFence}'s `allowBareFence`.
|
|
51
|
+
*/
|
|
52
|
+
const ENCLOSING_BARE_FENCE_RE = /^(`{3,})[ \t]*\r?\n([\s\S]*?)\r?\n\1[ \t]*$/;
|
|
53
|
+
|
|
46
54
|
/**
|
|
47
55
|
* Unwraps a message the model wrapped entirely in a ```markdown / ```md fence.
|
|
48
56
|
*
|
|
@@ -53,6 +61,14 @@ const ENCLOSING_MARKDOWN_FENCE_RE =
|
|
|
53
61
|
* no-op for everything else (already-rich markdown, prose, or a reply that is
|
|
54
62
|
* legitimately a single code block).
|
|
55
63
|
*
|
|
64
|
+
* `allowBareFence` extends the unwrap to a whole-body fence with NO language
|
|
65
|
+
* tag. For an ordinary chat message a bare fence is ambiguous (it may be a
|
|
66
|
+
* legitimate single code block), so the default stays strict. A Plan-mode plan
|
|
67
|
+
* is different by contract: the turn's output IS a markdown document, so a
|
|
68
|
+
* reply that is one giant untagged fence is a wrapped plan, not code. Only
|
|
69
|
+
* plan-document surfaces pass `true`. A fence tagged with any other language
|
|
70
|
+
* (```python …) is never unwrapped in either mode.
|
|
71
|
+
*
|
|
56
72
|
* Render-time only: callers pass it the text right before handing it to the
|
|
57
73
|
* markdown renderer, so the transcript and the raw artifact stay faithful to
|
|
58
74
|
* what the agent produced — a single source of truth for the unwrap, with no
|
|
@@ -60,9 +76,47 @@ const ENCLOSING_MARKDOWN_FENCE_RE =
|
|
|
60
76
|
* arrived yet, so this no-ops and the live text renders as typed; it unwraps
|
|
61
77
|
* once the block closes.
|
|
62
78
|
*/
|
|
63
|
-
export function unwrapEnclosingMarkdownFence(
|
|
64
|
-
|
|
65
|
-
|
|
79
|
+
export function unwrapEnclosingMarkdownFence(
|
|
80
|
+
content: string,
|
|
81
|
+
allowBareFence = false,
|
|
82
|
+
): string {
|
|
83
|
+
const trimmed = content.trim();
|
|
84
|
+
const tagged = ENCLOSING_MARKDOWN_FENCE_RE.exec(trimmed);
|
|
85
|
+
if (tagged) return tagged[2];
|
|
86
|
+
if (allowBareFence) {
|
|
87
|
+
const bare = ENCLOSING_BARE_FENCE_RE.exec(trimmed);
|
|
88
|
+
if (bare) return bare[2];
|
|
89
|
+
}
|
|
90
|
+
return content;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Matches a document that OPENS with an `# H1` heading (optionally preceded by
|
|
95
|
+
* blank lines only). Group 1 is the heading text; the match spans through the
|
|
96
|
+
* heading's trailing newline(s) so `body` starts at the first content line.
|
|
97
|
+
*/
|
|
98
|
+
const LEADING_H1_RE = /^#[ \t]+(.+?)[ \t]*(?:\r?\n+|$)/;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Splits a markdown document into its leading `# H1` title and the remaining
|
|
102
|
+
* body, for surfaces that render the title in their own chrome (the plan
|
|
103
|
+
* document header) instead of inside the prose flow.
|
|
104
|
+
*
|
|
105
|
+
* Only a heading at the very start of the document counts as the title — an
|
|
106
|
+
* `# H1` further down is document content and stays in the body. When there is
|
|
107
|
+
* no leading H1, `title` is `null` and `body` is the input unchanged.
|
|
108
|
+
*
|
|
109
|
+
* Render-time only, like {@link unwrapEnclosingMarkdownFence}: the stored
|
|
110
|
+
* message/artifact keeps its heading; only the presentation moves it.
|
|
111
|
+
*/
|
|
112
|
+
export function extractLeadingH1(markdown: string): {
|
|
113
|
+
readonly title: string | null;
|
|
114
|
+
readonly body: string;
|
|
115
|
+
} {
|
|
116
|
+
const trimmed = markdown.trim();
|
|
117
|
+
const match = LEADING_H1_RE.exec(trimmed);
|
|
118
|
+
if (!match) return { title: null, body: markdown };
|
|
119
|
+
return { title: match[1], body: trimmed.slice(match[0].length) };
|
|
66
120
|
}
|
|
67
121
|
|
|
68
122
|
/**
|
|
@@ -77,7 +131,7 @@ export function unwrapEnclosingMarkdownFence(content: string): string {
|
|
|
77
131
|
export const MARKDOWN_COMPONENTS: Components = {
|
|
78
132
|
p({ children, ...props }: MdProps<"p">) {
|
|
79
133
|
return (
|
|
80
|
-
<p className="text-sm text-foreground mb-3 last:mb-0 leading-relaxed" {...props}>
|
|
134
|
+
<p className="text-sm text-foreground mb-3 last:mb-0 leading-relaxed break-words" {...props}>
|
|
81
135
|
{children}
|
|
82
136
|
</p>
|
|
83
137
|
);
|
|
@@ -87,7 +141,7 @@ export const MARKDOWN_COMPONENTS: Components = {
|
|
|
87
141
|
return (
|
|
88
142
|
<a
|
|
89
143
|
href={href}
|
|
90
|
-
className="text-primary underline underline-offset-2 hover:text-primary-muted"
|
|
144
|
+
className="text-primary underline underline-offset-2 hover:text-primary-muted break-words"
|
|
91
145
|
target="_blank"
|
|
92
146
|
rel="noopener noreferrer"
|
|
93
147
|
{...props}
|
|
@@ -99,7 +153,7 @@ export const MARKDOWN_COMPONENTS: Components = {
|
|
|
99
153
|
|
|
100
154
|
h1({ children, ...props }: MdProps<"h1">) {
|
|
101
155
|
return (
|
|
102
|
-
<h1 className="text-lg font-semibold text-foreground mt-5 mb-2 first:mt-0" {...props}>
|
|
156
|
+
<h1 className="text-lg font-semibold text-foreground mt-5 mb-2 first:mt-0 break-words" {...props}>
|
|
103
157
|
{children}
|
|
104
158
|
</h1>
|
|
105
159
|
);
|
|
@@ -107,7 +161,7 @@ export const MARKDOWN_COMPONENTS: Components = {
|
|
|
107
161
|
|
|
108
162
|
h2({ children, ...props }: MdProps<"h2">) {
|
|
109
163
|
return (
|
|
110
|
-
<h2 className="text-base font-semibold text-foreground mt-5 mb-2 first:mt-0" {...props}>
|
|
164
|
+
<h2 className="text-base font-semibold text-foreground mt-5 mb-2 first:mt-0 break-words" {...props}>
|
|
111
165
|
{children}
|
|
112
166
|
</h2>
|
|
113
167
|
);
|
|
@@ -115,7 +169,7 @@ export const MARKDOWN_COMPONENTS: Components = {
|
|
|
115
169
|
|
|
116
170
|
h3({ children, ...props }: MdProps<"h3">) {
|
|
117
171
|
return (
|
|
118
|
-
<h3 className="text-sm font-semibold text-foreground mt-4 mb-1.5 first:mt-0" {...props}>
|
|
172
|
+
<h3 className="text-sm font-semibold text-foreground mt-4 mb-1.5 first:mt-0 break-words" {...props}>
|
|
119
173
|
{children}
|
|
120
174
|
</h3>
|
|
121
175
|
);
|
|
@@ -123,7 +177,7 @@ export const MARKDOWN_COMPONENTS: Components = {
|
|
|
123
177
|
|
|
124
178
|
h4({ children, ...props }: MdProps<"h4">) {
|
|
125
179
|
return (
|
|
126
|
-
<h4 className="text-sm font-medium text-foreground mt-3 mb-1 first:mt-0" {...props}>
|
|
180
|
+
<h4 className="text-sm font-medium text-foreground mt-3 mb-1 first:mt-0 break-words" {...props}>
|
|
127
181
|
{children}
|
|
128
182
|
</h4>
|
|
129
183
|
);
|
|
@@ -147,7 +201,7 @@ export const MARKDOWN_COMPONENTS: Components = {
|
|
|
147
201
|
|
|
148
202
|
li({ children, ...props }: MdProps<"li">) {
|
|
149
203
|
return (
|
|
150
|
-
<li className="leading-relaxed" {...props}>
|
|
204
|
+
<li className="leading-relaxed break-words" {...props}>
|
|
151
205
|
{children}
|
|
152
206
|
</li>
|
|
153
207
|
);
|
|
@@ -195,7 +249,7 @@ export const MARKDOWN_COMPONENTS: Components = {
|
|
|
195
249
|
|
|
196
250
|
return (
|
|
197
251
|
<code
|
|
198
|
-
className="font-mono text-xs bg-muted px-1 py-0.5 rounded text-foreground"
|
|
252
|
+
className="font-mono text-xs bg-muted px-1 py-0.5 rounded text-foreground break-words"
|
|
199
253
|
{...props}
|
|
200
254
|
>
|
|
201
255
|
{children}
|
|
@@ -263,3 +317,54 @@ export const MARKDOWN_COMPONENTS: Components = {
|
|
|
263
317
|
);
|
|
264
318
|
},
|
|
265
319
|
};
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Document-grade typography for a Plan-mode plan: one step up the heading
|
|
323
|
+
* scale from the chat-tuned {@link MARKDOWN_COMPONENTS}, wider section
|
|
324
|
+
* spacing, and a hairline under `##` section headings for scannability. The
|
|
325
|
+
* plan is a reviewable document, not a chat bubble — its headings must carry
|
|
326
|
+
* the structure at a glance.
|
|
327
|
+
*
|
|
328
|
+
* Everything except the headings is inherited from `MARKDOWN_COMPONENTS`, so
|
|
329
|
+
* body text, code, tables, and links render identically across chat and plan
|
|
330
|
+
* surfaces. Used by `PlanDocumentMessage` (thread) — the same treatment any
|
|
331
|
+
* plan-document surface should share.
|
|
332
|
+
*/
|
|
333
|
+
export const PLAN_DOCUMENT_MARKDOWN_COMPONENTS: Components = {
|
|
334
|
+
...MARKDOWN_COMPONENTS,
|
|
335
|
+
|
|
336
|
+
h1({ children, ...props }: MdProps<"h1">) {
|
|
337
|
+
return (
|
|
338
|
+
<h1 className="text-lg font-semibold text-foreground mt-6 mb-3 first:mt-0 break-words" {...props}>
|
|
339
|
+
{children}
|
|
340
|
+
</h1>
|
|
341
|
+
);
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
h2({ children, ...props }: MdProps<"h2">) {
|
|
345
|
+
return (
|
|
346
|
+
<h2
|
|
347
|
+
className="text-base font-semibold text-foreground mt-6 mb-2.5 pb-1 border-b border-border-muted first:mt-0 break-words"
|
|
348
|
+
{...props}
|
|
349
|
+
>
|
|
350
|
+
{children}
|
|
351
|
+
</h2>
|
|
352
|
+
);
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
h3({ children, ...props }: MdProps<"h3">) {
|
|
356
|
+
return (
|
|
357
|
+
<h3 className="text-sm font-semibold text-foreground mt-5 mb-2 first:mt-0 break-words" {...props}>
|
|
358
|
+
{children}
|
|
359
|
+
</h3>
|
|
360
|
+
);
|
|
361
|
+
},
|
|
362
|
+
|
|
363
|
+
h4({ children, ...props }: MdProps<"h4">) {
|
|
364
|
+
return (
|
|
365
|
+
<h4 className="text-sm font-medium text-foreground mt-4 mb-1.5 first:mt-0 break-words" {...props}>
|
|
366
|
+
{children}
|
|
367
|
+
</h4>
|
|
368
|
+
);
|
|
369
|
+
},
|
|
370
|
+
};
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Utility for respecting the user's motion preference (prefers-reduced-motion)
|
|
3
|
-
* in programmatic viewport animations (fitView, setCenter, etc.)
|
|
4
|
-
* covered by the CSS-level reduced-motion rule in styles.css.
|
|
3
|
+
* in programmatic viewport animations (fitView, setCenter, scrollIntoView, etc.)
|
|
4
|
+
* that are NOT covered by the CSS-level reduced-motion rule in styles.css.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* bypass CSS media queries — they must be explicitly
|
|
6
|
+
* JS-driven animations (React Flow's duration parameter on fitView/setCenter,
|
|
7
|
+
* smooth `scrollIntoView`) bypass CSS media queries — they must be explicitly
|
|
8
|
+
* checked. Lives in `internal/` because it is cross-cutting: the workflow graph
|
|
9
|
+
* and the workspace file viewer both depend on it, and `internal/` may not
|
|
10
|
+
* depend on a feature domain.
|
|
8
11
|
*/
|
|
9
12
|
|
|
10
13
|
let cachedPreference: boolean | null = null;
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
+
import { WorkspaceEditorsStore, editorKey } from "../workspace-editors-store";
|
|
3
|
+
|
|
4
|
+
function paths(store: WorkspaceEditorsStore): string[] {
|
|
5
|
+
return store.getSnapshot().editors.map((e) => e.path);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let store: WorkspaceEditorsStore;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
store = new WorkspaceEditorsStore();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
describe("WorkspaceEditorsStore", () => {
|
|
14
|
+
it("starts empty", () => {
|
|
15
|
+
const snap = store.getSnapshot();
|
|
16
|
+
expect(snap.editors).toEqual([]);
|
|
17
|
+
expect(snap.activeKey).toBeNull();
|
|
18
|
+
expect(snap.activeFile).toBeNull();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("openPreview adds a preview tab and makes it active", () => {
|
|
22
|
+
store.openPreview("e1", "a.ts");
|
|
23
|
+
const snap = store.getSnapshot();
|
|
24
|
+
expect(snap.editors).toEqual([{ entryId: "e1", path: "a.ts", preview: true }]);
|
|
25
|
+
expect(snap.activeFile).toEqual({ entryId: "e1", path: "a.ts" });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("openPreview reuses the single preview slot for a new file", () => {
|
|
29
|
+
store.openPreview("e1", "a.ts");
|
|
30
|
+
store.openPreview("e1", "b.ts");
|
|
31
|
+
// b.ts replaced a.ts in place — still one tab, now b.ts.
|
|
32
|
+
expect(paths(store)).toEqual(["b.ts"]);
|
|
33
|
+
expect(store.getSnapshot().activeFile).toEqual({ entryId: "e1", path: "b.ts" });
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("openPreview on an already-open editor just focuses it (no duplicate)", () => {
|
|
37
|
+
store.openPinned("e1", "a.ts");
|
|
38
|
+
store.openPinned("e1", "b.ts");
|
|
39
|
+
store.openPreview("e1", "a.ts");
|
|
40
|
+
expect(paths(store)).toEqual(["a.ts", "b.ts"]);
|
|
41
|
+
expect(store.getSnapshot().activeFile).toEqual({ entryId: "e1", path: "a.ts" });
|
|
42
|
+
// a.ts stays pinned — focusing does not turn it back into a preview.
|
|
43
|
+
expect(store.getSnapshot().editors[0].preview).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("a pinned tab survives when a subsequent preview opens", () => {
|
|
47
|
+
store.openPinned("e1", "a.ts");
|
|
48
|
+
store.openPreview("e1", "b.ts");
|
|
49
|
+
store.openPreview("e1", "c.ts");
|
|
50
|
+
// a.ts pinned stays; the preview slot cycled b.ts -> c.ts.
|
|
51
|
+
expect(paths(store)).toEqual(["a.ts", "c.ts"]);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("openPinned promotes an existing preview tab to persistent", () => {
|
|
55
|
+
store.openPreview("e1", "a.ts");
|
|
56
|
+
expect(store.getSnapshot().editors[0].preview).toBe(true);
|
|
57
|
+
store.openPinned("e1", "a.ts");
|
|
58
|
+
expect(store.getSnapshot().editors[0].preview).toBe(false);
|
|
59
|
+
expect(paths(store)).toEqual(["a.ts"]);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("pin clears the preview flag", () => {
|
|
63
|
+
store.openPreview("e1", "a.ts");
|
|
64
|
+
store.pin("e1", "a.ts");
|
|
65
|
+
expect(store.getSnapshot().editors[0].preview).toBe(false);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("activate focuses an open tab and no-ops for an unopened one", () => {
|
|
69
|
+
store.openPinned("e1", "a.ts");
|
|
70
|
+
store.openPinned("e1", "b.ts");
|
|
71
|
+
store.activate("e1", "a.ts");
|
|
72
|
+
expect(store.getSnapshot().activeFile).toEqual({ entryId: "e1", path: "a.ts" });
|
|
73
|
+
store.activate("e1", "missing.ts");
|
|
74
|
+
expect(store.getSnapshot().activeFile).toEqual({ entryId: "e1", path: "a.ts" });
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("close removes a tab and activates the right neighbor", () => {
|
|
78
|
+
store.openPinned("e1", "a.ts");
|
|
79
|
+
store.openPinned("e1", "b.ts");
|
|
80
|
+
store.openPinned("e1", "c.ts");
|
|
81
|
+
store.activate("e1", "b.ts");
|
|
82
|
+
store.close("e1", "b.ts");
|
|
83
|
+
expect(paths(store)).toEqual(["a.ts", "c.ts"]);
|
|
84
|
+
// The tab that shifted into b's slot (c.ts) becomes active.
|
|
85
|
+
expect(store.getSnapshot().activeFile).toEqual({ entryId: "e1", path: "c.ts" });
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("close activates the left neighbor when the last tab is closed", () => {
|
|
89
|
+
store.openPinned("e1", "a.ts");
|
|
90
|
+
store.openPinned("e1", "b.ts");
|
|
91
|
+
store.activate("e1", "b.ts");
|
|
92
|
+
store.close("e1", "b.ts");
|
|
93
|
+
expect(store.getSnapshot().activeFile).toEqual({ entryId: "e1", path: "a.ts" });
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("closing the only tab empties the group", () => {
|
|
97
|
+
store.openPreview("e1", "a.ts");
|
|
98
|
+
store.close("e1", "a.ts");
|
|
99
|
+
expect(store.getSnapshot().editors).toEqual([]);
|
|
100
|
+
expect(store.getSnapshot().activeFile).toBeNull();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("closing an inactive tab keeps the active one", () => {
|
|
104
|
+
store.openPinned("e1", "a.ts");
|
|
105
|
+
store.openPinned("e1", "b.ts");
|
|
106
|
+
store.activate("e1", "b.ts");
|
|
107
|
+
store.close("e1", "a.ts");
|
|
108
|
+
expect(store.getSnapshot().activeFile).toEqual({ entryId: "e1", path: "b.ts" });
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("keys files by entry, so same path in two entries are distinct tabs", () => {
|
|
112
|
+
store.openPinned("e1", "a.ts");
|
|
113
|
+
store.openPinned("e2", "a.ts");
|
|
114
|
+
expect(store.getSnapshot().editors).toHaveLength(2);
|
|
115
|
+
expect(store.getSnapshot().activeFile).toEqual({ entryId: "e2", path: "a.ts" });
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("returns a stable snapshot ref between mutations", () => {
|
|
119
|
+
store.openPreview("e1", "a.ts");
|
|
120
|
+
const snapA = store.getSnapshot();
|
|
121
|
+
const snapB = store.getSnapshot();
|
|
122
|
+
expect(snapA).toBe(snapB);
|
|
123
|
+
store.openPreview("e1", "b.ts");
|
|
124
|
+
expect(store.getSnapshot()).not.toBe(snapA);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("notifies subscribers on mutation", () => {
|
|
128
|
+
let count = 0;
|
|
129
|
+
const unsub = store.subscribe(() => {
|
|
130
|
+
count++;
|
|
131
|
+
});
|
|
132
|
+
store.openPreview("e1", "a.ts");
|
|
133
|
+
expect(count).toBe(1);
|
|
134
|
+
unsub();
|
|
135
|
+
store.openPreview("e1", "b.ts");
|
|
136
|
+
expect(count).toBe(1);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("closeAll empties a populated group and is a no-op when empty", () => {
|
|
140
|
+
store.openPinned("e1", "a.ts");
|
|
141
|
+
let count = 0;
|
|
142
|
+
store.subscribe(() => {
|
|
143
|
+
count++;
|
|
144
|
+
});
|
|
145
|
+
store.closeAll();
|
|
146
|
+
expect(store.getSnapshot().editors).toEqual([]);
|
|
147
|
+
expect(count).toBe(1);
|
|
148
|
+
store.closeAll();
|
|
149
|
+
expect(count).toBe(1);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe("reveal (jump-to-line)", () => {
|
|
153
|
+
it("starts with no reveal, and an open without a line sets none", () => {
|
|
154
|
+
expect(store.getSnapshot().reveal).toBeNull();
|
|
155
|
+
store.openPreview("e1", "a.ts");
|
|
156
|
+
expect(store.getSnapshot().reveal).toBeNull();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("openPreview with a line sets a reveal targeting the active editor", () => {
|
|
160
|
+
store.openPreview("e1", "a.ts", { line: 42 });
|
|
161
|
+
const snap = store.getSnapshot();
|
|
162
|
+
expect(snap.reveal).toEqual({
|
|
163
|
+
key: editorKey("e1", "a.ts"),
|
|
164
|
+
line: 42,
|
|
165
|
+
nonce: expect.any(Number),
|
|
166
|
+
});
|
|
167
|
+
// The reveal always names the now-active editor.
|
|
168
|
+
expect(snap.reveal!.key).toBe(snap.activeKey);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("bumps the nonce on every open-with-line, even for the same file+line", () => {
|
|
172
|
+
store.openPreview("e1", "a.ts", { line: 10 });
|
|
173
|
+
const first = store.getSnapshot().reveal!.nonce;
|
|
174
|
+
// A second search hit in the already-open, already-active file must still
|
|
175
|
+
// re-scroll — so the nonce advances.
|
|
176
|
+
store.openPreview("e1", "a.ts", { line: 10 });
|
|
177
|
+
expect(store.getSnapshot().reveal!.nonce).toBeGreaterThan(first);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("clears the reveal when switching to another tab", () => {
|
|
181
|
+
store.openPinned("e1", "a.ts");
|
|
182
|
+
store.openPreview("e1", "b.ts", { line: 5 });
|
|
183
|
+
expect(store.getSnapshot().reveal).not.toBeNull();
|
|
184
|
+
store.activate("e1", "a.ts");
|
|
185
|
+
expect(store.getSnapshot().reveal).toBeNull();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("clears the reveal on close and closeAll", () => {
|
|
189
|
+
store.openPreview("e1", "a.ts", { line: 5 });
|
|
190
|
+
store.close("e1", "a.ts");
|
|
191
|
+
expect(store.getSnapshot().reveal).toBeNull();
|
|
192
|
+
|
|
193
|
+
store.openPreview("e1", "b.ts", { line: 3 });
|
|
194
|
+
store.closeAll();
|
|
195
|
+
expect(store.getSnapshot().reveal).toBeNull();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("preserves editors and activeFile refs on a reveal-only update", () => {
|
|
199
|
+
store.openPinned("e1", "a.ts");
|
|
200
|
+
const before = store.getSnapshot();
|
|
201
|
+
// Already open + active → only the reveal changes; the tab list and the
|
|
202
|
+
// active-file projection must keep their references (invariant #3).
|
|
203
|
+
store.openPreview("e1", "a.ts", { line: 9 });
|
|
204
|
+
const after = store.getSnapshot();
|
|
205
|
+
expect(after.editors).toBe(before.editors);
|
|
206
|
+
expect(after.activeFile).toBe(before.activeFile);
|
|
207
|
+
expect(after.reveal).toEqual({
|
|
208
|
+
key: editorKey("e1", "a.ts"),
|
|
209
|
+
line: 9,
|
|
210
|
+
nonce: expect.any(Number),
|
|
211
|
+
});
|
|
212
|
+
// Focusing-for-reveal must not turn a pinned tab back into a preview.
|
|
213
|
+
expect(after.editors[0].preview).toBe(false);
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
WorkspaceFileSelectionStore,
|
|
4
|
+
type SelectedWorkspaceFile,
|
|
5
|
+
} from "../workspace-file-selection-store";
|
|
6
|
+
|
|
7
|
+
function file(entryId: string, path: string): SelectedWorkspaceFile {
|
|
8
|
+
return { entryId, path };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe("WorkspaceFileSelectionStore", () => {
|
|
12
|
+
it("starts with null selection", () => {
|
|
13
|
+
const store = new WorkspaceFileSelectionStore();
|
|
14
|
+
expect(store.getSelection()).toBeNull();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("select sets the selection and notifies listeners", () => {
|
|
18
|
+
const store = new WorkspaceFileSelectionStore();
|
|
19
|
+
const listener = vi.fn();
|
|
20
|
+
store.subscribe(listener);
|
|
21
|
+
|
|
22
|
+
store.select(file("ws-1", "src/index.ts"));
|
|
23
|
+
expect(store.getSelection()).toEqual(file("ws-1", "src/index.ts"));
|
|
24
|
+
expect(listener).toHaveBeenCalledOnce();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("select with an equal file does not notify", () => {
|
|
28
|
+
const store = new WorkspaceFileSelectionStore();
|
|
29
|
+
store.select(file("ws-1", "src/index.ts"));
|
|
30
|
+
|
|
31
|
+
const listener = vi.fn();
|
|
32
|
+
store.subscribe(listener);
|
|
33
|
+
|
|
34
|
+
store.select(file("ws-1", "src/index.ts"));
|
|
35
|
+
expect(listener).not.toHaveBeenCalled();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("keeps a stable snapshot reference between mutations (getSnapshot safety)", () => {
|
|
39
|
+
const store = new WorkspaceFileSelectionStore();
|
|
40
|
+
store.select(file("ws-1", "a.ts"));
|
|
41
|
+
expect(store.getSelection()).toBe(store.getSelection());
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("select notifies when only the path differs within the same entry", () => {
|
|
45
|
+
const store = new WorkspaceFileSelectionStore();
|
|
46
|
+
store.select(file("ws-1", "a.ts"));
|
|
47
|
+
|
|
48
|
+
const listener = vi.fn();
|
|
49
|
+
store.subscribe(listener);
|
|
50
|
+
|
|
51
|
+
store.select(file("ws-1", "b.ts"));
|
|
52
|
+
expect(store.getSelection()).toEqual(file("ws-1", "b.ts"));
|
|
53
|
+
expect(listener).toHaveBeenCalledOnce();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("deselect clears the selection and notifies", () => {
|
|
57
|
+
const store = new WorkspaceFileSelectionStore();
|
|
58
|
+
store.select(file("ws-1", "a.ts"));
|
|
59
|
+
|
|
60
|
+
const listener = vi.fn();
|
|
61
|
+
store.subscribe(listener);
|
|
62
|
+
|
|
63
|
+
store.deselect();
|
|
64
|
+
expect(store.getSelection()).toBeNull();
|
|
65
|
+
expect(listener).toHaveBeenCalledOnce();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("deselect when already null does not notify", () => {
|
|
69
|
+
const store = new WorkspaceFileSelectionStore();
|
|
70
|
+
const listener = vi.fn();
|
|
71
|
+
store.subscribe(listener);
|
|
72
|
+
|
|
73
|
+
store.deselect();
|
|
74
|
+
expect(listener).not.toHaveBeenCalled();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("toggle selects when nothing is selected", () => {
|
|
78
|
+
const store = new WorkspaceFileSelectionStore();
|
|
79
|
+
store.toggle(file("ws-1", "a.ts"));
|
|
80
|
+
expect(store.getSelection()).toEqual(file("ws-1", "a.ts"));
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("toggle deselects when the same file is selected", () => {
|
|
84
|
+
const store = new WorkspaceFileSelectionStore();
|
|
85
|
+
store.select(file("ws-1", "a.ts"));
|
|
86
|
+
store.toggle(file("ws-1", "a.ts"));
|
|
87
|
+
expect(store.getSelection()).toBeNull();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("toggle switches to a different file", () => {
|
|
91
|
+
const store = new WorkspaceFileSelectionStore();
|
|
92
|
+
store.select(file("ws-1", "a.ts"));
|
|
93
|
+
store.toggle(file("ws-2", "b.ts"));
|
|
94
|
+
expect(store.getSelection()).toEqual(file("ws-2", "b.ts"));
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("unsubscribe removes the listener", () => {
|
|
98
|
+
const store = new WorkspaceFileSelectionStore();
|
|
99
|
+
const listener = vi.fn();
|
|
100
|
+
const unsub = store.subscribe(listener);
|
|
101
|
+
|
|
102
|
+
unsub();
|
|
103
|
+
store.select(file("ws-1", "a.ts"));
|
|
104
|
+
expect(listener).not.toHaveBeenCalled();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("supports multiple listeners", () => {
|
|
108
|
+
const store = new WorkspaceFileSelectionStore();
|
|
109
|
+
const a = vi.fn();
|
|
110
|
+
const b = vi.fn();
|
|
111
|
+
store.subscribe(a);
|
|
112
|
+
store.subscribe(b);
|
|
113
|
+
|
|
114
|
+
store.select(file("ws-1", "a.ts"));
|
|
115
|
+
expect(a).toHaveBeenCalledOnce();
|
|
116
|
+
expect(b).toHaveBeenCalledOnce();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
import { createContext, useContext, useRef, useSyncExternalStore } from "react";
|
|
4
4
|
import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
5
5
|
import { ConversationStore, type StreamState } from "./conversation-store.js";
|
|
6
|
+
import {
|
|
7
|
+
WorkspaceFileSelectionStore,
|
|
8
|
+
type SelectedWorkspaceFile,
|
|
9
|
+
} from "./workspace-file-selection-store.js";
|
|
10
|
+
import {
|
|
11
|
+
WorkspaceEditorsStore,
|
|
12
|
+
type WorkspaceEditorsSnapshot,
|
|
13
|
+
} from "./workspace-editors-store.js";
|
|
6
14
|
|
|
7
15
|
export { ConversationStore, type StreamState } from "./conversation-store.js";
|
|
8
16
|
export { structuralShare } from "./structural-share.js";
|
|
@@ -16,6 +24,22 @@ export {
|
|
|
16
24
|
export { SelectionStore } from "./selection-store.js";
|
|
17
25
|
export type { SelectedThreadItem } from "./selection-store.js";
|
|
18
26
|
|
|
27
|
+
export { WorkspaceFileSelectionStore } from "./workspace-file-selection-store.js";
|
|
28
|
+
export type { SelectedWorkspaceFile } from "./workspace-file-selection-store.js";
|
|
29
|
+
|
|
30
|
+
export {
|
|
31
|
+
WorkspaceEditorsStore,
|
|
32
|
+
editorKey,
|
|
33
|
+
virtualEntryId,
|
|
34
|
+
isVirtualEntryId,
|
|
35
|
+
} from "./workspace-editors-store.js";
|
|
36
|
+
export type {
|
|
37
|
+
OpenEditor,
|
|
38
|
+
OpenFileOptions,
|
|
39
|
+
EditorReveal,
|
|
40
|
+
WorkspaceEditorsSnapshot,
|
|
41
|
+
} from "./workspace-editors-store.js";
|
|
42
|
+
|
|
19
43
|
// ---------------------------------------------------------------------------
|
|
20
44
|
// Context
|
|
21
45
|
// ---------------------------------------------------------------------------
|
|
@@ -75,3 +99,73 @@ export function useStoreExecution(
|
|
|
75
99
|
export function useStoreStreamState(store: ConversationStore): StreamState {
|
|
76
100
|
return useSyncExternalStore(store.subscribe, store.getStreamState);
|
|
77
101
|
}
|
|
102
|
+
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
// Workspace file selection — the DD-07 shared "which file is open" store
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Internal context carrying the {@link WorkspaceFileSelectionStore} instance
|
|
109
|
+
* (stable ref) to both columns of the session viewer. Not exported from the
|
|
110
|
+
* public SDK barrel — consumed only within SDK components and `SessionViewer`.
|
|
111
|
+
*/
|
|
112
|
+
export const WorkspaceFileSelectionContext =
|
|
113
|
+
createContext<WorkspaceFileSelectionStore | null>(null);
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Access the workspace-file selection store from context.
|
|
117
|
+
* Throws if called outside a `WorkspaceFileSelectionContext.Provider`.
|
|
118
|
+
*/
|
|
119
|
+
export function useWorkspaceFileSelectionStore(): WorkspaceFileSelectionStore {
|
|
120
|
+
const store = useContext(WorkspaceFileSelectionContext);
|
|
121
|
+
if (!store) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
"useWorkspaceFileSelectionStore must be used within a WorkspaceFileSelectionContext.Provider",
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
return store;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Create or reuse a `WorkspaceFileSelectionStore` instance, preserved across
|
|
131
|
+
* re-renders via ref. `SessionViewer` calls this and provides the result
|
|
132
|
+
* through {@link WorkspaceFileSelectionContext} (DD-07).
|
|
133
|
+
*/
|
|
134
|
+
export function useWorkspaceFileSelectionStoreRef(): WorkspaceFileSelectionStore {
|
|
135
|
+
const ref = useRef<WorkspaceFileSelectionStore | null>(null);
|
|
136
|
+
if (!ref.current) {
|
|
137
|
+
ref.current = new WorkspaceFileSelectionStore();
|
|
138
|
+
}
|
|
139
|
+
return ref.current;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Subscribe to the currently-selected workspace file. */
|
|
143
|
+
export function useWorkspaceFileSelection(
|
|
144
|
+
store: WorkspaceFileSelectionStore,
|
|
145
|
+
): SelectedWorkspaceFile | null {
|
|
146
|
+
return useSyncExternalStore(store.subscribe, store.getSelection);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
// Workspace editors — the surface's open-editor group (Slice B)
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Create or reuse a `WorkspaceEditorsStore` instance, preserved across
|
|
155
|
+
* re-renders via ref. Owned by `SessionViewer` alongside the selection store;
|
|
156
|
+
* the surface subscribes to it for its tab group.
|
|
157
|
+
*/
|
|
158
|
+
export function useWorkspaceEditorsStoreRef(): WorkspaceEditorsStore {
|
|
159
|
+
const ref = useRef<WorkspaceEditorsStore | null>(null);
|
|
160
|
+
if (!ref.current) {
|
|
161
|
+
ref.current = new WorkspaceEditorsStore();
|
|
162
|
+
}
|
|
163
|
+
return ref.current;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Subscribe to the open-editor group snapshot. */
|
|
167
|
+
export function useWorkspaceEditors(
|
|
168
|
+
store: WorkspaceEditorsStore,
|
|
169
|
+
): WorkspaceEditorsSnapshot {
|
|
170
|
+
return useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
171
|
+
}
|