@tangle-network/sandbox-ui 0.14.0 → 0.15.1
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/dist/auth.d.ts +1 -74
- package/dist/auth.js +1 -4
- package/dist/chat.d.ts +1 -136
- package/dist/chat.js +2 -15
- package/dist/chunk-2BUPSB7O.js +0 -0
- package/dist/chunk-3J6FG3FJ.js +18 -0
- package/dist/chunk-76IQLPW2.js +206 -0
- package/dist/chunk-7ZA5SEK3.js +239 -0
- package/dist/chunk-AHBZCBDO.js +2960 -0
- package/dist/chunk-AZ3AWMTM.js +8 -0
- package/dist/chunk-CMY7W45U.js +380 -0
- package/dist/{chunk-QMU2PWOU.js → chunk-DNZ4DTNA.js} +71 -17
- package/dist/chunk-EI44GEQ5.js +6 -0
- package/dist/{chunk-5OQ27N57.js → chunk-GPT7VKK6.js} +34 -38
- package/dist/chunk-JBGKGLD7.js +16 -0
- package/dist/chunk-NJNME4J4.js +14 -0
- package/dist/chunk-QPAJR74X.js +20 -0
- package/dist/chunk-TK46XFLM.js +28 -0
- package/dist/chunk-WID73FPH.js +89 -0
- package/dist/chunk-YVXK4XRO.js +30 -0
- package/dist/dashboard.d.ts +538 -4
- package/dist/dashboard.js +15 -886
- package/dist/editor.d.ts +1 -120
- package/dist/editor.js +1 -5
- package/dist/files.d.ts +1 -129
- package/dist/files.js +2 -7
- package/dist/globals.css +2 -1265
- package/dist/hooks.d.ts +114 -11
- package/dist/hooks.js +17 -88
- package/dist/index.d.ts +24 -99
- package/dist/index.js +247 -252
- package/dist/markdown.d.ts +1 -29
- package/dist/markdown.js +2 -2
- package/dist/openui.d.ts +8 -115
- package/dist/openui.js +1 -6
- package/dist/pages.d.ts +1 -2
- package/dist/pages.js +68 -66
- package/dist/primitives.d.ts +14 -49
- package/dist/primitives.js +69 -77
- package/dist/run.d.ts +1 -14
- package/dist/run.js +2 -22
- package/dist/sdk-hooks.d.ts +3 -283
- package/dist/sdk-hooks.js +10 -14
- package/dist/stores.d.ts +2 -14
- package/dist/stores.js +11 -39
- package/dist/styles.css +2 -1265
- package/dist/{usage-chart-CPTcNlGs.d.ts → template-card-UhV3pmRC.d.ts} +16 -1
- package/dist/types.d.ts +11 -8
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +1 -44
- package/dist/utils.js +6 -12
- package/dist/workspace.d.ts +5 -10
- package/dist/workspace.js +3 -19
- package/package.json +19 -54
- package/dist/active-sessions-store-CeOmXgv5.d.ts +0 -85
- package/dist/artifact-pane-Bh45Ssco.d.ts +0 -24
- package/dist/branding-DCi5VEik.d.ts +0 -13
- package/dist/button-CMQuQEW_.d.ts +0 -17
- package/dist/chat-container-f4yEs6KN.d.ts +0 -106
- package/dist/chunk-34A66VBG.js +0 -214
- package/dist/chunk-34I7UFSX.js +0 -92
- package/dist/chunk-36QY2W5G.js +0 -802
- package/dist/chunk-4CLN43XT.js +0 -45
- package/dist/chunk-54SQQMMM.js +0 -156
- package/dist/chunk-66EZOYZR.js +0 -102
- package/dist/chunk-BX6AQMUS.js +0 -183
- package/dist/chunk-DI3NZ5ZX.js +0 -192
- package/dist/chunk-DPGIXDAI.js +0 -220
- package/dist/chunk-DXMIEK4K.js +0 -1426
- package/dist/chunk-GSZA3TSY.js +0 -79
- package/dist/chunk-HB5Y37YU.js +0 -54
- package/dist/chunk-LQNEZDRM.js +0 -109
- package/dist/chunk-MA7YKRUP.js +0 -131
- package/dist/chunk-MKTSMWVD.js +0 -109
- package/dist/chunk-MQXABZTB.js +0 -1348
- package/dist/chunk-MT5FJ3ZT.js +0 -186
- package/dist/chunk-NKUPJC34.js +0 -2070
- package/dist/chunk-OEX7NZE3.js +0 -321
- package/dist/chunk-OKLQVY3Y.js +0 -139
- package/dist/chunk-Q56BYXQF.js +0 -61
- package/dist/chunk-QD4QE5P5.js +0 -40
- package/dist/chunk-QDH5GEGY.js +0 -630
- package/dist/chunk-QID2OOMG.js +0 -133
- package/dist/chunk-RQHJBTEU.js +0 -10
- package/dist/chunk-T7HMZEVO.js +0 -216
- package/dist/chunk-U6QTHMY6.js +0 -1290
- package/dist/chunk-US6JKJKH.js +0 -124
- package/dist/chunk-VX3XOUEB.js +0 -63
- package/dist/chunk-XLG757B6.js +0 -933
- package/dist/chunk-ZMNSRDMH.js +0 -127
- package/dist/chunk-ZNCEM5CD.js +0 -316
- package/dist/document-editor-pane-A70-EhdQ.d.ts +0 -124
- package/dist/document-editor-pane-TLPVRBBU.js +0 -11
- package/dist/expanded-tool-detail-Dh99mcbY.d.ts +0 -63
- package/dist/file-tabs-BLfxfmAH.d.ts +0 -51
- package/dist/parts-CyGkM6Fp.d.ts +0 -50
- package/dist/run-CtFZ6s-D.d.ts +0 -41
- package/dist/sidebar-drop-zone-tDBsuOH5.d.ts +0 -301
- package/dist/sidecar-CFU2W9j1.d.ts +0 -8
- package/dist/template-card-BAtvcAkU.d.ts +0 -18
- package/dist/tool-call-feed-Bs3MyQMT.d.ts +0 -68
- package/dist/tool-display-Ct9nFAzJ.d.ts +0 -32
- package/dist/use-sandbox-metrics-DWc0k9Xm.d.ts +0 -153
- package/dist/variant-list-BrHYcBCk.d.ts +0 -540
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
// src/hooks/use-session-stream.ts
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
function mapApiMessage(msg, counterRef) {
|
|
4
|
+
const created = msg.info.timestamp ? new Date(msg.info.timestamp).getTime() : Date.now();
|
|
5
|
+
const message = {
|
|
6
|
+
id: msg.info.id,
|
|
7
|
+
role: msg.info.role,
|
|
8
|
+
time: { created },
|
|
9
|
+
_insertionIndex: counterRef.current++
|
|
10
|
+
};
|
|
11
|
+
const parts = (msg.parts ?? []).map((p, i) => {
|
|
12
|
+
if (p.type === "tool" && p.tool) {
|
|
13
|
+
return {
|
|
14
|
+
type: "tool",
|
|
15
|
+
id: p.id ?? `${msg.info.id}-tool-${i}`,
|
|
16
|
+
tool: p.tool,
|
|
17
|
+
state: {
|
|
18
|
+
status: p.state?.status ?? "completed",
|
|
19
|
+
input: p.state?.input,
|
|
20
|
+
output: p.state?.output,
|
|
21
|
+
error: p.state?.error,
|
|
22
|
+
metadata: p.state?.metadata,
|
|
23
|
+
time: p.time
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (p.type === "reasoning") {
|
|
28
|
+
return {
|
|
29
|
+
type: "reasoning",
|
|
30
|
+
text: p.text ?? "",
|
|
31
|
+
time: p.time
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return { type: "text", text: p.text ?? "" };
|
|
35
|
+
});
|
|
36
|
+
return { message, parts };
|
|
37
|
+
}
|
|
38
|
+
async function fetchJson(url, token, init) {
|
|
39
|
+
const headers = { Authorization: `Bearer ${token}` };
|
|
40
|
+
if (init?.body) headers["Content-Type"] = "application/json";
|
|
41
|
+
const res = await fetch(url, { ...init, headers: { ...headers, ...init?.headers }, credentials: "include" });
|
|
42
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
43
|
+
return res.json();
|
|
44
|
+
}
|
|
45
|
+
function useSessionStream({
|
|
46
|
+
apiUrl,
|
|
47
|
+
token,
|
|
48
|
+
sessionId,
|
|
49
|
+
enabled = true
|
|
50
|
+
}) {
|
|
51
|
+
const [messages, setMessages] = useState([]);
|
|
52
|
+
const [partMap, setPartMap] = useState({});
|
|
53
|
+
const [isStreaming, setIsStreaming] = useState(false);
|
|
54
|
+
const [error, setError] = useState(null);
|
|
55
|
+
const [connected, setConnected] = useState(false);
|
|
56
|
+
const abortRef = useRef(null);
|
|
57
|
+
const reconnectTimerRef = useRef(null);
|
|
58
|
+
const streamingMsgIdRef = useRef(null);
|
|
59
|
+
const insertionCounterRef = useRef(0);
|
|
60
|
+
const handleSSEEventRef = useRef(null);
|
|
61
|
+
const refetch = useCallback(async () => {
|
|
62
|
+
if (!token || !sessionId || !apiUrl) return;
|
|
63
|
+
try {
|
|
64
|
+
const url = `${apiUrl}/session/sessions/${encodeURIComponent(sessionId)}/messages?limit=200`;
|
|
65
|
+
const data = await fetchJson(url, token);
|
|
66
|
+
const apiMessages = Array.isArray(data) ? data : data.messages ?? [];
|
|
67
|
+
const newMessages = [];
|
|
68
|
+
const newPartMap = {};
|
|
69
|
+
for (const apiMsg of apiMessages) {
|
|
70
|
+
const { message, parts } = mapApiMessage(apiMsg, insertionCounterRef);
|
|
71
|
+
newMessages.push(message);
|
|
72
|
+
newPartMap[message.id] = parts;
|
|
73
|
+
}
|
|
74
|
+
setMessages(newMessages);
|
|
75
|
+
setPartMap(newPartMap);
|
|
76
|
+
streamingMsgIdRef.current = null;
|
|
77
|
+
} catch (err) {
|
|
78
|
+
const msg = err instanceof Error ? err.message : "Failed to fetch messages";
|
|
79
|
+
setError(msg);
|
|
80
|
+
}
|
|
81
|
+
}, [apiUrl, token, sessionId]);
|
|
82
|
+
const connectSSE = useCallback(async () => {
|
|
83
|
+
if (!token || !sessionId || !apiUrl || !enabled) return;
|
|
84
|
+
if (reconnectTimerRef.current) {
|
|
85
|
+
clearTimeout(reconnectTimerRef.current);
|
|
86
|
+
reconnectTimerRef.current = null;
|
|
87
|
+
}
|
|
88
|
+
abortRef.current?.abort();
|
|
89
|
+
const controller = new AbortController();
|
|
90
|
+
abortRef.current = controller;
|
|
91
|
+
try {
|
|
92
|
+
const url = `${apiUrl}/session/events?sessionId=${encodeURIComponent(sessionId)}`;
|
|
93
|
+
const res = await fetch(url, {
|
|
94
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
95
|
+
signal: controller.signal,
|
|
96
|
+
credentials: "include"
|
|
97
|
+
});
|
|
98
|
+
if (!res.ok) throw new Error(`SSE connection failed: ${res.status}`);
|
|
99
|
+
setConnected(true);
|
|
100
|
+
setError(null);
|
|
101
|
+
const reader = res.body?.getReader();
|
|
102
|
+
if (!reader) throw new Error("No response body");
|
|
103
|
+
const decoder = new TextDecoder();
|
|
104
|
+
let buffer = "";
|
|
105
|
+
while (true) {
|
|
106
|
+
const { done, value } = await reader.read();
|
|
107
|
+
if (done) break;
|
|
108
|
+
buffer += decoder.decode(value, { stream: true });
|
|
109
|
+
const frames = buffer.split("\n\n");
|
|
110
|
+
buffer = frames.pop() ?? "";
|
|
111
|
+
for (const frame of frames) {
|
|
112
|
+
if (!frame.trim()) continue;
|
|
113
|
+
let eventType = "message";
|
|
114
|
+
const dataLines = [];
|
|
115
|
+
for (const line of frame.split("\n")) {
|
|
116
|
+
if (line.startsWith("event:")) {
|
|
117
|
+
eventType = line.slice(6).trim();
|
|
118
|
+
} else if (line.startsWith("data:")) {
|
|
119
|
+
dataLines.push(line.slice(5).trim());
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (dataLines.length === 0) continue;
|
|
123
|
+
let parsed;
|
|
124
|
+
try {
|
|
125
|
+
parsed = JSON.parse(dataLines.join("\n"));
|
|
126
|
+
} catch {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
handleSSEEventRef.current?.(eventType, parsed);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} catch (err) {
|
|
133
|
+
if (err.name === "AbortError") return;
|
|
134
|
+
const msg = err instanceof Error ? err.message : "SSE connection error";
|
|
135
|
+
setError(msg);
|
|
136
|
+
setConnected(false);
|
|
137
|
+
if (!controller.signal.aborted) {
|
|
138
|
+
reconnectTimerRef.current = setTimeout(() => connectSSE(), 3e3);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}, [apiUrl, token, sessionId, enabled]);
|
|
142
|
+
const handleSSEEvent = useCallback((type, raw) => {
|
|
143
|
+
const envelope = raw?.properties;
|
|
144
|
+
const props = envelope?.info ?? envelope?.part ?? envelope ?? raw;
|
|
145
|
+
if (type === "message.updated") {
|
|
146
|
+
const id = props.id ?? props.messageId ?? "";
|
|
147
|
+
const role = props.role ?? "assistant";
|
|
148
|
+
if (!id) return;
|
|
149
|
+
setMessages((prev) => {
|
|
150
|
+
const exists = prev.some((m) => m.id === id);
|
|
151
|
+
if (exists) return prev;
|
|
152
|
+
return [
|
|
153
|
+
...prev,
|
|
154
|
+
{
|
|
155
|
+
id,
|
|
156
|
+
role,
|
|
157
|
+
time: { created: Date.now() },
|
|
158
|
+
_insertionIndex: insertionCounterRef.current++
|
|
159
|
+
}
|
|
160
|
+
];
|
|
161
|
+
});
|
|
162
|
+
if (role === "assistant") {
|
|
163
|
+
streamingMsgIdRef.current = id;
|
|
164
|
+
setIsStreaming(true);
|
|
165
|
+
}
|
|
166
|
+
} else if (type === "message.part.updated") {
|
|
167
|
+
const msgId = streamingMsgIdRef.current;
|
|
168
|
+
if (!msgId) return;
|
|
169
|
+
const partType = props.type ?? "text";
|
|
170
|
+
setIsStreaming(true);
|
|
171
|
+
setPartMap((prev) => {
|
|
172
|
+
const existing = prev[msgId] ?? [];
|
|
173
|
+
const updated = [...existing];
|
|
174
|
+
if (partType === "text") {
|
|
175
|
+
const text = props.text ?? props.content ?? "";
|
|
176
|
+
const idx = updated.findIndex((p) => p.type === "text");
|
|
177
|
+
const textPart = { type: "text", text };
|
|
178
|
+
if (idx >= 0) {
|
|
179
|
+
updated[idx] = textPart;
|
|
180
|
+
} else {
|
|
181
|
+
updated.push(textPart);
|
|
182
|
+
}
|
|
183
|
+
} else if (partType === "tool") {
|
|
184
|
+
const toolId = props.id ?? props.toolId ?? `tool-${Date.now()}`;
|
|
185
|
+
const toolName = props.tool ?? props.name ?? "unknown";
|
|
186
|
+
const state = props.state ?? { status: "running" };
|
|
187
|
+
const toolPart = {
|
|
188
|
+
type: "tool",
|
|
189
|
+
id: toolId,
|
|
190
|
+
tool: toolName,
|
|
191
|
+
state: {
|
|
192
|
+
status: state.status ?? "running",
|
|
193
|
+
input: state.input,
|
|
194
|
+
output: state.output,
|
|
195
|
+
error: state.error,
|
|
196
|
+
metadata: state.metadata,
|
|
197
|
+
time: state.time
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
const idx = updated.findIndex((p) => p.type === "tool" && p.id === toolId);
|
|
201
|
+
if (idx >= 0) {
|
|
202
|
+
updated[idx] = toolPart;
|
|
203
|
+
} else {
|
|
204
|
+
updated.push(toolPart);
|
|
205
|
+
}
|
|
206
|
+
} else if (partType === "reasoning") {
|
|
207
|
+
const text = props.text ?? "";
|
|
208
|
+
const idx = updated.findIndex((p) => p.type === "reasoning");
|
|
209
|
+
const reasoningPart = { type: "reasoning", text };
|
|
210
|
+
if (idx >= 0) {
|
|
211
|
+
updated[idx] = reasoningPart;
|
|
212
|
+
} else {
|
|
213
|
+
updated.push(reasoningPart);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return { ...prev, [msgId]: updated };
|
|
217
|
+
});
|
|
218
|
+
} else if (type === "session.idle") {
|
|
219
|
+
setIsStreaming(false);
|
|
220
|
+
streamingMsgIdRef.current = null;
|
|
221
|
+
refetch();
|
|
222
|
+
} else if (type === "session.error") {
|
|
223
|
+
setIsStreaming(false);
|
|
224
|
+
streamingMsgIdRef.current = null;
|
|
225
|
+
const errorMsg = props.error ?? props.message ?? "Agent error";
|
|
226
|
+
setError(errorMsg);
|
|
227
|
+
refetch();
|
|
228
|
+
}
|
|
229
|
+
}, [refetch]);
|
|
230
|
+
handleSSEEventRef.current = handleSSEEvent;
|
|
231
|
+
const send = useCallback(async (text) => {
|
|
232
|
+
if (!token || !sessionId || !apiUrl) return;
|
|
233
|
+
try {
|
|
234
|
+
const url = `${apiUrl}/session/sessions/${encodeURIComponent(sessionId)}/messages`;
|
|
235
|
+
await fetchJson(url, token, {
|
|
236
|
+
method: "POST",
|
|
237
|
+
body: JSON.stringify({ parts: [{ type: "text", text }] })
|
|
238
|
+
});
|
|
239
|
+
setIsStreaming(true);
|
|
240
|
+
} catch (err) {
|
|
241
|
+
const msg = err instanceof Error ? err.message : "Failed to send message";
|
|
242
|
+
setError(msg);
|
|
243
|
+
}
|
|
244
|
+
}, [apiUrl, token, sessionId]);
|
|
245
|
+
const abort = useCallback(async () => {
|
|
246
|
+
if (!token || !sessionId || !apiUrl) return;
|
|
247
|
+
try {
|
|
248
|
+
const url = `${apiUrl}/session/sessions/${encodeURIComponent(sessionId)}/abort`;
|
|
249
|
+
await fetchJson(url, token, { method: "POST" });
|
|
250
|
+
} catch (err) {
|
|
251
|
+
const msg = err instanceof Error ? err.message : "Failed to abort";
|
|
252
|
+
setError(msg);
|
|
253
|
+
}
|
|
254
|
+
}, [apiUrl, token, sessionId]);
|
|
255
|
+
useEffect(() => {
|
|
256
|
+
if (!enabled || !token || !sessionId) return;
|
|
257
|
+
refetch();
|
|
258
|
+
connectSSE();
|
|
259
|
+
return () => {
|
|
260
|
+
abortRef.current?.abort();
|
|
261
|
+
if (reconnectTimerRef.current) clearTimeout(reconnectTimerRef.current);
|
|
262
|
+
setConnected(false);
|
|
263
|
+
};
|
|
264
|
+
}, [enabled, token, sessionId, refetch, connectSSE]);
|
|
265
|
+
return { messages, partMap, isStreaming, send, abort, refetch, error, connected };
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// src/hooks/use-sidecar-auth.ts
|
|
269
|
+
import { useState as useState2, useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
270
|
+
function storageKey(resourceId, apiUrl) {
|
|
271
|
+
return `sidecar_session_${resourceId}__${apiUrl}`;
|
|
272
|
+
}
|
|
273
|
+
function loadSession(resourceId, apiUrl) {
|
|
274
|
+
if (typeof window === "undefined") return null;
|
|
275
|
+
try {
|
|
276
|
+
const raw = localStorage.getItem(storageKey(resourceId, apiUrl));
|
|
277
|
+
if (!raw) return null;
|
|
278
|
+
const data = JSON.parse(raw);
|
|
279
|
+
if (data.expiresAt * 1e3 - Date.now() < 6e4) {
|
|
280
|
+
localStorage.removeItem(storageKey(resourceId, apiUrl));
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
return data;
|
|
284
|
+
} catch {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
function saveSession(resourceId, apiUrl, token, expiresAt) {
|
|
289
|
+
if (typeof window === "undefined") return;
|
|
290
|
+
try {
|
|
291
|
+
localStorage.setItem(storageKey(resourceId, apiUrl), JSON.stringify({ token, expiresAt }));
|
|
292
|
+
} catch {
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function clearSession(resourceId, apiUrl) {
|
|
296
|
+
if (typeof window === "undefined") return;
|
|
297
|
+
localStorage.removeItem(storageKey(resourceId, apiUrl));
|
|
298
|
+
}
|
|
299
|
+
function useSidecarAuth({ resourceId, apiUrl, signMessage }) {
|
|
300
|
+
const cached = loadSession(resourceId, apiUrl);
|
|
301
|
+
const [token, setToken] = useState2(cached?.token ?? null);
|
|
302
|
+
const [expiresAt, setExpiresAt] = useState2(cached?.expiresAt ?? 0);
|
|
303
|
+
const [isAuthenticating, setIsAuthenticating] = useState2(false);
|
|
304
|
+
const [error, setError] = useState2(null);
|
|
305
|
+
const refreshTimerRef = useRef2(void 0);
|
|
306
|
+
const clearCachedToken = useCallback2(() => {
|
|
307
|
+
setToken(null);
|
|
308
|
+
setExpiresAt(0);
|
|
309
|
+
clearSession(resourceId, apiUrl);
|
|
310
|
+
}, [resourceId, apiUrl]);
|
|
311
|
+
const authenticate = useCallback2(async () => {
|
|
312
|
+
if (!apiUrl) return null;
|
|
313
|
+
setIsAuthenticating(true);
|
|
314
|
+
setError(null);
|
|
315
|
+
try {
|
|
316
|
+
const challengeRes = await fetch(`${apiUrl}/api/auth/challenge`, {
|
|
317
|
+
method: "POST"
|
|
318
|
+
});
|
|
319
|
+
if (!challengeRes.ok) {
|
|
320
|
+
throw new Error(`Challenge failed: ${challengeRes.status}`);
|
|
321
|
+
}
|
|
322
|
+
const { nonce, message } = await challengeRes.json();
|
|
323
|
+
const signature = await signMessage(message);
|
|
324
|
+
const sessionRes = await fetch(`${apiUrl}/api/auth/session`, {
|
|
325
|
+
method: "POST",
|
|
326
|
+
headers: { "Content-Type": "application/json" },
|
|
327
|
+
body: JSON.stringify({ nonce, signature })
|
|
328
|
+
});
|
|
329
|
+
if (!sessionRes.ok) {
|
|
330
|
+
const text = await sessionRes.text();
|
|
331
|
+
throw new Error(text || `Session exchange failed: ${sessionRes.status}`);
|
|
332
|
+
}
|
|
333
|
+
const { token: newToken, expires_at } = await sessionRes.json();
|
|
334
|
+
setToken(newToken);
|
|
335
|
+
setExpiresAt(expires_at);
|
|
336
|
+
saveSession(resourceId, apiUrl, newToken, expires_at);
|
|
337
|
+
return newToken;
|
|
338
|
+
} catch (err) {
|
|
339
|
+
setError(err instanceof Error ? err.message : "Authentication failed");
|
|
340
|
+
clearCachedToken();
|
|
341
|
+
return null;
|
|
342
|
+
} finally {
|
|
343
|
+
setIsAuthenticating(false);
|
|
344
|
+
}
|
|
345
|
+
}, [resourceId, apiUrl, signMessage, clearCachedToken]);
|
|
346
|
+
useEffect2(() => {
|
|
347
|
+
if (refreshTimerRef.current) {
|
|
348
|
+
clearTimeout(refreshTimerRef.current);
|
|
349
|
+
}
|
|
350
|
+
if (!token || !expiresAt) return;
|
|
351
|
+
const msUntilRefresh = (expiresAt - 300) * 1e3 - Date.now();
|
|
352
|
+
if (msUntilRefresh <= 0) {
|
|
353
|
+
clearCachedToken();
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
refreshTimerRef.current = setTimeout(() => {
|
|
357
|
+
authenticate().catch(() => {
|
|
358
|
+
clearCachedToken();
|
|
359
|
+
});
|
|
360
|
+
}, msUntilRefresh);
|
|
361
|
+
return () => {
|
|
362
|
+
if (refreshTimerRef.current) {
|
|
363
|
+
clearTimeout(refreshTimerRef.current);
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
}, [token, expiresAt, authenticate, clearCachedToken]);
|
|
367
|
+
return {
|
|
368
|
+
token,
|
|
369
|
+
isAuthenticated: token !== null,
|
|
370
|
+
isAuthenticating,
|
|
371
|
+
authenticate,
|
|
372
|
+
clearCachedToken,
|
|
373
|
+
error
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
export {
|
|
378
|
+
useSessionStream,
|
|
379
|
+
useSidecarAuth
|
|
380
|
+
};
|
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "./chunk-
|
|
2
|
+
cn
|
|
3
|
+
} from "./chunk-EI44GEQ5.js";
|
|
4
|
+
|
|
5
|
+
// src/dashboard/billing-dashboard.tsx
|
|
6
|
+
import { Button } from "@tangle-network/ui/primitives";
|
|
7
|
+
import { Badge } from "@tangle-network/ui/primitives";
|
|
4
8
|
import {
|
|
5
|
-
Badge,
|
|
6
9
|
Card,
|
|
7
10
|
CardContent,
|
|
8
11
|
CardDescription,
|
|
9
12
|
CardHeader,
|
|
10
13
|
CardTitle
|
|
11
|
-
} from "
|
|
12
|
-
import {
|
|
13
|
-
Button
|
|
14
|
-
} from "./chunk-MKTSMWVD.js";
|
|
15
|
-
import {
|
|
16
|
-
cn
|
|
17
|
-
} from "./chunk-RQHJBTEU.js";
|
|
18
|
-
|
|
19
|
-
// src/dashboard/billing-dashboard.tsx
|
|
14
|
+
} from "@tangle-network/ui/primitives";
|
|
15
|
+
import { Progress } from "@tangle-network/ui/primitives";
|
|
20
16
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
21
17
|
var variantColors = {
|
|
22
18
|
sandbox: {
|
|
@@ -367,6 +363,7 @@ function PricingPage({
|
|
|
367
363
|
|
|
368
364
|
// src/dashboard/usage-chart.tsx
|
|
369
365
|
import * as React from "react";
|
|
366
|
+
import { Card as Card2, CardContent as CardContent2, CardHeader as CardHeader2, CardTitle as CardTitle2 } from "@tangle-network/ui/primitives";
|
|
370
367
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
371
368
|
var colors = {
|
|
372
369
|
bar: "bg-[image:var(--accent-gradient-strong)]",
|
|
@@ -390,15 +387,15 @@ function UsageChart({ data, title, unit, className }) {
|
|
|
390
387
|
const maxValue = Math.max(...data.map((d) => d.value), 1);
|
|
391
388
|
const total = data.reduce((sum, d) => sum + d.value, 0);
|
|
392
389
|
const [hoveredIndex, setHoveredIndex] = React.useState(null);
|
|
393
|
-
return /* @__PURE__ */ jsxs3(
|
|
394
|
-
/* @__PURE__ */ jsxs3(
|
|
395
|
-
/* @__PURE__ */ jsx3(
|
|
390
|
+
return /* @__PURE__ */ jsxs3(Card2, { className, children: [
|
|
391
|
+
/* @__PURE__ */ jsxs3(CardHeader2, { className: "flex flex-row items-center justify-between pb-2", children: [
|
|
392
|
+
/* @__PURE__ */ jsx3(CardTitle2, { className: "font-medium text-base", children: title }),
|
|
396
393
|
/* @__PURE__ */ jsxs3("div", { className: "text-right", children: [
|
|
397
394
|
/* @__PURE__ */ jsx3("span", { className: cn("font-bold text-2xl", colors.text), children: formatValue(total) }),
|
|
398
395
|
/* @__PURE__ */ jsx3("span", { className: "ml-1 text-muted-foreground text-sm", children: unit })
|
|
399
396
|
] })
|
|
400
397
|
] }),
|
|
401
|
-
/* @__PURE__ */ jsxs3(
|
|
398
|
+
/* @__PURE__ */ jsxs3(CardContent2, { children: [
|
|
402
399
|
/* @__PURE__ */ jsxs3("div", { className: "relative", children: [
|
|
403
400
|
/* @__PURE__ */ jsxs3("div", { className: "absolute top-0 left-0 flex h-48 flex-col justify-between text-muted-foreground text-xs", children: [
|
|
404
401
|
/* @__PURE__ */ jsx3("span", { children: formatValue(maxValue) }),
|
|
@@ -485,9 +482,66 @@ function UsageChart({ data, title, unit, className }) {
|
|
|
485
482
|
] });
|
|
486
483
|
}
|
|
487
484
|
|
|
485
|
+
// src/dashboard/template-card.tsx
|
|
486
|
+
import { ArrowRight } from "lucide-react";
|
|
487
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
488
|
+
function TemplateCard({ template, onUseTemplate, className }) {
|
|
489
|
+
return /* @__PURE__ */ jsxs4(
|
|
490
|
+
"div",
|
|
491
|
+
{
|
|
492
|
+
className: cn(
|
|
493
|
+
"group relative flex flex-col justify-between rounded-2xl border border-border bg-card p-6 transition-all hover:border-primary/30 hover:shadow-md",
|
|
494
|
+
className
|
|
495
|
+
),
|
|
496
|
+
children: [
|
|
497
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
498
|
+
/* @__PURE__ */ jsx4("div", { className: "mb-4 flex h-12 w-12 items-center justify-center rounded-xl bg-muted border border-border", children: template.icon ?? /* @__PURE__ */ jsx4("span", { className: "text-lg font-bold text-primary", children: template.name.charAt(0).toUpperCase() }) }),
|
|
499
|
+
/* @__PURE__ */ jsx4("h3", { className: "mb-1 text-base font-bold text-foreground", children: template.name }),
|
|
500
|
+
/* @__PURE__ */ jsx4("p", { className: "text-sm text-muted-foreground leading-relaxed line-clamp-2", children: template.description }),
|
|
501
|
+
template.tags && template.tags.length > 0 && /* @__PURE__ */ jsx4("div", { className: "mt-3 flex flex-wrap gap-1.5", children: template.tags.map((tag, i) => /* @__PURE__ */ jsx4(
|
|
502
|
+
"span",
|
|
503
|
+
{
|
|
504
|
+
className: "rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground",
|
|
505
|
+
children: tag
|
|
506
|
+
},
|
|
507
|
+
`${tag}-${i}`
|
|
508
|
+
)) })
|
|
509
|
+
] }),
|
|
510
|
+
/* @__PURE__ */ jsxs4(
|
|
511
|
+
"button",
|
|
512
|
+
{
|
|
513
|
+
type: "button",
|
|
514
|
+
onClick: () => onUseTemplate(template.id),
|
|
515
|
+
className: "mt-5 inline-flex w-full items-center justify-center gap-2 rounded-xl bg-primary/10 border border-primary/20 px-4 py-2.5 text-sm font-bold text-primary transition-colors hover:bg-primary hover:text-primary-foreground active:scale-[0.98]",
|
|
516
|
+
children: [
|
|
517
|
+
"Use Template",
|
|
518
|
+
/* @__PURE__ */ jsx4(ArrowRight, { className: "h-4 w-4 transition-transform group-hover:translate-x-0.5" })
|
|
519
|
+
]
|
|
520
|
+
}
|
|
521
|
+
)
|
|
522
|
+
]
|
|
523
|
+
}
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// src/dashboard/info-panel.tsx
|
|
528
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
529
|
+
function InfoPanel({ label, title, description, className }) {
|
|
530
|
+
return /* @__PURE__ */ jsxs5("div", { className: cn("rounded-lg bg-[var(--brand-strong)] p-5 text-[var(--brand-strong-text)] relative overflow-hidden", className), children: [
|
|
531
|
+
/* @__PURE__ */ jsxs5("div", { className: "relative z-10", children: [
|
|
532
|
+
/* @__PURE__ */ jsx5("p", { className: "text-[10px] font-bold uppercase tracking-widest text-[var(--brand-strong-text-dim)]", children: label }),
|
|
533
|
+
/* @__PURE__ */ jsx5("h3", { className: "mt-1 text-lg font-bold", children: title }),
|
|
534
|
+
/* @__PURE__ */ jsx5("p", { className: "mt-1 text-sm text-[var(--brand-strong-text-muted)]", children: description })
|
|
535
|
+
] }),
|
|
536
|
+
/* @__PURE__ */ jsx5("div", { className: "absolute right-0 top-0 h-full w-1/3 bg-white/5 -skew-x-12 translate-x-12 pointer-events-none" })
|
|
537
|
+
] });
|
|
538
|
+
}
|
|
539
|
+
|
|
488
540
|
export {
|
|
489
541
|
BillingDashboard,
|
|
490
542
|
formatPrice,
|
|
491
543
|
PricingPage,
|
|
492
|
-
UsageChart
|
|
544
|
+
UsageChart,
|
|
545
|
+
TemplateCard,
|
|
546
|
+
InfoPanel
|
|
493
547
|
};
|
|
@@ -1,36 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useActiveSessions,
|
|
3
|
-
useNavbarSessions,
|
|
4
|
-
useProjectActivity,
|
|
5
|
-
useTotalRunningSessions
|
|
6
|
-
} from "./chunk-OEX7NZE3.js";
|
|
7
|
-
import {
|
|
8
|
-
EmptyState,
|
|
9
|
-
Input
|
|
10
|
-
} from "./chunk-MA7YKRUP.js";
|
|
11
|
-
import {
|
|
12
|
-
ChatContainer
|
|
13
|
-
} from "./chunk-XLG757B6.js";
|
|
14
|
-
import {
|
|
15
|
-
OpenUIArtifactRenderer
|
|
16
|
-
} from "./chunk-ZNCEM5CD.js";
|
|
17
|
-
import {
|
|
18
|
-
FileArtifactPane,
|
|
19
|
-
FileTree,
|
|
20
|
-
filterFileTree
|
|
21
|
-
} from "./chunk-QDH5GEGY.js";
|
|
22
|
-
import {
|
|
23
|
-
ArtifactPane
|
|
24
|
-
} from "./chunk-HB5Y37YU.js";
|
|
25
|
-
import {
|
|
26
|
-
Markdown
|
|
27
|
-
} from "./chunk-T7HMZEVO.js";
|
|
28
|
-
import {
|
|
29
|
-
Badge
|
|
30
|
-
} from "./chunk-ZMNSRDMH.js";
|
|
31
1
|
import {
|
|
32
2
|
cn
|
|
33
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-EI44GEQ5.js";
|
|
34
4
|
|
|
35
5
|
// src/workspace/workspace-layout.tsx
|
|
36
6
|
import {
|
|
@@ -487,9 +457,19 @@ function WorkspaceLayout({
|
|
|
487
457
|
);
|
|
488
458
|
}
|
|
489
459
|
|
|
460
|
+
// src/workspace/index.ts
|
|
461
|
+
import { ArtifactPane as ArtifactPane3 } from "@tangle-network/ui/primitives";
|
|
462
|
+
|
|
490
463
|
// src/workspace/directory-pane.tsx
|
|
491
464
|
import { useMemo as useMemo2, useState as useState2 } from "react";
|
|
492
465
|
import { RefreshCw, Search, Upload } from "lucide-react";
|
|
466
|
+
import { ArtifactPane } from "@tangle-network/ui/primitives";
|
|
467
|
+
import {
|
|
468
|
+
FileTree,
|
|
469
|
+
filterFileTree
|
|
470
|
+
} from "@tangle-network/ui/files";
|
|
471
|
+
import { EmptyState } from "@tangle-network/ui/primitives";
|
|
472
|
+
import { Input } from "@tangle-network/ui/primitives";
|
|
493
473
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
494
474
|
function countNodes(node) {
|
|
495
475
|
if (node.type === "file") {
|
|
@@ -612,6 +592,9 @@ function DirectoryPane({
|
|
|
612
592
|
);
|
|
613
593
|
}
|
|
614
594
|
|
|
595
|
+
// src/workspace/runtime-pane.tsx
|
|
596
|
+
import { Binary, ShieldCheck, TerminalSquare } from "lucide-react";
|
|
597
|
+
|
|
615
598
|
// src/workspace/status-banner.tsx
|
|
616
599
|
import { Loader2, AlertCircle, CheckCircle, Wifi } from "lucide-react";
|
|
617
600
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
@@ -773,7 +756,6 @@ function TerminalPanel({
|
|
|
773
756
|
}
|
|
774
757
|
|
|
775
758
|
// src/workspace/runtime-pane.tsx
|
|
776
|
-
import { Binary, ShieldCheck, TerminalSquare } from "lucide-react";
|
|
777
759
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
778
760
|
function RuntimePane({
|
|
779
761
|
title = "Runtime",
|
|
@@ -833,6 +815,7 @@ function RuntimePane({
|
|
|
833
815
|
// src/workspace/session-sidebar.tsx
|
|
834
816
|
import { useCallback, useMemo as useMemo3, useRef as useRef3, useState as useState3 } from "react";
|
|
835
817
|
import { ArrowLeft, FolderTree, MessageSquareText, Plus, Search as Search2, Settings, Sparkles } from "lucide-react";
|
|
818
|
+
import { useNavbarSessions } from "@tangle-network/ui/stores";
|
|
836
819
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
837
820
|
function statusDot(status) {
|
|
838
821
|
switch (status) {
|
|
@@ -1155,6 +1138,11 @@ function SessionSidebar({
|
|
|
1155
1138
|
|
|
1156
1139
|
// src/workspace/session-activity-monitor.tsx
|
|
1157
1140
|
import { Activity, AlertCircle as AlertCircle2, LoaderCircle, MessageSquareText as MessageSquareText2 } from "lucide-react";
|
|
1141
|
+
import {
|
|
1142
|
+
useActiveSessions,
|
|
1143
|
+
useProjectActivity,
|
|
1144
|
+
useTotalRunningSessions
|
|
1145
|
+
} from "@tangle-network/ui/stores";
|
|
1158
1146
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1159
1147
|
function SessionStatusDot({ session }) {
|
|
1160
1148
|
if (session.status === "error") {
|
|
@@ -1260,6 +1248,13 @@ import {
|
|
|
1260
1248
|
LayoutPanelTop,
|
|
1261
1249
|
X as X4
|
|
1262
1250
|
} from "lucide-react";
|
|
1251
|
+
import { Badge } from "@tangle-network/ui/primitives";
|
|
1252
|
+
import { EmptyState as EmptyState2 } from "@tangle-network/ui/primitives";
|
|
1253
|
+
import { Markdown } from "@tangle-network/ui/markdown";
|
|
1254
|
+
import { ChatContainer } from "@tangle-network/ui/chat";
|
|
1255
|
+
import { FileArtifactPane } from "@tangle-network/ui/files";
|
|
1256
|
+
import { OpenUIArtifactRenderer } from "@tangle-network/ui/openui";
|
|
1257
|
+
import { ArtifactPane as ArtifactPane2 } from "@tangle-network/ui/primitives";
|
|
1263
1258
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1264
1259
|
function getArtifactTabIcon(kind) {
|
|
1265
1260
|
switch (kind) {
|
|
@@ -1348,7 +1343,7 @@ function renderArtifact(artifact) {
|
|
|
1348
1343
|
);
|
|
1349
1344
|
case "markdown":
|
|
1350
1345
|
return /* @__PURE__ */ jsx9(
|
|
1351
|
-
|
|
1346
|
+
ArtifactPane2,
|
|
1352
1347
|
{
|
|
1353
1348
|
eyebrow: artifact.eyebrow ?? "Document",
|
|
1354
1349
|
title: artifact.title,
|
|
@@ -1362,7 +1357,7 @@ function renderArtifact(artifact) {
|
|
|
1362
1357
|
);
|
|
1363
1358
|
case "openui":
|
|
1364
1359
|
return /* @__PURE__ */ jsx9(
|
|
1365
|
-
|
|
1360
|
+
ArtifactPane2,
|
|
1366
1361
|
{
|
|
1367
1362
|
eyebrow: artifact.eyebrow ?? "Structured Artifact",
|
|
1368
1363
|
title: artifact.title,
|
|
@@ -1376,7 +1371,7 @@ function renderArtifact(artifact) {
|
|
|
1376
1371
|
);
|
|
1377
1372
|
case "custom":
|
|
1378
1373
|
return /* @__PURE__ */ jsx9(
|
|
1379
|
-
|
|
1374
|
+
ArtifactPane2,
|
|
1380
1375
|
{
|
|
1381
1376
|
eyebrow: artifact.eyebrow ?? "Artifact",
|
|
1382
1377
|
title: artifact.title,
|
|
@@ -1480,7 +1475,7 @@ function SandboxWorkbench({
|
|
|
1480
1475
|
] })
|
|
1481
1476
|
] });
|
|
1482
1477
|
const center = /* @__PURE__ */ jsx9(
|
|
1483
|
-
|
|
1478
|
+
ArtifactPane2,
|
|
1484
1479
|
{
|
|
1485
1480
|
eyebrow: session.eyebrow ?? "Agent Session",
|
|
1486
1481
|
title: session.title ?? "Execution timeline",
|
|
@@ -1510,7 +1505,7 @@ function SandboxWorkbench({
|
|
|
1510
1505
|
}
|
|
1511
1506
|
),
|
|
1512
1507
|
/* @__PURE__ */ jsx9("div", { className: "min-h-0 flex-1 overflow-auto bg-background", children: activeArtifact ? renderArtifact(activeArtifact) : /* @__PURE__ */ jsx9("div", { className: "flex h-full items-center justify-center p-6", children: emptyArtifactState ?? /* @__PURE__ */ jsx9(
|
|
1513
|
-
|
|
1508
|
+
EmptyState2,
|
|
1514
1509
|
{
|
|
1515
1510
|
icon: /* @__PURE__ */ jsx9(Boxes, { className: "h-8 w-8" }),
|
|
1516
1511
|
title: "No artifact selected",
|
|
@@ -2200,5 +2195,6 @@ export {
|
|
|
2200
2195
|
AuditResults,
|
|
2201
2196
|
TaskBoard,
|
|
2202
2197
|
CalendarView,
|
|
2203
|
-
ApprovalQueue
|
|
2198
|
+
ApprovalQueue,
|
|
2199
|
+
ArtifactPane3 as ArtifactPane
|
|
2204
2200
|
};
|