@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect, afterEach } from "vitest";
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
2
|
import { render, screen, fireEvent, cleanup } from "@testing-library/react";
|
|
3
3
|
import { ArtifactContentRenderer } from "../ArtifactContentRenderer";
|
|
4
4
|
|
|
@@ -60,3 +60,82 @@ describe("ArtifactContentRenderer — markdown", () => {
|
|
|
60
60
|
).toBeGreaterThan(0);
|
|
61
61
|
});
|
|
62
62
|
});
|
|
63
|
+
|
|
64
|
+
describe("ArtifactContentRenderer — reveal (jump-to-line)", () => {
|
|
65
|
+
let scrollIntoView: ReturnType<typeof vi.fn>;
|
|
66
|
+
beforeEach(() => {
|
|
67
|
+
// happy-dom lacks a real scrollIntoView; the hook calls it optionally.
|
|
68
|
+
scrollIntoView = vi.fn();
|
|
69
|
+
Element.prototype.scrollIntoView =
|
|
70
|
+
scrollIntoView as unknown as typeof Element.prototype.scrollIntoView;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("renders addressable lines and highlights the target row for plain text", () => {
|
|
74
|
+
const { container } = render(
|
|
75
|
+
<ArtifactContentRenderer
|
|
76
|
+
content={"one\ntwo\nthree"}
|
|
77
|
+
fileName="notes.txt"
|
|
78
|
+
reveal={{ line: 2, nonce: 1 }}
|
|
79
|
+
/>,
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Every line is addressable; exactly the target row carries the highlight.
|
|
83
|
+
expect(container.querySelectorAll("[data-line]").length).toBe(3);
|
|
84
|
+
const target = container.querySelector('[data-line="2"]');
|
|
85
|
+
expect(target?.className).toContain("bg-primary-subtle");
|
|
86
|
+
expect(container.querySelectorAll(".bg-primary-subtle").length).toBe(1);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("does not highlight anything when the target line is out of range", () => {
|
|
90
|
+
const { container } = render(
|
|
91
|
+
<ArtifactContentRenderer
|
|
92
|
+
content={"one\ntwo"}
|
|
93
|
+
fileName="notes.txt"
|
|
94
|
+
reveal={{ line: 99, nonce: 1 }}
|
|
95
|
+
/>,
|
|
96
|
+
);
|
|
97
|
+
expect(container.querySelectorAll(".bg-primary-subtle").length).toBe(0);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("forces Markdown to its Source (line-faithful) view when revealing", () => {
|
|
101
|
+
const { container } = render(
|
|
102
|
+
<ArtifactContentRenderer
|
|
103
|
+
content={"# Heading\n\ntext"}
|
|
104
|
+
fileName="doc.md"
|
|
105
|
+
reveal={{ line: 1, nonce: 1 }}
|
|
106
|
+
/>,
|
|
107
|
+
);
|
|
108
|
+
// Source is line-numbered <pre>, not the rendered <h1>.
|
|
109
|
+
expect(container.querySelector("h1")).toBeNull();
|
|
110
|
+
expect(container.querySelector("pre")).not.toBeNull();
|
|
111
|
+
expect(container.querySelector('[data-line="1"]')).not.toBeNull();
|
|
112
|
+
// The Rendered/Source toggle is still offered.
|
|
113
|
+
expect(screen.getByRole("tab", { name: "Source" })).toBeTruthy();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("renders JSON raw (not reformatted) when revealing, so line numbers hold", () => {
|
|
117
|
+
// Minified single-line JSON: pretty-printing would expand it to many lines
|
|
118
|
+
// and shift line 1. Raw rendering keeps it one addressable row.
|
|
119
|
+
const { container } = render(
|
|
120
|
+
<ArtifactContentRenderer
|
|
121
|
+
content={'{"a":1,"b":2}'}
|
|
122
|
+
fileName="data.json"
|
|
123
|
+
reveal={{ line: 1, nonce: 1 }}
|
|
124
|
+
/>,
|
|
125
|
+
);
|
|
126
|
+
const rows = container.querySelectorAll("[data-line]");
|
|
127
|
+
expect(rows.length).toBe(1);
|
|
128
|
+
expect(rows[0].textContent).toContain('{"a":1,"b":2}');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("scrolls the target line into view", () => {
|
|
132
|
+
render(
|
|
133
|
+
<ArtifactContentRenderer
|
|
134
|
+
content={"one\ntwo\nthree"}
|
|
135
|
+
fileName="notes.txt"
|
|
136
|
+
reveal={{ line: 3, nonce: 1 }}
|
|
137
|
+
/>,
|
|
138
|
+
);
|
|
139
|
+
expect(scrollIntoView).toHaveBeenCalled();
|
|
140
|
+
});
|
|
141
|
+
});
|
|
@@ -26,8 +26,8 @@ function withStigmer(children: ReactNode) {
|
|
|
26
26
|
|
|
27
27
|
afterEach(cleanup);
|
|
28
28
|
|
|
29
|
-
describe("ArtifactPreviewContent — Build
|
|
30
|
-
it("renders a 'Build
|
|
29
|
+
describe("ArtifactPreviewContent — Build action", () => {
|
|
30
|
+
it("renders a 'Build' button only when onImplement is provided", () => {
|
|
31
31
|
const { rerender } = render(
|
|
32
32
|
withStigmer(
|
|
33
33
|
<ArtifactPreviewContent
|
|
@@ -39,7 +39,7 @@ describe("ArtifactPreviewContent — Build from plan action", () => {
|
|
|
39
39
|
/>,
|
|
40
40
|
),
|
|
41
41
|
);
|
|
42
|
-
expect(screen.queryByText("Build
|
|
42
|
+
expect(screen.queryByText("Build")).toBeNull();
|
|
43
43
|
|
|
44
44
|
rerender(
|
|
45
45
|
withStigmer(
|
|
@@ -53,10 +53,10 @@ describe("ArtifactPreviewContent — Build from plan action", () => {
|
|
|
53
53
|
/>,
|
|
54
54
|
),
|
|
55
55
|
);
|
|
56
|
-
expect(screen.getByText("Build
|
|
56
|
+
expect(screen.getByText("Build")).toBeTruthy();
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
-
it("calls onImplement then closes the modal when 'Build
|
|
59
|
+
it("calls onImplement then closes the modal when 'Build' is clicked", () => {
|
|
60
60
|
const calls: string[] = [];
|
|
61
61
|
const onImplement = vi.fn(() => calls.push("implement"));
|
|
62
62
|
const onClose = vi.fn(() => calls.push("close"));
|
|
@@ -74,7 +74,7 @@ describe("ArtifactPreviewContent — Build from plan action", () => {
|
|
|
74
74
|
),
|
|
75
75
|
);
|
|
76
76
|
|
|
77
|
-
fireEvent.click(screen.getByText("Build
|
|
77
|
+
fireEvent.click(screen.getByText("Build"));
|
|
78
78
|
|
|
79
79
|
expect(onImplement).toHaveBeenCalledTimes(1);
|
|
80
80
|
expect(onClose).toHaveBeenCalledTimes(1);
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileChangeProgressBar — the live "N files changed so far" strip for a running
|
|
3
|
+
* turn (DD-32). These tests cover its own responsibilities: emptiness, the
|
|
4
|
+
* summary count + aggregate stat, the expandable per-file list with its cap
|
|
5
|
+
* overflow, zero-count hiding, and that only the count is an aria-live region.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, afterEach } from "vitest";
|
|
9
|
+
import { render, screen, fireEvent, cleanup } from "@testing-library/react";
|
|
10
|
+
import { create } from "@bufbuild/protobuf";
|
|
11
|
+
import {
|
|
12
|
+
FileChangeProgressSchema,
|
|
13
|
+
FileChangeProgressEntrySchema,
|
|
14
|
+
type FileChangeProgress,
|
|
15
|
+
} from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/filereview_pb";
|
|
16
|
+
import { FileChangeKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
17
|
+
import { FileChangeProgressBar } from "../FileChangeProgressBar";
|
|
18
|
+
|
|
19
|
+
function entry(path: string, kind: FileChangeKind, added: number, removed: number) {
|
|
20
|
+
return create(FileChangeProgressEntrySchema, {
|
|
21
|
+
pathBefore: kind === FileChangeKind.ADD ? "" : path,
|
|
22
|
+
pathAfter: kind === FileChangeKind.DELETE ? "" : path,
|
|
23
|
+
kind,
|
|
24
|
+
linesAdded: added,
|
|
25
|
+
linesRemoved: removed,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function progress(overrides: Partial<FileChangeProgress> = {}): FileChangeProgress {
|
|
30
|
+
return create(FileChangeProgressSchema, {
|
|
31
|
+
changeSetId: "exec:0",
|
|
32
|
+
filesChanged: 2,
|
|
33
|
+
linesAdded: 7,
|
|
34
|
+
linesRemoved: 3,
|
|
35
|
+
entries: [
|
|
36
|
+
entry("src/a.ts", FileChangeKind.ADD, 5, 0),
|
|
37
|
+
entry("src/b.ts", FileChangeKind.MODIFY, 2, 3),
|
|
38
|
+
],
|
|
39
|
+
capturedAt: "2026-07-05T00:00:00Z",
|
|
40
|
+
...overrides,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
afterEach(() => cleanup());
|
|
45
|
+
|
|
46
|
+
describe("FileChangeProgressBar", () => {
|
|
47
|
+
it("renders nothing when progress is undefined", () => {
|
|
48
|
+
const { container } = render(<FileChangeProgressBar progress={undefined} />);
|
|
49
|
+
expect(container.firstChild).toBeNull();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("renders nothing when zero files have changed (revert-to-clean)", () => {
|
|
53
|
+
const { container } = render(
|
|
54
|
+
<FileChangeProgressBar
|
|
55
|
+
progress={progress({ filesChanged: 0, entries: [], linesAdded: 0, linesRemoved: 0 })}
|
|
56
|
+
/>,
|
|
57
|
+
);
|
|
58
|
+
expect(container.firstChild).toBeNull();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("shows the summary count and aggregate +N −M", () => {
|
|
62
|
+
render(<FileChangeProgressBar progress={progress()} />);
|
|
63
|
+
expect(screen.getByText(/2 files changing/)).toBeTruthy();
|
|
64
|
+
expect(screen.getByText("+7")).toBeTruthy();
|
|
65
|
+
expect(screen.getByText("-3")).toBeTruthy();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("uses the singular noun for a single file", () => {
|
|
69
|
+
render(
|
|
70
|
+
<FileChangeProgressBar
|
|
71
|
+
progress={progress({ filesChanged: 1, entries: [entry("only.ts", FileChangeKind.ADD, 1, 0)] })}
|
|
72
|
+
/>,
|
|
73
|
+
);
|
|
74
|
+
expect(screen.getByText(/1 file changing/)).toBeTruthy();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("puts only the count in an aria-live region, not the per-file list", () => {
|
|
78
|
+
render(<FileChangeProgressBar progress={progress()} />);
|
|
79
|
+
const live = screen.getByText(/2 files changing/);
|
|
80
|
+
expect(live.getAttribute("aria-live")).toBe("polite");
|
|
81
|
+
// The expandable list is not part of any live region.
|
|
82
|
+
fireEvent.click(screen.getByRole("button", { name: /2 files changing/ }));
|
|
83
|
+
const link = screen.getByText("a.ts");
|
|
84
|
+
expect(link.closest("[aria-live]")).toBeNull();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("expands to a per-file list on click and collapses again", () => {
|
|
88
|
+
render(<FileChangeProgressBar progress={progress()} />);
|
|
89
|
+
expect(screen.queryByText("a.ts")).toBeNull();
|
|
90
|
+
|
|
91
|
+
const toggle = screen.getByRole("button", { name: /2 files changing/ });
|
|
92
|
+
fireEvent.click(toggle);
|
|
93
|
+
expect(screen.getByText("a.ts")).toBeTruthy();
|
|
94
|
+
expect(screen.getByText("b.ts")).toBeTruthy();
|
|
95
|
+
expect(toggle.getAttribute("aria-expanded")).toBe("true");
|
|
96
|
+
|
|
97
|
+
fireEvent.click(toggle);
|
|
98
|
+
expect(screen.queryByText("a.ts")).toBeNull();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("shows an honest overflow line when the entry list is capped", () => {
|
|
102
|
+
// 5 files changed but only 2 entries carried → "… and 3 more".
|
|
103
|
+
render(<FileChangeProgressBar progress={progress({ filesChanged: 5 })} />);
|
|
104
|
+
fireEvent.click(screen.getByRole("button", { name: /5 files changing/ }));
|
|
105
|
+
expect(screen.getByText(/and 3 more/)).toBeTruthy();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("hides the per-file stat when both counts are zero (binary/secret)", () => {
|
|
109
|
+
render(
|
|
110
|
+
<FileChangeProgressBar
|
|
111
|
+
progress={progress({
|
|
112
|
+
filesChanged: 1,
|
|
113
|
+
linesAdded: 0,
|
|
114
|
+
linesRemoved: 0,
|
|
115
|
+
entries: [entry(".env", FileChangeKind.MODIFY, 0, 0)],
|
|
116
|
+
})}
|
|
117
|
+
/>,
|
|
118
|
+
);
|
|
119
|
+
fireEvent.click(screen.getByRole("button", { name: /1 file changing/ }));
|
|
120
|
+
// The secret path is present…
|
|
121
|
+
expect(screen.getByText(".env")).toBeTruthy();
|
|
122
|
+
// …but no +0 −0 stat is rendered anywhere.
|
|
123
|
+
expect(screen.queryByText("+0")).toBeNull();
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
WorkspaceEntrySchema,
|
|
6
6
|
WorkspaceSourceSchema,
|
|
7
7
|
LocalPathSourceSchema,
|
|
8
|
+
GitRepoSourceSchema,
|
|
8
9
|
} from "@stigmer/protos/ai/stigmer/agentic/session/v1/workspace_pb";
|
|
9
10
|
import type { WorkspaceEntry } from "@stigmer/protos/ai/stigmer/agentic/session/v1/workspace_pb";
|
|
10
11
|
import { FilePathLink } from "../FilePathLink";
|
|
@@ -89,4 +90,90 @@ describe("FilePathLink interaction", () => {
|
|
|
89
90
|
expect(onFilePathClick.mock.calls[0][0]).toBe("src/main.go");
|
|
90
91
|
expect(onFilePathClick.mock.calls[0][1].action).toBe("copy");
|
|
91
92
|
});
|
|
93
|
+
|
|
94
|
+
it("falls back to copy when a copy-action handler declines (returns false)", async () => {
|
|
95
|
+
const writeText = vi.fn().mockResolvedValue(undefined);
|
|
96
|
+
vi.stubGlobal("navigator", { clipboard: { writeText } });
|
|
97
|
+
const onFilePathClick = vi.fn().mockReturnValue(false);
|
|
98
|
+
render(
|
|
99
|
+
<FilePathContext.Provider value={{ workspaceEntries: [], onFilePathClick }}>
|
|
100
|
+
<FilePathLink path="src/main.go" />
|
|
101
|
+
</FilePathContext.Provider>,
|
|
102
|
+
);
|
|
103
|
+
fireEvent.click(screen.getByRole("button"));
|
|
104
|
+
expect(onFilePathClick).toHaveBeenCalledTimes(1);
|
|
105
|
+
expect(writeText).toHaveBeenCalledWith("src/main.go");
|
|
106
|
+
vi.unstubAllGlobals();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("suppresses the copy default when a copy-action handler returns void", () => {
|
|
110
|
+
const writeText = vi.fn().mockResolvedValue(undefined);
|
|
111
|
+
vi.stubGlobal("navigator", { clipboard: { writeText } });
|
|
112
|
+
const onFilePathClick = vi.fn(); // returns undefined -> handled
|
|
113
|
+
render(
|
|
114
|
+
<FilePathContext.Provider value={{ workspaceEntries: [], onFilePathClick }}>
|
|
115
|
+
<FilePathLink path="src/main.go" />
|
|
116
|
+
</FilePathContext.Provider>,
|
|
117
|
+
);
|
|
118
|
+
fireEvent.click(screen.getByRole("button"));
|
|
119
|
+
expect(onFilePathClick).toHaveBeenCalledTimes(1);
|
|
120
|
+
expect(writeText).not.toHaveBeenCalled();
|
|
121
|
+
vi.unstubAllGlobals();
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe("FilePathLink link-action with an injected handler", () => {
|
|
126
|
+
const gitEntries = [
|
|
127
|
+
create(WorkspaceEntrySchema, {
|
|
128
|
+
name: "acme/app",
|
|
129
|
+
source: create(WorkspaceSourceSchema, {
|
|
130
|
+
source: {
|
|
131
|
+
case: "gitRepo",
|
|
132
|
+
value: create(GitRepoSourceSchema, {
|
|
133
|
+
url: "https://github.com/acme/app.git",
|
|
134
|
+
branch: "main",
|
|
135
|
+
}),
|
|
136
|
+
},
|
|
137
|
+
}),
|
|
138
|
+
}),
|
|
139
|
+
];
|
|
140
|
+
|
|
141
|
+
it("renders a real <a href> even when a handler is present (native link semantics)", () => {
|
|
142
|
+
const onFilePathClick = vi.fn().mockReturnValue(true);
|
|
143
|
+
render(
|
|
144
|
+
<FilePathContext.Provider value={{ workspaceEntries: gitEntries, onFilePathClick }}>
|
|
145
|
+
<FilePathLink path="src/main.go" />
|
|
146
|
+
</FilePathContext.Provider>,
|
|
147
|
+
);
|
|
148
|
+
const anchor = screen.getByRole("link");
|
|
149
|
+
expect(anchor.getAttribute("href")).toBe(
|
|
150
|
+
"https://github.com/acme/app/blob/main/src/main.go",
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("prevents native navigation when the handler opens it in-app (returns true)", () => {
|
|
155
|
+
const onFilePathClick = vi.fn().mockReturnValue(true);
|
|
156
|
+
render(
|
|
157
|
+
<FilePathContext.Provider value={{ workspaceEntries: gitEntries, onFilePathClick }}>
|
|
158
|
+
<FilePathLink path="src/main.go" />
|
|
159
|
+
</FilePathContext.Provider>,
|
|
160
|
+
);
|
|
161
|
+
const evt = new MouseEvent("click", { bubbles: true, cancelable: true });
|
|
162
|
+
screen.getByRole("link").dispatchEvent(evt);
|
|
163
|
+
expect(onFilePathClick).toHaveBeenCalledTimes(1);
|
|
164
|
+
expect(evt.defaultPrevented).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("leaves native navigation intact when the handler declines (returns false)", () => {
|
|
168
|
+
const onFilePathClick = vi.fn().mockReturnValue(false);
|
|
169
|
+
render(
|
|
170
|
+
<FilePathContext.Provider value={{ workspaceEntries: gitEntries, onFilePathClick }}>
|
|
171
|
+
<FilePathLink path="src/main.go" />
|
|
172
|
+
</FilePathContext.Provider>,
|
|
173
|
+
);
|
|
174
|
+
const evt = new MouseEvent("click", { bubbles: true, cancelable: true });
|
|
175
|
+
screen.getByRole("link").dispatchEvent(evt);
|
|
176
|
+
expect(onFilePathClick).toHaveBeenCalledTimes(1);
|
|
177
|
+
expect(evt.defaultPrevented).toBe(false);
|
|
178
|
+
});
|
|
92
179
|
});
|
|
@@ -248,6 +248,16 @@ describe("FileReviewCard", () => {
|
|
|
248
248
|
});
|
|
249
249
|
|
|
250
250
|
describe("multi-file set (per-file controls)", () => {
|
|
251
|
+
it("starts a complete multi-file set collapsed in diff mode — auto-expansion is list-mode only", () => {
|
|
252
|
+
// Diff mode's expanded body is every full diff with NO height cap (the
|
|
253
|
+
// workflow file-review list); auto-expanding a multi-file set there
|
|
254
|
+
// would dump every diff open on mount. Only the compact list mode
|
|
255
|
+
// (showDiffs=false, the dock) starts multi-file sets expanded.
|
|
256
|
+
render(<FileReviewCard fileChangeSet={multiChangeSet()} onSubmit={noop} />);
|
|
257
|
+
expect(document.querySelector('[data-cursor-target="file-diff"]')).toBeNull();
|
|
258
|
+
expect(screen.getByRole("button", { name: "Review" })).toBeTruthy();
|
|
259
|
+
});
|
|
260
|
+
|
|
251
261
|
it("renders a Keep/Discard radio per file plus whole-set controls", () => {
|
|
252
262
|
render(<FileReviewCard fileChangeSet={multiChangeSet()} onSubmit={noop} />);
|
|
253
263
|
expandCard();
|
|
@@ -848,11 +858,12 @@ describe("FileReviewCard", () => {
|
|
|
848
858
|
// cases mirror the decision cases above without the diff DOM. The default
|
|
849
859
|
// (showDiffs unset) stays covered by every other suite in this file.
|
|
850
860
|
describe("list mode (showDiffs=false)", () => {
|
|
861
|
+
/** Open a still-collapsed card's file inventory (single complete file). */
|
|
851
862
|
function expandFiles() {
|
|
852
863
|
fireEvent.click(screen.getByRole("button", { name: "Files" }));
|
|
853
864
|
}
|
|
854
865
|
|
|
855
|
-
it("
|
|
866
|
+
it("starts a multi-file set expanded — the per-file controls are the honest decision surface", () => {
|
|
856
867
|
render(
|
|
857
868
|
<FileReviewCard
|
|
858
869
|
fileChangeSet={multiChangeSet()}
|
|
@@ -860,17 +871,65 @@ describe("FileReviewCard", () => {
|
|
|
860
871
|
showDiffs={false}
|
|
861
872
|
/>,
|
|
862
873
|
);
|
|
863
|
-
|
|
874
|
+
// No expander click: the list rows and per-file controls are immediately
|
|
875
|
+
// visible, with no diff DOM (the transcript's stamped rows own the diffs).
|
|
864
876
|
expect(document.querySelector('[data-cursor-target="file-diff"]')).toBeNull();
|
|
865
877
|
expect(
|
|
866
878
|
document.querySelectorAll('[data-cursor-target="file-review-list-row"]'),
|
|
867
879
|
).toHaveLength(2);
|
|
868
|
-
|
|
869
|
-
//
|
|
880
|
+
expect(screen.getByRole("button", { name: "Hide" })).toBeTruthy();
|
|
881
|
+
// Filename-first linked path (FilePathLink: copy fallback without a
|
|
882
|
+
// provider — an accessible button, never a bare span), full path on hover.
|
|
870
883
|
expect(screen.getByText("a.ts")).toBeTruthy();
|
|
871
884
|
expect(screen.getByText("b.ts")).toBeTruthy();
|
|
885
|
+
expect(screen.getByRole("button", { name: /Copy path: src\/a\.ts/ })).toBeTruthy();
|
|
872
886
|
expect(screen.getByTitle("src/a.ts")).toBeTruthy();
|
|
873
|
-
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
it("keeps a single complete file collapsed behind the 'Files' expander", () => {
|
|
890
|
+
render(
|
|
891
|
+
<FileReviewCard fileChangeSet={changeSet()} onSubmit={noop} showDiffs={false} />,
|
|
892
|
+
);
|
|
893
|
+
expect(
|
|
894
|
+
document.querySelector('[data-cursor-target="file-review-list-row"]'),
|
|
895
|
+
).toBeNull();
|
|
896
|
+
fireEvent.click(screen.getByRole("button", { name: "Files" }));
|
|
897
|
+
expect(
|
|
898
|
+
document.querySelector('[data-cursor-target="file-review-list-row"]'),
|
|
899
|
+
).toBeTruthy();
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
it("shows per-file +N −M from the capture-time counts, hiding the stat when no count exists", () => {
|
|
903
|
+
const counted = create(CapturedFileChangeSchema, {
|
|
904
|
+
id: "fc1",
|
|
905
|
+
pathBefore: "src/a.ts",
|
|
906
|
+
pathAfter: "src/a.ts",
|
|
907
|
+
kind: FileChangeKind.MODIFY,
|
|
908
|
+
captureClass: FileCaptureClass.GIT_TRACKED,
|
|
909
|
+
before: inline("old\n"),
|
|
910
|
+
after: inline("new\n"),
|
|
911
|
+
fileDigest: "d-fc1",
|
|
912
|
+
diffComplete: true,
|
|
913
|
+
linesAdded: 37,
|
|
914
|
+
linesRemoved: 2,
|
|
915
|
+
});
|
|
916
|
+
render(
|
|
917
|
+
<FileReviewCard
|
|
918
|
+
fileChangeSet={multiChangeSet({ fc1: counted })}
|
|
919
|
+
onSubmit={noop}
|
|
920
|
+
showDiffs={false}
|
|
921
|
+
/>,
|
|
922
|
+
);
|
|
923
|
+
const rows = document.querySelectorAll('[data-cursor-target="file-review-list-row"]');
|
|
924
|
+
// fc1 carries counts; fc2 (legacy fixture, zero counts) shows no stat —
|
|
925
|
+
// never a misleading "+0 -0". The bar also aggregates the set's counts,
|
|
926
|
+
// so exactly two stats render: the bar's and fc1's row.
|
|
927
|
+
const stats = document.querySelectorAll('[data-cursor-target="file-review-line-stats"]');
|
|
928
|
+
expect(rows).toHaveLength(2);
|
|
929
|
+
expect(stats).toHaveLength(2);
|
|
930
|
+
expect(stats[0].textContent).toBe("+37 -2");
|
|
931
|
+
expect(stats[1].textContent).toBe("+37 -2");
|
|
932
|
+
expect(screen.getAllByLabelText("37 added, 2 removed")).toHaveLength(2);
|
|
874
933
|
});
|
|
875
934
|
|
|
876
935
|
it("marks each file with its change-kind letter (A/M/D)", () => {
|
|
@@ -899,7 +958,7 @@ describe("FileReviewCard", () => {
|
|
|
899
958
|
showDiffs={false}
|
|
900
959
|
/>,
|
|
901
960
|
);
|
|
902
|
-
|
|
961
|
+
// A multi-file list-mode set starts expanded — the letters are visible.
|
|
903
962
|
expect(screen.getByLabelText("added").textContent).toBe("A");
|
|
904
963
|
expect(screen.getByLabelText("deleted").textContent).toBe("D");
|
|
905
964
|
});
|
|
@@ -937,7 +996,7 @@ describe("FileReviewCard", () => {
|
|
|
937
996
|
showDiffs={false}
|
|
938
997
|
/>,
|
|
939
998
|
);
|
|
940
|
-
|
|
999
|
+
// Starts expanded (multi-file list mode) — the row control is live.
|
|
941
1000
|
fireEvent.click(screen.getByRole("radio", { name: "Keep src/a.ts" }));
|
|
942
1001
|
expect(onSubmit).toHaveBeenCalledWith(FileDecisionAction.APPROVE, {
|
|
943
1002
|
scope: FileDecisionScope.FILE,
|
|
@@ -784,6 +784,50 @@ describe("MessageThread", () => {
|
|
|
784
784
|
});
|
|
785
785
|
});
|
|
786
786
|
|
|
787
|
+
describe("live plan collapse (streaming Plan turn)", () => {
|
|
788
|
+
function streamingPlanExecution() {
|
|
789
|
+
return makeExecution({
|
|
790
|
+
id: "exec-live",
|
|
791
|
+
phase: ExecutionPhase.EXECUTION_IN_PROGRESS,
|
|
792
|
+
interactionMode: InteractionMode.PLAN,
|
|
793
|
+
aiContent: "# Rollout Plan\n\n1. First step",
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
it("collapses the streaming plan behind a live card when onOpenPlan is wired", () => {
|
|
798
|
+
const onOpenPlan = vi.fn();
|
|
799
|
+
render(
|
|
800
|
+
<MessageThread
|
|
801
|
+
executions={[]}
|
|
802
|
+
activeStreamExecution={streamingPlanExecution()}
|
|
803
|
+
onOpenPlan={onOpenPlan}
|
|
804
|
+
/>,
|
|
805
|
+
);
|
|
806
|
+
|
|
807
|
+
const card = screen.getByRole("region", { name: "Plan being written" });
|
|
808
|
+
expect(card.textContent).toContain("Rollout Plan");
|
|
809
|
+
// The plan body lives in the panel's plan tab, not the thread.
|
|
810
|
+
expect(screen.queryByText(/First step/)).toBeNull();
|
|
811
|
+
|
|
812
|
+
fireEvent.click(screen.getByText("Open plan"));
|
|
813
|
+
expect(onOpenPlan).toHaveBeenCalledWith("exec-live");
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
it("keeps the plan streaming inline for hosts without a plan surface (DD-011)", () => {
|
|
817
|
+
render(
|
|
818
|
+
<MessageThread
|
|
819
|
+
executions={[]}
|
|
820
|
+
activeStreamExecution={streamingPlanExecution()}
|
|
821
|
+
/>,
|
|
822
|
+
);
|
|
823
|
+
|
|
824
|
+
expect(
|
|
825
|
+
screen.queryByRole("region", { name: "Plan being written" }),
|
|
826
|
+
).toBeNull();
|
|
827
|
+
expect(screen.getByText(/First step/)).toBeTruthy();
|
|
828
|
+
});
|
|
829
|
+
});
|
|
830
|
+
|
|
787
831
|
it("renders plan-completion card when last execution is completed Plan mode", () => {
|
|
788
832
|
const exec = makeExecution({
|
|
789
833
|
id: "exec-plan",
|
|
@@ -800,10 +844,67 @@ describe("MessageThread", () => {
|
|
|
800
844
|
/>,
|
|
801
845
|
);
|
|
802
846
|
|
|
803
|
-
const buildBtn = screen.getByRole("button", { name:
|
|
847
|
+
const buildBtn = screen.getByRole("button", { name: "Build" });
|
|
804
848
|
expect(buildBtn).toBeTruthy();
|
|
805
849
|
|
|
806
850
|
fireEvent.click(buildBtn);
|
|
807
851
|
expect(onBuildFromPlan).toHaveBeenCalledOnce();
|
|
808
852
|
});
|
|
853
|
+
|
|
854
|
+
describe("plan-turn identity", () => {
|
|
855
|
+
it("marks a Plan turn's prompt bubble with the Plan badge", () => {
|
|
856
|
+
const exec = makeExecution({
|
|
857
|
+
id: "exec-plan",
|
|
858
|
+
phase: ExecutionPhase.EXECUTION_COMPLETED,
|
|
859
|
+
interactionMode: InteractionMode.PLAN,
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
render(<MessageThread executions={[exec]} />);
|
|
863
|
+
|
|
864
|
+
expect(screen.getByRole("status", { name: "Plan mode" })).toBeTruthy();
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
it("shows no mode badge on Agent turns", () => {
|
|
868
|
+
const exec = makeExecution({
|
|
869
|
+
id: "exec-agent",
|
|
870
|
+
phase: ExecutionPhase.EXECUTION_COMPLETED,
|
|
871
|
+
interactionMode: InteractionMode.AGENT,
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
render(<MessageThread executions={[exec]} />);
|
|
875
|
+
|
|
876
|
+
expect(screen.queryByRole("status", { name: "Plan mode" })).toBeNull();
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
it("renders a completed Plan turn's plan as a document", () => {
|
|
880
|
+
const exec = makeExecution({
|
|
881
|
+
id: "exec-plan",
|
|
882
|
+
phase: ExecutionPhase.EXECUTION_COMPLETED,
|
|
883
|
+
interactionMode: InteractionMode.PLAN,
|
|
884
|
+
aiContent: "# Rollout Plan\n\n1. First step",
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
render(<MessageThread executions={[exec]} />);
|
|
888
|
+
|
|
889
|
+
const doc = screen.getByRole("article", { name: "Plan document" });
|
|
890
|
+
expect(doc.textContent).toContain("Rollout Plan");
|
|
891
|
+
expect(doc.textContent).toContain("First step");
|
|
892
|
+
});
|
|
893
|
+
|
|
894
|
+
it("renders a streaming Plan turn's text as an ordinary chat message", () => {
|
|
895
|
+
const exec = makeExecution({
|
|
896
|
+
id: "exec-live",
|
|
897
|
+
phase: ExecutionPhase.EXECUTION_IN_PROGRESS,
|
|
898
|
+
interactionMode: InteractionMode.PLAN,
|
|
899
|
+
aiContent: "Draft so far",
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
render(<MessageThread executions={[]} activeStreamExecution={exec} />);
|
|
903
|
+
|
|
904
|
+
expect(
|
|
905
|
+
screen.queryByRole("article", { name: "Plan document" }),
|
|
906
|
+
).toBeNull();
|
|
907
|
+
expect(screen.getByRole("article", { name: "AI response" })).toBeTruthy();
|
|
908
|
+
});
|
|
909
|
+
});
|
|
809
910
|
});
|