@tangle-network/sandbox-ui 0.137.2 → 0.138.0

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.
@@ -4,7 +4,7 @@ import * as React$1 from "react";
4
4
  import { createPortal } from "react-dom";
5
5
  import { Bot, Brain, Check, ChevronDown, Lock, Pencil, Plus, Send, Sparkles, Square, Trash2, X } from "lucide-react";
6
6
  import { focusField, focusRing } from "@tangle-network/ui/utils";
7
- import { AgentTimeline, ChatContainer as ChatContainer$1, ChatMessage, ChatMessage as ChatMessage$1, MessageAuthor, MessageList, TRANSCRIPT_TEXT, ThinkingIndicator, UserMessage, isViewerMessage } from "@tangle-network/ui/chat";
7
+ import { AgentTimeline as AgentTimeline$1, ChatContainer as ChatContainer$1, ChatMessage, ChatMessage as ChatMessage$1, MessageAuthor, MessageList, TRANSCRIPT_TEXT, ThinkingIndicator, UserMessage, isViewerMessage } from "@tangle-network/ui/chat";
8
8
  import { modelProvider, reasoningLadder, snapHarnessToModel } from "@tangle-network/agent-interface";
9
9
  import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
10
10
  // src/chat/reasoning-level-picker.tsx
@@ -862,4 +862,4 @@ function ArtifactAgentDock({ scope, open, onOpenChange, transport, defaultPrompt
862
862
  ]
863
863
  });
864
864
  }
865
- export { MessageList as a, UserMessage as c, modelProvider as d, snapHarnessToModel as f, ReasoningLevelPicker as g, HARNESS_REASONING_OPTIONS as h, MessageAuthor as i, isViewerMessage as l, DEFAULT_REASONING_LEVEL_OPTIONS as m, ChatContainer$1 as n, TRANSCRIPT_TEXT as o, AgentProfilePicker as p, ChatMessage$1 as r, ThinkingIndicator as s, AgentTimeline as t, ArtifactAgentDock as u };
865
+ export { MessageList as a, UserMessage as c, modelProvider as d, snapHarnessToModel as f, ReasoningLevelPicker as g, HARNESS_REASONING_OPTIONS as h, MessageAuthor as i, isViewerMessage as l, DEFAULT_REASONING_LEVEL_OPTIONS as m, ChatContainer$1 as n, TRANSCRIPT_TEXT as o, AgentProfilePicker as p, ChatMessage$1 as r, ThinkingIndicator as s, AgentTimeline$1 as t, ArtifactAgentDock as u };
package/dist/chat.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { A as ArtifactDockMessage, B as AgentProfilePickerProps, C as ThinkingIndicatorProps, D as ArtifactAgentDock, E as isViewerMessage, F as snapHarnessToModel, G as ReasoningLevelPicker, H as HARNESS_REASONING_OPTIONS, I as AgentProfileCapability, K as ReasoningLevelPickerProps, L as AgentProfileDraft, M as ArtifactKind, N as ArtifactScope, O as ArtifactAgentDockProps, P as modelProvider, R as AgentProfileOption, S as ThinkingIndicator, T as UserMessageProps, U as ReasoningLevel, V as DEFAULT_REASONING_LEVEL_OPTIONS, W as ReasoningLevelOption, _ as MessageAuthorProps, a as AgentTimelineMessageItem, b as MessageRole, c as AgentTimelineTone, d as ChatAuthor, f as ChatContainer, g as MessageAuthor, h as ChatMessageProps, i as AgentTimelineItem, j as ArtifactDockStreamEvent, k as ArtifactAgentDockTransport, l as AgentTimelineToolGroupItem, m as ChatMessage, n as AgentTimelineArtifactItem, o as AgentTimelineProps, p as ChatContainerProps, r as AgentTimelineCustomItem, s as AgentTimelineStatusItem, t as AgentTimeline, u as AgentTimelineToolItem, v as MessageList, w as UserMessage, x as TRANSCRIPT_TEXT, y as MessageListProps, z as AgentProfilePicker } from "./index-4KFqFK1f.js";
1
+ import { A as ArtifactDockMessage, B as AgentProfilePickerProps, C as ThinkingIndicatorProps, D as ArtifactAgentDock, E as isViewerMessage, F as snapHarnessToModel, G as ReasoningLevelPicker, H as HARNESS_REASONING_OPTIONS, I as AgentProfileCapability, K as ReasoningLevelPickerProps, L as AgentProfileDraft, M as ArtifactKind, N as ArtifactScope, O as ArtifactAgentDockProps, P as modelProvider, R as AgentProfileOption, S as ThinkingIndicator, T as UserMessageProps, U as ReasoningLevel, V as DEFAULT_REASONING_LEVEL_OPTIONS, W as ReasoningLevelOption, _ as MessageAuthorProps, a as AgentTimelineMessageItem, b as MessageRole, c as AgentTimelineTone, d as ChatAuthor, f as ChatContainer, g as MessageAuthor, h as ChatMessageProps, i as AgentTimelineItem, j as ArtifactDockStreamEvent, k as ArtifactAgentDockTransport, l as AgentTimelineToolGroupItem, m as ChatMessage, n as AgentTimelineArtifactItem, o as AgentTimelineProps, p as ChatContainerProps, r as AgentTimelineCustomItem, s as AgentTimelineStatusItem, t as AgentTimeline, u as AgentTimelineToolItem, v as MessageList, w as UserMessage, x as TRANSCRIPT_TEXT, y as MessageListProps, z as AgentProfilePicker } from "./index-ucJHuuVZ.js";
2
2
  export { type AgentProfileCapability, type AgentProfileDraft, type AgentProfileOption, AgentProfilePicker, type AgentProfilePickerProps, AgentTimeline, type AgentTimelineArtifactItem, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, ArtifactAgentDock, type ArtifactAgentDockProps, type ArtifactAgentDockTransport, type ArtifactDockMessage, type ArtifactDockStreamEvent, type ArtifactKind, type ArtifactScope, type ChatAuthor, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, DEFAULT_REASONING_LEVEL_OPTIONS, HARNESS_REASONING_OPTIONS, MessageAuthor, type MessageAuthorProps, MessageList, type MessageListProps, type MessageRole, type ReasoningLevel, type ReasoningLevelOption, ReasoningLevelPicker, type ReasoningLevelPickerProps, TRANSCRIPT_TEXT, ThinkingIndicator, type ThinkingIndicatorProps, UserMessage, type UserMessageProps, isViewerMessage, modelProvider, snapHarnessToModel };
