@tangle-network/sandbox-ui 0.62.0 → 0.64.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.
- package/dist/chat.d.ts +14 -1
- package/dist/chat.js +1 -1
- package/dist/{chunk-R72QYE2U.js → chunk-2E3FJM56.js} +160 -44
- package/dist/{chunk-J36F6LD2.js → chunk-G4YJYSFA.js} +1 -1
- package/dist/{chunk-OQZQFSWM.js → chunk-QSCCNGXZ.js} +44 -17
- package/dist/dashboard.d.ts +22 -1
- package/dist/dashboard.js +1 -1
- package/dist/globals.css +23 -46
- package/dist/index.js +3 -3
- package/dist/styles.css +23 -46
- package/dist/workbench.js +2 -2
- package/package.json +1 -1
package/dist/chat.d.ts
CHANGED
|
@@ -124,8 +124,21 @@ interface AgentSessionHarnessControl {
|
|
|
124
124
|
* switch harness.
|
|
125
125
|
*/
|
|
126
126
|
locked?: boolean;
|
|
127
|
-
/** Tooltip shown on the locked trigger. */
|
|
127
|
+
/** Tooltip shown on the locked trigger when no `onNewChat` is provided. */
|
|
128
128
|
lockReason?: string;
|
|
129
|
+
/**
|
|
130
|
+
* Fork action for a locked harness. When provided, the locked trigger turns
|
|
131
|
+
* into an informative chip: hover or tap opens a small popover explaining the
|
|
132
|
+
* lock and offering a button that calls this to start a fresh session. When
|
|
133
|
+
* omitted, the locked trigger stays a plain inert button with `lockReason`.
|
|
134
|
+
*/
|
|
135
|
+
onNewChat?: () => void;
|
|
136
|
+
/** Popover heading. Defaults to `Agent fixed to {harness} for this conversation.` */
|
|
137
|
+
lockTitle?: React.ReactNode;
|
|
138
|
+
/** Popover sub-line. Defaults to "Conversations stay on one agent." */
|
|
139
|
+
lockBody?: React.ReactNode;
|
|
140
|
+
/** Fork button label. Defaults to "New chat to switch agent". */
|
|
141
|
+
newChatLabel?: string;
|
|
129
142
|
}
|
|
130
143
|
interface AgentSessionModelControl {
|
|
131
144
|
/** Canonical model id (provider-prefixed, e.g. "anthropic/claude-opus-4-8"). */
|
package/dist/chat.js
CHANGED
|
@@ -156,7 +156,24 @@ import {
|
|
|
156
156
|
reasoningEffortsFor
|
|
157
157
|
} from "@tangle-network/agent-interface";
|
|
158
158
|
import * as DropdownMenu2 from "@radix-ui/react-dropdown-menu";
|
|
159
|
-
import { ChevronDown as ChevronDown3, Lock, SlidersHorizontal } from "lucide-react";
|
|
159
|
+
import { ChevronDown as ChevronDown3, Lock, Plus as Plus2, SlidersHorizontal } from "lucide-react";
|
|
160
|
+
import * as React3 from "react";
|
|
161
|
+
|
|
162
|
+
// src/lib/use-click-outside.ts
|
|
163
|
+
import * as React from "react";
|
|
164
|
+
function useClickOutside(onOutside) {
|
|
165
|
+
const ref = React.useRef(null);
|
|
166
|
+
React.useEffect(() => {
|
|
167
|
+
function handler(event) {
|
|
168
|
+
if (ref.current && !ref.current.contains(event.target)) {
|
|
169
|
+
onOutside();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
document.addEventListener("mousedown", handler);
|
|
173
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
174
|
+
}, [onOutside]);
|
|
175
|
+
return ref;
|
|
176
|
+
}
|
|
160
177
|
|
|
161
178
|
// src/chat/harness-model-compat.ts
|
|
162
179
|
import {
|
|
@@ -173,21 +190,8 @@ function snapModelToHarness(harness, modelId, models) {
|
|
|
173
190
|
|
|
174
191
|
// src/chat/agent-profile-picker.tsx
|
|
175
192
|
import { Bot, Check, ChevronDown as ChevronDown2, Pencil, Plus, Trash2 } from "lucide-react";
|
|
176
|
-
import * as
|
|
193
|
+
import * as React2 from "react";
|
|
177
194
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
178
|
-
function useClickOutside(onOutside) {
|
|
179
|
-
const ref = React.useRef(null);
|
|
180
|
-
React.useEffect(() => {
|
|
181
|
-
function handler(event) {
|
|
182
|
-
if (ref.current && !ref.current.contains(event.target)) {
|
|
183
|
-
onOutside();
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
document.addEventListener("mousedown", handler);
|
|
187
|
-
return () => document.removeEventListener("mousedown", handler);
|
|
188
|
-
}, [onOutside]);
|
|
189
|
-
return ref;
|
|
190
|
-
}
|
|
191
195
|
function profileSubtitle(profile) {
|
|
192
196
|
if (profile.description) return profile.description;
|
|
193
197
|
const count = profile.capabilities?.length ?? 0;
|
|
@@ -205,8 +209,8 @@ function AgentProfilePicker({
|
|
|
205
209
|
className,
|
|
206
210
|
side = "top"
|
|
207
211
|
}) {
|
|
208
|
-
const [open, setOpen] =
|
|
209
|
-
const [composing, setComposing] =
|
|
212
|
+
const [open, setOpen] = React2.useState(false);
|
|
213
|
+
const [composing, setComposing] = React2.useState(
|
|
210
214
|
null
|
|
211
215
|
);
|
|
212
216
|
const ref = useClickOutside(() => {
|
|
@@ -373,11 +377,11 @@ function ProfileForm({
|
|
|
373
377
|
onCancel,
|
|
374
378
|
onSave
|
|
375
379
|
}) {
|
|
376
|
-
const [name, setName] =
|
|
377
|
-
const [caps, setCaps] =
|
|
380
|
+
const [name, setName] = React2.useState(initial?.name ?? "");
|
|
381
|
+
const [caps, setCaps] = React2.useState(
|
|
378
382
|
initial?.capabilities ? [...initial.capabilities] : capabilities.map((c) => c.id)
|
|
379
383
|
);
|
|
380
|
-
const [instructions, setInstructions] =
|
|
384
|
+
const [instructions, setInstructions] = React2.useState(initial?.instructions ?? "");
|
|
381
385
|
const toggle = (id) => setCaps(
|
|
382
386
|
(prev) => prev.includes(id) ? prev.filter((c) => c !== id) : [...prev, id]
|
|
383
387
|
);
|
|
@@ -466,6 +470,102 @@ function selectorIgnoreNote(harness) {
|
|
|
466
470
|
if (ignoresEffort) return "Ignores reasoning effort";
|
|
467
471
|
return null;
|
|
468
472
|
}
|
|
473
|
+
function InformativeLock({
|
|
474
|
+
label,
|
|
475
|
+
lockTitle,
|
|
476
|
+
lockBody,
|
|
477
|
+
newChatLabel,
|
|
478
|
+
onNewChat
|
|
479
|
+
}) {
|
|
480
|
+
const [open, setOpen] = React3.useState(false);
|
|
481
|
+
const closeTimer = React3.useRef(null);
|
|
482
|
+
const ref = useClickOutside(() => setOpen(false));
|
|
483
|
+
const cancelClose = React3.useCallback(() => {
|
|
484
|
+
if (closeTimer.current) {
|
|
485
|
+
clearTimeout(closeTimer.current);
|
|
486
|
+
closeTimer.current = null;
|
|
487
|
+
}
|
|
488
|
+
}, []);
|
|
489
|
+
const scheduleClose = React3.useCallback(() => {
|
|
490
|
+
cancelClose();
|
|
491
|
+
closeTimer.current = setTimeout(() => setOpen(false), 150);
|
|
492
|
+
}, [cancelClose]);
|
|
493
|
+
React3.useEffect(() => cancelClose, [cancelClose]);
|
|
494
|
+
return /* @__PURE__ */ jsxs3(
|
|
495
|
+
"div",
|
|
496
|
+
{
|
|
497
|
+
ref,
|
|
498
|
+
className: "relative inline-flex",
|
|
499
|
+
onMouseEnter: () => {
|
|
500
|
+
cancelClose();
|
|
501
|
+
setOpen(true);
|
|
502
|
+
},
|
|
503
|
+
onMouseLeave: scheduleClose,
|
|
504
|
+
onKeyDown: (event) => {
|
|
505
|
+
if (event.key === "Escape") setOpen(false);
|
|
506
|
+
},
|
|
507
|
+
children: [
|
|
508
|
+
/* @__PURE__ */ jsxs3(
|
|
509
|
+
"button",
|
|
510
|
+
{
|
|
511
|
+
type: "button",
|
|
512
|
+
onClick: () => setOpen(true),
|
|
513
|
+
"data-state": open ? "open" : "closed",
|
|
514
|
+
"aria-label": "Agent harness (locked)",
|
|
515
|
+
"aria-haspopup": "dialog",
|
|
516
|
+
"aria-expanded": open,
|
|
517
|
+
className: cn(
|
|
518
|
+
"inline-flex h-8 items-center gap-1.5 rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container px-2.5",
|
|
519
|
+
"text-xs font-medium text-foreground shadow-sm transition-colors",
|
|
520
|
+
"hover:border-[var(--md3-outline-variant)] hover:bg-surface-container-high focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
521
|
+
"data-[state=open]:border-[var(--md3-outline-variant)] data-[state=open]:bg-surface-container-high"
|
|
522
|
+
),
|
|
523
|
+
children: [
|
|
524
|
+
/* @__PURE__ */ jsx3(Lock, { className: "h-3 w-3 text-muted-foreground" }),
|
|
525
|
+
/* @__PURE__ */ jsx3("span", { children: label })
|
|
526
|
+
]
|
|
527
|
+
}
|
|
528
|
+
),
|
|
529
|
+
open && /* @__PURE__ */ jsxs3(
|
|
530
|
+
"div",
|
|
531
|
+
{
|
|
532
|
+
role: "dialog",
|
|
533
|
+
className: cn(
|
|
534
|
+
"absolute bottom-full left-0 z-50 mb-2 w-72 rounded-[var(--radius-md)] border border-[var(--md3-outline-variant)] bg-surface-container-highest p-3",
|
|
535
|
+
"shadow-[0_8px_30px_rgba(0,0,0,0.45)] ring-1 ring-[#ffffff14]"
|
|
536
|
+
),
|
|
537
|
+
children: [
|
|
538
|
+
/* @__PURE__ */ jsxs3("p", { className: "flex items-start gap-2 text-sm font-medium text-foreground", children: [
|
|
539
|
+
/* @__PURE__ */ jsx3(Lock, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
|
|
540
|
+
/* @__PURE__ */ jsx3("span", { children: lockTitle ?? `Agent fixed to ${label} for this conversation.` })
|
|
541
|
+
] }),
|
|
542
|
+
/* @__PURE__ */ jsx3("p", { className: "mt-1.5 text-xs text-muted-foreground", children: lockBody ?? "Conversations stay on one agent." }),
|
|
543
|
+
/* @__PURE__ */ jsxs3(
|
|
544
|
+
"button",
|
|
545
|
+
{
|
|
546
|
+
type: "button",
|
|
547
|
+
onClick: () => {
|
|
548
|
+
setOpen(false);
|
|
549
|
+
onNewChat();
|
|
550
|
+
},
|
|
551
|
+
className: cn(
|
|
552
|
+
"mt-3 flex w-full items-center justify-center gap-1.5 rounded-md px-2.5 py-2 text-sm font-medium text-foreground",
|
|
553
|
+
"bg-primary/10 ring-1 ring-inset ring-primary/25 transition-colors",
|
|
554
|
+
"hover:bg-primary/15 focus:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
|
555
|
+
),
|
|
556
|
+
children: [
|
|
557
|
+
/* @__PURE__ */ jsx3(Plus2, { className: "h-4 w-4" }),
|
|
558
|
+
newChatLabel ?? "New chat to switch agent"
|
|
559
|
+
]
|
|
560
|
+
}
|
|
561
|
+
)
|
|
562
|
+
]
|
|
563
|
+
}
|
|
564
|
+
)
|
|
565
|
+
]
|
|
566
|
+
}
|
|
567
|
+
);
|
|
568
|
+
}
|
|
469
569
|
function HarnessDropdown({
|
|
470
570
|
value,
|
|
471
571
|
onChange,
|
|
@@ -473,6 +573,10 @@ function HarnessDropdown({
|
|
|
473
573
|
disabled,
|
|
474
574
|
locked,
|
|
475
575
|
lockReason,
|
|
576
|
+
onNewChat,
|
|
577
|
+
lockTitle,
|
|
578
|
+
lockBody,
|
|
579
|
+
newChatLabel,
|
|
476
580
|
side = "bottom",
|
|
477
581
|
align = "start",
|
|
478
582
|
avoidCollisions
|
|
@@ -482,6 +586,18 @@ function HarnessDropdown({
|
|
|
482
586
|
);
|
|
483
587
|
const options = HARNESS_OPTIONS.filter((h) => allowed.has(h.type));
|
|
484
588
|
const selected = options.find((option) => option.type === value);
|
|
589
|
+
if (locked && onNewChat) {
|
|
590
|
+
return /* @__PURE__ */ jsx3(
|
|
591
|
+
InformativeLock,
|
|
592
|
+
{
|
|
593
|
+
label: selected?.label ?? value,
|
|
594
|
+
lockTitle,
|
|
595
|
+
lockBody,
|
|
596
|
+
newChatLabel,
|
|
597
|
+
onNewChat
|
|
598
|
+
}
|
|
599
|
+
);
|
|
600
|
+
}
|
|
485
601
|
return /* @__PURE__ */ jsxs3(DropdownMenu2.Root, { children: [
|
|
486
602
|
/* @__PURE__ */ jsx3(DropdownMenu2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs3(
|
|
487
603
|
"button",
|
|
@@ -785,7 +901,7 @@ import {
|
|
|
785
901
|
Upload,
|
|
786
902
|
X
|
|
787
903
|
} from "lucide-react";
|
|
788
|
-
import * as
|
|
904
|
+
import * as React4 from "react";
|
|
789
905
|
import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
790
906
|
function AgentComposer({
|
|
791
907
|
value,
|
|
@@ -816,22 +932,22 @@ function AgentComposer({
|
|
|
816
932
|
sendLabel = "Send",
|
|
817
933
|
autoFocus
|
|
818
934
|
}) {
|
|
819
|
-
const textareaRef =
|
|
820
|
-
const fileInputRef =
|
|
821
|
-
const folderInputRef =
|
|
822
|
-
const [dragOver, setDragOver] =
|
|
823
|
-
const dragDepth =
|
|
824
|
-
const resize =
|
|
935
|
+
const textareaRef = React4.useRef(null);
|
|
936
|
+
const fileInputRef = React4.useRef(null);
|
|
937
|
+
const folderInputRef = React4.useRef(null);
|
|
938
|
+
const [dragOver, setDragOver] = React4.useState(false);
|
|
939
|
+
const dragDepth = React4.useRef(0);
|
|
940
|
+
const resize = React4.useCallback(
|
|
825
941
|
(el) => {
|
|
826
942
|
el.style.height = "auto";
|
|
827
943
|
el.style.height = `${Math.min(el.scrollHeight, maxHeight)}px`;
|
|
828
944
|
},
|
|
829
945
|
[maxHeight]
|
|
830
946
|
);
|
|
831
|
-
|
|
947
|
+
React4.useEffect(() => {
|
|
832
948
|
if (textareaRef.current) resize(textareaRef.current);
|
|
833
949
|
}, [value, resize]);
|
|
834
|
-
|
|
950
|
+
React4.useEffect(() => {
|
|
835
951
|
if (!focusShortcut || disabled) return;
|
|
836
952
|
function onKeyDown(event) {
|
|
837
953
|
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "l") {
|
|
@@ -1070,7 +1186,7 @@ function AgentComposer({
|
|
|
1070
1186
|
}
|
|
1071
1187
|
|
|
1072
1188
|
// src/chat/artifact-agent-dock.tsx
|
|
1073
|
-
import * as
|
|
1189
|
+
import * as React5 from "react";
|
|
1074
1190
|
import { Sparkles as Sparkles2, Send, Square as Square2, X as X2 } from "lucide-react";
|
|
1075
1191
|
import { ChatMessage } from "@tangle-network/ui/chat";
|
|
1076
1192
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
@@ -1119,23 +1235,23 @@ function ArtifactAgentDock({
|
|
|
1119
1235
|
onError,
|
|
1120
1236
|
className
|
|
1121
1237
|
}) {
|
|
1122
|
-
const [threadId, setThreadId] =
|
|
1123
|
-
const [messages, setMessages] =
|
|
1124
|
-
const [composer, setComposer] =
|
|
1125
|
-
const [streamContent, setStreamContent] =
|
|
1126
|
-
const [sending, setSending] =
|
|
1127
|
-
const [loading, setLoading] =
|
|
1128
|
-
const abortRef =
|
|
1129
|
-
const scrollRef =
|
|
1130
|
-
const scopeTokenRef =
|
|
1131
|
-
const reportError =
|
|
1238
|
+
const [threadId, setThreadId] = React5.useState(null);
|
|
1239
|
+
const [messages, setMessages] = React5.useState([]);
|
|
1240
|
+
const [composer, setComposer] = React5.useState(defaultPrompt ?? "");
|
|
1241
|
+
const [streamContent, setStreamContent] = React5.useState("");
|
|
1242
|
+
const [sending, setSending] = React5.useState(false);
|
|
1243
|
+
const [loading, setLoading] = React5.useState(false);
|
|
1244
|
+
const abortRef = React5.useRef(null);
|
|
1245
|
+
const scrollRef = React5.useRef(null);
|
|
1246
|
+
const scopeTokenRef = React5.useRef(0);
|
|
1247
|
+
const reportError = React5.useCallback(
|
|
1132
1248
|
(message) => {
|
|
1133
1249
|
if (onError) onError(message);
|
|
1134
1250
|
else if (typeof console !== "undefined") console.error("[ArtifactAgentDock]", message);
|
|
1135
1251
|
},
|
|
1136
1252
|
[onError]
|
|
1137
1253
|
);
|
|
1138
|
-
|
|
1254
|
+
React5.useEffect(() => {
|
|
1139
1255
|
if (!open) return;
|
|
1140
1256
|
scopeTokenRef.current += 1;
|
|
1141
1257
|
abortRef.current?.abort();
|
|
@@ -1171,11 +1287,11 @@ function ArtifactAgentDock({
|
|
|
1171
1287
|
cancelled = true;
|
|
1172
1288
|
};
|
|
1173
1289
|
}, [open, scope.kind, scope.key, transport, reportError]);
|
|
1174
|
-
|
|
1290
|
+
React5.useEffect(() => {
|
|
1175
1291
|
if (!scrollRef.current) return;
|
|
1176
1292
|
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
|
|
1177
1293
|
}, [messages.length, streamContent]);
|
|
1178
|
-
const send =
|
|
1294
|
+
const send = React5.useCallback(async () => {
|
|
1179
1295
|
const text = composer.trim();
|
|
1180
1296
|
if (!text || !threadId || sending) return;
|
|
1181
1297
|
const token = scopeTokenRef.current;
|
|
@@ -1225,7 +1341,7 @@ function ArtifactAgentDock({
|
|
|
1225
1341
|
if (abortRef.current === controller) abortRef.current = null;
|
|
1226
1342
|
}
|
|
1227
1343
|
}, [composer, threadId, sending, transport, reportError]);
|
|
1228
|
-
const cancel =
|
|
1344
|
+
const cancel = React5.useCallback(() => {
|
|
1229
1345
|
if (threadId && transport.cancel) {
|
|
1230
1346
|
try {
|
|
1231
1347
|
void Promise.resolve(transport.cancel({ threadId })).catch(() => {
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
DropdownMenuTrigger
|
|
23
23
|
} from "@tangle-network/ui/primitives";
|
|
24
24
|
import { Skeleton, useTheme } from "@tangle-network/ui/primitives";
|
|
25
|
-
import { Check, Monitor, PanelLeft } from "lucide-react";
|
|
25
|
+
import { Check, Monitor, MoreHorizontal, PanelLeft } from "lucide-react";
|
|
26
26
|
|
|
27
27
|
// src/dashboard/sidebar-context.tsx
|
|
28
28
|
import * as React from "react";
|
|
@@ -564,13 +564,17 @@ function RailExpandable({
|
|
|
564
564
|
loadSubItems,
|
|
565
565
|
activeSubIds,
|
|
566
566
|
emptyLabel = "Nothing here yet",
|
|
567
|
+
defaultOpen,
|
|
567
568
|
onNavigate,
|
|
568
569
|
LinkComponent,
|
|
569
570
|
className
|
|
570
571
|
}) {
|
|
571
572
|
const Link = LinkComponent ?? DefaultLink;
|
|
572
|
-
const [open, setOpen] = React3.useState(false);
|
|
573
|
+
const [open, setOpen] = React3.useState(defaultOpen ?? false);
|
|
573
574
|
const { items, loading, ensureLoaded } = useExpandableItems(subItems, loadSubItems);
|
|
575
|
+
React3.useEffect(() => {
|
|
576
|
+
if (defaultOpen) ensureLoaded();
|
|
577
|
+
}, [defaultOpen, ensureLoaded]);
|
|
574
578
|
const activeSet = React3.useMemo(() => new Set(activeSubIds ?? []), [activeSubIds]);
|
|
575
579
|
const triggerRef = React3.useRef(null);
|
|
576
580
|
const closeTimer = React3.useRef(null);
|
|
@@ -581,7 +585,7 @@ function RailExpandable({
|
|
|
581
585
|
const subLink = (item) => {
|
|
582
586
|
const FIcon = item.icon;
|
|
583
587
|
const active = activeSet.has(item.id);
|
|
584
|
-
|
|
588
|
+
const link = /* @__PURE__ */ jsxs2(
|
|
585
589
|
Link,
|
|
586
590
|
{
|
|
587
591
|
href: item.href,
|
|
@@ -589,8 +593,8 @@ function RailExpandable({
|
|
|
589
593
|
onClick: onNavigate,
|
|
590
594
|
...item.prefetch !== void 0 ? { prefetch: item.prefetch } : {},
|
|
591
595
|
className: cn(
|
|
592
|
-
"flex
|
|
593
|
-
active ? "bg-[var(--accent-surface-strong)] font-medium text-[var(--accent-text)]" : "text-muted-foreground hover:bg-[var(--accent-surface-soft)] hover:text-foreground"
|
|
596
|
+
"flex min-w-0 flex-1 items-center gap-2 rounded-md px-2.5 text-[12px] transition-colors",
|
|
597
|
+
active ? "h-7 bg-[var(--accent-surface-strong)] font-medium text-[var(--accent-text)]" : item.emphasis ? "py-2 font-medium text-[var(--accent-text)] hover:underline" : "h-7 text-muted-foreground hover:bg-[var(--accent-surface-soft)] hover:text-foreground"
|
|
594
598
|
),
|
|
595
599
|
children: [
|
|
596
600
|
FIcon ? /* @__PURE__ */ jsx3(FIcon, { className: "h-4 w-4 shrink-0" }) : null,
|
|
@@ -601,16 +605,41 @@ function RailExpandable({
|
|
|
601
605
|
...item.isLoading ? { role: "status", "aria-label": "Agent responding" } : {},
|
|
602
606
|
children: item.label
|
|
603
607
|
}
|
|
604
|
-
)
|
|
605
|
-
item.isLoading ? /* @__PURE__ */ jsxs2("span", { className: "responding-ellipsis", "aria-hidden": "true", children: [
|
|
606
|
-
/* @__PURE__ */ jsx3("span", {}),
|
|
607
|
-
/* @__PURE__ */ jsx3("span", {}),
|
|
608
|
-
/* @__PURE__ */ jsx3("span", {})
|
|
609
|
-
] }) : null
|
|
608
|
+
)
|
|
610
609
|
]
|
|
611
610
|
},
|
|
612
611
|
item.id
|
|
613
612
|
);
|
|
613
|
+
if (!showLabel || !item.actions?.length) return link;
|
|
614
|
+
return /* @__PURE__ */ jsxs2("div", { className: "group/sub relative flex items-center", children: [
|
|
615
|
+
link,
|
|
616
|
+
/* @__PURE__ */ jsxs2(DropdownMenu, { children: [
|
|
617
|
+
/* @__PURE__ */ jsx3(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(
|
|
618
|
+
"button",
|
|
619
|
+
{
|
|
620
|
+
type: "button",
|
|
621
|
+
"aria-label": "Chat actions",
|
|
622
|
+
className: "absolute right-1 flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-[var(--accent-surface-soft)] text-muted-foreground opacity-0 transition hover:text-foreground focus-visible:opacity-100 group-hover/sub:opacity-100 data-[state=open]:bg-[var(--accent-surface-strong)] data-[state=open]:opacity-100",
|
|
623
|
+
children: /* @__PURE__ */ jsx3(MoreHorizontal, { className: "h-3.5 w-3.5" })
|
|
624
|
+
}
|
|
625
|
+
) }),
|
|
626
|
+
/* @__PURE__ */ jsx3(DropdownMenuContent, { align: "end", className: "w-40", children: item.actions.map((action) => /* @__PURE__ */ jsxs2(
|
|
627
|
+
DropdownMenuItem,
|
|
628
|
+
{
|
|
629
|
+
onSelect: action.onSelect,
|
|
630
|
+
className: cn(
|
|
631
|
+
"gap-2",
|
|
632
|
+
action.destructive && "text-destructive focus:text-destructive"
|
|
633
|
+
),
|
|
634
|
+
children: [
|
|
635
|
+
action.icon ? /* @__PURE__ */ jsx3(action.icon, { className: "h-3.5 w-3.5" }) : null,
|
|
636
|
+
action.label
|
|
637
|
+
]
|
|
638
|
+
},
|
|
639
|
+
action.id
|
|
640
|
+
)) })
|
|
641
|
+
] })
|
|
642
|
+
] }, item.id);
|
|
614
643
|
};
|
|
615
644
|
const list = loading ? /* @__PURE__ */ jsx3(SubItemsSkeleton, {}) : items && items.length > 0 ? items.map(subLink) : /* @__PURE__ */ jsx3("p", { className: "px-2.5 py-1.5 text-xs text-muted-foreground", children: emptyLabel });
|
|
616
645
|
if (!showLabel) {
|
|
@@ -719,18 +748,15 @@ function RailExpandable({
|
|
|
719
748
|
/* @__PURE__ */ jsx3(
|
|
720
749
|
Icon,
|
|
721
750
|
{
|
|
722
|
-
className:
|
|
723
|
-
"h-[17px] w-[17px] shrink-0 transition-opacity duration-150",
|
|
724
|
-
open ? "opacity-0" : "opacity-100 group-hover/exp:opacity-0"
|
|
725
|
-
)
|
|
751
|
+
className: "h-[17px] w-[17px] shrink-0 opacity-100 transition-opacity duration-150 group-hover/exp:opacity-0"
|
|
726
752
|
}
|
|
727
753
|
),
|
|
728
754
|
/* @__PURE__ */ jsx3(
|
|
729
755
|
ChevronRightIcon,
|
|
730
756
|
{
|
|
731
757
|
className: cn(
|
|
732
|
-
"absolute h-4 w-4 transition-all duration-150",
|
|
733
|
-
open
|
|
758
|
+
"absolute h-4 w-4 opacity-0 transition-all duration-150 group-hover/exp:opacity-100",
|
|
759
|
+
open && "rotate-90"
|
|
734
760
|
)
|
|
735
761
|
}
|
|
736
762
|
)
|
|
@@ -2368,6 +2394,7 @@ function SidebarLayoutInner({
|
|
|
2368
2394
|
loadSubItems: item.loadSubItems,
|
|
2369
2395
|
activeSubIds: item.subActiveIds,
|
|
2370
2396
|
emptyLabel: item.emptyLabel,
|
|
2397
|
+
defaultOpen: item.defaultOpen,
|
|
2371
2398
|
onNavigate: handleNavClick,
|
|
2372
2399
|
LinkComponent
|
|
2373
2400
|
},
|
package/dist/dashboard.d.ts
CHANGED
|
@@ -174,6 +174,17 @@ interface RailFlyoutProps {
|
|
|
174
174
|
* related destinations without permanently spending rail height on them.
|
|
175
175
|
*/
|
|
176
176
|
declare function RailFlyout({ icon: Icon, label, isActive, showLabel, title, children, className, }: RailFlyoutProps): react_jsx_runtime.JSX.Element;
|
|
177
|
+
/** A single entry in a sub-item's hover actions menu (kebab). */
|
|
178
|
+
interface RailSubItemAction {
|
|
179
|
+
id: string;
|
|
180
|
+
label: string;
|
|
181
|
+
icon?: React.ComponentType<{
|
|
182
|
+
className?: string;
|
|
183
|
+
}>;
|
|
184
|
+
/** Style the item as a destructive action (e.g. delete). */
|
|
185
|
+
destructive?: boolean;
|
|
186
|
+
onSelect: () => void;
|
|
187
|
+
}
|
|
177
188
|
/** A sub-destination revealed by a {@link RailExpandable} item. */
|
|
178
189
|
interface RailExpandableSubItem {
|
|
179
190
|
id: string;
|
|
@@ -185,6 +196,12 @@ interface RailExpandableSubItem {
|
|
|
185
196
|
prefetch?: "none" | "intent" | "render" | "viewport";
|
|
186
197
|
/** Show a live working indicator on the row while the item is busy. */
|
|
187
198
|
isLoading?: boolean;
|
|
199
|
+
/** Render the row emphasized (bold + accent) so it stands out — e.g. a
|
|
200
|
+
* trailing "view all" action below a capped list. */
|
|
201
|
+
emphasis?: boolean;
|
|
202
|
+
/** Hover-revealed kebab actions (e.g. rename/delete). Rendered on the
|
|
203
|
+
* labeled rail only; ignored in the collapsed-rail flyout. */
|
|
204
|
+
actions?: RailSubItemAction[];
|
|
188
205
|
}
|
|
189
206
|
interface RailExpandableProps {
|
|
190
207
|
icon: React.ComponentType<{
|
|
@@ -201,6 +218,8 @@ interface RailExpandableProps {
|
|
|
201
218
|
subItems?: RailExpandableSubItem[];
|
|
202
219
|
/** Lazy sub-items — called once on first open; the result is cached. */
|
|
203
220
|
loadSubItems?: () => Promise<RailExpandableSubItem[]>;
|
|
221
|
+
/** Start expanded on mount (labeled rail). Defaults to collapsed. */
|
|
222
|
+
defaultOpen?: boolean;
|
|
204
223
|
/** Ids of sub-items whose route is active (drives sub-item highlight). */
|
|
205
224
|
activeSubIds?: string[];
|
|
206
225
|
/** Shown when the resolved sub-item list is empty. */
|
|
@@ -218,7 +237,7 @@ interface RailExpandableProps {
|
|
|
218
237
|
* Sub-items can be fixed (`subItems`) or lazy (`loadSubItems`, with a loading
|
|
219
238
|
* skeleton). Used for e.g. a "History" entry fronting recent sessions.
|
|
220
239
|
*/
|
|
221
|
-
declare function RailExpandable({ icon: Icon, label, href, isActive, showLabel, subItems, loadSubItems, activeSubIds, emptyLabel, onNavigate, LinkComponent, className, }: RailExpandableProps): react_jsx_runtime.JSX.Element;
|
|
240
|
+
declare function RailExpandable({ icon: Icon, label, href, isActive, showLabel, subItems, loadSubItems, activeSubIds, emptyLabel, defaultOpen, onNavigate, LinkComponent, className, }: RailExpandableProps): react_jsx_runtime.JSX.Element;
|
|
222
241
|
interface RailModeButtonProps {
|
|
223
242
|
mode: string;
|
|
224
243
|
icon: React.ComponentType<{
|
|
@@ -913,6 +932,8 @@ interface SidebarLayoutNavItem {
|
|
|
913
932
|
subActiveIds?: string[];
|
|
914
933
|
/** Empty-state text for an `expandable` item that resolves to no sub-items. */
|
|
915
934
|
emptyLabel?: string;
|
|
935
|
+
/** Start an `expandable` item expanded on mount (labeled rail). */
|
|
936
|
+
defaultOpen?: boolean;
|
|
916
937
|
badge?: number;
|
|
917
938
|
/**
|
|
918
939
|
* React Router prefetch behavior for this link, forwarded to the underlying
|
package/dist/dashboard.js
CHANGED
package/dist/globals.css
CHANGED
|
@@ -3782,6 +3782,13 @@
|
|
|
3782
3782
|
}
|
|
3783
3783
|
}
|
|
3784
3784
|
}
|
|
3785
|
+
.group-hover\/sub\:opacity-100 {
|
|
3786
|
+
&:is(:where(.group\/sub):hover *) {
|
|
3787
|
+
@media (hover: hover) {
|
|
3788
|
+
opacity: 100%;
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3791
|
+
}
|
|
3785
3792
|
.peer-disabled\:cursor-not-allowed {
|
|
3786
3793
|
&:is(:where(.peer):disabled ~ *) {
|
|
3787
3794
|
cursor: not-allowed;
|
|
@@ -4984,6 +4991,11 @@
|
|
|
4984
4991
|
border-color: var(--md3-outline-variant);
|
|
4985
4992
|
}
|
|
4986
4993
|
}
|
|
4994
|
+
.data-\[state\=open\]\:bg-\[var\(--accent-surface-strong\)\] {
|
|
4995
|
+
&[data-state="open"] {
|
|
4996
|
+
background-color: var(--accent-surface-strong);
|
|
4997
|
+
}
|
|
4998
|
+
}
|
|
4987
4999
|
.data-\[state\=open\]\:bg-accent {
|
|
4988
5000
|
&[data-state="open"] {
|
|
4989
5001
|
background-color: var(--color-accent);
|
|
@@ -5007,6 +5019,11 @@
|
|
|
5007
5019
|
color: var(--color-muted-foreground);
|
|
5008
5020
|
}
|
|
5009
5021
|
}
|
|
5022
|
+
.data-\[state\=open\]\:opacity-100 {
|
|
5023
|
+
&[data-state="open"] {
|
|
5024
|
+
opacity: 100%;
|
|
5025
|
+
}
|
|
5026
|
+
}
|
|
5010
5027
|
.data-\[state\=selected\]\:bg-muted\/50 {
|
|
5011
5028
|
&[data-state="selected"] {
|
|
5012
5029
|
background-color: color-mix(in srgb, hsl(var(--muted)) 50%, transparent);
|
|
@@ -6014,53 +6031,23 @@
|
|
|
6014
6031
|
.shimmer-text {
|
|
6015
6032
|
background-image: linear-gradient(
|
|
6016
6033
|
90deg,
|
|
6017
|
-
hsl(var(--muted-foreground)) 0%,
|
|
6018
|
-
hsl(var(--muted-foreground))
|
|
6019
|
-
var(--
|
|
6020
|
-
hsl(var(--muted-foreground))
|
|
6021
|
-
hsl(var(--muted-foreground)) 100%
|
|
6034
|
+
hsl(var(--muted-foreground) / 0.5) 0%,
|
|
6035
|
+
hsl(var(--muted-foreground) / 0.5) 40%,
|
|
6036
|
+
hsl(var(--primary)) 50%,
|
|
6037
|
+
hsl(var(--muted-foreground) / 0.5) 60%,
|
|
6038
|
+
hsl(var(--muted-foreground) / 0.5) 100%
|
|
6022
6039
|
);
|
|
6023
6040
|
background-size: 200% 100%;
|
|
6024
6041
|
-webkit-background-clip: text;
|
|
6025
6042
|
background-clip: text;
|
|
6026
6043
|
-webkit-text-fill-color: transparent;
|
|
6027
|
-
animation: shimmer 1.
|
|
6044
|
+
animation: shimmer 1.1s linear infinite;
|
|
6028
6045
|
}
|
|
6029
6046
|
@media (prefers-reduced-motion: reduce) {
|
|
6030
6047
|
.shimmer-text {
|
|
6031
6048
|
animation: none;
|
|
6032
6049
|
}
|
|
6033
6050
|
}
|
|
6034
|
-
.responding-ellipsis {
|
|
6035
|
-
display: inline-flex;
|
|
6036
|
-
width: 1.25rem;
|
|
6037
|
-
margin-left: auto;
|
|
6038
|
-
flex-shrink: 0;
|
|
6039
|
-
align-items: center;
|
|
6040
|
-
justify-content: center;
|
|
6041
|
-
gap: 0.1875rem;
|
|
6042
|
-
color: hsl(var(--primary));
|
|
6043
|
-
}
|
|
6044
|
-
.responding-ellipsis > span {
|
|
6045
|
-
width: 0.25rem;
|
|
6046
|
-
height: 0.25rem;
|
|
6047
|
-
border-radius: 9999px;
|
|
6048
|
-
background: currentColor;
|
|
6049
|
-
opacity: 0.6;
|
|
6050
|
-
animation: responding-ellipsis 0.8s ease-in-out infinite;
|
|
6051
|
-
}
|
|
6052
|
-
.responding-ellipsis > span:nth-child(2) {
|
|
6053
|
-
animation-delay: 0.15s;
|
|
6054
|
-
}
|
|
6055
|
-
.responding-ellipsis > span:nth-child(3) {
|
|
6056
|
-
animation-delay: 0.3s;
|
|
6057
|
-
}
|
|
6058
|
-
@media (prefers-reduced-motion: reduce) {
|
|
6059
|
-
.responding-ellipsis > span {
|
|
6060
|
-
animation: none;
|
|
6061
|
-
opacity: 0.8;
|
|
6062
|
-
}
|
|
6063
|
-
}
|
|
6064
6051
|
.animate-in {
|
|
6065
6052
|
animation: fade-in 0.25s ease-out;
|
|
6066
6053
|
}
|
|
@@ -6095,16 +6082,6 @@
|
|
|
6095
6082
|
background-position: 200% 0;
|
|
6096
6083
|
}
|
|
6097
6084
|
}
|
|
6098
|
-
@keyframes responding-ellipsis {
|
|
6099
|
-
0%, 80%, 100% {
|
|
6100
|
-
opacity: 0.6;
|
|
6101
|
-
transform: translateY(0);
|
|
6102
|
-
}
|
|
6103
|
-
40% {
|
|
6104
|
-
opacity: 1;
|
|
6105
|
-
transform: translateY(-1.5px);
|
|
6106
|
-
}
|
|
6107
|
-
}
|
|
6108
6085
|
@keyframes fade-in {
|
|
6109
6086
|
from {
|
|
6110
6087
|
opacity: 0;
|
package/dist/index.js
CHANGED
|
@@ -102,7 +102,7 @@ import {
|
|
|
102
102
|
modelProvider,
|
|
103
103
|
snapHarnessToModel,
|
|
104
104
|
snapModelToHarness
|
|
105
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-2E3FJM56.js";
|
|
106
106
|
import {
|
|
107
107
|
ExpandedToolDetail,
|
|
108
108
|
InlineThinkingItem,
|
|
@@ -146,7 +146,7 @@ import {
|
|
|
146
146
|
buildUnifiedPatch,
|
|
147
147
|
computeDiffStats,
|
|
148
148
|
resolveLanguage
|
|
149
|
-
} from "./chunk-
|
|
149
|
+
} from "./chunk-G4YJYSFA.js";
|
|
150
150
|
import {
|
|
151
151
|
FileArtifactPane,
|
|
152
152
|
FilePreview,
|
|
@@ -211,7 +211,7 @@ import {
|
|
|
211
211
|
canAdminSandbox,
|
|
212
212
|
parseInsufficientBalance,
|
|
213
213
|
useSidebar
|
|
214
|
-
} from "./chunk-
|
|
214
|
+
} from "./chunk-QSCCNGXZ.js";
|
|
215
215
|
import "./chunk-VIREDUBF.js";
|
|
216
216
|
import {
|
|
217
217
|
usePtySession
|
package/dist/styles.css
CHANGED
|
@@ -3782,6 +3782,13 @@
|
|
|
3782
3782
|
}
|
|
3783
3783
|
}
|
|
3784
3784
|
}
|
|
3785
|
+
.group-hover\/sub\:opacity-100 {
|
|
3786
|
+
&:is(:where(.group\/sub):hover *) {
|
|
3787
|
+
@media (hover: hover) {
|
|
3788
|
+
opacity: 100%;
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3791
|
+
}
|
|
3785
3792
|
.peer-disabled\:cursor-not-allowed {
|
|
3786
3793
|
&:is(:where(.peer):disabled ~ *) {
|
|
3787
3794
|
cursor: not-allowed;
|
|
@@ -4984,6 +4991,11 @@
|
|
|
4984
4991
|
border-color: var(--md3-outline-variant);
|
|
4985
4992
|
}
|
|
4986
4993
|
}
|
|
4994
|
+
.data-\[state\=open\]\:bg-\[var\(--accent-surface-strong\)\] {
|
|
4995
|
+
&[data-state="open"] {
|
|
4996
|
+
background-color: var(--accent-surface-strong);
|
|
4997
|
+
}
|
|
4998
|
+
}
|
|
4987
4999
|
.data-\[state\=open\]\:bg-accent {
|
|
4988
5000
|
&[data-state="open"] {
|
|
4989
5001
|
background-color: var(--color-accent);
|
|
@@ -5007,6 +5019,11 @@
|
|
|
5007
5019
|
color: var(--color-muted-foreground);
|
|
5008
5020
|
}
|
|
5009
5021
|
}
|
|
5022
|
+
.data-\[state\=open\]\:opacity-100 {
|
|
5023
|
+
&[data-state="open"] {
|
|
5024
|
+
opacity: 100%;
|
|
5025
|
+
}
|
|
5026
|
+
}
|
|
5010
5027
|
.data-\[state\=selected\]\:bg-muted\/50 {
|
|
5011
5028
|
&[data-state="selected"] {
|
|
5012
5029
|
background-color: color-mix(in srgb, hsl(var(--muted)) 50%, transparent);
|
|
@@ -6014,53 +6031,23 @@
|
|
|
6014
6031
|
.shimmer-text {
|
|
6015
6032
|
background-image: linear-gradient(
|
|
6016
6033
|
90deg,
|
|
6017
|
-
hsl(var(--muted-foreground)) 0%,
|
|
6018
|
-
hsl(var(--muted-foreground))
|
|
6019
|
-
var(--
|
|
6020
|
-
hsl(var(--muted-foreground))
|
|
6021
|
-
hsl(var(--muted-foreground)) 100%
|
|
6034
|
+
hsl(var(--muted-foreground) / 0.5) 0%,
|
|
6035
|
+
hsl(var(--muted-foreground) / 0.5) 40%,
|
|
6036
|
+
hsl(var(--primary)) 50%,
|
|
6037
|
+
hsl(var(--muted-foreground) / 0.5) 60%,
|
|
6038
|
+
hsl(var(--muted-foreground) / 0.5) 100%
|
|
6022
6039
|
);
|
|
6023
6040
|
background-size: 200% 100%;
|
|
6024
6041
|
-webkit-background-clip: text;
|
|
6025
6042
|
background-clip: text;
|
|
6026
6043
|
-webkit-text-fill-color: transparent;
|
|
6027
|
-
animation: shimmer 1.
|
|
6044
|
+
animation: shimmer 1.1s linear infinite;
|
|
6028
6045
|
}
|
|
6029
6046
|
@media (prefers-reduced-motion: reduce) {
|
|
6030
6047
|
.shimmer-text {
|
|
6031
6048
|
animation: none;
|
|
6032
6049
|
}
|
|
6033
6050
|
}
|
|
6034
|
-
.responding-ellipsis {
|
|
6035
|
-
display: inline-flex;
|
|
6036
|
-
width: 1.25rem;
|
|
6037
|
-
margin-left: auto;
|
|
6038
|
-
flex-shrink: 0;
|
|
6039
|
-
align-items: center;
|
|
6040
|
-
justify-content: center;
|
|
6041
|
-
gap: 0.1875rem;
|
|
6042
|
-
color: hsl(var(--primary));
|
|
6043
|
-
}
|
|
6044
|
-
.responding-ellipsis > span {
|
|
6045
|
-
width: 0.25rem;
|
|
6046
|
-
height: 0.25rem;
|
|
6047
|
-
border-radius: 9999px;
|
|
6048
|
-
background: currentColor;
|
|
6049
|
-
opacity: 0.6;
|
|
6050
|
-
animation: responding-ellipsis 0.8s ease-in-out infinite;
|
|
6051
|
-
}
|
|
6052
|
-
.responding-ellipsis > span:nth-child(2) {
|
|
6053
|
-
animation-delay: 0.15s;
|
|
6054
|
-
}
|
|
6055
|
-
.responding-ellipsis > span:nth-child(3) {
|
|
6056
|
-
animation-delay: 0.3s;
|
|
6057
|
-
}
|
|
6058
|
-
@media (prefers-reduced-motion: reduce) {
|
|
6059
|
-
.responding-ellipsis > span {
|
|
6060
|
-
animation: none;
|
|
6061
|
-
opacity: 0.8;
|
|
6062
|
-
}
|
|
6063
|
-
}
|
|
6064
6051
|
.animate-in {
|
|
6065
6052
|
animation: fade-in 0.25s ease-out;
|
|
6066
6053
|
}
|
|
@@ -6095,16 +6082,6 @@
|
|
|
6095
6082
|
background-position: 200% 0;
|
|
6096
6083
|
}
|
|
6097
6084
|
}
|
|
6098
|
-
@keyframes responding-ellipsis {
|
|
6099
|
-
0%, 80%, 100% {
|
|
6100
|
-
opacity: 0.6;
|
|
6101
|
-
transform: translateY(0);
|
|
6102
|
-
}
|
|
6103
|
-
40% {
|
|
6104
|
-
opacity: 1;
|
|
6105
|
-
transform: translateY(-1.5px);
|
|
6106
|
-
}
|
|
6107
|
-
}
|
|
6108
6085
|
@keyframes fade-in {
|
|
6109
6086
|
from {
|
|
6110
6087
|
opacity: 0;
|
package/dist/workbench.js
CHANGED
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
buildUnifiedPatch,
|
|
13
13
|
computeDiffStats,
|
|
14
14
|
resolveLanguage
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-G4YJYSFA.js";
|
|
16
16
|
import "./chunk-3J6FG3FJ.js";
|
|
17
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-QSCCNGXZ.js";
|
|
18
18
|
import "./chunk-VIREDUBF.js";
|
|
19
19
|
import "./chunk-77WVVJA4.js";
|
|
20
20
|
import "./chunk-OMUIPJQZ.js";
|
package/package.json
CHANGED