@stigmer/react 0.0.52 → 0.0.54
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/deployment-mode.d.ts +35 -0
- package/deployment-mode.d.ts.map +1 -0
- package/deployment-mode.js +41 -0
- package/deployment-mode.js.map +1 -0
- package/execution/ApprovalCard.d.ts +8 -6
- package/execution/ApprovalCard.d.ts.map +1 -1
- package/execution/ApprovalCard.js +34 -96
- package/execution/ApprovalCard.js.map +1 -1
- package/execution/ArtifactCard.d.ts +11 -1
- package/execution/ArtifactCard.d.ts.map +1 -1
- package/execution/ArtifactCard.js +22 -3
- package/execution/ArtifactCard.js.map +1 -1
- package/execution/ArtifactPreviewModal.d.ts.map +1 -1
- package/execution/ArtifactPreviewModal.js +1 -1
- package/execution/ArtifactPreviewModal.js.map +1 -1
- package/execution/ArtifactsWidget.d.ts +26 -19
- package/execution/ArtifactsWidget.d.ts.map +1 -1
- package/execution/ArtifactsWidget.js +24 -26
- package/execution/ArtifactsWidget.js.map +1 -1
- package/execution/McpToolDetail.d.ts +48 -0
- package/execution/McpToolDetail.d.ts.map +1 -0
- package/execution/McpToolDetail.js +159 -0
- package/execution/McpToolDetail.js.map +1 -0
- package/execution/MessageThread.d.ts +10 -1
- package/execution/MessageThread.d.ts.map +1 -1
- package/execution/MessageThread.js +19 -17
- package/execution/MessageThread.js.map +1 -1
- package/execution/SandboxContext.d.ts +32 -0
- package/execution/SandboxContext.d.ts.map +1 -0
- package/execution/SandboxContext.js +26 -0
- package/execution/SandboxContext.js.map +1 -0
- package/execution/ToolArgsView.d.ts +41 -0
- package/execution/ToolArgsView.d.ts.map +1 -0
- package/execution/ToolArgsView.js +134 -0
- package/execution/ToolArgsView.js.map +1 -0
- package/execution/ToolCallDetail.d.ts +11 -4
- package/execution/ToolCallDetail.d.ts.map +1 -1
- package/execution/ToolCallDetail.js +32 -101
- package/execution/ToolCallDetail.js.map +1 -1
- package/execution/ToolCallGroup.d.ts.map +1 -1
- package/execution/ToolCallGroup.js +3 -2
- package/execution/ToolCallGroup.js.map +1 -1
- package/execution/ToolCallItem.d.ts +2 -0
- package/execution/ToolCallItem.d.ts.map +1 -1
- package/execution/ToolCallItem.js +13 -3
- package/execution/ToolCallItem.js.map +1 -1
- package/execution/WriteBackCard.d.ts +34 -0
- package/execution/WriteBackCard.d.ts.map +1 -0
- package/execution/WriteBackCard.js +75 -0
- package/execution/WriteBackCard.js.map +1 -0
- package/execution/WriteBacksWidget.d.ts +49 -0
- package/execution/WriteBacksWidget.d.ts.map +1 -0
- package/execution/WriteBacksWidget.js +44 -0
- package/execution/WriteBacksWidget.js.map +1 -0
- package/execution/__tests__/file-path-resolver.test.d.ts +2 -0
- package/execution/__tests__/file-path-resolver.test.d.ts.map +1 -0
- package/execution/__tests__/file-path-resolver.test.js +180 -0
- package/execution/__tests__/file-path-resolver.test.js.map +1 -0
- package/execution/file-path-resolver.d.ts +3 -3
- package/execution/file-path-resolver.d.ts.map +1 -1
- package/execution/file-path-resolver.js +23 -12
- package/execution/file-path-resolver.js.map +1 -1
- package/execution/index.d.ts +16 -1
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +9 -1
- package/execution/index.js.map +1 -1
- package/execution/sandbox-path-normalizer.d.ts +46 -0
- package/execution/sandbox-path-normalizer.d.ts.map +1 -0
- package/execution/sandbox-path-normalizer.js +73 -0
- package/execution/sandbox-path-normalizer.js.map +1 -0
- package/execution/tool-categories.d.ts +35 -8
- package/execution/tool-categories.d.ts.map +1 -1
- package/execution/tool-categories.js +76 -10
- package/execution/tool-categories.js.map +1 -1
- package/execution/tool-rendering-primitives.d.ts +61 -0
- package/execution/tool-rendering-primitives.d.ts.map +1 -0
- package/execution/tool-rendering-primitives.js +106 -0
- package/execution/tool-rendering-primitives.js.map +1 -0
- package/execution/useArtifactContent.d.ts +5 -1
- package/execution/useArtifactContent.d.ts.map +1 -1
- package/execution/useArtifactContent.js +6 -2
- package/execution/useArtifactContent.js.map +1 -1
- package/execution/useWorkspaceWriteBacks.d.ts +40 -0
- package/execution/useWorkspaceWriteBacks.d.ts.map +1 -0
- package/execution/useWorkspaceWriteBacks.js +41 -0
- package/execution/useWorkspaceWriteBacks.js.map +1 -0
- package/github/GitHubRepoPicker.d.ts +5 -2
- package/github/GitHubRepoPicker.d.ts.map +1 -1
- package/github/GitHubRepoPicker.js +133 -36
- package/github/GitHubRepoPicker.js.map +1 -1
- package/github/index.d.ts +1 -0
- package/github/index.d.ts.map +1 -1
- package/github/index.js +1 -0
- package/github/index.js.map +1 -1
- package/github/useGitHubSearch.d.ts +20 -0
- package/github/useGitHubSearch.d.ts.map +1 -0
- package/github/useGitHubSearch.js +127 -0
- package/github/useGitHubSearch.js.map +1 -0
- package/index.d.ts +9 -6
- package/index.d.ts.map +1 -1
- package/index.js +7 -3
- package/index.js.map +1 -1
- package/internal/CloudFeatureNotice.d.ts +19 -0
- package/internal/CloudFeatureNotice.d.ts.map +1 -0
- package/internal/CloudFeatureNotice.js +21 -0
- package/internal/CloudFeatureNotice.js.map +1 -0
- package/mcp-server/McpServerDetailView.d.ts +15 -1
- package/mcp-server/McpServerDetailView.d.ts.map +1 -1
- package/mcp-server/McpServerDetailView.js +11 -3
- package/mcp-server/McpServerDetailView.js.map +1 -1
- package/package.json +4 -4
- package/provider.d.ts +14 -2
- package/provider.d.ts.map +1 -1
- package/provider.js +3 -2
- package/provider.js.map +1 -1
- package/session/index.d.ts +4 -0
- package/session/index.d.ts.map +1 -1
- package/session/index.js +2 -0
- package/session/index.js.map +1 -1
- package/session/useSessionArtifacts.d.ts +73 -0
- package/session/useSessionArtifacts.d.ts.map +1 -0
- package/session/useSessionArtifacts.js +95 -0
- package/session/useSessionArtifacts.js.map +1 -0
- package/session/useSessionWriteBacks.d.ts +56 -0
- package/session/useSessionWriteBacks.d.ts.map +1 -0
- package/session/useSessionWriteBacks.js +56 -0
- package/session/useSessionWriteBacks.js.map +1 -0
- package/src/deployment-mode.ts +46 -0
- package/src/execution/ApprovalCard.tsx +130 -283
- package/src/execution/ArtifactCard.tsx +40 -0
- package/src/execution/ArtifactPreviewModal.tsx +2 -0
- package/src/execution/ArtifactsWidget.tsx +51 -43
- package/src/execution/McpToolDetail.tsx +283 -0
- package/src/execution/MessageThread.tsx +18 -0
- package/src/execution/SandboxContext.ts +47 -0
- package/src/execution/ToolArgsView.tsx +279 -0
- package/src/execution/ToolCallDetail.tsx +54 -220
- package/src/execution/ToolCallGroup.tsx +3 -2
- package/src/execution/ToolCallItem.tsx +21 -3
- package/src/execution/WriteBackCard.tsx +210 -0
- package/src/execution/WriteBacksWidget.tsx +82 -0
- package/src/execution/__tests__/file-path-resolver.test.ts +295 -0
- package/src/execution/file-path-resolver.ts +24 -12
- package/src/execution/index.ts +38 -0
- package/src/execution/sandbox-path-normalizer.ts +80 -0
- package/src/execution/tool-categories.ts +89 -9
- package/src/execution/tool-rendering-primitives.tsx +253 -0
- package/src/execution/useArtifactContent.ts +6 -1
- package/src/execution/useWorkspaceWriteBacks.ts +56 -0
- package/src/github/GitHubRepoPicker.tsx +413 -108
- package/src/github/index.ts +5 -0
- package/src/github/useGitHubSearch.ts +162 -0
- package/src/index.ts +27 -0
- package/src/internal/CloudFeatureNotice.tsx +60 -0
- package/src/mcp-server/McpServerDetailView.tsx +24 -2
- package/src/provider.tsx +18 -2
- package/src/session/index.ts +12 -0
- package/src/session/useSessionArtifacts.ts +143 -0
- package/src/session/useSessionWriteBacks.ts +94 -0
- package/styles.css +1 -1
package/src/github/index.ts
CHANGED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
+
import type { GitHubRepo } from "./useGitHubRepos";
|
|
5
|
+
|
|
6
|
+
const GITHUB_SEARCH_API = "https://api.github.com/search/repositories";
|
|
7
|
+
const DEBOUNCE_MS = 350;
|
|
8
|
+
const PER_PAGE = 30;
|
|
9
|
+
|
|
10
|
+
export interface UseGitHubSearchReturn {
|
|
11
|
+
readonly results: readonly GitHubRepo[];
|
|
12
|
+
readonly isSearching: boolean;
|
|
13
|
+
readonly error: string | null;
|
|
14
|
+
readonly query: string;
|
|
15
|
+
readonly setQuery: (query: string) => void;
|
|
16
|
+
readonly totalCount: number;
|
|
17
|
+
readonly hasMore: boolean;
|
|
18
|
+
readonly loadMore: () => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function parseSearchItem(r: Record<string, unknown>): GitHubRepo {
|
|
22
|
+
const ownerObj = r.owner as Record<string, unknown>;
|
|
23
|
+
return {
|
|
24
|
+
id: r.id as number,
|
|
25
|
+
fullName: r.full_name as string,
|
|
26
|
+
name: r.name as string,
|
|
27
|
+
owner: ownerObj.login as string,
|
|
28
|
+
ownerType:
|
|
29
|
+
(ownerObj.type as string) === "Organization" ? "Organization" : "User",
|
|
30
|
+
htmlUrl: r.html_url as string,
|
|
31
|
+
cloneUrl: r.clone_url as string,
|
|
32
|
+
defaultBranch: r.default_branch as string,
|
|
33
|
+
isPrivate: r.private as boolean,
|
|
34
|
+
updatedAt: r.updated_at as string,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function searchRepos(
|
|
39
|
+
query: string,
|
|
40
|
+
page: number,
|
|
41
|
+
token: string | null,
|
|
42
|
+
): Promise<{ repos: GitHubRepo[]; totalCount: number; hasMore: boolean }> {
|
|
43
|
+
const params = new URLSearchParams({
|
|
44
|
+
q: query,
|
|
45
|
+
sort: "stars",
|
|
46
|
+
order: "desc",
|
|
47
|
+
per_page: String(PER_PAGE),
|
|
48
|
+
page: String(page),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const headers: Record<string, string> = {
|
|
52
|
+
Accept: "application/vnd.github+json",
|
|
53
|
+
};
|
|
54
|
+
if (token) {
|
|
55
|
+
headers.Authorization = `Bearer ${token}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const resp = await fetch(`${GITHUB_SEARCH_API}?${params}`, { headers });
|
|
59
|
+
|
|
60
|
+
if (!resp.ok) {
|
|
61
|
+
if (resp.status === 403) {
|
|
62
|
+
throw new Error("GitHub search rate limit exceeded. Try again shortly.");
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`GitHub search error: ${resp.status}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const data = (await resp.json()) as {
|
|
68
|
+
total_count: number;
|
|
69
|
+
items: Record<string, unknown>[];
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const repos = data.items.map(parseSearchItem);
|
|
73
|
+
const totalCount = data.total_count;
|
|
74
|
+
const hasMore = page * PER_PAGE < totalCount;
|
|
75
|
+
|
|
76
|
+
return { repos, totalCount, hasMore };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Data hook that searches GitHub's public repository index.
|
|
81
|
+
*
|
|
82
|
+
* Uses the GitHub Search API (`/search/repositories`) with debounced input.
|
|
83
|
+
* Finds repositories across all of GitHub, not just the user's own repos.
|
|
84
|
+
* Works with or without an auth token (auth: 30 req/min; unauth: 10 req/min).
|
|
85
|
+
*/
|
|
86
|
+
export function useGitHubSearch(
|
|
87
|
+
token: string | null,
|
|
88
|
+
): UseGitHubSearchReturn {
|
|
89
|
+
const [query, setQuery] = useState("");
|
|
90
|
+
const [debouncedQuery, setDebouncedQuery] = useState("");
|
|
91
|
+
const [results, setResults] = useState<GitHubRepo[]>([]);
|
|
92
|
+
const [isSearching, setIsSearching] = useState(false);
|
|
93
|
+
const [error, setError] = useState<string | null>(null);
|
|
94
|
+
const [totalCount, setTotalCount] = useState(0);
|
|
95
|
+
const [hasMore, setHasMore] = useState(false);
|
|
96
|
+
const [page, setPage] = useState(1);
|
|
97
|
+
const debounceTimer = useRef<ReturnType<typeof setTimeout>>(undefined);
|
|
98
|
+
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
clearTimeout(debounceTimer.current);
|
|
101
|
+
if (!query.trim()) {
|
|
102
|
+
setDebouncedQuery("");
|
|
103
|
+
setResults([]);
|
|
104
|
+
setTotalCount(0);
|
|
105
|
+
setHasMore(false);
|
|
106
|
+
setError(null);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
debounceTimer.current = setTimeout(() => {
|
|
110
|
+
setDebouncedQuery(query.trim());
|
|
111
|
+
setPage(1);
|
|
112
|
+
}, DEBOUNCE_MS);
|
|
113
|
+
return () => clearTimeout(debounceTimer.current);
|
|
114
|
+
}, [query]);
|
|
115
|
+
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
if (!debouncedQuery) return;
|
|
118
|
+
|
|
119
|
+
const cancelled = { current: false };
|
|
120
|
+
|
|
121
|
+
async function run() {
|
|
122
|
+
setIsSearching(true);
|
|
123
|
+
setError(null);
|
|
124
|
+
try {
|
|
125
|
+
const result = await searchRepos(debouncedQuery, page, token);
|
|
126
|
+
if (cancelled.current) return;
|
|
127
|
+
setResults((prev) =>
|
|
128
|
+
page === 1 ? result.repos : [...prev, ...result.repos],
|
|
129
|
+
);
|
|
130
|
+
setTotalCount(result.totalCount);
|
|
131
|
+
setHasMore(result.hasMore);
|
|
132
|
+
} catch (e) {
|
|
133
|
+
if (cancelled.current) return;
|
|
134
|
+
setError(e instanceof Error ? e.message : "Search failed");
|
|
135
|
+
} finally {
|
|
136
|
+
if (!cancelled.current) setIsSearching(false);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
run();
|
|
141
|
+
return () => {
|
|
142
|
+
cancelled.current = true;
|
|
143
|
+
};
|
|
144
|
+
}, [debouncedQuery, page, token]);
|
|
145
|
+
|
|
146
|
+
const loadMore = useCallback(() => {
|
|
147
|
+
if (hasMore && !isSearching) {
|
|
148
|
+
setPage((prev) => prev + 1);
|
|
149
|
+
}
|
|
150
|
+
}, [hasMore, isSearching]);
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
results,
|
|
154
|
+
isSearching,
|
|
155
|
+
error,
|
|
156
|
+
query,
|
|
157
|
+
setQuery,
|
|
158
|
+
totalCount,
|
|
159
|
+
hasMore,
|
|
160
|
+
loadMore,
|
|
161
|
+
};
|
|
162
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,11 @@ export { StigmerContext } from "./context";
|
|
|
5
5
|
// Hooks
|
|
6
6
|
export { useStigmer } from "./hooks";
|
|
7
7
|
|
|
8
|
+
// Deployment mode and resource availability
|
|
9
|
+
export { useDeploymentMode, useResourceAvailable } from "./deployment-mode";
|
|
10
|
+
export { type DeploymentMode, isResourceAvailable, ApiResourceKind } from "@stigmer/sdk";
|
|
11
|
+
export { CloudFeatureNotice, type CloudFeatureNoticeProps } from "./internal/CloudFeatureNotice";
|
|
12
|
+
|
|
8
13
|
// Models — data hook, styled component, and registry data
|
|
9
14
|
export {
|
|
10
15
|
MODEL_REGISTRY,
|
|
@@ -47,6 +52,8 @@ export {
|
|
|
47
52
|
useSessionList,
|
|
48
53
|
useSessionExecutions,
|
|
49
54
|
useSessionConversation,
|
|
55
|
+
useSessionArtifacts,
|
|
56
|
+
useSessionWriteBacks,
|
|
50
57
|
useAgentRefFromSession,
|
|
51
58
|
groupSessionsByTime,
|
|
52
59
|
PENDING_SUBJECT,
|
|
@@ -63,6 +70,10 @@ export type {
|
|
|
63
70
|
UseSessionExecutionsReturn,
|
|
64
71
|
SendFollowUpOptions,
|
|
65
72
|
UseSessionConversationReturn,
|
|
73
|
+
SessionArtifactEntry,
|
|
74
|
+
UseSessionArtifactsReturn,
|
|
75
|
+
SessionWriteBackEntry,
|
|
76
|
+
UseSessionWriteBacksReturn,
|
|
66
77
|
UseAgentRefFromSessionReturn,
|
|
67
78
|
SessionGroup,
|
|
68
79
|
} from "./session";
|
|
@@ -81,7 +92,10 @@ export {
|
|
|
81
92
|
ExecutionCostSummary,
|
|
82
93
|
ToolCallGroup,
|
|
83
94
|
ToolCallDetail,
|
|
95
|
+
McpToolDetail,
|
|
96
|
+
parseMcpResult,
|
|
84
97
|
formatDuration,
|
|
98
|
+
humanizeToolName,
|
|
85
99
|
ToolCallItem,
|
|
86
100
|
SubAgentSection,
|
|
87
101
|
MessageEntry,
|
|
@@ -92,6 +106,10 @@ export {
|
|
|
92
106
|
ArtifactContentRenderer,
|
|
93
107
|
ArtifactPreviewModal,
|
|
94
108
|
ArtifactsWidget,
|
|
109
|
+
WriteBacksWidget,
|
|
110
|
+
ToolArgsView,
|
|
111
|
+
McpArgsView,
|
|
112
|
+
McpMetadataRow,
|
|
95
113
|
FilePathLink,
|
|
96
114
|
FilePathContext,
|
|
97
115
|
classifyPath,
|
|
@@ -101,6 +119,8 @@ export {
|
|
|
101
119
|
SessionVariablesInput,
|
|
102
120
|
useExecutionArtifacts,
|
|
103
121
|
useArtifactContent,
|
|
122
|
+
useWorkspaceWriteBacks,
|
|
123
|
+
WriteBackCard,
|
|
104
124
|
isTextArtifact,
|
|
105
125
|
isArtifactExpired,
|
|
106
126
|
formatArtifactSize,
|
|
@@ -121,6 +141,8 @@ export type {
|
|
|
121
141
|
ExecutionCostSummaryProps,
|
|
122
142
|
ToolCallGroupProps,
|
|
123
143
|
ToolCallDetailProps,
|
|
144
|
+
McpToolDetailProps,
|
|
145
|
+
ToolArgsViewProps,
|
|
124
146
|
ToolCallItemProps,
|
|
125
147
|
SubAgentSectionProps,
|
|
126
148
|
MessageEntryProps,
|
|
@@ -132,6 +154,7 @@ export type {
|
|
|
132
154
|
ArtifactRenderMode,
|
|
133
155
|
ArtifactPreviewModalProps,
|
|
134
156
|
ArtifactsWidgetProps,
|
|
157
|
+
WriteBacksWidgetProps,
|
|
135
158
|
FilePathLinkProps,
|
|
136
159
|
FilePathContextValue,
|
|
137
160
|
PathClassification,
|
|
@@ -141,6 +164,8 @@ export type {
|
|
|
141
164
|
SessionVariablesInputProps,
|
|
142
165
|
UseExecutionArtifactsReturn,
|
|
143
166
|
UseArtifactContentReturn,
|
|
167
|
+
UseWorkspaceWriteBacksReturn,
|
|
168
|
+
WriteBackCardProps,
|
|
144
169
|
} from "./execution";
|
|
145
170
|
|
|
146
171
|
// Execution — proto type re-exports for artifact consumers
|
|
@@ -244,6 +269,7 @@ export type {
|
|
|
244
269
|
export {
|
|
245
270
|
useGitHubConnection,
|
|
246
271
|
useGitHubRepos,
|
|
272
|
+
useGitHubSearch,
|
|
247
273
|
GitHubRepoPicker,
|
|
248
274
|
GITHUB_CALLBACK_MESSAGE_TYPE,
|
|
249
275
|
} from "./github";
|
|
@@ -254,6 +280,7 @@ export type {
|
|
|
254
280
|
GitHubRepo,
|
|
255
281
|
GitHubBranch,
|
|
256
282
|
UseGitHubReposReturn,
|
|
283
|
+
UseGitHubSearchReturn,
|
|
257
284
|
GitHubRepoPickerProps,
|
|
258
285
|
} from "./github";
|
|
259
286
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import { cn } from "@stigmer/theme";
|
|
5
|
+
|
|
6
|
+
export interface CloudFeatureNoticeProps {
|
|
7
|
+
/** Explanation of why the feature is unavailable and what to do instead. */
|
|
8
|
+
readonly children: ReactNode;
|
|
9
|
+
readonly className?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Subdued info notice displayed in place of cloud-only feature content
|
|
14
|
+
* when the connected Stigmer backend does not support the feature.
|
|
15
|
+
*
|
|
16
|
+
* Renders an inline box with an info icon and the provided message.
|
|
17
|
+
* The parent section provides its own heading and description — this
|
|
18
|
+
* component is purely the "why it's absent" explanation.
|
|
19
|
+
*
|
|
20
|
+
* All visual properties flow through `--stgm-*` design tokens.
|
|
21
|
+
* No Console-specific dependencies — safe for platform builder embedding.
|
|
22
|
+
*/
|
|
23
|
+
export function CloudFeatureNotice({
|
|
24
|
+
children,
|
|
25
|
+
className,
|
|
26
|
+
}: CloudFeatureNoticeProps) {
|
|
27
|
+
return (
|
|
28
|
+
<div
|
|
29
|
+
role="status"
|
|
30
|
+
className={cn(
|
|
31
|
+
"bg-muted/50 text-muted-foreground flex items-start gap-2.5 rounded-lg border border-transparent px-4 py-3",
|
|
32
|
+
className,
|
|
33
|
+
)}
|
|
34
|
+
>
|
|
35
|
+
<InfoIcon className="mt-0.5 size-4 shrink-0" />
|
|
36
|
+
<p className="text-xs leading-relaxed">{children}</p>
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function InfoIcon({ className }: { className?: string }) {
|
|
42
|
+
return (
|
|
43
|
+
<svg
|
|
44
|
+
width="16"
|
|
45
|
+
height="16"
|
|
46
|
+
viewBox="0 0 16 16"
|
|
47
|
+
fill="none"
|
|
48
|
+
stroke="currentColor"
|
|
49
|
+
strokeWidth="1.5"
|
|
50
|
+
strokeLinecap="round"
|
|
51
|
+
strokeLinejoin="round"
|
|
52
|
+
className={className}
|
|
53
|
+
aria-hidden="true"
|
|
54
|
+
>
|
|
55
|
+
<circle cx="8" cy="8" r="6.25" />
|
|
56
|
+
<path d="M8 7v4" />
|
|
57
|
+
<circle cx="8" cy="5" r="0.5" fill="currentColor" stroke="none" />
|
|
58
|
+
</svg>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -46,6 +46,20 @@ export interface McpServerDetailViewProps {
|
|
|
46
46
|
readonly onVisibilityChange?: (v: ApiResourceVisibility) => void;
|
|
47
47
|
/** `true` while a visibility update RPC is in flight. */
|
|
48
48
|
readonly isVisibilityPending?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Called after the approval-policy generation session and execution
|
|
51
|
+
* have been created successfully.
|
|
52
|
+
*
|
|
53
|
+
* When provided, the component delegates post-trigger behavior to the
|
|
54
|
+
* consumer (e.g. navigating to a session page) instead of rendering
|
|
55
|
+
* the inline {@link ApprovalPolicyGeneratorPanel}.
|
|
56
|
+
*
|
|
57
|
+
* When omitted, the inline panel is shown as a fallback.
|
|
58
|
+
*/
|
|
59
|
+
readonly onPolicySessionCreated?: (info: {
|
|
60
|
+
sessionId: string;
|
|
61
|
+
executionId: string;
|
|
62
|
+
}) => void;
|
|
49
63
|
/** Additional CSS classes for the root container. */
|
|
50
64
|
readonly className?: string;
|
|
51
65
|
}
|
|
@@ -78,6 +92,7 @@ export function McpServerDetailView({
|
|
|
78
92
|
onResourceLoad,
|
|
79
93
|
onVisibilityChange,
|
|
80
94
|
isVisibilityPending,
|
|
95
|
+
onPolicySessionCreated,
|
|
81
96
|
className,
|
|
82
97
|
}: McpServerDetailViewProps) {
|
|
83
98
|
const { mcpServer, isLoading, error, refetch } = useMcpServer(org, slug);
|
|
@@ -149,11 +164,18 @@ export function McpServerDetailView({
|
|
|
149
164
|
try {
|
|
150
165
|
const yaml = serializeMcpServerYaml(mcpServer);
|
|
151
166
|
const result = await policySession.trigger(yaml, org, slug);
|
|
152
|
-
|
|
167
|
+
if (onPolicySessionCreated) {
|
|
168
|
+
onPolicySessionCreated({
|
|
169
|
+
sessionId: result.sessionId,
|
|
170
|
+
executionId: result.executionId,
|
|
171
|
+
});
|
|
172
|
+
} else {
|
|
173
|
+
setPolicyPanelExecutionId(result.executionId);
|
|
174
|
+
}
|
|
153
175
|
} catch {
|
|
154
176
|
// error state is managed by the hook
|
|
155
177
|
}
|
|
156
|
-
}, [mcpServer, org, slug, policySession]);
|
|
178
|
+
}, [mcpServer, org, slug, policySession, onPolicySessionCreated]);
|
|
157
179
|
|
|
158
180
|
const handlePolicyPanelComplete = useCallback(() => {
|
|
159
181
|
refetch();
|
package/src/provider.tsx
CHANGED
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
|
-
import type { Stigmer } from "@stigmer/sdk";
|
|
4
|
+
import type { Stigmer, DeploymentMode } from "@stigmer/sdk";
|
|
5
5
|
import { cn, resolvePresetClass } from "@stigmer/theme";
|
|
6
6
|
import type { ThemePresetId } from "@stigmer/theme";
|
|
7
7
|
import { StigmerContext } from "./context";
|
|
8
|
+
import { DeploymentModeContext } from "./deployment-mode";
|
|
8
9
|
|
|
9
10
|
export interface StigmerProviderProps {
|
|
10
11
|
/** A configured {@link Stigmer} client instance. */
|
|
11
12
|
readonly client: Stigmer;
|
|
12
13
|
readonly children: ReactNode;
|
|
14
|
+
/**
|
|
15
|
+
* Deployment mode of the connected Stigmer backend.
|
|
16
|
+
*
|
|
17
|
+
* - `"local"` — local Go CLI server (OSS). Cloud-only resources
|
|
18
|
+
* (API keys, IAM, identity management) are unavailable.
|
|
19
|
+
* - `"cloud"` — Stigmer Cloud. All resources are available.
|
|
20
|
+
*
|
|
21
|
+
* Defaults to `"cloud"` so existing consumers see no change.
|
|
22
|
+
* The Stigmer Console derives this from the API URL hostname.
|
|
23
|
+
* Platform builders pass it based on their deployment context.
|
|
24
|
+
*/
|
|
25
|
+
readonly deploymentMode?: DeploymentMode;
|
|
13
26
|
/**
|
|
14
27
|
* Built-in theme preset to apply.
|
|
15
28
|
*
|
|
@@ -60,6 +73,7 @@ export interface StigmerProviderProps {
|
|
|
60
73
|
export function StigmerProvider({
|
|
61
74
|
client,
|
|
62
75
|
children,
|
|
76
|
+
deploymentMode = "cloud",
|
|
63
77
|
preset,
|
|
64
78
|
className,
|
|
65
79
|
}: StigmerProviderProps) {
|
|
@@ -67,7 +81,9 @@ export function StigmerProvider({
|
|
|
67
81
|
|
|
68
82
|
return (
|
|
69
83
|
<StigmerContext.Provider value={client}>
|
|
70
|
-
<
|
|
84
|
+
<DeploymentModeContext.Provider value={deploymentMode}>
|
|
85
|
+
<div className={cn("stgm", presetClass, className)}>{children}</div>
|
|
86
|
+
</DeploymentModeContext.Provider>
|
|
71
87
|
</StigmerContext.Provider>
|
|
72
88
|
);
|
|
73
89
|
}
|
package/src/session/index.ts
CHANGED
|
@@ -26,6 +26,18 @@ export type {
|
|
|
26
26
|
UseSessionConversationReturn,
|
|
27
27
|
} from "./useSessionConversation";
|
|
28
28
|
|
|
29
|
+
export { useSessionArtifacts } from "./useSessionArtifacts";
|
|
30
|
+
export type {
|
|
31
|
+
SessionArtifactEntry,
|
|
32
|
+
UseSessionArtifactsReturn,
|
|
33
|
+
} from "./useSessionArtifacts";
|
|
34
|
+
|
|
35
|
+
export { useSessionWriteBacks } from "./useSessionWriteBacks";
|
|
36
|
+
export type {
|
|
37
|
+
SessionWriteBackEntry,
|
|
38
|
+
UseSessionWriteBacksReturn,
|
|
39
|
+
} from "./useSessionWriteBacks";
|
|
40
|
+
|
|
29
41
|
export { useAgentRefFromSession } from "./useAgentRefFromSession";
|
|
30
42
|
export type { UseAgentRefFromSessionReturn } from "./useAgentRefFromSession";
|
|
31
43
|
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
5
|
+
import type { ExecutionArtifact } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/artifact_pb";
|
|
6
|
+
import { ExecutionPhase } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
7
|
+
import { isTerminalPhase } from "../execution/execution-phases";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A single artifact entry enriched with the execution context needed
|
|
11
|
+
* for content fetching and Apply/Push gating.
|
|
12
|
+
*
|
|
13
|
+
* The `executionId` identifies which execution produced (or last
|
|
14
|
+
* updated) this artifact — required by {@link useArtifactContent} and
|
|
15
|
+
* {@link ArtifactPreviewModal}. `isTerminal` controls whether the
|
|
16
|
+
* Apply CTA is enabled in the preview modal.
|
|
17
|
+
*/
|
|
18
|
+
export interface SessionArtifactEntry {
|
|
19
|
+
readonly artifact: ExecutionArtifact;
|
|
20
|
+
/** ID of the execution that produced this artifact version. */
|
|
21
|
+
readonly executionId: string;
|
|
22
|
+
/** Whether the producing execution is in a terminal phase. */
|
|
23
|
+
readonly isTerminal: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* `true` when another artifact in the deduplicated list shares the
|
|
26
|
+
* same display `name` but has a different `sandbox_path`. Consumers
|
|
27
|
+
* use this to render path context for disambiguation.
|
|
28
|
+
*/
|
|
29
|
+
readonly hasNameCollision: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface UseSessionArtifactsReturn {
|
|
33
|
+
/** Deduplicated, alphabetically-sorted artifacts from all executions. */
|
|
34
|
+
readonly artifacts: readonly SessionArtifactEntry[];
|
|
35
|
+
/** `true` when there is at least one artifact across all executions. */
|
|
36
|
+
readonly hasArtifacts: boolean;
|
|
37
|
+
/** Total number of deduplicated artifacts. */
|
|
38
|
+
readonly artifactCount: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Returns the dedup key for an artifact. Uses `sandbox_path` when
|
|
43
|
+
* available (stable filesystem identity within the session sandbox),
|
|
44
|
+
* falling back to `name` for older artifacts that predate the field.
|
|
45
|
+
*/
|
|
46
|
+
function dedupKey(artifact: ExecutionArtifact): string {
|
|
47
|
+
return artifact.sandboxPath || artifact.name;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Pure derivation hook that aggregates artifacts across all executions
|
|
52
|
+
* in a session into a unified, deduplicated, alphabetically-sorted
|
|
53
|
+
* list — like a file explorer showing the conversation's output.
|
|
54
|
+
*
|
|
55
|
+
* Follows the same `useMemo`-based pattern as
|
|
56
|
+
* {@link useExecutionArtifacts}: no side effects, no data fetching.
|
|
57
|
+
*
|
|
58
|
+
* **Dedup semantics:** Artifacts are keyed by `sandbox_path` (the
|
|
59
|
+
* original filesystem path in the agent sandbox). When multiple
|
|
60
|
+
* executions produce an artifact at the same path, the latest
|
|
61
|
+
* execution's version wins — matching filesystem overwrite semantics.
|
|
62
|
+
*
|
|
63
|
+
* **Sorting:** Entries are sorted alphabetically by display `name`
|
|
64
|
+
* (case-insensitive). This matches the file-explorer mental model
|
|
65
|
+
* where users scan by filename, not by creation order.
|
|
66
|
+
*
|
|
67
|
+
* **Name collision detection:** When two artifacts share the same
|
|
68
|
+
* display `name` but differ in `sandbox_path`, both entries are
|
|
69
|
+
* flagged with `hasNameCollision: true` so consumers can render path
|
|
70
|
+
* context for disambiguation.
|
|
71
|
+
*
|
|
72
|
+
* @param executions - All executions for a session, in chronological
|
|
73
|
+
* order (as returned by `listBySession`). Pass both completed and
|
|
74
|
+
* active-stream executions.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```tsx
|
|
78
|
+
* const conv = useSessionConversation(sessionId, org);
|
|
79
|
+
* const allExecutions = [
|
|
80
|
+
* ...conv.completedExecutions,
|
|
81
|
+
* ...(conv.activeStreamExecution ? [conv.activeStreamExecution] : []),
|
|
82
|
+
* ];
|
|
83
|
+
* const { artifacts, hasArtifacts } = useSessionArtifacts(allExecutions);
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @see useExecutionArtifacts — single-execution artifact derivation
|
|
87
|
+
* @see ArtifactsWidget — styled component that renders this data
|
|
88
|
+
*/
|
|
89
|
+
export function useSessionArtifacts(
|
|
90
|
+
executions: readonly AgentExecution[],
|
|
91
|
+
): UseSessionArtifactsReturn {
|
|
92
|
+
return useMemo(() => {
|
|
93
|
+
const entryMap = new Map<string, SessionArtifactEntry>();
|
|
94
|
+
|
|
95
|
+
for (const execution of executions) {
|
|
96
|
+
const executionId = execution.metadata?.id ?? "";
|
|
97
|
+
const phase =
|
|
98
|
+
execution.status?.phase ??
|
|
99
|
+
ExecutionPhase.EXECUTION_PHASE_UNSPECIFIED;
|
|
100
|
+
const terminal = isTerminalPhase(phase);
|
|
101
|
+
|
|
102
|
+
for (const artifact of execution.status?.artifacts ?? []) {
|
|
103
|
+
const key = dedupKey(artifact);
|
|
104
|
+
entryMap.set(key, {
|
|
105
|
+
artifact,
|
|
106
|
+
executionId,
|
|
107
|
+
isTerminal: terminal,
|
|
108
|
+
hasNameCollision: false,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const entries = Array.from(entryMap.values());
|
|
114
|
+
|
|
115
|
+
entries.sort((a, b) =>
|
|
116
|
+
a.artifact.name.localeCompare(b.artifact.name, undefined, {
|
|
117
|
+
sensitivity: "base",
|
|
118
|
+
}),
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// Detect name collisions: entries that share a display name but
|
|
122
|
+
// have different sandbox paths need path context for disambiguation.
|
|
123
|
+
const nameCount = new Map<string, number>();
|
|
124
|
+
for (const entry of entries) {
|
|
125
|
+
const lower = entry.artifact.name.toLowerCase();
|
|
126
|
+
nameCount.set(lower, (nameCount.get(lower) ?? 0) + 1);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const result: SessionArtifactEntry[] = entries.map((entry) => {
|
|
130
|
+
const lower = entry.artifact.name.toLowerCase();
|
|
131
|
+
if ((nameCount.get(lower) ?? 0) > 1) {
|
|
132
|
+
return { ...entry, hasNameCollision: true };
|
|
133
|
+
}
|
|
134
|
+
return entry;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
artifacts: result,
|
|
139
|
+
hasArtifacts: result.length > 0,
|
|
140
|
+
artifactCount: result.length,
|
|
141
|
+
};
|
|
142
|
+
}, [executions]);
|
|
143
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
5
|
+
import type { WorkspaceWriteBack } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/writeback_pb";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A single write-back entry enriched with the execution context that
|
|
9
|
+
* produced it.
|
|
10
|
+
*
|
|
11
|
+
* The `executionId` links the write-back to its originating execution
|
|
12
|
+
* for traceability in the UI (e.g., tooltip or detail view).
|
|
13
|
+
*/
|
|
14
|
+
export interface SessionWriteBackEntry {
|
|
15
|
+
readonly writeBack: WorkspaceWriteBack;
|
|
16
|
+
/** ID of the execution that produced this write-back. */
|
|
17
|
+
readonly executionId: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface UseSessionWriteBacksReturn {
|
|
21
|
+
/** All write-backs from the session, ordered by workspace entry name. */
|
|
22
|
+
readonly writeBacks: readonly SessionWriteBackEntry[];
|
|
23
|
+
/** `true` when there is at least one write-back across all executions. */
|
|
24
|
+
readonly hasWriteBacks: boolean;
|
|
25
|
+
/** Total number of write-backs. */
|
|
26
|
+
readonly writeBackCount: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Pure derivation hook that aggregates workspace write-backs across all
|
|
31
|
+
* executions in a session into a flat, deduplicated list.
|
|
32
|
+
*
|
|
33
|
+
* Follows the same pattern as {@link useSessionArtifacts}: `useMemo`-based
|
|
34
|
+
* derivation, no side effects, no data fetching. Takes the same
|
|
35
|
+
* `executions` array input.
|
|
36
|
+
*
|
|
37
|
+
* **Dedup semantics:** Write-backs are keyed by `workspace_entry_name`.
|
|
38
|
+
* When multiple executions write back to the same workspace entry (e.g.,
|
|
39
|
+
* a follow-up execution on the same git repo), the latest execution's
|
|
40
|
+
* write-back wins — each execution creates its own branch/PR, and the
|
|
41
|
+
* most recent one is the one users care about.
|
|
42
|
+
*
|
|
43
|
+
* **Sorting:** Entries are sorted alphabetically by workspace entry name.
|
|
44
|
+
*
|
|
45
|
+
* @param executions - All executions for a session, in chronological
|
|
46
|
+
* order. Pass both completed and active-stream executions.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```tsx
|
|
50
|
+
* const conv = useSessionConversation(sessionId, org);
|
|
51
|
+
* const allExecutions = [
|
|
52
|
+
* ...conv.completedExecutions,
|
|
53
|
+
* ...(conv.activeStreamExecution ? [conv.activeStreamExecution] : []),
|
|
54
|
+
* ];
|
|
55
|
+
* const { writeBacks, hasWriteBacks } = useSessionWriteBacks(allExecutions);
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* @see useWorkspaceWriteBacks — single-execution write-back derivation
|
|
59
|
+
* @see WriteBackCard — component that renders a single write-back
|
|
60
|
+
*/
|
|
61
|
+
export function useSessionWriteBacks(
|
|
62
|
+
executions: readonly AgentExecution[],
|
|
63
|
+
): UseSessionWriteBacksReturn {
|
|
64
|
+
return useMemo(() => {
|
|
65
|
+
const entryMap = new Map<string, SessionWriteBackEntry>();
|
|
66
|
+
|
|
67
|
+
for (const execution of executions) {
|
|
68
|
+
const executionId = execution.metadata?.id ?? "";
|
|
69
|
+
|
|
70
|
+
for (const wb of execution.status?.workspaceWriteBacks ?? []) {
|
|
71
|
+
entryMap.set(wb.workspaceEntryName, {
|
|
72
|
+
writeBack: wb,
|
|
73
|
+
executionId,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const entries = Array.from(entryMap.values());
|
|
79
|
+
|
|
80
|
+
entries.sort((a, b) =>
|
|
81
|
+
a.writeBack.workspaceEntryName.localeCompare(
|
|
82
|
+
b.writeBack.workspaceEntryName,
|
|
83
|
+
undefined,
|
|
84
|
+
{ sensitivity: "base" },
|
|
85
|
+
),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
writeBacks: entries,
|
|
90
|
+
hasWriteBacks: entries.length > 0,
|
|
91
|
+
writeBackCount: entries.length,
|
|
92
|
+
};
|
|
93
|
+
}, [executions]);
|
|
94
|
+
}
|