@stigmer/react 3.1.1 → 3.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/composer/SessionComposer.d.ts +24 -1
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +19 -8
- package/composer/SessionComposer.js.map +1 -1
- package/execution/ArtifactContentRenderer.d.ts +11 -1
- package/execution/ArtifactContentRenderer.d.ts.map +1 -1
- package/execution/ArtifactContentRenderer.js +39 -15
- package/execution/ArtifactContentRenderer.js.map +1 -1
- package/execution/FilePathContext.d.ts +8 -1
- package/execution/FilePathContext.d.ts.map +1 -1
- package/execution/FilePathContext.js.map +1 -1
- package/execution/FilePathLink.d.ts.map +1 -1
- package/execution/FilePathLink.js +21 -6
- package/execution/FilePathLink.js.map +1 -1
- package/execution/MessageEntry.d.ts +29 -0
- package/execution/MessageEntry.d.ts.map +1 -1
- package/execution/MessageEntry.js +29 -5
- package/execution/MessageEntry.js.map +1 -1
- package/execution/MessageThread.d.ts +76 -13
- package/execution/MessageThread.d.ts.map +1 -1
- package/execution/MessageThread.js +178 -24
- package/execution/MessageThread.js.map +1 -1
- package/execution/PlanArtifactCard.d.ts +27 -18
- package/execution/PlanArtifactCard.d.ts.map +1 -1
- package/execution/PlanArtifactCard.js +13 -23
- package/execution/PlanArtifactCard.js.map +1 -1
- package/execution/PlanDocumentMessage.d.ts +32 -0
- package/execution/PlanDocumentMessage.d.ts.map +1 -0
- package/execution/PlanDocumentMessage.js +37 -0
- package/execution/PlanDocumentMessage.js.map +1 -0
- package/execution/PlanStreamingCard.d.ts +45 -0
- package/execution/PlanStreamingCard.d.ts.map +1 -0
- package/execution/PlanStreamingCard.js +35 -0
- package/execution/PlanStreamingCard.js.map +1 -0
- package/execution/index.d.ts +5 -1
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +2 -0
- package/execution/index.js.map +1 -1
- package/execution/useCreateAgentExecution.d.ts +10 -0
- package/execution/useCreateAgentExecution.d.ts.map +1 -1
- package/execution/useCreateAgentExecution.js +5 -1
- package/execution/useCreateAgentExecution.js.map +1 -1
- package/github/decodeGitHubContent.d.ts +29 -0
- package/github/decodeGitHubContent.d.ts.map +1 -0
- package/github/decodeGitHubContent.js +72 -0
- package/github/decodeGitHubContent.js.map +1 -0
- package/github/index.d.ts +1 -0
- package/github/index.d.ts.map +1 -1
- package/github/index.js +1 -0
- package/github/index.js.map +1 -1
- package/github/useGitHubFileReader.d.ts +26 -0
- package/github/useGitHubFileReader.d.ts.map +1 -0
- package/github/useGitHubFileReader.js +106 -0
- package/github/useGitHubFileReader.js.map +1 -0
- package/github/useGitHubTreeLister.d.ts.map +1 -1
- package/github/useGitHubTreeLister.js +6 -2
- package/github/useGitHubTreeLister.js.map +1 -1
- package/index.d.ts +9 -9
- package/index.d.ts.map +1 -1
- package/index.js +5 -5
- package/index.js.map +1 -1
- package/internal/ResizableSplit.d.ts +72 -22
- package/internal/ResizableSplit.d.ts.map +1 -1
- package/internal/ResizableSplit.js +96 -38
- package/internal/ResizableSplit.js.map +1 -1
- package/internal/VirtualizedThread.d.ts +5 -3
- package/internal/VirtualizedThread.d.ts.map +1 -1
- package/internal/VirtualizedThread.js +6 -4
- package/internal/VirtualizedThread.js.map +1 -1
- package/internal/file-icons/index.d.ts +17 -0
- package/internal/file-icons/index.d.ts.map +1 -0
- package/internal/file-icons/index.js +60 -0
- package/internal/file-icons/index.js.map +1 -0
- package/internal/file-tree/FileTreeNode.d.ts +18 -1
- package/internal/file-tree/FileTreeNode.d.ts.map +1 -1
- package/internal/file-tree/FileTreeNode.js +11 -2
- package/internal/file-tree/FileTreeNode.js.map +1 -1
- package/internal/markdown-components.d.ts +38 -1
- package/internal/markdown-components.d.ts.map +1 -1
- package/internal/markdown-components.js +86 -11
- package/internal/markdown-components.js.map +1 -1
- package/{workflow → internal}/motion-preference.d.ts +7 -4
- package/internal/motion-preference.d.ts.map +1 -0
- package/{workflow → internal}/motion-preference.js +7 -4
- package/internal/motion-preference.js.map +1 -0
- package/internal/store/index.d.ts +33 -0
- package/internal/store/index.d.ts.map +1 -1
- package/internal/store/index.js +59 -0
- package/internal/store/index.js.map +1 -1
- package/internal/store/workspace-editors-store.d.ts +145 -0
- package/internal/store/workspace-editors-store.d.ts.map +1 -0
- package/internal/store/workspace-editors-store.js +208 -0
- package/internal/store/workspace-editors-store.js.map +1 -0
- package/internal/store/workspace-file-selection-store.d.ts +38 -0
- package/internal/store/workspace-file-selection-store.d.ts.map +1 -0
- package/internal/store/workspace-file-selection-store.js +62 -0
- package/internal/store/workspace-file-selection-store.js.map +1 -0
- package/internal/useRevealLine.d.ts +49 -0
- package/internal/useRevealLine.d.ts.map +1 -0
- package/internal/useRevealLine.js +43 -0
- package/internal/useRevealLine.js.map +1 -0
- package/library/detect-plan-artifact.d.ts +21 -0
- package/library/detect-plan-artifact.d.ts.map +1 -1
- package/library/detect-plan-artifact.js +20 -0
- package/library/detect-plan-artifact.js.map +1 -1
- package/library/detect-streaming-plan.d.ts +45 -0
- package/library/detect-streaming-plan.d.ts.map +1 -0
- package/library/detect-streaming-plan.js +83 -0
- package/library/detect-streaming-plan.js.map +1 -0
- package/library/index.d.ts +4 -1
- package/library/index.d.ts.map +1 -1
- package/library/index.js +2 -1
- package/library/index.js.map +1 -1
- package/package.json +4 -4
- package/session/NewSessionViewer.d.ts +19 -4
- package/session/NewSessionViewer.d.ts.map +1 -1
- package/session/NewSessionViewer.js +52 -25
- package/session/NewSessionViewer.js.map +1 -1
- package/session/PlanEditor.d.ts +55 -0
- package/session/PlanEditor.d.ts.map +1 -0
- package/session/PlanEditor.js +88 -0
- package/session/PlanEditor.js.map +1 -0
- package/session/PlanStreamingDocument.d.ts +30 -0
- package/session/PlanStreamingDocument.d.ts.map +1 -0
- package/session/PlanStreamingDocument.js +37 -0
- package/session/PlanStreamingDocument.js.map +1 -0
- package/session/SessionPanelChip.d.ts +26 -0
- package/session/SessionPanelChip.d.ts.map +1 -0
- package/session/SessionPanelChip.js +40 -0
- package/session/SessionPanelChip.js.map +1 -0
- package/session/SessionViewer.d.ts +34 -7
- package/session/SessionViewer.d.ts.map +1 -1
- package/session/SessionViewer.js +315 -33
- package/session/SessionViewer.js.map +1 -1
- package/session/{inspector → facets}/ArtifactsTab.d.ts +10 -2
- package/session/facets/ArtifactsTab.d.ts.map +1 -0
- package/session/{inspector → facets}/ArtifactsTab.js +8 -3
- package/session/facets/ArtifactsTab.js.map +1 -0
- package/session/{inspector → facets}/ChangesTab.d.ts +3 -3
- package/session/facets/ChangesTab.d.ts.map +1 -0
- package/session/{inspector → facets}/ChangesTab.js +3 -3
- package/session/facets/ChangesTab.js.map +1 -0
- package/session/facets/InspectTab.d.ts.map +1 -0
- package/session/facets/InspectTab.js.map +1 -0
- package/session/{inspector → facets}/SetupTab.d.ts +11 -2
- package/session/facets/SetupTab.d.ts.map +1 -0
- package/session/{inspector → facets}/SetupTab.js +4 -3
- package/session/facets/SetupTab.js.map +1 -0
- package/session/{inspector → facets}/UsageTab.d.ts +1 -1
- package/session/facets/UsageTab.d.ts.map +1 -0
- package/session/{inspector → facets}/UsageTab.js +1 -1
- package/session/facets/UsageTab.js.map +1 -0
- package/session/{inspector → facets}/index.d.ts +0 -6
- package/session/facets/index.d.ts.map +1 -0
- package/session/{inspector → facets}/index.js +0 -3
- package/session/facets/index.js.map +1 -0
- package/session/index.d.ts +11 -2
- package/session/index.d.ts.map +1 -1
- package/session/index.js +15 -2
- package/session/index.js.map +1 -1
- package/session/plan-document.d.ts +9 -0
- package/session/plan-document.d.ts.map +1 -0
- package/session/plan-document.js +17 -0
- package/session/plan-document.js.map +1 -0
- package/session/useOpenFileChange.d.ts +20 -0
- package/session/useOpenFileChange.d.ts.map +1 -0
- package/session/useOpenFileChange.js +31 -0
- package/session/useOpenFileChange.js.map +1 -0
- package/session/usePlanDraft.d.ts +52 -0
- package/session/usePlanDraft.d.ts.map +1 -0
- package/session/usePlanDraft.js +63 -0
- package/session/usePlanDraft.js.map +1 -0
- package/session/useSessionConversation.d.ts +6 -0
- package/session/useSessionConversation.d.ts.map +1 -1
- package/session/useSessionConversation.js +1 -0
- package/session/useSessionConversation.js.map +1 -1
- package/session/useSessionPageFlow.d.ts.map +1 -1
- package/session/useSessionPageFlow.js +1 -0
- package/session/useSessionPageFlow.js.map +1 -1
- package/session/useSessionPanel.d.ts +120 -0
- package/session/useSessionPanel.d.ts.map +1 -0
- package/session/useSessionPanel.js +130 -0
- package/session/useSessionPanel.js.map +1 -0
- package/session/useSessionRailViews.d.ts +45 -0
- package/session/useSessionRailViews.d.ts.map +1 -0
- package/session/useSessionRailViews.js +105 -0
- package/session/useSessionRailViews.js.map +1 -0
- package/src/composer/SessionComposer.tsx +52 -10
- package/src/composer/__tests__/SessionComposer-contract.test.tsx +58 -4
- package/src/execution/ArtifactContentRenderer.tsx +101 -24
- package/src/execution/FilePathContext.tsx +8 -1
- package/src/execution/FilePathLink.tsx +22 -6
- package/src/execution/MessageEntry.tsx +111 -1
- package/src/execution/MessageThread.tsx +291 -36
- package/src/execution/PlanArtifactCard.tsx +63 -31
- package/src/execution/PlanDocumentMessage.tsx +96 -0
- package/src/execution/PlanStreamingCard.tsx +137 -0
- package/src/execution/__tests__/ArtifactContentRenderer.test.tsx +80 -1
- package/src/execution/__tests__/FilePathLink.test.tsx +87 -0
- package/src/execution/__tests__/MessageThread.test.tsx +101 -0
- package/src/execution/__tests__/PlanArtifactCard.test.tsx +66 -12
- package/src/execution/__tests__/PlanDocumentMessage.test.tsx +55 -0
- package/src/execution/__tests__/PlanStreamingCard.test.tsx +49 -0
- package/src/execution/__tests__/buildThreadItems-plan-completion.test.ts +504 -22
- package/src/execution/__tests__/message-entry.test.tsx +48 -0
- package/src/execution/__tests__/useCreateAgentExecution.test.tsx +85 -0
- package/src/execution/index.ts +7 -1
- package/src/execution/useCreateAgentExecution.ts +16 -1
- package/src/github/__tests__/decodeGitHubContent.test.ts +102 -0
- package/src/github/__tests__/useGitHubFileReader.test.ts +183 -0
- package/src/github/decodeGitHubContent.ts +83 -0
- package/src/github/index.ts +1 -0
- package/src/github/useGitHubFileReader.ts +152 -0
- package/src/github/useGitHubTreeLister.ts +6 -2
- package/src/index.ts +63 -9
- package/src/internal/ResizableSplit.tsx +184 -51
- package/src/internal/VirtualizedThread.tsx +12 -4
- package/src/internal/__tests__/ResizableSplit.test.tsx +125 -3
- package/src/internal/__tests__/markdown-components.test.tsx +68 -0
- package/src/internal/__tests__/useRevealLine.test.tsx +97 -0
- package/src/internal/file-icons/__tests__/file-icons.test.tsx +35 -0
- package/src/internal/file-icons/index.tsx +137 -0
- package/src/internal/file-tree/FileTreeNode.tsx +43 -3
- package/src/internal/file-tree/__tests__/FileTreeNode-explorer.test.tsx +86 -0
- package/src/internal/markdown-components.tsx +116 -11
- package/src/{workflow → internal}/motion-preference.ts +7 -4
- package/src/internal/store/__tests__/workspace-editors-store.test.ts +216 -0
- package/src/internal/store/__tests__/workspace-file-selection-store.test.ts +118 -0
- package/src/internal/store/index.ts +94 -0
- package/src/internal/store/workspace-editors-store.ts +315 -0
- package/src/internal/store/workspace-file-selection-store.ts +88 -0
- package/src/internal/useRevealLine.ts +81 -0
- package/src/library/__tests__/detect-plan-artifact.test.ts +48 -0
- package/src/library/__tests__/detect-streaming-plan.test.ts +234 -0
- package/src/library/detect-plan-artifact.ts +35 -0
- package/src/library/detect-streaming-plan.ts +108 -0
- package/src/library/index.ts +5 -0
- package/src/session/NewSessionViewer.tsx +123 -55
- package/src/session/PlanEditor.tsx +361 -0
- package/src/session/PlanStreamingDocument.tsx +97 -0
- package/src/session/SessionPanelChip.tsx +103 -0
- package/src/session/SessionViewer.tsx +617 -90
- package/src/session/__tests__/NewSessionViewer.test.tsx +148 -0
- package/src/session/__tests__/PlanEditor.test.tsx +217 -0
- package/src/session/__tests__/PlanStreamingDocument.test.tsx +50 -0
- package/src/session/__tests__/SessionPanelChip.test.tsx +42 -0
- package/src/session/__tests__/SessionViewer-fileReviewDock.test.tsx +9 -4
- package/src/session/__tests__/SessionViewer-transcriptFileOpen.test.tsx +205 -0
- package/src/session/__tests__/audienceWiring.test.tsx +55 -19
- package/src/session/__tests__/useOpenFileChange.test.tsx +82 -0
- package/src/session/__tests__/usePlanDraft.test.ts +102 -0
- package/src/session/__tests__/useSessionPanel.test.ts +298 -0
- package/src/session/__tests__/useSessionRailViews.test.tsx +124 -0
- package/src/session/{inspector → facets}/ArtifactsTab.tsx +27 -5
- package/src/session/{inspector → facets}/ChangesTab.tsx +3 -3
- package/src/session/{inspector → facets}/SetupTab.tsx +13 -1
- package/src/session/{inspector → facets}/UsageTab.tsx +1 -1
- package/src/session/{inspector → facets}/__tests__/ArtifactsTab.test.tsx +35 -1
- package/src/session/facets/__tests__/SetupTab.test.tsx +44 -0
- package/src/session/{inspector → facets}/index.ts +0 -16
- package/src/session/index.ts +30 -13
- package/src/session/plan-document.ts +19 -0
- package/src/session/useOpenFileChange.ts +53 -0
- package/src/session/usePlanDraft.ts +109 -0
- package/src/session/useSessionConversation.ts +7 -0
- package/src/session/useSessionPageFlow.ts +1 -0
- package/src/session/useSessionPanel.ts +288 -0
- package/src/session/useSessionRailViews.tsx +200 -0
- package/src/workflow/WorkflowExecutionGraph.tsx +1 -1
- package/src/workflow/index.ts +1 -1
- package/src/workflow/useFollowExecution.ts +1 -1
- package/src/workspace/EditorTabs.tsx +145 -0
- package/src/workspace/ExplorerTree.tsx +247 -0
- package/src/workspace/FileViewer.tsx +516 -0
- package/src/workspace/WorkspaceContentSearch.tsx +478 -0
- package/src/workspace/WorkspaceContentSearcher.ts +70 -0
- package/src/workspace/WorkspaceFileLister.ts +11 -0
- package/src/workspace/WorkspaceFileReader.ts +57 -0
- package/src/workspace/WorkspaceFileSearch.tsx +429 -0
- package/src/workspace/WorkspaceSurface.tsx +781 -0
- package/src/workspace/__tests__/EditorTabs.test.tsx +100 -0
- package/src/workspace/__tests__/ExplorerTree.test.tsx +152 -0
- package/src/workspace/__tests__/FileViewer.test.tsx +421 -0
- package/src/workspace/__tests__/WorkspaceContentSearch.test.tsx +196 -0
- package/src/workspace/__tests__/WorkspaceFileSearch.test.tsx +206 -0
- package/src/workspace/__tests__/WorkspaceSurface.test.tsx +348 -0
- package/src/workspace/__tests__/findChangeForSelection.test.ts +132 -0
- package/src/workspace/__tests__/matchContentPreview.test.ts +55 -0
- package/src/workspace/__tests__/matchWorkspaceFiles.test.ts +104 -0
- package/src/workspace/__tests__/resolveWorkspaceFileSelection.test.ts +135 -0
- package/src/workspace/__tests__/useWorkspaceContentSearch.test.tsx +196 -0
- package/src/workspace/__tests__/useWorkspaceFileContent.test.tsx +190 -0
- package/src/workspace/__tests__/useWorkspaceFileSearch.test.tsx +162 -0
- package/src/workspace/findChangeForSelection.ts +61 -0
- package/src/workspace/index.ts +56 -2
- package/src/workspace/matchContentPreview.ts +51 -0
- package/src/workspace/matchWorkspaceFiles.ts +86 -0
- package/src/workspace/resolveWorkspaceFileSelection.ts +119 -0
- package/src/workspace/useWorkspaceContentSearch.ts +228 -0
- package/src/workspace/useWorkspaceFileContent.ts +129 -0
- package/src/workspace/useWorkspaceFileSearch.ts +184 -0
- package/src/workspace/useWorkspaceFiles.ts +27 -27
- package/src/workspace/workspaceListingCache.ts +93 -0
- package/styles.css +1 -1
- package/workflow/WorkflowExecutionGraph.js +1 -1
- package/workflow/WorkflowExecutionGraph.js.map +1 -1
- package/workflow/index.d.ts +1 -1
- package/workflow/index.d.ts.map +1 -1
- package/workflow/index.js +1 -1
- package/workflow/index.js.map +1 -1
- package/workflow/useFollowExecution.js +1 -1
- package/workflow/useFollowExecution.js.map +1 -1
- package/workspace/EditorTabs.d.ts +29 -0
- package/workspace/EditorTabs.d.ts.map +1 -0
- package/workspace/EditorTabs.js +66 -0
- package/workspace/EditorTabs.js.map +1 -0
- package/workspace/ExplorerTree.d.ts +32 -0
- package/workspace/ExplorerTree.d.ts.map +1 -0
- package/workspace/ExplorerTree.js +45 -0
- package/workspace/ExplorerTree.js.map +1 -0
- package/workspace/FileViewer.d.ts +93 -0
- package/workspace/FileViewer.d.ts.map +1 -0
- package/workspace/FileViewer.js +182 -0
- package/workspace/FileViewer.js.map +1 -0
- package/workspace/WorkspaceContentSearch.d.ts +41 -0
- package/workspace/WorkspaceContentSearch.d.ts.map +1 -0
- package/workspace/WorkspaceContentSearch.js +195 -0
- package/workspace/WorkspaceContentSearch.js.map +1 -0
- package/workspace/WorkspaceContentSearcher.d.ts +59 -0
- package/workspace/WorkspaceContentSearcher.d.ts.map +1 -0
- package/workspace/WorkspaceContentSearcher.js +7 -0
- package/workspace/WorkspaceContentSearcher.js.map +1 -0
- package/workspace/WorkspaceFileLister.d.ts +11 -0
- package/workspace/WorkspaceFileLister.d.ts.map +1 -1
- package/workspace/WorkspaceFileReader.d.ts +48 -0
- package/workspace/WorkspaceFileReader.d.ts.map +1 -0
- package/workspace/WorkspaceFileReader.js +11 -0
- package/workspace/WorkspaceFileReader.js.map +1 -0
- package/workspace/WorkspaceFileSearch.d.ts +32 -0
- package/workspace/WorkspaceFileSearch.d.ts.map +1 -0
- package/workspace/WorkspaceFileSearch.js +155 -0
- package/workspace/WorkspaceFileSearch.js.map +1 -0
- package/workspace/WorkspaceSurface.d.ts +151 -0
- package/workspace/WorkspaceSurface.d.ts.map +1 -0
- package/workspace/WorkspaceSurface.js +184 -0
- package/workspace/WorkspaceSurface.js.map +1 -0
- package/workspace/findChangeForSelection.d.ts +19 -0
- package/workspace/findChangeForSelection.d.ts.map +1 -0
- package/workspace/findChangeForSelection.js +46 -0
- package/workspace/findChangeForSelection.js.map +1 -0
- package/workspace/index.d.ts +24 -2
- package/workspace/index.d.ts.map +1 -1
- package/workspace/index.js +13 -1
- package/workspace/index.js.map +1 -1
- package/workspace/matchContentPreview.d.ts +21 -0
- package/workspace/matchContentPreview.d.ts.map +1 -0
- package/workspace/matchContentPreview.js +36 -0
- package/workspace/matchContentPreview.js.map +1 -0
- package/workspace/matchWorkspaceFiles.d.ts +30 -0
- package/workspace/matchWorkspaceFiles.d.ts.map +1 -0
- package/workspace/matchWorkspaceFiles.js +58 -0
- package/workspace/matchWorkspaceFiles.js.map +1 -0
- package/workspace/resolveWorkspaceFileSelection.d.ts +19 -0
- package/workspace/resolveWorkspaceFileSelection.d.ts.map +1 -0
- package/workspace/resolveWorkspaceFileSelection.js +115 -0
- package/workspace/resolveWorkspaceFileSelection.js.map +1 -0
- package/workspace/useWorkspaceContentSearch.d.ts +69 -0
- package/workspace/useWorkspaceContentSearch.d.ts.map +1 -0
- package/workspace/useWorkspaceContentSearch.js +154 -0
- package/workspace/useWorkspaceContentSearch.js.map +1 -0
- package/workspace/useWorkspaceFileContent.d.ts +73 -0
- package/workspace/useWorkspaceFileContent.d.ts.map +1 -0
- package/workspace/useWorkspaceFileContent.js +57 -0
- package/workspace/useWorkspaceFileContent.js.map +1 -0
- package/workspace/useWorkspaceFileSearch.d.ts +61 -0
- package/workspace/useWorkspaceFileSearch.d.ts.map +1 -0
- package/workspace/useWorkspaceFileSearch.js +119 -0
- package/workspace/useWorkspaceFileSearch.js.map +1 -0
- package/workspace/useWorkspaceFiles.d.ts +13 -5
- package/workspace/useWorkspaceFiles.d.ts.map +1 -1
- package/workspace/useWorkspaceFiles.js +18 -19
- package/workspace/useWorkspaceFiles.js.map +1 -1
- package/workspace/workspaceListingCache.d.ts +47 -0
- package/workspace/workspaceListingCache.d.ts.map +1 -0
- package/workspace/workspaceListingCache.js +55 -0
- package/workspace/workspaceListingCache.js.map +1 -0
- package/session/inspector/ArtifactsTab.d.ts.map +0 -1
- package/session/inspector/ArtifactsTab.js.map +0 -1
- package/session/inspector/ChangesTab.d.ts.map +0 -1
- package/session/inspector/ChangesTab.js.map +0 -1
- package/session/inspector/InspectTab.d.ts.map +0 -1
- package/session/inspector/InspectTab.js.map +0 -1
- package/session/inspector/SessionInspector.d.ts +0 -64
- package/session/inspector/SessionInspector.d.ts.map +0 -1
- package/session/inspector/SessionInspector.js +0 -53
- package/session/inspector/SessionInspector.js.map +0 -1
- package/session/inspector/SetupTab.d.ts.map +0 -1
- package/session/inspector/SetupTab.js.map +0 -1
- package/session/inspector/UsageTab.d.ts.map +0 -1
- package/session/inspector/UsageTab.js.map +0 -1
- package/session/inspector/WorkspaceTab.d.ts +0 -35
- package/session/inspector/WorkspaceTab.d.ts.map +0 -1
- package/session/inspector/WorkspaceTab.js +0 -75
- package/session/inspector/WorkspaceTab.js.map +0 -1
- package/session/inspector/index.d.ts.map +0 -1
- package/session/inspector/index.js.map +0 -1
- package/session/inspector/useSessionInspector.d.ts +0 -49
- package/session/inspector/useSessionInspector.d.ts.map +0 -1
- package/session/inspector/useSessionInspector.js +0 -122
- package/session/inspector/useSessionInspector.js.map +0 -1
- package/src/session/inspector/SessionInspector.tsx +0 -162
- package/src/session/inspector/WorkspaceTab.tsx +0 -245
- package/src/session/inspector/__tests__/useSessionInspector.test.ts +0 -251
- package/src/session/inspector/useSessionInspector.ts +0 -178
- package/src/workspace/WorkspaceEntryFiles.tsx +0 -196
- package/workflow/motion-preference.d.ts.map +0 -1
- package/workflow/motion-preference.js.map +0 -1
- package/workspace/WorkspaceEntryFiles.d.ts +0 -22
- package/workspace/WorkspaceEntryFiles.d.ts.map +0 -1
- package/workspace/WorkspaceEntryFiles.js +0 -58
- package/workspace/WorkspaceEntryFiles.js.map +0 -1
- /package/session/{inspector → facets}/InspectTab.d.ts +0 -0
- /package/session/{inspector → facets}/InspectTab.js +0 -0
- /package/src/{workflow → internal}/__tests__/motion-preference.test.ts +0 -0
- /package/src/session/{inspector → facets}/InspectTab.tsx +0 -0
- /package/src/session/{inspector → facets}/__tests__/ChangesTab.test.tsx +0 -0
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useCallback, useMemo, useRef, type ReactNode } from "react";
|
|
3
|
+
import { memo, useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
|
|
4
|
+
import { create } from "@bufbuild/protobuf";
|
|
4
5
|
import { cn } from "@stigmer/theme";
|
|
5
|
-
import { getUserMessage, type ResourceRef } from "@stigmer/sdk";
|
|
6
|
+
import { getUserMessage, type AttachmentInput, type ResourceRef } from "@stigmer/sdk";
|
|
7
|
+
import {
|
|
8
|
+
GetArtifactContentRequestSchema,
|
|
9
|
+
UploadAttachmentRequestSchema,
|
|
10
|
+
} from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/io_pb";
|
|
6
11
|
import type { UseGitHubConnectionReturn } from "../github/useGitHubConnection.js";
|
|
7
12
|
import type { WorkspaceFileLister } from "../workspace/WorkspaceFileLister.js";
|
|
13
|
+
import type { WorkspaceFileReader } from "../workspace/WorkspaceFileReader.js";
|
|
14
|
+
import type { WorkspaceContentSearcher } from "../workspace/WorkspaceContentSearcher.js";
|
|
15
|
+
import { resolveWorkspaceFileSelection } from "../workspace/resolveWorkspaceFileSelection.js";
|
|
16
|
+
import {
|
|
17
|
+
WorkspaceSurface,
|
|
18
|
+
type SurfaceVirtualDocument,
|
|
19
|
+
} from "../workspace/WorkspaceSurface.js";
|
|
8
20
|
import type { InteractionModeOption, SessionComposerHandle } from "../composer/index.js";
|
|
9
21
|
import type { ApplyResourceResult } from "../library/useApplyResource.js";
|
|
10
22
|
import { ResizableSplit } from "../internal/ResizableSplit.js";
|
|
11
23
|
import { SelectionStore } from "../internal/store/selection-store.js";
|
|
24
|
+
import { useWorkspaceEditors, isVirtualEntryId } from "../internal/store/index.js";
|
|
12
25
|
import { ThreadSelectionContext } from "../execution/ThreadSelectionContext.js";
|
|
13
26
|
import { useSelectedThreadItem } from "../execution/useThreadSelection.js";
|
|
14
27
|
import { MessageThread } from "../execution/MessageThread.js";
|
|
@@ -16,18 +29,98 @@ import { FileReviewDock } from "../execution/FileReviewDock.js";
|
|
|
16
29
|
import { ThreadSkeleton } from "../execution/ThreadSkeleton.js";
|
|
17
30
|
import { SessionComposer } from "../composer/index.js";
|
|
18
31
|
import { SecretFlowErrorGuide, isSecretFlowError } from "../error/index.js";
|
|
32
|
+
import { useStigmer } from "../hooks.js";
|
|
33
|
+
import {
|
|
34
|
+
PLAN_ARTIFACT_NAME,
|
|
35
|
+
findLatestSessionPlan,
|
|
36
|
+
findPlanArtifact,
|
|
37
|
+
type SessionPlan,
|
|
38
|
+
} from "../library/detect-plan-artifact.js";
|
|
39
|
+
import { findStreamingPlan } from "../library/detect-streaming-plan.js";
|
|
19
40
|
import { useSessionPageFlow } from "./useSessionPageFlow.js";
|
|
20
|
-
import {
|
|
41
|
+
import { useOpenFileChange } from "./useOpenFileChange.js";
|
|
42
|
+
import { usePlanDraft, planDraftKey, type PlanDraftController } from "./usePlanDraft.js";
|
|
43
|
+
import { PlanEditor } from "./PlanEditor.js";
|
|
44
|
+
import { PlanStreamingDocument } from "./PlanStreamingDocument.js";
|
|
45
|
+
import { PLAN_DOCUMENT_ENTRY_ID, PLAN_DOCUMENT_PATH } from "./plan-document.js";
|
|
46
|
+
import { useSessionRailViews } from "./useSessionRailViews.js";
|
|
47
|
+
import { useSessionPanel, type SessionPanelController } from "./useSessionPanel.js";
|
|
48
|
+
import { SessionPanelChip } from "./SessionPanelChip.js";
|
|
49
|
+
import { useSessionWriteBacks } from "./useSessionWriteBacks.js";
|
|
50
|
+
import { useSessionArtifacts } from "./useSessionArtifacts.js";
|
|
51
|
+
import type { SetupTabProps } from "./facets/SetupTab.js";
|
|
52
|
+
import { ExecutionPhase } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
21
53
|
import type { RuntimeEnvProvider } from "./runtime-env.js";
|
|
22
54
|
import type { SessionAudience } from "./audience.js";
|
|
23
55
|
|
|
24
56
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
57
|
+
* Where the approved plan mounts in the implement execution's workspace —
|
|
58
|
+
* the harnesses' standard attachment inputs directory, where the runner's
|
|
59
|
+
* implement-plan directive points the agent (shared/implement-plan-prompt.ts).
|
|
60
|
+
* Attaching at this exact path is what makes the build implement the document
|
|
61
|
+
* the user approved (including in-place edits), not a paraphrase from memory.
|
|
28
62
|
*/
|
|
29
|
-
const
|
|
30
|
-
|
|
63
|
+
const APPROVED_PLAN_MOUNT_PATH = `.stigmer/inputs/${PLAN_ARTIFACT_NAME}`;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The build turn's user message — a short human-readable label, NOT the
|
|
67
|
+
* implement instruction. The agent-facing instruction is runner-injected
|
|
68
|
+
* (keyed off `executionConfig.buildFromPlan`), so this text exists for
|
|
69
|
+
* humans: the thread renders the turn as a compact chip from the same flag,
|
|
70
|
+
* and surfaces without the chip treatment (the CLI, older clients) show
|
|
71
|
+
* this label as-is.
|
|
72
|
+
*/
|
|
73
|
+
const BUILD_FROM_PLAN_MESSAGE = "Build from plan";
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A plan the active execution is writing right now, resolved at the viewer
|
|
77
|
+
* level (from `findStreamingPlan`) so the panel's plan tab can render it
|
|
78
|
+
* live. The streaming sibling of {@link SessionPlan}: `executionId` keys the
|
|
79
|
+
* document (a new turn's stream resets the tab's view state) and forms the
|
|
80
|
+
* `<executionId>:streaming` identity for the plan-tab auto-open trigger.
|
|
81
|
+
*/
|
|
82
|
+
interface SessionStreamingPlan {
|
|
83
|
+
/** ID of the execution writing the plan. */
|
|
84
|
+
readonly executionId: string;
|
|
85
|
+
/** The live plan text (fence-stripped display projection). */
|
|
86
|
+
readonly displayText: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Reads the published plan's full text for the build handoff. Refuses a
|
|
91
|
+
* truncated read (content RPC caps at 512 KB): attaching a partial plan would
|
|
92
|
+
* silently implement half a document — the caller falls back to
|
|
93
|
+
* conversation-history implement instead.
|
|
94
|
+
*/
|
|
95
|
+
async function fetchPlanText(
|
|
96
|
+
stigmer: ReturnType<typeof useStigmer>,
|
|
97
|
+
plan: SessionPlan,
|
|
98
|
+
): Promise<string> {
|
|
99
|
+
const result = await stigmer.agentExecution.getArtifactContent(
|
|
100
|
+
create(GetArtifactContentRequestSchema, {
|
|
101
|
+
executionId: plan.executionId,
|
|
102
|
+
storageKey: plan.artifact.storageKey,
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
105
|
+
if (result.truncated) {
|
|
106
|
+
throw new Error("plan content truncated — not attaching a partial plan");
|
|
107
|
+
}
|
|
108
|
+
return new TextDecoder().decode(result.content);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Width and anchoring of the conversation reading column, shared by the
|
|
113
|
+
* thread and the composer/banners block so they can never drift apart.
|
|
114
|
+
*
|
|
115
|
+
* Centered (the classic chat reading view, matching Cursor's agent panel):
|
|
116
|
+
* with the session panel collapsed the column sits in the middle of the
|
|
117
|
+
* row; opening the panel narrows the chat pane below the column max, so
|
|
118
|
+
* the column simply fills it. The thread applies the same geometry via
|
|
119
|
+
* `contentColumn="center"`, which adds the item gutter; the composer/banner
|
|
120
|
+
* block's children carry their own edge padding, so only width and
|
|
121
|
+
* anchoring live here.
|
|
122
|
+
*/
|
|
123
|
+
const CONVERSATION_COLUMN_CLASS = "mx-auto w-full max-w-3xl";
|
|
31
124
|
|
|
32
125
|
/** Props for {@link SessionViewer}. */
|
|
33
126
|
export interface SessionViewerProps {
|
|
@@ -70,6 +163,21 @@ export interface SessionViewerProps {
|
|
|
70
163
|
* expandable file tree. (DD-004 capability injection, DD-011 opt-in.)
|
|
71
164
|
*/
|
|
72
165
|
readonly workspaceFileLister?: WorkspaceFileLister;
|
|
166
|
+
/**
|
|
167
|
+
* Platform-injected content reader for the read-only file viewer. When
|
|
168
|
+
* provided, clicking a file in the Workspace tree opens it in a contextual
|
|
169
|
+
* "Viewer" tab. GitHub Contents/blob on web, Tauri fs on desktop; `undefined`
|
|
170
|
+
* degrades the viewer to an "unavailable here" state (DD-004, DD-011 opt-in).
|
|
171
|
+
*/
|
|
172
|
+
readonly workspaceFileReader?: WorkspaceFileReader;
|
|
173
|
+
/**
|
|
174
|
+
* Platform-injected content (text) searcher. When provided, the session
|
|
175
|
+
* panel's Search pane gains a `Name | Text` toggle for full-text search
|
|
176
|
+
* across the workspace. Desktop injects a native ripgrep-backed searcher;
|
|
177
|
+
* web leaves it undefined (git content search needs a branch-accurate
|
|
178
|
+
* backend — DD-09), keeping Search filename-only there (DD-004, DD-011 opt-in).
|
|
179
|
+
*/
|
|
180
|
+
readonly workspaceContentSearcher?: WorkspaceContentSearcher;
|
|
73
181
|
/**
|
|
74
182
|
* Supplies host-app environment variables for every follow-up
|
|
75
183
|
* execution (e.g. short-lived credentials for MCP tools, minted as
|
|
@@ -92,11 +200,18 @@ export interface SessionViewerProps {
|
|
|
92
200
|
*/
|
|
93
201
|
readonly audience?: SessionAudience;
|
|
94
202
|
/**
|
|
95
|
-
* Slot for host-injected header actions
|
|
96
|
-
*
|
|
97
|
-
*
|
|
203
|
+
* Slot for host-injected header actions. Rendered in the top-right corner
|
|
204
|
+
* of the viewer, beside the panel chip. Keeps the SDK organism
|
|
205
|
+
* unopinionated about Console auth (DD-004).
|
|
98
206
|
*/
|
|
99
207
|
readonly headerActions?: ReactNode;
|
|
208
|
+
/**
|
|
209
|
+
* Host-injected access management control (e.g. the Console's
|
|
210
|
+
* `ManageAccessButton` with its own permission gating). Rendered inside
|
|
211
|
+
* the panel's Config facet rather than the header — access is session
|
|
212
|
+
* configuration, not a moment-to-moment action (DD-004 slot injection).
|
|
213
|
+
*/
|
|
214
|
+
readonly accessSlot?: ReactNode;
|
|
100
215
|
/** Called after a resource is applied from the Artifacts tab. */
|
|
101
216
|
readonly onApplied?: (result: ApplyResourceResult) => void;
|
|
102
217
|
/** Additional CSS classes for the root container. */
|
|
@@ -110,10 +225,13 @@ export interface SessionViewerProps {
|
|
|
110
225
|
* Owns `useSessionPageFlow` internally and composes:
|
|
111
226
|
* - **Conversation column** (primary): `MessageThread` + error
|
|
112
227
|
* banners + `SessionComposer`
|
|
113
|
-
* - **
|
|
114
|
-
*
|
|
228
|
+
* - **Session panel** (secondary): the unified `WorkspaceSurface` — explorer,
|
|
229
|
+
* search, read-only editor, and the session facets (Config, Changes,
|
|
230
|
+
* Artifacts, Usage, Inspect) as injected rail views. Collapsed by default
|
|
231
|
+
* to a top-right chip; opening a file (tree, search, or a transcript path)
|
|
232
|
+
* expands it.
|
|
115
233
|
*
|
|
116
|
-
* Connected via `ResizableSplit` with persisted width.
|
|
234
|
+
* Connected via `ResizableSplit` with persisted chat width.
|
|
117
235
|
*
|
|
118
236
|
* Thread selection is provided via `ThreadSelectionContext` (Phase 2
|
|
119
237
|
* opt-in) for render-isolated per-item selection.
|
|
@@ -150,9 +268,12 @@ export function SessionViewer({
|
|
|
150
268
|
enableLocal = false,
|
|
151
269
|
onBrowseLocalFolder,
|
|
152
270
|
workspaceFileLister,
|
|
271
|
+
workspaceFileReader,
|
|
272
|
+
workspaceContentSearcher,
|
|
153
273
|
getRuntimeEnv,
|
|
154
274
|
audience = "integrator",
|
|
155
275
|
headerActions,
|
|
276
|
+
accessSlot,
|
|
156
277
|
onApplied,
|
|
157
278
|
className,
|
|
158
279
|
}: SessionViewerProps) {
|
|
@@ -170,16 +291,179 @@ export function SessionViewer({
|
|
|
170
291
|
}
|
|
171
292
|
const selectionStore = selectionStoreRef.current;
|
|
172
293
|
|
|
294
|
+
const phase =
|
|
295
|
+
flow.displayExecution?.status?.phase ??
|
|
296
|
+
ExecutionPhase.EXECUTION_PHASE_UNSPECIFIED;
|
|
297
|
+
const hasPhase = phase !== ExecutionPhase.EXECUTION_PHASE_UNSPECIFIED;
|
|
298
|
+
|
|
299
|
+
// Facet arrival counts: rail badges inside the panel, the chip's dot-count
|
|
300
|
+
// while collapsed. Arrivals never auto-open the panel (badge-only signal).
|
|
301
|
+
const { hasWriteBacks, writeBackCount } = useSessionWriteBacks(flow.allExecutions);
|
|
302
|
+
const { artifactCount } = useSessionArtifacts(flow.allExecutions);
|
|
303
|
+
|
|
304
|
+
// The session's current plan (latest published plan.md across executions)
|
|
305
|
+
// and its viewer-owned draft. Ownership at this level is deliberate: the
|
|
306
|
+
// panel unmounts facet content on every view switch, so a facet-local
|
|
307
|
+
// draft would silently lose the user's edits (see usePlanDraft).
|
|
308
|
+
const stigmer = useStigmer();
|
|
309
|
+
const sessionPlan = useMemo(
|
|
310
|
+
() => findLatestSessionPlan(flow.allExecutions),
|
|
311
|
+
[flow.allExecutions],
|
|
312
|
+
);
|
|
313
|
+
const planDraft = usePlanDraft(sessionPlan);
|
|
314
|
+
|
|
315
|
+
// The plan the ACTIVE turn is writing right now (the H1 convention — see
|
|
316
|
+
// findStreamingPlan), resolved at this level for the same reason
|
|
317
|
+
// sessionPlan is: the panel's plan tab renders it. Recomputed per stream
|
|
318
|
+
// commit by design — this component already re-renders on every commit
|
|
319
|
+
// (it reads `flow`), and the scan touches only the last AI message.
|
|
320
|
+
const streamingPlan = useMemo<SessionStreamingPlan | undefined>(() => {
|
|
321
|
+
const activeExec = conv.activeStreamExecution;
|
|
322
|
+
const live = findStreamingPlan(activeExec);
|
|
323
|
+
const executionId = activeExec?.metadata?.id;
|
|
324
|
+
return live && executionId
|
|
325
|
+
? { executionId, displayText: live.displayText }
|
|
326
|
+
: undefined;
|
|
327
|
+
}, [conv.activeStreamExecution]);
|
|
328
|
+
const [isBuildingFromPlan, setIsBuildingFromPlan] = useState(false);
|
|
329
|
+
const [planAttachFailed, setPlanAttachFailed] = useState(false);
|
|
330
|
+
|
|
331
|
+
// WHICH plan the panel's plan document tab shows. `null` means the session's
|
|
332
|
+
// current (latest) plan — the editable, buildable one; an execution id
|
|
333
|
+
// selects that turn's historical plan, rendered read-only. One tab, host-
|
|
334
|
+
// controlled content (Decision 3 in DD-16).
|
|
335
|
+
const [openPlanExecutionId, setOpenPlanExecutionId] = useState<string | null>(null);
|
|
336
|
+
|
|
337
|
+
// The plan tab's identity across both plan lifecycles: while a plan
|
|
338
|
+
// streams, the in-flight turn owns the tab (`<executionId>:streaming`);
|
|
339
|
+
// once published, the artifact identity (planDraftKey) takes over. Each
|
|
340
|
+
// transition is a NEW identity, so useSessionPanel's planKey trigger
|
|
341
|
+
// auto-opens the tab the moment a plan starts streaming AND (idempotently)
|
|
342
|
+
// when it settles into the published plan.
|
|
343
|
+
const currentPlanKey = sessionPlan ? planDraftKey(sessionPlan) : null;
|
|
344
|
+
const panelPlanKey = streamingPlan
|
|
345
|
+
? `${streamingPlan.executionId}:streaming`
|
|
346
|
+
: currentPlanKey;
|
|
347
|
+
|
|
348
|
+
// A new plan identity (a plan starting to stream, the first published
|
|
349
|
+
// plan, or a refinement) supersedes any historical plan the user had
|
|
350
|
+
// opened: the tab snaps back to "latest" so the auto-open always surfaces
|
|
351
|
+
// the incoming plan. Adjust-state-during-render — own state only, the
|
|
352
|
+
// established idiom.
|
|
353
|
+
const [prevPlanKey, setPrevPlanKey] = useState(panelPlanKey);
|
|
354
|
+
if (panelPlanKey !== prevPlanKey) {
|
|
355
|
+
setPrevPlanKey(panelPlanKey);
|
|
356
|
+
setOpenPlanExecutionId(null);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// The unified-panel controller: owns the open-editor group store, the
|
|
360
|
+
// open/collapsed state, and the rail-view FSM. Shared with the launcher
|
|
361
|
+
// (DD-016). The editor store is owned here (never subscribed at this level)
|
|
362
|
+
// so opening/switching files re-renders only the panel subtree — the
|
|
363
|
+
// SessionPanelRegion subscribes, not the conversation column — preserving
|
|
364
|
+
// streaming render isolation (DD-009/DD-010, invariant 2).
|
|
365
|
+
const panel = useSessionPanel({
|
|
366
|
+
phase: hasPhase ? phase : null,
|
|
367
|
+
hasChanges: hasWriteBacks,
|
|
368
|
+
planKey: panelPlanKey,
|
|
369
|
+
});
|
|
370
|
+
|
|
173
371
|
const handleBuildFromPlan = useCallback(() => {
|
|
174
372
|
// Switch the picker to Agent (so subsequent turns stay in Agent) and submit
|
|
175
|
-
// the implement message
|
|
373
|
+
// the implement message through the composer's full pipeline.
|
|
176
374
|
// `interactionMode: "agent"` is passed explicitly to win the same-tick race
|
|
177
375
|
// where the composer prop has not yet re-rendered from "plan".
|
|
178
376
|
setInteractionMode("agent");
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
377
|
+
setPlanAttachFailed(false);
|
|
378
|
+
|
|
379
|
+
// `buildFromPlan` (not message text) is what tells the runner to inject
|
|
380
|
+
// the implement directive and the thread to render the compact chip —
|
|
381
|
+
// with or without the attachment (the runner picks the directive variant).
|
|
382
|
+
const submitImplementTurn = (attachments?: AttachmentInput[]) => {
|
|
383
|
+
composerRef.current?.submit(BUILD_FROM_PLAN_MESSAGE, {
|
|
384
|
+
interactionMode: "agent",
|
|
385
|
+
buildFromPlan: true,
|
|
386
|
+
attachments,
|
|
387
|
+
});
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
// No published artifact (the bare-CTA fallback card) — nothing to attach.
|
|
391
|
+
if (!sessionPlan) {
|
|
392
|
+
submitImplementTurn();
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Deterministic handoff: upload the APPROVED plan (draft if edited, else
|
|
397
|
+
// the artifact text — one uniform path) and attach it to the implement
|
|
398
|
+
// execution. The published artifact itself stays immutable; the approved
|
|
399
|
+
// copy is a new input on the build turn (edit-as-input provenance).
|
|
400
|
+
setIsBuildingFromPlan(true);
|
|
401
|
+
void (async () => {
|
|
402
|
+
try {
|
|
403
|
+
const approvedText =
|
|
404
|
+
planDraft.readDraft() ?? (await fetchPlanText(stigmer, sessionPlan));
|
|
405
|
+
const response = await stigmer.agentExecution.uploadAttachment(
|
|
406
|
+
create(UploadAttachmentRequestSchema, {
|
|
407
|
+
filename: PLAN_ARTIFACT_NAME,
|
|
408
|
+
content: new TextEncoder().encode(approvedText),
|
|
409
|
+
contentType: "text/markdown",
|
|
410
|
+
}),
|
|
411
|
+
);
|
|
412
|
+
submitImplementTurn([
|
|
413
|
+
{
|
|
414
|
+
filename: PLAN_ARTIFACT_NAME,
|
|
415
|
+
storageKey: response.storageKey,
|
|
416
|
+
mountPath: APPROVED_PLAN_MOUNT_PATH,
|
|
417
|
+
contentType: "text/markdown",
|
|
418
|
+
},
|
|
419
|
+
]);
|
|
420
|
+
} catch {
|
|
421
|
+
// Attachment plumbing must never block the build: implement from
|
|
422
|
+
// conversation history alone, and say so (non-blocking notice).
|
|
423
|
+
setPlanAttachFailed(true);
|
|
424
|
+
submitImplementTurn();
|
|
425
|
+
} finally {
|
|
426
|
+
setIsBuildingFromPlan(false);
|
|
427
|
+
}
|
|
428
|
+
})();
|
|
429
|
+
}, [setInteractionMode, sessionPlan, planDraft.readDraft, stigmer]);
|
|
430
|
+
|
|
431
|
+
// "Open plan" (a thread plan card, or the Artifacts facet's plan.md) → the
|
|
432
|
+
// panel's plan document tab. Opening the LATEST plan clears the historical
|
|
433
|
+
// selection (the tab shows the editable current plan); any other execution
|
|
434
|
+
// id opens that turn's plan read-only in the same tab.
|
|
435
|
+
const handleOpenPlan = useCallback(
|
|
436
|
+
(executionId: string) => {
|
|
437
|
+
setOpenPlanExecutionId(
|
|
438
|
+
sessionPlan && executionId === sessionPlan.executionId
|
|
439
|
+
? null
|
|
440
|
+
: executionId,
|
|
441
|
+
);
|
|
442
|
+
panel.openPlanDocument();
|
|
443
|
+
},
|
|
444
|
+
[sessionPlan, panel.openPlanDocument],
|
|
445
|
+
);
|
|
446
|
+
|
|
447
|
+
// Open a transcript tool-call file path in the panel's read-only editor.
|
|
448
|
+
// Resolves the (possibly absolute / subdir-prefixed) path to a
|
|
449
|
+
// repo/root-relative selection the editor can fetch; on a definite hit it
|
|
450
|
+
// opens the file (expanding the panel) and returns `true` (handled),
|
|
451
|
+
// otherwise returns `false` so the path keeps its default copy / GitHub-link
|
|
452
|
+
// behavior. Writing the editor store re-renders only the panel subtree
|
|
453
|
+
// (which subscribes), never this streaming column.
|
|
454
|
+
const handleTranscriptFilePathClick = useCallback(
|
|
455
|
+
(path: string): boolean => {
|
|
456
|
+
const selection = resolveWorkspaceFileSelection(
|
|
457
|
+
path,
|
|
458
|
+
flow.workspace.entries,
|
|
459
|
+
flow.sandboxWorkspaceRoot,
|
|
460
|
+
);
|
|
461
|
+
if (!selection) return false;
|
|
462
|
+
panel.openFile(selection.entryId, selection.path);
|
|
463
|
+
return true;
|
|
464
|
+
},
|
|
465
|
+
[flow.workspace.entries, flow.sandboxWorkspaceRoot, panel.openFile],
|
|
466
|
+
);
|
|
183
467
|
|
|
184
468
|
if (conv.isLoading) {
|
|
185
469
|
return (
|
|
@@ -199,22 +483,36 @@ export function SessionViewer({
|
|
|
199
483
|
|
|
200
484
|
return (
|
|
201
485
|
<div className={cn("relative flex h-full w-full flex-col", className)}>
|
|
202
|
-
{
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
486
|
+
{/* Top-right controls: host actions + the panel chip. The chip is the
|
|
487
|
+
panel's always-mounted toggle; while collapsed it carries only the
|
|
488
|
+
pending-item count. Execution status is never surfaced as header
|
|
489
|
+
chrome — the thread itself communicates run state. */}
|
|
490
|
+
<div className="absolute top-2 right-6 z-10 flex items-center gap-2">
|
|
491
|
+
{headerActions}
|
|
492
|
+
<SessionPanelChip
|
|
493
|
+
isOpen={panel.isOpen}
|
|
494
|
+
onToggle={panel.isOpen ? panel.closePanel : panel.openPanel}
|
|
495
|
+
badgeCount={writeBackCount + artifactCount}
|
|
496
|
+
/>
|
|
497
|
+
</div>
|
|
207
498
|
|
|
208
499
|
<ThreadSelectionContext.Provider value={selectionStore}>
|
|
500
|
+
{/* One layout, collapsed by default: chat fills the row until the panel
|
|
501
|
+
opens, then becomes the fixed narrow pane on the left while the
|
|
502
|
+
panel takes the flexible region. Collapsing goes through the
|
|
503
|
+
split's `collapsedPane` (CSS, not conditional structure), so the
|
|
504
|
+
conversation is always the same first child and an open/close never
|
|
505
|
+
remounts it (invariant 1). */}
|
|
209
506
|
<ResizableSplit
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
507
|
+
resizablePane="primary"
|
|
508
|
+
collapsedPane={panel.isOpen ? "none" : "secondary"}
|
|
509
|
+
defaultSize={420}
|
|
510
|
+
minSize={320}
|
|
511
|
+
maxSize={640}
|
|
512
|
+
storageKey="stgm-session-chat-width"
|
|
513
|
+
responsiveCollapse={panel.isOpen ? "primary" : "none"}
|
|
514
|
+
ariaLabel="Resize chat panel"
|
|
515
|
+
className="min-h-0 flex-1"
|
|
218
516
|
primary={
|
|
219
517
|
<ConversationColumn
|
|
220
518
|
flow={flow}
|
|
@@ -229,23 +527,37 @@ export function SessionViewer({
|
|
|
229
527
|
enableLocal={enableLocal}
|
|
230
528
|
onBrowseLocalFolder={onBrowseLocalFolder}
|
|
231
529
|
onBuildFromPlan={handleBuildFromPlan}
|
|
530
|
+
onOpenPlan={handleOpenPlan}
|
|
531
|
+
isBuildingFromPlan={isBuildingFromPlan}
|
|
532
|
+
planAttachFailed={planAttachFailed}
|
|
533
|
+
onDismissPlanAttachFailed={() => setPlanAttachFailed(false)}
|
|
534
|
+
onFilePathClick={handleTranscriptFilePathClick}
|
|
232
535
|
isEndUser={isEndUser}
|
|
233
536
|
/>
|
|
234
537
|
}
|
|
235
538
|
secondary={
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
539
|
+
panel.isOpen ? (
|
|
540
|
+
<SessionPanelRegion
|
|
541
|
+
flow={flow}
|
|
542
|
+
org={org}
|
|
543
|
+
panel={panel}
|
|
544
|
+
accessSlot={accessSlot}
|
|
545
|
+
onApplied={onApplied}
|
|
546
|
+
onImplementPlan={handleBuildFromPlan}
|
|
547
|
+
implementPlanDisabled={!conv.canSendFollowUp || isBuildingFromPlan}
|
|
548
|
+
sessionPlan={sessionPlan}
|
|
549
|
+
streamingPlan={streamingPlan}
|
|
550
|
+
planDraft={planDraft}
|
|
551
|
+
openPlanExecutionId={openPlanExecutionId}
|
|
552
|
+
onOpenPlan={handleOpenPlan}
|
|
553
|
+
enableLocal={enableLocal}
|
|
554
|
+
onBrowseLocalFolder={onBrowseLocalFolder}
|
|
555
|
+
workspaceFileLister={workspaceFileLister}
|
|
556
|
+
workspaceFileReader={workspaceFileReader}
|
|
557
|
+
workspaceContentSearcher={workspaceContentSearcher}
|
|
558
|
+
isEndUser={isEndUser}
|
|
559
|
+
/>
|
|
560
|
+
) : null
|
|
249
561
|
}
|
|
250
562
|
/>
|
|
251
563
|
</ThreadSelectionContext.Provider>
|
|
@@ -270,10 +582,23 @@ interface ConversationColumnProps {
|
|
|
270
582
|
readonly enableLocal: boolean;
|
|
271
583
|
readonly onBrowseLocalFolder?: () => Promise<string | null>;
|
|
272
584
|
readonly onBuildFromPlan: () => void;
|
|
585
|
+
/** Opens a plan in the panel's plan document tab (thread card "Open plan"). */
|
|
586
|
+
readonly onOpenPlan: (executionId: string) => void;
|
|
587
|
+
/** True while the approved plan is being uploaded ahead of the build turn. */
|
|
588
|
+
readonly isBuildingFromPlan: boolean;
|
|
589
|
+
/** True when the last build fell back to a message-only implement. */
|
|
590
|
+
readonly planAttachFailed: boolean;
|
|
591
|
+
readonly onDismissPlanAttachFailed: () => void;
|
|
592
|
+
/**
|
|
593
|
+
* Opens a transcript tool-call file path in the Viewer. Returns `true` when it
|
|
594
|
+
* resolved and opened the file (suppressing the link's default), `false` to
|
|
595
|
+
* let the path keep its copy / GitHub-link behavior.
|
|
596
|
+
*/
|
|
597
|
+
readonly onFilePathClick: (path: string) => boolean;
|
|
273
598
|
readonly isEndUser: boolean;
|
|
274
599
|
}
|
|
275
600
|
|
|
276
|
-
function ConversationColumn({
|
|
601
|
+
const ConversationColumn = memo(function ConversationColumn({
|
|
277
602
|
flow,
|
|
278
603
|
modelId,
|
|
279
604
|
setModelId,
|
|
@@ -286,6 +611,11 @@ function ConversationColumn({
|
|
|
286
611
|
enableLocal,
|
|
287
612
|
onBrowseLocalFolder,
|
|
288
613
|
onBuildFromPlan,
|
|
614
|
+
onOpenPlan,
|
|
615
|
+
isBuildingFromPlan,
|
|
616
|
+
planAttachFailed,
|
|
617
|
+
onDismissPlanAttachFailed,
|
|
618
|
+
onFilePathClick,
|
|
289
619
|
isEndUser,
|
|
290
620
|
}: ConversationColumnProps) {
|
|
291
621
|
const { conv } = flow;
|
|
@@ -340,14 +670,20 @@ function ConversationColumn({
|
|
|
340
670
|
showFileReviewRecords
|
|
341
671
|
onEditMessage={conv.isStoppable ? handleEditMessage : undefined}
|
|
342
672
|
workspaceEntries={conv.workspaceEntries}
|
|
673
|
+
onFilePathClick={onFilePathClick}
|
|
343
674
|
sandboxWorkspaceRoot={flow.sandboxWorkspaceRoot}
|
|
344
675
|
onBuildFromPlan={onBuildFromPlan}
|
|
676
|
+
onOpenPlan={onOpenPlan}
|
|
345
677
|
org={org}
|
|
346
|
-
planActionsDisabled={!conv.canSendFollowUp}
|
|
347
|
-
|
|
678
|
+
planActionsDisabled={!conv.canSendFollowUp || isBuildingFromPlan}
|
|
679
|
+
planBuildPending={isBuildingFromPlan}
|
|
680
|
+
contentColumn="center"
|
|
348
681
|
className="flex-1"
|
|
349
682
|
/>
|
|
350
|
-
<div className=
|
|
683
|
+
<div className={CONVERSATION_COLUMN_CLASS}>
|
|
684
|
+
{planAttachFailed && (
|
|
685
|
+
<PlanAttachFailedNotice onDismiss={onDismissPlanAttachFailed} />
|
|
686
|
+
)}
|
|
351
687
|
{conv.isReconnecting && <ReconnectingIndicator />}
|
|
352
688
|
{conv.connectTimedOut && (
|
|
353
689
|
<ConnectTimedOutBanner onRetry={conv.reconnectStream} />
|
|
@@ -407,41 +743,165 @@ function ConversationColumn({
|
|
|
407
743
|
</div>
|
|
408
744
|
</div>
|
|
409
745
|
);
|
|
410
|
-
}
|
|
746
|
+
});
|
|
411
747
|
|
|
412
748
|
// ---------------------------------------------------------------------------
|
|
413
|
-
//
|
|
749
|
+
// Session panel region (right/secondary) — the unified panel's subtree
|
|
414
750
|
// ---------------------------------------------------------------------------
|
|
415
751
|
|
|
416
|
-
interface
|
|
752
|
+
interface SessionPanelRegionProps {
|
|
417
753
|
readonly flow: ReturnType<typeof useSessionPageFlow>;
|
|
418
754
|
readonly org: string;
|
|
419
|
-
|
|
755
|
+
/**
|
|
756
|
+
* The panel controller owned by `SessionViewer`. Its editor store is
|
|
757
|
+
* subscribed here (not at `SessionViewer`) so opening/switching files
|
|
758
|
+
* re-renders only this region, never the conversation column.
|
|
759
|
+
*/
|
|
760
|
+
readonly panel: SessionPanelController;
|
|
761
|
+
/** Host access management control, surfaced in the Config facet. */
|
|
762
|
+
readonly accessSlot?: ReactNode;
|
|
420
763
|
readonly onApplied?: (result: ApplyResourceResult) => void;
|
|
421
|
-
/** Implement a plan
|
|
764
|
+
/** Implement a plan (plan tab primary + Artifacts preview action). */
|
|
422
765
|
readonly onImplementPlan?: () => void;
|
|
423
|
-
readonly
|
|
766
|
+
readonly implementPlanDisabled?: boolean;
|
|
767
|
+
/** The session's latest plan — the plan tab's editable content. */
|
|
768
|
+
readonly sessionPlan?: SessionPlan;
|
|
769
|
+
/**
|
|
770
|
+
* The plan the active turn is writing right now. While present it OWNS the
|
|
771
|
+
* plan tab: the tab renders the live document (`PlanStreamingDocument`)
|
|
772
|
+
* instead of a published plan — the in-flight plan is the newest
|
|
773
|
+
* deliverable, and the snap-back in `SessionViewer` has already cleared any
|
|
774
|
+
* historical selection when this identity appeared.
|
|
775
|
+
*/
|
|
776
|
+
readonly streamingPlan?: SessionStreamingPlan;
|
|
777
|
+
/** Viewer-owned plan draft (survives panel collapse and view switches). */
|
|
778
|
+
readonly planDraft: PlanDraftController;
|
|
779
|
+
/**
|
|
780
|
+
* Which plan the plan document tab shows: `null` for the latest (editable),
|
|
781
|
+
* or an execution id whose historical plan renders read-only.
|
|
782
|
+
*/
|
|
783
|
+
readonly openPlanExecutionId: string | null;
|
|
784
|
+
/** Opens a plan in the plan tab (routed to the Artifacts facet's plan.md). */
|
|
785
|
+
readonly onOpenPlan: (executionId: string) => void;
|
|
424
786
|
readonly enableLocal: boolean;
|
|
425
|
-
readonly gitHubConnection?: UseGitHubConnectionReturn;
|
|
426
787
|
readonly onBrowseLocalFolder?: () => Promise<string | null>;
|
|
427
788
|
readonly workspaceFileLister?: WorkspaceFileLister;
|
|
789
|
+
readonly workspaceFileReader?: WorkspaceFileReader;
|
|
790
|
+
readonly workspaceContentSearcher?: WorkspaceContentSearcher;
|
|
428
791
|
readonly isEndUser: boolean;
|
|
429
792
|
}
|
|
430
793
|
|
|
431
|
-
function
|
|
794
|
+
function SessionPanelRegion({
|
|
432
795
|
flow,
|
|
433
796
|
org,
|
|
434
|
-
|
|
797
|
+
panel,
|
|
798
|
+
accessSlot,
|
|
435
799
|
onApplied,
|
|
436
800
|
onImplementPlan,
|
|
437
|
-
|
|
801
|
+
implementPlanDisabled,
|
|
802
|
+
sessionPlan,
|
|
803
|
+
streamingPlan,
|
|
804
|
+
planDraft,
|
|
805
|
+
openPlanExecutionId,
|
|
806
|
+
onOpenPlan,
|
|
438
807
|
enableLocal,
|
|
439
|
-
gitHubConnection,
|
|
440
808
|
onBrowseLocalFolder,
|
|
441
809
|
workspaceFileLister,
|
|
810
|
+
workspaceFileReader,
|
|
811
|
+
workspaceContentSearcher,
|
|
442
812
|
isEndUser,
|
|
443
|
-
}:
|
|
813
|
+
}: SessionPanelRegionProps) {
|
|
444
814
|
const selectedItem = useSelectedThreadItem();
|
|
815
|
+
const { editors, activeKey, activeFile, reveal } = useWorkspaceEditors(
|
|
816
|
+
panel.editorsStore,
|
|
817
|
+
);
|
|
818
|
+
|
|
819
|
+
// Honor a pending jump-to-line reveal only while it targets the active editor
|
|
820
|
+
// (an EditorReveal is structurally a RevealTarget). Switching tabs changes
|
|
821
|
+
// activeKey, so a stale reveal for another tab is naturally ignored.
|
|
822
|
+
const activeReveal =
|
|
823
|
+
reveal && reveal.key === activeKey ? reveal : undefined;
|
|
824
|
+
|
|
825
|
+
// This region is the level that subscribes to thread selection; report it to
|
|
826
|
+
// the controller so an open panel can auto-surface the Inspect view. (A
|
|
827
|
+
// collapsed panel never sees — and deliberately never reacts to — selection.)
|
|
828
|
+
useEffect(() => {
|
|
829
|
+
panel.notifySelection(selectedItem);
|
|
830
|
+
}, [selectedItem, panel.notifySelection]);
|
|
831
|
+
|
|
832
|
+
// Correlate the active file with its session change for diff-as-default
|
|
833
|
+
// (DD-06 parity with the transcript's rendering of the same change). A
|
|
834
|
+
// virtual document (the plan tab) is not a workspace file — pass `null` so
|
|
835
|
+
// the hook's no-file guard skips the net-change fold entirely, rather than
|
|
836
|
+
// relying on the correlation harmlessly missing the sentinel id.
|
|
837
|
+
const openFileChange = useOpenFileChange(
|
|
838
|
+
activeFile && !isVirtualEntryId(activeFile.entryId) ? activeFile : null,
|
|
839
|
+
flow.allExecutions,
|
|
840
|
+
flow.workspace.entries,
|
|
841
|
+
flow.sandboxWorkspaceRoot,
|
|
842
|
+
);
|
|
843
|
+
|
|
844
|
+
// Resolve WHICH plan the plan document tab shows: the latest (editable,
|
|
845
|
+
// buildable, draft-backed) unless a historical execution id was opened —
|
|
846
|
+
// that plan renders read-only. A stale id (execution gone, or its plan
|
|
847
|
+
// artifact missing) degrades to the latest rather than an empty tab.
|
|
848
|
+
const openPlan = useMemo<SessionPlan | undefined>(() => {
|
|
849
|
+
if (
|
|
850
|
+
openPlanExecutionId === null ||
|
|
851
|
+
openPlanExecutionId === sessionPlan?.executionId
|
|
852
|
+
) {
|
|
853
|
+
return sessionPlan;
|
|
854
|
+
}
|
|
855
|
+
const execution = flow.allExecutions.find(
|
|
856
|
+
(e) => e.metadata?.id === openPlanExecutionId,
|
|
857
|
+
);
|
|
858
|
+
const artifact = findPlanArtifact(execution);
|
|
859
|
+
return artifact
|
|
860
|
+
? { executionId: openPlanExecutionId, artifact }
|
|
861
|
+
: sessionPlan;
|
|
862
|
+
}, [openPlanExecutionId, sessionPlan, flow.allExecutions]);
|
|
863
|
+
|
|
864
|
+
// The plan document tab (SurfaceVirtualDocument): the panel's editor-area
|
|
865
|
+
// rendering of the session's plan. Three states, in precedence order:
|
|
866
|
+
// a STREAMING plan owns the tab (live document, no actions); otherwise the
|
|
867
|
+
// resolved `openPlan` renders in the editor (keyed by plan identity so
|
|
868
|
+
// switching plans resets view state cleanly); otherwise an honest empty
|
|
869
|
+
// notice (DD-006) — reachable only when a streaming plan auto-opened the
|
|
870
|
+
// tab and its turn then ended without publishing, with no earlier plan to
|
|
871
|
+
// fall back to.
|
|
872
|
+
const openPlanIsLatest = openPlan?.executionId === sessionPlan?.executionId;
|
|
873
|
+
const virtualDocuments = useMemo<readonly SurfaceVirtualDocument[]>(() => {
|
|
874
|
+
return [
|
|
875
|
+
{
|
|
876
|
+
entryId: PLAN_DOCUMENT_ENTRY_ID,
|
|
877
|
+
path: PLAN_DOCUMENT_PATH,
|
|
878
|
+
content: streamingPlan ? (
|
|
879
|
+
<PlanStreamingDocument
|
|
880
|
+
key={`streaming-${streamingPlan.executionId}`}
|
|
881
|
+
displayText={streamingPlan.displayText}
|
|
882
|
+
/>
|
|
883
|
+
) : openPlan ? (
|
|
884
|
+
<PlanEditor
|
|
885
|
+
key={planDraftKey(openPlan)}
|
|
886
|
+
plan={openPlan}
|
|
887
|
+
draft={openPlanIsLatest ? planDraft : undefined}
|
|
888
|
+
onBuildFromPlan={openPlanIsLatest ? onImplementPlan : undefined}
|
|
889
|
+
buildDisabled={implementPlanDisabled}
|
|
890
|
+
readOnly={!openPlanIsLatest}
|
|
891
|
+
/>
|
|
892
|
+
) : (
|
|
893
|
+
<PlanUnavailableNotice />
|
|
894
|
+
),
|
|
895
|
+
},
|
|
896
|
+
];
|
|
897
|
+
}, [
|
|
898
|
+
streamingPlan,
|
|
899
|
+
openPlan,
|
|
900
|
+
openPlanIsLatest,
|
|
901
|
+
planDraft,
|
|
902
|
+
onImplementPlan,
|
|
903
|
+
implementPlanDisabled,
|
|
904
|
+
]);
|
|
445
905
|
|
|
446
906
|
const handleRemoveAgent = useCallback(() => {
|
|
447
907
|
flow.setAgentRef(null);
|
|
@@ -470,7 +930,7 @@ function InspectorPanel({
|
|
|
470
930
|
[flow.skillRefs, flow.setSkillRefs],
|
|
471
931
|
);
|
|
472
932
|
|
|
473
|
-
const sessionConfig = useMemo(
|
|
933
|
+
const sessionConfig = useMemo<SetupTabProps>(
|
|
474
934
|
() => ({
|
|
475
935
|
agentRef: flow.agentRef,
|
|
476
936
|
isDefaultAgent: flow.isDefaultAgent,
|
|
@@ -480,8 +940,8 @@ function InspectorPanel({
|
|
|
480
940
|
harness: flow.harness,
|
|
481
941
|
executionTarget: flow.executionTarget,
|
|
482
942
|
modelId: flow.model[0],
|
|
483
|
-
// End users see the configuration but cannot strip it — the
|
|
484
|
-
//
|
|
943
|
+
// End users see the configuration but cannot strip it — the Config
|
|
944
|
+
// facet renders read-only without mutation callbacks (DD-011).
|
|
485
945
|
mutations: isEndUser
|
|
486
946
|
? undefined
|
|
487
947
|
: {
|
|
@@ -489,42 +949,59 @@ function InspectorPanel({
|
|
|
489
949
|
onRemoveMcp: handleRemoveMcp,
|
|
490
950
|
onRemoveSkill: handleRemoveSkill,
|
|
491
951
|
},
|
|
952
|
+
accessSlot,
|
|
492
953
|
}),
|
|
493
954
|
[
|
|
494
955
|
flow.agentRef, flow.isDefaultAgent, flow.mcpServerUsages, flow.skillRefs,
|
|
495
956
|
flow.sessionVariables, flow.harness, flow.executionTarget, flow.model,
|
|
496
957
|
isEndUser, handleRemoveAgent, handleRemoveMcp, handleRemoveSkill,
|
|
958
|
+
accessSlot,
|
|
497
959
|
],
|
|
498
960
|
);
|
|
499
961
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
)
|
|
962
|
+
// The session facets (Config / Changes / Artifacts / Usage / Inspect) as
|
|
963
|
+
// injected rail views — the full inspector feature set inside one panel.
|
|
964
|
+
const railViews = useSessionRailViews({
|
|
965
|
+
allExecutions: flow.allExecutions,
|
|
966
|
+
org,
|
|
967
|
+
sessionConfig,
|
|
968
|
+
selectedItem,
|
|
969
|
+
onApplied,
|
|
970
|
+
onImplementPlan,
|
|
971
|
+
onOpenPlan,
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
// Explorer-footer folder attach (desktop only — needs the native picker).
|
|
975
|
+
// Same wiring the retired Workspace tab used.
|
|
976
|
+
const canAddLocalFolder = enableLocal && !!onBrowseLocalFolder;
|
|
977
|
+
const handleAddLocalFolder = useCallback(async () => {
|
|
978
|
+
const path = await onBrowseLocalFolder?.();
|
|
979
|
+
if (path) flow.workspace.addLocalPath(path);
|
|
980
|
+
}, [onBrowseLocalFolder, flow.workspace.addLocalPath]);
|
|
513
981
|
|
|
514
982
|
return (
|
|
515
|
-
<
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
983
|
+
<WorkspaceSurface
|
|
984
|
+
entries={flow.workspace.entries}
|
|
985
|
+
lister={workspaceFileLister}
|
|
986
|
+
reader={workspaceFileReader}
|
|
987
|
+
searcher={workspaceContentSearcher}
|
|
988
|
+
view={panel.view}
|
|
989
|
+
onViewChange={panel.setView}
|
|
990
|
+
extraViews={railViews}
|
|
991
|
+
virtualDocuments={virtualDocuments}
|
|
992
|
+
onRemoveEntry={flow.workspace.remove}
|
|
993
|
+
onAddLocalFolder={canAddLocalFolder ? handleAddLocalFolder : undefined}
|
|
994
|
+
editors={editors}
|
|
995
|
+
selectedFile={activeFile}
|
|
996
|
+
onOpenFile={panel.openFile}
|
|
997
|
+
onActivateEditor={panel.activateEditor}
|
|
998
|
+
onPinEditor={panel.pinEditor}
|
|
999
|
+
onCloseEditor={panel.closeEditor}
|
|
1000
|
+
onCollapse={panel.closePanel}
|
|
1001
|
+
change={openFileChange ?? undefined}
|
|
1002
|
+
reveal={activeReveal}
|
|
1003
|
+
className="h-full"
|
|
1004
|
+
/>
|
|
528
1005
|
);
|
|
529
1006
|
}
|
|
530
1007
|
|
|
@@ -593,6 +1070,56 @@ function AutoApproveIndicator({ onTurnOff }: { onTurnOff: () => void }) {
|
|
|
593
1070
|
);
|
|
594
1071
|
}
|
|
595
1072
|
|
|
1073
|
+
/**
|
|
1074
|
+
* The plan document tab's empty state — reachable only when a streaming plan
|
|
1075
|
+
* auto-opened the tab and its turn then ended without publishing (stopped or
|
|
1076
|
+
* failed) while the session has no earlier published plan to fall back to.
|
|
1077
|
+
* The partial plan reverts to the conversation (the thread un-collapses it),
|
|
1078
|
+
* so the notice points there. Never a blank pane (DD-006).
|
|
1079
|
+
*/
|
|
1080
|
+
function PlanUnavailableNotice() {
|
|
1081
|
+
return (
|
|
1082
|
+
<div
|
|
1083
|
+
role="status"
|
|
1084
|
+
className="mx-auto flex w-full max-w-3xl flex-col items-center gap-1 px-4 py-8 text-center"
|
|
1085
|
+
>
|
|
1086
|
+
<p className="text-xs font-medium text-foreground">
|
|
1087
|
+
This turn ended before a plan was completed.
|
|
1088
|
+
</p>
|
|
1089
|
+
<p className="text-xs text-muted-foreground">
|
|
1090
|
+
Any partial plan text remains in the conversation.
|
|
1091
|
+
</p>
|
|
1092
|
+
</div>
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* Non-blocking notice for a build that fell back to message-only implement
|
|
1098
|
+
* (the approved plan.md could not be uploaded/attached). The build itself
|
|
1099
|
+
* proceeded — the agent follows the plan from conversation history — so this
|
|
1100
|
+
* is a status, not an alert, and it is dismissible.
|
|
1101
|
+
*/
|
|
1102
|
+
function PlanAttachFailedNotice({ onDismiss }: { onDismiss: () => void }) {
|
|
1103
|
+
return (
|
|
1104
|
+
<div
|
|
1105
|
+
role="status"
|
|
1106
|
+
className="flex items-center gap-2 border-t border-border-muted px-4 py-1.5 text-xs text-muted-foreground"
|
|
1107
|
+
>
|
|
1108
|
+
<span className="min-w-0 flex-1 truncate">
|
|
1109
|
+
Couldn’t attach plan.md — the agent will follow the plan from the
|
|
1110
|
+
conversation instead.
|
|
1111
|
+
</span>
|
|
1112
|
+
<button
|
|
1113
|
+
type="button"
|
|
1114
|
+
onClick={onDismiss}
|
|
1115
|
+
className="shrink-0 rounded font-medium text-foreground underline-offset-2 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
1116
|
+
>
|
|
1117
|
+
Dismiss
|
|
1118
|
+
</button>
|
|
1119
|
+
</div>
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
|
|
596
1123
|
function SendErrorBanner({ error }: { error: Error }) {
|
|
597
1124
|
if (isSecretFlowError(error)) {
|
|
598
1125
|
return <SecretFlowErrorGuide error={error} className="mx-4 my-2" />;
|