@stigmer/react 3.0.2-dev.20260609093630 → 3.0.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 +23 -5
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +12 -5
- package/composer/SessionComposer.js.map +1 -1
- package/composer/index.d.ts +1 -0
- package/composer/index.d.ts.map +1 -1
- package/composer/index.js +1 -0
- package/composer/index.js.map +1 -1
- package/composer/interaction-mode.d.ts +21 -0
- package/composer/interaction-mode.d.ts.map +1 -0
- package/composer/interaction-mode.js +37 -0
- package/composer/interaction-mode.js.map +1 -0
- package/execution/ArtifactPreviewModal.d.ts +15 -2
- package/execution/ArtifactPreviewModal.d.ts.map +1 -1
- package/execution/ArtifactPreviewModal.js +16 -6
- package/execution/ArtifactPreviewModal.js.map +1 -1
- package/execution/MessageThread.d.ts +17 -2
- package/execution/MessageThread.d.ts.map +1 -1
- package/execution/MessageThread.js +7 -7
- package/execution/MessageThread.js.map +1 -1
- package/execution/PlanArtifactCard.d.ts +13 -5
- package/execution/PlanArtifactCard.d.ts.map +1 -1
- package/execution/PlanArtifactCard.js +14 -34
- package/execution/PlanArtifactCard.js.map +1 -1
- package/execution/useCreateAgentExecution.d.ts.map +1 -1
- package/execution/useCreateAgentExecution.js +2 -6
- package/execution/useCreateAgentExecution.js.map +1 -1
- package/internal/VirtualizedThread.d.ts +3 -1
- package/internal/VirtualizedThread.d.ts.map +1 -1
- package/internal/VirtualizedThread.js +4 -2
- package/internal/VirtualizedThread.js.map +1 -1
- package/package.json +4 -4
- package/session/SessionViewer.d.ts.map +1 -1
- package/session/SessionViewer.js +20 -12
- package/session/SessionViewer.js.map +1 -1
- package/session/inspector/ArtifactsTab.d.ts +7 -1
- package/session/inspector/ArtifactsTab.d.ts.map +1 -1
- package/session/inspector/ArtifactsTab.js +3 -2
- package/session/inspector/ArtifactsTab.js.map +1 -1
- package/session/inspector/SessionInspector.d.ts +5 -0
- package/session/inspector/SessionInspector.d.ts.map +1 -1
- package/session/inspector/SessionInspector.js +2 -2
- package/session/inspector/SessionInspector.js.map +1 -1
- package/session/useSessionPageFlow.d.ts +12 -1
- package/session/useSessionPageFlow.d.ts.map +1 -1
- package/session/useSessionPageFlow.js +12 -0
- package/session/useSessionPageFlow.js.map +1 -1
- package/src/composer/SessionComposer.tsx +34 -9
- package/src/composer/__tests__/SessionComposer-contract.test.tsx +42 -2
- package/src/composer/__tests__/interaction-mode.test.ts +44 -0
- package/src/composer/index.ts +5 -0
- package/src/composer/interaction-mode.ts +43 -0
- package/src/execution/ArtifactPreviewModal.tsx +61 -1
- package/src/execution/MessageThread.tsx +35 -1
- package/src/execution/PlanArtifactCard.tsx +45 -85
- package/src/execution/__tests__/ArtifactPreviewModal.test.tsx +85 -0
- package/src/execution/__tests__/PlanArtifactCard.test.tsx +122 -0
- package/src/execution/useCreateAgentExecution.ts +2 -7
- package/src/internal/VirtualizedThread.tsx +7 -1
- package/src/session/SessionViewer.tsx +25 -10
- package/src/session/inspector/ArtifactsTab.tsx +11 -1
- package/src/session/inspector/SessionInspector.tsx +7 -0
- package/src/session/inspector/__tests__/ArtifactsTab.test.tsx +90 -0
- package/src/session/useSessionPageFlow.ts +33 -1
|
@@ -4,6 +4,7 @@ import { useCallback, useState } from "react";
|
|
|
4
4
|
import { useSessionArtifacts, } from "../useSessionArtifacts";
|
|
5
5
|
import { ArtifactCard } from "../../execution/ArtifactCard";
|
|
6
6
|
import { ArtifactPreviewModal } from "../../execution/ArtifactPreviewModal";
|
|
7
|
+
import { isPlanArtifact } from "../../library/detect-plan-artifact";
|
|
7
8
|
/**
|
|
8
9
|
* Artifacts facet for the SessionInspector.
|
|
9
10
|
*
|
|
@@ -11,7 +12,7 @@ import { ArtifactPreviewModal } from "../../execution/ArtifactPreviewModal";
|
|
|
11
12
|
* `ArtifactPreviewModal` — the same content as `ArtifactsWidget`
|
|
12
13
|
* without the section heading.
|
|
13
14
|
*/
|
|
14
|
-
export function ArtifactsTab({ executions, org, onApplied }) {
|
|
15
|
+
export function ArtifactsTab({ executions, org, onApplied, onImplementPlan }) {
|
|
15
16
|
const { artifacts, hasArtifacts } = useSessionArtifacts(executions);
|
|
16
17
|
const [previewEntry, setPreviewEntry] = useState(null);
|
|
17
18
|
const handlePreview = useCallback((entry) => {
|
|
@@ -23,6 +24,6 @@ export function ArtifactsTab({ executions, org, onApplied }) {
|
|
|
23
24
|
if (!hasArtifacts) {
|
|
24
25
|
return (_jsx("div", { className: "flex flex-col items-center justify-center px-4 py-8 text-center", children: _jsx("p", { className: "text-xs text-muted-foreground", children: "No artifacts yet. Files generated by the agent will appear here." }) }));
|
|
25
26
|
}
|
|
26
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { role: "list", className: "space-y-2", children: artifacts.map((entry) => (_jsx("div", { role: "listitem", children: _jsx(ArtifactCard, { artifact: entry.artifact, executionId: entry.executionId, org: org, hasNameCollision: entry.hasNameCollision, onPreview: () => handlePreview(entry) }) }, entry.artifact.sandboxPath || entry.artifact.name))) }), previewEntry && (_jsx(ArtifactPreviewModal, { artifact: previewEntry.artifact, executionId: previewEntry.executionId, isTerminal: previewEntry.isTerminal, org: org, open: true, onClose: handleClosePreview, onApplied: onApplied }))] }));
|
|
27
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { role: "list", className: "space-y-2", children: artifacts.map((entry) => (_jsx("div", { role: "listitem", children: _jsx(ArtifactCard, { artifact: entry.artifact, executionId: entry.executionId, org: org, hasNameCollision: entry.hasNameCollision, onPreview: () => handlePreview(entry) }) }, entry.artifact.sandboxPath || entry.artifact.name))) }), previewEntry && (_jsx(ArtifactPreviewModal, { artifact: previewEntry.artifact, executionId: previewEntry.executionId, isTerminal: previewEntry.isTerminal, org: org, open: true, onClose: handleClosePreview, onApplied: onApplied, onImplement: isPlanArtifact(previewEntry.artifact) ? onImplementPlan : undefined }))] }));
|
|
27
28
|
}
|
|
28
29
|
//# sourceMappingURL=ArtifactsTab.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArtifactsTab.js","sourceRoot":"","sources":["../../../src/session/inspector/ArtifactsTab.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE9C,OAAO,EACL,mBAAmB,GAEpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"ArtifactsTab.js","sourceRoot":"","sources":["../../../src/session/inspector/ArtifactsTab.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE9C,OAAO,EACL,mBAAmB,GAEpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAepE;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,EAAqB;IAC7F,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IACpE,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAA8B,IAAI,CAAC,CAAC;IAEpF,MAAM,aAAa,GAAG,WAAW,CAAC,CAAC,KAA2B,EAAE,EAAE;QAChE,eAAe,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,kBAAkB,GAAG,WAAW,CAAC,GAAG,EAAE;QAC1C,eAAe,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,CACL,cAAK,SAAS,EAAC,iEAAiE,YAC9E,YAAG,SAAS,EAAC,+BAA+B,iFAExC,GACA,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,8BACE,cAAK,IAAI,EAAC,MAAM,EAAC,SAAS,EAAC,WAAW,YACnC,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACxB,cAA6D,IAAI,EAAC,UAAU,YAC1E,KAAC,YAAY,IACX,QAAQ,EAAE,KAAK,CAAC,QAAQ,EACxB,WAAW,EAAE,KAAK,CAAC,WAAW,EAC9B,GAAG,EAAE,GAAG,EACR,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,EACxC,SAAS,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,GACrC,IAPM,KAAK,CAAC,QAAQ,CAAC,WAAW,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAQrD,CACP,CAAC,GACE,EAEL,YAAY,IAAI,CACf,KAAC,oBAAoB,IACnB,QAAQ,EAAE,YAAY,CAAC,QAAQ,EAC/B,WAAW,EAAE,YAAY,CAAC,WAAW,EACrC,UAAU,EAAE,YAAY,CAAC,UAAU,EACnC,GAAG,EAAE,GAAG,EACR,IAAI,QACJ,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,SAAS,EACpB,WAAW,EACT,cAAc,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,GAErE,CACH,IACA,CACJ,CAAC;AACJ,CAAC"}
|
|
@@ -22,6 +22,11 @@ export interface SessionInspectorProps {
|
|
|
22
22
|
readonly selectedItem: SelectedThreadItem | null;
|
|
23
23
|
/** Called after a resource is applied from the Artifacts tab. */
|
|
24
24
|
readonly onApplied?: (result: ApplyResourceResult) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Implement a plan from the Artifacts tab. When provided, plan
|
|
27
|
+
* artifacts (`plan.md`) surface an Implement action in their preview.
|
|
28
|
+
*/
|
|
29
|
+
readonly onImplementPlan?: () => void;
|
|
25
30
|
/**
|
|
26
31
|
* Session-level configuration for the Configure tab.
|
|
27
32
|
* Includes core config fields and optional interactive
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionInspector.d.ts","sourceRoot":"","sources":["../../../src/session/inspector/SessionInspector.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6DAA6D,CAAC;AAclG,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAE1E,0CAA0C;AAC1C,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,cAAc,GAAG,IAAI,CAAC;IACjD;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,SAAS,cAAc,EAAE,CAAC;IAClD,gDAAgD;IAChD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,QAAQ,CAAC,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACjD,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC3D;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC;;;;OAIG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,iBAAiB,CAAC;IAC7C,8BAA8B;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,gBAAgB,
|
|
1
|
+
{"version":3,"file":"SessionInspector.d.ts","sourceRoot":"","sources":["../../../src/session/inspector/SessionInspector.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6DAA6D,CAAC;AAclG,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAE1E,0CAA0C;AAC1C,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,cAAc,GAAG,IAAI,CAAC;IACjD;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,SAAS,cAAc,EAAE,CAAC;IAClD,gDAAgD;IAChD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,QAAQ,CAAC,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACjD,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC3D;;;OAGG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IACtC;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC;;;;OAIG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,iBAAiB,CAAC;IAC7C,8BAA8B;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,gBAAgB,6DA+E3B,CAAC"}
|
|
@@ -33,7 +33,7 @@ import { WorkspaceTab } from "./WorkspaceTab";
|
|
|
33
33
|
* All visual properties flow through `--stgm-*` tokens. Zero
|
|
34
34
|
* Console/Next/Tauri dependencies (DD-004).
|
|
35
35
|
*/
|
|
36
|
-
export const SessionInspector = memo(function SessionInspector({ displayExecution, allExecutions, org, selectedItem, onApplied, sessionConfig, workspaceConfig, className, }) {
|
|
36
|
+
export const SessionInspector = memo(function SessionInspector({ displayExecution, allExecutions, org, selectedItem, onApplied, onImplementPlan, sessionConfig, workspaceConfig, className, }) {
|
|
37
37
|
const phase = displayExecution?.status?.phase ??
|
|
38
38
|
ExecutionPhase.EXECUTION_PHASE_UNSPECIFIED;
|
|
39
39
|
const { hasWriteBacks, writeBackCount } = useSessionWriteBacks(allExecutions);
|
|
@@ -48,6 +48,6 @@ export const SessionInspector = memo(function SessionInspector({ displayExecutio
|
|
|
48
48
|
hasUsage,
|
|
49
49
|
selectedItem,
|
|
50
50
|
});
|
|
51
|
-
return (_jsxs("div", { className: cn("flex h-full flex-col", className), children: [_jsx("div", { className: "flex items-center gap-2 border-b border-border px-3 py-2.5", children: phase !== ExecutionPhase.EXECUTION_PHASE_UNSPECIFIED ? (_jsx(ExecutionPhaseBadge, { phase: phase })) : (_jsx("span", { className: "text-xs text-muted-foreground", children: "No execution" })) }), _jsx(Tabs, { tabs: tabs, activeTab: activeTab, onTabChange: onTabChange, "aria-label": "Session details", className: "min-h-0 flex-1", children: _jsxs("div", { className: "h-full min-h-0 overflow-y-auto px-3 py-3", children: [activeTab === "workspace" && workspaceConfig && (_jsx(WorkspaceTab, { ...workspaceConfig })), activeTab === "configure" && sessionConfig && (_jsx(SetupTab, { ...sessionConfig })), activeTab === "plan" && (_jsx(PlanTab, { execution: displayExecution })), activeTab === "changes" && (_jsx(ChangesTab, { executions: allExecutions })), activeTab === "artifacts" && (_jsx(ArtifactsTab, { executions: allExecutions, org: org, onApplied: onApplied })), activeTab === "usage" && (_jsx(UsageTab, { executions: allExecutions })), activeTab === "inspect" && (_jsx(InspectTab, { selectedItem: selectedItem }))] }) })] }));
|
|
51
|
+
return (_jsxs("div", { className: cn("flex h-full flex-col", className), children: [_jsx("div", { className: "flex items-center gap-2 border-b border-border px-3 py-2.5", children: phase !== ExecutionPhase.EXECUTION_PHASE_UNSPECIFIED ? (_jsx(ExecutionPhaseBadge, { phase: phase })) : (_jsx("span", { className: "text-xs text-muted-foreground", children: "No execution" })) }), _jsx(Tabs, { tabs: tabs, activeTab: activeTab, onTabChange: onTabChange, "aria-label": "Session details", className: "min-h-0 flex-1", children: _jsxs("div", { className: "h-full min-h-0 overflow-y-auto px-3 py-3", children: [activeTab === "workspace" && workspaceConfig && (_jsx(WorkspaceTab, { ...workspaceConfig })), activeTab === "configure" && sessionConfig && (_jsx(SetupTab, { ...sessionConfig })), activeTab === "plan" && (_jsx(PlanTab, { execution: displayExecution })), activeTab === "changes" && (_jsx(ChangesTab, { executions: allExecutions })), activeTab === "artifacts" && (_jsx(ArtifactsTab, { executions: allExecutions, org: org, onApplied: onApplied, onImplementPlan: onImplementPlan })), activeTab === "usage" && (_jsx(UsageTab, { executions: allExecutions })), activeTab === "inspect" && (_jsx(InspectTab, { selectedItem: selectedItem }))] }) })] }));
|
|
52
52
|
});
|
|
53
53
|
//# sourceMappingURL=SessionInspector.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionInspector.js","sourceRoot":"","sources":["../../../src/session/inspector/SessionInspector.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAE7B,OAAO,EAAE,cAAc,EAAE,MAAM,8DAA8D,CAAC;AAC9F,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAsB,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,YAAY,EAA0B,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"SessionInspector.js","sourceRoot":"","sources":["../../../src/session/inspector/SessionInspector.tsx"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import type { McpServerUsageInput, ResourceRef } from "@stigmer/sdk";
|
|
|
2
2
|
import type { AgentResolution } from "../agent";
|
|
3
3
|
import { type UseWorkspaceEntriesReturn } from "../workspace";
|
|
4
4
|
import { type UseSessionVariablesReturn } from "../execution/useSessionVariables";
|
|
5
|
-
import type { SessionComposerSubmitContext } from "../composer";
|
|
5
|
+
import type { SessionComposerSubmitContext, InteractionModeOption } from "../composer";
|
|
6
6
|
import { type HarnessOption } from "../models/harness";
|
|
7
7
|
import { type ExecutionTargetOption } from "./execution-target";
|
|
8
8
|
import { type UseSessionConversationReturn } from "./useSessionConversation";
|
|
@@ -38,6 +38,17 @@ export interface UseSessionPageFlowReturn {
|
|
|
38
38
|
readonly executionTarget: ExecutionTargetOption | undefined;
|
|
39
39
|
/** Persisted model selection: `[modelId, setModelId]`. */
|
|
40
40
|
readonly model: UsePersistedModelReturn;
|
|
41
|
+
/**
|
|
42
|
+
* Composer interaction mode: `[interactionMode, setInteractionMode]`.
|
|
43
|
+
*
|
|
44
|
+
* Derived like {@link model}: the user's explicit override wins, otherwise
|
|
45
|
+
* it reflects the latest execution's mode (so a completed Plan keeps the
|
|
46
|
+
* picker on "Plan" while it awaits review), falling back to `"agent"`.
|
|
47
|
+
*/
|
|
48
|
+
readonly interactionMode: readonly [
|
|
49
|
+
InteractionModeOption,
|
|
50
|
+
(mode: InteractionModeOption) => void
|
|
51
|
+
];
|
|
41
52
|
/** Currently selected agent reference (derived from session, or overridden by user). */
|
|
42
53
|
readonly agentRef: ResourceRef | null;
|
|
43
54
|
/** Update the agent reference for future follow-ups. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSessionPageFlow.d.ts","sourceRoot":"","sources":["../../src/session/useSessionPageFlow.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAErE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAGhD,OAAO,EAAuB,KAAK,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAAuB,KAAK,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AACvG,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"useSessionPageFlow.d.ts","sourceRoot":"","sources":["../../src/session/useSessionPageFlow.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ import { useDefaultAgent } from "../agent";
|
|
|
5
5
|
import { useStigmer } from "../hooks";
|
|
6
6
|
import { useWorkspaceEntries } from "../workspace";
|
|
7
7
|
import { useSessionVariables } from "../execution/useSessionVariables";
|
|
8
|
+
import { fromProtoInteractionMode } from "../composer";
|
|
8
9
|
import { fromProtoHarness } from "../models/harness";
|
|
9
10
|
import { Harness, ExecutionTarget } from "@stigmer/protos/ai/stigmer/agentic/session/v1/enum_pb";
|
|
10
11
|
import { fromProtoExecutionTarget } from "./execution-target";
|
|
@@ -71,6 +72,16 @@ export function useSessionPageFlow(options) {
|
|
|
71
72
|
}, [conv.completedExecutions]);
|
|
72
73
|
const modelId = persistedModelId ?? lastExecModelId;
|
|
73
74
|
const model = [modelId, setPersistedModelId];
|
|
75
|
+
// Interaction mode mirrors the model derivation: an explicit user override
|
|
76
|
+
// wins; otherwise reflect the latest execution's mode so a completed Plan
|
|
77
|
+
// keeps the composer on "Plan" until the user implements or switches. This
|
|
78
|
+
// is derived state (always consistent), never an effect-synced copy.
|
|
79
|
+
const lastExecInteractionMode = useMemo(() => fromProtoInteractionMode(conv.completedExecutions.at(-1)?.spec?.executionConfig?.interactionMode), [conv.completedExecutions]);
|
|
80
|
+
const [interactionModeOverride, setInteractionMode] = useState(null);
|
|
81
|
+
const interactionMode = [
|
|
82
|
+
interactionModeOverride ?? lastExecInteractionMode ?? "agent",
|
|
83
|
+
setInteractionMode,
|
|
84
|
+
];
|
|
74
85
|
const workspace = useWorkspaceEntries();
|
|
75
86
|
const sessionVariables = useSessionVariables();
|
|
76
87
|
const [mcpServerUsages, setMcpServerUsages] = useState([]);
|
|
@@ -197,6 +208,7 @@ export function useSessionPageFlow(options) {
|
|
|
197
208
|
harness,
|
|
198
209
|
executionTarget,
|
|
199
210
|
model,
|
|
211
|
+
interactionMode,
|
|
200
212
|
agentRef,
|
|
201
213
|
setAgentRef,
|
|
202
214
|
resolution,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSessionPageFlow.js","sourceRoot":"","sources":["../../src/session/useSessionPageFlow.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE1E,OAAO,EAAE,cAAc,EAAE,MAAM,8DAA8D,CAAC;AAE9F,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAkC,MAAM,cAAc,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAkC,MAAM,kCAAkC,CAAC;AAEvG,OAAO,EAAE,gBAAgB,EAAsB,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,uDAAuD,CAAC;AACjG,OAAO,EAAE,wBAAwB,EAA8B,MAAM,oBAAoB,CAAC;AAC1F,OAAO,EAAE,sBAAsB,EAAqC,MAAM,0BAA0B,CAAC;AACrG,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAgC,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEvF;;;GAGG;AACH,MAAM,sBAAsB,GAAG,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"useSessionPageFlow.js","sourceRoot":"","sources":["../../src/session/useSessionPageFlow.ts"],"names":[],"mappings":"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"}
|
|
@@ -48,17 +48,19 @@ import {
|
|
|
48
48
|
* Imperative handle exposed by {@link SessionComposer} via `ref`.
|
|
49
49
|
*
|
|
50
50
|
* Allows parent components to programmatically set the composer's
|
|
51
|
-
* message text
|
|
52
|
-
*
|
|
53
|
-
*
|
|
51
|
+
* message text, focus the textarea, or submit a message directly.
|
|
52
|
+
* Used for features like "Implement plan" where a CTA outside the
|
|
53
|
+
* composer needs to run the agent in one click.
|
|
54
54
|
*
|
|
55
55
|
* @example
|
|
56
56
|
* ```tsx
|
|
57
57
|
* const composerRef = useRef<SessionComposerHandle>(null);
|
|
58
58
|
*
|
|
59
59
|
* function handleBuildFromPlan() {
|
|
60
|
-
*
|
|
61
|
-
* composerRef.current?.
|
|
60
|
+
* // Switch to Agent mode and run immediately — no manual Send.
|
|
61
|
+
* composerRef.current?.submit("Implement the plan above", {
|
|
62
|
+
* interactionMode: "agent",
|
|
63
|
+
* });
|
|
62
64
|
* }
|
|
63
65
|
*
|
|
64
66
|
* <SessionComposer ref={composerRef} onSubmit={handleSubmit} />
|
|
@@ -69,6 +71,23 @@ export interface SessionComposerHandle {
|
|
|
69
71
|
setMessage(message: string): void;
|
|
70
72
|
/** Focus the composer's textarea. */
|
|
71
73
|
focus(): void;
|
|
74
|
+
/**
|
|
75
|
+
* Submit a message programmatically through the composer's full submit
|
|
76
|
+
* pipeline (system/agent/MCP env resolution, attachments, session vars).
|
|
77
|
+
*
|
|
78
|
+
* Unlike calling the consumer's `onSubmit` directly, this guarantees the
|
|
79
|
+
* same runtime context the user would get from pressing Send. No-ops when
|
|
80
|
+
* the message is empty or the composer is disabled.
|
|
81
|
+
*
|
|
82
|
+
* @param message - The message to submit.
|
|
83
|
+
* @param options.interactionMode - Force the interaction mode for this one
|
|
84
|
+
* submission, overriding the picker. Avoids the same-tick race when the
|
|
85
|
+
* caller also calls `onInteractionModeChange` just before submitting.
|
|
86
|
+
*/
|
|
87
|
+
submit(
|
|
88
|
+
message: string,
|
|
89
|
+
options?: { interactionMode?: InteractionModeOption },
|
|
90
|
+
): void;
|
|
72
91
|
}
|
|
73
92
|
|
|
74
93
|
/**
|
|
@@ -670,7 +689,7 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
|
|
|
670
689
|
// ---------------------------------------------------------------------------
|
|
671
690
|
|
|
672
691
|
const handleSubmit = useCallback(
|
|
673
|
-
async (message: string) => {
|
|
692
|
+
async (message: string, modeOverride?: InteractionModeOption) => {
|
|
674
693
|
// Persist save-for-future manual secrets before building runtimeEnv
|
|
675
694
|
if (sessionVariables?.hasSaveForFutureEntries) {
|
|
676
695
|
const saveVars = sessionVariables.toSaveForFutureEnv();
|
|
@@ -717,9 +736,10 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
|
|
|
717
736
|
const hasAttachments =
|
|
718
737
|
attachmentInputs !== undefined && attachmentInputs.length > 0;
|
|
719
738
|
const effectiveMode =
|
|
720
|
-
|
|
739
|
+
modeOverride ??
|
|
740
|
+
(showInteractionModePicker && interactionMode
|
|
721
741
|
? interactionMode
|
|
722
|
-
: undefined;
|
|
742
|
+
: undefined);
|
|
723
743
|
const hasFileRefs = enableFileReferences && fileRefs.hasRefs;
|
|
724
744
|
|
|
725
745
|
const context: SessionComposerSubmitContext | undefined =
|
|
@@ -755,7 +775,12 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
|
|
|
755
775
|
useImperativeHandle(ref, () => ({
|
|
756
776
|
setMessage: composer.setMessage,
|
|
757
777
|
focus: () => composer.textareaRef.current?.focus(),
|
|
758
|
-
|
|
778
|
+
submit: (message, options) => {
|
|
779
|
+
const trimmed = message.trim();
|
|
780
|
+
if (!trimmed || isDisabled) return;
|
|
781
|
+
void handleSubmit(trimmed, options?.interactionMode);
|
|
782
|
+
},
|
|
783
|
+
}), [composer.setMessage, composer.textareaRef, handleSubmit, isDisabled]);
|
|
759
784
|
|
|
760
785
|
const handleModelChange = useCallback(
|
|
761
786
|
(id: string) => {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
2
2
|
import { render, screen, cleanup, fireEvent, waitFor } from "@testing-library/react";
|
|
3
|
-
import type
|
|
3
|
+
import { createRef, type ReactNode } from "react";
|
|
4
4
|
import type { Stigmer } from "@stigmer/sdk";
|
|
5
5
|
import { StigmerContext } from "../../context";
|
|
6
6
|
import { ModelRegistryContext } from "../../models/ModelRegistryContext";
|
|
7
|
-
import { SessionComposer } from "../SessionComposer";
|
|
7
|
+
import { SessionComposer, type SessionComposerHandle } from "../SessionComposer";
|
|
8
8
|
|
|
9
9
|
// ---------------------------------------------------------------------------
|
|
10
10
|
// Helpers
|
|
@@ -124,3 +124,43 @@ describe("SessionComposer — public contract", () => {
|
|
|
124
124
|
expect(onSubmit).not.toHaveBeenCalled();
|
|
125
125
|
});
|
|
126
126
|
});
|
|
127
|
+
|
|
128
|
+
describe("SessionComposer — imperative submit (Implement plan)", () => {
|
|
129
|
+
it("submits a message with the interactionMode override, even when the picker is 'plan'", async () => {
|
|
130
|
+
const ref = createRef<SessionComposerHandle>();
|
|
131
|
+
const { onSubmit } = renderComposer({
|
|
132
|
+
ref,
|
|
133
|
+
showInteractionModePicker: true,
|
|
134
|
+
interactionMode: "plan",
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
ref.current!.submit("Implement the plan above", { interactionMode: "agent" });
|
|
138
|
+
|
|
139
|
+
await waitFor(() => {
|
|
140
|
+
expect(onSubmit).toHaveBeenCalledOnce();
|
|
141
|
+
});
|
|
142
|
+
const [message, , context] = onSubmit.mock.calls[0];
|
|
143
|
+
expect(message).toBe("Implement the plan above");
|
|
144
|
+
// The override must win over the current picker value ("plan") so the
|
|
145
|
+
// implement run executes in Agent mode regardless of render timing.
|
|
146
|
+
expect(context?.interactionMode).toBe("agent");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("no-ops when the composer is disabled", () => {
|
|
150
|
+
const ref = createRef<SessionComposerHandle>();
|
|
151
|
+
const { onSubmit } = renderComposer({ ref, disabled: true });
|
|
152
|
+
|
|
153
|
+
ref.current!.submit("Implement the plan above", { interactionMode: "agent" });
|
|
154
|
+
|
|
155
|
+
expect(onSubmit).not.toHaveBeenCalled();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("no-ops on an empty/whitespace message", () => {
|
|
159
|
+
const ref = createRef<SessionComposerHandle>();
|
|
160
|
+
const { onSubmit } = renderComposer({ ref });
|
|
161
|
+
|
|
162
|
+
ref.current!.submit(" ");
|
|
163
|
+
|
|
164
|
+
expect(onSubmit).not.toHaveBeenCalled();
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { InteractionMode } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
3
|
+
import {
|
|
4
|
+
toProtoInteractionMode,
|
|
5
|
+
fromProtoInteractionMode,
|
|
6
|
+
} from "../interaction-mode";
|
|
7
|
+
|
|
8
|
+
describe("interaction-mode converters", () => {
|
|
9
|
+
describe("toProtoInteractionMode", () => {
|
|
10
|
+
it("maps 'agent' to AGENT", () => {
|
|
11
|
+
expect(toProtoInteractionMode("agent")).toBe(InteractionMode.AGENT);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("maps 'plan' to PLAN", () => {
|
|
15
|
+
expect(toProtoInteractionMode("plan")).toBe(InteractionMode.PLAN);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe("fromProtoInteractionMode", () => {
|
|
20
|
+
it("maps AGENT to 'agent'", () => {
|
|
21
|
+
expect(fromProtoInteractionMode(InteractionMode.AGENT)).toBe("agent");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("maps PLAN to 'plan'", () => {
|
|
25
|
+
expect(fromProtoInteractionMode(InteractionMode.PLAN)).toBe("plan");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("maps UNSPECIFIED to undefined (caller picks the default)", () => {
|
|
29
|
+
expect(fromProtoInteractionMode(InteractionMode.UNSPECIFIED)).toBeUndefined();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("maps undefined to undefined", () => {
|
|
33
|
+
expect(fromProtoInteractionMode(undefined)).toBeUndefined();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe("round-trip", () => {
|
|
38
|
+
it("preserves 'agent' and 'plan' through proto and back", () => {
|
|
39
|
+
for (const mode of ["agent", "plan"] as const) {
|
|
40
|
+
expect(fromProtoInteractionMode(toProtoInteractionMode(mode))).toBe(mode);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
});
|
package/src/composer/index.ts
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { InteractionMode } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
2
|
+
import type { InteractionModeOption } from "./InteractionModePicker";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Convert an {@link InteractionModeOption} string to the proto
|
|
6
|
+
* {@link InteractionMode} enum.
|
|
7
|
+
*
|
|
8
|
+
* Mirrors {@link toProtoHarness} — keeps the option-string <-> proto mapping
|
|
9
|
+
* in one place so component props can stay framework-agnostic while execution
|
|
10
|
+
* creation speaks proto.
|
|
11
|
+
*/
|
|
12
|
+
export function toProtoInteractionMode(
|
|
13
|
+
mode: InteractionModeOption,
|
|
14
|
+
): InteractionMode {
|
|
15
|
+
switch (mode) {
|
|
16
|
+
case "plan":
|
|
17
|
+
return InteractionMode.PLAN;
|
|
18
|
+
case "agent":
|
|
19
|
+
default:
|
|
20
|
+
return InteractionMode.AGENT;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Convert a proto {@link InteractionMode} enum to an
|
|
26
|
+
* {@link InteractionModeOption} string.
|
|
27
|
+
*
|
|
28
|
+
* `UNSPECIFIED` (and any unknown value) maps to `undefined` so callers can
|
|
29
|
+
* decide their own default — the composer falls back to `"agent"`, matching
|
|
30
|
+
* the proto contract (`UNSPECIFIED` resolves to `INTERACTION_MODE_AGENT`).
|
|
31
|
+
*/
|
|
32
|
+
export function fromProtoInteractionMode(
|
|
33
|
+
mode: InteractionMode | undefined,
|
|
34
|
+
): InteractionModeOption | undefined {
|
|
35
|
+
switch (mode) {
|
|
36
|
+
case InteractionMode.AGENT:
|
|
37
|
+
return "agent";
|
|
38
|
+
case InteractionMode.PLAN:
|
|
39
|
+
return "plan";
|
|
40
|
+
default:
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -45,6 +45,13 @@ export interface ArtifactPreviewContentProps {
|
|
|
45
45
|
* as showing a toast or navigating to the Library.
|
|
46
46
|
*/
|
|
47
47
|
readonly onApplied?: (result: ApplyResourceResult) => void;
|
|
48
|
+
/**
|
|
49
|
+
* Optional "Implement" action. When provided, an Implement primary
|
|
50
|
+
* button appears in the action bar (used for plan artifacts: turn the
|
|
51
|
+
* plan into an Agent run). Clicking it calls `onImplement` then closes
|
|
52
|
+
* the modal. Omit for non-actionable artifacts.
|
|
53
|
+
*/
|
|
54
|
+
readonly onImplement?: () => void;
|
|
48
55
|
/** Additional CSS classes for the root container. */
|
|
49
56
|
readonly className?: string;
|
|
50
57
|
}
|
|
@@ -101,6 +108,7 @@ export function ArtifactPreviewContent({
|
|
|
101
108
|
isTerminal,
|
|
102
109
|
onClose,
|
|
103
110
|
onApplied,
|
|
111
|
+
onImplement,
|
|
104
112
|
className,
|
|
105
113
|
}: ArtifactPreviewContentProps) {
|
|
106
114
|
const isDirectory = artifact.kind === ExecutionArtifactKind.DIRECTORY;
|
|
@@ -219,6 +227,14 @@ export function ArtifactPreviewContent({
|
|
|
219
227
|
ctaLabel = `Push Skill to ${org}`;
|
|
220
228
|
}
|
|
221
229
|
|
|
230
|
+
// Implement runs the plan; closing the modal lets the host's submit pipeline
|
|
231
|
+
// take over (switch to Agent + send). Single combined handler keeps the
|
|
232
|
+
// caller's contract simple ("just give me onImplement").
|
|
233
|
+
const handleImplement = useCallback(() => {
|
|
234
|
+
onImplement?.();
|
|
235
|
+
onClose();
|
|
236
|
+
}, [onImplement, onClose]);
|
|
237
|
+
|
|
222
238
|
// ---------------------------------------------------------------------------
|
|
223
239
|
// Render
|
|
224
240
|
// ---------------------------------------------------------------------------
|
|
@@ -264,6 +280,7 @@ export function ArtifactPreviewContent({
|
|
|
264
280
|
applyResult={applyResult}
|
|
265
281
|
applyError={applyError}
|
|
266
282
|
onApply={handleApply}
|
|
283
|
+
onImplement={onImplement ? handleImplement : undefined}
|
|
267
284
|
/>
|
|
268
285
|
|
|
269
286
|
<div
|
|
@@ -308,6 +325,12 @@ export interface ArtifactPreviewModalProps {
|
|
|
308
325
|
* as showing a toast or navigating to the Library.
|
|
309
326
|
*/
|
|
310
327
|
readonly onApplied?: (result: ApplyResourceResult) => void;
|
|
328
|
+
/**
|
|
329
|
+
* Optional "Implement" action (see {@link ArtifactPreviewContentProps.onImplement}).
|
|
330
|
+
* When provided, an Implement primary button appears; clicking it calls
|
|
331
|
+
* `onImplement` then closes the modal.
|
|
332
|
+
*/
|
|
333
|
+
readonly onImplement?: () => void;
|
|
311
334
|
/** Additional CSS classes for the dialog element. */
|
|
312
335
|
readonly className?: string;
|
|
313
336
|
}
|
|
@@ -353,6 +376,7 @@ export function ArtifactPreviewModal({
|
|
|
353
376
|
open,
|
|
354
377
|
onClose,
|
|
355
378
|
onApplied,
|
|
379
|
+
onImplement,
|
|
356
380
|
className,
|
|
357
381
|
}: ArtifactPreviewModalProps) {
|
|
358
382
|
const dialogRef = useRef<HTMLDialogElement>(null);
|
|
@@ -395,6 +419,7 @@ export function ArtifactPreviewModal({
|
|
|
395
419
|
isTerminal={isTerminal}
|
|
396
420
|
onClose={onClose}
|
|
397
421
|
onApplied={onApplied}
|
|
422
|
+
onImplement={onImplement}
|
|
398
423
|
/>
|
|
399
424
|
)}
|
|
400
425
|
</dialog>
|
|
@@ -608,6 +633,7 @@ function ActionBar({
|
|
|
608
633
|
applyResult,
|
|
609
634
|
applyError,
|
|
610
635
|
onApply,
|
|
636
|
+
onImplement,
|
|
611
637
|
}: {
|
|
612
638
|
readonly artifact: ExecutionArtifact;
|
|
613
639
|
readonly isDirectory: boolean;
|
|
@@ -621,6 +647,7 @@ function ActionBar({
|
|
|
621
647
|
readonly applyResult: ApplyResourceResult | null;
|
|
622
648
|
readonly applyError: Error | null;
|
|
623
649
|
readonly onApply: () => void;
|
|
650
|
+
readonly onImplement?: () => void;
|
|
624
651
|
}) {
|
|
625
652
|
return (
|
|
626
653
|
<div className="flex items-center justify-between gap-3 border-t border-border px-4 py-3">
|
|
@@ -656,7 +683,21 @@ function ActionBar({
|
|
|
656
683
|
</a>
|
|
657
684
|
</div>
|
|
658
685
|
|
|
659
|
-
<div className="shrink-0">
|
|
686
|
+
<div className="flex shrink-0 items-center gap-3">
|
|
687
|
+
{onImplement && (
|
|
688
|
+
<button
|
|
689
|
+
type="button"
|
|
690
|
+
onClick={onImplement}
|
|
691
|
+
className={cn(
|
|
692
|
+
"inline-flex items-center gap-1.5 rounded-md px-4 py-1.5 text-xs font-medium transition-colors",
|
|
693
|
+
"bg-primary text-primary-foreground hover:bg-primary-hover",
|
|
694
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
695
|
+
)}
|
|
696
|
+
>
|
|
697
|
+
<ImplementIcon />
|
|
698
|
+
Implement
|
|
699
|
+
</button>
|
|
700
|
+
)}
|
|
660
701
|
{applyResult ? (
|
|
661
702
|
<span className="inline-flex items-center gap-1.5 text-xs font-medium text-success">
|
|
662
703
|
<CheckIcon />
|
|
@@ -873,6 +914,25 @@ function DownloadIcon() {
|
|
|
873
914
|
);
|
|
874
915
|
}
|
|
875
916
|
|
|
917
|
+
function ImplementIcon() {
|
|
918
|
+
return (
|
|
919
|
+
<svg
|
|
920
|
+
width="12"
|
|
921
|
+
height="12"
|
|
922
|
+
viewBox="0 0 12 12"
|
|
923
|
+
fill="none"
|
|
924
|
+
stroke="currentColor"
|
|
925
|
+
strokeWidth="1.5"
|
|
926
|
+
strokeLinecap="round"
|
|
927
|
+
strokeLinejoin="round"
|
|
928
|
+
className="shrink-0"
|
|
929
|
+
aria-hidden="true"
|
|
930
|
+
>
|
|
931
|
+
<path d="M2 6h8M7 3l3 3-3 3" />
|
|
932
|
+
</svg>
|
|
933
|
+
);
|
|
934
|
+
}
|
|
935
|
+
|
|
876
936
|
function CheckIcon() {
|
|
877
937
|
return (
|
|
878
938
|
<svg
|