@sandbox-agent/react 0.3.1 → 0.4.0-rc.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/index.d.ts CHANGED
@@ -1,6 +1,180 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { CSSProperties } from 'react';
2
+ import * as react from 'react';
3
+ import { RefObject, ReactNode, KeyboardEvent, Ref, TextareaHTMLAttributes, CSSProperties } from 'react';
3
4
  import { SandboxAgent, TerminalExitStatus, TerminalErrorStatus } from 'sandbox-agent';
5
+ import * as _tanstack_react_virtual from '@tanstack/react-virtual';
6
+
7
+ type PermissionReply = "once" | "always" | "reject";
8
+ type PermissionOption = {
9
+ optionId: string;
10
+ name: string;
11
+ kind: string;
12
+ };
13
+ type TranscriptEntry = {
14
+ id: string;
15
+ eventId?: string;
16
+ kind: "message" | "tool" | "meta" | "reasoning" | "permission";
17
+ time: string;
18
+ role?: "user" | "assistant";
19
+ text?: string;
20
+ toolName?: string;
21
+ toolInput?: string;
22
+ toolOutput?: string;
23
+ toolStatus?: string;
24
+ reasoning?: {
25
+ text: string;
26
+ visibility?: string;
27
+ };
28
+ meta?: {
29
+ title: string;
30
+ detail?: string;
31
+ severity?: "info" | "error";
32
+ };
33
+ permission?: {
34
+ permissionId: string;
35
+ title: string;
36
+ description?: string;
37
+ options: PermissionOption[];
38
+ resolved?: boolean;
39
+ selectedOptionId?: string;
40
+ };
41
+ };
42
+ interface AgentTranscriptClassNames {
43
+ root: string;
44
+ divider: string;
45
+ dividerLine: string;
46
+ dividerText: string;
47
+ message: string;
48
+ messageContent: string;
49
+ messageText: string;
50
+ error: string;
51
+ toolGroupSingle: string;
52
+ toolGroupContainer: string;
53
+ toolGroupHeader: string;
54
+ toolGroupIcon: string;
55
+ toolGroupLabel: string;
56
+ toolGroupChevron: string;
57
+ toolGroupBody: string;
58
+ toolItem: string;
59
+ toolItemConnector: string;
60
+ toolItemDot: string;
61
+ toolItemLine: string;
62
+ toolItemContent: string;
63
+ toolItemHeader: string;
64
+ toolItemIcon: string;
65
+ toolItemLabel: string;
66
+ toolItemSpinner: string;
67
+ toolItemLink: string;
68
+ toolItemChevron: string;
69
+ toolItemBody: string;
70
+ toolSection: string;
71
+ toolSectionTitle: string;
72
+ toolCode: string;
73
+ toolCodeMuted: string;
74
+ permissionPrompt: string;
75
+ permissionHeader: string;
76
+ permissionIcon: string;
77
+ permissionTitle: string;
78
+ permissionDescription: string;
79
+ permissionActions: string;
80
+ permissionButton: string;
81
+ permissionAutoResolved: string;
82
+ thinkingRow: string;
83
+ thinkingAvatar: string;
84
+ thinkingAvatarImage: string;
85
+ thinkingAvatarLabel: string;
86
+ thinkingIndicator: string;
87
+ thinkingDot: string;
88
+ endAnchor: string;
89
+ }
90
+ interface PermissionOptionRenderContext {
91
+ entry: TranscriptEntry;
92
+ option: PermissionOption;
93
+ label: string;
94
+ reply: PermissionReply;
95
+ selected: boolean;
96
+ dimmed: boolean;
97
+ resolved: boolean;
98
+ }
99
+ interface AgentTranscriptProps {
100
+ entries: TranscriptEntry[];
101
+ className?: string;
102
+ classNames?: Partial<AgentTranscriptClassNames>;
103
+ endRef?: RefObject<HTMLDivElement>;
104
+ scrollRef?: RefObject<HTMLDivElement>;
105
+ scrollToEntryId?: string | null;
106
+ sessionError?: string | null;
107
+ eventError?: string | null;
108
+ isThinking?: boolean;
109
+ agentId?: string;
110
+ virtualize?: boolean;
111
+ onAtBottomChange?: (atBottom: boolean) => void;
112
+ onEventClick?: (eventId: string) => void;
113
+ onPermissionReply?: (permissionId: string, reply: PermissionReply) => void;
114
+ isDividerEntry?: (entry: TranscriptEntry) => boolean;
115
+ canOpenEvent?: (entry: TranscriptEntry) => boolean;
116
+ getToolGroupSummary?: (entries: TranscriptEntry[]) => string;
117
+ renderMessageText?: (entry: TranscriptEntry) => ReactNode;
118
+ renderInlinePendingIndicator?: () => ReactNode;
119
+ renderThinkingState?: (context: {
120
+ agentId?: string;
121
+ }) => ReactNode;
122
+ renderToolItemIcon?: (entry: TranscriptEntry) => ReactNode;
123
+ renderToolGroupIcon?: (entries: TranscriptEntry[], expanded: boolean) => ReactNode;
124
+ renderChevron?: (expanded: boolean) => ReactNode;
125
+ renderEventLinkContent?: (entry: TranscriptEntry) => ReactNode;
126
+ renderPermissionIcon?: (entry: TranscriptEntry) => ReactNode;
127
+ renderPermissionOptionContent?: (context: PermissionOptionRenderContext) => ReactNode;
128
+ }
129
+ declare const AgentTranscript: ({ entries, className, classNames: classNameOverrides, endRef, scrollRef, scrollToEntryId, sessionError, eventError, isThinking, agentId, virtualize, onAtBottomChange, onEventClick, onPermissionReply, isDividerEntry, canOpenEvent, getToolGroupSummary, renderMessageText, renderInlinePendingIndicator, renderThinkingState, renderToolItemIcon, renderToolGroupIcon, renderChevron, renderEventLinkContent, renderPermissionIcon, renderPermissionOptionContent, }: AgentTranscriptProps) => react_jsx_runtime.JSX.Element;
130
+
131
+ interface ChatComposerClassNames {
132
+ root: string;
133
+ form: string;
134
+ input: string;
135
+ submit: string;
136
+ submitContent: string;
137
+ }
138
+ interface ChatComposerProps {
139
+ message: string;
140
+ onMessageChange: (value: string) => void;
141
+ onSubmit: () => void;
142
+ onKeyDown?: (event: KeyboardEvent<HTMLTextAreaElement>) => void;
143
+ placeholder?: string;
144
+ disabled?: boolean;
145
+ submitDisabled?: boolean;
146
+ allowEmptySubmit?: boolean;
147
+ submitLabel?: string;
148
+ className?: string;
149
+ classNames?: Partial<ChatComposerClassNames>;
150
+ inputRef?: Ref<HTMLTextAreaElement>;
151
+ rows?: number;
152
+ textareaProps?: Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, "className" | "disabled" | "onChange" | "onKeyDown" | "placeholder" | "rows" | "value">;
153
+ renderSubmitContent?: () => ReactNode;
154
+ renderFooter?: () => ReactNode;
155
+ }
156
+ declare const ChatComposer: ({ message, onMessageChange, onSubmit, onKeyDown, placeholder, disabled, submitDisabled, allowEmptySubmit, submitLabel, className, classNames: classNameOverrides, inputRef, rows, textareaProps, renderSubmitContent, renderFooter, }: ChatComposerProps) => react_jsx_runtime.JSX.Element;
157
+
158
+ interface AgentConversationClassNames {
159
+ root: string;
160
+ transcript: string;
161
+ emptyState: string;
162
+ composer: string;
163
+ }
164
+ interface AgentConversationProps {
165
+ entries: TranscriptEntry[];
166
+ className?: string;
167
+ classNames?: Partial<AgentConversationClassNames>;
168
+ emptyState?: ReactNode;
169
+ transcriptClassName?: string;
170
+ transcriptClassNames?: Partial<AgentTranscriptClassNames>;
171
+ scrollRef?: RefObject<HTMLDivElement>;
172
+ composerClassName?: string;
173
+ composerClassNames?: Partial<ChatComposerClassNames>;
174
+ transcriptProps?: Omit<AgentTranscriptProps, "entries" | "className" | "classNames" | "scrollRef">;
175
+ composerProps?: Omit<ChatComposerProps, "className" | "classNames">;
176
+ }
177
+ declare const AgentConversation: ({ entries, className, classNames: classNameOverrides, emptyState, transcriptClassName, transcriptClassNames, scrollRef, composerClassName, composerClassNames, transcriptProps, composerProps, }: AgentConversationProps) => react_jsx_runtime.JSX.Element;
4
178
 
5
179
  type ProcessTerminalClient = Pick<SandboxAgent, "connectProcessTerminal">;