package/dist/chat.js CHANGED
@@ -1 +1 @@
1
- export { p as AgentProfilePicker, t as AgentTimeline, u as ArtifactAgentDock, n as ChatContainer, r as ChatMessage, m as DEFAULT_REASONING_LEVEL_OPTIONS, h as HARNESS_REASONING_OPTIONS, i as MessageAuthor, a as MessageList, g as ReasoningLevelPicker, o as TRANSCRIPT_TEXT, s as ThinkingIndicator, c as UserMessage, l as isViewerMessage, d as modelProvider, f as snapHarnessToModel } from "./chat-Cw13rqn9.js";
1
+ export { p as AgentProfilePicker, t as AgentTimeline, u as ArtifactAgentDock, n as ChatContainer, r as ChatMessage, m as DEFAULT_REASONING_LEVEL_OPTIONS, h as HARNESS_REASONING_OPTIONS, i as MessageAuthor, a as MessageList, g as ReasoningLevelPicker, o as TRANSCRIPT_TEXT, s as ThinkingIndicator, c as UserMessage, l as isViewerMessage, d as modelProvider, f as snapHarnessToModel } from "./chat-BYTVLZQW.js";
@@ -0,0 +1,287 @@
1
+ import { t as cn } from "./utils-BER_bdgE.js";
2
+ import { Button } from "@tangle-network/ui/primitives";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import * as React$1 from "react";
5
+ import { File, FileDiff, getSingularPatch } from "@pierre/diffs";
6
+ import { createTwoFilesPatch, diffLines } from "diff";
7
+ // src/workbench/syntax.tsx
8
+ /** The one code theme: CodeSurface and DiffView share @pierre/diffs' Shiki highlighter and these themes. */
9
+ const CODE_THEME = {
10
+ dark: "github-dark",
11
+ light: "github-light"
12
+ };
13
+ const CODE_FONT_FAMILY = "var(--font-mono, \"Geist Mono\", \"JetBrains Mono\", ui-monospace, monospace)";
14
+ const CONTAINER_TAG = "diffs-container";
15
+ /** Follow the host's Brand theme (`data-theme` or the `light` class on <html>) unless the caller fixes one. */
16
+ function useHostThemeType(explicit) {
17
+ const read = () => {
18
+ if (typeof document === "undefined") return "dark";
19
+ const root = document.documentElement;
20
+ return root.getAttribute("data-theme") === "light" || root.classList.contains("light") ? "light" : "dark";
21
+ };
22
+ const [host, setHost] = React$1.useState(read);
23
+ React$1.useEffect(() => {
24
+ if (explicit) return;
25
+ setHost(read());
26
+ const observer = new MutationObserver(() => setHost(read()));
27
+ observer.observe(document.documentElement, {
28
+ attributes: true,
29
+ attributeFilter: ["class", "data-theme"]
30
+ });
31
+ return () => observer.disconnect();
32
+ }, [explicit]);
33
+ return explicit ?? host;
34
+ }
35
+ /**
36
+ * Read-only code renderer on @pierre/diffs' `File`, the same Shiki highlighter and theme as DiffView. A new
37
+ * custom element per render survives StrictMode remounts; the surrounding element owns scrolling.
38
+ */
39
+ function CodeSurface({ code, filename, language, showLineNumbers = true, wrap = false, line, themeType, className }) {
40
+ const theme = useHostThemeType(themeType);
41
+ const hostRef = React$1.useRef(null);
42
+ const instanceRef = React$1.useRef(null);
43
+ const containerRef = React$1.useRef(null);
44
+ const latestTheme = React$1.useRef(theme);
45
+ const appliedTheme = React$1.useRef(theme);
46
+ const pendingLine = React$1.useRef(line);
47
+ React$1.useLayoutEffect(() => {
48
+ latestTheme.current = theme;
49
+ }, [theme]);
50
+ const reveal = React$1.useCallback(() => {
51
+ const target = pendingLine.current;
52
+ const element = target ? containerRef.current?.shadowRoot?.querySelector(`[data-line="${target}"]`) : null;
53
+ if (!target || !element) return;
54
+ pendingLine.current = void 0;
55
+ instanceRef.current?.setSelectedLines({
56
+ start: target,
57
+ end: target
58
+ });
59
+ element.scrollIntoView({ block: "center" });
60
+ }, []);
61
+ React$1.useLayoutEffect(() => {
62
+ const host = hostRef.current;
63
+ if (host == null) return;
64
+ const container = document.createElement(CONTAINER_TAG);
65
+ container.style.setProperty("--diffs-font-family", CODE_FONT_FAMILY);
66
+ container.style.display = "block";
67
+ container.style.minWidth = "0";
68
+ container.style.maxWidth = "100%";
69
+ host.appendChild(container);
70
+ containerRef.current = container;
71
+ const instance = new File({
72
+ theme: CODE_THEME,
73
+ themeType: latestTheme.current,
74
+ overflow: wrap ? "wrap" : "scroll",
75
+ disableFileHeader: true,
76
+ disableLineNumbers: !showLineNumbers,
77
+ onPostRender: () => reveal()
78
+ });
79
+ instanceRef.current = instance;
80
+ appliedTheme.current = latestTheme.current;
81
+ instance.render({
82
+ file: {
83
+ name: filename,
84
+ contents: code,
85
+ ...language ? { lang: language } : {}
86
+ },
87
+ fileContainer: container
88
+ });
89
+ return () => {
90
+ if (instanceRef.current === instance) instanceRef.current = null;
91
+ instance.cleanUp();
92
+ container.remove();
93
+ };
94
+ }, [
95
+ code,
96
+ filename,
97
+ language,
98
+ showLineNumbers,
99
+ wrap,
100
+ reveal
101
+ ]);
102
+ React$1.useLayoutEffect(() => {
103
+ if (appliedTheme.current === theme) return;
104
+ instanceRef.current?.setThemeType(theme);
105
+ appliedTheme.current = theme;
106
+ }, [theme]);
107
+ React$1.useLayoutEffect(() => {
108
+ pendingLine.current = line;
109
+ reveal();
110
+ }, [line, reveal]);
111
+ return /* @__PURE__ */ jsx("div", {
112
+ ref: hostRef,
113
+ "data-code-surface": "",
114
+ role: "region",
115
+ "aria-label": filename,
116
+ tabIndex: 0,
117
+ className,
118
+ style: {
119
+ height: "100%",
120
+ minWidth: 0,
121
+ overflow: "auto",
122
+ fontSize: "var(--code-font-size, 0.8125rem)"
123
+ }
124
+ });
125
+ }
126
+ // src/workbench/diff-utils.ts
127
+ /**
128
+ * Count added / removed lines between two file revisions.
129
+ *
130
+ * Ported from blueprint-agent's `computeDiffStats`: normalize CRLF, short-
131
+ * circuit on equality, then `diffLines` with `ignoreWhitespace` so pure
132
+ * reindentation does not inflate the counts. `newlineIsToken:false` keeps a
133
+ * line (not its trailing newline) as the unit, matching the +/- a reader
134
+ * counts by eye.
135
+ */
136
+ function computeDiffStats(original, current) {
137
+ if (original === current) return {
138
+ added: 0,
139
+ removed: 0
140
+ };
141
+ const a = original.replace(/\r\n/g, "\n");
142
+ const b = current.replace(/\r\n/g, "\n");
143
+ if (a === b) return {
144
+ added: 0,
145
+ removed: 0
146
+ };
147
+ const changes = diffLines(a, b, {
148
+ newlineIsToken: false,
149
+ ignoreWhitespace: true
150
+ });
151
+ let added = 0;
152
+ let removed = 0;
153
+ for (const part of changes) {
154
+ if (!part.added && !part.removed) continue;
155
+ const count = part.count ?? part.value.split("\n").length;
156
+ if (part.added) added += count;
157
+ else if (part.removed) removed += count;
158
+ }
159
+ return {
160
+ added,
161
+ removed
162
+ };
163
+ }
164
+ /**
165
+ * Build a single-file unified patch (baseline → current) for `@pierre/diffs`'
166
+ * `PatchDiff`. `context: Infinity` would print the whole file; the default
167
+ * 4-line context keeps hunks compact while preserving locality. Equal inputs
168
+ * yield an empty string so callers can treat "" as "no diff".
169
+ */
170
+ function buildUnifiedPatch(filename, baseline, current) {
171
+ if (baseline === current) return "";
172
+ return createTwoFilesPatch(filename, filename, baseline, current, "", "");
173
+ }
174
+ // src/workbench/diff-view.tsx
175
+ const DIFF_OPTIONS = {
176
+ diffStyle: "unified",
177
+ diffIndicators: "classic",
178
+ lineDiffType: "word",
179
+ hunkSeparators: "simple",
180
+ expandUnchanged: false,
181
+ theme: CODE_THEME,
182
+ stickyHeader: true
183
+ };
184
+ const DIFF_CONTAINER_TAG = "diffs-container";
185
+ /**
186
+ * Keep the maintained renderer for hunking, word diffs and highlighting. A new
187
+ * custom element per effect survives StrictMode remounts without hydrating stale
188
+ * shadow content. Wrapping is a renderer option, not a CSS patch into its shadow
189
+ * root; the plain patch disclosure is the accessible, engine-independent view.
190
+ */
191
+ function DiffView({ filename, baseline, current, showFileHeader = true, defaultWrap = true, themeType = "dark", className }) {
192
+ const patch = React$1.useMemo(() => buildUnifiedPatch(filename, baseline, current), [
193
+ filename,
194
+ baseline,
195
+ current
196
+ ]);
197
+ const [wrap, setWrap] = React$1.useState(defaultWrap);
198
+ const hostRef = React$1.useRef(null);
199
+ const instanceRef = React$1.useRef(null);
200
+ const latestThemeType = React$1.useRef(themeType);
201
+ const appliedThemeType = React$1.useRef(themeType);
202
+ React$1.useLayoutEffect(() => {
203
+ latestThemeType.current = themeType;
204
+ }, [themeType]);
205
+ React$1.useLayoutEffect(() => {
206
+ const host = hostRef.current;
207
+ if (host == null || !patch) return;
208
+ const container = document.createElement(DIFF_CONTAINER_TAG);
209
+ container.style.setProperty("--diffs-font-family", CODE_FONT_FAMILY);
210
+ container.style.display = "block";
211
+ container.style.minWidth = "0";
212
+ container.style.maxWidth = "100%";
213
+ host.appendChild(container);
214
+ const instance = new FileDiff({
215
+ ...DIFF_OPTIONS,
216
+ themeType: latestThemeType.current,
217
+ overflow: wrap ? "wrap" : "scroll",
218
+ disableFileHeader: !showFileHeader
219
+ }, void 0);
220
+ instanceRef.current = instance;
221
+ appliedThemeType.current = latestThemeType.current;
222
+ instance.hydrate({
223
+ fileDiff: getSingularPatch(patch),
224
+ fileContainer: container
225
+ });
226
+ return () => {
227
+ if (instanceRef.current === instance) instanceRef.current = null;
228
+ instance.cleanUp();
229
+ container.remove();
230
+ };
231
+ }, [
232
+ patch,
233
+ showFileHeader,
234
+ wrap
235
+ ]);
236
+ React$1.useLayoutEffect(() => {
237
+ if (appliedThemeType.current === themeType) return;
238
+ instanceRef.current?.setThemeType(themeType);
239
+ appliedThemeType.current = themeType;
240
+ }, [themeType]);
241
+ if (!patch) return /* @__PURE__ */ jsx("div", {
242
+ className: cn("flex h-full min-w-0 items-center justify-center bg-surface-container", className),
243
+ children: /* @__PURE__ */ jsx("p", {
244
+ className: "text-sm text-muted-foreground",
245
+ children: "No changes — baseline and working copy are identical."
246
+ })
247
+ });
248
+ return /* @__PURE__ */ jsxs("div", {
249
+ className: cn("flex h-full min-h-0 min-w-0 max-w-full flex-col overflow-hidden bg-surface-container", className),
250
+ children: [
251
+ /* @__PURE__ */ jsx("div", {
252
+ className: "flex shrink-0 flex-wrap items-center gap-2 border-b border-border px-3 py-2",
253
+ children: /* @__PURE__ */ jsx(Button, {
254
+ type: "button",
255
+ variant: "outline",
256
+ size: "sm",
257
+ "aria-pressed": wrap,
258
+ onClick: () => setWrap((value) => !value),
259
+ children: "Wrap lines"
260
+ })
261
+ }),
262
+ /* @__PURE__ */ jsx("div", {
263
+ ref: hostRef,
264
+ "data-testid": "diff-view",
265
+ role: "region",
266
+ "aria-label": `Diff for ${filename}`,
267
+ tabIndex: 0,
268
+ className: "min-h-0 min-w-0 max-w-full flex-1 overflow-auto text-[13px]"
269
+ }),
270
+ /* @__PURE__ */ jsxs("details", {
271
+ className: "max-h-[40%] shrink-0 overflow-auto border-t border-border",
272
+ children: [/* @__PURE__ */ jsx("summary", {
273
+ className: "cursor-pointer px-3 py-2 text-sm",
274
+ children: "Read plain-text diff"
275
+ }), /* @__PURE__ */ jsx("pre", {
276
+ role: "region",
277
+ tabIndex: 0,
278
+ "aria-label": `Plain-text diff for ${filename}`,
279
+ className: "m-0 whitespace-pre-wrap p-3 font-mono text-xs leading-relaxed",
280
+ style: { overflowWrap: "anywhere" },
281
+ children: patch
282
+ })]
283
+ })
284
+ ]
285
+ });
286
+ }
287
+ export { CodeSurface as a, CODE_THEME as i, buildUnifiedPatch as n, computeDiffStats as r, DiffView as t };
@@ -0,0 +1,21 @@
1
+ import * as React$1 from "react";
2
+ interface DiffViewProps {
3
+ filename: string;
4
+ baseline: string;
5
+ current: string;
6
+ /** Hide when the surrounding PanelHeader already identifies the file. */
7
+ showFileHeader?: boolean;
8
+ /** Start wrapped so narrow review panes never conceal the end of a line. */
9
+ defaultWrap?: boolean;
10
+ /** Match the host app's selected theme. Defaults to dark for existing consumers. */
11
+ themeType?: "light" | "dark";
12
+ className?: string;
13
+ }
14
+ /**
15
+ * Keep the maintained renderer for hunking, word diffs and highlighting. A new
16
+ * custom element per effect survives StrictMode remounts without hydrating stale
17
+ * shadow content. Wrapping is a renderer option, not a CSS patch into its shadow
18
+ * root; the plain patch disclosure is the accessible, engine-independent view.
19
+ */
20
+ declare function DiffView({ filename, baseline, current, showFileHeader, defaultWrap, themeType, className }: DiffViewProps): React$1.JSX.Element;
21
+ export { DiffViewProps as n, DiffView as t };
package/dist/globals.css CHANGED
@@ -397,6 +397,9 @@
397
397
  .bottom-2 {
398
398
  bottom: calc(var(--spacing) * 2);
399
399
  }
