@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
|
@@ -194,6 +194,23 @@ describe("MessageEntry — Human messages", () => {
|
|
|
194
194
|
});
|
|
195
195
|
});
|
|
196
196
|
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
198
|
+
// Build-from-plan turns — no special human-message treatment
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
|
|
201
|
+
describe("MessageEntry — Build-from-plan turns", () => {
|
|
202
|
+
it("renders any human message as the ordinary prompt bubble (the thread hides build turns before they reach MessageEntry)", () => {
|
|
203
|
+
// The retired chip treatment lived here; today buildThreadItems skips
|
|
204
|
+
// synthesizing the prompt item for a build turn entirely, so a human
|
|
205
|
+
// message that DOES reach MessageEntry is always ordinary prose.
|
|
206
|
+
const msg = makeMessage(MessageType.MESSAGE_HUMAN, "Build from plan");
|
|
207
|
+
const { container } = render(<MessageEntry message={msg} />);
|
|
208
|
+
|
|
209
|
+
expect(queryArticle(container, "User message")).not.toBeNull();
|
|
210
|
+
expect(queryArticle(container, "Build from plan")).toBeNull();
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
197
214
|
// ---------------------------------------------------------------------------
|
|
198
215
|
// System messages — unchanged
|
|
199
216
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { renderHook, act, waitFor } from "@testing-library/react";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import type { Stigmer } from "@stigmer/sdk";
|
|
5
|
+
import { StigmerContext } from "../../context";
|
|
6
|
+
import { useArtifactCopy } from "../useArtifactCopy";
|
|
7
|
+
|
|
8
|
+
function wrapperFor(stigmer: Stigmer) {
|
|
9
|
+
return ({ children }: { children: ReactNode }) => (
|
|
10
|
+
<StigmerContext.Provider value={stigmer}>{children}</StigmerContext.Provider>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function makeStigmer(getArtifactContent = vi.fn()) {
|
|
15
|
+
return { agentExecution: { getArtifactContent } } as unknown as Stigmer;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const writeText = vi.fn().mockResolvedValue(undefined);
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
writeText.mockClear();
|
|
22
|
+
vi.stubGlobal("navigator", { clipboard: { writeText } });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe("useArtifactCopy", () => {
|
|
26
|
+
it("fetches content at click time and writes decoded text to the clipboard", async () => {
|
|
27
|
+
const bytes = new TextEncoder().encode("# Plan\n\nsteps");
|
|
28
|
+
const fn = vi.fn().mockResolvedValue({ content: bytes });
|
|
29
|
+
const { result } = renderHook(() => useArtifactCopy("aex_1"), {
|
|
30
|
+
wrapper: wrapperFor(makeStigmer(fn)),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
expect(result.current.copied).toBe(false);
|
|
34
|
+
await act(async () => {
|
|
35
|
+
await result.current.copy("artifacts/aex_1/plan.md");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
39
|
+
const req = fn.mock.calls[0][0];
|
|
40
|
+
expect(req.executionId).toBe("aex_1");
|
|
41
|
+
expect(req.storageKey).toBe("artifacts/aex_1/plan.md");
|
|
42
|
+
expect(writeText).toHaveBeenCalledWith("# Plan\n\nsteps");
|
|
43
|
+
expect(result.current.copied).toBe(true);
|
|
44
|
+
expect(result.current.error).toBeNull();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("resets the copied flag after the feedback window", async () => {
|
|
48
|
+
vi.useFakeTimers();
|
|
49
|
+
const bytes = new TextEncoder().encode("x");
|
|
50
|
+
const fn = vi.fn().mockResolvedValue({ content: bytes });
|
|
51
|
+
const { result } = renderHook(() => useArtifactCopy("aex_1"), {
|
|
52
|
+
wrapper: wrapperFor(makeStigmer(fn)),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await act(async () => {
|
|
56
|
+
await result.current.copy("artifacts/aex_1/plan.md");
|
|
57
|
+
});
|
|
58
|
+
expect(result.current.copied).toBe(true);
|
|
59
|
+
|
|
60
|
+
act(() => {
|
|
61
|
+
vi.advanceTimersByTime(2000);
|
|
62
|
+
});
|
|
63
|
+
expect(result.current.copied).toBe(false);
|
|
64
|
+
vi.useRealTimers();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("is a no-op when the execution id is unknown", async () => {
|
|
68
|
+
const fn = vi.fn();
|
|
69
|
+
const { result } = renderHook(() => useArtifactCopy(null), {
|
|
70
|
+
wrapper: wrapperFor(makeStigmer(fn)),
|
|
71
|
+
});
|
|
72
|
+
await act(async () => {
|
|
73
|
+
await result.current.copy("artifacts/x/plan.md");
|
|
74
|
+
});
|
|
75
|
+
expect(fn).not.toHaveBeenCalled();
|
|
76
|
+
expect(writeText).not.toHaveBeenCalled();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("surfaces an error when the content RPC fails", async () => {
|
|
80
|
+
const fn = vi.fn().mockRejectedValue(new Error("boom"));
|
|
81
|
+
const { result } = renderHook(() => useArtifactCopy("aex_1"), {
|
|
82
|
+
wrapper: wrapperFor(makeStigmer(fn)),
|
|
83
|
+
});
|
|
84
|
+
await act(async () => {
|
|
85
|
+
await result.current.copy("artifacts/aex_1/plan.md");
|
|
86
|
+
});
|
|
87
|
+
await waitFor(() => expect(result.current.error?.message).toBe("boom"));
|
|
88
|
+
expect(result.current.copied).toBe(false);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -38,6 +38,8 @@ describe("useArtifactDownload", () => {
|
|
|
38
38
|
const req = fn.mock.calls[0][0];
|
|
39
39
|
expect(req.executionId).toBe("aex_1");
|
|
40
40
|
expect(req.storageKey).toBe("artifacts/aex_1/file.bin");
|
|
41
|
+
// Save-to-disk actions force an attachment disposition on the minted URL.
|
|
42
|
+
expect(req.asAttachment).toBe(true);
|
|
41
43
|
expect(result.current.isDownloading).toBe(false);
|
|
42
44
|
expect(result.current.error).toBeNull();
|
|
43
45
|
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { renderHook, act } from "@testing-library/react";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import type { Stigmer } from "@stigmer/sdk";
|
|
5
|
+
import { InteractionMode } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
6
|
+
import { StigmerContext } from "../../context";
|
|
7
|
+
import { useCreateAgentExecution } from "../useCreateAgentExecution";
|
|
8
|
+
|
|
9
|
+
const mockCreate = vi.fn();
|
|
10
|
+
|
|
11
|
+
function makeMockClient(): Stigmer {
|
|
12
|
+
return {
|
|
13
|
+
agentExecution: { create: mockCreate },
|
|
14
|
+
} as unknown as Stigmer;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function createWrapper(client: Stigmer) {
|
|
18
|
+
return function Wrapper({ children }: { children: ReactNode }) {
|
|
19
|
+
return <StigmerContext.Provider value={client}>{children}</StigmerContext.Provider>;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
vi.clearAllMocks();
|
|
25
|
+
mockCreate.mockResolvedValue({ metadata: { id: "aex-1" } });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe("useCreateAgentExecution — executionConfig mapping", () => {
|
|
29
|
+
it("maps buildFromPlan into executionConfig (the Build-from-plan turn)", async () => {
|
|
30
|
+
const { result } = renderHook(() => useCreateAgentExecution(), {
|
|
31
|
+
wrapper: createWrapper(makeMockClient()),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
await act(async () => {
|
|
35
|
+
await result.current.create({
|
|
36
|
+
org: "acme",
|
|
37
|
+
sessionId: "ses-1",
|
|
38
|
+
message: "Build from plan",
|
|
39
|
+
interactionMode: "agent",
|
|
40
|
+
buildFromPlan: true,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
expect(mockCreate).toHaveBeenCalledTimes(1);
|
|
45
|
+
expect(mockCreate.mock.calls[0][0].executionConfig).toMatchObject({
|
|
46
|
+
interactionMode: InteractionMode.AGENT,
|
|
47
|
+
buildFromPlan: true,
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("builds an executionConfig when buildFromPlan is the only config input", async () => {
|
|
52
|
+
const { result } = renderHook(() => useCreateAgentExecution(), {
|
|
53
|
+
wrapper: createWrapper(makeMockClient()),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
await act(async () => {
|
|
57
|
+
await result.current.create({
|
|
58
|
+
org: "acme",
|
|
59
|
+
sessionId: "ses-1",
|
|
60
|
+
message: "Build from plan",
|
|
61
|
+
buildFromPlan: true,
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
expect(mockCreate.mock.calls[0][0].executionConfig).toMatchObject({
|
|
66
|
+
buildFromPlan: true,
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("omits executionConfig entirely for an ordinary message", async () => {
|
|
71
|
+
const { result } = renderHook(() => useCreateAgentExecution(), {
|
|
72
|
+
wrapper: createWrapper(makeMockClient()),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
await act(async () => {
|
|
76
|
+
await result.current.create({
|
|
77
|
+
org: "acme",
|
|
78
|
+
sessionId: "ses-1",
|
|
79
|
+
message: "Hello",
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
expect(mockCreate.mock.calls[0][0].executionConfig).toBeUndefined();
|
|
84
|
+
});
|
|
85
|
+
});
|
package/src/execution/index.ts
CHANGED
|
@@ -41,6 +41,12 @@ export type { PlanCompletionCardProps } from "./PlanCompletionCard.js";
|
|
|
41
41
|
export { PlanArtifactCard } from "./PlanArtifactCard.js";
|
|
42
42
|
export type { PlanArtifactCardProps } from "./PlanArtifactCard.js";
|
|
43
43
|
|
|
44
|
+
export { PlanStreamingCard } from "./PlanStreamingCard.js";
|
|
45
|
+
export type { PlanStreamingCardProps } from "./PlanStreamingCard.js";
|
|
46
|
+
|
|
47
|
+
export { PlanDocumentMessage } from "./PlanDocumentMessage.js";
|
|
48
|
+
export type { PlanDocumentMessageProps } from "./PlanDocumentMessage.js";
|
|
49
|
+
|
|
44
50
|
export { useExecutionArtifacts } from "./useExecutionArtifacts.js";
|
|
45
51
|
export type { UseExecutionArtifactsReturn } from "./useExecutionArtifacts.js";
|
|
46
52
|
|
|
@@ -56,6 +62,9 @@ export type {
|
|
|
56
62
|
export { useArtifactDownload } from "./useArtifactDownload.js";
|
|
57
63
|
export type { UseArtifactDownloadReturn } from "./useArtifactDownload.js";
|
|
58
64
|
|
|
65
|
+
export { useArtifactCopy } from "./useArtifactCopy.js";
|
|
66
|
+
export type { UseArtifactCopyReturn } from "./useArtifactCopy.js";
|
|
67
|
+
|
|
59
68
|
export { useToolOutputContent } from "./useToolOutputContent.js";
|
|
60
69
|
export type {
|
|
61
70
|
UseToolOutputContentReturn,
|
|
@@ -160,7 +169,7 @@ export { MessageEntry } from "./MessageEntry.js";
|
|
|
160
169
|
export type { MessageEntryProps } from "./MessageEntry.js";
|
|
161
170
|
|
|
162
171
|
export { MessageThread } from "./MessageThread.js";
|
|
163
|
-
export type { MessageThreadProps } from "./MessageThread.js";
|
|
172
|
+
export type { MessageThreadProps, ThreadContentColumn } from "./MessageThread.js";
|
|
164
173
|
|
|
165
174
|
export { ThreadSkeleton } from "./ThreadSkeleton.js";
|
|
166
175
|
export type { ThreadSkeletonProps } from "./ThreadSkeleton.js";
|
|
@@ -224,6 +233,9 @@ export type { FileReviewCardProps } from "./FileReviewCard.js";
|
|
|
224
233
|
export { FileReviewDock } from "./FileReviewDock.js";
|
|
225
234
|
export type { FileReviewDockProps } from "./FileReviewDock.js";
|
|
226
235
|
|
|
236
|
+
export { FileChangeProgressBar } from "./FileChangeProgressBar.js";
|
|
237
|
+
export type { FileChangeProgressBarProps } from "./FileChangeProgressBar.js";
|
|
238
|
+
|
|
227
239
|
export { ApprovalContext, useApproval } from "./ApprovalContext.js";
|
|
228
240
|
export type { ApprovalContextValue, UseApprovalResult } from "./ApprovalContext.js";
|
|
229
241
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { useCallback, type KeyboardEvent } from "react";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Card-scoped `Cmd/Ctrl+Enter` accelerator for
|
|
6
|
+
* Card-scoped `Cmd/Ctrl+Enter` accelerator for a plan card's "Build" action.
|
|
7
7
|
*
|
|
8
8
|
* Returns an `onKeyDown` handler for a plan card's root element. Because it is
|
|
9
9
|
* attached to the card (not `window`), it fires only when the keystroke
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { create } from "@bufbuild/protobuf";
|
|
5
|
+
import { GetArtifactContentRequestSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/io_pb";
|
|
6
|
+
import { useStigmer } from "../hooks.js";
|
|
7
|
+
import { toError } from "../internal/toError.js";
|
|
8
|
+
|
|
9
|
+
/** How long the transient `copied` flag stays true after a successful copy. */
|
|
10
|
+
const COPIED_FEEDBACK_MS = 2000;
|
|
11
|
+
|
|
12
|
+
/** Return value of {@link useArtifactCopy}. */
|
|
13
|
+
export interface UseArtifactCopyReturn {
|
|
14
|
+
/**
|
|
15
|
+
* Fetch the artifact's text at click time and write it to the clipboard.
|
|
16
|
+
* No-op when the execution id is unknown or a copy is already in flight.
|
|
17
|
+
* Resolves once the copy has been attempted.
|
|
18
|
+
*
|
|
19
|
+
* @param storageKey - Storage key of the artifact to copy.
|
|
20
|
+
*/
|
|
21
|
+
readonly copy: (storageKey: string) => Promise<void>;
|
|
22
|
+
|
|
23
|
+
/** `true` while the content is being fetched / written to the clipboard. */
|
|
24
|
+
readonly isCopying: boolean;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* `true` for a brief window after a successful copy (drives "Copied"
|
|
28
|
+
* affordance feedback), then resets automatically.
|
|
29
|
+
*/
|
|
30
|
+
readonly copied: boolean;
|
|
31
|
+
|
|
32
|
+
/** Error from the last failed copy attempt, or `null` when healthy. */
|
|
33
|
+
readonly error: Error | null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Behavior hook that copies an execution artifact's text to the clipboard on
|
|
38
|
+
* demand.
|
|
39
|
+
*
|
|
40
|
+
* The imperative sibling of {@link useArtifactDownload}: it fetches content at
|
|
41
|
+
* click time via `getArtifactContent` (CORS-safe, through the Stigmer API)
|
|
42
|
+
* rather than requiring the caller to have loaded it. This suits content-free
|
|
43
|
+
* surfaces — a plan card that detects the artifact by convention and never
|
|
44
|
+
* fetches until the user acts — where a mount-time {@link useArtifactContent}
|
|
45
|
+
* would be wasteful.
|
|
46
|
+
*
|
|
47
|
+
* Returns an imperative `copy(storageKey)` action plus a transient `copied`
|
|
48
|
+
* flag for feedback, mirroring the modal's copy affordance so every surface
|
|
49
|
+
* shares one implementation.
|
|
50
|
+
*
|
|
51
|
+
* @param executionId - Execution that produced the artifacts, or `null` to
|
|
52
|
+
* disable (the action becomes a no-op).
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* const { copy, isCopying, copied } = useArtifactCopy(executionId);
|
|
57
|
+
* <button onClick={() => copy(artifact.storageKey)} disabled={isCopying}>
|
|
58
|
+
* {copied ? "Copied" : "Copy"}
|
|
59
|
+
* </button>
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @see useArtifactDownload — imperative save-to-disk counterpart
|
|
63
|
+
* @see useArtifactContent — declarative content reader (preview rendering)
|
|
64
|
+
*/
|
|
65
|
+
export function useArtifactCopy(
|
|
66
|
+
executionId: string | null,
|
|
67
|
+
): UseArtifactCopyReturn {
|
|
68
|
+
const stigmer = useStigmer();
|
|
69
|
+
const [isCopying, setIsCopying] = useState(false);
|
|
70
|
+
const [copied, setCopied] = useState(false);
|
|
71
|
+
const [error, setError] = useState<Error | null>(null);
|
|
72
|
+
|
|
73
|
+
// Clear the pending "copied" timer on unmount so a resolved copy never sets
|
|
74
|
+
// state on an unmounted component.
|
|
75
|
+
const copiedTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
return () => {
|
|
78
|
+
if (copiedTimer.current !== null) clearTimeout(copiedTimer.current);
|
|
79
|
+
};
|
|
80
|
+
}, []);
|
|
81
|
+
|
|
82
|
+
const copy = useCallback(
|
|
83
|
+
async (storageKey: string) => {
|
|
84
|
+
if (!executionId || !storageKey || isCopying) return;
|
|
85
|
+
setIsCopying(true);
|
|
86
|
+
setError(null);
|
|
87
|
+
try {
|
|
88
|
+
const result = await stigmer.agentExecution.getArtifactContent(
|
|
89
|
+
create(GetArtifactContentRequestSchema, { executionId, storageKey }),
|
|
90
|
+
);
|
|
91
|
+
const text = new TextDecoder().decode(result.content);
|
|
92
|
+
await navigator.clipboard.writeText(text);
|
|
93
|
+
setCopied(true);
|
|
94
|
+
if (copiedTimer.current !== null) clearTimeout(copiedTimer.current);
|
|
95
|
+
copiedTimer.current = setTimeout(() => setCopied(false), COPIED_FEEDBACK_MS);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
setError(toError(err));
|
|
98
|
+
} finally {
|
|
99
|
+
setIsCopying(false);
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
[executionId, stigmer, isCopying],
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
return useMemo(
|
|
106
|
+
() => ({ copy, isCopying, copied, error }),
|
|
107
|
+
[copy, isCopying, copied, error],
|
|
108
|
+
);
|
|
109
|
+
}
|
|
@@ -65,7 +65,16 @@ export function useArtifactDownload(
|
|
|
65
65
|
setError(null);
|
|
66
66
|
try {
|
|
67
67
|
const result = await stigmer.agentExecution.getArtifactDownloadUrl(
|
|
68
|
-
create(GetArtifactDownloadUrlRequestSchema, {
|
|
68
|
+
create(GetArtifactDownloadUrlRequestSchema, {
|
|
69
|
+
executionId,
|
|
70
|
+
storageKey,
|
|
71
|
+
// This is a save-to-disk action, so mint a URL that forces a
|
|
72
|
+
// browser download (Content-Disposition: attachment). Browsers
|
|
73
|
+
// ignore the anchor's `download` attribute cross-origin, so the
|
|
74
|
+
// disposition must ride on the URL itself. Contrast
|
|
75
|
+
// useArtifactDownloadUrl, which stays inline for `<img src>`.
|
|
76
|
+
asAttachment: true,
|
|
77
|
+
}),
|
|
69
78
|
);
|
|
70
79
|
if (result.downloadUrl) {
|
|
71
80
|
triggerBrowserDownload(result.downloadUrl, fileName);
|
|
@@ -86,10 +95,13 @@ export function useArtifactDownload(
|
|
|
86
95
|
}
|
|
87
96
|
|
|
88
97
|
/**
|
|
89
|
-
* Trigger a browser download for a URL via a transient anchor click.
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
98
|
+
* Trigger a browser download for a URL via a transient anchor click.
|
|
99
|
+
*
|
|
100
|
+
* The URL minted for this flow carries `Content-Disposition: attachment`
|
|
101
|
+
* (requested via `asAttachment`), so the browser saves the file even
|
|
102
|
+
* cross-origin — where it would ignore the anchor's `download` attribute. The
|
|
103
|
+
* `download` hint is still set as a same-origin nicety. Falls back to a new tab
|
|
104
|
+
* in non-DOM environments.
|
|
93
105
|
*/
|
|
94
106
|
function triggerBrowserDownload(url: string, fileName?: string): void {
|
|
95
107
|
if (typeof document === "undefined") {
|
|
@@ -54,6 +54,18 @@ export interface CreateAgentExecutionInput {
|
|
|
54
54
|
* Maps to `ExecutionConfig.interaction_mode` in the proto.
|
|
55
55
|
*/
|
|
56
56
|
readonly interactionMode?: "agent" | "plan";
|
|
57
|
+
/**
|
|
58
|
+
* Marks this execution as a Build-from-plan turn: the user approved a
|
|
59
|
+
* plan from a prior Plan-mode execution and asked the agent to implement
|
|
60
|
+
* it. The runner injects the implement-plan directive (pointing at the
|
|
61
|
+
* attached approved plan when present); the thread hides the turn's
|
|
62
|
+
* machine-written message entirely — the plan card above it is the
|
|
63
|
+
* visible cause. Surfaces without that treatment (the CLI, history)
|
|
64
|
+
* show the message text as-is.
|
|
65
|
+
*
|
|
66
|
+
* Maps to `ExecutionConfig.build_from_plan` in the proto.
|
|
67
|
+
*/
|
|
68
|
+
readonly buildFromPlan?: boolean;
|
|
57
69
|
/**
|
|
58
70
|
* Auto-approve every tool call for this execution.
|
|
59
71
|
*
|
|
@@ -158,7 +170,11 @@ export function useCreateAgentExecution(): UseCreateAgentExecutionReturn {
|
|
|
158
170
|
setError(null);
|
|
159
171
|
|
|
160
172
|
try {
|
|
161
|
-
const hasConfig =
|
|
173
|
+
const hasConfig =
|
|
174
|
+
input.modelName ||
|
|
175
|
+
input.interactionMode ||
|
|
176
|
+
input.structuredOutputSchema ||
|
|
177
|
+
input.buildFromPlan;
|
|
162
178
|
const executionConfig = hasConfig
|
|
163
179
|
? {
|
|
164
180
|
...(input.modelName ? { modelName: input.modelName } : {}),
|
|
@@ -168,6 +184,7 @@ export function useCreateAgentExecution(): UseCreateAgentExecutionReturn {
|
|
|
168
184
|
...(input.structuredOutputSchema
|
|
169
185
|
? { structuredOutputSchema: input.structuredOutputSchema }
|
|
170
186
|
: {}),
|
|
187
|
+
...(input.buildFromPlan ? { buildFromPlan: true } : {}),
|
|
171
188
|
}
|
|
172
189
|
: undefined;
|
|
173
190
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
base64ToBytes,
|
|
4
|
+
detectBinary,
|
|
5
|
+
bytesToText,
|
|
6
|
+
normalizeGitHubContent,
|
|
7
|
+
} from "../decodeGitHubContent";
|
|
8
|
+
import { MAX_WORKSPACE_FILE_READ_BYTES } from "../../workspace/WorkspaceFileReader";
|
|
9
|
+
|
|
10
|
+
function utf8(s: string): Uint8Array {
|
|
11
|
+
return new TextEncoder().encode(s);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe("base64ToBytes", () => {
|
|
15
|
+
it("decodes plain base64 to bytes", () => {
|
|
16
|
+
expect(bytesToText(base64ToBytes("SGVsbG8gV29ybGQh"))).toBe("Hello World!");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("strips the newlines GitHub inserts every 60 chars", () => {
|
|
20
|
+
// GitHub's Contents API line-wraps its base64; atob would otherwise reject it.
|
|
21
|
+
const wrapped = "SGVsbG8g\nV29ybGQh\n";
|
|
22
|
+
expect(bytesToText(base64ToBytes(wrapped))).toBe("Hello World!");
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe("detectBinary", () => {
|
|
27
|
+
it("flags a buffer containing a NUL byte", () => {
|
|
28
|
+
expect(detectBinary(new Uint8Array([0x48, 0x00, 0x49]))).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("treats NUL-free text as non-binary", () => {
|
|
32
|
+
expect(detectBinary(utf8("just some text"))).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("only sniffs the head — a NUL past the sniff window is not detected", () => {
|
|
36
|
+
const bytes = new Uint8Array(9000).fill(0x61); // non-zero baseline
|
|
37
|
+
bytes[8500] = 0; // beyond the 8000-byte sniff window
|
|
38
|
+
expect(detectBinary(bytes)).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe("bytesToText", () => {
|
|
43
|
+
it("decodes valid UTF-8", () => {
|
|
44
|
+
expect(bytesToText(utf8("héllo — 世界"))).toBe("héllo — 世界");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("returns null for invalid UTF-8", () => {
|
|
48
|
+
// 0xFF is never a valid UTF-8 lead byte; the fatal decoder throws → null.
|
|
49
|
+
expect(bytesToText(new Uint8Array([0xff]))).toBeNull();
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe("normalizeGitHubContent", () => {
|
|
54
|
+
it("maps clean text to a utf-8 content record with the full size", () => {
|
|
55
|
+
const bytes = utf8("hello");
|
|
56
|
+
expect(normalizeGitHubContent(bytes, bytes.length)).toEqual({
|
|
57
|
+
text: "hello",
|
|
58
|
+
isBinary: false,
|
|
59
|
+
size: bytes.length,
|
|
60
|
+
encoding: "utf-8",
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("reports binary content with text null", () => {
|
|
65
|
+
const result = normalizeGitHubContent(new Uint8Array([0x00, 0x01, 0x02]), 3);
|
|
66
|
+
expect(result).toEqual({
|
|
67
|
+
text: null,
|
|
68
|
+
isBinary: true,
|
|
69
|
+
size: 3,
|
|
70
|
+
encoding: "base64",
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("marks undecodable (non-binary) bytes as unknown encoding", () => {
|
|
75
|
+
// 0xC0 is an invalid UTF-8 lead byte but not a NUL, so it is not "binary".
|
|
76
|
+
const result = normalizeGitHubContent(new Uint8Array([0xc0, 0x41]), 2);
|
|
77
|
+
expect(result).toEqual({
|
|
78
|
+
text: null,
|
|
79
|
+
isBinary: false,
|
|
80
|
+
size: 2,
|
|
81
|
+
encoding: "unknown",
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("truncates at the 1 MB cap and flags it, while size reports the full length", () => {
|
|
86
|
+
const total = MAX_WORKSPACE_FILE_READ_BYTES + 500;
|
|
87
|
+
const bytes = new Uint8Array(total).fill(0x61); // 'a'
|
|
88
|
+
const result = normalizeGitHubContent(bytes, total);
|
|
89
|
+
|
|
90
|
+
expect(result.truncated).toBe(true);
|
|
91
|
+
expect(result.size).toBe(total);
|
|
92
|
+
expect(result.text).toHaveLength(MAX_WORKSPACE_FILE_READ_BYTES);
|
|
93
|
+
expect(result.encoding).toBe("utf-8");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("does not set truncated when exactly at the cap", () => {
|
|
97
|
+
const bytes = new Uint8Array(MAX_WORKSPACE_FILE_READ_BYTES).fill(0x61);
|
|
98
|
+
const result = normalizeGitHubContent(bytes, bytes.length);
|
|
99
|
+
expect(result.truncated).toBeUndefined();
|
|
100
|
+
expect(result.text).toHaveLength(MAX_WORKSPACE_FILE_READ_BYTES);
|
|
101
|
+
});
|
|
102
|
+
});
|