@stigmer/react 3.1.2 → 3.1.4
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 +37 -5
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +13 -5
- package/composer/SessionComposer.js.map +1 -1
- package/execution/ArtifactApplyButton.d.ts +25 -0
- package/execution/ArtifactApplyButton.d.ts.map +1 -0
- package/execution/ArtifactApplyButton.js +21 -0
- package/execution/ArtifactApplyButton.js.map +1 -0
- package/execution/ArtifactContentBody.d.ts +36 -0
- package/execution/ArtifactContentBody.d.ts.map +1 -0
- package/execution/ArtifactContentBody.js +62 -0
- package/execution/ArtifactContentBody.js.map +1 -0
- package/execution/ArtifactDocument.d.ts +48 -0
- package/execution/ArtifactDocument.d.ts.map +1 -0
- package/execution/ArtifactDocument.js +89 -0
- package/execution/ArtifactDocument.js.map +1 -0
- package/execution/ArtifactPreviewModal.d.ts +9 -9
- package/execution/ArtifactPreviewModal.d.ts.map +1 -1
- package/execution/ArtifactPreviewModal.js +18 -145
- package/execution/ArtifactPreviewModal.js.map +1 -1
- package/execution/ArtifactRow.d.ts +49 -0
- package/execution/ArtifactRow.d.ts.map +1 -0
- package/execution/ArtifactRow.js +56 -0
- package/execution/ArtifactRow.js.map +1 -0
- package/execution/ArtifactsWidget.d.ts +6 -9
- package/execution/ArtifactsWidget.d.ts.map +1 -1
- package/execution/ArtifactsWidget.js +15 -19
- package/execution/ArtifactsWidget.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/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 +0 -9
- package/execution/MessageEntry.d.ts.map +1 -1
- package/execution/MessageEntry.js +1 -11
- package/execution/MessageEntry.js.map +1 -1
- package/execution/MessageThread.d.ts +3 -4
- package/execution/MessageThread.d.ts.map +1 -1
- package/execution/MessageThread.js +25 -11
- package/execution/MessageThread.js.map +1 -1
- package/execution/PlanArtifactCard.d.ts +16 -10
- package/execution/PlanArtifactCard.d.ts.map +1 -1
- package/execution/PlanArtifactCard.js +31 -7
- 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/PlanStreamingCard.d.ts +7 -2
- package/execution/PlanStreamingCard.d.ts.map +1 -1
- package/execution/PlanStreamingCard.js +11 -6
- package/execution/PlanStreamingCard.js.map +1 -1
- package/execution/index.d.ts +12 -2
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +6 -1
- 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/useArtifactContent.d.ts +6 -1
- package/execution/useArtifactContent.d.ts.map +1 -1
- package/execution/useArtifactContent.js +7 -2
- package/execution/useArtifactContent.js.map +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/useArtifactInspection.d.ts +85 -0
- package/execution/useArtifactInspection.d.ts.map +1 -0
- package/execution/useArtifactInspection.js +143 -0
- package/execution/useArtifactInspection.js.map +1 -0
- package/execution/useCreateAgentExecution.d.ts +16 -3
- package/execution/useCreateAgentExecution.d.ts.map +1 -1
- package/execution/useCreateAgentExecution.js +1 -0
- package/execution/useCreateAgentExecution.js.map +1 -1
- package/index.d.ts +4 -4
- package/index.d.ts.map +1 -1
- package/index.js +3 -3
- package/index.js.map +1 -1
- package/internal/MermaidDiagram.d.ts +47 -0
- package/internal/MermaidDiagram.d.ts.map +1 -0
- package/internal/MermaidDiagram.js +118 -0
- package/internal/MermaidDiagram.js.map +1 -0
- package/internal/file-tree/FileTreeNode.d.ts.map +1 -1
- package/internal/file-tree/FileTreeNode.js +2 -2
- package/internal/file-tree/FileTreeNode.js.map +1 -1
- package/internal/markdown-components.d.ts.map +1 -1
- package/internal/markdown-components.js +34 -0
- package/internal/markdown-components.js.map +1 -1
- package/internal/mermaid-loader.d.ts +26 -0
- package/internal/mermaid-loader.d.ts.map +1 -0
- package/internal/mermaid-loader.js +34 -0
- package/internal/mermaid-loader.js.map +1 -0
- package/internal/mermaid-theme-css.d.ts +41 -0
- package/internal/mermaid-theme-css.d.ts.map +1 -0
- package/internal/mermaid-theme-css.js +179 -0
- package/internal/mermaid-theme-css.js.map +1 -0
- package/internal/slug.d.ts +9 -5
- package/internal/slug.d.ts.map +1 -1
- package/internal/slug.js +10 -6
- package/internal/slug.js.map +1 -1
- package/library/detect-plan-artifact.d.ts +27 -9
- package/library/detect-plan-artifact.d.ts.map +1 -1
- package/library/detect-plan-artifact.js +26 -6
- package/library/detect-plan-artifact.js.map +1 -1
- package/library/index.d.ts +1 -1
- package/library/index.d.ts.map +1 -1
- package/library/index.js +1 -1
- package/library/index.js.map +1 -1
- package/package.json +5 -4
- package/session/PlanEditor.js +1 -1
- package/session/PlanEditor.js.map +1 -1
- package/session/SessionViewer.d.ts.map +1 -1
- package/session/SessionViewer.js +122 -30
- package/session/SessionViewer.js.map +1 -1
- package/session/artifact-document.d.ts +13 -0
- package/session/artifact-document.d.ts.map +1 -0
- package/session/artifact-document.js +22 -0
- package/session/artifact-document.js.map +1 -0
- package/session/facets/ArtifactsTab.d.ts +30 -4
- package/session/facets/ArtifactsTab.d.ts.map +1 -1
- package/session/facets/ArtifactsTab.js +32 -10
- package/session/facets/ArtifactsTab.js.map +1 -1
- package/session/index.d.ts +2 -1
- package/session/index.d.ts.map +1 -1
- package/session/index.js +4 -1
- package/session/index.js.map +1 -1
- package/session/plan-document.d.ts +14 -2
- package/session/plan-document.d.ts.map +1 -1
- package/session/plan-document.js +14 -3
- package/session/plan-document.js.map +1 -1
- package/session/usePlanDraft.d.ts +1 -1
- package/session/useSessionArtifacts.d.ts +17 -0
- package/session/useSessionArtifacts.d.ts.map +1 -1
- package/session/useSessionArtifacts.js +16 -5
- package/session/useSessionArtifacts.js.map +1 -1
- package/session/useSessionConversation.d.ts +26 -3
- package/session/useSessionConversation.d.ts.map +1 -1
- package/session/useSessionConversation.js +51 -6
- 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 +20 -0
- package/session/useSessionPanel.d.ts.map +1 -1
- package/session/useSessionPanel.js +13 -0
- package/session/useSessionPanel.js.map +1 -1
- package/session/useSessionRailViews.d.ts +13 -1
- package/session/useSessionRailViews.d.ts.map +1 -1
- package/session/useSessionRailViews.js +5 -3
- package/session/useSessionRailViews.js.map +1 -1
- package/src/composer/SessionComposer.tsx +76 -7
- package/src/composer/__tests__/SessionComposer-editing.test.tsx +128 -0
- package/src/execution/ArtifactApplyButton.tsx +79 -0
- package/src/execution/ArtifactContentBody.tsx +255 -0
- package/src/execution/ArtifactDocument.tsx +344 -0
- package/src/execution/ArtifactPreviewModal.tsx +49 -415
- package/src/execution/ArtifactRow.tsx +165 -0
- package/src/execution/ArtifactsWidget.tsx +24 -33
- package/src/execution/FileChangeProgressBar.tsx +121 -0
- package/src/execution/FileChangesView.tsx +18 -4
- package/src/execution/FileReviewAtoms.tsx +89 -0
- package/src/execution/FileReviewCard.tsx +57 -90
- package/src/execution/MessageEntry.tsx +0 -62
- package/src/execution/MessageThread.tsx +29 -15
- package/src/execution/PlanArtifactCard.tsx +130 -52
- package/src/execution/PlanCompletionCard.tsx +5 -5
- package/src/execution/PlanStreamingCard.tsx +15 -11
- package/src/execution/__tests__/ArtifactContentBody.test.tsx +131 -0
- package/src/execution/__tests__/ArtifactDocument.test.tsx +100 -0
- package/src/execution/__tests__/ArtifactPreviewModal.test.tsx +6 -6
- package/src/execution/__tests__/ArtifactRow.test.tsx +139 -0
- package/src/execution/__tests__/ArtifactsWidget.test.tsx +78 -0
- package/src/execution/__tests__/FileChangeProgressBar.test.tsx +125 -0
- package/src/execution/__tests__/FileReviewCard.test.tsx +66 -7
- package/src/execution/__tests__/MessageThread.test.tsx +1 -1
- package/src/execution/__tests__/PlanArtifactCard.test.tsx +52 -18
- package/src/execution/__tests__/PlanCompletionCard.test.tsx +2 -2
- package/src/execution/__tests__/PlanStreamingCard.test.tsx +11 -4
- package/src/execution/__tests__/buildThreadItems-plan-completion.test.ts +104 -8
- package/src/execution/__tests__/message-entry.test.tsx +56 -39
- package/src/execution/__tests__/useArtifactCopy.test.tsx +90 -0
- package/src/execution/__tests__/useArtifactDownload.test.tsx +2 -0
- package/src/execution/__tests__/useArtifactInspection.test.tsx +151 -0
- package/src/execution/__tests__/useCreateAgentExecution.test.tsx +35 -0
- package/src/execution/index.ts +20 -2
- package/src/execution/use-build-from-plan-hotkey.ts +1 -1
- package/src/execution/useArtifactContent.ts +7 -0
- package/src/execution/useArtifactCopy.ts +109 -0
- package/src/execution/useArtifactDownload.ts +17 -5
- package/src/execution/useArtifactInspection.ts +252 -0
- package/src/execution/useCreateAgentExecution.ts +17 -3
- package/src/index.ts +17 -2
- package/src/internal/MermaidDiagram.tsx +164 -0
- package/src/internal/__tests__/a11y/mermaid-theme.a11y.test.tsx +122 -0
- package/src/internal/__tests__/markdown-components.test.tsx +93 -1
- package/src/internal/__tests__/mermaid-diagram.test.tsx +282 -0
- package/src/internal/file-tree/FileTreeNode.tsx +13 -2
- package/src/internal/markdown-components.tsx +36 -1
- package/src/internal/mermaid-loader.ts +44 -0
- package/src/internal/mermaid-theme-css.ts +178 -0
- package/src/internal/slug.ts +10 -6
- package/src/library/__tests__/detect-plan-artifact.test.ts +21 -0
- package/src/library/detect-plan-artifact.ts +32 -10
- package/src/library/index.ts +2 -0
- package/src/session/PlanEditor.tsx +1 -1
- package/src/session/SessionViewer.tsx +227 -51
- package/src/session/__tests__/PlanEditor.test.tsx +4 -4
- package/src/session/__tests__/PlanStreamingDocument.test.tsx +1 -1
- package/src/session/__tests__/SessionViewer-artifactTabs.test.tsx +210 -0
- package/src/session/__tests__/SessionViewer-editResubmit.test.tsx +233 -0
- package/src/session/__tests__/SessionViewer-fileReviewDock.test.tsx +57 -0
- package/src/session/__tests__/useSessionArtifacts.test.ts +57 -0
- package/src/session/__tests__/useSessionConversation.test.tsx +216 -1
- package/src/session/__tests__/useSessionPanel.test.ts +70 -1
- package/src/session/artifact-document.ts +23 -0
- package/src/session/facets/ArtifactsTab.tsx +66 -18
- package/src/session/facets/__tests__/ArtifactsTab.test.tsx +111 -47
- package/src/session/index.ts +5 -1
- package/src/session/plan-document.ts +14 -3
- package/src/session/usePlanDraft.ts +1 -1
- package/src/session/useSessionArtifacts.ts +16 -5
- package/src/session/useSessionConversation.ts +80 -10
- package/src/session/useSessionPageFlow.ts +1 -0
- package/src/session/useSessionPanel.ts +41 -0
- package/src/session/useSessionRailViews.tsx +21 -1
- package/src/workspace/EditorTabs.tsx +38 -9
- package/src/workspace/ExplorerTree.tsx +10 -4
- package/src/workspace/FileViewer.tsx +27 -6
- package/src/workspace/WorkspaceContentSearch.tsx +44 -20
- package/src/workspace/WorkspaceEditor.tsx +19 -16
- package/src/workspace/WorkspaceFileSearch.tsx +51 -28
- package/src/workspace/WorkspaceSurface.tsx +106 -48
- package/src/workspace/__tests__/EditorTabs.test.tsx +4 -2
- package/src/workspace/__tests__/ExplorerTree.test.tsx +52 -0
- package/src/workspace/__tests__/FileViewer.test.tsx +18 -0
- package/src/workspace/__tests__/WorkspaceContentSearch.test.tsx +38 -5
- package/src/workspace/__tests__/WorkspaceEditor-initialPanel.test.tsx +19 -0
- package/src/workspace/__tests__/WorkspaceFileSearch.test.tsx +27 -6
- package/src/workspace/__tests__/WorkspaceSurface.test.tsx +70 -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/styles.css +1 -1
- package/workspace/EditorTabs.d.ts +21 -3
- package/workspace/EditorTabs.d.ts.map +1 -1
- package/workspace/EditorTabs.js +18 -6
- package/workspace/EditorTabs.js.map +1 -1
- package/workspace/ExplorerTree.js +8 -4
- package/workspace/ExplorerTree.js.map +1 -1
- package/workspace/FileViewer.d.ts.map +1 -1
- package/workspace/FileViewer.js +19 -8
- package/workspace/FileViewer.js.map +1 -1
- package/workspace/WorkspaceContentSearch.d.ts.map +1 -1
- package/workspace/WorkspaceContentSearch.js +23 -2
- package/workspace/WorkspaceContentSearch.js.map +1 -1
- package/workspace/WorkspaceEditor.d.ts.map +1 -1
- package/workspace/WorkspaceEditor.js +8 -10
- package/workspace/WorkspaceEditor.js.map +1 -1
- package/workspace/WorkspaceFileSearch.d.ts.map +1 -1
- package/workspace/WorkspaceFileSearch.js +23 -3
- package/workspace/WorkspaceFileSearch.js.map +1 -1
- package/workspace/WorkspaceSurface.d.ts.map +1 -1
- package/workspace/WorkspaceSurface.js +54 -18
- package/workspace/WorkspaceSurface.js.map +1 -1
- package/execution/ArtifactCard.d.ts +0 -81
- package/execution/ArtifactCard.d.ts.map +0 -1
- package/execution/ArtifactCard.js +0 -130
- package/execution/ArtifactCard.js.map +0 -1
- package/src/execution/ArtifactCard.tsx +0 -320
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
WorkspaceSurface,
|
|
18
18
|
type SurfaceVirtualDocument,
|
|
19
19
|
} from "../workspace/WorkspaceSurface.js";
|
|
20
|
-
import type { InteractionModeOption, SessionComposerHandle } from "../composer/index.js";
|
|
20
|
+
import type { InteractionModeOption, SessionComposerHandle, SessionComposerSubmitContext } from "../composer/index.js";
|
|
21
21
|
import type { ApplyResourceResult } from "../library/useApplyResource.js";
|
|
22
22
|
import { ResizableSplit } from "../internal/ResizableSplit.js";
|
|
23
23
|
import { SelectionStore } from "../internal/store/selection-store.js";
|
|
@@ -25,13 +25,17 @@ import { useWorkspaceEditors, isVirtualEntryId } from "../internal/store/index.j
|
|
|
25
25
|
import { ThreadSelectionContext } from "../execution/ThreadSelectionContext.js";
|
|
26
26
|
import { useSelectedThreadItem } from "../execution/useThreadSelection.js";
|
|
27
27
|
import { MessageThread } from "../execution/MessageThread.js";
|
|
28
|
+
import { FileChangeProgressBar } from "../execution/FileChangeProgressBar.js";
|
|
28
29
|
import { FileReviewDock } from "../execution/FileReviewDock.js";
|
|
30
|
+
import {
|
|
31
|
+
FilePathContext,
|
|
32
|
+
type FilePathContextValue,
|
|
33
|
+
} from "../execution/FilePathContext.js";
|
|
29
34
|
import { ThreadSkeleton } from "../execution/ThreadSkeleton.js";
|
|
30
35
|
import { SessionComposer } from "../composer/index.js";
|
|
31
36
|
import { SecretFlowErrorGuide, isSecretFlowError } from "../error/index.js";
|
|
32
37
|
import { useStigmer } from "../hooks.js";
|
|
33
38
|
import {
|
|
34
|
-
PLAN_ARTIFACT_NAME,
|
|
35
39
|
findLatestSessionPlan,
|
|
36
40
|
findPlanArtifact,
|
|
37
41
|
type SessionPlan,
|
|
@@ -43,11 +47,17 @@ import { usePlanDraft, planDraftKey, type PlanDraftController } from "./usePlanD
|
|
|
43
47
|
import { PlanEditor } from "./PlanEditor.js";
|
|
44
48
|
import { PlanStreamingDocument } from "./PlanStreamingDocument.js";
|
|
45
49
|
import { PLAN_DOCUMENT_ENTRY_ID, PLAN_DOCUMENT_PATH } from "./plan-document.js";
|
|
50
|
+
import { ARTIFACT_DOCUMENT_ENTRY_ID } from "./artifact-document.js";
|
|
51
|
+
import { ArtifactDocument } from "../execution/ArtifactDocument.js";
|
|
46
52
|
import { useSessionRailViews } from "./useSessionRailViews.js";
|
|
47
53
|
import { useSessionPanel, type SessionPanelController } from "./useSessionPanel.js";
|
|
48
54
|
import { SessionPanelChip } from "./SessionPanelChip.js";
|
|
49
55
|
import { useSessionWriteBacks } from "./useSessionWriteBacks.js";
|
|
50
|
-
import {
|
|
56
|
+
import {
|
|
57
|
+
useSessionArtifacts,
|
|
58
|
+
artifactKey,
|
|
59
|
+
type SessionArtifactEntry,
|
|
60
|
+
} from "./useSessionArtifacts.js";
|
|
51
61
|
import type { SetupTabProps } from "./facets/SetupTab.js";
|
|
52
62
|
import { ExecutionPhase } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
53
63
|
import type { RuntimeEnvProvider } from "./runtime-env.js";
|
|
@@ -57,18 +67,22 @@ import type { SessionAudience } from "./audience.js";
|
|
|
57
67
|
* Where the approved plan mounts in the implement execution's workspace —
|
|
58
68
|
* the harnesses' standard attachment inputs directory, where the runner's
|
|
59
69
|
* implement-plan directive points the agent (shared/implement-plan-prompt.ts).
|
|
60
|
-
* Attaching
|
|
61
|
-
* the user approved (including in-place
|
|
70
|
+
* Attaching under the plan's own filename (e.g. `feature-x_a1b2c3d4.plan.md`) is what
|
|
71
|
+
* makes the build implement the document the user approved (including in-place
|
|
72
|
+
* edits), not a paraphrase from memory; the runner detects it by the plan
|
|
73
|
+
* filename convention (`isPlanArtifactName`), so the exact name is free to vary.
|
|
62
74
|
*/
|
|
63
|
-
|
|
75
|
+
function approvedPlanMountPath(planFileName: string): string {
|
|
76
|
+
return `.stigmer/inputs/${planFileName}`;
|
|
77
|
+
}
|
|
64
78
|
|
|
65
79
|
/**
|
|
66
80
|
* The build turn's user message — a short human-readable label, NOT the
|
|
67
81
|
* implement instruction. The agent-facing instruction is runner-injected
|
|
68
|
-
* (keyed off `executionConfig.buildFromPlan`)
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
82
|
+
* (keyed off `executionConfig.buildFromPlan`). The thread hides the turn
|
|
83
|
+
* entirely from the same flag (the plan card above it is the visible cause);
|
|
84
|
+
* this label exists for surfaces without that treatment (the CLI, execution
|
|
85
|
+
* history, older clients), which show it as-is.
|
|
72
86
|
*/
|
|
73
87
|
const BUILD_FROM_PLAN_MESSAGE = "Build from plan";
|
|
74
88
|
|
|
@@ -377,7 +391,7 @@ export function SessionViewer({
|
|
|
377
391
|
setPlanAttachFailed(false);
|
|
378
392
|
|
|
379
393
|
// `buildFromPlan` (not message text) is what tells the runner to inject
|
|
380
|
-
// the implement directive and the thread to
|
|
394
|
+
// the implement directive and the thread to hide the turn's message —
|
|
381
395
|
// with or without the attachment (the runner picks the directive variant).
|
|
382
396
|
const submitImplementTurn = (attachments?: AttachmentInput[]) => {
|
|
383
397
|
composerRef.current?.submit(BUILD_FROM_PLAN_MESSAGE, {
|
|
@@ -398,22 +412,25 @@ export function SessionViewer({
|
|
|
398
412
|
// execution. The published artifact itself stays immutable; the approved
|
|
399
413
|
// copy is a new input on the build turn (edit-as-input provenance).
|
|
400
414
|
setIsBuildingFromPlan(true);
|
|
415
|
+
// The approved copy keeps the published plan's filename, so the mounted
|
|
416
|
+
// input, the download, and the plan card all agree on one name.
|
|
417
|
+
const planFileName = sessionPlan.artifact.name;
|
|
401
418
|
void (async () => {
|
|
402
419
|
try {
|
|
403
420
|
const approvedText =
|
|
404
421
|
planDraft.readDraft() ?? (await fetchPlanText(stigmer, sessionPlan));
|
|
405
422
|
const response = await stigmer.agentExecution.uploadAttachment(
|
|
406
423
|
create(UploadAttachmentRequestSchema, {
|
|
407
|
-
filename:
|
|
424
|
+
filename: planFileName,
|
|
408
425
|
content: new TextEncoder().encode(approvedText),
|
|
409
426
|
contentType: "text/markdown",
|
|
410
427
|
}),
|
|
411
428
|
);
|
|
412
429
|
submitImplementTurn([
|
|
413
430
|
{
|
|
414
|
-
filename:
|
|
431
|
+
filename: planFileName,
|
|
415
432
|
storageKey: response.storageKey,
|
|
416
|
-
mountPath:
|
|
433
|
+
mountPath: approvedPlanMountPath(planFileName),
|
|
417
434
|
contentType: "text/markdown",
|
|
418
435
|
},
|
|
419
436
|
]);
|
|
@@ -444,6 +461,28 @@ export function SessionViewer({
|
|
|
444
461
|
[sessionPlan, panel.openPlanDocument],
|
|
445
462
|
);
|
|
446
463
|
|
|
464
|
+
// "Open artifact" (an Artifacts-facet row) → an editor-pane document tab.
|
|
465
|
+
// Writing the editors store re-renders only the panel subtree (which
|
|
466
|
+
// subscribes), never this streaming column. Plan artifacts are routed to the
|
|
467
|
+
// plan tab upstream (in ArtifactsTab), so they never reach here.
|
|
468
|
+
const handleOpenArtifact = useCallback(
|
|
469
|
+
(entry: SessionArtifactEntry) => {
|
|
470
|
+
panel.openArtifact(entry.artifact);
|
|
471
|
+
},
|
|
472
|
+
[panel.openArtifact],
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
// Double-click an artifact row → pin its tab (the leading single click already
|
|
476
|
+
// opened the preview via `handleOpenArtifact`). Mirrors the file tree's
|
|
477
|
+
// preview/pin split; plan artifacts are routed to the plan tab upstream (in
|
|
478
|
+
// ArtifactsTab) and never reach here.
|
|
479
|
+
const handleActivateArtifact = useCallback(
|
|
480
|
+
(entry: SessionArtifactEntry) => {
|
|
481
|
+
panel.pinArtifact(entry.artifact);
|
|
482
|
+
},
|
|
483
|
+
[panel.pinArtifact],
|
|
484
|
+
);
|
|
485
|
+
|
|
447
486
|
// Open a transcript tool-call file path in the panel's read-only editor.
|
|
448
487
|
// Resolves the (possibly absolute / subdir-prefixed) path to a
|
|
449
488
|
// repo/root-relative selection the editor can fetch; on a definite hit it
|
|
@@ -550,6 +589,8 @@ export function SessionViewer({
|
|
|
550
589
|
planDraft={planDraft}
|
|
551
590
|
openPlanExecutionId={openPlanExecutionId}
|
|
552
591
|
onOpenPlan={handleOpenPlan}
|
|
592
|
+
onOpenArtifact={handleOpenArtifact}
|
|
593
|
+
onActivateArtifact={handleActivateArtifact}
|
|
553
594
|
enableLocal={enableLocal}
|
|
554
595
|
onBrowseLocalFolder={onBrowseLocalFolder}
|
|
555
596
|
workspaceFileLister={workspaceFileLister}
|
|
@@ -641,18 +682,69 @@ const ConversationColumn = memo(function ConversationColumn({
|
|
|
641
682
|
void conv.stop();
|
|
642
683
|
}, [conv.stop]);
|
|
643
684
|
|
|
644
|
-
// Edit-and-resubmit: stop the in-flight turn
|
|
645
|
-
// the original text
|
|
646
|
-
//
|
|
647
|
-
//
|
|
648
|
-
//
|
|
685
|
+
// Edit-and-resubmit: stop the in-flight turn, pre-fill the composer with
|
|
686
|
+
// the original text, and remember which execution is being edited. The
|
|
687
|
+
// append-only execution log is never rewritten — submitting while editing
|
|
688
|
+
// creates a NEW execution that carries `supersedesExecutionId`, and the
|
|
689
|
+
// conversation read model hides the superseded turn so the edited message
|
|
690
|
+
// replaces the original in place (Cursor-style, stigmer/stigmer#181).
|
|
691
|
+
//
|
|
692
|
+
// The editing state is explicit (banner + cancel in the composer) so the
|
|
693
|
+
// supersede link only attaches when the user actually resubmits the edit.
|
|
694
|
+
// Cancelling drops the link — a subsequent unrelated message appends
|
|
695
|
+
// normally without hiding any history.
|
|
696
|
+
const [editingExecutionId, setEditingExecutionId] = useState<string | null>(
|
|
697
|
+
null,
|
|
698
|
+
);
|
|
699
|
+
const activeExecutionId = conv.activeStreamExecution?.metadata?.id ?? null;
|
|
700
|
+
|
|
649
701
|
const handleEditMessage = useCallback(
|
|
650
702
|
(text: string) => {
|
|
651
703
|
void conv.stop();
|
|
704
|
+
setEditingExecutionId(activeExecutionId);
|
|
652
705
|
composerRef.current?.setMessage(text);
|
|
653
706
|
composerRef.current?.focus();
|
|
654
707
|
},
|
|
655
|
-
[conv.stop, composerRef],
|
|
708
|
+
[conv.stop, activeExecutionId, composerRef],
|
|
709
|
+
);
|
|
710
|
+
|
|
711
|
+
const handleCancelEdit = useCallback(() => {
|
|
712
|
+
setEditingExecutionId(null);
|
|
713
|
+
composerRef.current?.setMessage("");
|
|
714
|
+
}, [composerRef]);
|
|
715
|
+
|
|
716
|
+
// Submit wrapper that attaches the supersede link while editing, then
|
|
717
|
+
// exits editing mode. Ordinary (non-editing) submits pass through as-is.
|
|
718
|
+
const handleComposerSubmit = useCallback(
|
|
719
|
+
(
|
|
720
|
+
message: string,
|
|
721
|
+
modelName?: string,
|
|
722
|
+
context?: SessionComposerSubmitContext,
|
|
723
|
+
) => {
|
|
724
|
+
void flow.handleSubmit(
|
|
725
|
+
message,
|
|
726
|
+
modelName,
|
|
727
|
+
editingExecutionId
|
|
728
|
+
? { ...context, supersedesExecutionId: editingExecutionId }
|
|
729
|
+
: context,
|
|
730
|
+
);
|
|
731
|
+
setEditingExecutionId(null);
|
|
732
|
+
},
|
|
733
|
+
[flow.handleSubmit, editingExecutionId],
|
|
734
|
+
);
|
|
735
|
+
|
|
736
|
+
// The composer-docked FileReviewDock sits OUTSIDE MessageThread, so the
|
|
737
|
+
// thread's own FilePathContext provider does not reach it. This provider
|
|
738
|
+
// gives the dock's file list the same path resolution and click routing
|
|
739
|
+
// (open in the panel's viewer; GitHub/copy fallback) as the transcript —
|
|
740
|
+
// one click behavior for a path everywhere in the session. Memoized so the
|
|
741
|
+
// dock's memoized cards are not invalidated by unrelated renders (DD-010).
|
|
742
|
+
const dockFilePathCtx = useMemo<FilePathContextValue>(
|
|
743
|
+
() => ({
|
|
744
|
+
workspaceEntries: conv.workspaceEntries ?? [],
|
|
745
|
+
onFilePathClick,
|
|
746
|
+
}),
|
|
747
|
+
[conv.workspaceEntries, onFilePathClick],
|
|
656
748
|
);
|
|
657
749
|
|
|
658
750
|
return (
|
|
@@ -703,19 +795,28 @@ const ConversationColumn = memo(function ConversationColumn({
|
|
|
703
795
|
decision the agent is blocked on can never scroll out of view. The
|
|
704
796
|
thread renders only observational rows (badges) and read-only
|
|
705
797
|
settled records; this is the one decision surface. */}
|
|
706
|
-
<
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
798
|
+
<FilePathContext.Provider value={dockFilePathCtx}>
|
|
799
|
+
{/* Mid-run live capture (DD-32): the "N files changed so far" strip for
|
|
800
|
+
a still-running turn. Mutually exclusive with the dock below —
|
|
801
|
+
progress shows while CAPTURING, the dock once AWAITING_REVIEW — so it
|
|
802
|
+
hands off cleanly when review opens. Non-interactive. */}
|
|
803
|
+
<FileChangeProgressBar progress={conv.fileChangeProgress} />
|
|
804
|
+
<FileReviewDock
|
|
805
|
+
changeSets={conv.fileChangeSets}
|
|
806
|
+
onSubmit={conv.submitFileDecision}
|
|
807
|
+
submittingDecisionKeys={conv.submittingFileDecisionKeys}
|
|
808
|
+
decisionErrors={conv.fileDecisionErrors}
|
|
809
|
+
/>
|
|
810
|
+
</FilePathContext.Provider>
|
|
712
811
|
<SessionComposer
|
|
713
812
|
ref={composerRef}
|
|
714
|
-
onSubmit={
|
|
813
|
+
onSubmit={handleComposerSubmit}
|
|
715
814
|
isSubmitting={conv.isSending}
|
|
716
815
|
disabled={!conv.canSendFollowUp}
|
|
717
816
|
onStop={conv.isStoppable ? handleStop : undefined}
|
|
718
817
|
isStopping={conv.isStopping}
|
|
818
|
+
isEditing={editingExecutionId != null}
|
|
819
|
+
onCancelEdit={handleCancelEdit}
|
|
719
820
|
org={org}
|
|
720
821
|
harness={flow.harness}
|
|
721
822
|
defaultModelId={modelId}
|
|
@@ -783,6 +884,10 @@ interface SessionPanelRegionProps {
|
|
|
783
884
|
readonly openPlanExecutionId: string | null;
|
|
784
885
|
/** Opens a plan in the plan tab (routed to the Artifacts facet's plan.md). */
|
|
785
886
|
readonly onOpenPlan: (executionId: string) => void;
|
|
887
|
+
/** Opens an artifact as an editor-pane document (routed to the Artifacts facet). */
|
|
888
|
+
readonly onOpenArtifact: (entry: SessionArtifactEntry) => void;
|
|
889
|
+
/** Pins an artifact's document tab — the double-click half of the open/pin split. */
|
|
890
|
+
readonly onActivateArtifact: (entry: SessionArtifactEntry) => void;
|
|
786
891
|
readonly enableLocal: boolean;
|
|
787
892
|
readonly onBrowseLocalFolder?: () => Promise<string | null>;
|
|
788
893
|
readonly workspaceFileLister?: WorkspaceFileLister;
|
|
@@ -804,6 +909,8 @@ function SessionPanelRegion({
|
|
|
804
909
|
planDraft,
|
|
805
910
|
openPlanExecutionId,
|
|
806
911
|
onOpenPlan,
|
|
912
|
+
onOpenArtifact,
|
|
913
|
+
onActivateArtifact,
|
|
807
914
|
enableLocal,
|
|
808
915
|
onBrowseLocalFolder,
|
|
809
916
|
workspaceFileLister,
|
|
@@ -815,6 +922,9 @@ function SessionPanelRegion({
|
|
|
815
922
|
const { editors, activeKey, activeFile, reveal } = useWorkspaceEditors(
|
|
816
923
|
panel.editorsStore,
|
|
817
924
|
);
|
|
925
|
+
// Session artifacts, deduped by identity — the source both the Artifacts
|
|
926
|
+
// rail-view badge and the open artifact document tabs resolve against.
|
|
927
|
+
const { artifacts: sessionArtifacts } = useSessionArtifacts(flow.allExecutions);
|
|
818
928
|
|
|
819
929
|
// Honor a pending jump-to-line reveal only while it targets the active editor
|
|
820
930
|
// (an EditorReveal is structurally a RevealTarget). Switching tabs changes
|
|
@@ -870,30 +980,28 @@ function SessionPanelRegion({
|
|
|
870
980
|
// tab and its turn then ended without publishing, with no earlier plan to
|
|
871
981
|
// fall back to.
|
|
872
982
|
const openPlanIsLatest = openPlan?.executionId === sessionPlan?.executionId;
|
|
873
|
-
const
|
|
874
|
-
return
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
},
|
|
896
|
-
];
|
|
983
|
+
const planVirtualDocument = useMemo<SurfaceVirtualDocument>(() => {
|
|
984
|
+
return {
|
|
985
|
+
entryId: PLAN_DOCUMENT_ENTRY_ID,
|
|
986
|
+
path: PLAN_DOCUMENT_PATH,
|
|
987
|
+
content: streamingPlan ? (
|
|
988
|
+
<PlanStreamingDocument
|
|
989
|
+
key={`streaming-${streamingPlan.executionId}`}
|
|
990
|
+
displayText={streamingPlan.displayText}
|
|
991
|
+
/>
|
|
992
|
+
) : openPlan ? (
|
|
993
|
+
<PlanEditor
|
|
994
|
+
key={planDraftKey(openPlan)}
|
|
995
|
+
plan={openPlan}
|
|
996
|
+
draft={openPlanIsLatest ? planDraft : undefined}
|
|
997
|
+
onBuildFromPlan={openPlanIsLatest ? onImplementPlan : undefined}
|
|
998
|
+
buildDisabled={implementPlanDisabled}
|
|
999
|
+
readOnly={!openPlanIsLatest}
|
|
1000
|
+
/>
|
|
1001
|
+
) : (
|
|
1002
|
+
<PlanUnavailableNotice />
|
|
1003
|
+
),
|
|
1004
|
+
};
|
|
897
1005
|
}, [
|
|
898
1006
|
streamingPlan,
|
|
899
1007
|
openPlan,
|
|
@@ -903,6 +1011,50 @@ function SessionPanelRegion({
|
|
|
903
1011
|
implementPlanDisabled,
|
|
904
1012
|
]);
|
|
905
1013
|
|
|
1014
|
+
// The open artifact document tabs (the artifact virtual-document FAMILY).
|
|
1015
|
+
// Built in a SEPARATE memo from the plan doc so artifact-tab churn never
|
|
1016
|
+
// recreates the plan doc (and vice versa). Bounded to what is actually open:
|
|
1017
|
+
// one document per editor whose entry id is the artifact family's, resolved
|
|
1018
|
+
// back to its `SessionArtifactEntry` by the same `artifactKey` used to open
|
|
1019
|
+
// it (single source of truth for artifact identity). Only the ACTIVE doc's
|
|
1020
|
+
// `content` is mounted by the surface, so building these elements is cheap;
|
|
1021
|
+
// keying on `contentHash` remounts a tab whose artifact was overwritten by a
|
|
1022
|
+
// later execution. A tab whose artifact no longer exists degrades to an
|
|
1023
|
+
// honest notice rather than vanishing.
|
|
1024
|
+
const artifactByKey = useMemo(
|
|
1025
|
+
() =>
|
|
1026
|
+
new Map(sessionArtifacts.map((entry) => [artifactKey(entry.artifact), entry])),
|
|
1027
|
+
[sessionArtifacts],
|
|
1028
|
+
);
|
|
1029
|
+
const artifactVirtualDocuments = useMemo<readonly SurfaceVirtualDocument[]>(() => {
|
|
1030
|
+
return editors
|
|
1031
|
+
.filter((editor) => editor.entryId === ARTIFACT_DOCUMENT_ENTRY_ID)
|
|
1032
|
+
.map((editor) => {
|
|
1033
|
+
const entry = artifactByKey.get(editor.path);
|
|
1034
|
+
return {
|
|
1035
|
+
entryId: ARTIFACT_DOCUMENT_ENTRY_ID,
|
|
1036
|
+
path: editor.path,
|
|
1037
|
+
content: entry ? (
|
|
1038
|
+
<ArtifactDocument
|
|
1039
|
+
key={entry.artifact.contentHash || editor.path}
|
|
1040
|
+
artifact={entry.artifact}
|
|
1041
|
+
executionId={entry.executionId}
|
|
1042
|
+
org={org}
|
|
1043
|
+
isTerminal={entry.isTerminal}
|
|
1044
|
+
onApplied={onApplied}
|
|
1045
|
+
/>
|
|
1046
|
+
) : (
|
|
1047
|
+
<ArtifactUnavailableNotice />
|
|
1048
|
+
),
|
|
1049
|
+
};
|
|
1050
|
+
});
|
|
1051
|
+
}, [editors, artifactByKey, org, onApplied]);
|
|
1052
|
+
|
|
1053
|
+
const virtualDocuments = useMemo<readonly SurfaceVirtualDocument[]>(
|
|
1054
|
+
() => [planVirtualDocument, ...artifactVirtualDocuments],
|
|
1055
|
+
[planVirtualDocument, artifactVirtualDocuments],
|
|
1056
|
+
);
|
|
1057
|
+
|
|
906
1058
|
const handleRemoveAgent = useCallback(() => {
|
|
907
1059
|
flow.setAgentRef(null);
|
|
908
1060
|
flow.setResolution(null);
|
|
@@ -969,6 +1121,8 @@ function SessionPanelRegion({
|
|
|
969
1121
|
onApplied,
|
|
970
1122
|
onImplementPlan,
|
|
971
1123
|
onOpenPlan,
|
|
1124
|
+
onOpenArtifact,
|
|
1125
|
+
onActivateArtifact,
|
|
972
1126
|
});
|
|
973
1127
|
|
|
974
1128
|
// Explorer-footer folder attach (desktop only — needs the native picker).
|
|
@@ -1093,6 +1247,28 @@ function PlanUnavailableNotice() {
|
|
|
1093
1247
|
);
|
|
1094
1248
|
}
|
|
1095
1249
|
|
|
1250
|
+
/**
|
|
1251
|
+
* Shown in an artifact document tab whose artifact is no longer among the
|
|
1252
|
+
* session's outputs (an edge only reachable if the executions backing the tab
|
|
1253
|
+
* changed underneath it). The tab stays closable; the content is honest rather
|
|
1254
|
+
* than blank.
|
|
1255
|
+
*/
|
|
1256
|
+
function ArtifactUnavailableNotice() {
|
|
1257
|
+
return (
|
|
1258
|
+
<div
|
|
1259
|
+
role="status"
|
|
1260
|
+
className="mx-auto flex w-full max-w-3xl flex-col items-center gap-1 px-4 py-8 text-center"
|
|
1261
|
+
>
|
|
1262
|
+
<p className="text-xs font-medium text-foreground">
|
|
1263
|
+
This artifact is no longer available.
|
|
1264
|
+
</p>
|
|
1265
|
+
<p className="text-xs text-muted-foreground">
|
|
1266
|
+
It may have been replaced by a newer version of this session.
|
|
1267
|
+
</p>
|
|
1268
|
+
</div>
|
|
1269
|
+
);
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1096
1272
|
/**
|
|
1097
1273
|
* Non-blocking notice for a build that fell back to message-only implement
|
|
1098
1274
|
* (the approved plan.md could not be uploaded/attached). The build itself
|
|
@@ -81,9 +81,9 @@ describe("PlanEditor", () => {
|
|
|
81
81
|
renderEditor({ onBuildFromPlan });
|
|
82
82
|
|
|
83
83
|
await waitFor(() =>
|
|
84
|
-
expect(screen.getByText("Build
|
|
84
|
+
expect(screen.getByText("Build")).toBeTruthy(),
|
|
85
85
|
);
|
|
86
|
-
fireEvent.click(screen.getByText("Build
|
|
86
|
+
fireEvent.click(screen.getByText("Build"));
|
|
87
87
|
expect(onBuildFromPlan).toHaveBeenCalledTimes(1);
|
|
88
88
|
});
|
|
89
89
|
|
|
@@ -99,7 +99,7 @@ describe("PlanEditor", () => {
|
|
|
99
99
|
);
|
|
100
100
|
expect(screen.getByText("Rollout Plan").className).toContain("truncate");
|
|
101
101
|
|
|
102
|
-
const buildLabel = screen.getByText("Build
|
|
102
|
+
const buildLabel = screen.getByText("Build");
|
|
103
103
|
expect(buildLabel.className).toContain("truncate");
|
|
104
104
|
const toolbar = screen.getByRole("tablist", { name: "Plan view" })
|
|
105
105
|
.parentElement!;
|
|
@@ -188,7 +188,7 @@ describe("PlanEditor — read-only (superseded plan)", () => {
|
|
|
188
188
|
);
|
|
189
189
|
expect(screen.getByText("Superseded by a newer plan")).toBeTruthy();
|
|
190
190
|
expect(screen.queryByText("Edit")).toBeNull();
|
|
191
|
-
expect(screen.queryByText("Build
|
|
191
|
+
expect(screen.queryByText("Build")).toBeNull();
|
|
192
192
|
});
|
|
193
193
|
|
|
194
194
|
it("never applies the current plan's draft to a superseded plan", async () => {
|
|
@@ -44,7 +44,7 @@ describe("PlanStreamingDocument — live plan tab view", () => {
|
|
|
44
44
|
render(<PlanStreamingDocument displayText={"# Live Plan\n\nBody"} />);
|
|
45
45
|
|
|
46
46
|
expect(screen.queryByText("Edit")).toBeNull();
|
|
47
|
-
expect(screen.queryByText("Build
|
|
47
|
+
expect(screen.queryByText("Build")).toBeNull();
|
|
48
48
|
expect(screen.queryByRole("tablist")).toBeNull();
|
|
49
49
|
});
|
|
50
50
|
});
|