400
+ .bottom-3 {
401
+ bottom: calc(var(--spacing) * 3);
402
+ }
400
403
  .bottom-4 {
401
404
  bottom: calc(var(--spacing) * 4);
402
405
  }
@@ -958,6 +961,9 @@
958
961
  .h-\[36rem\] {
959
962
  height: 36rem;
960
963
  }
964
+ .h-\[70vh\] {
965
+ height: 70vh;
966
+ }
961
967
  .h-\[72\%\] {
962
968
  height: 72%;
963
969
  }
@@ -1171,6 +1177,9 @@
1171
1177
  .min-h-\[66px\] {
1172
1178
  min-height: 66px;
1173
1179
  }
1180
+ .min-h-\[70vh\] {
1181
+ min-height: 70vh;
1182
+ }
1174
1183
  .min-h-\[72px\] {
1175
1184
  min-height: 72px;
1176
1185
  }
@@ -1465,6 +1474,9 @@
1465
1474
  .max-w-40 {
1466
1475
  max-width: calc(var(--spacing) * 40);
1467
1476
  }
1477
+ .max-w-48 {
1478
+ max-width: calc(var(--spacing) * 48);
1479
+ }
1468
1480
  .max-w-72 {
1469
1481
  max-width: calc(var(--spacing) * 72);
1470
1482
  }
