@stigmer/react 3.0.9-dev.20260616060535 → 3.1.0
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/execution/ApprovalCard.d.ts +47 -3
- package/execution/ApprovalCard.d.ts.map +1 -1
- package/execution/ApprovalCard.js +138 -70
- package/execution/ApprovalCard.js.map +1 -1
- package/execution/ApprovalContext.d.ts +72 -0
- package/execution/ApprovalContext.d.ts.map +1 -0
- package/execution/ApprovalContext.js +41 -0
- package/execution/ApprovalContext.js.map +1 -0
- package/execution/ArtifactCard.d.ts.map +1 -1
- package/execution/ArtifactCard.js +3 -1
- package/execution/ArtifactCard.js.map +1 -1
- package/execution/ArtifactPreviewModal.d.ts.map +1 -1
- package/execution/ArtifactPreviewModal.js +5 -3
- package/execution/ArtifactPreviewModal.js.map +1 -1
- package/execution/EmptyChangeNotice.d.ts +38 -0
- package/execution/EmptyChangeNotice.d.ts.map +1 -0
- package/execution/EmptyChangeNotice.js +27 -0
- package/execution/EmptyChangeNotice.js.map +1 -0
- package/execution/FileChangesView.d.ts +81 -0
- package/execution/FileChangesView.d.ts.map +1 -0
- package/execution/FileChangesView.js +164 -0
- package/execution/FileChangesView.js.map +1 -0
- package/execution/FilePathLink.d.ts +24 -4
- package/execution/FilePathLink.d.ts.map +1 -1
- package/execution/FilePathLink.js +31 -9
- package/execution/FilePathLink.js.map +1 -1
- package/execution/FileReviewCard.d.ts +111 -0
- package/execution/FileReviewCard.d.ts.map +1 -0
- package/execution/FileReviewCard.js +558 -0
- package/execution/FileReviewCard.js.map +1 -0
- package/execution/FileReviewContext.d.ts +35 -0
- package/execution/FileReviewContext.d.ts.map +1 -0
- package/execution/FileReviewContext.js +23 -0
- package/execution/FileReviewContext.js.map +1 -0
- package/execution/FileReviewDock.d.ts +73 -0
- package/execution/FileReviewDock.d.ts.map +1 -0
- package/execution/FileReviewDock.js +65 -0
- package/execution/FileReviewDock.js.map +1 -0
- package/execution/McpToolDetail.d.ts.map +1 -1
- package/execution/McpToolDetail.js +38 -5
- package/execution/McpToolDetail.js.map +1 -1
- package/execution/MessageThread.d.ts +42 -3
- package/execution/MessageThread.d.ts.map +1 -1
- package/execution/MessageThread.js +263 -18
- package/execution/MessageThread.js.map +1 -1
- package/execution/PlanArtifactCard.d.ts.map +1 -1
- package/execution/PlanArtifactCard.js +3 -1
- package/execution/PlanArtifactCard.js.map +1 -1
- package/execution/PlanCompletionCard.d.ts +1 -1
- package/execution/PlanCompletionCard.js +1 -1
- package/execution/ResultView.d.ts +19 -1
- package/execution/ResultView.d.ts.map +1 -1
- package/execution/ResultView.js +141 -40
- package/execution/ResultView.js.map +1 -1
- package/execution/SubAgentSection.d.ts.map +1 -1
- package/execution/SubAgentSection.js +45 -6
- package/execution/SubAgentSection.js.map +1 -1
- package/execution/TerminalSession.d.ts +34 -0
- package/execution/TerminalSession.d.ts.map +1 -0
- package/execution/TerminalSession.js +34 -0
- package/execution/TerminalSession.js.map +1 -0
- package/execution/TodoCard.d.ts +53 -0
- package/execution/TodoCard.d.ts.map +1 -0
- package/execution/TodoCard.js +77 -0
- package/execution/TodoCard.js.map +1 -0
- package/execution/ToolArgsView.d.ts +7 -1
- package/execution/ToolArgsView.d.ts.map +1 -1
- package/execution/ToolArgsView.js +10 -9
- package/execution/ToolArgsView.js.map +1 -1
- package/execution/ToolCallDetail.d.ts +10 -1
- package/execution/ToolCallDetail.d.ts.map +1 -1
- package/execution/ToolCallDetail.js +66 -19
- package/execution/ToolCallDetail.js.map +1 -1
- package/execution/ToolCallGroup.d.ts +28 -18
- package/execution/ToolCallGroup.d.ts.map +1 -1
- package/execution/ToolCallGroup.js +39 -148
- package/execution/ToolCallGroup.js.map +1 -1
- package/execution/ToolCallItem.d.ts +36 -8
- package/execution/ToolCallItem.d.ts.map +1 -1
- package/execution/ToolCallItem.js +140 -21
- package/execution/ToolCallItem.js.map +1 -1
- package/execution/ToolRunGroup.d.ts +48 -0
- package/execution/ToolRunGroup.d.ts.map +1 -0
- package/execution/ToolRunGroup.js +168 -0
- package/execution/ToolRunGroup.js.map +1 -0
- package/execution/approval-provenance.d.ts +2 -0
- package/execution/approval-provenance.d.ts.map +1 -0
- package/execution/approval-provenance.js +6 -0
- package/execution/approval-provenance.js.map +1 -0
- package/execution/artifact-utils.d.ts +0 -10
- package/execution/artifact-utils.d.ts.map +1 -1
- package/execution/artifact-utils.js +0 -17
- package/execution/artifact-utils.js.map +1 -1
- package/execution/execution-phases.d.ts +1 -6
- package/execution/execution-phases.d.ts.map +1 -1
- package/execution/execution-phases.js +4 -14
- package/execution/execution-phases.js.map +1 -1
- package/execution/file-path-resolver.d.ts +28 -0
- package/execution/file-path-resolver.d.ts.map +1 -1
- package/execution/file-path-resolver.js +24 -0
- package/execution/file-path-resolver.js.map +1 -1
- package/execution/file-review-status.d.ts +127 -0
- package/execution/file-review-status.d.ts.map +1 -0
- package/execution/file-review-status.js +135 -0
- package/execution/file-review-status.js.map +1 -0
- package/execution/index.d.ts +39 -5
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +23 -3
- package/execution/index.js.map +1 -1
- package/execution/segment-tool-calls.d.ts +46 -0
- package/execution/segment-tool-calls.d.ts.map +1 -0
- package/execution/segment-tool-calls.js +71 -0
- package/execution/segment-tool-calls.js.map +1 -0
- package/execution/tool-categories.d.ts +62 -1
- package/execution/tool-categories.d.ts.map +1 -1
- package/execution/tool-categories.js +96 -2
- package/execution/tool-categories.js.map +1 -1
- package/execution/tool-presenter.d.ts +38 -2
- package/execution/tool-presenter.d.ts.map +1 -1
- package/execution/tool-presenter.js +23 -1
- package/execution/tool-presenter.js.map +1 -1
- package/execution/tool-rendering-primitives.d.ts.map +1 -1
- package/execution/tool-rendering-primitives.js +3 -2
- package/execution/tool-rendering-primitives.js.map +1 -1
- package/execution/useArtifactDownload.d.ts +44 -0
- package/execution/useArtifactDownload.d.ts.map +1 -0
- package/execution/useArtifactDownload.js +80 -0
- package/execution/useArtifactDownload.js.map +1 -0
- package/execution/useArtifactDownloadUrl.d.ts +67 -0
- package/execution/useArtifactDownloadUrl.d.ts.map +1 -0
- package/execution/useArtifactDownloadUrl.js +59 -0
- package/execution/useArtifactDownloadUrl.js.map +1 -0
- package/execution/useFileChangeContent.d.ts +61 -0
- package/execution/useFileChangeContent.d.ts.map +1 -0
- package/execution/useFileChangeContent.js +89 -0
- package/execution/useFileChangeContent.js.map +1 -0
- package/execution/useFileReview.d.ts +89 -0
- package/execution/useFileReview.d.ts.map +1 -0
- package/execution/useFileReview.js +106 -0
- package/execution/useFileReview.js.map +1 -0
- package/execution/useSubmitApproval.d.ts +17 -2
- package/execution/useSubmitApproval.d.ts.map +1 -1
- package/execution/useSubmitApproval.js +27 -23
- package/execution/useSubmitApproval.js.map +1 -1
- package/execution/useToolOutputContent.d.ts +44 -0
- package/execution/useToolOutputContent.d.ts.map +1 -0
- package/execution/useToolOutputContent.js +31 -0
- package/execution/useToolOutputContent.js.map +1 -0
- package/index.d.ts +6 -6
- package/index.d.ts.map +1 -1
- package/index.js +3 -3
- package/index.js.map +1 -1
- package/internal/ApprovalPeekBar.d.ts +23 -0
- package/internal/ApprovalPeekBar.d.ts.map +1 -0
- package/internal/ApprovalPeekBar.js +25 -0
- package/internal/ApprovalPeekBar.js.map +1 -0
- package/internal/BoundedContent.d.ts +49 -0
- package/internal/BoundedContent.d.ts.map +1 -0
- package/internal/BoundedContent.js +50 -0
- package/internal/BoundedContent.js.map +1 -0
- package/internal/DecisionButton.d.ts +47 -0
- package/internal/DecisionButton.d.ts.map +1 -0
- package/internal/DecisionButton.js +42 -0
- package/internal/DecisionButton.js.map +1 -0
- package/internal/InCardDecisionError.d.ts +31 -0
- package/internal/InCardDecisionError.d.ts.map +1 -0
- package/internal/InCardDecisionError.js +23 -0
- package/internal/InCardDecisionError.js.map +1 -0
- package/internal/RevealToggle.d.ts +36 -0
- package/internal/RevealToggle.d.ts.map +1 -0
- package/internal/RevealToggle.js +32 -0
- package/internal/RevealToggle.js.map +1 -0
- package/internal/VirtualizedThread.d.ts +7 -1
- package/internal/VirtualizedThread.d.ts.map +1 -1
- package/internal/VirtualizedThread.js +7 -3
- package/internal/VirtualizedThread.js.map +1 -1
- package/internal/useAutoDisclosure.d.ts +34 -0
- package/internal/useAutoDisclosure.d.ts.map +1 -0
- package/internal/useAutoDisclosure.js +53 -0
- package/internal/useAutoDisclosure.js.map +1 -0
- package/internal/useElapsedSince.d.ts +30 -0
- package/internal/useElapsedSince.d.ts.map +1 -0
- package/internal/useElapsedSince.js +70 -0
- package/internal/useElapsedSince.js.map +1 -0
- package/internal/useIsOverflowing.d.ts +30 -0
- package/internal/useIsOverflowing.d.ts.map +1 -0
- package/internal/useIsOverflowing.js +47 -0
- package/internal/useIsOverflowing.js.map +1 -0
- package/internal/useIsTextTruncated.d.ts +24 -0
- package/internal/useIsTextTruncated.d.ts.map +1 -0
- package/internal/useIsTextTruncated.js +41 -0
- package/internal/useIsTextTruncated.js.map +1 -0
- package/internal/useKeyedSubmission.d.ts +49 -0
- package/internal/useKeyedSubmission.d.ts.map +1 -0
- package/internal/useKeyedSubmission.js +67 -0
- package/internal/useKeyedSubmission.js.map +1 -0
- package/package.json +4 -4
- package/session/SessionViewer.d.ts +2 -2
- package/session/SessionViewer.d.ts.map +1 -1
- package/session/SessionViewer.js +10 -4
- package/session/SessionViewer.js.map +1 -1
- package/session/index.d.ts +2 -0
- package/session/index.d.ts.map +1 -1
- package/session/index.js +1 -0
- package/session/index.js.map +1 -1
- package/session/inspector/ChangesTab.d.ts +8 -5
- package/session/inspector/ChangesTab.d.ts.map +1 -1
- package/session/inspector/ChangesTab.js +11 -8
- package/session/inspector/ChangesTab.js.map +1 -1
- package/session/inspector/SessionInspector.d.ts +4 -4
- package/session/inspector/SessionInspector.d.ts.map +1 -1
- package/session/inspector/SessionInspector.js +4 -4
- package/session/inspector/SessionInspector.js.map +1 -1
- package/session/inspector/index.d.ts +0 -2
- package/session/inspector/index.d.ts.map +1 -1
- package/session/inspector/index.js +0 -1
- package/session/inspector/index.js.map +1 -1
- package/session/inspector/useSessionInspector.d.ts +8 -4
- package/session/inspector/useSessionInspector.d.ts.map +1 -1
- package/session/inspector/useSessionInspector.js +27 -20
- package/session/inspector/useSessionInspector.js.map +1 -1
- package/session/useSessionConversation.d.ts +37 -3
- package/session/useSessionConversation.d.ts.map +1 -1
- package/session/useSessionConversation.js +18 -2
- package/session/useSessionConversation.js.map +1 -1
- package/session/useSessionFileChanges.d.ts +74 -0
- package/session/useSessionFileChanges.d.ts.map +1 -0
- package/session/useSessionFileChanges.js +178 -0
- package/session/useSessionFileChanges.js.map +1 -0
- package/src/__tests__/styles-border-layer-invariant.test.ts +105 -0
- package/src/execution/ApprovalCard.tsx +368 -230
- package/src/execution/ApprovalContext.ts +109 -0
- package/src/execution/ArtifactCard.tsx +10 -6
- package/src/execution/ArtifactPreviewModal.tsx +12 -6
- package/src/execution/EmptyChangeNotice.tsx +62 -0
- package/src/execution/FileChangesView.tsx +383 -0
- package/src/execution/FilePathLink.tsx +65 -12
- package/src/execution/FileReviewCard.tsx +1118 -0
- package/src/execution/FileReviewContext.ts +53 -0
- package/src/execution/FileReviewDock.tsx +157 -0
- package/src/execution/McpToolDetail.tsx +98 -32
- package/src/execution/MessageThread.tsx +374 -9
- package/src/execution/PlanArtifactCard.tsx +9 -6
- package/src/execution/PlanCompletionCard.tsx +1 -1
- package/src/execution/ResultView.tsx +333 -162
- package/src/execution/SubAgentSection.tsx +58 -11
- package/src/execution/TerminalSession.tsx +91 -0
- package/src/execution/TodoCard.tsx +186 -0
- package/src/execution/ToolArgsView.tsx +28 -17
- package/src/execution/ToolCallDetail.tsx +137 -26
- package/src/execution/ToolCallGroup.tsx +68 -296
- package/src/execution/ToolCallItem.tsx +265 -67
- package/src/execution/ToolRunGroup.tsx +302 -0
- package/src/execution/__tests__/ApprovalCard.test.tsx +395 -5
- package/src/execution/__tests__/ArtifactPreviewModal.test.tsx +0 -1
- package/src/execution/__tests__/EmptyChangeNotice.test.tsx +24 -0
- package/src/execution/__tests__/FileChangesView.test.tsx +296 -0
- package/src/execution/__tests__/FilePathLink.test.tsx +92 -0
- package/src/execution/__tests__/FileReviewCard.test.tsx +1044 -0
- package/src/execution/__tests__/FileReviewDock.test.tsx +134 -0
- package/src/execution/__tests__/McpToolDetail.test.tsx +79 -0
- package/src/execution/__tests__/MessageThread.test.tsx +324 -0
- package/src/execution/__tests__/PlanArtifactCard.test.tsx +37 -16
- package/src/execution/__tests__/ResultView.test.tsx +280 -2
- package/src/execution/__tests__/SubAgentSection.test.tsx +180 -0
- package/src/execution/__tests__/TerminalSession.test.tsx +72 -0
- package/src/execution/__tests__/TodoCard.test.tsx +102 -0
- package/src/execution/__tests__/ToolArgsView.test.tsx +48 -0
- package/src/execution/__tests__/ToolCallDetail.test.tsx +195 -0
- package/src/execution/__tests__/ToolCallGroup.test.tsx +132 -0
- package/src/execution/__tests__/ToolCallItem.test.tsx +521 -0
- package/src/execution/__tests__/ToolRunGroup.test.tsx +137 -0
- package/src/execution/__tests__/blanked-narration.test.tsx +149 -0
- package/src/execution/__tests__/buildThreadItems-approvals.test.ts +304 -0
- package/src/execution/__tests__/buildThreadItems-file-review.test.ts +331 -0
- package/src/execution/__tests__/file-path-resolver.test.ts +44 -0
- package/src/execution/__tests__/file-review-status.test.ts +343 -0
- package/src/execution/__tests__/segment-tool-calls.test.ts +124 -0
- package/src/execution/__tests__/subagent-file-review-badge.test.tsx +273 -0
- package/src/execution/__tests__/thread-keys.test.ts +195 -0
- package/src/execution/__tests__/tool-presenter.test.tsx +95 -0
- package/src/execution/__tests__/useArtifactDownload.test.tsx +67 -0
- package/src/execution/__tests__/useArtifactDownloadUrl.test.tsx +51 -0
- package/src/execution/__tests__/useFileChangeContent.test.tsx +240 -0
- package/src/execution/__tests__/useFileReview.test.tsx +236 -0
- package/src/execution/__tests__/useSubmitApproval.test.tsx +165 -0
- package/src/execution/__tests__/useToolOutputContent.test.tsx +82 -0
- package/src/execution/approval-provenance.ts +8 -0
- package/src/execution/artifact-utils.ts +0 -18
- package/src/execution/execution-phases.ts +4 -16
- package/src/execution/file-path-resolver.ts +38 -0
- package/src/execution/file-review-status.ts +219 -0
- package/src/execution/index.ts +84 -4
- package/src/execution/segment-tool-calls.ts +101 -0
- package/src/execution/tool-categories.ts +128 -1
- package/src/execution/tool-presenter.ts +58 -3
- package/src/execution/tool-rendering-primitives.tsx +11 -14
- package/src/execution/useArtifactDownload.ts +109 -0
- package/src/execution/useArtifactDownloadUrl.ts +116 -0
- package/src/execution/useFileChangeContent.ts +149 -0
- package/src/execution/useFileReview.ts +197 -0
- package/src/execution/useSubmitApproval.ts +49 -27
- package/src/execution/useToolOutputContent.ts +70 -0
- package/src/index.ts +60 -1
- package/src/internal/ApprovalPeekBar.tsx +73 -0
- package/src/internal/BoundedContent.tsx +97 -0
- package/src/internal/DecisionButton.tsx +127 -0
- package/src/internal/InCardDecisionError.tsx +47 -0
- package/src/internal/RevealToggle.tsx +91 -0
- package/src/internal/VirtualizedThread.tsx +28 -2
- package/src/internal/__tests__/ApprovalPeekBar.test.tsx +34 -0
- package/src/internal/__tests__/BoundedContent.test.tsx +92 -0
- package/src/internal/__tests__/DecisionButton.test.tsx +107 -0
- package/src/internal/__tests__/RevealToggle.test.tsx +61 -0
- package/src/internal/__tests__/useAutoDisclosure.test.ts +74 -0
- package/src/internal/__tests__/useElapsedSince.test.tsx +68 -0
- package/src/internal/__tests__/useIsOverflowing.test.ts +36 -0
- package/src/internal/__tests__/useKeyedSubmission.test.tsx +126 -0
- package/src/internal/useAutoDisclosure.ts +58 -0
- package/src/internal/useElapsedSince.ts +72 -0
- package/src/internal/useIsOverflowing.ts +61 -0
- package/src/internal/useIsTextTruncated.ts +55 -0
- package/src/internal/useKeyedSubmission.ts +101 -0
- package/src/session/SessionViewer.tsx +21 -4
- package/src/session/__tests__/SessionViewer-fileReviewDock.test.tsx +198 -0
- package/src/session/__tests__/audienceWiring.test.tsx +4 -0
- package/src/session/__tests__/useSessionFileChanges.test.ts +303 -0
- package/src/session/index.ts +3 -0
- package/src/session/inspector/ChangesTab.tsx +20 -17
- package/src/session/inspector/SessionInspector.tsx +12 -10
- package/src/session/inspector/__tests__/ArtifactsTab.test.tsx +0 -1
- package/src/session/inspector/__tests__/ChangesTab.test.tsx +38 -0
- package/src/session/inspector/__tests__/useSessionInspector.test.ts +46 -61
- package/src/session/inspector/index.ts +0 -3
- package/src/session/inspector/useSessionInspector.ts +27 -20
- package/src/session/useSessionConversation.ts +80 -3
- package/src/session/useSessionFileChanges.ts +207 -0
- package/src/styles.css +35 -10
- package/src/version-history/DiffViewer.tsx +10 -7
- package/src/version-history/UnifiedDiffView.tsx +66 -0
- package/src/version-history/__tests__/DiffViewer.test.tsx +57 -0
- package/src/version-history/__tests__/UnifiedDiffView.test.tsx +50 -0
- package/src/version-history/__tests__/computeDiff.test.ts +35 -0
- package/src/version-history/__tests__/parseUnifiedDiff.test.ts +82 -0
- package/src/version-history/computeDiff.ts +6 -37
- package/src/version-history/diff-hunks.ts +63 -0
- package/src/version-history/index.ts +1 -0
- package/src/version-history/parseUnifiedDiff.ts +34 -0
- package/src/workflow/WorkflowExecutionApprovalCard.tsx +49 -24
- package/src/workflow/WorkflowExecutionTimeline.tsx +15 -4
- package/src/workflow/WorkflowExecutionTimelineEvent.tsx +8 -3
- package/src/workflow/WorkflowExecutionViewer.tsx +72 -28
- package/src/workflow/WorkflowFileReviewList.tsx +152 -0
- package/src/workflow/WorkflowTaskApprovalCard.tsx +37 -85
- package/src/workflow/__tests__/ExecutionInspector.test.tsx +30 -2
- package/src/workflow/__tests__/WorkflowExecutionApprovalCard.test.tsx +129 -0
- package/src/workflow/__tests__/WorkflowFileReviewList.test.tsx +129 -0
- package/src/workflow/__tests__/WorkflowTaskApprovalCard.test.tsx +43 -11
- package/src/workflow/__tests__/useWorkflowExecutionActions.test.tsx +276 -0
- package/src/workflow/execution-inspector/ExecutionInspector.tsx +42 -18
- package/src/workflow/index.ts +5 -0
- package/src/workflow/useWorkflowExecutionActions.ts +177 -29
- package/styles.css +1 -1
- package/version-history/DiffViewer.d.ts.map +1 -1
- package/version-history/DiffViewer.js +9 -3
- package/version-history/DiffViewer.js.map +1 -1
- package/version-history/UnifiedDiffView.d.ts +29 -0
- package/version-history/UnifiedDiffView.d.ts.map +1 -0
- package/version-history/UnifiedDiffView.js +36 -0
- package/version-history/UnifiedDiffView.js.map +1 -0
- package/version-history/computeDiff.d.ts +3 -1
- package/version-history/computeDiff.d.ts.map +1 -1
- package/version-history/computeDiff.js +5 -35
- package/version-history/computeDiff.js.map +1 -1
- package/version-history/diff-hunks.d.ts +21 -0
- package/version-history/diff-hunks.d.ts.map +1 -0
- package/version-history/diff-hunks.js +58 -0
- package/version-history/diff-hunks.js.map +1 -0
- package/version-history/index.d.ts +1 -0
- package/version-history/index.d.ts.map +1 -1
- package/version-history/index.js +1 -0
- package/version-history/index.js.map +1 -1
- package/version-history/parseUnifiedDiff.d.ts +22 -0
- package/version-history/parseUnifiedDiff.d.ts.map +1 -0
- package/version-history/parseUnifiedDiff.js +34 -0
- package/version-history/parseUnifiedDiff.js.map +1 -0
- package/workflow/WorkflowExecutionApprovalCard.d.ts +8 -1
- package/workflow/WorkflowExecutionApprovalCard.d.ts.map +1 -1
- package/workflow/WorkflowExecutionApprovalCard.js +17 -3
- package/workflow/WorkflowExecutionApprovalCard.js.map +1 -1
- package/workflow/WorkflowExecutionTimeline.d.ts +11 -2
- package/workflow/WorkflowExecutionTimeline.d.ts.map +1 -1
- package/workflow/WorkflowExecutionTimeline.js +2 -2
- package/workflow/WorkflowExecutionTimeline.js.map +1 -1
- package/workflow/WorkflowExecutionTimelineEvent.d.ts +4 -1
- package/workflow/WorkflowExecutionTimelineEvent.d.ts.map +1 -1
- package/workflow/WorkflowExecutionTimelineEvent.js +2 -2
- package/workflow/WorkflowExecutionTimelineEvent.js.map +1 -1
- package/workflow/WorkflowExecutionViewer.d.ts.map +1 -1
- package/workflow/WorkflowExecutionViewer.js +18 -10
- package/workflow/WorkflowExecutionViewer.js.map +1 -1
- package/workflow/WorkflowFileReviewList.d.ts +46 -0
- package/workflow/WorkflowFileReviewList.d.ts.map +1 -0
- package/workflow/WorkflowFileReviewList.js +48 -0
- package/workflow/WorkflowFileReviewList.js.map +1 -0
- package/workflow/WorkflowTaskApprovalCard.d.ts +8 -1
- package/workflow/WorkflowTaskApprovalCard.d.ts.map +1 -1
- package/workflow/WorkflowTaskApprovalCard.js +12 -19
- package/workflow/WorkflowTaskApprovalCard.js.map +1 -1
- package/workflow/execution-inspector/ExecutionInspector.d.ts +21 -4
- package/workflow/execution-inspector/ExecutionInspector.d.ts.map +1 -1
- package/workflow/execution-inspector/ExecutionInspector.js +6 -3
- package/workflow/execution-inspector/ExecutionInspector.js.map +1 -1
- package/workflow/index.d.ts +1 -0
- package/workflow/index.d.ts.map +1 -1
- package/workflow/index.js +1 -0
- package/workflow/index.js.map +1 -1
- package/workflow/useWorkflowExecutionActions.d.ts +62 -4
- package/workflow/useWorkflowExecutionActions.d.ts.map +1 -1
- package/workflow/useWorkflowExecutionActions.js +94 -18
- package/workflow/useWorkflowExecutionActions.js.map +1 -1
- package/session/inspector/PlanTab.d.ts +0 -15
- package/session/inspector/PlanTab.d.ts.map +0 -1
- package/session/inspector/PlanTab.js +0 -19
- package/session/inspector/PlanTab.js.map +0 -1
- package/src/session/inspector/PlanTab.tsx +0 -31
|
@@ -13,17 +13,24 @@ const planArtifact = create(ExecutionArtifactSchema, {
|
|
|
13
13
|
kind: ExecutionArtifactKind.FILE,
|
|
14
14
|
sizeBytes: 4500n,
|
|
15
15
|
storageKey: "artifacts/aex_1/plan.md",
|
|
16
|
-
downloadUrl: "https://example.test/plan.md",
|
|
17
16
|
});
|
|
18
17
|
|
|
19
18
|
/** Modal content fetches artifact text — keep it pending so nothing rejects. */
|
|
20
|
-
function createStigmerMock(): {
|
|
19
|
+
function createStigmerMock(): {
|
|
20
|
+
stigmer: Stigmer;
|
|
21
|
+
getArtifactContent: ReturnType<typeof vi.fn>;
|
|
22
|
+
getArtifactDownloadUrl: ReturnType<typeof vi.fn>;
|
|
23
|
+
} {
|
|
21
24
|
const getArtifactContent = vi.fn().mockReturnValue(new Promise(() => {}));
|
|
25
|
+
const getArtifactDownloadUrl = vi
|
|
26
|
+
.fn()
|
|
27
|
+
.mockResolvedValue({ downloadUrl: "https://example.test/plan.md" });
|
|
22
28
|
return {
|
|
23
29
|
stigmer: {
|
|
24
|
-
agentExecution: { getArtifactContent },
|
|
30
|
+
agentExecution: { getArtifactContent, getArtifactDownloadUrl },
|
|
25
31
|
} as unknown as Stigmer,
|
|
26
32
|
getArtifactContent,
|
|
33
|
+
getArtifactDownloadUrl,
|
|
27
34
|
};
|
|
28
35
|
}
|
|
29
36
|
|
|
@@ -33,11 +40,16 @@ function withStigmer(children: ReactNode, stigmer: Stigmer) {
|
|
|
33
40
|
);
|
|
34
41
|
}
|
|
35
42
|
|
|
43
|
+
/** PlanArtifactCard now resolves downloads on demand, so it needs a provider. */
|
|
44
|
+
function renderCard(ui: ReactNode) {
|
|
45
|
+
return render(withStigmer(ui, createStigmerMock().stigmer));
|
|
46
|
+
}
|
|
47
|
+
|
|
36
48
|
afterEach(cleanup);
|
|
37
49
|
|
|
38
50
|
describe("PlanArtifactCard — action surface", () => {
|
|
39
51
|
it("is an accessible region labelled as the plan's actions, with name + size", () => {
|
|
40
|
-
|
|
52
|
+
renderCard(
|
|
41
53
|
<PlanArtifactCard executionId="aex_1" artifact={planArtifact} org="acme" />,
|
|
42
54
|
);
|
|
43
55
|
|
|
@@ -61,7 +73,7 @@ describe("PlanArtifactCard — action surface", () => {
|
|
|
61
73
|
|
|
62
74
|
it("offers exactly one primary 'Build from plan' action that calls onImplement", () => {
|
|
63
75
|
const onImplement = vi.fn();
|
|
64
|
-
|
|
76
|
+
renderCard(
|
|
65
77
|
<PlanArtifactCard
|
|
66
78
|
executionId="aex_1"
|
|
67
79
|
artifact={planArtifact}
|
|
@@ -75,7 +87,7 @@ describe("PlanArtifactCard — action surface", () => {
|
|
|
75
87
|
});
|
|
76
88
|
|
|
77
89
|
it("hides 'Build from plan' when onImplement is not provided", () => {
|
|
78
|
-
|
|
90
|
+
renderCard(
|
|
79
91
|
<PlanArtifactCard executionId="aex_1" artifact={planArtifact} org="acme" />,
|
|
80
92
|
);
|
|
81
93
|
expect(screen.queryByText("Build from plan")).toBeNull();
|
|
@@ -83,7 +95,7 @@ describe("PlanArtifactCard — action surface", () => {
|
|
|
83
95
|
|
|
84
96
|
it("disables 'Build from plan' when disabled", () => {
|
|
85
97
|
const onImplement = vi.fn();
|
|
86
|
-
|
|
98
|
+
renderCard(
|
|
87
99
|
<PlanArtifactCard
|
|
88
100
|
executionId="aex_1"
|
|
89
101
|
artifact={planArtifact}
|
|
@@ -99,19 +111,28 @@ describe("PlanArtifactCard — action surface", () => {
|
|
|
99
111
|
expect(onImplement).not.toHaveBeenCalled();
|
|
100
112
|
});
|
|
101
113
|
|
|
102
|
-
it("
|
|
114
|
+
it("downloads the artifact on demand via a freshly minted URL", async () => {
|
|
115
|
+
const { stigmer, getArtifactDownloadUrl } = createStigmerMock();
|
|
103
116
|
render(
|
|
104
|
-
|
|
117
|
+
withStigmer(
|
|
118
|
+
<PlanArtifactCard executionId="aex_1" artifact={planArtifact} org="acme" />,
|
|
119
|
+
stigmer,
|
|
120
|
+
),
|
|
105
121
|
);
|
|
106
|
-
|
|
107
|
-
|
|
122
|
+
fireEvent.click(screen.getByText("Download"));
|
|
123
|
+
// The URL is resolved at click time from the stable storage key — never a
|
|
124
|
+
// baked, expirable URL.
|
|
125
|
+
expect(getArtifactDownloadUrl).toHaveBeenCalledTimes(1);
|
|
126
|
+
const req = getArtifactDownloadUrl.mock.calls[0][0];
|
|
127
|
+
expect(req.executionId).toBe("aex_1");
|
|
128
|
+
expect(req.storageKey).toBe("artifacts/aex_1/plan.md");
|
|
108
129
|
});
|
|
109
130
|
});
|
|
110
131
|
|
|
111
132
|
describe("PlanArtifactCard — Cmd/Ctrl+Enter accelerator (card-scoped)", () => {
|
|
112
133
|
it("fires onImplement on Cmd+Enter from within the card", () => {
|
|
113
134
|
const onImplement = vi.fn();
|
|
114
|
-
|
|
135
|
+
renderCard(
|
|
115
136
|
<PlanArtifactCard
|
|
116
137
|
executionId="aex_1"
|
|
117
138
|
artifact={planArtifact}
|
|
@@ -127,7 +148,7 @@ describe("PlanArtifactCard — Cmd/Ctrl+Enter accelerator (card-scoped)", () =>
|
|
|
127
148
|
|
|
128
149
|
it("fires onImplement on Ctrl+Enter", () => {
|
|
129
150
|
const onImplement = vi.fn();
|
|
130
|
-
|
|
151
|
+
renderCard(
|
|
131
152
|
<PlanArtifactCard
|
|
132
153
|
executionId="aex_1"
|
|
133
154
|
artifact={planArtifact}
|
|
@@ -143,7 +164,7 @@ describe("PlanArtifactCard — Cmd/Ctrl+Enter accelerator (card-scoped)", () =>
|
|
|
143
164
|
|
|
144
165
|
it("ignores a plain Enter (no modifier) so it never hijacks typing", () => {
|
|
145
166
|
const onImplement = vi.fn();
|
|
146
|
-
|
|
167
|
+
renderCard(
|
|
147
168
|
<PlanArtifactCard
|
|
148
169
|
executionId="aex_1"
|
|
149
170
|
artifact={planArtifact}
|
|
@@ -159,7 +180,7 @@ describe("PlanArtifactCard — Cmd/Ctrl+Enter accelerator (card-scoped)", () =>
|
|
|
159
180
|
|
|
160
181
|
it("does not fire when disabled", () => {
|
|
161
182
|
const onImplement = vi.fn();
|
|
162
|
-
|
|
183
|
+
renderCard(
|
|
163
184
|
<PlanArtifactCard
|
|
164
185
|
executionId="aex_1"
|
|
165
186
|
artifact={planArtifact}
|
|
@@ -197,7 +218,7 @@ describe("PlanArtifactCard — Open full (org-gated preview)", () => {
|
|
|
197
218
|
|
|
198
219
|
it("hides 'Open full' when org is absent (modal needs org), keeping Build + Download", () => {
|
|
199
220
|
const onImplement = vi.fn();
|
|
200
|
-
|
|
221
|
+
renderCard(
|
|
201
222
|
<PlanArtifactCard
|
|
202
223
|
executionId="aex_1"
|
|
203
224
|
artifact={planArtifact}
|
|
@@ -1,10 +1,24 @@
|
|
|
1
|
-
import { describe, it, expect, afterEach } from "vitest";
|
|
2
|
-
import { render, cleanup } from "@testing-library/react";
|
|
1
|
+
import { describe, it, expect, afterEach, vi } from "vitest";
|
|
2
|
+
import { render, cleanup, screen, fireEvent, waitFor } from "@testing-library/react";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import { create, type JsonObject } from "@bufbuild/protobuf";
|
|
5
|
+
import { ToolCallSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
|
|
6
|
+
import {
|
|
7
|
+
ToolCallStatus,
|
|
8
|
+
ToolKind,
|
|
9
|
+
} from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
10
|
+
import { normalizeToolResult } from "@stigmer/sdk";
|
|
3
11
|
import type { ToolResultView } from "@stigmer/sdk";
|
|
12
|
+
import type { Stigmer } from "@stigmer/sdk";
|
|
13
|
+
import { StigmerContext } from "../../context";
|
|
4
14
|
import { ResultView, summarizeResultView } from "../ResultView";
|
|
5
15
|
|
|
6
16
|
afterEach(cleanup);
|
|
7
17
|
|
|
18
|
+
function withStigmer(children: ReactNode, stigmer: Stigmer) {
|
|
19
|
+
return <StigmerContext.Provider value={stigmer}>{children}</StigmerContext.Provider>;
|
|
20
|
+
}
|
|
21
|
+
|
|
8
22
|
describe("ResultView", () => {
|
|
9
23
|
it("renders an edit diff with add/remove counts from the envelope", () => {
|
|
10
24
|
const view: ToolResultView = {
|
|
@@ -30,6 +44,39 @@ describe("ResultView", () => {
|
|
|
30
44
|
expect(container.textContent).toContain("hello world");
|
|
31
45
|
});
|
|
32
46
|
|
|
47
|
+
it("renders a Cursor unifiedDiff through the DiffViewer table, not a raw patch dump", () => {
|
|
48
|
+
const view: ToolResultView = {
|
|
49
|
+
type: "diff",
|
|
50
|
+
path: "/workspace/notes.md",
|
|
51
|
+
unifiedDiff: "--- /dev/null\n+++ b/notes.md\n@@ -0,0 +1,2 @@\n+# Title\n+body\n",
|
|
52
|
+
linesAdded: 2,
|
|
53
|
+
linesRemoved: 0,
|
|
54
|
+
};
|
|
55
|
+
const { container } = render(<ResultView view={view} />);
|
|
56
|
+
// The accessible table renders the content...
|
|
57
|
+
expect(container.querySelector("table")).not.toBeNull();
|
|
58
|
+
expect(container.textContent).toContain("# Title");
|
|
59
|
+
// ...and the raw patch preamble never reaches the screen.
|
|
60
|
+
expect(container.textContent).not.toContain("/dev/null");
|
|
61
|
+
expect(container.textContent).not.toContain("@@");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("suppresses the +N -M stats when showStats is false (owning row shows them)", () => {
|
|
65
|
+
const view: ToolResultView = {
|
|
66
|
+
type: "diff",
|
|
67
|
+
path: "/workspace/x.md",
|
|
68
|
+
oldText: "a",
|
|
69
|
+
newText: "a b",
|
|
70
|
+
};
|
|
71
|
+
const { container } = render(
|
|
72
|
+
<ResultView view={view} showFileName={false} showStats={false} />,
|
|
73
|
+
);
|
|
74
|
+
// The diff content still renders, but the duplicate counts do not.
|
|
75
|
+
expect(container.textContent).toContain("a b");
|
|
76
|
+
expect(container.textContent).not.toContain("+1");
|
|
77
|
+
expect(container.textContent).not.toContain("-0");
|
|
78
|
+
});
|
|
79
|
+
|
|
33
80
|
it("renders a terminal with a non-zero exit badge", () => {
|
|
34
81
|
const view: ToolResultView = {
|
|
35
82
|
type: "terminal",
|
|
@@ -42,6 +89,26 @@ describe("ResultView", () => {
|
|
|
42
89
|
expect(container.textContent).toContain("boom");
|
|
43
90
|
});
|
|
44
91
|
|
|
92
|
+
it("renders a terminal as one session: $ command then output, no badge on success", () => {
|
|
93
|
+
const view: ToolResultView = {
|
|
94
|
+
type: "terminal",
|
|
95
|
+
command: "echo hello",
|
|
96
|
+
stdout: "hello",
|
|
97
|
+
stderr: "",
|
|
98
|
+
exitCode: 0,
|
|
99
|
+
};
|
|
100
|
+
const { container } = render(<ResultView view={view} />);
|
|
101
|
+
// The command leads the session as a prompt line, with its output below.
|
|
102
|
+
expect(container.textContent).toContain("$ echo hello");
|
|
103
|
+
expect(container.textContent).toContain("hello");
|
|
104
|
+
// Success carries no exit badge — the row's status icon confirms the run.
|
|
105
|
+
expect(container.textContent).not.toContain("exit 0");
|
|
106
|
+
// One block, not a command box + a separate output box.
|
|
107
|
+
expect(
|
|
108
|
+
container.querySelectorAll('[data-cursor-target="terminal-session"]'),
|
|
109
|
+
).toHaveLength(1);
|
|
110
|
+
});
|
|
111
|
+
|
|
45
112
|
it("renders a search match list", () => {
|
|
46
113
|
const view: ToolResultView = {
|
|
47
114
|
type: "search",
|
|
@@ -52,6 +119,95 @@ describe("ResultView", () => {
|
|
|
52
119
|
expect(container.textContent).toContain("2 matches");
|
|
53
120
|
});
|
|
54
121
|
|
|
122
|
+
it("renders a file-name search as a clickable file list with a 'files' count", () => {
|
|
123
|
+
const view: ToolResultView = {
|
|
124
|
+
type: "search",
|
|
125
|
+
kind: "files",
|
|
126
|
+
matches: [{ file: "src/a.ts", text: "src/a.ts" }],
|
|
127
|
+
count: 1,
|
|
128
|
+
};
|
|
129
|
+
const { container } = render(<ResultView view={view} />);
|
|
130
|
+
expect(container.textContent).toContain("1 file");
|
|
131
|
+
// The path renders filename-first through FilePathLink (an interactive control).
|
|
132
|
+
expect(container.textContent).toContain("a.ts");
|
|
133
|
+
expect(container.querySelector("button, a")).not.toBeNull();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("renders content matches grouped under their file with line numbers", () => {
|
|
137
|
+
const view: ToolResultView = {
|
|
138
|
+
type: "search",
|
|
139
|
+
kind: "content",
|
|
140
|
+
matches: [
|
|
141
|
+
{ file: "a.ts", line: 12, text: "// TODO: fix" },
|
|
142
|
+
{ file: "a.ts", line: 30, text: "// TODO: later" },
|
|
143
|
+
],
|
|
144
|
+
count: 2,
|
|
145
|
+
};
|
|
146
|
+
const { container } = render(<ResultView view={view} />);
|
|
147
|
+
expect(container.textContent).toContain("2 matches");
|
|
148
|
+
expect(container.textContent).toContain("12:");
|
|
149
|
+
expect(container.textContent).toContain("// TODO: fix");
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("names the subtype in the empty state (files vs matches), query-free", () => {
|
|
153
|
+
const files = render(
|
|
154
|
+
<ResultView view={{ type: "search", kind: "files", matches: [], count: 0 }} />,
|
|
155
|
+
);
|
|
156
|
+
expect(files.container.textContent).toContain("No files found");
|
|
157
|
+
|
|
158
|
+
const content = render(
|
|
159
|
+
<ResultView view={{ type: "search", kind: "content", matches: [], count: 0 }} />,
|
|
160
|
+
);
|
|
161
|
+
expect(content.container.textContent).toContain("No matches");
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("shows a 'showing first N' note when the engine truncated the results", () => {
|
|
165
|
+
const view: ToolResultView = {
|
|
166
|
+
type: "search",
|
|
167
|
+
kind: "files",
|
|
168
|
+
matches: [
|
|
169
|
+
{ file: "a.ts", text: "a.ts" },
|
|
170
|
+
{ file: "b.ts", text: "b.ts" },
|
|
171
|
+
],
|
|
172
|
+
count: 200,
|
|
173
|
+
truncated: true,
|
|
174
|
+
};
|
|
175
|
+
const { container } = render(<ResultView view={view} />);
|
|
176
|
+
expect(container.textContent).toContain("200 files");
|
|
177
|
+
expect(container.textContent).toContain("showing first 2");
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("suppresses the search count when showStats is false (owning row shows it)", () => {
|
|
181
|
+
const view: ToolResultView = {
|
|
182
|
+
type: "search",
|
|
183
|
+
kind: "files",
|
|
184
|
+
matches: [{ file: "Dockerfile", text: "Dockerfile" }],
|
|
185
|
+
count: 1,
|
|
186
|
+
};
|
|
187
|
+
const { container } = render(<ResultView view={view} showStats={false} />);
|
|
188
|
+
// The file still renders, but the redundant "1 file" count does not.
|
|
189
|
+
expect(container.textContent).toContain("Dockerfile");
|
|
190
|
+
expect(container.textContent).not.toContain("1 file");
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it("keeps the truncation note even when the count is suppressed", () => {
|
|
194
|
+
const view: ToolResultView = {
|
|
195
|
+
type: "search",
|
|
196
|
+
kind: "files",
|
|
197
|
+
matches: [
|
|
198
|
+
{ file: "a.ts", text: "a.ts" },
|
|
199
|
+
{ file: "b.ts", text: "b.ts" },
|
|
200
|
+
],
|
|
201
|
+
count: 200,
|
|
202
|
+
truncated: true,
|
|
203
|
+
};
|
|
204
|
+
const { container } = render(<ResultView view={view} showStats={false} />);
|
|
205
|
+
// The count header is gone, but the "showing first N of M" note remains —
|
|
206
|
+
// it is information the row header does not carry.
|
|
207
|
+
expect(container.textContent).not.toContain("200 files");
|
|
208
|
+
expect(container.textContent).toContain("Showing first 2 of 200");
|
|
209
|
+
});
|
|
210
|
+
|
|
55
211
|
it("renders unknown JSON results as a labeled code block, not a raw dump", () => {
|
|
56
212
|
const view: ToolResultView = { type: "json", value: { a: 1 } };
|
|
57
213
|
const { container } = render(<ResultView view={view} />);
|
|
@@ -70,6 +226,119 @@ describe("ResultView", () => {
|
|
|
70
226
|
const { container } = render(<ResultView view={{ type: "empty" }} />);
|
|
71
227
|
expect(container.textContent).toBe("");
|
|
72
228
|
});
|
|
229
|
+
|
|
230
|
+
it("suppresses the diff filename when showFileName is false (owning row names it)", () => {
|
|
231
|
+
const view: ToolResultView = {
|
|
232
|
+
type: "diff",
|
|
233
|
+
path: "/workspace/secret.md",
|
|
234
|
+
oldText: "a",
|
|
235
|
+
newText: "a b",
|
|
236
|
+
};
|
|
237
|
+
const { container } = render(<ResultView view={view} showFileName={false} />);
|
|
238
|
+
// The path is not restated in the body; the diff content still renders.
|
|
239
|
+
expect(container.textContent).not.toContain("secret.md");
|
|
240
|
+
expect(container.textContent).toContain("a b");
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it("renders a neutral 'no preview' notice for a contentless diff", () => {
|
|
244
|
+
const view: ToolResultView = { type: "diff", path: "/workspace/x.md" };
|
|
245
|
+
const { container } = render(<ResultView view={view} showFileName={false} />);
|
|
246
|
+
expect(container.textContent).toContain("No preview available for this change");
|
|
247
|
+
expect(container.textContent).not.toContain("x.md");
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Integration lock through the full normalizeToolResult -> ResultView pipeline:
|
|
251
|
+
// a whole-file write's proposed content is reconstructed from the tool args
|
|
252
|
+
// (Phase 5 Slice 4 removed the ToolCall.file_changes capture) and renders as
|
|
253
|
+
// the file body — never the "No preview available" notice.
|
|
254
|
+
it("renders a whole-file write's proposed content from args, not 'No preview available'", () => {
|
|
255
|
+
const CONTENT = "# Notes\n\n- first bullet\n- second bullet\n";
|
|
256
|
+
const toolCall = create(ToolCallSchema, {
|
|
257
|
+
id: "tool_create",
|
|
258
|
+
name: "write_file",
|
|
259
|
+
toolKind: ToolKind.FILE_WRITE,
|
|
260
|
+
status: ToolCallStatus.TOOL_CALL_COMPLETED,
|
|
261
|
+
args: { path: "notes.md", contents: CONTENT } as JsonObject,
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
const { container } = render(<ResultView view={normalizeToolResult(toolCall)} />);
|
|
265
|
+
expect(container.textContent).toContain("first bullet");
|
|
266
|
+
expect(container.textContent).not.toContain("No preview available");
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it("suppresses the file path in a write fallback when showFileName is false", () => {
|
|
270
|
+
const view: ToolResultView = {
|
|
271
|
+
type: "file",
|
|
272
|
+
path: "/workspace/created.md",
|
|
273
|
+
content: "the body",
|
|
274
|
+
truncated: false,
|
|
275
|
+
};
|
|
276
|
+
const { container } = render(<ResultView view={view} showFileName={false} />);
|
|
277
|
+
expect(container.textContent).toContain("the body");
|
|
278
|
+
expect(container.textContent).not.toContain("created.md");
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
describe("ResultView — offloaded outputRef (on-demand resolution)", () => {
|
|
283
|
+
const imageView: ToolResultView = {
|
|
284
|
+
type: "outputRef",
|
|
285
|
+
storageKey: "artifacts/aex_1/toolcalls/tc.png",
|
|
286
|
+
contentHash: "h",
|
|
287
|
+
isImage: true,
|
|
288
|
+
mimeType: "image/png",
|
|
289
|
+
sizeBytes: 1234,
|
|
290
|
+
preview: "",
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const textView: ToolResultView = {
|
|
294
|
+
type: "outputRef",
|
|
295
|
+
storageKey: "artifacts/aex_1/toolcalls/tc.txt",
|
|
296
|
+
contentHash: "h",
|
|
297
|
+
isImage: false,
|
|
298
|
+
mimeType: "text/plain",
|
|
299
|
+
sizeBytes: 900_000,
|
|
300
|
+
preview: "short head…",
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
it("renders an offloaded image from a freshly minted URL (never a baked one)", async () => {
|
|
304
|
+
const getArtifactDownloadUrl = vi
|
|
305
|
+
.fn()
|
|
306
|
+
.mockResolvedValue({ downloadUrl: "https://fresh/url.png" });
|
|
307
|
+
const stigmer = {
|
|
308
|
+
agentExecution: { getArtifactDownloadUrl, getArtifactContent: vi.fn() },
|
|
309
|
+
} as unknown as Stigmer;
|
|
310
|
+
|
|
311
|
+
render(withStigmer(<ResultView view={imageView} />, stigmer));
|
|
312
|
+
|
|
313
|
+
const img = await screen.findByRole("img");
|
|
314
|
+
expect(img.getAttribute("src")).toBe("https://fresh/url.png");
|
|
315
|
+
// URL was resolved on demand from the stable storage key.
|
|
316
|
+
const req = getArtifactDownloadUrl.mock.calls[0][0];
|
|
317
|
+
expect(req.storageKey).toBe("artifacts/aex_1/toolcalls/tc.png");
|
|
318
|
+
expect(req.executionId).toBe("aex_1");
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it("shows the preview head and defers the full fetch until 'View full output'", async () => {
|
|
322
|
+
const getArtifactContent = vi.fn().mockResolvedValue({
|
|
323
|
+
content: new TextEncoder().encode("THE FULL OUTPUT"),
|
|
324
|
+
contentType: "text/plain",
|
|
325
|
+
truncated: false,
|
|
326
|
+
});
|
|
327
|
+
const stigmer = {
|
|
328
|
+
agentExecution: { getArtifactContent, getArtifactDownloadUrl: vi.fn() },
|
|
329
|
+
} as unknown as Stigmer;
|
|
330
|
+
|
|
331
|
+
render(withStigmer(<ResultView view={textView} />, stigmer));
|
|
332
|
+
|
|
333
|
+
// Lazy: nothing fetched until the user expands.
|
|
334
|
+
expect(screen.getByText("short head…")).toBeTruthy();
|
|
335
|
+
expect(getArtifactContent).not.toHaveBeenCalled();
|
|
336
|
+
|
|
337
|
+
fireEvent.click(screen.getByText(/View full output/));
|
|
338
|
+
|
|
339
|
+
await waitFor(() => expect(screen.getByText("THE FULL OUTPUT")).toBeTruthy());
|
|
340
|
+
expect(getArtifactContent).toHaveBeenCalledTimes(1);
|
|
341
|
+
});
|
|
73
342
|
});
|
|
74
343
|
|
|
75
344
|
describe("summarizeResultView", () => {
|
|
@@ -89,6 +358,15 @@ describe("summarizeResultView", () => {
|
|
|
89
358
|
expect(summarizeResultView({ type: "list", entries: [], count: 1 })).toBe("1 item");
|
|
90
359
|
});
|
|
91
360
|
|
|
361
|
+
it("uses the file noun for a file-name search summary", () => {
|
|
362
|
+
expect(
|
|
363
|
+
summarizeResultView({ type: "search", kind: "files", matches: [], count: 3 }),
|
|
364
|
+
).toBe("3 files");
|
|
365
|
+
expect(
|
|
366
|
+
summarizeResultView({ type: "search", kind: "files", matches: [], count: 1 }),
|
|
367
|
+
).toBe("1 file");
|
|
368
|
+
});
|
|
369
|
+
|
|
92
370
|
it("returns null when there is nothing to summarize", () => {
|
|
93
371
|
expect(summarizeResultView({ type: "text", text: "hi" })).toBeNull();
|
|
94
372
|
});
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach, vi } from "vitest";
|
|
2
|
+
import { render, screen, cleanup, act } from "@testing-library/react";
|
|
3
|
+
import { create } from "@bufbuild/protobuf";
|
|
4
|
+
import {
|
|
5
|
+
AgentMessageSchema,
|
|
6
|
+
ToolCallSchema,
|
|
7
|
+
type AgentMessage,
|
|
8
|
+
} from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
|
|
9
|
+
import {
|
|
10
|
+
SubAgentExecutionSchema,
|
|
11
|
+
type SubAgentExecution,
|
|
12
|
+
} from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/subagent_pb";
|
|
13
|
+
import {
|
|
14
|
+
PendingApprovalSchema,
|
|
15
|
+
type PendingApproval,
|
|
16
|
+
} from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/approval_pb";
|
|
17
|
+
import {
|
|
18
|
+
MessageType,
|
|
19
|
+
SubAgentStatus,
|
|
20
|
+
ToolCallStatus,
|
|
21
|
+
} from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
22
|
+
import { SubAgentSection } from "../SubAgentSection";
|
|
23
|
+
import { ApprovalContext, type ApprovalContextValue } from "../ApprovalContext";
|
|
24
|
+
|
|
25
|
+
afterEach(cleanup);
|
|
26
|
+
|
|
27
|
+
function gatedToolMessage(toolCallId: string): AgentMessage {
|
|
28
|
+
return create(AgentMessageSchema, {
|
|
29
|
+
type: MessageType.MESSAGE_AI,
|
|
30
|
+
content: "",
|
|
31
|
+
toolCalls: [
|
|
32
|
+
create(ToolCallSchema, {
|
|
33
|
+
id: toolCallId,
|
|
34
|
+
name: "delete_file",
|
|
35
|
+
status: ToolCallStatus.TOOL_CALL_WAITING_APPROVAL,
|
|
36
|
+
}),
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function subAgent(opts: {
|
|
42
|
+
status: SubAgentStatus;
|
|
43
|
+
messages?: AgentMessage[];
|
|
44
|
+
startedAt?: string;
|
|
45
|
+
completedAt?: string;
|
|
46
|
+
}): SubAgentExecution {
|
|
47
|
+
return create(SubAgentExecutionSchema, {
|
|
48
|
+
id: "sa-1",
|
|
49
|
+
name: "researcher",
|
|
50
|
+
status: opts.status,
|
|
51
|
+
messages: opts.messages ?? [],
|
|
52
|
+
startedAt: opts.startedAt ?? "",
|
|
53
|
+
completedAt: opts.completedAt ?? "",
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** The CollapsibleCard's own toggle is the first button under its role=group. */
|
|
58
|
+
function sectionExpanded(container: HTMLElement): boolean {
|
|
59
|
+
const toggle = container.querySelector('[role="group"] > button');
|
|
60
|
+
return toggle?.getAttribute("aria-expanded") === "true";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const emptyCtx: ApprovalContextValue = {
|
|
64
|
+
approvalsByToolCallId: new Map(),
|
|
65
|
+
submittingIds: new Set(),
|
|
66
|
+
errorsByToolCallId: new Map(),
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
describe("SubAgentSection auto-disclosure", () => {
|
|
70
|
+
it("auto-opens while the sub-agent is running", () => {
|
|
71
|
+
const { container } = render(
|
|
72
|
+
<ApprovalContext.Provider value={emptyCtx}>
|
|
73
|
+
<SubAgentSection
|
|
74
|
+
subAgentExecution={subAgent({ status: SubAgentStatus.SUB_AGENT_IN_PROGRESS })}
|
|
75
|
+
/>
|
|
76
|
+
</ApprovalContext.Provider>,
|
|
77
|
+
);
|
|
78
|
+
expect(sectionExpanded(container)).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("stays collapsed when the sub-agent has settled", () => {
|
|
82
|
+
const { container } = render(
|
|
83
|
+
<ApprovalContext.Provider value={emptyCtx}>
|
|
84
|
+
<SubAgentSection
|
|
85
|
+
subAgentExecution={subAgent({ status: SubAgentStatus.SUB_AGENT_COMPLETED })}
|
|
86
|
+
/>
|
|
87
|
+
</ApprovalContext.Provider>,
|
|
88
|
+
);
|
|
89
|
+
expect(sectionExpanded(container)).toBe(false);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("auto-opens a settled sub-agent when a nested tool awaits approval, and shows the gate inline", () => {
|
|
93
|
+
const approval: PendingApproval = create(PendingApprovalSchema, {
|
|
94
|
+
toolCallId: "tc-nested",
|
|
95
|
+
toolName: "delete_file",
|
|
96
|
+
argsPreview: '{"path":"/tmp/x"}',
|
|
97
|
+
});
|
|
98
|
+
const ctx: ApprovalContextValue = {
|
|
99
|
+
approvalsByToolCallId: new Map([["tc-nested", approval]]),
|
|
100
|
+
onSubmit: () => {},
|
|
101
|
+
submittingIds: new Set(),
|
|
102
|
+
errorsByToolCallId: new Map(),
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const { container } = render(
|
|
106
|
+
<ApprovalContext.Provider value={ctx}>
|
|
107
|
+
<SubAgentSection
|
|
108
|
+
subAgentExecution={subAgent({
|
|
109
|
+
status: SubAgentStatus.SUB_AGENT_COMPLETED,
|
|
110
|
+
messages: [gatedToolMessage("tc-nested")],
|
|
111
|
+
})}
|
|
112
|
+
/>
|
|
113
|
+
</ApprovalContext.Provider>,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
expect(sectionExpanded(container)).toBe(true);
|
|
117
|
+
// The nested gate's actions surface inside the sub-agent section.
|
|
118
|
+
expect(screen.getByLabelText("Approve")).toBeTruthy();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// The Cursor SDK delivers sub-agent internals only at completion (nothing to
|
|
123
|
+
// stream mid-run), so the running card's honest live signal is a ticking
|
|
124
|
+
// elapsed counter from started_at. Completed cards keep the precise static
|
|
125
|
+
// duration (start -> completion), not a counter.
|
|
126
|
+
describe("SubAgentSection running duration", () => {
|
|
127
|
+
afterEach(() => {
|
|
128
|
+
vi.useRealTimers();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("shows a ticking elapsed time while running", () => {
|
|
132
|
+
vi.useFakeTimers();
|
|
133
|
+
vi.setSystemTime(new Date("2026-07-02T12:00:42Z"));
|
|
134
|
+
|
|
135
|
+
render(
|
|
136
|
+
<ApprovalContext.Provider value={emptyCtx}>
|
|
137
|
+
<SubAgentSection
|
|
138
|
+
subAgentExecution={subAgent({
|
|
139
|
+
status: SubAgentStatus.SUB_AGENT_IN_PROGRESS,
|
|
140
|
+
startedAt: "2026-07-02T12:00:00Z",
|
|
141
|
+
})}
|
|
142
|
+
/>
|
|
143
|
+
</ApprovalContext.Provider>,
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
expect(screen.getByText("42s")).toBeTruthy();
|
|
147
|
+
|
|
148
|
+
act(() => {
|
|
149
|
+
vi.advanceTimersByTime(20_000);
|
|
150
|
+
});
|
|
151
|
+
expect(screen.getByText("1m 2s")).toBeTruthy();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("shows no counter while running when started_at is absent", () => {
|
|
155
|
+
render(
|
|
156
|
+
<ApprovalContext.Provider value={emptyCtx}>
|
|
157
|
+
<SubAgentSection
|
|
158
|
+
subAgentExecution={subAgent({ status: SubAgentStatus.SUB_AGENT_IN_PROGRESS })}
|
|
159
|
+
/>
|
|
160
|
+
</ApprovalContext.Provider>,
|
|
161
|
+
);
|
|
162
|
+
expect(screen.queryByText(/^\d+s$/)).toBeNull();
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("shows the static duration (not a counter) once completed", () => {
|
|
166
|
+
render(
|
|
167
|
+
<ApprovalContext.Provider value={emptyCtx}>
|
|
168
|
+
<SubAgentSection
|
|
169
|
+
subAgentExecution={subAgent({
|
|
170
|
+
status: SubAgentStatus.SUB_AGENT_COMPLETED,
|
|
171
|
+
startedAt: "2026-07-02T12:00:00Z",
|
|
172
|
+
completedAt: "2026-07-02T12:01:14.500Z",
|
|
173
|
+
})}
|
|
174
|
+
/>
|
|
175
|
+
</ApprovalContext.Provider>,
|
|
176
|
+
);
|
|
177
|
+
// formatDuration's m/s rendering for a completed 74.5s run.
|
|
178
|
+
expect(screen.getByText("1m 15s")).toBeTruthy();
|
|
179
|
+
});
|
|
180
|
+
});
|