@tangle-network/sandbox-ui 0.13.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.
Files changed (106) hide show
  1. package/dist/auth.d.ts +1 -74
  2. package/dist/auth.js +1 -4
  3. package/dist/chat.d.ts +1 -136
  4. package/dist/chat.js +2 -15
  5. package/dist/chunk-2BUPSB7O.js +0 -0
  6. package/dist/chunk-3J6FG3FJ.js +18 -0
  7. package/dist/chunk-76IQLPW2.js +206 -0
  8. package/dist/chunk-7ZA5SEK3.js +239 -0
  9. package/dist/{chunk-ESVYBDGA.js → chunk-AG7QDC2Q.js} +182 -2
  10. package/dist/chunk-AHBZCBDO.js +2960 -0
  11. package/dist/chunk-AZ3AWMTM.js +8 -0
  12. package/dist/chunk-CMY7W45U.js +380 -0
  13. package/dist/{chunk-QMU2PWOU.js → chunk-DNZ4DTNA.js} +71 -17
  14. package/dist/chunk-EI44GEQ5.js +6 -0
  15. package/dist/{chunk-5OQ27N57.js → chunk-GPT7VKK6.js} +34 -38
  16. package/dist/chunk-JBGKGLD7.js +16 -0
  17. package/dist/chunk-NJNME4J4.js +14 -0
  18. package/dist/chunk-QPAJR74X.js +20 -0
  19. package/dist/chunk-TK46XFLM.js +28 -0
  20. package/dist/chunk-WID73FPH.js +89 -0
  21. package/dist/chunk-YVXK4XRO.js +30 -0
  22. package/dist/dashboard.d.ts +538 -4
  23. package/dist/dashboard.js +15 -886
  24. package/dist/editor.d.ts +1 -120
  25. package/dist/editor.js +1 -5
  26. package/dist/files.d.ts +1 -129
  27. package/dist/files.js +2 -7
  28. package/dist/globals.css +5 -1265
  29. package/dist/hooks.d.ts +114 -11
  30. package/dist/hooks.js +17 -88
  31. package/dist/index.d.ts +24 -99
  32. package/dist/index.js +247 -252
  33. package/dist/markdown.d.ts +1 -29
  34. package/dist/markdown.js +2 -2
  35. package/dist/openui.d.ts +8 -115
  36. package/dist/openui.js +1 -6
  37. package/dist/pages.d.ts +1 -2
  38. package/dist/pages.js +68 -66
  39. package/dist/primitives.d.ts +14 -49
  40. package/dist/primitives.js +69 -77
  41. package/dist/run.d.ts +1 -14
  42. package/dist/run.js +2 -22
  43. package/dist/sdk-hooks.d.ts +3 -283
  44. package/dist/sdk-hooks.js +10 -14
  45. package/dist/stores.d.ts +2 -14
  46. package/dist/stores.js +11 -39
  47. package/dist/styles.css +5 -1265
  48. package/dist/{usage-chart-CPTcNlGs.d.ts → template-card-UhV3pmRC.d.ts} +16 -1
  49. package/dist/terminal.js +39 -2
  50. package/dist/types.d.ts +11 -8
  51. package/dist/types.js +1 -0
  52. package/dist/utils.d.ts +1 -44
  53. package/dist/utils.js +6 -12
  54. package/dist/workspace.d.ts +5 -10
  55. package/dist/workspace.js +3 -19
  56. package/package.json +23 -54
  57. package/dist/active-sessions-store-CeOmXgv5.d.ts +0 -85
  58. package/dist/artifact-pane-Bh45Ssco.d.ts +0 -24
  59. package/dist/branding-DCi5VEik.d.ts +0 -13
  60. package/dist/button-CMQuQEW_.d.ts +0 -17
  61. package/dist/chat-container-f4yEs6KN.d.ts +0 -106
  62. package/dist/chunk-34A66VBG.js +0 -214
  63. package/dist/chunk-34I7UFSX.js +0 -92
  64. package/dist/chunk-36QY2W5G.js +0 -802
  65. package/dist/chunk-4CLN43XT.js +0 -45
  66. package/dist/chunk-54SQQMMM.js +0 -156
  67. package/dist/chunk-66EZOYZR.js +0 -102
  68. package/dist/chunk-BX6AQMUS.js +0 -183
  69. package/dist/chunk-DI3NZ5ZX.js +0 -192
  70. package/dist/chunk-DPGIXDAI.js +0 -220
  71. package/dist/chunk-DXMIEK4K.js +0 -1426
  72. package/dist/chunk-GSZA3TSY.js +0 -79
  73. package/dist/chunk-HB5Y37YU.js +0 -54
  74. package/dist/chunk-LQNEZDRM.js +0 -109
  75. package/dist/chunk-MA7YKRUP.js +0 -131
  76. package/dist/chunk-MKTSMWVD.js +0 -109
  77. package/dist/chunk-MQXABZTB.js +0 -1348
  78. package/dist/chunk-MT5FJ3ZT.js +0 -186
  79. package/dist/chunk-NKUPJC34.js +0 -2070
  80. package/dist/chunk-OEX7NZE3.js +0 -321
  81. package/dist/chunk-OKLQVY3Y.js +0 -139
  82. package/dist/chunk-Q56BYXQF.js +0 -61
  83. package/dist/chunk-QD4QE5P5.js +0 -40
  84. package/dist/chunk-QDH5GEGY.js +0 -630
  85. package/dist/chunk-QID2OOMG.js +0 -133
  86. package/dist/chunk-RQHJBTEU.js +0 -10
  87. package/dist/chunk-T7HMZEVO.js +0 -216
  88. package/dist/chunk-U6QTHMY6.js +0 -1290
  89. package/dist/chunk-US6JKJKH.js +0 -124
  90. package/dist/chunk-VX3XOUEB.js +0 -63
  91. package/dist/chunk-XLG757B6.js +0 -933
  92. package/dist/chunk-ZMNSRDMH.js +0 -127
  93. package/dist/chunk-ZNCEM5CD.js +0 -316
  94. package/dist/document-editor-pane-A70-EhdQ.d.ts +0 -124
  95. package/dist/document-editor-pane-TLPVRBBU.js +0 -11
  96. package/dist/expanded-tool-detail-Dh99mcbY.d.ts +0 -63
  97. package/dist/file-tabs-BLfxfmAH.d.ts +0 -51
  98. package/dist/parts-CyGkM6Fp.d.ts +0 -50
  99. package/dist/run-CtFZ6s-D.d.ts +0 -41
  100. package/dist/sidebar-drop-zone-tDBsuOH5.d.ts +0 -301
  101. package/dist/sidecar-CFU2W9j1.d.ts +0 -8
  102. package/dist/template-card-BAtvcAkU.d.ts +0 -18
  103. package/dist/tool-call-feed-Bs3MyQMT.d.ts +0 -68
  104. package/dist/tool-display-Ct9nFAzJ.d.ts +0 -32
  105. package/dist/use-sandbox-metrics-B64diPqN.d.ts +0 -141
  106. package/dist/variant-list-BrHYcBCk.d.ts +0 -540