@@ -2103,6 +2115,9 @@
2103
2115
  .self-start {
2104
2116
  align-self: flex-start;
2105
2117
  }
2118
+ .self-stretch {
2119
+ align-self: stretch;
2120
+ }
2106
2121
  .justify-self-start {
2107
2122
  justify-self: flex-start;
2108
2123
  }
@@ -2274,6 +2289,10 @@
2274
2289
  border-bottom-style: var(--tw-border-style);
2275
2290
  border-bottom-width: 1px;
2276
2291
  }
2292
+ .border-b-0 {
2293
+ border-bottom-style: var(--tw-border-style);
2294
+ border-bottom-width: 0px;
2295
+ }
2277
2296
  .border-b-2 {
2278
2297
  border-bottom-style: var(--tw-border-style);
2279
2298
  border-bottom-width: 2px;
@@ -2709,6 +2728,9 @@
2709
2728
  .bg-\[var\(--status-running\)\] {
2710
2729
  background-color: var(--status-running);
2711
2730
  }
2731
+ .bg-\[var\(--status-running\,\#34c48c\)\] {
2732
+ background-color: var(--status-running,#34c48c);
2733
+ }
2712
2734
  .bg-\[var\(--surface-danger-bg\)\] {
2713
2735
  background-color: var(--surface-danger-bg);
2714
2736
  }
@@ -2940,6 +2962,12 @@
2940
2962
  background-color: color-mix(in oklab, hsl(var(--muted-foreground)) 40%, transparent);
2941
2963
  }
2942
2964
  }
2965
+ .bg-muted-foreground\/50 {
2966
+ background-color: hsl(var(--muted-foreground));
2967
+ @supports (color: color-mix(in lab, red, red)) {
2968
+ background-color: color-mix(in oklab, hsl(var(--muted-foreground)) 50%, transparent);
2969
+ }
2970
+ }
2943
2971
  .bg-muted\/10 {
2944
2972
  background-color: hsl(var(--muted));
2945
2973
  @supports (color: color-mix(in lab, red, red)) {
@@ -4432,6 +4460,9 @@
4432
4460
  --tw-translate-x: calc(var(--spacing) * 0.5);
4433
4461
  translate: var(--tw-translate-x) var(--tw-translate-y);
4434
4462
  }
4463
+ .group-hover\:bg-primary:is(:where(.group):hover *) {
4464
+ background-color: hsl(var(--primary));
4465
+ }
4435
4466
  .group-hover\:bg-primary\/20:is(:where(.group):hover *) {
4436
4467
  background-color: hsl(var(--primary));
4437
4468
  }
@@ -4467,6 +4498,9 @@
4467
4498
  opacity: 100%;
4468
4499
  }
4469
4500
  }