6
180
  interface ProcessTerminalProps {
@@ -9,10 +183,17 @@ interface ProcessTerminalProps {
9
183
  className?: string;
10
184
  style?: CSSProperties;
11
185
  terminalStyle?: CSSProperties;
186
+ statusBarStyleOverride?: CSSProperties;
12
187
  height?: number | string;
188
+ showStatusBar?: boolean;
13
189
  onExit?: (status: TerminalExitStatus) => void;
14
190
  onError?: (error: TerminalErrorStatus | Error) => void;
15
191
  }
16
- declare const ProcessTerminal: ({ client, processId, className, style, terminalStyle, height, onExit, onError, }: ProcessTerminalProps) => react_jsx_runtime.JSX.Element;
192
+ declare const ProcessTerminal: ({ client, processId, className, style, terminalStyle, statusBarStyleOverride, height, showStatusBar, onExit, onError, }: ProcessTerminalProps) => react_jsx_runtime.JSX.Element;
193
+
194
+ declare function useTranscriptVirtualizer<T>(items: T[], scrollElementRef?: RefObject<HTMLDivElement>, onAtBottomChange?: (atBottom: boolean) => void): {
195
+ virtualizer: _tanstack_react_virtual.Virtualizer<HTMLDivElement, Element>;
196
+ isFollowingRef: react.MutableRefObject<boolean>;
197
+ };
17
198
 
18
- export { ProcessTerminal, type ProcessTerminalClient, type ProcessTerminalProps };
199
+ export { AgentConversation, type AgentConversationClassNames, type AgentConversationProps, AgentTranscript, type AgentTranscriptClassNames, type AgentTranscriptProps, ChatComposer, type ChatComposerClassNames, type ChatComposerProps, type PermissionOption, type PermissionOptionRenderContext, type PermissionReply, ProcessTerminal, type ProcessTerminalClient, type ProcessTerminalProps, type TranscriptEntry, useTranscriptVirtualizer };
package/dist/index.js CHANGED
@@ -1,6 +1,787 @@
1
- // src/ProcessTerminal.tsx
2
- import { useEffect, useRef, useState } from "react";
1
+ // src/AgentTranscript.tsx
2
+ import { useEffect as useEffect2, useMemo, useRef as useRef2, useState } from "react";
3
+
4
+ // src/useTranscriptVirtualizer.ts
5
+ import { useEffect, useRef } from "react";
6
+ import { useVirtualizer } from "@tanstack/react-virtual";
7
+ function useTranscriptVirtualizer(items, scrollElementRef, onAtBottomChange) {
8
+ const isFollowingRef = useRef(true);
9
+ const virtualizer = useVirtualizer({
10
+ count: items.length,
11
+ getScrollElement: () => scrollElementRef?.current ?? null,
12
+ estimateSize: () => 80,
13
+ measureElement: (element) => element.getBoundingClientRect().height,
14
+ overscan: 10
15
+ });
16
+ virtualizer.shouldAdjustScrollPositionOnItemSizeChange = () => isFollowingRef.current;
17
+ useEffect(() => {
18
+ const scrollElement = scrollElementRef?.current;
19
+ if (!scrollElement) {
20
+ return;
21
+ }
22
+ const updateFollowState = () => {
23
+ const atBottom = scrollElement.scrollHeight - scrollElement.scrollTop - scrollElement.clientHeight < 50;
24
+ isFollowingRef.current = atBottom;
25
+ onAtBottomChange?.(atBottom);
26
+ };
27
+ updateFollowState();
28
+ scrollElement.addEventListener("scroll", updateFollowState, { passive: true });
29
+ return () => {
30
+ scrollElement.removeEventListener("scroll", updateFollowState);
31
+ };
32
+ }, [onAtBottomChange, scrollElementRef]);
33
+ useEffect(() => {
34
+ if (!isFollowingRef.current || items.length === 0) {
35
+ return;
36
+ }
37
+ const frameId = requestAnimationFrame(() => {
38
+ virtualizer.scrollToIndex(items.length - 1, {
39
+ align: "end",
40
+ behavior: "smooth"
41
+ });
42
+ });
43
+ return () => {
44
+ cancelAnimationFrame(frameId);
45
+ };
46
+ }, [items.length, virtualizer]);
47
+ return { virtualizer, isFollowingRef };
48
+ }
49
+
50
+ // src/AgentTranscript.tsx
3
51
  import { jsx, jsxs } from "react/jsx-runtime";
52
+ var VIRTUAL_GROUP_GAP_PX = 12;
53
+ var DEFAULT_CLASS_NAMES = {
54
+ root: "sa-agent-transcript",
55
+ divider: "sa-agent-transcript-divider",
56
+ dividerLine: "sa-agent-transcript-divider-line",
57
+ dividerText: "sa-agent-transcript-divider-text",
58
+ message: "sa-agent-transcript-message",
59
+ messageContent: "sa-agent-transcript-message-content",
60
+ messageText: "sa-agent-transcript-message-text",
61
+ error: "sa-agent-transcript-error",
62
+ toolGroupSingle: "sa-agent-transcript-tool-group-single",
63
+ toolGroupContainer: "sa-agent-transcript-tool-group",
64
+ toolGroupHeader: "sa-agent-transcript-tool-group-header",
65
+ toolGroupIcon: "sa-agent-transcript-tool-group-icon",
66
+ toolGroupLabel: "sa-agent-transcript-tool-group-label",
67
+ toolGroupChevron: "sa-agent-transcript-tool-group-chevron",
68
+ toolGroupBody: "sa-agent-transcript-tool-group-body",
69
+ toolItem: "sa-agent-transcript-tool-item",
70
+ toolItemConnector: "sa-agent-transcript-tool-item-connector",
71
+ toolItemDot: "sa-agent-transcript-tool-item-dot",
72
+ toolItemLine: "sa-agent-transcript-tool-item-line",
73
+ toolItemContent: "sa-agent-transcript-tool-item-content",
74
+ toolItemHeader: "sa-agent-transcript-tool-item-header",
75
+ toolItemIcon: "sa-agent-transcript-tool-item-icon",
76
+ toolItemLabel: "sa-agent-transcript-tool-item-label",
77
+ toolItemSpinner: "sa-agent-transcript-tool-item-spinner",
78
+ toolItemLink: "sa-agent-transcript-tool-item-link",
79
+ toolItemChevron: "sa-agent-transcript-tool-item-chevron",
80
+ toolItemBody: "sa-agent-transcript-tool-item-body",
81
+ toolSection: "sa-agent-transcript-tool-section",
82
+ toolSectionTitle: "sa-agent-transcript-tool-section-title",
83
+ toolCode: "sa-agent-transcript-tool-code",
84
+ toolCodeMuted: "sa-agent-transcript-tool-code-muted",
85
+ permissionPrompt: "sa-agent-transcript-permission-prompt",
86
+ permissionHeader: "sa-agent-transcript-permission-header",
87
+ permissionIcon: "sa-agent-transcript-permission-icon",
88
+ permissionTitle: "sa-agent-transcript-permission-title",
89
+ permissionDescription: "sa-agent-transcript-permission-description",
90
+ permissionActions: "sa-agent-transcript-permission-actions",
91
+ permissionButton: "sa-agent-transcript-permission-button",
92
+ permissionAutoResolved: "sa-agent-transcript-permission-auto-resolved",
93
+ thinkingRow: "sa-agent-transcript-thinking-row",
94
+ thinkingAvatar: "sa-agent-transcript-thinking-avatar",
95
+ thinkingAvatarImage: "sa-agent-transcript-thinking-avatar-image",
96
+ thinkingAvatarLabel: "sa-agent-transcript-thinking-avatar-label",
97
+ thinkingIndicator: "sa-agent-transcript-thinking-indicator",
98
+ thinkingDot: "sa-agent-transcript-thinking-dot",
99
+ endAnchor: "sa-agent-transcript-end"
100
+ };
101
+ var DEFAULT_DIVIDER_TITLES = /* @__PURE__ */ new Set(["Session Started", "Turn Started", "Turn Ended"]);
102
+ var cx = (...values) => values.filter(Boolean).join(" ");
103
+ var mergeClassNames = (defaults, overrides) => ({
104
+ root: cx(defaults.root, overrides?.root),
105
+ divider: cx(defaults.divider, overrides?.divider),
106
+ dividerLine: cx(defaults.dividerLine, overrides?.dividerLine),
107
+ dividerText: cx(defaults.dividerText, overrides?.dividerText),
108
+ message: cx(defaults.message, overrides?.message),
109
+ messageContent: cx(defaults.messageContent, overrides?.messageContent),
110
+ messageText: cx(defaults.messageText, overrides?.messageText),
111
+ error: cx(defaults.error, overrides?.error),
112
+ toolGroupSingle: cx(defaults.toolGroupSingle, overrides?.toolGroupSingle),
113
+ toolGroupContainer: cx(defaults.toolGroupContainer, overrides?.toolGroupContainer),
114
+ toolGroupHeader: cx(defaults.toolGroupHeader, overrides?.toolGroupHeader),
115
+ toolGroupIcon: cx(defaults.toolGroupIcon, overrides?.toolGroupIcon),
116
+ toolGroupLabel: cx(defaults.toolGroupLabel, overrides?.toolGroupLabel),
117
+ toolGroupChevron: cx(defaults.toolGroupChevron, overrides?.toolGroupChevron),
118
+ toolGroupBody: cx(defaults.toolGroupBody, overrides?.toolGroupBody),
119
+ toolItem: cx(defaults.toolItem, overrides?.toolItem),
120
+ toolItemConnector: cx(defaults.toolItemConnector, overrides?.toolItemConnector),
121
+ toolItemDot: cx(defaults.toolItemDot, overrides?.toolItemDot),
122
+ toolItemLine: cx(defaults.toolItemLine, overrides?.toolItemLine),
123
+ toolItemContent: cx(defaults.toolItemContent, overrides?.toolItemContent),
124
+ toolItemHeader: cx(defaults.toolItemHeader, overrides?.toolItemHeader),
125
+ toolItemIcon: cx(defaults.toolItemIcon, overrides?.toolItemIcon),
126
+ toolItemLabel: cx(defaults.toolItemLabel, overrides?.toolItemLabel),
127
+ toolItemSpinner: cx(defaults.toolItemSpinner, overrides?.toolItemSpinner),
128
+ toolItemLink: cx(defaults.toolItemLink, overrides?.toolItemLink),
129
+ toolItemChevron: cx(defaults.toolItemChevron, overrides?.toolItemChevron),
130
+ toolItemBody: cx(defaults.toolItemBody, overrides?.toolItemBody),
131
+ toolSection: cx(defaults.toolSection, overrides?.toolSection),
132
+ toolSectionTitle: cx(defaults.toolSectionTitle, overrides?.toolSectionTitle),
133
+ toolCode: cx(defaults.toolCode, overrides?.toolCode),
134
+ toolCodeMuted: cx(defaults.toolCodeMuted, overrides?.toolCodeMuted),
135
+ permissionPrompt: cx(defaults.permissionPrompt, overrides?.permissionPrompt),
136
+ permissionHeader: cx(defaults.permissionHeader, overrides?.permissionHeader),
137
+ permissionIcon: cx(defaults.permissionIcon, overrides?.permissionIcon),
138
+ permissionTitle: cx(defaults.permissionTitle, overrides?.permissionTitle),
139
+ permissionDescription: cx(defaults.permissionDescription, overrides?.permissionDescription),
140
+ permissionActions: cx(defaults.permissionActions, overrides?.permissionActions),
141
+ permissionButton: cx(defaults.permissionButton, overrides?.permissionButton),
142
+ permissionAutoResolved: cx(defaults.permissionAutoResolved, overrides?.permissionAutoResolved),
143
+ thinkingRow: cx(defaults.thinkingRow, overrides?.thinkingRow),
144
+ thinkingAvatar: cx(defaults.thinkingAvatar, overrides?.thinkingAvatar),
145
+ thinkingAvatarImage: cx(defaults.thinkingAvatarImage, overrides?.thinkingAvatarImage),
146
+ thinkingAvatarLabel: cx(defaults.thinkingAvatarLabel, overrides?.thinkingAvatarLabel),
147
+ thinkingIndicator: cx(defaults.thinkingIndicator, overrides?.thinkingIndicator),
148
+ thinkingDot: cx(defaults.thinkingDot, overrides?.thinkingDot),
149
+ endAnchor: cx(defaults.endAnchor, overrides?.endAnchor)
150
+ });
151
+ var getMessageVariant = (entry) => {
152
+ if (entry.kind === "tool") return "tool";
153
+ if (entry.kind === "meta") return entry.meta?.severity === "error" ? "error" : "system";
154
+ if (entry.kind === "reasoning") return "assistant";
155
+ if (entry.kind === "permission") return "system";
156
+ if (entry.role === "user") return "user";
157
+ return "assistant";
158
+ };
159
+ var getToolItemLabel = (entry) => {
160
+ if (entry.kind === "tool") {
161
+ const statusLabel = entry.toolStatus && entry.toolStatus !== "completed" ? ` (${entry.toolStatus.replaceAll("_", " ")})` : "";
162
+ return `${entry.toolName ?? "tool"}${statusLabel}`;
163
+ }
164
+ if (entry.kind === "reasoning") {
165
+ return `Reasoning${entry.reasoning?.visibility ? ` (${entry.reasoning.visibility})` : ""}`;
166
+ }
167
+ return entry.meta?.title ?? "Status";
168
+ };
169
+ var getDefaultToolItemIcon = (entry) => {
170
+ if (entry.kind === "tool") return "Tool";
171
+ if (entry.kind === "reasoning") return "Thought";
172
+ return entry.meta?.severity === "error" ? "Error" : "Info";
173
+ };
174
+ var getDefaultToolGroupSummary = (entries) => {
175
+ const count = entries.length;
176
+ return `${count} Event${count === 1 ? "" : "s"}`;
177
+ };
178
+ var getPermissionReplyForOption = (kind) => {
179
+ if (kind === "allow_once") return "once";
180
+ if (kind === "allow_always") return "always";
181
+ return "reject";
182
+ };
183
+ var getPermissionOptionLabel = (option) => {
184
+ if (option.name) return option.name;
185
+ if (option.kind === "allow_once") return "Allow Once";
186
+ if (option.kind === "allow_always") return "Always Allow";
187
+ if (option.kind === "reject_once") return "Reject";
188
+ if (option.kind === "reject_always") return "Reject Always";
189
+ return option.kind;
190
+ };
191
+ var getPermissionOptionTone = (kind) => kind.startsWith("allow") ? "allow" : "reject";
192
+ var defaultRenderMessageText = (entry) => entry.text;
193
+ var defaultRenderPendingIndicator = () => "...";
194
+ var defaultRenderChevron = (expanded) => expanded ? "\u25BE" : "\u25B8";
195
+ var defaultRenderEventLinkContent = () => "Open";
196
+ var defaultRenderPermissionIcon = () => "Permission";
197
+ var defaultRenderPermissionOptionContent = ({ label }) => label;
198
+ var defaultIsDividerEntry = (entry) => entry.kind === "meta" && DEFAULT_DIVIDER_TITLES.has(entry.meta?.title ?? "");
199
+ var defaultCanOpenEvent = (entry) => Boolean(entry.eventId);
200
+ var buildGroupedEntries = (entries, isDividerEntry) => {
201
+ const groupedEntries = [];
202
+ let currentToolGroup = [];
203
+ const flushToolGroup = () => {
204
+ if (currentToolGroup.length === 0) {
205
+ return;
206
+ }
207
+ groupedEntries.push({ type: "tool-group", entries: currentToolGroup });
208
+ currentToolGroup = [];
209
+ };
210
+ for (const entry of entries) {
211
+ if (isDividerEntry(entry)) {
212
+ flushToolGroup();
213
+ groupedEntries.push({ type: "divider", entries: [entry] });
214
+ continue;
215
+ }
216
+ if (entry.kind === "permission") {
217
+ flushToolGroup();
218
+ groupedEntries.push({ type: "permission", entries: [entry] });
219
+ continue;
220
+ }
221
+ if (entry.kind === "tool" || entry.kind === "reasoning" || entry.kind === "meta") {
222
+ currentToolGroup.push(entry);
223
+ continue;
224
+ }
225
+ flushToolGroup();
226
+ groupedEntries.push({ type: "message", entries: [entry] });
227
+ }
228
+ flushToolGroup();
229
+ return groupedEntries;
230
+ };
231
+ var getGroupedEntryKey = (group, index) => {
232
+ const firstEntry = group.entries[0];
233
+ if (group.type === "tool-group") {
234
+ return `tool-group:${firstEntry?.id ?? index}`;
235
+ }
236
+ return firstEntry?.id ?? `${group.type}:${index}`;
237
+ };
238
+ var ToolItem = ({
239
+ entry,
240
+ isLast,
241
+ expanded,
242
+ onExpandedChange,
243
+ classNames,
244
+ onEventClick,
245
+ canOpenEvent,
246
+ renderInlinePendingIndicator,
247
+ renderToolItemIcon,
248
+ renderChevron,
249
+ renderEventLinkContent
250
+ }) => {
251
+ const isTool = entry.kind === "tool";
252
+ const isReasoning = entry.kind === "reasoning";
253
+ const isMeta = entry.kind === "meta";
254
+ const isComplete = isTool && (entry.toolStatus === "completed" || entry.toolStatus === "failed");
255
+ const isFailed = isTool && entry.toolStatus === "failed";
256
+ const isInProgress = isTool && entry.toolStatus === "in_progress";
257
+ const hasContent = isTool ? Boolean(entry.toolInput || entry.toolOutput) : isReasoning ? Boolean(entry.reasoning?.text?.trim()) : Boolean(entry.meta?.detail?.trim());
258
+ const showEventLink = Boolean(entry.eventId && onEventClick && canOpenEvent(entry));
259
+ return /* @__PURE__ */ jsxs(
260
+ "div",
261
+ {
262
+ className: cx(classNames.toolItem, isLast && "last", isFailed && "failed"),
263
+ "data-slot": "tool-item",
264
+ "data-kind": entry.kind,
265
+ "data-state": entry.toolStatus,
266
+ "data-last": isLast ? "true" : void 0,
267
+ "data-failed": isFailed ? "true" : void 0,
268
+ children: [
269
+ /* @__PURE__ */ jsxs("div", { className: classNames.toolItemConnector, "data-slot": "tool-item-connector", children: [
270
+ /* @__PURE__ */ jsx("div", { className: classNames.toolItemDot, "data-slot": "tool-item-dot" }),
271
+ !isLast ? /* @__PURE__ */ jsx("div", { className: classNames.toolItemLine, "data-slot": "tool-item-line" }) : null
272
+ ] }),
273
+ /* @__PURE__ */ jsxs("div", { className: classNames.toolItemContent, "data-slot": "tool-item-content", children: [
274
+ /* @__PURE__ */ jsxs(
275
+ "button",
276
+ {
277
+ type: "button",
278
+ className: cx(classNames.toolItemHeader, expanded && "expanded"),
279
+ "data-slot": "tool-item-header",
280
+ "data-expanded": expanded ? "true" : void 0,
281
+ "data-has-content": hasContent ? "true" : void 0,
282
+ disabled: !hasContent,
283
+ onClick: () => {
284
+ if (hasContent) {
285
+ onExpandedChange(!expanded);
286
+ }
287
+ },
288
+ children: [
289
+ /* @__PURE__ */ jsx("span", { className: classNames.toolItemIcon, "data-slot": "tool-item-icon", children: renderToolItemIcon(entry) }),
290
+ /* @__PURE__ */ jsx("span", { className: classNames.toolItemLabel, "data-slot": "tool-item-label", children: getToolItemLabel(entry) }),
291
+ isInProgress ? /* @__PURE__ */ jsx("span", { className: classNames.toolItemSpinner, "data-slot": "tool-item-spinner", children: renderInlinePendingIndicator() }) : null,
292
+ showEventLink ? /* @__PURE__ */ jsx(
293
+ "span",
294
+ {
295
+ className: classNames.toolItemLink,
296
+ "data-slot": "tool-item-link",
297
+ role: "button",
298
+ tabIndex: 0,
299
+ onClick: (event) => {
300
+ event.stopPropagation();
301
+ onEventClick?.(entry.eventId);
302
+ },
303
+ onKeyDown: (event) => {
304
+ if (event.key === "Enter" || event.key === " ") {
305
+ event.preventDefault();
306
+ event.stopPropagation();
307
+ onEventClick?.(entry.eventId);
308
+ }
309
+ },
310
+ children: renderEventLinkContent(entry)
311
+ }
312
+ ) : null,
313
+ hasContent ? /* @__PURE__ */ jsx("span", { className: classNames.toolItemChevron, "data-slot": "tool-item-chevron", children: renderChevron(expanded) }) : null
314
+ ]
315
+ }
316
+ ),
317
+ expanded && hasContent ? /* @__PURE__ */ jsxs("div", { className: classNames.toolItemBody, "data-slot": "tool-item-body", children: [
318
+ isTool && entry.toolInput ? /* @__PURE__ */ jsxs("div", { className: classNames.toolSection, "data-slot": "tool-section", "data-section": "input", children: [
319
+ /* @__PURE__ */ jsx("div", { className: classNames.toolSectionTitle, "data-slot": "tool-section-title", children: "Input" }),
320
+ /* @__PURE__ */ jsx("pre", { className: classNames.toolCode, "data-slot": "tool-code", children: entry.toolInput })
321
+ ] }) : null,
322
+ isTool && isComplete && entry.toolOutput ? /* @__PURE__ */ jsxs("div", { className: classNames.toolSection, "data-slot": "tool-section", "data-section": "output", children: [
323
+ /* @__PURE__ */ jsx("div", { className: classNames.toolSectionTitle, "data-slot": "tool-section-title", children: "Output" }),
324
+ /* @__PURE__ */ jsx("pre", { className: classNames.toolCode, "data-slot": "tool-code", children: entry.toolOutput })
325
+ ] }) : null,
326
+ isReasoning && entry.reasoning?.text ? /* @__PURE__ */ jsx("div", { className: classNames.toolSection, "data-slot": "tool-section", "data-section": "reasoning", children: /* @__PURE__ */ jsx("pre", { className: cx(classNames.toolCode, classNames.toolCodeMuted), "data-slot": "tool-code", children: entry.reasoning.text }) }) : null,
327
+ isMeta && entry.meta?.detail ? /* @__PURE__ */ jsx("div", { className: classNames.toolSection, "data-slot": "tool-section", "data-section": "meta", children: /* @__PURE__ */ jsx("pre", { className: classNames.toolCode, "data-slot": "tool-code", children: entry.meta.detail }) }) : null
328
+ ] }) : null
329
+ ] })
330
+ ]
331
+ }
332
+ );
333
+ };
334
+ var ToolGroup = ({
335
+ entries,
336
+ expanded,
337
+ onExpandedChange,
338
+ expandedItemIds,
339
+ onToolItemExpandedChange,
340
+ classNames,
341
+ onEventClick,
342
+ canOpenEvent,
343
+ getToolGroupSummary,
344
+ renderInlinePendingIndicator,
345
+ renderToolItemIcon,
346
+ renderToolGroupIcon,
347
+ renderChevron,
348
+ renderEventLinkContent
349
+ }) => {
350
+ const hasFailed = entries.some((entry) => entry.kind === "tool" && entry.toolStatus === "failed");
351
+ if (entries.length === 1) {
352
+ return /* @__PURE__ */ jsx("div", { className: classNames.toolGroupSingle, "data-slot": "tool-group-single", children: /* @__PURE__ */ jsx(
353
+ ToolItem,
354
+ {
355
+ entry: entries[0],
356
+ isLast: true,
357
+ expanded: Boolean(expandedItemIds[entries[0].id]),
358
+ onExpandedChange: (nextExpanded) => onToolItemExpandedChange(entries[0].id, nextExpanded),
359
+ classNames,
360
+ onEventClick,
361
+ canOpenEvent,
362
+ renderInlinePendingIndicator,
363
+ renderToolItemIcon,
364
+ renderChevron,
365
+ renderEventLinkContent
366
+ }
367
+ ) });
368
+ }
369
+ return /* @__PURE__ */ jsxs("div", { className: cx(classNames.toolGroupContainer, hasFailed && "failed"), "data-slot": "tool-group", "data-failed": hasFailed ? "true" : void 0, children: [
370
+ /* @__PURE__ */ jsxs(
371
+ "button",
372
+ {
373
+ type: "button",
374
+ className: cx(classNames.toolGroupHeader, expanded && "expanded"),
375
+ "data-slot": "tool-group-header",
376
+ "data-expanded": expanded ? "true" : void 0,
377
+ onClick: () => onExpandedChange(!expanded),
378
+ children: [
379
+ /* @__PURE__ */ jsx("span", { className: classNames.toolGroupIcon, "data-slot": "tool-group-icon", children: renderToolGroupIcon(entries, expanded) }),
380
+ /* @__PURE__ */ jsx("span", { className: classNames.toolGroupLabel, "data-slot": "tool-group-label", children: getToolGroupSummary(entries) }),
381
+ /* @__PURE__ */ jsx("span", { className: classNames.toolGroupChevron, "data-slot": "tool-group-chevron", children: renderChevron(expanded) })
382
+ ]
383
+ }
384
+ ),
385
+ expanded ? /* @__PURE__ */ jsx("div", { className: classNames.toolGroupBody, "data-slot": "tool-group-body", children: entries.map((entry, index) => /* @__PURE__ */ jsx(
386
+ ToolItem,
387
+ {
388
+ entry,
389
+ isLast: index === entries.length - 1,
390
+ expanded: Boolean(expandedItemIds[entry.id]),
391
+ onExpandedChange: (nextExpanded) => onToolItemExpandedChange(entry.id, nextExpanded),
392
+ classNames,
393
+ onEventClick,
394
+ canOpenEvent,
395
+ renderInlinePendingIndicator,
396
+ renderToolItemIcon,
397
+ renderChevron,
398
+ renderEventLinkContent
399
+ },
400
+ entry.id
401
+ )) }) : null
402
+ ] });
403
+ };
404
+ var PermissionPrompt = ({
405
+ entry,
406
+ classNames,
407
+ onPermissionReply,
408
+ renderPermissionIcon,
409
+ renderPermissionOptionContent
410
+ }) => {
411
+ const permission = entry.permission;
412
+ if (!permission) {
413
+ return null;
414
+ }
415
+ const resolved = Boolean(permission.resolved);
416
+ const selectedOptionId = permission.selectedOptionId;
417
+ const canReply = Boolean(onPermissionReply) && !resolved;
418
+ return /* @__PURE__ */ jsxs("div", { className: cx(classNames.permissionPrompt, resolved && "resolved"), "data-slot": "permission-prompt", "data-resolved": resolved ? "true" : void 0, children: [
419
+ /* @__PURE__ */ jsxs("div", { className: classNames.permissionHeader, "data-slot": "permission-header", children: [
420
+ /* @__PURE__ */ jsx("span", { className: classNames.permissionIcon, "data-slot": "permission-icon", children: renderPermissionIcon(entry) }),
421
+ /* @__PURE__ */ jsx("span", { className: classNames.permissionTitle, "data-slot": "permission-title", children: permission.title })
422
+ ] }),
423
+ permission.description ? /* @__PURE__ */ jsx("div", { className: classNames.permissionDescription, "data-slot": "permission-description", children: permission.description }) : null,
424
+ /* @__PURE__ */ jsxs("div", { className: classNames.permissionActions, "data-slot": "permission-actions", children: [
425
+ permission.options.map((option) => {
426
+ const reply = getPermissionReplyForOption(option.kind);
427
+ const label = getPermissionOptionLabel(option);
428
+ const selected = resolved && selectedOptionId === option.optionId;
429
+ const dimmed = resolved && !selected && selectedOptionId != null;
430
+ const tone = getPermissionOptionTone(option.kind);
431
+ return /* @__PURE__ */ jsx(
432
+ "button",
433
+ {
434
+ type: "button",
435
+ className: cx(classNames.permissionButton, tone, selected && "selected", dimmed && "dimmed"),
436
+ "data-slot": "permission-button",
437
+ "data-tone": tone,
438
+ "data-selected": selected ? "true" : void 0,
439
+ "data-dimmed": dimmed ? "true" : void 0,
440
+ disabled: !canReply,
441
+ onClick: () => onPermissionReply?.(permission.permissionId, reply),
442
+ children: renderPermissionOptionContent({
443
+ entry,
444
+ option,
445
+ label,
446
+ reply,
447
+ selected,
448
+ dimmed,
449
+ resolved
450
+ })
451
+ },
452
+ option.optionId
453
+ );
454
+ }),
455
+ resolved && !selectedOptionId ? /* @__PURE__ */ jsx("span", { className: classNames.permissionAutoResolved, "data-slot": "permission-auto-resolved", children: "Auto-resolved" }) : null
456
+ ] })
457
+ ] });
458
+ };
459
+ var AgentTranscript = ({
460
+ entries,
461
+ className,
462
+ classNames: classNameOverrides,
463
+ endRef,
464
+ scrollRef,
465
+ scrollToEntryId,
466
+ sessionError,
467
+ eventError,
468
+ isThinking,
469
+ agentId,
470
+ virtualize = false,
471
+ onAtBottomChange,
472
+ onEventClick,
473
+ onPermissionReply,
474
+ isDividerEntry = defaultIsDividerEntry,
475
+ canOpenEvent = defaultCanOpenEvent,
476
+ getToolGroupSummary = getDefaultToolGroupSummary,
477
+ renderMessageText = defaultRenderMessageText,
478
+ renderInlinePendingIndicator = defaultRenderPendingIndicator,
479
+ renderThinkingState,
480
+ renderToolItemIcon = getDefaultToolItemIcon,
481
+ renderToolGroupIcon = () => null,
482
+ renderChevron = defaultRenderChevron,
483
+ renderEventLinkContent = defaultRenderEventLinkContent,
484
+ renderPermissionIcon = defaultRenderPermissionIcon,
485
+ renderPermissionOptionContent = defaultRenderPermissionOptionContent
486
+ }) => {
487
+ const resolvedClassNames = useMemo(() => mergeClassNames(DEFAULT_CLASS_NAMES, classNameOverrides), [classNameOverrides]);
488
+ const groupedEntries = useMemo(() => buildGroupedEntries(entries, isDividerEntry), [entries, isDividerEntry]);
489
+ const [expandedToolGroups, setExpandedToolGroups] = useState({});
490
+ const [expandedToolItems, setExpandedToolItems] = useState({});
491
+ const lastScrollTargetRef = useRef2(null);
492
+ const isVirtualized = virtualize && Boolean(scrollRef);
493
+ const { virtualizer, isFollowingRef } = useTranscriptVirtualizer(groupedEntries, isVirtualized ? scrollRef : void 0, onAtBottomChange);
494
+ useEffect2(() => {
495
+ if (!scrollToEntryId) {
496
+ lastScrollTargetRef.current = null;
497
+ return;
498
+ }
499
+ if (!isVirtualized || scrollToEntryId === lastScrollTargetRef.current) {
500
+ return;
501
+ }
502
+ const targetIndex = groupedEntries.findIndex((group) => group.entries.some((entry) => entry.id === scrollToEntryId));
503
+ if (targetIndex < 0) {
504
+ return;
505
+ }
506
+ lastScrollTargetRef.current = scrollToEntryId;
507
+ const frameId = requestAnimationFrame(() => {
508
+ virtualizer.scrollToIndex(targetIndex, {
509
+ align: "center",
510
+ behavior: "smooth"
511
+ });
512
+ });
513
+ return () => {
514
+ cancelAnimationFrame(frameId);
515
+ };
516
+ }, [groupedEntries, isVirtualized, scrollToEntryId, virtualizer]);
517
+ useEffect2(() => {
518
+ if (!isVirtualized || !scrollRef?.current || !isFollowingRef.current) {
519
+ return;
520
+ }
521
+ const scrollElement = scrollRef.current;
522
+ const frameId = requestAnimationFrame(() => {
523
+ scrollElement.scrollTo({ top: scrollElement.scrollHeight });
524
+ });
525
+ return () => {
526
+ cancelAnimationFrame(frameId);
527
+ };
528
+ }, [eventError, isFollowingRef, isThinking, isVirtualized, scrollRef, sessionError]);
529
+ const setToolGroupExpanded = (groupKey, expanded) => {
530
+ setExpandedToolGroups((current) => {
531
+ if (current[groupKey] === expanded) {
532
+ return current;
533
+ }
534
+ return { ...current, [groupKey]: expanded };
535
+ });
536
+ };
537
+ const setToolItemExpanded = (entryId, expanded) => {
538
+ setExpandedToolItems((current) => {
539
+ if (current[entryId] === expanded) {
540
+ return current;
541
+ }
542
+ return { ...current, [entryId]: expanded };
543
+ });
544
+ };
545
+ const renderGroup = (group, index) => {
546
+ if (group.type === "divider") {
547
+ const entry2 = group.entries[0];
548
+ const title = entry2.meta?.title ?? "Status";
549
+ return /* @__PURE__ */ jsxs("div", { className: resolvedClassNames.divider, "data-slot": "divider", children: [
550
+ /* @__PURE__ */ jsx("div", { className: resolvedClassNames.dividerLine, "data-slot": "divider-line" }),
551
+ /* @__PURE__ */ jsx("span", { className: resolvedClassNames.dividerText, "data-slot": "divider-text", children: title }),
552
+ /* @__PURE__ */ jsx("div", { className: resolvedClassNames.dividerLine, "data-slot": "divider-line" })
553
+ ] }, entry2.id);
554
+ }
555
+ if (group.type === "tool-group") {
556
+ const groupKey = getGroupedEntryKey(group, index);
557
+ return /* @__PURE__ */ jsx(
558
+ ToolGroup,
559
+ {
560
+ entries: group.entries,
561
+ expanded: Boolean(expandedToolGroups[groupKey]),
562
+ onExpandedChange: (expanded) => setToolGroupExpanded(groupKey, expanded),
563
+ expandedItemIds: expandedToolItems,
564
+ onToolItemExpandedChange: setToolItemExpanded,
565
+ classNames: resolvedClassNames,
566
+ onEventClick,
567
+ canOpenEvent,
568
+ getToolGroupSummary,
569
+ renderInlinePendingIndicator,
570
+ renderToolItemIcon,
571
+ renderToolGroupIcon,
572
+ renderChevron,
573
+ renderEventLinkContent
574
+ },
575
+ groupKey
576
+ );
577
+ }
578
+ if (group.type === "permission") {
579
+ const entry2 = group.entries[0];
580
+ return /* @__PURE__ */ jsx(
581
+ PermissionPrompt,
582
+ {
583
+ entry: entry2,
584
+ classNames: resolvedClassNames,
585
+ onPermissionReply,
586
+ renderPermissionIcon,
587
+ renderPermissionOptionContent
588
+ },
589
+ entry2.id
590
+ );
591
+ }
592
+ const entry = group.entries[0];
593
+ const messageVariant = getMessageVariant(entry);
594
+ return /* @__PURE__ */ jsx(
595
+ "div",
596
+ {
597
+ className: cx(resolvedClassNames.message, messageVariant, "no-avatar"),
598
+ "data-slot": "message",
599
+ "data-kind": entry.kind,
600
+ "data-role": entry.role,
601
+ "data-variant": messageVariant,
602
+ "data-severity": entry.meta?.severity,
603
+ children: /* @__PURE__ */ jsx("div", { className: resolvedClassNames.messageContent, "data-slot": "message-content", children: entry.text ? /* @__PURE__ */ jsx("div", { className: resolvedClassNames.messageText, "data-slot": "message-text", children: renderMessageText(entry) }) : /* @__PURE__ */ jsx("span", { className: resolvedClassNames.thinkingIndicator, "data-slot": "thinking-indicator", children: renderInlinePendingIndicator() }) })
604
+ },
605
+ entry.id
606
+ );
607
+ };
608
+ return /* @__PURE__ */ jsxs("div", { className: cx(resolvedClassNames.root, className), "data-slot": "root", "data-virtualized": isVirtualized ? "true" : void 0, children: [
609
+ isVirtualized ? /* @__PURE__ */ jsx(
610
+ "div",
611
+ {
612
+ "data-slot": "virtual-list",
613
+ style: {
614
+ height: `${virtualizer.getTotalSize()}px`,
615
+ position: "relative",
616
+ width: "100%"
617
+ },
618
+ children: virtualizer.getVirtualItems().map((virtualItem) => {
619
+ const group = groupedEntries[virtualItem.index];
620
+ if (!group) {
621
+ return null;
622
+ }
623
+ return /* @__PURE__ */ jsx(
624
+ "div",
625
+ {
626
+ "data-index": virtualItem.index,
627
+ ref: (node) => {
628
+ if (node) {
629
+ virtualizer.measureElement(node);
630
+ }
631
+ },
632
+ style: {
633
+ left: 0,
634
+ position: "absolute",
635
+ top: 0,
636
+ transform: `translateY(${virtualItem.start}px)`,
637
+ width: "100%"
638
+ },
639
+ children: /* @__PURE__ */ jsx("div", { style: { paddingBottom: virtualItem.index === groupedEntries.length - 1 ? 0 : `${VIRTUAL_GROUP_GAP_PX}px` }, children: renderGroup(group, virtualItem.index) })
640
+ },
641
+ getGroupedEntryKey(group, virtualItem.index)
642
+ );
643
+ })
644
+ }
645
+ ) : groupedEntries.map((group, index) => renderGroup(group, index)),
646
+ sessionError ? /* @__PURE__ */ jsx("div", { className: resolvedClassNames.error, "data-slot": "error", "data-source": "session", children: sessionError }) : null,
647
+ eventError ? /* @__PURE__ */ jsx("div", { className: resolvedClassNames.error, "data-slot": "error", "data-source": "event", children: eventError }) : null,
648
+ isThinking ? renderThinkingState?.({ agentId }) ?? /* @__PURE__ */ jsx("div", { className: resolvedClassNames.thinkingRow, "data-slot": "thinking-row", children: /* @__PURE__ */ jsx("span", { className: resolvedClassNames.thinkingIndicator, "data-slot": "thinking-indicator", children: "Thinking..." }) }) : null,
649
+ !isVirtualized ? /* @__PURE__ */ jsx("div", { ref: endRef, className: resolvedClassNames.endAnchor, "data-slot": "end-anchor" }) : null
650
+ ] });
651
+ };
652
+
653
+ // src/ChatComposer.tsx
654
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
655
+ var DEFAULT_CLASS_NAMES2 = {
656
+ root: "sa-chat-composer",
657
+ form: "sa-chat-composer-form",
658
+ input: "sa-chat-composer-input",
659
+ submit: "sa-chat-composer-submit",
660
+ submitContent: "sa-chat-composer-submit-content"
661
+ };
662
+ var cx2 = (...values) => values.filter(Boolean).join(" ");
663
+ var mergeClassNames2 = (defaults, overrides) => ({
664
+ root: cx2(defaults.root, overrides?.root),
665
+ form: cx2(defaults.form, overrides?.form),
666
+ input: cx2(defaults.input, overrides?.input),
667
+ submit: cx2(defaults.submit, overrides?.submit),
668
+ submitContent: cx2(defaults.submitContent, overrides?.submitContent)
669
+ });
670
+ var ChatComposer = ({
671
+ message,
672
+ onMessageChange,
673
+ onSubmit,
674
+ onKeyDown,
675
+ placeholder,
676
+ disabled = false,
677
+ submitDisabled = false,
678
+ allowEmptySubmit = false,
679
+ submitLabel = "Send",
680
+ className,
681
+ classNames: classNameOverrides,
682
+ inputRef,
683
+ rows = 1,
684
+ textareaProps,
685
+ renderSubmitContent,
686
+ renderFooter
687
+ }) => {
688
+ const resolvedClassNames = mergeClassNames2(DEFAULT_CLASS_NAMES2, classNameOverrides);
689
+ const isSubmitDisabled = disabled || submitDisabled || !allowEmptySubmit && message.trim().length === 0;
690
+ return /* @__PURE__ */ jsx2("div", { className: cx2(resolvedClassNames.root, className), "data-slot": "root", children: /* @__PURE__ */ jsxs2(
691
+ "form",
692
+ {
693
+ className: resolvedClassNames.form,
694
+ "data-slot": "form",
695
+ onSubmit: (event) => {
696
+ event.preventDefault();
697
+ if (!isSubmitDisabled) {
698
+ onSubmit();
699
+ }
700
+ },
701
+ children: [
702
+ /* @__PURE__ */ jsx2(
703
+ "textarea",
704
+ {
705
+ ...textareaProps,
706
+ ref: inputRef,
707
+ className: resolvedClassNames.input,
708
+ "data-slot": "input",
709
+ "data-disabled": disabled ? "true" : void 0,
710
+ "data-empty": message.trim().length === 0 ? "true" : void 0,
711
+ value: message,
712
+ onChange: (event) => onMessageChange(event.target.value),
713
+ onKeyDown,
714
+ placeholder,
715
+ rows,
716
+ disabled
717
+ }
718
+ ),
719
+ renderFooter?.(),
720
+ /* @__PURE__ */ jsx2(
721
+ "button",
722
+ {
723
+ type: "submit",
724
+ className: resolvedClassNames.submit,
725
+ "data-slot": "submit",
726
+ "data-disabled": isSubmitDisabled ? "true" : void 0,
727
+ disabled: isSubmitDisabled,
728
+ "aria-label": submitLabel,
729
+ title: submitLabel,
730
+ children: /* @__PURE__ */ jsx2("span", { className: resolvedClassNames.submitContent, "data-slot": "submit-content", children: renderSubmitContent?.() ?? submitLabel })
731
+ }
732
+ )
733
+ ]
734
+ }
735
+ ) });
736
+ };
737
+
738
+ // src/AgentConversation.tsx
739
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
740
+ var DEFAULT_CLASS_NAMES3 = {
741
+ root: "sa-agent-conversation",
742
+ transcript: "sa-agent-conversation-transcript",
743
+ emptyState: "sa-agent-conversation-empty-state",
744
+ composer: "sa-agent-conversation-composer"
745
+ };
746
+ var cx3 = (...values) => values.filter(Boolean).join(" ");
747
+ var mergeClassNames3 = (defaults, overrides) => ({
748
+ root: cx3(defaults.root, overrides?.root),
749
+ transcript: cx3(defaults.transcript, overrides?.transcript),
750
+ emptyState: cx3(defaults.emptyState, overrides?.emptyState),
751
+ composer: cx3(defaults.composer, overrides?.composer)
752
+ });
753
+ var AgentConversation = ({
754
+ entries,
755
+ className,
756
+ classNames: classNameOverrides,
757
+ emptyState,
758
+ transcriptClassName,
759
+ transcriptClassNames,
760
+ scrollRef,
761
+ composerClassName,
762
+ composerClassNames,
763
+ transcriptProps,
764
+ composerProps
765
+ }) => {
766
+ const resolvedClassNames = mergeClassNames3(DEFAULT_CLASS_NAMES3, classNameOverrides);
767
+ const hasTranscriptContent = entries.length > 0 || Boolean(transcriptProps?.sessionError) || Boolean(transcriptProps?.eventError);
768
+ return /* @__PURE__ */ jsxs3("div", { className: cx3(resolvedClassNames.root, className), "data-slot": "root", children: [
769
+ hasTranscriptContent ? scrollRef ? /* @__PURE__ */ jsx3("div", { className: cx3(resolvedClassNames.transcript, transcriptClassName), "data-slot": "transcript", ref: scrollRef, children: /* @__PURE__ */ jsx3(AgentTranscript, { entries, classNames: transcriptClassNames, ...transcriptProps }) }) : /* @__PURE__ */ jsx3(
770
+ AgentTranscript,
771
+ {
772
+ entries,
773
+ className: cx3(resolvedClassNames.transcript, transcriptClassName),
774
+ classNames: transcriptClassNames,
775
+ ...transcriptProps
776
+ }
777
+ ) : emptyState ? /* @__PURE__ */ jsx3("div", { className: resolvedClassNames.emptyState, "data-slot": "empty-state", children: emptyState }) : null,
778
+ composerProps ? /* @__PURE__ */ jsx3(ChatComposer, { className: cx3(resolvedClassNames.composer, composerClassName), classNames: composerClassNames, ...composerProps }) : null
779
+ ] });
780
+ };
781
+
782
+ // src/ProcessTerminal.tsx
783
+ import { useEffect as useEffect3, useRef as useRef3, useState as useState2 } from "react";
784
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
4
785
  var terminalTheme = {
5
786
  background: "#09090b",
6
787
  foreground: "#f4f4f5",
@@ -71,15 +852,17 @@ var ProcessTerminal = ({
71
852
  className,
72
853
  style,
73
854
  terminalStyle,
855
+ statusBarStyleOverride,
74
856
  height = 360,
857
+ showStatusBar = true,
75
858
  onExit,
76
859
  onError
77
860
  }) => {
78
- const hostRef = useRef(null);
79
- const [connectionState, setConnectionState] = useState("connecting");
80
- const [statusMessage, setStatusMessage] = useState("Connecting to PTY...");
81
- const [exitCode, setExitCode] = useState(null);
82
- useEffect(() => {
861
+ const hostRef = useRef3(null);
862
+ const [connectionState, setConnectionState] = useState2("connecting");
863
+ const [statusMessage, setStatusMessage] = useState2("Connecting to PTY...");
864
+ const [exitCode, setExitCode] = useState2(null);
865
+ useEffect3(() => {
83
866
  let cancelled = false;
84
867
  let terminal = null;
85
868
  let fitAddon = null;
@@ -157,9 +940,7 @@ var ProcessTerminal = ({
157
940
  }
158
941
  setConnectionState("closed");
159
942
  setExitCode(frame.exitCode ?? null);
160
- setStatusMessage(
161
- frame.exitCode == null ? "Process exited." : `Process exited with code ${frame.exitCode}.`
162
- );
943
+ setStatusMessage(frame.exitCode == null ? "Process exited." : `Process exited with code ${frame.exitCode}.`);
163
944
  onExit?.(frame);
164
945
  });
165
946
  nextSession.onError((error) => {
@@ -199,15 +980,15 @@ var ProcessTerminal = ({
199
980
  terminal?.dispose();
200
981
  };
201
982
  }, [client, onError, onExit, processId]);
202
- return /* @__PURE__ */ jsxs("div", { className, style: { ...shellStyle, ...style }, children: [
203
- /* @__PURE__ */ jsxs("div", { style: statusBarStyle, children: [
204
- /* @__PURE__ */ jsx("span", { style: { color: getStatusColor(connectionState) }, children: statusMessage }),
205
- exitCode != null ? /* @__PURE__ */ jsxs("span", { style: exitCodeStyle, children: [
983
+ return /* @__PURE__ */ jsxs4("div", { className, style: { ...shellStyle, ...style }, children: [
984
+ showStatusBar ? /* @__PURE__ */ jsxs4("div", { style: { ...statusBarStyle, ...statusBarStyleOverride }, children: [
985
+ /* @__PURE__ */ jsx4("span", { style: { color: getStatusColor(connectionState) }, children: statusMessage }),
986
+ exitCode != null ? /* @__PURE__ */ jsxs4("span", { style: exitCodeStyle, children: [
206
987
  "exit=",
207
988
  exitCode
208
989
  ] }) : null
209
- ] }),
210
- /* @__PURE__ */ jsx(
990
+ ] }) : null,
991
+ /* @__PURE__ */ jsx4(
211
992
  "div",
212
993
  {
213
994
  ref: hostRef,
@@ -225,6 +1006,10 @@ var ProcessTerminal = ({
225
1006
  ] });
226
1007
  };
227
1008
  export {
228
- ProcessTerminal
1009
+ AgentConversation,
1010
+ AgentTranscript,
1011
+ ChatComposer,
1012
+ ProcessTerminal,
1013
+ useTranscriptVirtualizer
229
1014
  };
230
1015
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ProcessTerminal.tsx"],"sourcesContent":["\"use client\";\n\nimport type { FitAddon as GhosttyFitAddon, Terminal as GhosttyTerminal } from \"ghostty-web\";\nimport type { CSSProperties } from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport type { SandboxAgent, TerminalErrorStatus, TerminalExitStatus } from \"sandbox-agent\";\n\ntype ConnectionState = \"connecting\" | \"ready\" | \"closed\" | \"error\";\n\nexport type ProcessTerminalClient = Pick<SandboxAgent, \"connectProcessTerminal\">;\n\nexport interface ProcessTerminalProps {\n client: ProcessTerminalClient;\n processId: string;\n className?: string;\n style?: CSSProperties;\n terminalStyle?: CSSProperties;\n height?: number | string;\n onExit?: (status: TerminalExitStatus) => void;\n onError?: (error: TerminalErrorStatus | Error) => void;\n}\n\nconst terminalTheme = {\n background: \"#09090b\",\n foreground: \"#f4f4f5\",\n cursor: \"#f97316\",\n cursorAccent: \"#09090b\",\n selectionBackground: \"#27272a\",\n black: \"#18181b\",\n red: \"#f87171\",\n green: \"#4ade80\",\n yellow: \"#fbbf24\",\n blue: \"#60a5fa\",\n magenta: \"#f472b6\",\n cyan: \"#22d3ee\",\n white: \"#e4e4e7\",\n brightBlack: \"#3f3f46\",\n brightRed: \"#fb7185\",\n brightGreen: \"#86efac\",\n brightYellow: \"#fde047\",\n brightBlue: \"#93c5fd\",\n brightMagenta: \"#f9a8d4\",\n brightCyan: \"#67e8f9\",\n brightWhite: \"#fafafa\",\n};\n\nconst shellStyle: CSSProperties = {\n display: \"flex\",\n flexDirection: \"column\",\n overflow: \"hidden\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n borderRadius: 10,\n background: \"rgba(0, 0, 0, 0.3)\",\n};\n\nconst statusBarStyle: CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 12,\n padding: \"8px 12px\",\n borderBottom: \"1px solid rgba(255, 255, 255, 0.08)\",\n background: \"rgba(0, 0, 0, 0.2)\",\n color: \"rgba(244, 244, 245, 0.86)\",\n fontSize: 11,\n lineHeight: 1.4,\n};\n\nconst hostBaseStyle: CSSProperties = {\n minHeight: 320,\n padding: 10,\n overflow: \"hidden\",\n};\n\nconst exitCodeStyle: CSSProperties = {\n fontFamily: \"ui-monospace, SFMono-Regular, SF Mono, Menlo, monospace\",\n opacity: 0.72,\n};\n\nconst getStatusColor = (state: ConnectionState): string => {\n switch (state) {\n case \"ready\":\n return \"#4ade80\";\n case \"error\":\n return \"#fb7185\";\n case \"closed\":\n return \"#fbbf24\";\n default:\n return \"rgba(244, 244, 245, 0.72)\";\n }\n};\n\nexport const ProcessTerminal = ({\n client,\n processId,\n className,\n style,\n terminalStyle,\n height = 360,\n onExit,\n onError,\n}: ProcessTerminalProps) => {\n const hostRef = useRef<HTMLDivElement | null>(null);\n const [connectionState, setConnectionState] = useState<ConnectionState>(\"connecting\");\n const [statusMessage, setStatusMessage] = useState(\"Connecting to PTY...\");\n const [exitCode, setExitCode] = useState<number | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n let terminal: GhosttyTerminal | null = null;\n let fitAddon: GhosttyFitAddon | null = null;\n let session: ReturnType<ProcessTerminalClient[\"connectProcessTerminal\"]> | null = null;\n let resizeRaf = 0;\n let removeDataListener: { dispose(): void } | null = null;\n let removeResizeListener: { dispose(): void } | null = null;\n\n setConnectionState(\"connecting\");\n setStatusMessage(\"Connecting to PTY...\");\n setExitCode(null);\n\n const syncSize = () => {\n if (!terminal || !session) {\n return;\n }\n\n session.resize({\n cols: terminal.cols,\n rows: terminal.rows,\n });\n };\n\n const connect = async () => {\n try {\n const ghostty = await import(\"ghostty-web\");\n await ghostty.init();\n\n if (cancelled || !hostRef.current) {\n return;\n }\n\n terminal = new ghostty.Terminal({\n allowTransparency: true,\n cursorBlink: true,\n cursorStyle: \"block\",\n fontFamily: \"ui-monospace, SFMono-Regular, SF Mono, Menlo, monospace\",\n fontSize: 13,\n smoothScrollDuration: 90,\n theme: terminalTheme,\n });\n fitAddon = new ghostty.FitAddon();\n\n terminal.open(hostRef.current);\n const terminalRoot = hostRef.current.firstElementChild;\n if (terminalRoot instanceof HTMLElement) {\n terminalRoot.style.width = \"100%\";\n terminalRoot.style.height = \"100%\";\n }\n terminal.loadAddon(fitAddon);\n fitAddon.fit();\n fitAddon.observeResize();\n terminal.focus();\n\n removeDataListener = terminal.onData((data) => {\n session?.sendInput(data);\n });\n\n removeResizeListener = terminal.onResize(() => {\n if (resizeRaf) {\n window.cancelAnimationFrame(resizeRaf);\n }\n resizeRaf = window.requestAnimationFrame(syncSize);\n });\n\n const nextSession = client.connectProcessTerminal(processId);\n session = nextSession;\n\n nextSession.onReady((frame) => {\n if (cancelled || frame.type !== \"ready\") {\n return;\n }\n\n setConnectionState(\"ready\");\n setStatusMessage(\"Connected\");\n syncSize();\n });\n\n nextSession.onData((bytes) => {\n if (cancelled || !terminal) {\n return;\n }\n terminal.write(bytes);\n });\n\n nextSession.onExit((frame) => {\n if (cancelled || frame.type !== \"exit\") {\n return;\n }\n\n setConnectionState(\"closed\");\n setExitCode(frame.exitCode ?? null);\n setStatusMessage(\n frame.exitCode == null ? \"Process exited.\" : `Process exited with code ${frame.exitCode}.`\n );\n onExit?.(frame);\n });\n\n nextSession.onError((error) => {\n if (cancelled) {\n return;\n }\n\n setConnectionState(\"error\");\n setStatusMessage(error instanceof Error ? error.message : error.message);\n onError?.(error);\n });\n\n nextSession.onClose(() => {\n if (cancelled) {\n return;\n }\n\n setConnectionState((current) => (current === \"error\" ? current : \"closed\"));\n setStatusMessage((current) => (current === \"Connected\" ? \"Terminal disconnected.\" : current));\n });\n } catch (error) {\n if (cancelled) {\n return;\n }\n\n const nextError = error instanceof Error ? error : new Error(\"Failed to initialize terminal.\");\n setConnectionState(\"error\");\n setStatusMessage(nextError.message);\n onError?.(nextError);\n }\n };\n\n void connect();\n\n return () => {\n cancelled = true;\n if (resizeRaf) {\n window.cancelAnimationFrame(resizeRaf);\n }\n removeDataListener?.dispose();\n removeResizeListener?.dispose();\n session?.close();\n terminal?.dispose();\n };\n }, [client, onError, onExit, processId]);\n\n return (\n <div className={className} style={{ ...shellStyle, ...style }}>\n <div style={statusBarStyle}>\n <span style={{ color: getStatusColor(connectionState) }}>{statusMessage}</span>\n {exitCode != null ? <span style={exitCodeStyle}>exit={exitCode}</span> : null}\n </div>\n <div\n ref={hostRef}\n role=\"presentation\"\n style={{\n ...hostBaseStyle,\n height,\n ...terminalStyle,\n }}\n onClick={() => {\n hostRef.current?.querySelector(\"textarea\")?.focus();\n }}\n />\n </div>\n );\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/AgentTranscript.tsx","../src/useTranscriptVirtualizer.ts","../src/ChatComposer.tsx","../src/AgentConversation.tsx","../src/ProcessTerminal.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ReactNode, RefObject } from \"react\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useTranscriptVirtualizer } from \"./useTranscriptVirtualizer.ts\";\n\nexport type PermissionReply = \"once\" | \"always\" | \"reject\";\n\nexport type PermissionOption = {\n optionId: string;\n name: string;\n kind: string;\n};\n\nexport type TranscriptEntry = {\n id: string;\n eventId?: string;\n kind: \"message\" | \"tool\" | \"meta\" | \"reasoning\" | \"permission\";\n time: string;\n role?: \"user\" | \"assistant\";\n text?: string;\n toolName?: string;\n toolInput?: string;\n toolOutput?: string;\n toolStatus?: string;\n reasoning?: { text: string; visibility?: string };\n meta?: { title: string; detail?: string; severity?: \"info\" | \"error\" };\n permission?: {\n permissionId: string;\n title: string;\n description?: string;\n options: PermissionOption[];\n resolved?: boolean;\n selectedOptionId?: string;\n };\n};\n\nexport interface AgentTranscriptClassNames {\n root: string;\n divider: string;\n dividerLine: string;\n dividerText: string;\n message: string;\n messageContent: string;\n messageText: string;\n error: string;\n toolGroupSingle: string;\n toolGroupContainer: string;\n toolGroupHeader: string;\n toolGroupIcon: string;\n toolGroupLabel: string;\n toolGroupChevron: string;\n toolGroupBody: string;\n toolItem: string;\n toolItemConnector: string;\n toolItemDot: string;\n toolItemLine: string;\n toolItemContent: string;\n toolItemHeader: string;\n toolItemIcon: string;\n toolItemLabel: string;\n toolItemSpinner: string;\n toolItemLink: string;\n toolItemChevron: string;\n toolItemBody: string;\n toolSection: string;\n toolSectionTitle: string;\n toolCode: string;\n toolCodeMuted: string;\n permissionPrompt: string;\n permissionHeader: string;\n permissionIcon: string;\n permissionTitle: string;\n permissionDescription: string;\n permissionActions: string;\n permissionButton: string;\n permissionAutoResolved: string;\n thinkingRow: string;\n thinkingAvatar: string;\n thinkingAvatarImage: string;\n thinkingAvatarLabel: string;\n thinkingIndicator: string;\n thinkingDot: string;\n endAnchor: string;\n}\n\nexport interface PermissionOptionRenderContext {\n entry: TranscriptEntry;\n option: PermissionOption;\n label: string;\n reply: PermissionReply;\n selected: boolean;\n dimmed: boolean;\n resolved: boolean;\n}\n\nexport interface AgentTranscriptProps {\n entries: TranscriptEntry[];\n className?: string;\n classNames?: Partial<AgentTranscriptClassNames>;\n endRef?: RefObject<HTMLDivElement>;\n scrollRef?: RefObject<HTMLDivElement>;\n scrollToEntryId?: string | null;\n sessionError?: string | null;\n eventError?: string | null;\n isThinking?: boolean;\n agentId?: string;\n virtualize?: boolean;\n onAtBottomChange?: (atBottom: boolean) => void;\n onEventClick?: (eventId: string) => void;\n onPermissionReply?: (permissionId: string, reply: PermissionReply) => void;\n isDividerEntry?: (entry: TranscriptEntry) => boolean;\n canOpenEvent?: (entry: TranscriptEntry) => boolean;\n getToolGroupSummary?: (entries: TranscriptEntry[]) => string;\n renderMessageText?: (entry: TranscriptEntry) => ReactNode;\n renderInlinePendingIndicator?: () => ReactNode;\n renderThinkingState?: (context: { agentId?: string }) => ReactNode;\n renderToolItemIcon?: (entry: TranscriptEntry) => ReactNode;\n renderToolGroupIcon?: (entries: TranscriptEntry[], expanded: boolean) => ReactNode;\n renderChevron?: (expanded: boolean) => ReactNode;\n renderEventLinkContent?: (entry: TranscriptEntry) => ReactNode;\n renderPermissionIcon?: (entry: TranscriptEntry) => ReactNode;\n renderPermissionOptionContent?: (context: PermissionOptionRenderContext) => ReactNode;\n}\n\ntype GroupedEntries =\n | { type: \"message\"; entries: TranscriptEntry[] }\n | { type: \"tool-group\"; entries: TranscriptEntry[] }\n | { type: \"divider\"; entries: TranscriptEntry[] }\n | { type: \"permission\"; entries: TranscriptEntry[] };\n\nconst VIRTUAL_GROUP_GAP_PX = 12;\n\nconst DEFAULT_CLASS_NAMES: AgentTranscriptClassNames = {\n root: \"sa-agent-transcript\",\n divider: \"sa-agent-transcript-divider\",\n dividerLine: \"sa-agent-transcript-divider-line\",\n dividerText: \"sa-agent-transcript-divider-text\",\n message: \"sa-agent-transcript-message\",\n messageContent: \"sa-agent-transcript-message-content\",\n messageText: \"sa-agent-transcript-message-text\",\n error: \"sa-agent-transcript-error\",\n toolGroupSingle: \"sa-agent-transcript-tool-group-single\",\n toolGroupContainer: \"sa-agent-transcript-tool-group\",\n toolGroupHeader: \"sa-agent-transcript-tool-group-header\",\n toolGroupIcon: \"sa-agent-transcript-tool-group-icon\",\n toolGroupLabel: \"sa-agent-transcript-tool-group-label\",\n toolGroupChevron: \"sa-agent-transcript-tool-group-chevron\",\n toolGroupBody: \"sa-agent-transcript-tool-group-body\",\n toolItem: \"sa-agent-transcript-tool-item\",\n toolItemConnector: \"sa-agent-transcript-tool-item-connector\",\n toolItemDot: \"sa-agent-transcript-tool-item-dot\",\n toolItemLine: \"sa-agent-transcript-tool-item-line\",\n toolItemContent: \"sa-agent-transcript-tool-item-content\",\n toolItemHeader: \"sa-agent-transcript-tool-item-header\",\n toolItemIcon: \"sa-agent-transcript-tool-item-icon\",\n toolItemLabel: \"sa-agent-transcript-tool-item-label\",\n toolItemSpinner: \"sa-agent-transcript-tool-item-spinner\",\n toolItemLink: \"sa-agent-transcript-tool-item-link\",\n toolItemChevron: \"sa-agent-transcript-tool-item-chevron\",\n toolItemBody: \"sa-agent-transcript-tool-item-body\",\n toolSection: \"sa-agent-transcript-tool-section\",\n toolSectionTitle: \"sa-agent-transcript-tool-section-title\",\n toolCode: \"sa-agent-transcript-tool-code\",\n toolCodeMuted: \"sa-agent-transcript-tool-code-muted\",\n permissionPrompt: \"sa-agent-transcript-permission-prompt\",\n permissionHeader: \"sa-agent-transcript-permission-header\",\n permissionIcon: \"sa-agent-transcript-permission-icon\",\n permissionTitle: \"sa-agent-transcript-permission-title\",\n permissionDescription: \"sa-agent-transcript-permission-description\",\n permissionActions: \"sa-agent-transcript-permission-actions\",\n permissionButton: \"sa-agent-transcript-permission-button\",\n permissionAutoResolved: \"sa-agent-transcript-permission-auto-resolved\",\n thinkingRow: \"sa-agent-transcript-thinking-row\",\n thinkingAvatar: \"sa-agent-transcript-thinking-avatar\",\n thinkingAvatarImage: \"sa-agent-transcript-thinking-avatar-image\",\n thinkingAvatarLabel: \"sa-agent-transcript-thinking-avatar-label\",\n thinkingIndicator: \"sa-agent-transcript-thinking-indicator\",\n thinkingDot: \"sa-agent-transcript-thinking-dot\",\n endAnchor: \"sa-agent-transcript-end\",\n};\n\nconst DEFAULT_DIVIDER_TITLES = new Set([\"Session Started\", \"Turn Started\", \"Turn Ended\"]);\n\nconst cx = (...values: Array<string | false | null | undefined>) => values.filter(Boolean).join(\" \");\n\nconst mergeClassNames = (defaults: AgentTranscriptClassNames, overrides?: Partial<AgentTranscriptClassNames>): AgentTranscriptClassNames => ({\n root: cx(defaults.root, overrides?.root),\n divider: cx(defaults.divider, overrides?.divider),\n dividerLine: cx(defaults.dividerLine, overrides?.dividerLine),\n dividerText: cx(defaults.dividerText, overrides?.dividerText),\n message: cx(defaults.message, overrides?.message),\n messageContent: cx(defaults.messageContent, overrides?.messageContent),\n messageText: cx(defaults.messageText, overrides?.messageText),\n error: cx(defaults.error, overrides?.error),\n toolGroupSingle: cx(defaults.toolGroupSingle, overrides?.toolGroupSingle),\n toolGroupContainer: cx(defaults.toolGroupContainer, overrides?.toolGroupContainer),\n toolGroupHeader: cx(defaults.toolGroupHeader, overrides?.toolGroupHeader),\n toolGroupIcon: cx(defaults.toolGroupIcon, overrides?.toolGroupIcon),\n toolGroupLabel: cx(defaults.toolGroupLabel, overrides?.toolGroupLabel),\n toolGroupChevron: cx(defaults.toolGroupChevron, overrides?.toolGroupChevron),\n toolGroupBody: cx(defaults.toolGroupBody, overrides?.toolGroupBody),\n toolItem: cx(defaults.toolItem, overrides?.toolItem),\n toolItemConnector: cx(defaults.toolItemConnector, overrides?.toolItemConnector),\n toolItemDot: cx(defaults.toolItemDot, overrides?.toolItemDot),\n toolItemLine: cx(defaults.toolItemLine, overrides?.toolItemLine),\n toolItemContent: cx(defaults.toolItemContent, overrides?.toolItemContent),\n toolItemHeader: cx(defaults.toolItemHeader, overrides?.toolItemHeader),\n toolItemIcon: cx(defaults.toolItemIcon, overrides?.toolItemIcon),\n toolItemLabel: cx(defaults.toolItemLabel, overrides?.toolItemLabel),\n toolItemSpinner: cx(defaults.toolItemSpinner, overrides?.toolItemSpinner),\n toolItemLink: cx(defaults.toolItemLink, overrides?.toolItemLink),\n toolItemChevron: cx(defaults.toolItemChevron, overrides?.toolItemChevron),\n toolItemBody: cx(defaults.toolItemBody, overrides?.toolItemBody),\n toolSection: cx(defaults.toolSection, overrides?.toolSection),\n toolSectionTitle: cx(defaults.toolSectionTitle, overrides?.toolSectionTitle),\n toolCode: cx(defaults.toolCode, overrides?.toolCode),\n toolCodeMuted: cx(defaults.toolCodeMuted, overrides?.toolCodeMuted),\n permissionPrompt: cx(defaults.permissionPrompt, overrides?.permissionPrompt),\n permissionHeader: cx(defaults.permissionHeader, overrides?.permissionHeader),\n permissionIcon: cx(defaults.permissionIcon, overrides?.permissionIcon),\n permissionTitle: cx(defaults.permissionTitle, overrides?.permissionTitle),\n permissionDescription: cx(defaults.permissionDescription, overrides?.permissionDescription),\n permissionActions: cx(defaults.permissionActions, overrides?.permissionActions),\n permissionButton: cx(defaults.permissionButton, overrides?.permissionButton),\n permissionAutoResolved: cx(defaults.permissionAutoResolved, overrides?.permissionAutoResolved),\n thinkingRow: cx(defaults.thinkingRow, overrides?.thinkingRow),\n thinkingAvatar: cx(defaults.thinkingAvatar, overrides?.thinkingAvatar),\n thinkingAvatarImage: cx(defaults.thinkingAvatarImage, overrides?.thinkingAvatarImage),\n thinkingAvatarLabel: cx(defaults.thinkingAvatarLabel, overrides?.thinkingAvatarLabel),\n thinkingIndicator: cx(defaults.thinkingIndicator, overrides?.thinkingIndicator),\n thinkingDot: cx(defaults.thinkingDot, overrides?.thinkingDot),\n endAnchor: cx(defaults.endAnchor, overrides?.endAnchor),\n});\n\nconst getMessageVariant = (entry: TranscriptEntry) => {\n if (entry.kind === \"tool\") return \"tool\";\n if (entry.kind === \"meta\") return entry.meta?.severity === \"error\" ? \"error\" : \"system\";\n if (entry.kind === \"reasoning\") return \"assistant\";\n if (entry.kind === \"permission\") return \"system\";\n if (entry.role === \"user\") return \"user\";\n return \"assistant\";\n};\n\nconst getToolItemLabel = (entry: TranscriptEntry) => {\n if (entry.kind === \"tool\") {\n const statusLabel = entry.toolStatus && entry.toolStatus !== \"completed\" ? ` (${entry.toolStatus.replaceAll(\"_\", \" \")})` : \"\";\n return `${entry.toolName ?? \"tool\"}${statusLabel}`;\n }\n\n if (entry.kind === \"reasoning\") {\n return `Reasoning${entry.reasoning?.visibility ? ` (${entry.reasoning.visibility})` : \"\"}`;\n }\n\n return entry.meta?.title ?? \"Status\";\n};\n\nconst getDefaultToolItemIcon = (entry: TranscriptEntry) => {\n if (entry.kind === \"tool\") return \"Tool\";\n if (entry.kind === \"reasoning\") return \"Thought\";\n return entry.meta?.severity === \"error\" ? \"Error\" : \"Info\";\n};\n\nconst getDefaultToolGroupSummary = (entries: TranscriptEntry[]) => {\n const count = entries.length;\n return `${count} Event${count === 1 ? \"\" : \"s\"}`;\n};\n\nconst getPermissionReplyForOption = (kind: string): PermissionReply => {\n if (kind === \"allow_once\") return \"once\";\n if (kind === \"allow_always\") return \"always\";\n return \"reject\";\n};\n\nconst getPermissionOptionLabel = (option: PermissionOption) => {\n if (option.name) return option.name;\n if (option.kind === \"allow_once\") return \"Allow Once\";\n if (option.kind === \"allow_always\") return \"Always Allow\";\n if (option.kind === \"reject_once\") return \"Reject\";\n if (option.kind === \"reject_always\") return \"Reject Always\";\n return option.kind;\n};\n\nconst getPermissionOptionTone = (kind: string) => (kind.startsWith(\"allow\") ? \"allow\" : \"reject\");\n\nconst defaultRenderMessageText = (entry: TranscriptEntry) => entry.text;\nconst defaultRenderPendingIndicator = () => \"...\";\nconst defaultRenderChevron = (expanded: boolean) => (expanded ? \"▾\" : \"▸\");\nconst defaultRenderEventLinkContent = () => \"Open\";\nconst defaultRenderPermissionIcon = () => \"Permission\";\nconst defaultRenderPermissionOptionContent = ({ label }: PermissionOptionRenderContext) => label;\nconst defaultIsDividerEntry = (entry: TranscriptEntry) => entry.kind === \"meta\" && DEFAULT_DIVIDER_TITLES.has(entry.meta?.title ?? \"\");\n\nconst defaultCanOpenEvent = (entry: TranscriptEntry) => Boolean(entry.eventId);\n\nconst buildGroupedEntries = (entries: TranscriptEntry[], isDividerEntry: (entry: TranscriptEntry) => boolean): GroupedEntries[] => {\n const groupedEntries: GroupedEntries[] = [];\n let currentToolGroup: TranscriptEntry[] = [];\n\n const flushToolGroup = () => {\n if (currentToolGroup.length === 0) {\n return;\n }\n groupedEntries.push({ type: \"tool-group\", entries: currentToolGroup });\n currentToolGroup = [];\n };\n\n for (const entry of entries) {\n if (isDividerEntry(entry)) {\n flushToolGroup();\n groupedEntries.push({ type: \"divider\", entries: [entry] });\n continue;\n }\n\n if (entry.kind === \"permission\") {\n flushToolGroup();\n groupedEntries.push({ type: \"permission\", entries: [entry] });\n continue;\n }\n\n if (entry.kind === \"tool\" || entry.kind === \"reasoning\" || entry.kind === \"meta\") {\n currentToolGroup.push(entry);\n continue;\n }\n\n flushToolGroup();\n groupedEntries.push({ type: \"message\", entries: [entry] });\n }\n\n flushToolGroup();\n return groupedEntries;\n};\n\nconst getGroupedEntryKey = (group: GroupedEntries, index: number): string => {\n const firstEntry = group.entries[0];\n\n if (group.type === \"tool-group\") {\n return `tool-group:${firstEntry?.id ?? index}`;\n }\n\n return firstEntry?.id ?? `${group.type}:${index}`;\n};\n\nconst ToolItem = ({\n entry,\n isLast,\n expanded,\n onExpandedChange,\n classNames,\n onEventClick,\n canOpenEvent,\n renderInlinePendingIndicator,\n renderToolItemIcon,\n renderChevron,\n renderEventLinkContent,\n}: {\n entry: TranscriptEntry;\n isLast: boolean;\n expanded: boolean;\n onExpandedChange: (expanded: boolean) => void;\n classNames: AgentTranscriptClassNames;\n onEventClick?: (eventId: string) => void;\n canOpenEvent: (entry: TranscriptEntry) => boolean;\n renderInlinePendingIndicator: () => ReactNode;\n renderToolItemIcon: (entry: TranscriptEntry) => ReactNode;\n renderChevron: (expanded: boolean) => ReactNode;\n renderEventLinkContent: (entry: TranscriptEntry) => ReactNode;\n}) => {\n const isTool = entry.kind === \"tool\";\n const isReasoning = entry.kind === \"reasoning\";\n const isMeta = entry.kind === \"meta\";\n const isComplete = isTool && (entry.toolStatus === \"completed\" || entry.toolStatus === \"failed\");\n const isFailed = isTool && entry.toolStatus === \"failed\";\n const isInProgress = isTool && entry.toolStatus === \"in_progress\";\n const hasContent = isTool\n ? Boolean(entry.toolInput || entry.toolOutput)\n : isReasoning\n ? Boolean(entry.reasoning?.text?.trim())\n : Boolean(entry.meta?.detail?.trim());\n const showEventLink = Boolean(entry.eventId && onEventClick && canOpenEvent(entry));\n\n return (\n <div\n className={cx(classNames.toolItem, isLast && \"last\", isFailed && \"failed\")}\n data-slot=\"tool-item\"\n data-kind={entry.kind}\n data-state={entry.toolStatus}\n data-last={isLast ? \"true\" : undefined}\n data-failed={isFailed ? \"true\" : undefined}\n >\n <div className={classNames.toolItemConnector} data-slot=\"tool-item-connector\">\n <div className={classNames.toolItemDot} data-slot=\"tool-item-dot\" />\n {!isLast ? <div className={classNames.toolItemLine} data-slot=\"tool-item-line\" /> : null}\n </div>\n <div className={classNames.toolItemContent} data-slot=\"tool-item-content\">\n <button\n type=\"button\"\n className={cx(classNames.toolItemHeader, expanded && \"expanded\")}\n data-slot=\"tool-item-header\"\n data-expanded={expanded ? \"true\" : undefined}\n data-has-content={hasContent ? \"true\" : undefined}\n disabled={!hasContent}\n onClick={() => {\n if (hasContent) {\n onExpandedChange(!expanded);\n }\n }}\n >\n <span className={classNames.toolItemIcon} data-slot=\"tool-item-icon\">\n {renderToolItemIcon(entry)}\n </span>\n <span className={classNames.toolItemLabel} data-slot=\"tool-item-label\">\n {getToolItemLabel(entry)}\n </span>\n {isInProgress ? (\n <span className={classNames.toolItemSpinner} data-slot=\"tool-item-spinner\">\n {renderInlinePendingIndicator()}\n </span>\n ) : null}\n {showEventLink ? (\n <span\n className={classNames.toolItemLink}\n data-slot=\"tool-item-link\"\n role=\"button\"\n tabIndex={0}\n onClick={(event) => {\n event.stopPropagation();\n onEventClick?.(entry.eventId!);\n }}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n event.stopPropagation();\n onEventClick?.(entry.eventId!);\n }\n }}\n >\n {renderEventLinkContent(entry)}\n </span>\n ) : null}\n {hasContent ? (\n <span className={classNames.toolItemChevron} data-slot=\"tool-item-chevron\">\n {renderChevron(expanded)}\n </span>\n ) : null}\n </button>\n {expanded && hasContent ? (\n <div className={classNames.toolItemBody} data-slot=\"tool-item-body\">\n {isTool && entry.toolInput ? (\n <div className={classNames.toolSection} data-slot=\"tool-section\" data-section=\"input\">\n <div className={classNames.toolSectionTitle} data-slot=\"tool-section-title\">\n Input\n </div>\n <pre className={classNames.toolCode} data-slot=\"tool-code\">\n {entry.toolInput}\n </pre>\n </div>\n ) : null}\n {isTool && isComplete && entry.toolOutput ? (\n <div className={classNames.toolSection} data-slot=\"tool-section\" data-section=\"output\">\n <div className={classNames.toolSectionTitle} data-slot=\"tool-section-title\">\n Output\n </div>\n <pre className={classNames.toolCode} data-slot=\"tool-code\">\n {entry.toolOutput}\n </pre>\n </div>\n ) : null}\n {isReasoning && entry.reasoning?.text ? (\n <div className={classNames.toolSection} data-slot=\"tool-section\" data-section=\"reasoning\">\n <pre className={cx(classNames.toolCode, classNames.toolCodeMuted)} data-slot=\"tool-code\">\n {entry.reasoning.text}\n </pre>\n </div>\n ) : null}\n {isMeta && entry.meta?.detail ? (\n <div className={classNames.toolSection} data-slot=\"tool-section\" data-section=\"meta\">\n <pre className={classNames.toolCode} data-slot=\"tool-code\">\n {entry.meta.detail}\n </pre>\n </div>\n ) : null}\n </div>\n ) : null}\n </div>\n </div>\n );\n};\n\nconst ToolGroup = ({\n entries,\n expanded,\n onExpandedChange,\n expandedItemIds,\n onToolItemExpandedChange,\n classNames,\n onEventClick,\n canOpenEvent,\n getToolGroupSummary,\n renderInlinePendingIndicator,\n renderToolItemIcon,\n renderToolGroupIcon,\n renderChevron,\n renderEventLinkContent,\n}: {\n entries: TranscriptEntry[];\n expanded: boolean;\n onExpandedChange: (expanded: boolean) => void;\n expandedItemIds: Record<string, boolean>;\n onToolItemExpandedChange: (entryId: string, expanded: boolean) => void;\n classNames: AgentTranscriptClassNames;\n onEventClick?: (eventId: string) => void;\n canOpenEvent: (entry: TranscriptEntry) => boolean;\n getToolGroupSummary: (entries: TranscriptEntry[]) => string;\n renderInlinePendingIndicator: () => ReactNode;\n renderToolItemIcon: (entry: TranscriptEntry) => ReactNode;\n renderToolGroupIcon: (entries: TranscriptEntry[], expanded: boolean) => ReactNode;\n renderChevron: (expanded: boolean) => ReactNode;\n renderEventLinkContent: (entry: TranscriptEntry) => ReactNode;\n}) => {\n const hasFailed = entries.some((entry) => entry.kind === \"tool\" && entry.toolStatus === \"failed\");\n\n if (entries.length === 1) {\n return (\n <div className={classNames.toolGroupSingle} data-slot=\"tool-group-single\">\n <ToolItem\n entry={entries[0]}\n isLast={true}\n expanded={Boolean(expandedItemIds[entries[0]!.id])}\n onExpandedChange={(nextExpanded) => onToolItemExpandedChange(entries[0]!.id, nextExpanded)}\n classNames={classNames}\n onEventClick={onEventClick}\n canOpenEvent={canOpenEvent}\n renderInlinePendingIndicator={renderInlinePendingIndicator}\n renderToolItemIcon={renderToolItemIcon}\n renderChevron={renderChevron}\n renderEventLinkContent={renderEventLinkContent}\n />\n </div>\n );\n }\n\n return (\n <div className={cx(classNames.toolGroupContainer, hasFailed && \"failed\")} data-slot=\"tool-group\" data-failed={hasFailed ? \"true\" : undefined}>\n <button\n type=\"button\"\n className={cx(classNames.toolGroupHeader, expanded && \"expanded\")}\n data-slot=\"tool-group-header\"\n data-expanded={expanded ? \"true\" : undefined}\n onClick={() => onExpandedChange(!expanded)}\n >\n <span className={classNames.toolGroupIcon} data-slot=\"tool-group-icon\">\n {renderToolGroupIcon(entries, expanded)}\n </span>\n <span className={classNames.toolGroupLabel} data-slot=\"tool-group-label\">\n {getToolGroupSummary(entries)}\n </span>\n <span className={classNames.toolGroupChevron} data-slot=\"tool-group-chevron\">\n {renderChevron(expanded)}\n </span>\n </button>\n {expanded ? (\n <div className={classNames.toolGroupBody} data-slot=\"tool-group-body\">\n {entries.map((entry, index) => (\n <ToolItem\n key={entry.id}\n entry={entry}\n isLast={index === entries.length - 1}\n expanded={Boolean(expandedItemIds[entry.id])}\n onExpandedChange={(nextExpanded) => onToolItemExpandedChange(entry.id, nextExpanded)}\n classNames={classNames}\n onEventClick={onEventClick}\n canOpenEvent={canOpenEvent}\n renderInlinePendingIndicator={renderInlinePendingIndicator}\n renderToolItemIcon={renderToolItemIcon}\n renderChevron={renderChevron}\n renderEventLinkContent={renderEventLinkContent}\n />\n ))}\n </div>\n ) : null}\n </div>\n );\n};\n\nconst PermissionPrompt = ({\n entry,\n classNames,\n onPermissionReply,\n renderPermissionIcon,\n renderPermissionOptionContent,\n}: {\n entry: TranscriptEntry;\n classNames: AgentTranscriptClassNames;\n onPermissionReply?: (permissionId: string, reply: PermissionReply) => void;\n renderPermissionIcon: (entry: TranscriptEntry) => ReactNode;\n renderPermissionOptionContent: (context: PermissionOptionRenderContext) => ReactNode;\n}) => {\n const permission = entry.permission;\n if (!permission) {\n return null;\n }\n\n const resolved = Boolean(permission.resolved);\n const selectedOptionId = permission.selectedOptionId;\n const canReply = Boolean(onPermissionReply) && !resolved;\n\n return (\n <div className={cx(classNames.permissionPrompt, resolved && \"resolved\")} data-slot=\"permission-prompt\" data-resolved={resolved ? \"true\" : undefined}>\n <div className={classNames.permissionHeader} data-slot=\"permission-header\">\n <span className={classNames.permissionIcon} data-slot=\"permission-icon\">\n {renderPermissionIcon(entry)}\n </span>\n <span className={classNames.permissionTitle} data-slot=\"permission-title\">\n {permission.title}\n </span>\n </div>\n {permission.description ? (\n <div className={classNames.permissionDescription} data-slot=\"permission-description\">\n {permission.description}\n </div>\n ) : null}\n <div className={classNames.permissionActions} data-slot=\"permission-actions\">\n {permission.options.map((option) => {\n const reply = getPermissionReplyForOption(option.kind);\n const label = getPermissionOptionLabel(option);\n const selected = resolved && selectedOptionId === option.optionId;\n const dimmed = resolved && !selected && selectedOptionId != null;\n const tone = getPermissionOptionTone(option.kind);\n\n return (\n <button\n key={option.optionId}\n type=\"button\"\n className={cx(classNames.permissionButton, tone, selected && \"selected\", dimmed && \"dimmed\")}\n data-slot=\"permission-button\"\n data-tone={tone}\n data-selected={selected ? \"true\" : undefined}\n data-dimmed={dimmed ? \"true\" : undefined}\n disabled={!canReply}\n onClick={() => onPermissionReply?.(permission.permissionId, reply)}\n >\n {renderPermissionOptionContent({\n entry,\n option,\n label,\n reply,\n selected,\n dimmed,\n resolved,\n })}\n </button>\n );\n })}\n {resolved && !selectedOptionId ? (\n <span className={classNames.permissionAutoResolved} data-slot=\"permission-auto-resolved\">\n Auto-resolved\n </span>\n ) : null}\n </div>\n </div>\n );\n};\n\nexport const AgentTranscript = ({\n entries,\n className,\n classNames: classNameOverrides,\n endRef,\n scrollRef,\n scrollToEntryId,\n sessionError,\n eventError,\n isThinking,\n agentId,\n virtualize = false,\n onAtBottomChange,\n onEventClick,\n onPermissionReply,\n isDividerEntry = defaultIsDividerEntry,\n canOpenEvent = defaultCanOpenEvent,\n getToolGroupSummary = getDefaultToolGroupSummary,\n renderMessageText = defaultRenderMessageText,\n renderInlinePendingIndicator = defaultRenderPendingIndicator,\n renderThinkingState,\n renderToolItemIcon = getDefaultToolItemIcon,\n renderToolGroupIcon = () => null,\n renderChevron = defaultRenderChevron,\n renderEventLinkContent = defaultRenderEventLinkContent,\n renderPermissionIcon = defaultRenderPermissionIcon,\n renderPermissionOptionContent = defaultRenderPermissionOptionContent,\n}: AgentTranscriptProps) => {\n const resolvedClassNames = useMemo(() => mergeClassNames(DEFAULT_CLASS_NAMES, classNameOverrides), [classNameOverrides]);\n const groupedEntries = useMemo(() => buildGroupedEntries(entries, isDividerEntry), [entries, isDividerEntry]);\n const [expandedToolGroups, setExpandedToolGroups] = useState<Record<string, boolean>>({});\n const [expandedToolItems, setExpandedToolItems] = useState<Record<string, boolean>>({});\n const lastScrollTargetRef = useRef<string | null>(null);\n const isVirtualized = virtualize && Boolean(scrollRef);\n const { virtualizer, isFollowingRef } = useTranscriptVirtualizer(groupedEntries, isVirtualized ? scrollRef : undefined, onAtBottomChange);\n\n useEffect(() => {\n if (!scrollToEntryId) {\n lastScrollTargetRef.current = null;\n return;\n }\n\n if (!isVirtualized || scrollToEntryId === lastScrollTargetRef.current) {\n return;\n }\n\n const targetIndex = groupedEntries.findIndex((group) => group.entries.some((entry) => entry.id === scrollToEntryId));\n if (targetIndex < 0) {\n return;\n }\n\n lastScrollTargetRef.current = scrollToEntryId;\n\n const frameId = requestAnimationFrame(() => {\n virtualizer.scrollToIndex(targetIndex, {\n align: \"center\",\n behavior: \"smooth\",\n });\n });\n\n return () => {\n cancelAnimationFrame(frameId);\n };\n }, [groupedEntries, isVirtualized, scrollToEntryId, virtualizer]);\n\n useEffect(() => {\n if (!isVirtualized || !scrollRef?.current || !isFollowingRef.current) {\n return;\n }\n\n const scrollElement = scrollRef.current;\n const frameId = requestAnimationFrame(() => {\n scrollElement.scrollTo({ top: scrollElement.scrollHeight });\n });\n\n return () => {\n cancelAnimationFrame(frameId);\n };\n }, [eventError, isFollowingRef, isThinking, isVirtualized, scrollRef, sessionError]);\n\n const setToolGroupExpanded = (groupKey: string, expanded: boolean) => {\n setExpandedToolGroups((current) => {\n if (current[groupKey] === expanded) {\n return current;\n }\n return { ...current, [groupKey]: expanded };\n });\n };\n\n const setToolItemExpanded = (entryId: string, expanded: boolean) => {\n setExpandedToolItems((current) => {\n if (current[entryId] === expanded) {\n return current;\n }\n return { ...current, [entryId]: expanded };\n });\n };\n\n const renderGroup = (group: GroupedEntries, index: number) => {\n if (group.type === \"divider\") {\n const entry = group.entries[0];\n const title = entry.meta?.title ?? \"Status\";\n return (\n <div key={entry.id} className={resolvedClassNames.divider} data-slot=\"divider\">\n <div className={resolvedClassNames.dividerLine} data-slot=\"divider-line\" />\n <span className={resolvedClassNames.dividerText} data-slot=\"divider-text\">\n {title}\n </span>\n <div className={resolvedClassNames.dividerLine} data-slot=\"divider-line\" />\n </div>\n );\n }\n\n if (group.type === \"tool-group\") {\n const groupKey = getGroupedEntryKey(group, index);\n\n return (\n <ToolGroup\n key={groupKey}\n entries={group.entries}\n expanded={Boolean(expandedToolGroups[groupKey])}\n onExpandedChange={(expanded) => setToolGroupExpanded(groupKey, expanded)}\n expandedItemIds={expandedToolItems}\n onToolItemExpandedChange={setToolItemExpanded}\n classNames={resolvedClassNames}\n onEventClick={onEventClick}\n canOpenEvent={canOpenEvent}\n getToolGroupSummary={getToolGroupSummary}\n renderInlinePendingIndicator={renderInlinePendingIndicator}\n renderToolItemIcon={renderToolItemIcon}\n renderToolGroupIcon={renderToolGroupIcon}\n renderChevron={renderChevron}\n renderEventLinkContent={renderEventLinkContent}\n />\n );\n }\n\n if (group.type === \"permission\") {\n const entry = group.entries[0];\n return (\n <PermissionPrompt\n key={entry.id}\n entry={entry}\n classNames={resolvedClassNames}\n onPermissionReply={onPermissionReply}\n renderPermissionIcon={renderPermissionIcon}\n renderPermissionOptionContent={renderPermissionOptionContent}\n />\n );\n }\n\n const entry = group.entries[0];\n const messageVariant = getMessageVariant(entry);\n\n return (\n <div\n key={entry.id}\n className={cx(resolvedClassNames.message, messageVariant, \"no-avatar\")}\n data-slot=\"message\"\n data-kind={entry.kind}\n data-role={entry.role}\n data-variant={messageVariant}\n data-severity={entry.meta?.severity}\n >\n <div className={resolvedClassNames.messageContent} data-slot=\"message-content\">\n {entry.text ? (\n <div className={resolvedClassNames.messageText} data-slot=\"message-text\">\n {renderMessageText(entry)}\n </div>\n ) : (\n <span className={resolvedClassNames.thinkingIndicator} data-slot=\"thinking-indicator\">\n {renderInlinePendingIndicator()}\n </span>\n )}\n </div>\n </div>\n );\n };\n\n return (\n <div className={cx(resolvedClassNames.root, className)} data-slot=\"root\" data-virtualized={isVirtualized ? \"true\" : undefined}>\n {isVirtualized ? (\n <div\n data-slot=\"virtual-list\"\n style={{\n height: `${virtualizer.getTotalSize()}px`,\n position: \"relative\",\n width: \"100%\",\n }}\n >\n {virtualizer.getVirtualItems().map((virtualItem) => {\n const group = groupedEntries[virtualItem.index];\n if (!group) {\n return null;\n }\n\n return (\n <div\n key={getGroupedEntryKey(group, virtualItem.index)}\n data-index={virtualItem.index}\n ref={(node) => {\n if (node) {\n virtualizer.measureElement(node);\n }\n }}\n style={{\n left: 0,\n position: \"absolute\",\n top: 0,\n transform: `translateY(${virtualItem.start}px)`,\n width: \"100%\",\n }}\n >\n <div style={{ paddingBottom: virtualItem.index === groupedEntries.length - 1 ? 0 : `${VIRTUAL_GROUP_GAP_PX}px` }}>\n {renderGroup(group, virtualItem.index)}\n </div>\n </div>\n );\n })}\n </div>\n ) : (\n groupedEntries.map((group, index) => renderGroup(group, index))\n )}\n {sessionError ? (\n <div className={resolvedClassNames.error} data-slot=\"error\" data-source=\"session\">\n {sessionError}\n </div>\n ) : null}\n {eventError ? (\n <div className={resolvedClassNames.error} data-slot=\"error\" data-source=\"event\">\n {eventError}\n </div>\n ) : null}\n {isThinking\n ? (renderThinkingState?.({ agentId }) ?? (\n <div className={resolvedClassNames.thinkingRow} data-slot=\"thinking-row\">\n <span className={resolvedClassNames.thinkingIndicator} data-slot=\"thinking-indicator\">\n Thinking...\n </span>\n </div>\n ))\n : null}\n {!isVirtualized ? <div ref={endRef} className={resolvedClassNames.endAnchor} data-slot=\"end-anchor\" /> : null}\n </div>\n );\n};\n","\"use client\";\n\nimport type { RefObject } from \"react\";\nimport { useEffect, useRef } from \"react\";\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\n\nexport function useTranscriptVirtualizer<T>(items: T[], scrollElementRef?: RefObject<HTMLDivElement>, onAtBottomChange?: (atBottom: boolean) => void) {\n const isFollowingRef = useRef(true);\n\n const virtualizer = useVirtualizer({\n count: items.length,\n getScrollElement: () => scrollElementRef?.current ?? null,\n estimateSize: () => 80,\n measureElement: (element) => element.getBoundingClientRect().height,\n overscan: 10,\n });\n\n virtualizer.shouldAdjustScrollPositionOnItemSizeChange = () => isFollowingRef.current;\n\n useEffect(() => {\n const scrollElement = scrollElementRef?.current;\n if (!scrollElement) {\n return;\n }\n\n const updateFollowState = () => {\n const atBottom = scrollElement.scrollHeight - scrollElement.scrollTop - scrollElement.clientHeight < 50;\n isFollowingRef.current = atBottom;\n onAtBottomChange?.(atBottom);\n };\n\n updateFollowState();\n scrollElement.addEventListener(\"scroll\", updateFollowState, { passive: true });\n\n return () => {\n scrollElement.removeEventListener(\"scroll\", updateFollowState);\n };\n }, [onAtBottomChange, scrollElementRef]);\n\n useEffect(() => {\n if (!isFollowingRef.current || items.length === 0) {\n return;\n }\n\n const frameId = requestAnimationFrame(() => {\n virtualizer.scrollToIndex(items.length - 1, {\n align: \"end\",\n behavior: \"smooth\",\n });\n });\n\n return () => {\n cancelAnimationFrame(frameId);\n };\n }, [items.length, virtualizer]);\n\n return { virtualizer, isFollowingRef };\n}\n","\"use client\";\n\nimport type { KeyboardEvent, ReactNode, Ref, TextareaHTMLAttributes } from \"react\";\n\nexport interface ChatComposerClassNames {\n root: string;\n form: string;\n input: string;\n submit: string;\n submitContent: string;\n}\n\nexport interface ChatComposerProps {\n message: string;\n onMessageChange: (value: string) => void;\n onSubmit: () => void;\n onKeyDown?: (event: KeyboardEvent<HTMLTextAreaElement>) => void;\n placeholder?: string;\n disabled?: boolean;\n submitDisabled?: boolean;\n allowEmptySubmit?: boolean;\n submitLabel?: string;\n className?: string;\n classNames?: Partial<ChatComposerClassNames>;\n inputRef?: Ref<HTMLTextAreaElement>;\n rows?: number;\n textareaProps?: Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, \"className\" | \"disabled\" | \"onChange\" | \"onKeyDown\" | \"placeholder\" | \"rows\" | \"value\">;\n renderSubmitContent?: () => ReactNode;\n renderFooter?: () => ReactNode;\n}\n\nconst DEFAULT_CLASS_NAMES: ChatComposerClassNames = {\n root: \"sa-chat-composer\",\n form: \"sa-chat-composer-form\",\n input: \"sa-chat-composer-input\",\n submit: \"sa-chat-composer-submit\",\n submitContent: \"sa-chat-composer-submit-content\",\n};\n\nconst cx = (...values: Array<string | false | null | undefined>) => values.filter(Boolean).join(\" \");\n\nconst mergeClassNames = (defaults: ChatComposerClassNames, overrides?: Partial<ChatComposerClassNames>): ChatComposerClassNames => ({\n root: cx(defaults.root, overrides?.root),\n form: cx(defaults.form, overrides?.form),\n input: cx(defaults.input, overrides?.input),\n submit: cx(defaults.submit, overrides?.submit),\n submitContent: cx(defaults.submitContent, overrides?.submitContent),\n});\n\nexport const ChatComposer = ({\n message,\n onMessageChange,\n onSubmit,\n onKeyDown,\n placeholder,\n disabled = false,\n submitDisabled = false,\n allowEmptySubmit = false,\n submitLabel = \"Send\",\n className,\n classNames: classNameOverrides,\n inputRef,\n rows = 1,\n textareaProps,\n renderSubmitContent,\n renderFooter,\n}: ChatComposerProps) => {\n const resolvedClassNames = mergeClassNames(DEFAULT_CLASS_NAMES, classNameOverrides);\n const isSubmitDisabled = disabled || submitDisabled || (!allowEmptySubmit && message.trim().length === 0);\n\n return (\n <div className={cx(resolvedClassNames.root, className)} data-slot=\"root\">\n <form\n className={resolvedClassNames.form}\n data-slot=\"form\"\n onSubmit={(event) => {\n event.preventDefault();\n if (!isSubmitDisabled) {\n onSubmit();\n }\n }}\n >\n <textarea\n {...textareaProps}\n ref={inputRef}\n className={resolvedClassNames.input}\n data-slot=\"input\"\n data-disabled={disabled ? \"true\" : undefined}\n data-empty={message.trim().length === 0 ? \"true\" : undefined}\n value={message}\n onChange={(event) => onMessageChange(event.target.value)}\n onKeyDown={onKeyDown}\n placeholder={placeholder}\n rows={rows}\n disabled={disabled}\n />\n {renderFooter?.()}\n <button\n type=\"submit\"\n className={resolvedClassNames.submit}\n data-slot=\"submit\"\n data-disabled={isSubmitDisabled ? \"true\" : undefined}\n disabled={isSubmitDisabled}\n aria-label={submitLabel}\n title={submitLabel}\n >\n <span className={resolvedClassNames.submitContent} data-slot=\"submit-content\">\n {renderSubmitContent?.() ?? submitLabel}\n </span>\n </button>\n </form>\n </div>\n );\n};\n","\"use client\";\n\nimport type { ReactNode, RefObject } from \"react\";\nimport { AgentTranscript, type AgentTranscriptClassNames, type AgentTranscriptProps, type TranscriptEntry } from \"./AgentTranscript.tsx\";\nimport { ChatComposer, type ChatComposerClassNames, type ChatComposerProps } from \"./ChatComposer.tsx\";\n\nexport interface AgentConversationClassNames {\n root: string;\n transcript: string;\n emptyState: string;\n composer: string;\n}\n\nexport interface AgentConversationProps {\n entries: TranscriptEntry[];\n className?: string;\n classNames?: Partial<AgentConversationClassNames>;\n emptyState?: ReactNode;\n transcriptClassName?: string;\n transcriptClassNames?: Partial<AgentTranscriptClassNames>;\n scrollRef?: RefObject<HTMLDivElement>;\n composerClassName?: string;\n composerClassNames?: Partial<ChatComposerClassNames>;\n transcriptProps?: Omit<AgentTranscriptProps, \"entries\" | \"className\" | \"classNames\" | \"scrollRef\">;\n composerProps?: Omit<ChatComposerProps, \"className\" | \"classNames\">;\n}\n\nconst DEFAULT_CLASS_NAMES: AgentConversationClassNames = {\n root: \"sa-agent-conversation\",\n transcript: \"sa-agent-conversation-transcript\",\n emptyState: \"sa-agent-conversation-empty-state\",\n composer: \"sa-agent-conversation-composer\",\n};\n\nconst cx = (...values: Array<string | false | null | undefined>) => values.filter(Boolean).join(\" \");\n\nconst mergeClassNames = (defaults: AgentConversationClassNames, overrides?: Partial<AgentConversationClassNames>): AgentConversationClassNames => ({\n root: cx(defaults.root, overrides?.root),\n transcript: cx(defaults.transcript, overrides?.transcript),\n emptyState: cx(defaults.emptyState, overrides?.emptyState),\n composer: cx(defaults.composer, overrides?.composer),\n});\n\nexport const AgentConversation = ({\n entries,\n className,\n classNames: classNameOverrides,\n emptyState,\n transcriptClassName,\n transcriptClassNames,\n scrollRef,\n composerClassName,\n composerClassNames,\n transcriptProps,\n composerProps,\n}: AgentConversationProps) => {\n const resolvedClassNames = mergeClassNames(DEFAULT_CLASS_NAMES, classNameOverrides);\n const hasTranscriptContent = entries.length > 0 || Boolean(transcriptProps?.sessionError) || Boolean(transcriptProps?.eventError);\n\n return (\n <div className={cx(resolvedClassNames.root, className)} data-slot=\"root\">\n {hasTranscriptContent ? (\n scrollRef ? (\n <div className={cx(resolvedClassNames.transcript, transcriptClassName)} data-slot=\"transcript\" ref={scrollRef}>\n <AgentTranscript entries={entries} classNames={transcriptClassNames} {...transcriptProps} />\n </div>\n ) : (\n <AgentTranscript\n entries={entries}\n className={cx(resolvedClassNames.transcript, transcriptClassName)}\n classNames={transcriptClassNames}\n {...transcriptProps}\n />\n )\n ) : emptyState ? (\n <div className={resolvedClassNames.emptyState} data-slot=\"empty-state\">\n {emptyState}\n </div>\n ) : null}\n {composerProps ? (\n <ChatComposer className={cx(resolvedClassNames.composer, composerClassName)} classNames={composerClassNames} {...composerProps} />\n ) : null}\n </div>\n );\n};\n","\"use client\";\n\nimport type { FitAddon as GhosttyFitAddon, Terminal as GhosttyTerminal } from \"ghostty-web\";\nimport type { CSSProperties } from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport type {\n SandboxAgent,\n TerminalErrorStatus,\n TerminalExitStatus,\n TerminalReadyStatus,\n} from \"sandbox-agent\";\n\ntype ConnectionState = \"connecting\" | \"ready\" | \"closed\" | \"error\";\n\nexport type ProcessTerminalClient = Pick<SandboxAgent, \"connectProcessTerminal\">;\n\nexport interface ProcessTerminalProps {\n client: ProcessTerminalClient;\n processId: string;\n className?: string;\n style?: CSSProperties;\n terminalStyle?: CSSProperties;\n statusBarStyleOverride?: CSSProperties;\n height?: number | string;\n showStatusBar?: boolean;\n onExit?: (status: TerminalExitStatus) => void;\n onError?: (error: TerminalErrorStatus | Error) => void;\n}\n\nconst terminalTheme = {\n background: \"#09090b\",\n foreground: \"#f4f4f5\",\n cursor: \"#f97316\",\n cursorAccent: \"#09090b\",\n selectionBackground: \"#27272a\",\n black: \"#18181b\",\n red: \"#f87171\",\n green: \"#4ade80\",\n yellow: \"#fbbf24\",\n blue: \"#60a5fa\",\n magenta: \"#f472b6\",\n cyan: \"#22d3ee\",\n white: \"#e4e4e7\",\n brightBlack: \"#3f3f46\",\n brightRed: \"#fb7185\",\n brightGreen: \"#86efac\",\n brightYellow: \"#fde047\",\n brightBlue: \"#93c5fd\",\n brightMagenta: \"#f9a8d4\",\n brightCyan: \"#67e8f9\",\n brightWhite: \"#fafafa\",\n};\n\nconst shellStyle: CSSProperties = {\n display: \"flex\",\n flexDirection: \"column\",\n overflow: \"hidden\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n borderRadius: 10,\n background: \"rgba(0, 0, 0, 0.3)\",\n};\n\nconst statusBarStyle: CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 12,\n padding: \"8px 12px\",\n borderBottom: \"1px solid rgba(255, 255, 255, 0.08)\",\n background: \"rgba(0, 0, 0, 0.2)\",\n color: \"rgba(244, 244, 245, 0.86)\",\n fontSize: 11,\n lineHeight: 1.4,\n};\n\nconst hostBaseStyle: CSSProperties = {\n minHeight: 320,\n padding: 10,\n overflow: \"hidden\",\n};\n\nconst exitCodeStyle: CSSProperties = {\n fontFamily: \"ui-monospace, SFMono-Regular, SF Mono, Menlo, monospace\",\n opacity: 0.72,\n};\n\nconst getStatusColor = (state: ConnectionState): string => {\n switch (state) {\n case \"ready\":\n return \"#4ade80\";\n case \"error\":\n return \"#fb7185\";\n case \"closed\":\n return \"#fbbf24\";\n default:\n return \"rgba(244, 244, 245, 0.72)\";\n }\n};\n\nexport const ProcessTerminal = ({\n client,\n processId,\n className,\n style,\n terminalStyle,\n statusBarStyleOverride,\n height = 360,\n showStatusBar = true,\n onExit,\n onError,\n}: ProcessTerminalProps) => {\n const hostRef = useRef<HTMLDivElement | null>(null);\n const [connectionState, setConnectionState] = useState<ConnectionState>(\"connecting\");\n const [statusMessage, setStatusMessage] = useState(\"Connecting to PTY...\");\n const [exitCode, setExitCode] = useState<number | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n let terminal: GhosttyTerminal | null = null;\n let fitAddon: GhosttyFitAddon | null = null;\n let session: ReturnType<ProcessTerminalClient[\"connectProcessTerminal\"]> | null = null;\n let resizeRaf = 0;\n let removeDataListener: { dispose(): void } | null = null;\n let removeResizeListener: { dispose(): void } | null = null;\n\n setConnectionState(\"connecting\");\n setStatusMessage(\"Connecting to PTY...\");\n setExitCode(null);\n\n const syncSize = () => {\n if (!terminal || !session) {\n return;\n }\n\n session.resize({\n cols: terminal.cols,\n rows: terminal.rows,\n });\n };\n\n const connect = async () => {\n try {\n const ghostty = await import(\"ghostty-web\");\n await ghostty.init();\n\n if (cancelled || !hostRef.current) {\n return;\n }\n\n terminal = new ghostty.Terminal({\n allowTransparency: true,\n cursorBlink: true,\n cursorStyle: \"block\",\n fontFamily: \"ui-monospace, SFMono-Regular, SF Mono, Menlo, monospace\",\n fontSize: 13,\n smoothScrollDuration: 90,\n theme: terminalTheme,\n });\n fitAddon = new ghostty.FitAddon();\n\n terminal.open(hostRef.current);\n const terminalRoot = hostRef.current.firstElementChild;\n if (terminalRoot instanceof HTMLElement) {\n terminalRoot.style.width = \"100%\";\n terminalRoot.style.height = \"100%\";\n }\n terminal.loadAddon(fitAddon);\n fitAddon.fit();\n fitAddon.observeResize();\n terminal.focus();\n\n removeDataListener = terminal.onData((data) => {\n session?.sendInput(data);\n });\n\n removeResizeListener = terminal.onResize(() => {\n if (resizeRaf) {\n window.cancelAnimationFrame(resizeRaf);\n }\n resizeRaf = window.requestAnimationFrame(syncSize);\n });\n\n const nextSession = client.connectProcessTerminal(processId);\n session = nextSession;\n\n nextSession.onReady((frame: TerminalReadyStatus) => {\n if (cancelled || frame.type !== \"ready\") {\n return;\n }\n\n setConnectionState(\"ready\");\n setStatusMessage(\"Connected\");\n syncSize();\n });\n\n nextSession.onData((bytes: Uint8Array) => {\n if (cancelled || !terminal) {\n return;\n }\n terminal.write(bytes);\n });\n\n nextSession.onExit((frame: TerminalExitStatus) => {\n if (cancelled || frame.type !== \"exit\") {\n return;\n }\n\n setConnectionState(\"closed\");\n setExitCode(frame.exitCode ?? null);\n setStatusMessage(frame.exitCode == null ? \"Process exited.\" : `Process exited with code ${frame.exitCode}.`);\n onExit?.(frame);\n });\n\n nextSession.onError((error: TerminalErrorStatus | Error) => {\n if (cancelled) {\n return;\n }\n\n setConnectionState(\"error\");\n setStatusMessage(error instanceof Error ? error.message : error.message);\n onError?.(error);\n });\n\n nextSession.onClose(() => {\n if (cancelled) {\n return;\n }\n\n setConnectionState((current) => (current === \"error\" ? current : \"closed\"));\n setStatusMessage((current) => (current === \"Connected\" ? \"Terminal disconnected.\" : current));\n });\n } catch (error) {\n if (cancelled) {\n return;\n }\n\n const nextError = error instanceof Error ? error : new Error(\"Failed to initialize terminal.\");\n setConnectionState(\"error\");\n setStatusMessage(nextError.message);\n onError?.(nextError);\n }\n };\n\n void connect();\n\n return () => {\n cancelled = true;\n if (resizeRaf) {\n window.cancelAnimationFrame(resizeRaf);\n }\n removeDataListener?.dispose();\n removeResizeListener?.dispose();\n session?.close();\n terminal?.dispose();\n };\n }, [client, onError, onExit, processId]);\n\n return (\n <div className={className} style={{ ...shellStyle, ...style }}>\n {showStatusBar ? (\n <div style={{ ...statusBarStyle, ...statusBarStyleOverride }}>\n <span style={{ color: getStatusColor(connectionState) }}>{statusMessage}</span>\n {exitCode != null ? <span style={exitCodeStyle}>exit={exitCode}</span> : null}\n </div>\n ) : null}\n <div\n ref={hostRef}\n role=\"presentation\"\n style={{\n ...hostBaseStyle,\n height,\n ...terminalStyle,\n }}\n onClick={() => {\n hostRef.current?.querySelector(\"textarea\")?.focus();\n }}\n />\n </div>\n );\n};\n"],"mappings":";AAGA,SAAS,aAAAA,YAAW,SAAS,UAAAC,SAAQ,gBAAgB;;;ACArD,SAAS,WAAW,cAAc;AAClC,SAAS,sBAAsB;AAExB,SAAS,yBAA4B,OAAY,kBAA8C,kBAAgD;AACpJ,QAAM,iBAAiB,OAAO,IAAI;AAElC,QAAM,cAAc,eAAe;AAAA,IACjC,OAAO,MAAM;AAAA,IACb,kBAAkB,MAAM,kBAAkB,WAAW;AAAA,IACrD,cAAc,MAAM;AAAA,IACpB,gBAAgB,CAAC,YAAY,QAAQ,sBAAsB,EAAE;AAAA,IAC7D,UAAU;AAAA,EACZ,CAAC;AAED,cAAY,6CAA6C,MAAM,eAAe;AAE9E,YAAU,MAAM;AACd,UAAM,gBAAgB,kBAAkB;AACxC,QAAI,CAAC,eAAe;AAClB;AAAA,IACF;AAEA,UAAM,oBAAoB,MAAM;AAC9B,YAAM,WAAW,cAAc,eAAe,cAAc,YAAY,cAAc,eAAe;AACrG,qBAAe,UAAU;AACzB,yBAAmB,QAAQ;AAAA,IAC7B;AAEA,sBAAkB;AAClB,kBAAc,iBAAiB,UAAU,mBAAmB,EAAE,SAAS,KAAK,CAAC;AAE7E,WAAO,MAAM;AACX,oBAAc,oBAAoB,UAAU,iBAAiB;AAAA,IAC/D;AAAA,EACF,GAAG,CAAC,kBAAkB,gBAAgB,CAAC;AAEvC,YAAU,MAAM;AACd,QAAI,CAAC,eAAe,WAAW,MAAM,WAAW,GAAG;AACjD;AAAA,IACF;AAEA,UAAM,UAAU,sBAAsB,MAAM;AAC1C,kBAAY,cAAc,MAAM,SAAS,GAAG;AAAA,QAC1C,OAAO;AAAA,QACP,UAAU;AAAA,MACZ,CAAC;AAAA,IACH,CAAC;AAED,WAAO,MAAM;AACX,2BAAqB,OAAO;AAAA,IAC9B;AAAA,EACF,GAAG,CAAC,MAAM,QAAQ,WAAW,CAAC;AAE9B,SAAO,EAAE,aAAa,eAAe;AACvC;;;AD6UM,SACE,KADF;AAnQN,IAAM,uBAAuB;AAE7B,IAAM,sBAAiD;AAAA,EACrD,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,aAAa;AAAA,EACb,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,OAAO;AAAA,EACP,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,UAAU;AAAA,EACV,mBAAmB;AAAA,EACnB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,UAAU;AAAA,EACV,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,uBAAuB;AAAA,EACvB,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,wBAAwB;AAAA,EACxB,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,mBAAmB;AAAA,EACnB,aAAa;AAAA,EACb,WAAW;AACb;AAEA,IAAM,yBAAyB,oBAAI,IAAI,CAAC,mBAAmB,gBAAgB,YAAY,CAAC;AAExF,IAAM,KAAK,IAAI,WAAqD,OAAO,OAAO,OAAO,EAAE,KAAK,GAAG;AAEnG,IAAM,kBAAkB,CAAC,UAAqC,eAA+E;AAAA,EAC3I,MAAM,GAAG,SAAS,MAAM,WAAW,IAAI;AAAA,EACvC,SAAS,GAAG,SAAS,SAAS,WAAW,OAAO;AAAA,EAChD,aAAa,GAAG,SAAS,aAAa,WAAW,WAAW;AAAA,EAC5D,aAAa,GAAG,SAAS,aAAa,WAAW,WAAW;AAAA,EAC5D,SAAS,GAAG,SAAS,SAAS,WAAW,OAAO;AAAA,EAChD,gBAAgB,GAAG,SAAS,gBAAgB,WAAW,cAAc;AAAA,EACrE,aAAa,GAAG,SAAS,aAAa,WAAW,WAAW;AAAA,EAC5D,OAAO,GAAG,SAAS,OAAO,WAAW,KAAK;AAAA,EAC1C,iBAAiB,GAAG,SAAS,iBAAiB,WAAW,eAAe;AAAA,EACxE,oBAAoB,GAAG,SAAS,oBAAoB,WAAW,kBAAkB;AAAA,EACjF,iBAAiB,GAAG,SAAS,iBAAiB,WAAW,eAAe;AAAA,EACxE,eAAe,GAAG,SAAS,eAAe,WAAW,aAAa;AAAA,EAClE,gBAAgB,GAAG,SAAS,gBAAgB,WAAW,cAAc;AAAA,EACrE,kBAAkB,GAAG,SAAS,kBAAkB,WAAW,gBAAgB;AAAA,EAC3E,eAAe,GAAG,SAAS,eAAe,WAAW,aAAa;AAAA,EAClE,UAAU,GAAG,SAAS,UAAU,WAAW,QAAQ;AAAA,EACnD,mBAAmB,GAAG,SAAS,mBAAmB,WAAW,iBAAiB;AAAA,EAC9E,aAAa,GAAG,SAAS,aAAa,WAAW,WAAW;AAAA,EAC5D,cAAc,GAAG,SAAS,cAAc,WAAW,YAAY;AAAA,EAC/D,iBAAiB,GAAG,SAAS,iBAAiB,WAAW,eAAe;AAAA,EACxE,gBAAgB,GAAG,SAAS,gBAAgB,WAAW,cAAc;AAAA,EACrE,cAAc,GAAG,SAAS,cAAc,WAAW,YAAY;AAAA,EAC/D,eAAe,GAAG,SAAS,eAAe,WAAW,aAAa;AAAA,EAClE,iBAAiB,GAAG,SAAS,iBAAiB,WAAW,eAAe;AAAA,EACxE,cAAc,GAAG,SAAS,cAAc,WAAW,YAAY;AAAA,EAC/D,iBAAiB,GAAG,SAAS,iBAAiB,WAAW,eAAe;AAAA,EACxE,cAAc,GAAG,SAAS,cAAc,WAAW,YAAY;AAAA,EAC/D,aAAa,GAAG,SAAS,aAAa,WAAW,WAAW;AAAA,EAC5D,kBAAkB,GAAG,SAAS,kBAAkB,WAAW,gBAAgB;AAAA,EAC3E,UAAU,GAAG,SAAS,UAAU,WAAW,QAAQ;AAAA,EACnD,eAAe,GAAG,SAAS,eAAe,WAAW,aAAa;AAAA,EAClE,kBAAkB,GAAG,SAAS,kBAAkB,WAAW,gBAAgB;AAAA,EAC3E,kBAAkB,GAAG,SAAS,kBAAkB,WAAW,gBAAgB;AAAA,EAC3E,gBAAgB,GAAG,SAAS,gBAAgB,WAAW,cAAc;AAAA,EACrE,iBAAiB,GAAG,SAAS,iBAAiB,WAAW,eAAe;AAAA,EACxE,uBAAuB,GAAG,SAAS,uBAAuB,WAAW,qBAAqB;AAAA,EAC1F,mBAAmB,GAAG,SAAS,mBAAmB,WAAW,iBAAiB;AAAA,EAC9E,kBAAkB,GAAG,SAAS,kBAAkB,WAAW,gBAAgB;AAAA,EAC3E,wBAAwB,GAAG,SAAS,wBAAwB,WAAW,sBAAsB;AAAA,EAC7F,aAAa,GAAG,SAAS,aAAa,WAAW,WAAW;AAAA,EAC5D,gBAAgB,GAAG,SAAS,gBAAgB,WAAW,cAAc;AAAA,EACrE,qBAAqB,GAAG,SAAS,qBAAqB,WAAW,mBAAmB;AAAA,EACpF,qBAAqB,GAAG,SAAS,qBAAqB,WAAW,mBAAmB;AAAA,EACpF,mBAAmB,GAAG,SAAS,mBAAmB,WAAW,iBAAiB;AAAA,EAC9E,aAAa,GAAG,SAAS,aAAa,WAAW,WAAW;AAAA,EAC5D,WAAW,GAAG,SAAS,WAAW,WAAW,SAAS;AACxD;AAEA,IAAM,oBAAoB,CAAC,UAA2B;AACpD,MAAI,MAAM,SAAS,OAAQ,QAAO;AAClC,MAAI,MAAM,SAAS,OAAQ,QAAO,MAAM,MAAM,aAAa,UAAU,UAAU;AAC/E,MAAI,MAAM,SAAS,YAAa,QAAO;AACvC,MAAI,MAAM,SAAS,aAAc,QAAO;AACxC,MAAI,MAAM,SAAS,OAAQ,QAAO;AAClC,SAAO;AACT;AAEA,IAAM,mBAAmB,CAAC,UAA2B;AACnD,MAAI,MAAM,SAAS,QAAQ;AACzB,UAAM,cAAc,MAAM,cAAc,MAAM,eAAe,cAAc,KAAK,MAAM,WAAW,WAAW,KAAK,GAAG,CAAC,MAAM;AAC3H,WAAO,GAAG,MAAM,YAAY,MAAM,GAAG,WAAW;AAAA,EAClD;AAEA,MAAI,MAAM,SAAS,aAAa;AAC9B,WAAO,YAAY,MAAM,WAAW,aAAa,KAAK,MAAM,UAAU,UAAU,MAAM,EAAE;AAAA,EAC1F;AAEA,SAAO,MAAM,MAAM,SAAS;AAC9B;AAEA,IAAM,yBAAyB,CAAC,UAA2B;AACzD,MAAI,MAAM,SAAS,OAAQ,QAAO;AAClC,MAAI,MAAM,SAAS,YAAa,QAAO;AACvC,SAAO,MAAM,MAAM,aAAa,UAAU,UAAU;AACtD;AAEA,IAAM,6BAA6B,CAAC,YAA+B;AACjE,QAAM,QAAQ,QAAQ;AACtB,SAAO,GAAG,KAAK,SAAS,UAAU,IAAI,KAAK,GAAG;AAChD;AAEA,IAAM,8BAA8B,CAAC,SAAkC;AACrE,MAAI,SAAS,aAAc,QAAO;AAClC,MAAI,SAAS,eAAgB,QAAO;AACpC,SAAO;AACT;AAEA,IAAM,2BAA2B,CAAC,WAA6B;AAC7D,MAAI,OAAO,KAAM,QAAO,OAAO;AAC/B,MAAI,OAAO,SAAS,aAAc,QAAO;AACzC,MAAI,OAAO,SAAS,eAAgB,QAAO;AAC3C,MAAI,OAAO,SAAS,cAAe,QAAO;AAC1C,MAAI,OAAO,SAAS,gBAAiB,QAAO;AAC5C,SAAO,OAAO;AAChB;AAEA,IAAM,0BAA0B,CAAC,SAAkB,KAAK,WAAW,OAAO,IAAI,UAAU;AAExF,IAAM,2BAA2B,CAAC,UAA2B,MAAM;AACnE,IAAM,gCAAgC,MAAM;AAC5C,IAAM,uBAAuB,CAAC,aAAuB,WAAW,WAAM;AACtE,IAAM,gCAAgC,MAAM;AAC5C,IAAM,8BAA8B,MAAM;AAC1C,IAAM,uCAAuC,CAAC,EAAE,MAAM,MAAqC;AAC3F,IAAM,wBAAwB,CAAC,UAA2B,MAAM,SAAS,UAAU,uBAAuB,IAAI,MAAM,MAAM,SAAS,EAAE;AAErI,IAAM,sBAAsB,CAAC,UAA2B,QAAQ,MAAM,OAAO;AAE7E,IAAM,sBAAsB,CAAC,SAA4B,mBAA0E;AACjI,QAAM,iBAAmC,CAAC;AAC1C,MAAI,mBAAsC,CAAC;AAE3C,QAAM,iBAAiB,MAAM;AAC3B,QAAI,iBAAiB,WAAW,GAAG;AACjC;AAAA,IACF;AACA,mBAAe,KAAK,EAAE,MAAM,cAAc,SAAS,iBAAiB,CAAC;AACrE,uBAAmB,CAAC;AAAA,EACtB;AAEA,aAAW,SAAS,SAAS;AAC3B,QAAI,eAAe,KAAK,GAAG;AACzB,qBAAe;AACf,qBAAe,KAAK,EAAE,MAAM,WAAW,SAAS,CAAC,KAAK,EAAE,CAAC;AACzD;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,cAAc;AAC/B,qBAAe;AACf,qBAAe,KAAK,EAAE,MAAM,cAAc,SAAS,CAAC,KAAK,EAAE,CAAC;AAC5D;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,UAAU,MAAM,SAAS,eAAe,MAAM,SAAS,QAAQ;AAChF,uBAAiB,KAAK,KAAK;AAC3B;AAAA,IACF;AAEA,mBAAe;AACf,mBAAe,KAAK,EAAE,MAAM,WAAW,SAAS,CAAC,KAAK,EAAE,CAAC;AAAA,EAC3D;AAEA,iBAAe;AACf,SAAO;AACT;AAEA,IAAM,qBAAqB,CAAC,OAAuB,UAA0B;AAC3E,QAAM,aAAa,MAAM,QAAQ,CAAC;AAElC,MAAI,MAAM,SAAS,cAAc;AAC/B,WAAO,cAAc,YAAY,MAAM,KAAK;AAAA,EAC9C;AAEA,SAAO,YAAY,MAAM,GAAG,MAAM,IAAI,IAAI,KAAK;AACjD;AAEA,IAAM,WAAW,CAAC;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAYM;AACJ,QAAM,SAAS,MAAM,SAAS;AAC9B,QAAM,cAAc,MAAM,SAAS;AACnC,QAAM,SAAS,MAAM,SAAS;AAC9B,QAAM,aAAa,WAAW,MAAM,eAAe,eAAe,MAAM,eAAe;AACvF,QAAM,WAAW,UAAU,MAAM,eAAe;AAChD,QAAM,eAAe,UAAU,MAAM,eAAe;AACpD,QAAM,aAAa,SACf,QAAQ,MAAM,aAAa,MAAM,UAAU,IAC3C,cACE,QAAQ,MAAM,WAAW,MAAM,KAAK,CAAC,IACrC,QAAQ,MAAM,MAAM,QAAQ,KAAK,CAAC;AACxC,QAAM,gBAAgB,QAAQ,MAAM,WAAW,gBAAgB,aAAa,KAAK,CAAC;AAElF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,GAAG,WAAW,UAAU,UAAU,QAAQ,YAAY,QAAQ;AAAA,MACzE,aAAU;AAAA,MACV,aAAW,MAAM;AAAA,MACjB,cAAY,MAAM;AAAA,MAClB,aAAW,SAAS,SAAS;AAAA,MAC7B,eAAa,WAAW,SAAS;AAAA,MAEjC;AAAA,6BAAC,SAAI,WAAW,WAAW,mBAAmB,aAAU,uBACtD;AAAA,8BAAC,SAAI,WAAW,WAAW,aAAa,aAAU,iBAAgB;AAAA,UACjE,CAAC,SAAS,oBAAC,SAAI,WAAW,WAAW,cAAc,aAAU,kBAAiB,IAAK;AAAA,WACtF;AAAA,QACA,qBAAC,SAAI,WAAW,WAAW,iBAAiB,aAAU,qBACpD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAW,GAAG,WAAW,gBAAgB,YAAY,UAAU;AAAA,cAC/D,aAAU;AAAA,cACV,iBAAe,WAAW,SAAS;AAAA,cACnC,oBAAkB,aAAa,SAAS;AAAA,cACxC,UAAU,CAAC;AAAA,cACX,SAAS,MAAM;AACb,oBAAI,YAAY;AACd,mCAAiB,CAAC,QAAQ;AAAA,gBAC5B;AAAA,cACF;AAAA,cAEA;AAAA,oCAAC,UAAK,WAAW,WAAW,cAAc,aAAU,kBACjD,6BAAmB,KAAK,GAC3B;AAAA,gBACA,oBAAC,UAAK,WAAW,WAAW,eAAe,aAAU,mBAClD,2BAAiB,KAAK,GACzB;AAAA,gBACC,eACC,oBAAC,UAAK,WAAW,WAAW,iBAAiB,aAAU,qBACpD,uCAA6B,GAChC,IACE;AAAA,gBACH,gBACC;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAW,WAAW;AAAA,oBACtB,aAAU;AAAA,oBACV,MAAK;AAAA,oBACL,UAAU;AAAA,oBACV,SAAS,CAAC,UAAU;AAClB,4BAAM,gBAAgB;AACtB,qCAAe,MAAM,OAAQ;AAAA,oBAC/B;AAAA,oBACA,WAAW,CAAC,UAAU;AACpB,0BAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;AAC9C,8BAAM,eAAe;AACrB,8BAAM,gBAAgB;AACtB,uCAAe,MAAM,OAAQ;AAAA,sBAC/B;AAAA,oBACF;AAAA,oBAEC,iCAAuB,KAAK;AAAA;AAAA,gBAC/B,IACE;AAAA,gBACH,aACC,oBAAC,UAAK,WAAW,WAAW,iBAAiB,aAAU,qBACpD,wBAAc,QAAQ,GACzB,IACE;AAAA;AAAA;AAAA,UACN;AAAA,UACC,YAAY,aACX,qBAAC,SAAI,WAAW,WAAW,cAAc,aAAU,kBAChD;AAAA,sBAAU,MAAM,YACf,qBAAC,SAAI,WAAW,WAAW,aAAa,aAAU,gBAAe,gBAAa,SAC5E;AAAA,kCAAC,SAAI,WAAW,WAAW,kBAAkB,aAAU,sBAAqB,mBAE5E;AAAA,cACA,oBAAC,SAAI,WAAW,WAAW,UAAU,aAAU,aAC5C,gBAAM,WACT;AAAA,eACF,IACE;AAAA,YACH,UAAU,cAAc,MAAM,aAC7B,qBAAC,SAAI,WAAW,WAAW,aAAa,aAAU,gBAAe,gBAAa,UAC5E;AAAA,kCAAC,SAAI,WAAW,WAAW,kBAAkB,aAAU,sBAAqB,oBAE5E;AAAA,cACA,oBAAC,SAAI,WAAW,WAAW,UAAU,aAAU,aAC5C,gBAAM,YACT;AAAA,eACF,IACE;AAAA,YACH,eAAe,MAAM,WAAW,OAC/B,oBAAC,SAAI,WAAW,WAAW,aAAa,aAAU,gBAAe,gBAAa,aAC5E,8BAAC,SAAI,WAAW,GAAG,WAAW,UAAU,WAAW,aAAa,GAAG,aAAU,aAC1E,gBAAM,UAAU,MACnB,GACF,IACE;AAAA,YACH,UAAU,MAAM,MAAM,SACrB,oBAAC,SAAI,WAAW,WAAW,aAAa,aAAU,gBAAe,gBAAa,QAC5E,8BAAC,SAAI,WAAW,WAAW,UAAU,aAAU,aAC5C,gBAAM,KAAK,QACd,GACF,IACE;AAAA,aACN,IACE;AAAA,WACN;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,IAAM,YAAY,CAAC;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAeM;AACJ,QAAM,YAAY,QAAQ,KAAK,CAAC,UAAU,MAAM,SAAS,UAAU,MAAM,eAAe,QAAQ;AAEhG,MAAI,QAAQ,WAAW,GAAG;AACxB,WACE,oBAAC,SAAI,WAAW,WAAW,iBAAiB,aAAU,qBACpD;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,QAAQ,CAAC;AAAA,QAChB,QAAQ;AAAA,QACR,UAAU,QAAQ,gBAAgB,QAAQ,CAAC,EAAG,EAAE,CAAC;AAAA,QACjD,kBAAkB,CAAC,iBAAiB,yBAAyB,QAAQ,CAAC,EAAG,IAAI,YAAY;AAAA,QACzF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF,GACF;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAW,GAAG,WAAW,oBAAoB,aAAa,QAAQ,GAAG,aAAU,cAAa,eAAa,YAAY,SAAS,QACjI;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAW,GAAG,WAAW,iBAAiB,YAAY,UAAU;AAAA,QAChE,aAAU;AAAA,QACV,iBAAe,WAAW,SAAS;AAAA,QACnC,SAAS,MAAM,iBAAiB,CAAC,QAAQ;AAAA,QAEzC;AAAA,8BAAC,UAAK,WAAW,WAAW,eAAe,aAAU,mBAClD,8BAAoB,SAAS,QAAQ,GACxC;AAAA,UACA,oBAAC,UAAK,WAAW,WAAW,gBAAgB,aAAU,oBACnD,8BAAoB,OAAO,GAC9B;AAAA,UACA,oBAAC,UAAK,WAAW,WAAW,kBAAkB,aAAU,sBACrD,wBAAc,QAAQ,GACzB;AAAA;AAAA;AAAA,IACF;AAAA,IACC,WACC,oBAAC,SAAI,WAAW,WAAW,eAAe,aAAU,mBACjD,kBAAQ,IAAI,CAAC,OAAO,UACnB;AAAA,MAAC;AAAA;AAAA,QAEC;AAAA,QACA,QAAQ,UAAU,QAAQ,SAAS;AAAA,QACnC,UAAU,QAAQ,gBAAgB,MAAM,EAAE,CAAC;AAAA,QAC3C,kBAAkB,CAAC,iBAAiB,yBAAyB,MAAM,IAAI,YAAY;AAAA,QACnF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,MAXK,MAAM;AAAA,IAYb,CACD,GACH,IACE;AAAA,KACN;AAEJ;AAEA,IAAM,mBAAmB,CAAC;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAMM;AACJ,QAAM,aAAa,MAAM;AACzB,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,QAAQ,WAAW,QAAQ;AAC5C,QAAM,mBAAmB,WAAW;AACpC,QAAM,WAAW,QAAQ,iBAAiB,KAAK,CAAC;AAEhD,SACE,qBAAC,SAAI,WAAW,GAAG,WAAW,kBAAkB,YAAY,UAAU,GAAG,aAAU,qBAAoB,iBAAe,WAAW,SAAS,QACxI;AAAA,yBAAC,SAAI,WAAW,WAAW,kBAAkB,aAAU,qBACrD;AAAA,0BAAC,UAAK,WAAW,WAAW,gBAAgB,aAAU,mBACnD,+BAAqB,KAAK,GAC7B;AAAA,MACA,oBAAC,UAAK,WAAW,WAAW,iBAAiB,aAAU,oBACpD,qBAAW,OACd;AAAA,OACF;AAAA,IACC,WAAW,cACV,oBAAC,SAAI,WAAW,WAAW,uBAAuB,aAAU,0BACzD,qBAAW,aACd,IACE;AAAA,IACJ,qBAAC,SAAI,WAAW,WAAW,mBAAmB,aAAU,sBACrD;AAAA,iBAAW,QAAQ,IAAI,CAAC,WAAW;AAClC,cAAM,QAAQ,4BAA4B,OAAO,IAAI;AACrD,cAAM,QAAQ,yBAAyB,MAAM;AAC7C,cAAM,WAAW,YAAY,qBAAqB,OAAO;AACzD,cAAM,SAAS,YAAY,CAAC,YAAY,oBAAoB;AAC5D,cAAM,OAAO,wBAAwB,OAAO,IAAI;AAEhD,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,WAAW,GAAG,WAAW,kBAAkB,MAAM,YAAY,YAAY,UAAU,QAAQ;AAAA,YAC3F,aAAU;AAAA,YACV,aAAW;AAAA,YACX,iBAAe,WAAW,SAAS;AAAA,YACnC,eAAa,SAAS,SAAS;AAAA,YAC/B,UAAU,CAAC;AAAA,YACX,SAAS,MAAM,oBAAoB,WAAW,cAAc,KAAK;AAAA,YAEhE,wCAA8B;AAAA,cAC7B;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF,CAAC;AAAA;AAAA,UAlBI,OAAO;AAAA,QAmBd;AAAA,MAEJ,CAAC;AAAA,MACA,YAAY,CAAC,mBACZ,oBAAC,UAAK,WAAW,WAAW,wBAAwB,aAAU,4BAA2B,2BAEzF,IACE;AAAA,OACN;AAAA,KACF;AAEJ;AAEO,IAAM,kBAAkB,CAAC;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,sBAAsB;AAAA,EACtB,oBAAoB;AAAA,EACpB,+BAA+B;AAAA,EAC/B;AAAA,EACA,qBAAqB;AAAA,EACrB,sBAAsB,MAAM;AAAA,EAC5B,gBAAgB;AAAA,EAChB,yBAAyB;AAAA,EACzB,uBAAuB;AAAA,EACvB,gCAAgC;AAClC,MAA4B;AAC1B,QAAM,qBAAqB,QAAQ,MAAM,gBAAgB,qBAAqB,kBAAkB,GAAG,CAAC,kBAAkB,CAAC;AACvH,QAAM,iBAAiB,QAAQ,MAAM,oBAAoB,SAAS,cAAc,GAAG,CAAC,SAAS,cAAc,CAAC;AAC5G,QAAM,CAAC,oBAAoB,qBAAqB,IAAI,SAAkC,CAAC,CAAC;AACxF,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAAkC,CAAC,CAAC;AACtF,QAAM,sBAAsBC,QAAsB,IAAI;AACtD,QAAM,gBAAgB,cAAc,QAAQ,SAAS;AACrD,QAAM,EAAE,aAAa,eAAe,IAAI,yBAAyB,gBAAgB,gBAAgB,YAAY,QAAW,gBAAgB;AAExI,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,iBAAiB;AACpB,0BAAoB,UAAU;AAC9B;AAAA,IACF;AAEA,QAAI,CAAC,iBAAiB,oBAAoB,oBAAoB,SAAS;AACrE;AAAA,IACF;AAEA,UAAM,cAAc,eAAe,UAAU,CAAC,UAAU,MAAM,QAAQ,KAAK,CAAC,UAAU,MAAM,OAAO,eAAe,CAAC;AACnH,QAAI,cAAc,GAAG;AACnB;AAAA,IACF;AAEA,wBAAoB,UAAU;AAE9B,UAAM,UAAU,sBAAsB,MAAM;AAC1C,kBAAY,cAAc,aAAa;AAAA,QACrC,OAAO;AAAA,QACP,UAAU;AAAA,MACZ,CAAC;AAAA,IACH,CAAC;AAED,WAAO,MAAM;AACX,2BAAqB,OAAO;AAAA,IAC9B;AAAA,EACF,GAAG,CAAC,gBAAgB,eAAe,iBAAiB,WAAW,CAAC;AAEhE,EAAAA,WAAU,MAAM;AACd,QAAI,CAAC,iBAAiB,CAAC,WAAW,WAAW,CAAC,eAAe,SAAS;AACpE;AAAA,IACF;AAEA,UAAM,gBAAgB,UAAU;AAChC,UAAM,UAAU,sBAAsB,MAAM;AAC1C,oBAAc,SAAS,EAAE,KAAK,cAAc,aAAa,CAAC;AAAA,IAC5D,CAAC;AAED,WAAO,MAAM;AACX,2BAAqB,OAAO;AAAA,IAC9B;AAAA,EACF,GAAG,CAAC,YAAY,gBAAgB,YAAY,eAAe,WAAW,YAAY,CAAC;AAEnF,QAAM,uBAAuB,CAAC,UAAkB,aAAsB;AACpE,0BAAsB,CAAC,YAAY;AACjC,UAAI,QAAQ,QAAQ,MAAM,UAAU;AAClC,eAAO;AAAA,MACT;AACA,aAAO,EAAE,GAAG,SAAS,CAAC,QAAQ,GAAG,SAAS;AAAA,IAC5C,CAAC;AAAA,EACH;AAEA,QAAM,sBAAsB,CAAC,SAAiB,aAAsB;AAClE,yBAAqB,CAAC,YAAY;AAChC,UAAI,QAAQ,OAAO,MAAM,UAAU;AACjC,eAAO;AAAA,MACT;AACA,aAAO,EAAE,GAAG,SAAS,CAAC,OAAO,GAAG,SAAS;AAAA,IAC3C,CAAC;AAAA,EACH;AAEA,QAAM,cAAc,CAAC,OAAuB,UAAkB;AAC5D,QAAI,MAAM,SAAS,WAAW;AAC5B,YAAMC,SAAQ,MAAM,QAAQ,CAAC;AAC7B,YAAM,QAAQA,OAAM,MAAM,SAAS;AACnC,aACE,qBAAC,SAAmB,WAAW,mBAAmB,SAAS,aAAU,WACnE;AAAA,4BAAC,SAAI,WAAW,mBAAmB,aAAa,aAAU,gBAAe;AAAA,QACzE,oBAAC,UAAK,WAAW,mBAAmB,aAAa,aAAU,gBACxD,iBACH;AAAA,QACA,oBAAC,SAAI,WAAW,mBAAmB,aAAa,aAAU,gBAAe;AAAA,WALjEA,OAAM,EAMhB;AAAA,IAEJ;AAEA,QAAI,MAAM,SAAS,cAAc;AAC/B,YAAM,WAAW,mBAAmB,OAAO,KAAK;AAEhD,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,SAAS,MAAM;AAAA,UACf,UAAU,QAAQ,mBAAmB,QAAQ,CAAC;AAAA,UAC9C,kBAAkB,CAAC,aAAa,qBAAqB,UAAU,QAAQ;AAAA,UACvE,iBAAiB;AAAA,UACjB,0BAA0B;AAAA,UAC1B,YAAY;AAAA,UACZ;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,QAdK;AAAA,MAeP;AAAA,IAEJ;AAEA,QAAI,MAAM,SAAS,cAAc;AAC/B,YAAMA,SAAQ,MAAM,QAAQ,CAAC;AAC7B,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,OAAOA;AAAA,UACP,YAAY;AAAA,UACZ;AAAA,UACA;AAAA,UACA;AAAA;AAAA,QALKA,OAAM;AAAA,MAMb;AAAA,IAEJ;AAEA,UAAM,QAAQ,MAAM,QAAQ,CAAC;AAC7B,UAAM,iBAAiB,kBAAkB,KAAK;AAE9C,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW,GAAG,mBAAmB,SAAS,gBAAgB,WAAW;AAAA,QACrE,aAAU;AAAA,QACV,aAAW,MAAM;AAAA,QACjB,aAAW,MAAM;AAAA,QACjB,gBAAc;AAAA,QACd,iBAAe,MAAM,MAAM;AAAA,QAE3B,8BAAC,SAAI,WAAW,mBAAmB,gBAAgB,aAAU,mBAC1D,gBAAM,OACL,oBAAC,SAAI,WAAW,mBAAmB,aAAa,aAAU,gBACvD,4BAAkB,KAAK,GAC1B,IAEA,oBAAC,UAAK,WAAW,mBAAmB,mBAAmB,aAAU,sBAC9D,uCAA6B,GAChC,GAEJ;AAAA;AAAA,MAlBK,MAAM;AAAA,IAmBb;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAW,GAAG,mBAAmB,MAAM,SAAS,GAAG,aAAU,QAAO,oBAAkB,gBAAgB,SAAS,QACjH;AAAA,oBACC;AAAA,MAAC;AAAA;AAAA,QACC,aAAU;AAAA,QACV,OAAO;AAAA,UACL,QAAQ,GAAG,YAAY,aAAa,CAAC;AAAA,UACrC,UAAU;AAAA,UACV,OAAO;AAAA,QACT;AAAA,QAEC,sBAAY,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;AAClD,gBAAM,QAAQ,eAAe,YAAY,KAAK;AAC9C,cAAI,CAAC,OAAO;AACV,mBAAO;AAAA,UACT;AAEA,iBACE;AAAA,YAAC;AAAA;AAAA,cAEC,cAAY,YAAY;AAAA,cACxB,KAAK,CAAC,SAAS;AACb,oBAAI,MAAM;AACR,8BAAY,eAAe,IAAI;AAAA,gBACjC;AAAA,cACF;AAAA,cACA,OAAO;AAAA,gBACL,MAAM;AAAA,gBACN,UAAU;AAAA,gBACV,KAAK;AAAA,gBACL,WAAW,cAAc,YAAY,KAAK;AAAA,gBAC1C,OAAO;AAAA,cACT;AAAA,cAEA,8BAAC,SAAI,OAAO,EAAE,eAAe,YAAY,UAAU,eAAe,SAAS,IAAI,IAAI,GAAG,oBAAoB,KAAK,GAC5G,sBAAY,OAAO,YAAY,KAAK,GACvC;AAAA;AAAA,YAjBK,mBAAmB,OAAO,YAAY,KAAK;AAAA,UAkBlD;AAAA,QAEJ,CAAC;AAAA;AAAA,IACH,IAEA,eAAe,IAAI,CAAC,OAAO,UAAU,YAAY,OAAO,KAAK,CAAC;AAAA,IAE/D,eACC,oBAAC,SAAI,WAAW,mBAAmB,OAAO,aAAU,SAAQ,eAAY,WACrE,wBACH,IACE;AAAA,IACH,aACC,oBAAC,SAAI,WAAW,mBAAmB,OAAO,aAAU,SAAQ,eAAY,SACrE,sBACH,IACE;AAAA,IACH,aACI,sBAAsB,EAAE,QAAQ,CAAC,KAChC,oBAAC,SAAI,WAAW,mBAAmB,aAAa,aAAU,gBACxD,8BAAC,UAAK,WAAW,mBAAmB,mBAAmB,aAAU,sBAAqB,yBAEtF,GACF,IAEF;AAAA,IACH,CAAC,gBAAgB,oBAAC,SAAI,KAAK,QAAQ,WAAW,mBAAmB,WAAW,aAAU,cAAa,IAAK;AAAA,KAC3G;AAEJ;;;AEr0BM,SAUE,OAAAC,MAVF,QAAAC,aAAA;AAzCN,IAAMC,uBAA8C;AAAA,EAClD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,eAAe;AACjB;AAEA,IAAMC,MAAK,IAAI,WAAqD,OAAO,OAAO,OAAO,EAAE,KAAK,GAAG;AAEnG,IAAMC,mBAAkB,CAAC,UAAkC,eAAyE;AAAA,EAClI,MAAMD,IAAG,SAAS,MAAM,WAAW,IAAI;AAAA,EACvC,MAAMA,IAAG,SAAS,MAAM,WAAW,IAAI;AAAA,EACvC,OAAOA,IAAG,SAAS,OAAO,WAAW,KAAK;AAAA,EAC1C,QAAQA,IAAG,SAAS,QAAQ,WAAW,MAAM;AAAA,EAC7C,eAAeA,IAAG,SAAS,eAAe,WAAW,aAAa;AACpE;AAEO,IAAM,eAAe,CAAC;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AACF,MAAyB;AACvB,QAAM,qBAAqBC,iBAAgBF,sBAAqB,kBAAkB;AAClF,QAAM,mBAAmB,YAAY,kBAAmB,CAAC,oBAAoB,QAAQ,KAAK,EAAE,WAAW;AAEvG,SACE,gBAAAF,KAAC,SAAI,WAAWG,IAAG,mBAAmB,MAAM,SAAS,GAAG,aAAU,QAChE,0BAAAF;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,mBAAmB;AAAA,MAC9B,aAAU;AAAA,MACV,UAAU,CAAC,UAAU;AACnB,cAAM,eAAe;AACrB,YAAI,CAAC,kBAAkB;AACrB,mBAAS;AAAA,QACX;AAAA,MACF;AAAA,MAEA;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACE,GAAG;AAAA,YACJ,KAAK;AAAA,YACL,WAAW,mBAAmB;AAAA,YAC9B,aAAU;AAAA,YACV,iBAAe,WAAW,SAAS;AAAA,YACnC,cAAY,QAAQ,KAAK,EAAE,WAAW,IAAI,SAAS;AAAA,YACnD,OAAO;AAAA,YACP,UAAU,CAAC,UAAU,gBAAgB,MAAM,OAAO,KAAK;AAAA,YACvD;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA;AAAA,QACF;AAAA,QACC,eAAe;AAAA,QAChB,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAW,mBAAmB;AAAA,YAC9B,aAAU;AAAA,YACV,iBAAe,mBAAmB,SAAS;AAAA,YAC3C,UAAU;AAAA,YACV,cAAY;AAAA,YACZ,OAAO;AAAA,YAEP,0BAAAA,KAAC,UAAK,WAAW,mBAAmB,eAAe,aAAU,kBAC1D,gCAAsB,KAAK,aAC9B;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF,GACF;AAEJ;;;ACrDI,SAIQ,OAAAK,MAJR,QAAAC,aAAA;AAjCJ,IAAMC,uBAAmD;AAAA,EACvD,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,UAAU;AACZ;AAEA,IAAMC,MAAK,IAAI,WAAqD,OAAO,OAAO,OAAO,EAAE,KAAK,GAAG;AAEnG,IAAMC,mBAAkB,CAAC,UAAuC,eAAmF;AAAA,EACjJ,MAAMD,IAAG,SAAS,MAAM,WAAW,IAAI;AAAA,EACvC,YAAYA,IAAG,SAAS,YAAY,WAAW,UAAU;AAAA,EACzD,YAAYA,IAAG,SAAS,YAAY,WAAW,UAAU;AAAA,EACzD,UAAUA,IAAG,SAAS,UAAU,WAAW,QAAQ;AACrD;AAEO,IAAM,oBAAoB,CAAC;AAAA,EAChC;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAA8B;AAC5B,QAAM,qBAAqBC,iBAAgBF,sBAAqB,kBAAkB;AAClF,QAAM,uBAAuB,QAAQ,SAAS,KAAK,QAAQ,iBAAiB,YAAY,KAAK,QAAQ,iBAAiB,UAAU;AAEhI,SACE,gBAAAD,MAAC,SAAI,WAAWE,IAAG,mBAAmB,MAAM,SAAS,GAAG,aAAU,QAC/D;AAAA,2BACC,YACE,gBAAAH,KAAC,SAAI,WAAWG,IAAG,mBAAmB,YAAY,mBAAmB,GAAG,aAAU,cAAa,KAAK,WAClG,0BAAAH,KAAC,mBAAgB,SAAkB,YAAY,sBAAuB,GAAG,iBAAiB,GAC5F,IAEA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAWG,IAAG,mBAAmB,YAAY,mBAAmB;AAAA,QAChE,YAAY;AAAA,QACX,GAAG;AAAA;AAAA,IACN,IAEA,aACF,gBAAAH,KAAC,SAAI,WAAW,mBAAmB,YAAY,aAAU,eACtD,sBACH,IACE;AAAA,IACH,gBACC,gBAAAA,KAAC,gBAAa,WAAWG,IAAG,mBAAmB,UAAU,iBAAiB,GAAG,YAAY,oBAAqB,GAAG,eAAe,IAC9H;AAAA,KACN;AAEJ;;;AChFA,SAAS,aAAAE,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AAiQlC,gBAAAC,MACoB,QAAAC,aADpB;AAxOV,IAAM,gBAAgB;AAAA,EACpB,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,qBAAqB;AAAA,EACrB,OAAO;AAAA,EACP,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aAAa;AAAA,EACb,WAAW;AAAA,EACX,aAAa;AAAA,EACb,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,aAAa;AACf;AAEA,IAAM,aAA4B;AAAA,EAChC,SAAS;AAAA,EACT,eAAe;AAAA,EACf,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,YAAY;AACd;AAEA,IAAM,iBAAgC;AAAA,EACpC,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,KAAK;AAAA,EACL,SAAS;AAAA,EACT,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,YAAY;AACd;AAEA,IAAM,gBAA+B;AAAA,EACnC,WAAW;AAAA,EACX,SAAS;AAAA,EACT,UAAU;AACZ;AAEA,IAAM,gBAA+B;AAAA,EACnC,YAAY;AAAA,EACZ,SAAS;AACX;AAEA,IAAM,iBAAiB,CAAC,UAAmC;AACzD,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEO,IAAM,kBAAkB,CAAC;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB;AAAA,EACA;AACF,MAA4B;AAC1B,QAAM,UAAUH,QAA8B,IAAI;AAClD,QAAM,CAAC,iBAAiB,kBAAkB,IAAIC,UAA0B,YAAY;AACpF,QAAM,CAAC,eAAe,gBAAgB,IAAIA,UAAS,sBAAsB;AACzE,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAwB,IAAI;AAE5D,EAAAF,WAAU,MAAM;AACd,QAAI,YAAY;AAChB,QAAI,WAAmC;AACvC,QAAI,WAAmC;AACvC,QAAI,UAA8E;AAClF,QAAI,YAAY;AAChB,QAAI,qBAAiD;AACrD,QAAI,uBAAmD;AAEvD,uBAAmB,YAAY;AAC/B,qBAAiB,sBAAsB;AACvC,gBAAY,IAAI;AAEhB,UAAM,WAAW,MAAM;AACrB,UAAI,CAAC,YAAY,CAAC,SAAS;AACzB;AAAA,MACF;AAEA,cAAQ,OAAO;AAAA,QACb,MAAM,SAAS;AAAA,QACf,MAAM,SAAS;AAAA,MACjB,CAAC;AAAA,IACH;AAEA,UAAM,UAAU,YAAY;AAC1B,UAAI;AACF,cAAM,UAAU,MAAM,OAAO,aAAa;AAC1C,cAAM,QAAQ,KAAK;AAEnB,YAAI,aAAa,CAAC,QAAQ,SAAS;AACjC;AAAA,QACF;AAEA,mBAAW,IAAI,QAAQ,SAAS;AAAA,UAC9B,mBAAmB;AAAA,UACnB,aAAa;AAAA,UACb,aAAa;AAAA,UACb,YAAY;AAAA,UACZ,UAAU;AAAA,UACV,sBAAsB;AAAA,UACtB,OAAO;AAAA,QACT,CAAC;AACD,mBAAW,IAAI,QAAQ,SAAS;AAEhC,iBAAS,KAAK,QAAQ,OAAO;AAC7B,cAAM,eAAe,QAAQ,QAAQ;AACrC,YAAI,wBAAwB,aAAa;AACvC,uBAAa,MAAM,QAAQ;AAC3B,uBAAa,MAAM,SAAS;AAAA,QAC9B;AACA,iBAAS,UAAU,QAAQ;AAC3B,iBAAS,IAAI;AACb,iBAAS,cAAc;AACvB,iBAAS,MAAM;AAEf,6BAAqB,SAAS,OAAO,CAAC,SAAS;AAC7C,mBAAS,UAAU,IAAI;AAAA,QACzB,CAAC;AAED,+BAAuB,SAAS,SAAS,MAAM;AAC7C,cAAI,WAAW;AACb,mBAAO,qBAAqB,SAAS;AAAA,UACvC;AACA,sBAAY,OAAO,sBAAsB,QAAQ;AAAA,QACnD,CAAC;AAED,cAAM,cAAc,OAAO,uBAAuB,SAAS;AAC3D,kBAAU;AAEV,oBAAY,QAAQ,CAAC,UAA+B;AAClD,cAAI,aAAa,MAAM,SAAS,SAAS;AACvC;AAAA,UACF;AAEA,6BAAmB,OAAO;AAC1B,2BAAiB,WAAW;AAC5B,mBAAS;AAAA,QACX,CAAC;AAED,oBAAY,OAAO,CAAC,UAAsB;AACxC,cAAI,aAAa,CAAC,UAAU;AAC1B;AAAA,UACF;AACA,mBAAS,MAAM,KAAK;AAAA,QACtB,CAAC;AAED,oBAAY,OAAO,CAAC,UAA8B;AAChD,cAAI,aAAa,MAAM,SAAS,QAAQ;AACtC;AAAA,UACF;AAEA,6BAAmB,QAAQ;AAC3B,sBAAY,MAAM,YAAY,IAAI;AAClC,2BAAiB,MAAM,YAAY,OAAO,oBAAoB,4BAA4B,MAAM,QAAQ,GAAG;AAC3G,mBAAS,KAAK;AAAA,QAChB,CAAC;AAED,oBAAY,QAAQ,CAAC,UAAuC;AAC1D,cAAI,WAAW;AACb;AAAA,UACF;AAEA,6BAAmB,OAAO;AAC1B,2BAAiB,iBAAiB,QAAQ,MAAM,UAAU,MAAM,OAAO;AACvE,oBAAU,KAAK;AAAA,QACjB,CAAC;AAED,oBAAY,QAAQ,MAAM;AACxB,cAAI,WAAW;AACb;AAAA,UACF;AAEA,6BAAmB,CAAC,YAAa,YAAY,UAAU,UAAU,QAAS;AAC1E,2BAAiB,CAAC,YAAa,YAAY,cAAc,2BAA2B,OAAQ;AAAA,QAC9F,CAAC;AAAA,MACH,SAAS,OAAO;AACd,YAAI,WAAW;AACb;AAAA,QACF;AAEA,cAAM,YAAY,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,gCAAgC;AAC7F,2BAAmB,OAAO;AAC1B,yBAAiB,UAAU,OAAO;AAClC,kBAAU,SAAS;AAAA,MACrB;AAAA,IACF;AAEA,SAAK,QAAQ;AAEb,WAAO,MAAM;AACX,kBAAY;AACZ,UAAI,WAAW;AACb,eAAO,qBAAqB,SAAS;AAAA,MACvC;AACA,0BAAoB,QAAQ;AAC5B,4BAAsB,QAAQ;AAC9B,eAAS,MAAM;AACf,gBAAU,QAAQ;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,QAAQ,SAAS,CAAC;AAEvC,SACE,gBAAAI,MAAC,SAAI,WAAsB,OAAO,EAAE,GAAG,YAAY,GAAG,MAAM,GACzD;AAAA,oBACC,gBAAAA,MAAC,SAAI,OAAO,EAAE,GAAG,gBAAgB,GAAG,uBAAuB,GACzD;AAAA,sBAAAD,KAAC,UAAK,OAAO,EAAE,OAAO,eAAe,eAAe,EAAE,GAAI,yBAAc;AAAA,MACvE,YAAY,OAAO,gBAAAC,MAAC,UAAK,OAAO,eAAe;AAAA;AAAA,QAAM;AAAA,SAAS,IAAU;AAAA,OAC3E,IACE;AAAA,IACJ,gBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAK;AAAA,QACL,OAAO;AAAA,UACL,GAAG;AAAA,UACH;AAAA,UACA,GAAG;AAAA,QACL;AAAA,QACA,SAAS,MAAM;AACb,kBAAQ,SAAS,cAAc,UAAU,GAAG,MAAM;AAAA,QACpD;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":["useEffect","useRef","useRef","useEffect","entry","jsx","jsxs","DEFAULT_CLASS_NAMES","cx","mergeClassNames","jsx","jsxs","DEFAULT_CLASS_NAMES","cx","mergeClassNames","useEffect","useRef","useState","jsx","jsxs"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sandbox-agent/react",
3
- "version": "0.3.1",
3
+ "version": "0.4.0-rc.1",
4
4
  "description": "React components for Sandbox Agent frontend integrations",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -24,6 +24,7 @@
24
24
  "sandbox-agent": "^0.2.2"
25
25
  },
26
26
  "dependencies": {
27
+ "@tanstack/react-virtual": "^3.13.22",
27
28
  "ghostty-web": "^0.4.0"
28
29
  },
29
30
  "devDependencies": {
@@ -31,7 +32,7 @@
31
32
  "react": "^18.3.1",
32
33
  "tsup": "^8.0.0",
33
34
  "typescript": "^5.7.0",
34
- "sandbox-agent": "0.3.1"
35
+ "sandbox-agent": "0.4.0-rc.1"
35
36
  },
36
37
  "scripts": {
37
38
  "build": "tsup",