package/dist/auth.d.ts CHANGED
@@ -1,74 +1 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import * as React from 'react';
3
- import { a as ButtonProps } from './button-CMQuQEW_.js';
4
- import 'class-variance-authority/types';
5
-
6
- interface SessionUser {
7
- customer_id: string;
8
- email: string;
9
- name?: string;
10
- tier?: string;
11
- github?: {
12
- login: string;
13
- connected: boolean;
14
- } | null;
15
- session_expires_at: string;
16
- }
17
- interface GitHubLoginButtonProps extends Omit<ButtonProps, "onClick"> {
18
- /** API base URL (defaults to /auth/github) */
19
- authUrl?: string;
20
- /** Product variant for styling */
21
- variant?: "sandbox" | "default" | "outline";
22
- }
23
- declare function GitHubLoginButton({ authUrl, variant, className, children, ...props }: GitHubLoginButtonProps): react_jsx_runtime.JSX.Element;
24
- interface UserMenuProps {
25
- user: SessionUser;
26
- /** API base URL for logout */
27
- logoutUrl?: string;
28
- /** Links to show in menu */
29
- links?: Array<{
30
- href: string;
31
- label: string;
32
- icon?: React.ReactNode;
33
- }>;
34
- /** Product variant for styling */
35
- variant?: "sandbox";
36
- /** Callback when logout is clicked */
37
- onLogout?: () => void;
38
- }
39
- declare function UserMenu({ user, logoutUrl, links, variant, onLogout, }: UserMenuProps): react_jsx_runtime.JSX.Element;
40
- interface AuthHeaderProps {
41
- /** Current session user (null if not logged in) */
42
- user: SessionUser | null;
43
- /** Whether session is loading */
44
- loading?: boolean;
45
- /** Product variant */
46
- variant?: "sandbox";
47
- /** API base URL */
48
- apiBaseUrl?: string;
49
- /** Links for user menu */
50
- menuLinks?: UserMenuProps["links"];
51
- /** Custom className */
52
- className?: string;
53
- }
54
- declare function AuthHeader({ user, loading, variant, apiBaseUrl, menuLinks, className, }: AuthHeaderProps): react_jsx_runtime.JSX.Element;
55
-
56
- interface LoginLayoutProps {
57
- title?: React.ReactNode;
58
- subtitle?: React.ReactNode;
59
- brandIcon?: React.ReactNode;
60
- children: React.ReactNode;
61
- className?: string;
62
- /** (Deprecated) terminal lines from legacy layout, kept for backwards compatibility */
63
- terminalLines?: string[];
64
- /** (Deprecated) tagline, kept for backwards compatibility */
65
- tagline?: React.ReactNode;
66
- /** (Deprecated) footerLinks, kept for backwards compatibility */
67
- footerLinks?: {
68
- label: string;
69
- href: string;
70
- }[];
71
- }
72
- declare function LoginLayout({ title, subtitle, brandIcon, children, className, }: LoginLayoutProps): react_jsx_runtime.JSX.Element;
73
-
74
- export { AuthHeader, type AuthHeaderProps, GitHubLoginButton, type GitHubLoginButtonProps, LoginLayout, type LoginLayoutProps, type SessionUser, UserMenu, type UserMenuProps };
1
+ export { AuthHeader, AuthHeaderProps, GitHubLoginButton, GitHubLoginButtonProps, LoginLayout, LoginLayoutProps, SessionUser, UserMenu, UserMenuProps } from '@tangle-network/ui/auth';
package/dist/auth.js CHANGED
@@ -3,10 +3,7 @@ import {
3
3
  GitHubLoginButton,
4
4
  LoginLayout,
5
5
  UserMenu
6
- } from "./chunk-DI3NZ5ZX.js";
7
- import "./chunk-34A66VBG.js";
8
- import "./chunk-MKTSMWVD.js";
9
- import "./chunk-RQHJBTEU.js";
6
+ } from "./chunk-NJNME4J4.js";
10
7
  export {
11
8
  AuthHeader,
12
9
  GitHubLoginButton,
package/dist/chat.d.ts CHANGED
@@ -1,136 +1 @@
1
- export { C as ChatContainer, a as ChatContainerProps, b as ChatInput, c as ChatInputProps, P as PendingFile } from './chat-container-f4yEs6KN.js';
2
- import * as React from 'react';
3
- import { ReactNode } from 'react';
4
- import * as react_jsx_runtime from 'react/jsx-runtime';
5
- import { G as GroupedMessage } from './run-CtFZ6s-D.js';
6
- import { a as SessionPart, S as SessionMessage, b as ToolPart } from './parts-CyGkM6Fp.js';
7
- import { A as AgentBranding } from './branding-DCi5VEik.js';
8
- import { C as CustomToolRenderer } from './tool-display-Ct9nFAzJ.js';
9
- import { T as ToolCallData } from './tool-call-feed-Bs3MyQMT.js';
10
- import './openui.js';
11
-
12
- type MessageRole = "user" | "assistant" | "system";
13
- interface ChatMessageProps {
14
- role: MessageRole;
15
- content: string;
16
- /** Inline tool call activity rendered between text chunks */
17
- toolCalls?: ReactNode;
18
- /** Whether the message is still streaming */
19
- isStreaming?: boolean;
20
- /** Timestamp */
21
- timestamp?: Date;
22
- className?: string;
23
- /** Custom user label. Default: "You" */
24
- userLabel?: string;
25
- /** Custom assistant label. Default: "Agent" */
26
- assistantLabel?: string;
27
- /** Hide the role label row entirely */
28
- hideRoleLabel?: boolean;
29
- /** Hide the avatar icon */
30
- hideAvatar?: boolean;
31
- /** Custom avatar element (replaces default User/Bot icon) */
32
- avatar?: ReactNode;
33
- }
34
- declare function ChatMessage({ role, content, toolCalls, isStreaming, timestamp, className, userLabel, assistantLabel, hideRoleLabel, hideAvatar, avatar, }: ChatMessageProps): react_jsx_runtime.JSX.Element;
35
-
36
- interface MessageListProps {
37
- groups: GroupedMessage[];
38
- partMap: Record<string, SessionPart[]>;
39
- isCollapsed: (runId: string) => boolean;
40
- onToggleCollapse: (runId: string) => void;
41
- branding?: AgentBranding;
42
- renderToolDetail?: CustomToolRenderer;
43
- renderRunActions?: (group: Extract<GroupedMessage, {
44
- type: "run";
45
- }>["run"]) => ReactNode;
46
- renderUserMessageActions?: (message: SessionMessage, parts: SessionPart[]) => ReactNode;
47
- renderToolActions?: (part: ToolPart, options: {
48
- run: Extract<GroupedMessage, {
49
- type: "run";
50
- }>["run"];
51
- messageId: string;
52
- partIndex: number;
53
- }) => ReactNode;
54
- }
55
- /**
56
- * Maps GroupedMessage[] to UserMessage and RunGroup components.
57
- * This is the main render list for the chat view.
58
- */
59
- declare const MessageList: React.MemoExoticComponent<({ groups, partMap, isCollapsed, onToggleCollapse, branding, renderToolDetail, renderRunActions, renderUserMessageActions, renderToolActions, }: MessageListProps) => react_jsx_runtime.JSX.Element>;
60
-
61
- interface UserMessageProps {
62
- message: SessionMessage;
63
- parts: SessionPart[];
64
- actions?: ReactNode;
65
- }
66
- /**
67
- * Simple user message bubble.
68
- * Renders text parts from the user's message.
69
- */
70
- declare const UserMessage: React.MemoExoticComponent<({ message, parts, actions }: UserMessageProps) => react_jsx_runtime.JSX.Element | null>;
71
-
72
- interface ThinkingIndicatorProps {
73
- className?: string;
74
- }
75
- declare function ThinkingIndicator({ className }: ThinkingIndicatorProps): react_jsx_runtime.JSX.Element;
76
-
77
- type AgentTimelineTone = "default" | "info" | "success" | "warning" | "error";
78
- interface AgentTimelineMessageItem {
79
- id: string;
80
- kind: "message";
81
- role: MessageRole;
82
- content: string;
83
- toolCalls?: ReactNode;
84
- isStreaming?: boolean;
85
- timestamp?: Date;
86
- after?: ReactNode;
87
- }
88
- interface AgentTimelineToolItem {
89
- id: string;
90
- kind: "tool";
91
- call: ToolCallData;
92
- }
93
- interface AgentTimelineToolGroupItem {
94
- id: string;
95
- kind: "tool_group";
96
- title?: string;
97
- calls: ToolCallData[];
98
- }
99
- interface AgentTimelineStatusItem {
100
- id: string;
101
- kind: "status";
102
- label: string;
103
- detail?: string;
104
- tone?: AgentTimelineTone;
105
- }
106
- interface AgentTimelineArtifactItem {
107
- id: string;
108
- kind: "artifact";
109
- title: string;
110
- description?: string;
111
- meta?: ReactNode;
112
- icon?: ReactNode;
113
- tone?: AgentTimelineTone;
114
- action?: ReactNode;
115
- onClick?: () => void;
116
- }
117
- interface AgentTimelineCustomItem {
118
- id: string;
119
- kind: "custom";
120
- content: ReactNode;
121
- }
122
- type AgentTimelineItem = AgentTimelineMessageItem | AgentTimelineToolItem | AgentTimelineToolGroupItem | AgentTimelineStatusItem | AgentTimelineArtifactItem | AgentTimelineCustomItem;
123
- interface AgentTimelineProps {
124
- items: AgentTimelineItem[];
125
- isThinking?: boolean;
126
- emptyState?: ReactNode;
127
- className?: string;
128
- }
129
- /**
130
- * AgentTimeline — unified mixed-content timeline for agent-backed sandbox
131
- * sessions. Renders messages, tool steps, status cards, and artifact handoffs in
132
- * a single execution narrative.
133
- */
134
- declare function AgentTimeline({ items, isThinking, emptyState, className, }: AgentTimelineProps): react_jsx_runtime.JSX.Element | null;
135
-
136
- export { AgentTimeline, type AgentTimelineArtifactItem, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, ChatMessage, type ChatMessageProps, MessageList, type MessageListProps, type MessageRole, ThinkingIndicator, type ThinkingIndicatorProps, UserMessage, type UserMessageProps };
1
+ export { AgentTimeline, AgentTimelineArtifactItem, AgentTimelineCustomItem, AgentTimelineItem, AgentTimelineMessageItem, AgentTimelineProps, AgentTimelineStatusItem, AgentTimelineTone, AgentTimelineToolGroupItem, AgentTimelineToolItem, ChatContainer, ChatContainerProps, ChatInput, ChatInputProps, ChatMessage, ChatMessageProps, MessageList, MessageListProps, MessageRole, PendingFile, ThinkingIndicator, ThinkingIndicatorProps, UserMessage, UserMessageProps } from '@tangle-network/ui/chat';
package/dist/chat.js CHANGED
@@ -1,25 +1,12 @@
1
- import {
2
- ChatMessage
3
- } from "./chunk-GSZA3TSY.js";
4
1
  import {
5
2
  AgentTimeline,
6
3
  ChatContainer,
7
4
  ChatInput,
5
+ ChatMessage,
8
6
  MessageList,
9
7
  ThinkingIndicator,
10
8
  UserMessage
11
- } from "./chunk-XLG757B6.js";
12
- import "./chunk-54SQQMMM.js";
13
- import "./chunk-MQXABZTB.js";
14
- import "./chunk-4CLN43XT.js";
15
- import "./chunk-MT5FJ3ZT.js";
16
- import "./chunk-BX6AQMUS.js";
17
- import "./chunk-ZNCEM5CD.js";
18
- import "./chunk-34I7UFSX.js";
19
- import "./chunk-T7HMZEVO.js";
20
- import "./chunk-ZMNSRDMH.js";
21
- import "./chunk-MKTSMWVD.js";
22
- import "./chunk-RQHJBTEU.js";
9
+ } from "./chunk-QPAJR74X.js";
23
10
  export {
24
11
  AgentTimeline,
25
12
  ChatContainer,
File without changes
@@ -0,0 +1,18 @@
1
+ // src/files/index.ts
2
+ import {
3
+ FileArtifactPane,
4
+ FilePreview,
5
+ FileTabs,
6
+ FileTree,
7
+ RichFileTree,
8
+ filterFileTree
9
+ } from "@tangle-network/ui/files";
10
+
11
+ export {
12
+ FileArtifactPane,
13
+ FilePreview,
14
+ FileTabs,
15
+ FileTree,
16
+ RichFileTree,
17
+ filterFileTree
18
+ };
@@ -0,0 +1,206 @@
1
+ // src/hooks/index.ts
2
+ import {
3
+ RealtimeSessionRegistry,
4
+ createAuthFetcher,
5
+ useApiKey,
6
+ useAuth,
7
+ useAutoScroll,
8
+ useDropdownMenu,
9
+ useLiveTime,
10
+ useRealtimeSession,
11
+ useRunCollapseState,
12
+ useRunGroups,
13
+ useSSEStream,
14
+ useSdkSession,
15
+ useToolCallStream
16
+ } from "@tangle-network/ui/hooks";
17
+
18
+ // src/hooks/use-sandbox-metrics.ts
19
+ import * as React from "react";
20
+ function useSandboxMetrics({
21
+ apiBaseUrl,
22
+ sandboxId,
23
+ token,
24
+ enabled = true,
25
+ intervalMs = 3e3
26
+ }) {
27
+ const [metrics, setMetrics] = React.useState(null);
28
+ const [loading, setLoading] = React.useState(false);
29
+ const [error, setError] = React.useState(null);
30
+ const [lastUpdatedAt, setLastUpdatedAt] = React.useState(null);
31
+ const sampleRef = React.useRef(null);
32
+ const hasLoadedRef = React.useRef(false);
33
+ const prevSandboxIdRef = React.useRef(null);
34
+ React.useEffect(() => {
35
+ const sandboxCleared = !sandboxId || !apiBaseUrl;
36
+ const sandboxChanged = prevSandboxIdRef.current !== null && prevSandboxIdRef.current !== sandboxId;
37
+ if (sandboxCleared && prevSandboxIdRef.current !== null || sandboxChanged) {
38
+ sampleRef.current = null;
39
+ hasLoadedRef.current = false;
40
+ setMetrics(null);
41
+ setLastUpdatedAt(null);
42
+ setError(null);
43
+ if (sandboxCleared) setLoading(false);
44
+ }
45
+ prevSandboxIdRef.current = sandboxId ?? null;
46
+ if (!enabled || sandboxCleared) {
47
+ return;
48
+ }
49
+ const controller = new AbortController();
50
+ let cancelled = false;
51
+ let timeoutId = null;
52
+ const delay = Math.max(intervalMs, 500);
53
+ const fetchOnce = async () => {
54
+ if (!hasLoadedRef.current) setLoading(true);
55
+ try {
56
+ const headers = {};
57
+ if (token) headers.Authorization = `Bearer ${token}`;
58
+ const res = await fetch(
59
+ `${apiBaseUrl}/v1/sidecar-proxy/${encodeURIComponent(sandboxId)}/metrics/json`,
60
+ {
61
+ method: "GET",
62
+ credentials: "include",
63
+ headers,
64
+ signal: controller.signal
65
+ }
66
+ );
67
+ if (!res.ok) {
68
+ throw new Error(`Metrics request failed (HTTP ${res.status})`);
69
+ }
70
+ const data = await res.json();
71
+ const user = data?.process?.cpuSeconds?.user ?? 0;
72
+ const system = data?.process?.cpuSeconds?.system ?? 0;
73
+ const cpuSeconds = user + system;
74
+ const wallMs = Date.now();
75
+ if (cancelled) return;
76
+ let cpuPercent = null;
77
+ const prev = sampleRef.current;
78
+ if (prev && prev.sandboxId === sandboxId) {
79
+ const dCpu = cpuSeconds - prev.cpuSeconds;
80
+ const dWallSec = (wallMs - prev.wallMs) / 1e3;
81
+ if (dWallSec > 0 && dCpu >= 0) {
82
+ cpuPercent = dCpu / dWallSec * 100;
83
+ }
84
+ }
85
+ sampleRef.current = { cpuSeconds, wallMs, sandboxId };
86
+ setMetrics({
87
+ cpuPercent,
88
+ rssBytes: data?.process?.memoryBytes?.rss ?? 0,
89
+ heapUsedBytes: data?.process?.memoryBytes?.heapUsed ?? 0,
90
+ heapTotalBytes: data?.process?.memoryBytes?.heapTotal ?? 0
91
+ });
92
+ setLastUpdatedAt(wallMs);
93
+ setError(null);
94
+ hasLoadedRef.current = true;
95
+ setLoading(false);
96
+ } catch (err) {
97
+ if (cancelled || err instanceof DOMException && err.name === "AbortError") {
98
+ return;
99
+ }
100
+ setError(err instanceof Error ? err : new Error(String(err)));
101
+ if (!hasLoadedRef.current) setLoading(false);
102
+ }
103
+ };
104
+ const runLoop = async () => {
105
+ if (cancelled) return;
106
+ await fetchOnce();
107
+ if (cancelled) return;
108
+ timeoutId = window.setTimeout(runLoop, delay);
109
+ };
110
+ runLoop();
111
+ return () => {
112
+ cancelled = true;
113
+ controller.abort();
114
+ if (timeoutId !== null) window.clearTimeout(timeoutId);
115
+ };
116
+ }, [apiBaseUrl, sandboxId, token, enabled, intervalMs]);
117
+ return { metrics, loading, error, lastUpdatedAt };
118
+ }
119
+
120
+ // src/hooks/use-session-crud.ts
121
+ import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
122
+ async function sessionFetch(apiUrl, token, path, opts) {
123
+ const res = await fetch(`${apiUrl}${path}`, {
124
+ ...opts,
125
+ headers: {
126
+ "Content-Type": "application/json",
127
+ Authorization: `Bearer ${token}`,
128
+ ...opts?.headers ?? {}
129
+ }
130
+ });
131
+ if (!res.ok) {
132
+ const text = await res.text();
133
+ throw new Error(text || `API error: ${res.status}`);
134
+ }
135
+ return res.json();
136
+ }
137
+ function useSessions(apiUrl, token) {
138
+ return useQuery({
139
+ queryKey: ["sessions", apiUrl, token],
140
+ queryFn: () => sessionFetch(apiUrl, token, "/session/sessions"),
141
+ enabled: !!token,
142
+ staleTime: 3e4
143
+ });
144
+ }
145
+ function useCreateSession(apiUrl, token) {
146
+ const queryClient = useQueryClient();
147
+ return useMutation({
148
+ mutationFn: async (title) => {
149
+ return sessionFetch(apiUrl, token, "/session/sessions", {
150
+ method: "POST",
151
+ body: JSON.stringify({ title, backend: { type: "opencode" } })
152
+ });
153
+ },
154
+ onSuccess: () => {
155
+ queryClient.invalidateQueries({ queryKey: ["sessions", apiUrl, token] });
156
+ }
157
+ });
158
+ }
159
+ function useDeleteSession(apiUrl, token) {
160
+ const queryClient = useQueryClient();
161
+ return useMutation({
162
+ mutationFn: async (sessionId) => {
163
+ return sessionFetch(apiUrl, token, `/session/sessions/${encodeURIComponent(sessionId)}`, {
164
+ method: "DELETE"
165
+ });
166
+ },
167
+ onSuccess: () => {
168
+ queryClient.invalidateQueries({ queryKey: ["sessions", apiUrl, token] });
169
+ }
170
+ });
171
+ }
172
+ function useRenameSession(apiUrl, token) {
173
+ const queryClient = useQueryClient();
174
+ return useMutation({
175
+ mutationFn: async ({ sessionId, title }) => {
176
+ return sessionFetch(apiUrl, token, `/session/sessions/${encodeURIComponent(sessionId)}`, {
177
+ method: "PATCH",
178
+ body: JSON.stringify({ title })
179
+ });
180
+ },
181
+ onSuccess: () => {
182
+ queryClient.invalidateQueries({ queryKey: ["sessions", apiUrl, token] });
183
+ }
184
+ });
185
+ }
186
+
187
+ export {
188
+ useSandboxMetrics,
189
+ useSessions,
190
+ useCreateSession,
191
+ useDeleteSession,
192
+ useRenameSession,
193
+ RealtimeSessionRegistry,
194
+ createAuthFetcher,
195
+ useApiKey,
196
+ useAuth,
197
+ useAutoScroll,
198
+ useDropdownMenu,
199
+ useLiveTime,
200
+ useRealtimeSession,
201
+ useRunCollapseState,
202
+ useRunGroups,
203
+ useSSEStream,
204
+ useSdkSession,
205
+ useToolCallStream
206
+ };