4501
+ .group-focus-visible\:bg-primary:is(:where(.group):focus-visible *) {
4502
+ background-color: hsl(var(--primary));
4503
+ }
4470
4504
  .group-focus-visible\:bg-primary\/30:is(:where(.group):focus-visible *) {
4471
4505
  background-color: hsl(var(--primary));
4472
4506
  @supports (color: color-mix(in lab, red, red)) {
@@ -4600,6 +4634,9 @@
4600
4634
  border-color: color-mix(in oklab, hsl(var(--accent)) 50%, transparent);
4601
4635
  }
4602
4636
  }
4637
+ .hover\:border-border:hover {
4638
+ border-color: hsl(var(--border));
4639
+ }
4603
4640
  .hover\:border-destructive\/30:hover {
4604
4641
  border-color: hsl(var(--destructive));
4605
4642
  }
@@ -5111,6 +5148,9 @@
5111
5148
  .focus-visible\:text-foreground:focus-visible {
5112
5149
  color: hsl(var(--foreground));
5113
5150
  }
5151
+ .focus-visible\:underline:focus-visible {
5152
+ text-decoration-line: underline;
5153
+ }
5114
5154
  .focus-visible\:opacity-100:focus-visible {
5115
5155
  opacity: 100%;
5116
5156
  }
@@ -6149,6 +6189,9 @@
6149
6189
  .\[\&\:not\(\:first-child\)\]\:pt-3:not(:first-child) {
6150
6190
  padding-top: calc(var(--spacing) * 3);
6151
6191
  }
6192
+ .\[\&\>\*\]\:min-h-full > * {
6193
+ min-height: 100%;
6194
+ }
6152
6195
  .\[\&\>\*\]\:max-w-full > * {
6153
6196
  max-width: 100%;
6154
6197
  }
@@ -0,0 +1,91 @@
1
+ import { ReactNode } from "react";
2
+ import { ApprovalCard, ApprovalCardProps, ApprovalDiffFile, ApprovalDiffSummary, ApprovalPlanStep, ExpandedToolDetail, ExpandedToolDetailProps, FeedSegment, InlineThinkingItem as InlineThinkingItem$1, InlineThinkingItemProps, InlineToolItem, InlineToolItemProps, LiveDuration, RunGroup, RunGroupProps, RunPhase, RunPhaseList, RunRowShell, RunRowShellProps, RunRowStatus, RunRowStatusDot, TaskList, TaskListItem, TaskListProps, TaskStatus, ToolCallData, ToolCallData as ToolCallData$1, ToolCallFeed, ToolCallFeedProps, ToolCallStatus, ToolCallType, parseToolEvent, showsTaskPriority, taskProgress, taskStatus } from "@tangle-network/ui/run";
3
+ import { FlowWaterfallProps } from "@tangle-network/charts/react";
4
+ import { FlowMarker, FlowSpan, FlowTrace } from "@tangle-network/charts";
5
+ /** Agent and model spans show their lab/host mark; tool spans show their provider's mark. Unknown keeps the kind glyph. */
6
+ declare function traceSpanMark(span: FlowSpan): ReactNode;
7
+ type TraceWaterfallProps = FlowWaterfallProps;
8
+ /**
9
+ * The run inspector: the agent timeline (`defaultView="agents"`) and the span waterfall over one clock, from
10
+ * `@tangle-network/charts`, with Sandbox UI's brand marks. Feed it `otlpFlowTrace(spans)` from the
11
+ * `traces convert` contract. Import `@tangle-network/charts/react/flow-waterfall.css` once.
12
+ */
13
+ declare function TraceWaterfall({ renderIcon, ...props }: TraceWaterfallProps): import("react").JSX.Element;
14
+ /** A moment on the run's event track: a release, a check verdict, a spawn, a crash or a steer. */
15
+ interface TraceEvent extends FlowMarker {}
16
+ interface TraceWorkspaceProps extends Omit<TraceWaterfallProps, "trace" | "markers" | "onSelect" | "onTimeChange" | "selectedId" | "onDeselect"> {
17
+ trace: FlowTrace;
18
+ /** The selected agent's message stream (Server-Sent Events: rows, reset, end; reconnects with ?after=lastSeq). */
19
+ streamUrl?: (agentId: string) => string;
20
+ events?: TraceEvent[];
21
+ /** The time the reader moved to, in trace ms; null while following live or showing the whole run. */
22
+ onTimeChange?: (t: number | null) => void;
23
+ /**
24
+ * The code workspace as of the cursor and scoped to the selected agent, usually a WorkspaceFilesPane: the page answers
25
+ * the as-of query. It spans the full width and at least 70% of the viewport. Keep its key on the commit so a scrub
26
+ * keeps its state.
27
+ */
28
+ files?: ReactNode;
29
+ /** The scoreboard as of the cursor, under the code workspace; omitted when not given. */
30
+ scoreboard?: ReactNode;
31
+ selectedAgentId?: string;
32
+ /** Called with the agent the reader selected, or undefined when they close its drawer or press Escape. */
33
+ onSelectAgent?: (agentId: string | undefined) => void;
34
+ className?: string;
35
+ }
36
+ /**
37
+ * The run workspace: the agent timeline and span waterfall over one clock, the selected agent's conversation
38
+ * streaming in a right-hand drawer, and the page's code workspace and scoreboard following the time cursor. Scrubbing is time travel:
39
+ * every panel shows what was true at the cursor, and the conversation shows what had been said by then.
40
+ */
41
+ declare function TraceWorkspace({ trace, streamUrl, events, onTimeChange, files, scoreboard, selectedAgentId, onSelectAgent, className, ...waterfall }: TraceWorkspaceProps): import("react").JSX.Element;
42
+ /** One row of an agent's message stream (tangle-tools `/api/discovery/runs/<run>/agents/<agent>/stream`). */
43
+ interface AgentStreamRow {
44
+ seq: number;
45
+ /** ISO time the event happened. */
46
+ at: string;
47
+ stream?: string;
48
+ attempt?: number;
49
+ event: {
50
+ kind: "text" | "reasoning" | "tool-call" | "tool-result" | "user" | (string & {});
51
+ text?: string;
52
+ toolCallId?: string;
53
+ toolName?: string;
54
+ args?: unknown;
55
+ result?: unknown;
56
+ };
57
+ }
58
+ /** A transcript entry with the time it began, so a time cursor can show the conversation as of any moment. */
59
+ type AgentTranscriptEntry = {
60
+ id: string;
61
+ at: number;
62
+ kind: "message";
63
+ role: "assistant" | "user";
64
+ content: string;
65
+ } | {
66
+ id: string;
67
+ at: number;
68
+ kind: "reasoning";
69
+ text: string;
70
+ } | {
71
+ id: string;
72
+ at: number;
73
+ kind: "tool";
74
+ call: ToolCallData;
75
+ };
76
+ interface AgentStreamState {
77
+ generation?: string | number;
78
+ entries: AgentTranscriptEntry[];
79
+ lastSeq: number;
80
+ /** The agent is still producing output. */
81
+ alive: boolean;
82
+ error?: string;
83
+ }
84
+ /** Fold stream rows into transcript entries: text of one turn merges, a tool call becomes a row its result completes. */
85
+ declare function foldAgentRows(entries: AgentTranscriptEntry[], rows: readonly AgentStreamRow[]): AgentTranscriptEntry[];
86
+ /**
87
+ * Follow one agent's message stream over Server-Sent Events: `rows`, `reset` and `end` events, reconnecting with
88
+ * `?after=<lastSeq>` when the server closes the connection, so a long turn streams without gaps or repeats.
89
+ */
90
+ declare function useAgentStream(url: string | undefined): AgentStreamState;
91
+ export { ToolCallType as A, TraceEvent as B, TaskListItem as C, ToolCallFeed as D, ToolCallData$1 as E, AgentStreamRow as F, traceSpanMark as G, TraceWorkspaceProps as H, AgentStreamState as I, AgentTranscriptEntry as L, showsTaskPriority as M, taskProgress as N, ToolCallFeedProps as O, taskStatus as P, foldAgentRows as R, TaskList as S, TaskStatus as T, TraceWaterfall as U, TraceWorkspace as V, TraceWaterfallProps as W, RunPhaseList as _, ApprovalPlanStep as a, RunRowStatus as b, FeedSegment as c, InlineToolItem as d, InlineToolItemProps as f, RunPhase as g, RunGroupProps as h, ApprovalDiffSummary as i, parseToolEvent as j, ToolCallStatus as k, InlineThinkingItem$1 as l, RunGroup as m, ApprovalCardProps as n, ExpandedToolDetail as o, LiveDuration as p, ApprovalDiffFile as r, ExpandedToolDetailProps as s, ApprovalCard as t, InlineThinkingItemProps as u, RunRowShell as v, TaskListProps as w, RunRowStatusDot as x, RunRowShellProps as y, useAgentStream as z };
@@ -1,5 +1,6 @@
1
1
  import { g as ExposedPort } from "./index-DRDtTgb0.js";
2
2
  import { D as RichFileTreeGitStatus, E as RichFileTreeGitEntry } from "./index-BoHOpP2_.js";
3
+ import "./diff-view-DDHWtR6X.js";
3
4
  import { a as PreviewReadiness, i as PreviewAccess } from "./embedded-app-view-Ta5GI4hx.js";
4
5
  import * as React$1 from "react";
5
6
  import { CSSProperties } from "react";
@@ -230,6 +231,10 @@ interface CodeViewProps {
230
231
  onFileSelect?: (path: string) => void;
231
232
  /** Show the file-tree rail. Off for single-file embeds where the host owns navigation. */
232
233
  showTree?: boolean;
234
+ /** Start with long lines wrapped. */
235
+ defaultWrap?: boolean;
236
+ /** Defaults to the host's Brand theme. */
237
+ themeType?: "light" | "dark";
233
238
  className?: string;
234
239
  }
235
240
  /**
@@ -238,26 +243,7 @@ interface CodeViewProps {
238
243
  * view. The rail owns navigation; selecting a path fans out to `onFileSelect`
239
244
  * so the host can swap the active artifact.
240
245
  */
241
- declare function CodeView({ path, filename, content, language, paths, gitStatus, onFileSelect, showTree, className }: CodeViewProps): React$1.JSX.Element;
242
- interface DiffViewProps {
243
- filename: string;
244
- baseline: string;
245
- current: string;
246
- /** Hide when the surrounding PanelHeader already identifies the file. */
247
- showFileHeader?: boolean;
248
- /** Start wrapped so narrow review panes never conceal the end of a line. */
249
- defaultWrap?: boolean;
250
- /** Match the host app's selected theme. Defaults to dark for existing consumers. */
251
- themeType?: "light" | "dark";
252
- className?: string;
253
- }
254
- /**
255
- * Keep the maintained renderer for hunking, word diffs and highlighting. A new
256
- * custom element per effect survives StrictMode remounts without hydrating stale
257
- * shadow content. Wrapping is a renderer option, not a CSS patch into its shadow
258
- * root; the plain patch disclosure is the accessible, engine-independent view.
259
- */
260
- declare function DiffView({ filename, baseline, current, showFileHeader, defaultWrap, themeType, className }: DiffViewProps): React$1.JSX.Element;
246
+ declare function CodeView({ path, filename, content, language, paths, gitStatus, onFileSelect, showTree, defaultWrap, themeType, className }: CodeViewProps): React$1.JSX.Element;
261
247
  interface PreviewViewProps {
262
248
  /** A product-authorized preview URL. Relative navigation stays on its origin. */
263
249
  url: string;
@@ -276,20 +262,29 @@ interface PreviewViewProps {
276
262
  className?: string;
277
263
  }
278
264
  declare function PreviewView({ url, allowedOrigins, access, readiness, onCheckReadiness, onNavigate, variant, title, toolbarActions, className }: PreviewViewProps): React$1.JSX.Element;
279
- /** Resolve a Prism language id from an explicit hint or the filename. */
280
- declare function resolveLanguage(filename: string, explicit?: string): string;
281
- declare const BRAND_PRISM_THEME: Record<string, CSSProperties>;
265
+ /** The one code theme: CodeSurface and DiffView share @pierre/diffs' Shiki highlighter and these themes. */
266
+ declare const CODE_THEME: {
267
+ readonly dark: "github-dark";
268
+ readonly light: "github-light";
269
+ };
282
270
  interface CodeSurfaceProps {
283
271
  code: string;
272
+ /** Names the file and picks its grammar: every Shiki language, loaded on first use. */
284
273
  filename: string;
274
+ /** A Shiki language id that overrides the filename, such as `rust` for a file without an extension. */
285
275
  language?: string;
286
276
  showLineNumbers?: boolean;
277
+ /** Wrap long lines inside the pane instead of scrolling sideways. */
278
+ wrap?: boolean;
279
+ /** A 1-based line to select and scroll into view. */
280
+ line?: number;
281
+ /** Defaults to the host's Brand theme. */
282
+ themeType?: "light" | "dark";
287
283
  className?: string;
288
284
  }
289
285
  /**
290
- * Read-only, brand-themed code renderer. Wrapped in a scroll container so the
291
- * highlighter itself never grows the layout; line numbers sit in a muted,
292
- * tabular column.
286
+ * Read-only code renderer on @pierre/diffs' `File`, the same Shiki highlighter and theme as DiffView. A new
287
+ * custom element per render survives StrictMode remounts; the surrounding element owns scrolling.
293
288
  */
294
- declare function CodeSurface({ code, filename, language, showLineNumbers, className }: CodeSurfaceProps): React$1.JSX.Element;
295
- export { SandboxArtifactTerminal as A, ChangesPane as C, ChangesPaneProps as D, ChangedFile as E, SandboxArtifact as O, PillTabsProps as S, ArtifactView as T, DiffStats as _, PreviewView as a, PillTabItem as b, DiffViewProps as c, FileBreadcrumb as d, FileBreadcrumbProps as f, PanelHeaderProps as g, PanelHeader as h, resolveLanguage as i, SandboxArtifactPaneProps as k, CodeView as l, GitStatusBadge as m, CodeSurface as n, PreviewViewProps as o, DiffStatsBadge as p, CodeSurfaceProps as r, DiffView as s, BRAND_PRISM_THEME as t, CodeViewProps as u, buildUnifiedPatch as v, SandboxArtifactPane as w, PillTabs as x, computeDiffStats as y };
289
+ declare function CodeSurface({ code, filename, language, showLineNumbers, wrap, line, themeType, className }: CodeSurfaceProps): React$1.JSX.Element;
290
+ export { ChangedFile as C, SandboxArtifactTerminal as D, SandboxArtifactPaneProps as E, ArtifactView as S, SandboxArtifact as T, PillTabItem as _, PreviewViewProps as a, ChangesPane as b, FileBreadcrumb as c, GitStatusBadge as d, PanelHeader as f, computeDiffStats as g, buildUnifiedPatch as h, PreviewView as i, FileBreadcrumbProps as l, DiffStats as m, CodeSurface as n, CodeView as o, PanelHeaderProps as p, CodeSurfaceProps as r, CodeViewProps as s, CODE_THEME as t, DiffStatsBadge as u, PillTabs as v, ChangesPaneProps as w, SandboxArtifactPane as x, PillTabsProps as y };