@tangle-network/sandbox-ui 0.112.0 → 0.113.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/README.md +46 -0
- package/dist/{chunk-D5VXCWUG.js → chunk-2Q3KDQX7.js} +370 -156
- package/dist/globals.css +38 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -1
- package/dist/styles.css +38 -0
- package/dist/workspace.d.ts +114 -5
- package/dist/workspace.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -168,6 +168,52 @@ const partMap: Record<string, SessionPart[]> = {};
|
|
|
168
168
|
|
|
169
169
|
`FileTreeVisibilityOptions` is a UI-layer policy only. Sensitive paths still need to be hidden and denied by the app/backend layer.
|
|
170
170
|
|
|
171
|
+
### The three-pane shell
|
|
172
|
+
|
|
173
|
+
For a chats rail · transcript + composer · artifacts layout, hand `SandboxWorkbench` a `SessionSidebar` as its `rail`, your composer as `composer`, and `centerHeader={null}` for the quiet center. `WorkspaceLayout` owns the pane sizes and, when you pass `layout.leftOpen` / `layout.onLeftOpenChange`, the open state too.
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
const [chatsOpen, setChatsOpen] = useState(true);
|
|
177
|
+
|
|
178
|
+
<SandboxWorkbench
|
|
179
|
+
centerHeader={null}
|
|
180
|
+
rail={
|
|
181
|
+
<SessionSidebar
|
|
182
|
+
variant="quiet"
|
|
183
|
+
groupBy="status"
|
|
184
|
+
showUpdatedAt
|
|
185
|
+
fill
|
|
186
|
+
className="border-r-0"
|
|
187
|
+
title="Chats"
|
|
188
|
+
createLabel="New chat"
|
|
189
|
+
items={threads}
|
|
190
|
+
currentItemId={threadId}
|
|
191
|
+
onSelectItem={(item) => navigate(item.href)}
|
|
192
|
+
onCreate={createThread}
|
|
193
|
+
onCollapse={() => setChatsOpen(false)}
|
|
194
|
+
/>
|
|
195
|
+
}
|
|
196
|
+
session={{ messages, partMap, isStreaming }}
|
|
197
|
+
composer={<ChatComposer onSend={runTurn} />}
|
|
198
|
+
artifacts={[
|
|
199
|
+
{ id: "changes", kind: "custom", title: "Changes", icon: GitCompare, pinned: true, content: <ChangesPanel /> },
|
|
200
|
+
...openFiles,
|
|
201
|
+
]}
|
|
202
|
+
layout={{
|
|
203
|
+
leftOpen: chatsOpen,
|
|
204
|
+
onLeftOpenChange: setChatsOpen,
|
|
205
|
+
keyboardShortcuts: true,
|
|
206
|
+
leftCollapsedControl: (
|
|
207
|
+
<button type="button" aria-label="Show chats" onClick={() => setChatsOpen(true)}>
|
|
208
|
+
<PanelLeftOpen className="h-4 w-4" />
|
|
209
|
+
</button>
|
|
210
|
+
),
|
|
211
|
+
}}
|
|
212
|
+
/>;
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Each `SessionSidebarItem` can carry an `icon` (rendered in a 16×20 slot, with the status dot as a corner badge) and a `meta` line; `formatRelativeAge` from `/workspace` formats the age for that line.
|
|
216
|
+
|
|
171
217
|
## Theming And Retheming
|
|
172
218
|
|
|
173
219
|
There is a built-in Tangle default theme, but consumers can restyle the library in three layers:
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
|
|
8
8
|
// src/workspace/workspace-layout.tsx
|
|
9
9
|
import {
|
|
10
|
+
useCallback,
|
|
10
11
|
useEffect,
|
|
11
12
|
useMemo,
|
|
12
13
|
useRef,
|
|
@@ -46,6 +47,14 @@ var DESKTOP_BREAKPOINT = "(min-width: 1024px)";
|
|
|
46
47
|
function clamp(value, min, max) {
|
|
47
48
|
return Math.min(Math.max(value, min), max);
|
|
48
49
|
}
|
|
50
|
+
function isEditableTarget(target) {
|
|
51
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
52
|
+
if (target.isContentEditable) return true;
|
|
53
|
+
const tag = target.tagName;
|
|
54
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
55
|
+
const editable = target.closest("[contenteditable]");
|
|
56
|
+
return editable !== null && editable.getAttribute("contenteditable") !== "false";
|
|
57
|
+
}
|
|
49
58
|
function readStoredLayout(key) {
|
|
50
59
|
if (typeof window === "undefined") return null;
|
|
51
60
|
try {
|
|
@@ -215,6 +224,15 @@ function WorkspaceLayout({
|
|
|
215
224
|
leftLabel = "Left workspace panel",
|
|
216
225
|
rightLabel = "Right workspace panel",
|
|
217
226
|
bottomLabel = "Bottom runtime panel",
|
|
227
|
+
leftOpen: leftOpenProp,
|
|
228
|
+
onLeftOpenChange,
|
|
229
|
+
rightOpen: rightOpenProp,
|
|
230
|
+
onRightOpenChange,
|
|
231
|
+
keyboardShortcuts = false,
|
|
232
|
+
leftCollapsedControl,
|
|
233
|
+
leftContentClassName,
|
|
234
|
+
rightContentClassName,
|
|
235
|
+
centerHeaderVisibility = "always",
|
|
218
236
|
className
|
|
219
237
|
}) {
|
|
220
238
|
const desktop = useDesktopMediaQuery(DESKTOP_BREAKPOINT);
|
|
@@ -223,8 +241,28 @@ function WorkspaceLayout({
|
|
|
223
241
|
() => persistenceKey ? readStoredLayout(persistenceKey) : null,
|
|
224
242
|
[persistenceKey]
|
|
225
243
|
);
|
|
226
|
-
const [
|
|
227
|
-
const [
|
|
244
|
+
const [uncontrolledLeftOpen, setUncontrolledLeftOpen] = useState(storedLayout?.leftOpen ?? defaultLeftOpen);
|
|
245
|
+
const [uncontrolledRightOpen, setUncontrolledRightOpen] = useState(storedLayout?.rightOpen ?? defaultRightOpen);
|
|
246
|
+
const leftControlled = leftOpenProp !== void 0;
|
|
247
|
+
const rightControlled = rightOpenProp !== void 0;
|
|
248
|
+
const leftOpen = leftControlled ? leftOpenProp : uncontrolledLeftOpen;
|
|
249
|
+
const rightOpen = rightControlled ? rightOpenProp : uncontrolledRightOpen;
|
|
250
|
+
const setLeftOpen = useCallback(
|
|
251
|
+
(open) => {
|
|
252
|
+
if (!leftControlled) setUncontrolledLeftOpen(open);
|
|
253
|
+
onLeftOpenChange?.(open);
|
|
254
|
+
},
|
|
255
|
+
[leftControlled, onLeftOpenChange]
|
|
256
|
+
);
|
|
257
|
+
const setRightOpen = useCallback(
|
|
258
|
+
(open) => {
|
|
259
|
+
if (!rightControlled) setUncontrolledRightOpen(open);
|
|
260
|
+
onRightOpenChange?.(open);
|
|
261
|
+
},
|
|
262
|
+
[rightControlled, onRightOpenChange]
|
|
263
|
+
);
|
|
264
|
+
const hasLeft = Boolean(left);
|
|
265
|
+
const hasRight = Boolean(right);
|
|
228
266
|
const [bottomOpen, setBottomOpen] = useState(storedLayout?.bottomOpen ?? defaultBottomOpen);
|
|
229
267
|
const [leftWidth, setLeftWidth] = useState(
|
|
230
268
|
clamp(storedLayout?.leftWidth ?? defaultLeftWidth, minLeftWidth, maxLeftWidth)
|
|
@@ -235,6 +273,8 @@ function WorkspaceLayout({
|
|
|
235
273
|
const [bottomHeight, setBottomHeight] = useState(
|
|
236
274
|
clamp(storedLayout?.bottomHeight ?? defaultBottomHeight, minBottomHeight, maxBottomHeight)
|
|
237
275
|
);
|
|
276
|
+
const centerHeaderHasContent = Boolean(centerHeader) || hasLeft && !leftOpen || hasRight && !rightOpen || Boolean(bottom) && !bottomOpen;
|
|
277
|
+
const showCenterHeader = centerHeaderVisibility === "auto" ? centerHeaderHasContent : Boolean(centerHeader || left || right || bottom);
|
|
238
278
|
useEffect(() => {
|
|
239
279
|
if (!persistenceKey || typeof window === "undefined") return;
|
|
240
280
|
const payload = {
|
|
@@ -247,6 +287,23 @@ function WorkspaceLayout({
|
|
|
247
287
|
};
|
|
248
288
|
window.localStorage.setItem(persistenceKey, JSON.stringify(payload));
|
|
249
289
|
}, [bottomHeight, bottomOpen, leftOpen, leftWidth, persistenceKey, rightOpen, rightWidth]);
|
|
290
|
+
useEffect(() => {
|
|
291
|
+
if (!keyboardShortcuts || typeof window === "undefined") return;
|
|
292
|
+
const handleKeyDown = (event) => {
|
|
293
|
+
if (!(event.metaKey || event.ctrlKey) || event.altKey || event.shiftKey) return;
|
|
294
|
+
if (isEditableTarget(event.target)) return;
|
|
295
|
+
const key = event.key.toLowerCase();
|
|
296
|
+
if (key === "b" && hasLeft) {
|
|
297
|
+
event.preventDefault();
|
|
298
|
+
setLeftOpen(!leftOpen);
|
|
299
|
+
} else if (key === "e" && hasRight) {
|
|
300
|
+
event.preventDefault();
|
|
301
|
+
setRightOpen(!rightOpen);
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
305
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
306
|
+
}, [hasLeft, hasRight, keyboardShortcuts, leftOpen, rightOpen, setLeftOpen, setRightOpen]);
|
|
250
307
|
useEffect(() => {
|
|
251
308
|
if (!desktop) return;
|
|
252
309
|
const handlePointerMove = (event) => {
|
|
@@ -336,7 +393,7 @@ function WorkspaceLayout({
|
|
|
336
393
|
}
|
|
337
394
|
)
|
|
338
395
|
] }),
|
|
339
|
-
/* @__PURE__ */ jsx2("div", { className: "min-h-0 flex-1 overflow-auto py-1", children: left })
|
|
396
|
+
/* @__PURE__ */ jsx2("div", { className: cn("min-h-0 flex-1 overflow-auto py-1", leftContentClassName), children: left })
|
|
340
397
|
]
|
|
341
398
|
}
|
|
342
399
|
),
|
|
@@ -350,8 +407,8 @@ function WorkspaceLayout({
|
|
|
350
407
|
)
|
|
351
408
|
] }),
|
|
352
409
|
/* @__PURE__ */ jsxs("main", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
353
|
-
|
|
354
|
-
left && !leftOpen && /* @__PURE__ */ jsx2(
|
|
410
|
+
showCenterHeader && /* @__PURE__ */ jsxs(WorkspacePaneHeader, { className: "gap-2", children: [
|
|
411
|
+
left && !leftOpen && (leftCollapsedControl ?? /* @__PURE__ */ jsx2(
|
|
355
412
|
"button",
|
|
356
413
|
{
|
|
357
414
|
type: "button",
|
|
@@ -360,7 +417,7 @@ function WorkspaceLayout({
|
|
|
360
417
|
className: "rounded-[2px] p-1 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary/60",
|
|
361
418
|
children: /* @__PURE__ */ jsx2(PanelLeftOpen, { className: "h-4 w-4" })
|
|
362
419
|
}
|
|
363
|
-
),
|
|
420
|
+
)),
|
|
364
421
|
/* @__PURE__ */ jsx2("div", { className: "min-w-0 flex-1", children: centerHeader }),
|
|
365
422
|
bottom && !bottomOpen && /* @__PURE__ */ jsx2(
|
|
366
423
|
"button",
|
|
@@ -449,7 +506,7 @@ function WorkspaceLayout({
|
|
|
449
506
|
}
|
|
450
507
|
)
|
|
451
508
|
] }),
|
|
452
|
-
/* @__PURE__ */ jsx2("div", { className: "min-h-0 flex-1 overflow-auto", children: right })
|
|
509
|
+
/* @__PURE__ */ jsx2("div", { className: cn("min-h-0 flex-1 overflow-auto", rightContentClassName), children: right })
|
|
453
510
|
]
|
|
454
511
|
}
|
|
455
512
|
)
|
|
@@ -865,12 +922,35 @@ function RuntimePane({
|
|
|
865
922
|
}
|
|
866
923
|
|
|
867
924
|
// src/workspace/session-sidebar.tsx
|
|
868
|
-
import { useCallback as
|
|
869
|
-
import { ArrowLeft, FolderTree, MessageSquareText, Plus, Search as Search2, Settings, Sparkles } from "lucide-react";
|
|
925
|
+
import { useCallback as useCallback3, useImperativeHandle, useMemo as useMemo3, useRef as useRef4, useState as useState4 } from "react";
|
|
926
|
+
import { ArrowLeft, FolderTree, MessageSquareText, PanelLeftClose as PanelLeftClose2, Plus, Search as Search2, Settings, Sparkles } from "lucide-react";
|
|
927
|
+
|
|
928
|
+
// src/lib/format-relative-age.ts
|
|
929
|
+
var SECOND = 1e3;
|
|
930
|
+
var MINUTE = 60 * SECOND;
|
|
931
|
+
var HOUR = 60 * MINUTE;
|
|
932
|
+
var DAY = 24 * HOUR;
|
|
933
|
+
var WEEK = 7 * DAY;
|
|
934
|
+
var MONTH = 30 * DAY;
|
|
935
|
+
var YEAR = 365 * DAY;
|
|
936
|
+
function formatRelativeAge(date, now = Date.now()) {
|
|
937
|
+
const timestamp = date instanceof Date ? date.getTime() : new Date(date).getTime();
|
|
938
|
+
if (Number.isNaN(timestamp)) return "";
|
|
939
|
+
const elapsed = Math.max(0, now - timestamp);
|
|
940
|
+
if (elapsed < MINUTE) return "now";
|
|
941
|
+
if (elapsed < HOUR) return `${Math.floor(elapsed / MINUTE)}m`;
|
|
942
|
+
if (elapsed < DAY) return `${Math.floor(elapsed / HOUR)}h`;
|
|
943
|
+
if (elapsed < WEEK) return `${Math.floor(elapsed / DAY)}d`;
|
|
944
|
+
if (elapsed < MONTH) return `${Math.floor(elapsed / WEEK)}w`;
|
|
945
|
+
if (elapsed < YEAR) return `${Math.floor(elapsed / MONTH)}mo`;
|
|
946
|
+
return `${Math.floor(elapsed / YEAR)}y`;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
// src/workspace/session-sidebar.tsx
|
|
870
950
|
import { useNavbarSessions } from "@tangle-network/ui/stores";
|
|
871
951
|
|
|
872
952
|
// src/workspace/session-optimistic.ts
|
|
873
|
-
import { useCallback, useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
953
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
874
954
|
var SESSION_CREATED_EVENT = "sandbox-thread-created";
|
|
875
955
|
function dispatchSessionCreated(detail, eventName = SESSION_CREATED_EVENT) {
|
|
876
956
|
if (typeof window === "undefined") return;
|
|
@@ -885,19 +965,19 @@ function useOptimisticSessionItems(items, options = {}) {
|
|
|
885
965
|
useEffect3(() => {
|
|
886
966
|
setOptimisticItems(items);
|
|
887
967
|
}, [items]);
|
|
888
|
-
const add =
|
|
968
|
+
const add = useCallback2((detail) => {
|
|
889
969
|
const next = toItem(detail);
|
|
890
970
|
setOptimisticItems((prev) => [next, ...prev.filter((item) => item.id !== next.id)]);
|
|
891
971
|
}, []);
|
|
892
|
-
const update =
|
|
972
|
+
const update = useCallback2((id, patch) => {
|
|
893
973
|
setOptimisticItems(
|
|
894
974
|
(prev) => prev.map((item) => item.id === id ? { ...item, ...patch } : item)
|
|
895
975
|
);
|
|
896
976
|
}, []);
|
|
897
|
-
const remove =
|
|
977
|
+
const remove = useCallback2((id) => {
|
|
898
978
|
setOptimisticItems((prev) => prev.filter((item) => item.id !== id));
|
|
899
979
|
}, []);
|
|
900
|
-
const reset =
|
|
980
|
+
const reset = useCallback2(() => setOptimisticItems(items), [items]);
|
|
901
981
|
const addRef = useRef3(add);
|
|
902
982
|
addRef.current = add;
|
|
903
983
|
useEffect3(() => {
|
|
@@ -928,6 +1008,24 @@ var NO_CONTROLLER = {
|
|
|
928
1008
|
reset: () => {
|
|
929
1009
|
}
|
|
930
1010
|
};
|
|
1011
|
+
var STATUS_GROUPS = [
|
|
1012
|
+
{ key: "attention", label: "Needs input" },
|
|
1013
|
+
{ key: "failed", label: "Failed" },
|
|
1014
|
+
{ key: "working", label: "Working" },
|
|
1015
|
+
{ key: "done", label: "Done" }
|
|
1016
|
+
];
|
|
1017
|
+
function groupKeyForStatus(status) {
|
|
1018
|
+
switch (status) {
|
|
1019
|
+
case "attention-needed":
|
|
1020
|
+
return "attention";
|
|
1021
|
+
case "error":
|
|
1022
|
+
return "failed";
|
|
1023
|
+
case "running":
|
|
1024
|
+
return "working";
|
|
1025
|
+
default:
|
|
1026
|
+
return "done";
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
931
1029
|
function statusDot(status) {
|
|
932
1030
|
switch (status) {
|
|
933
1031
|
case "running":
|
|
@@ -952,6 +1050,11 @@ function iconForLink(icon) {
|
|
|
952
1050
|
return Sparkles;
|
|
953
1051
|
}
|
|
954
1052
|
}
|
|
1053
|
+
function toDate(value) {
|
|
1054
|
+
if (value === void 0) return null;
|
|
1055
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
1056
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
1057
|
+
}
|
|
955
1058
|
function sortItems(items, sessionStatusById) {
|
|
956
1059
|
return [...items].sort((left, right) => {
|
|
957
1060
|
if (Boolean(left.isPinned) !== Boolean(right.isPinned)) {
|
|
@@ -1003,20 +1106,20 @@ function useResizable(defaultWidth, min, max, onChange) {
|
|
|
1003
1106
|
const dragging = useRef4(false);
|
|
1004
1107
|
const startX = useRef4(0);
|
|
1005
1108
|
const startW = useRef4(0);
|
|
1006
|
-
const onPointerDown =
|
|
1109
|
+
const onPointerDown = useCallback3((e) => {
|
|
1007
1110
|
dragging.current = true;
|
|
1008
1111
|
startX.current = e.clientX;
|
|
1009
1112
|
startW.current = width;
|
|
1010
1113
|
e.currentTarget.setPointerCapture(e.pointerId);
|
|
1011
1114
|
}, [width]);
|
|
1012
|
-
const onPointerMove =
|
|
1115
|
+
const onPointerMove = useCallback3((e) => {
|
|
1013
1116
|
if (!dragging.current) return;
|
|
1014
1117
|
const delta = e.clientX - startX.current;
|
|
1015
1118
|
const next = Math.min(max, Math.max(min, startW.current + delta));
|
|
1016
1119
|
setWidth(next);
|
|
1017
1120
|
onChange?.(next);
|
|
1018
1121
|
}, [min, max, onChange]);
|
|
1019
|
-
const onPointerUp =
|
|
1122
|
+
const onPointerUp = useCallback3(() => {
|
|
1020
1123
|
dragging.current = false;
|
|
1021
1124
|
}, []);
|
|
1022
1125
|
return { width, onPointerDown, onPointerMove, onPointerUp };
|
|
@@ -1046,8 +1149,14 @@ function SessionSidebar({
|
|
|
1046
1149
|
onWidthChange,
|
|
1047
1150
|
renderItemActions,
|
|
1048
1151
|
optimistic = false,
|
|
1049
|
-
optimisticRef
|
|
1152
|
+
optimisticRef,
|
|
1153
|
+
variant = "default",
|
|
1154
|
+
groupBy = "none",
|
|
1155
|
+
showUpdatedAt = false,
|
|
1156
|
+
onCollapse,
|
|
1157
|
+
fill = false
|
|
1050
1158
|
}) {
|
|
1159
|
+
const quiet = variant === "quiet";
|
|
1051
1160
|
const [query, setQuery] = useState4("");
|
|
1052
1161
|
const [activeFilterId, setActiveFilterId] = useState4(defaultFilterId ?? filters[0]?.id ?? "all");
|
|
1053
1162
|
const optimisticOptions = typeof optimistic === "object" ? optimistic : void 0;
|
|
@@ -1085,6 +1194,19 @@ function SessionSidebar({
|
|
|
1085
1194
|
return haystack.includes(normalizedQuery);
|
|
1086
1195
|
});
|
|
1087
1196
|
}, [activeFilterId, currentItemId, filters, orderedItems, query, sessionsById]);
|
|
1197
|
+
const groups = useMemo3(() => {
|
|
1198
|
+
if (groupBy !== "status") {
|
|
1199
|
+
return [{ key: "all", label: null, items: visibleItems }];
|
|
1200
|
+
}
|
|
1201
|
+
return STATUS_GROUPS.map((group) => ({
|
|
1202
|
+
key: group.key,
|
|
1203
|
+
label: group.label,
|
|
1204
|
+
items: visibleItems.filter(
|
|
1205
|
+
(item) => groupKeyForStatus(sessionsById.get(item.id)?.status ?? item.status) === group.key
|
|
1206
|
+
)
|
|
1207
|
+
})).filter((group) => group.items.length > 0);
|
|
1208
|
+
}, [groupBy, sessionsById, visibleItems]);
|
|
1209
|
+
const showGroupLabels = groups.length > 1;
|
|
1088
1210
|
const runningCount = activeSessions.filter((session) => session.status === "running").length;
|
|
1089
1211
|
const filterCounts = useMemo3(() => Object.fromEntries(filters.map((filter) => [
|
|
1090
1212
|
filter.id,
|
|
@@ -1094,13 +1216,134 @@ function SessionSidebar({
|
|
|
1094
1216
|
})).length
|
|
1095
1217
|
])), [currentItemId, filters, orderedItems, sessionsById]);
|
|
1096
1218
|
const resize = useResizable(defaultWidth, minWidth, maxWidth, onWidthChange);
|
|
1219
|
+
const fillsParent = fill && !resizable;
|
|
1220
|
+
const renderRow = (item, index) => {
|
|
1221
|
+
const session = sessionsById.get(item.id) ?? null;
|
|
1222
|
+
const isActive = currentItemId === item.id;
|
|
1223
|
+
const status = session?.status ?? item.status;
|
|
1224
|
+
const isWorking = status === "running";
|
|
1225
|
+
const visibleBadges = [
|
|
1226
|
+
...item.isPinned ? [{ id: `${item.id}-pinned`, label: "Pinned", tone: "neutral" }] : [],
|
|
1227
|
+
...item.badges ?? []
|
|
1228
|
+
].filter((badge) => !quiet || (badge.tone ?? "neutral") !== "neutral");
|
|
1229
|
+
const updatedAt = showUpdatedAt && item.meta === void 0 ? toDate(item.updatedAt) : null;
|
|
1230
|
+
const metaLine = item.meta ?? (updatedAt ? /* @__PURE__ */ jsx8("time", { dateTime: updatedAt.toISOString(), title: updatedAt.toLocaleString(), children: formatRelativeAge(updatedAt) }) : null);
|
|
1231
|
+
return /* @__PURE__ */ jsx8(
|
|
1232
|
+
"li",
|
|
1233
|
+
{
|
|
1234
|
+
className: "agent-arrive",
|
|
1235
|
+
style: { "--stagger-index": index },
|
|
1236
|
+
children: /* @__PURE__ */ jsxs7(
|
|
1237
|
+
"div",
|
|
1238
|
+
{
|
|
1239
|
+
className: cn(
|
|
1240
|
+
quiet ? "group relative flex items-center gap-2 rounded-lg py-2 pl-2 pr-3 transition-colors" : "group relative flex items-center gap-2 rounded-[var(--radius-sm)] px-2.5 py-1.5 transition-colors",
|
|
1241
|
+
MOTION_CONTROL,
|
|
1242
|
+
quiet ? isActive ? "bg-surface-container-high" : "hover:bg-surface-container" : isActive ? "bg-accent font-medium text-foreground" : "text-muted-foreground hover:bg-accent/30"
|
|
1243
|
+
),
|
|
1244
|
+
children: [
|
|
1245
|
+
/* @__PURE__ */ jsxs7(
|
|
1246
|
+
"button",
|
|
1247
|
+
{
|
|
1248
|
+
type: "button",
|
|
1249
|
+
onClick: () => {
|
|
1250
|
+
if (onSelectItem) {
|
|
1251
|
+
onSelectItem(item);
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
navigateToHref(item.href);
|
|
1255
|
+
},
|
|
1256
|
+
"aria-current": isActive ? "page" : void 0,
|
|
1257
|
+
className: "min-w-0 flex flex-1 items-center gap-2 text-left",
|
|
1258
|
+
children: [
|
|
1259
|
+
item.icon ? /* @__PURE__ */ jsxs7("span", { className: "relative flex h-5 w-4 shrink-0 items-center justify-center", "aria-hidden": "true", children: [
|
|
1260
|
+
item.icon,
|
|
1261
|
+
/* @__PURE__ */ jsx8("span", { className: cn("absolute -bottom-0.5 -right-0.5 h-1.5 w-1.5 rounded-full", statusDot(status)) })
|
|
1262
|
+
] }) : /* @__PURE__ */ jsx8("span", { className: cn("h-1.5 w-1.5 shrink-0 rounded-full", statusDot(status)) }),
|
|
1263
|
+
/* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1", children: [
|
|
1264
|
+
/* @__PURE__ */ jsx8(
|
|
1265
|
+
"div",
|
|
1266
|
+
{
|
|
1267
|
+
className: cn(
|
|
1268
|
+
quiet ? "truncate text-sm leading-5 text-foreground/75 group-hover:text-foreground" : "truncate text-sm font-medium",
|
|
1269
|
+
isActive && "text-foreground",
|
|
1270
|
+
isWorking && "agent-shimmer"
|
|
1271
|
+
),
|
|
1272
|
+
...isWorking ? { "data-motion": "essential" } : {},
|
|
1273
|
+
children: item.title
|
|
1274
|
+
}
|
|
1275
|
+
),
|
|
1276
|
+
item.subtitle && /* @__PURE__ */ jsx8("div", { className: "truncate text-xs leading-tight text-muted-foreground", children: item.subtitle }),
|
|
1277
|
+
metaLine && /* @__PURE__ */ jsx8("div", { className: "truncate text-xs leading-tight text-muted-foreground", children: metaLine })
|
|
1278
|
+
] })
|
|
1279
|
+
]
|
|
1280
|
+
}
|
|
1281
|
+
),
|
|
1282
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
1283
|
+
visibleBadges.length > 0 && visibleBadges.slice(0, 1).map((badge) => /* @__PURE__ */ jsx8(
|
|
1284
|
+
"span",
|
|
1285
|
+
{
|
|
1286
|
+
className: cn(
|
|
1287
|
+
"rounded-full border px-1.5 py-px text-[8px] font-semibold uppercase",
|
|
1288
|
+
badgeTone(badge.tone)
|
|
1289
|
+
),
|
|
1290
|
+
children: badge.label
|
|
1291
|
+
},
|
|
1292
|
+
badge.id
|
|
1293
|
+
)),
|
|
1294
|
+
session?.isForeground && /* @__PURE__ */ jsx8("span", { className: "h-1.5 w-1.5 rounded-full bg-[var(--status-running)]", title: "Live" }),
|
|
1295
|
+
renderItemActions ? /* @__PURE__ */ jsx8(
|
|
1296
|
+
"div",
|
|
1297
|
+
{
|
|
1298
|
+
className: cn("opacity-0 transition-opacity group-hover:opacity-100", MOTION_CONTROL),
|
|
1299
|
+
onClick: (event) => event.stopPropagation(),
|
|
1300
|
+
children: renderItemActions(item, { session, isActive })
|
|
1301
|
+
}
|
|
1302
|
+
) : null
|
|
1303
|
+
] })
|
|
1304
|
+
]
|
|
1305
|
+
}
|
|
1306
|
+
)
|
|
1307
|
+
},
|
|
1308
|
+
item.id
|
|
1309
|
+
);
|
|
1310
|
+
};
|
|
1311
|
+
let rowIndex = 0;
|
|
1097
1312
|
return /* @__PURE__ */ jsxs7(
|
|
1098
1313
|
"aside",
|
|
1099
1314
|
{
|
|
1100
|
-
className: cn(
|
|
1101
|
-
|
|
1315
|
+
className: cn(
|
|
1316
|
+
"relative flex shrink-0 flex-col border-r border-[var(--md3-outline-variant)] bg-surface-container-low",
|
|
1317
|
+
fillsParent && "h-full w-full",
|
|
1318
|
+
className
|
|
1319
|
+
),
|
|
1320
|
+
style: fillsParent ? void 0 : { width: resizable ? resize.width : defaultWidth },
|
|
1102
1321
|
children: [
|
|
1103
|
-
|
|
1322
|
+
quiet ? /* @__PURE__ */ jsxs7("div", { className: "flex h-14 shrink-0 items-center justify-between gap-2 px-3", children: [
|
|
1323
|
+
/* @__PURE__ */ jsx8("span", { className: "sr-only", children: title }),
|
|
1324
|
+
onCreate ? /* @__PURE__ */ jsxs7(
|
|
1325
|
+
"button",
|
|
1326
|
+
{
|
|
1327
|
+
type: "button",
|
|
1328
|
+
onClick: onCreate,
|
|
1329
|
+
className: cn("flex items-center gap-1.5 rounded-md px-1.5 py-1 text-sm text-muted-foreground transition-colors hover:text-foreground", MOTION_CONTROL),
|
|
1330
|
+
children: [
|
|
1331
|
+
/* @__PURE__ */ jsx8(Plus, { className: "h-4 w-4", "aria-hidden": "true" }),
|
|
1332
|
+
/* @__PURE__ */ jsx8("span", { children: createLabel })
|
|
1333
|
+
]
|
|
1334
|
+
}
|
|
1335
|
+
) : /* @__PURE__ */ jsx8("span", {}),
|
|
1336
|
+
onCollapse && /* @__PURE__ */ jsx8(
|
|
1337
|
+
"button",
|
|
1338
|
+
{
|
|
1339
|
+
type: "button",
|
|
1340
|
+
onClick: onCollapse,
|
|
1341
|
+
"aria-label": "Hide chats",
|
|
1342
|
+
className: cn("flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-surface-container hover:text-foreground", MOTION_CONTROL),
|
|
1343
|
+
children: /* @__PURE__ */ jsx8(PanelLeftClose2, { className: "h-4 w-4" })
|
|
1344
|
+
}
|
|
1345
|
+
)
|
|
1346
|
+
] }) : /* @__PURE__ */ jsx8(WorkspacePaneHeader, { children: /* @__PURE__ */ jsxs7("div", { className: "flex w-full items-center justify-between gap-2", children: [
|
|
1104
1347
|
/* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1105
1348
|
/* @__PURE__ */ jsx8("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-[var(--radius-sm)] border border-[var(--border-accent)] bg-[var(--accent-surface-soft)] text-primary", children: /* @__PURE__ */ jsx8(MessageSquareText, { className: "h-3.5 w-3.5" }) }),
|
|
1106
1349
|
/* @__PURE__ */ jsxs7("div", { className: "min-w-0", children: [
|
|
@@ -1122,129 +1365,69 @@ function SessionSidebar({
|
|
|
1122
1365
|
)
|
|
1123
1366
|
] })
|
|
1124
1367
|
] }) }),
|
|
1125
|
-
(enableSearch && items.length > 0 || filters.length > 0) && /* @__PURE__ */ jsxs7(
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
"
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
"
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1368
|
+
(enableSearch && items.length > 0 || filters.length > 0) && /* @__PURE__ */ jsxs7(
|
|
1369
|
+
"div",
|
|
1370
|
+
{
|
|
1371
|
+
className: cn(
|
|
1372
|
+
"shrink-0",
|
|
1373
|
+
quiet ? "px-3 pb-1" : "border-b border-[var(--md3-outline-variant)] px-3 py-2.5"
|
|
1374
|
+
),
|
|
1375
|
+
children: [
|
|
1376
|
+
enableSearch && effectiveItems.length > 0 && /* @__PURE__ */ jsxs7("div", { className: "relative", children: [
|
|
1377
|
+
/* @__PURE__ */ jsx8(Search2, { className: "pointer-events-none absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
|
|
1378
|
+
/* @__PURE__ */ jsx8(
|
|
1379
|
+
"input",
|
|
1380
|
+
{
|
|
1381
|
+
value: query,
|
|
1382
|
+
onChange: (event) => setQuery(event.target.value),
|
|
1383
|
+
placeholder: searchPlaceholder,
|
|
1384
|
+
"aria-label": searchPlaceholder,
|
|
1385
|
+
className: cn(
|
|
1386
|
+
quiet ? "h-8 w-full rounded-md border-0 bg-transparent pl-7 pr-2 text-sm text-foreground placeholder:text-muted-foreground transition-colors focus-visible:bg-surface-container focus-visible:outline-none" : "h-8 w-full rounded-[var(--radius-sm)] border border-[var(--md3-outline-variant)] bg-surface-container-lowest pl-7 pr-2 text-sm text-foreground placeholder:text-muted-foreground transition-colors focus-visible:border-[var(--border-accent)] focus-visible:bg-transparent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--border-accent)]",
|
|
1387
|
+
MOTION_CONTROL
|
|
1388
|
+
)
|
|
1389
|
+
}
|
|
1390
|
+
)
|
|
1391
|
+
] }),
|
|
1392
|
+
filters.length > 0 && /* @__PURE__ */ jsx8("div", { className: cn("flex flex-wrap gap-1", enableSearch && items.length > 0 && "mt-2"), children: filters.map((filter) => {
|
|
1393
|
+
const isSelected = activeFilterId === filter.id;
|
|
1394
|
+
return /* @__PURE__ */ jsxs7(
|
|
1395
|
+
"button",
|
|
1396
|
+
{
|
|
1397
|
+
type: "button",
|
|
1398
|
+
onClick: () => setActiveFilterId(filter.id),
|
|
1399
|
+
className: cn(
|
|
1400
|
+
"inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs font-medium transition-colors",
|
|
1401
|
+
MOTION_CONTROL,
|
|
1402
|
+
isSelected ? "border-[var(--border-accent)] bg-[var(--accent-surface-soft)] text-primary" : "border-[var(--md3-outline-variant)] text-muted-foreground hover:text-foreground"
|
|
1403
|
+
),
|
|
1404
|
+
children: [
|
|
1405
|
+
/* @__PURE__ */ jsx8("span", { children: filter.label }),
|
|
1406
|
+
/* @__PURE__ */ jsx8("span", { className: "text-[11px] opacity-60", children: filterCounts[filter.id] ?? 0 })
|
|
1407
|
+
]
|
|
1408
|
+
},
|
|
1409
|
+
filter.id
|
|
1410
|
+
);
|
|
1411
|
+
}) })
|
|
1412
|
+
]
|
|
1413
|
+
}
|
|
1414
|
+
),
|
|
1160
1415
|
/* @__PURE__ */ jsx8("nav", { "aria-label": "Sessions", className: "flex-1 overflow-y-auto px-1.5 py-1.5", children: visibleItems.length === 0 ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-col items-center justify-center gap-2 px-4 py-10 text-center text-sm text-muted-foreground", children: [
|
|
1161
1416
|
/* @__PURE__ */ jsx8(MessageSquareText, { className: "h-5 w-5 opacity-50", "aria-hidden": "true" }),
|
|
1162
1417
|
/* @__PURE__ */ jsx8("p", { children: query.trim() ? `No sessions match "${query.trim()}".` : emptyMessage })
|
|
1163
|
-
] }) : /* @__PURE__ */
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
const status = session?.status ?? item.status;
|
|
1167
|
-
const isWorking = status === "running";
|
|
1168
|
-
const visibleBadges = [
|
|
1169
|
-
...item.isPinned ? [{ id: `${item.id}-pinned`, label: "Pinned", tone: "neutral" }] : [],
|
|
1170
|
-
...item.badges ?? []
|
|
1171
|
-
];
|
|
1172
|
-
return /* @__PURE__ */ jsx8(
|
|
1173
|
-
"li",
|
|
1418
|
+
] }) : showGroupLabels ? groups.map((group, groupIndex) => /* @__PURE__ */ jsxs7("section", { "aria-label": group.label ?? void 0, children: [
|
|
1419
|
+
/* @__PURE__ */ jsx8(
|
|
1420
|
+
"div",
|
|
1174
1421
|
{
|
|
1175
|
-
className:
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
),
|
|
1185
|
-
children: [
|
|
1186
|
-
/* @__PURE__ */ jsxs7(
|
|
1187
|
-
"button",
|
|
1188
|
-
{
|
|
1189
|
-
type: "button",
|
|
1190
|
-
onClick: () => {
|
|
1191
|
-
if (onSelectItem) {
|
|
1192
|
-
onSelectItem(item);
|
|
1193
|
-
return;
|
|
1194
|
-
}
|
|
1195
|
-
navigateToHref(item.href);
|
|
1196
|
-
},
|
|
1197
|
-
"aria-current": isActive ? "page" : void 0,
|
|
1198
|
-
className: "min-w-0 flex flex-1 items-center gap-2 text-left",
|
|
1199
|
-
children: [
|
|
1200
|
-
/* @__PURE__ */ jsx8("span", { className: cn("h-1.5 w-1.5 shrink-0 rounded-full", statusDot(status)) }),
|
|
1201
|
-
/* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1", children: [
|
|
1202
|
-
/* @__PURE__ */ jsx8(
|
|
1203
|
-
"div",
|
|
1204
|
-
{
|
|
1205
|
-
className: cn(
|
|
1206
|
-
"truncate text-sm font-medium",
|
|
1207
|
-
isActive && "text-foreground",
|
|
1208
|
-
isWorking && "agent-shimmer"
|
|
1209
|
-
),
|
|
1210
|
-
...isWorking ? { "data-motion": "essential" } : {},
|
|
1211
|
-
children: item.title
|
|
1212
|
-
}
|
|
1213
|
-
),
|
|
1214
|
-
item.subtitle && /* @__PURE__ */ jsx8("div", { className: "truncate text-xs leading-tight text-muted-foreground", children: item.subtitle })
|
|
1215
|
-
] })
|
|
1216
|
-
]
|
|
1217
|
-
}
|
|
1218
|
-
),
|
|
1219
|
-
/* @__PURE__ */ jsxs7("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
1220
|
-
visibleBadges.length > 0 && visibleBadges.slice(0, 1).map((badge) => /* @__PURE__ */ jsx8(
|
|
1221
|
-
"span",
|
|
1222
|
-
{
|
|
1223
|
-
className: cn(
|
|
1224
|
-
"rounded-full border px-1.5 py-px text-[8px] font-semibold uppercase",
|
|
1225
|
-
badgeTone(badge.tone)
|
|
1226
|
-
),
|
|
1227
|
-
children: badge.label
|
|
1228
|
-
},
|
|
1229
|
-
badge.id
|
|
1230
|
-
)),
|
|
1231
|
-
session?.isForeground && /* @__PURE__ */ jsx8("span", { className: "h-1.5 w-1.5 rounded-full bg-[var(--status-running)]", title: "Live" }),
|
|
1232
|
-
renderItemActions ? /* @__PURE__ */ jsx8(
|
|
1233
|
-
"div",
|
|
1234
|
-
{
|
|
1235
|
-
className: cn("opacity-0 transition-opacity group-hover:opacity-100", MOTION_CONTROL),
|
|
1236
|
-
onClick: (event) => event.stopPropagation(),
|
|
1237
|
-
children: renderItemActions(item, { session, isActive })
|
|
1238
|
-
}
|
|
1239
|
-
) : null
|
|
1240
|
-
] })
|
|
1241
|
-
]
|
|
1242
|
-
}
|
|
1243
|
-
)
|
|
1244
|
-
},
|
|
1245
|
-
item.id
|
|
1246
|
-
);
|
|
1247
|
-
}) }) }),
|
|
1422
|
+
className: cn(
|
|
1423
|
+
"px-2 pb-1 text-[11px] font-medium uppercase tracking-wider text-muted-foreground",
|
|
1424
|
+
groupIndex === 0 ? "pt-1" : "pt-3"
|
|
1425
|
+
),
|
|
1426
|
+
children: group.label
|
|
1427
|
+
}
|
|
1428
|
+
),
|
|
1429
|
+
/* @__PURE__ */ jsx8("ul", { className: "space-y-px", children: group.items.map((item) => renderRow(item, rowIndex++)) })
|
|
1430
|
+
] }, group.key)) : /* @__PURE__ */ jsx8("ul", { className: "space-y-px", children: visibleItems.map((item) => renderRow(item, rowIndex++)) }) }),
|
|
1248
1431
|
activityMonitor && /* @__PURE__ */ jsx8("div", { className: "border-t border-[var(--md3-outline-variant)] px-2 py-1.5", children: activityMonitor }),
|
|
1249
1432
|
links.length > 0 && /* @__PURE__ */ jsx8("nav", { "aria-label": "Workspace sections", className: "border-t border-[var(--md3-outline-variant)] px-1.5 py-1.5", children: /* @__PURE__ */ jsx8("div", { className: "space-y-px", children: links.map((link) => {
|
|
1250
1433
|
const Icon = iconForLink(link.icon);
|
|
@@ -1434,6 +1617,13 @@ function artifactTabLabel(artifact) {
|
|
|
1434
1617
|
if (artifact.kind === "file") return artifact.filename;
|
|
1435
1618
|
return "Artifact";
|
|
1436
1619
|
}
|
|
1620
|
+
function sortPinnedFirst(artifacts) {
|
|
1621
|
+
if (!artifacts.some((artifact) => artifact.pinned)) return artifacts;
|
|
1622
|
+
return [
|
|
1623
|
+
...artifacts.filter((artifact) => artifact.pinned),
|
|
1624
|
+
...artifacts.filter((artifact) => !artifact.pinned)
|
|
1625
|
+
];
|
|
1626
|
+
}
|
|
1437
1627
|
function ArtifactTabs({
|
|
1438
1628
|
artifacts,
|
|
1439
1629
|
activeArtifactId,
|
|
@@ -1442,7 +1632,7 @@ function ArtifactTabs({
|
|
|
1442
1632
|
}) {
|
|
1443
1633
|
if (artifacts.length === 0) return null;
|
|
1444
1634
|
return /* @__PURE__ */ jsx10("div", { className: "flex items-center overflow-x-auto border-b border-[var(--md3-outline-variant)] bg-surface-container-high", children: artifacts.map((artifact) => {
|
|
1445
|
-
const Icon = getArtifactTabIcon(artifact.kind);
|
|
1635
|
+
const Icon = artifact.icon ?? getArtifactTabIcon(artifact.kind);
|
|
1446
1636
|
const isActive = artifact.id === activeArtifactId;
|
|
1447
1637
|
return /* @__PURE__ */ jsxs9(
|
|
1448
1638
|
"div",
|
|
@@ -1464,7 +1654,7 @@ function ArtifactTabs({
|
|
|
1464
1654
|
]
|
|
1465
1655
|
}
|
|
1466
1656
|
),
|
|
1467
|
-
onClose && /* @__PURE__ */ jsx10(
|
|
1657
|
+
onClose && !artifact.pinned && /* @__PURE__ */ jsx10(
|
|
1468
1658
|
"button",
|
|
1469
1659
|
{
|
|
1470
1660
|
type: "button",
|
|
@@ -1551,6 +1741,9 @@ function regionHeader(sections, fallback) {
|
|
|
1551
1741
|
return fallback;
|
|
1552
1742
|
}
|
|
1553
1743
|
switch (sections[0]?.key) {
|
|
1744
|
+
// The rail brings its own header row.
|
|
1745
|
+
case "rail":
|
|
1746
|
+
return void 0;
|
|
1554
1747
|
case "directory":
|
|
1555
1748
|
return /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.12em] text-muted-foreground", children: [
|
|
1556
1749
|
/* @__PURE__ */ jsx10(FolderTree2, { className: "h-3.5 w-3.5" }),
|
|
@@ -1588,9 +1781,12 @@ function SandboxWorkbench({
|
|
|
1588
1781
|
title = "Sandbox session",
|
|
1589
1782
|
subtitle,
|
|
1590
1783
|
status,
|
|
1784
|
+
centerHeader: centerHeaderProp,
|
|
1785
|
+
composer,
|
|
1786
|
+
rail,
|
|
1591
1787
|
directory,
|
|
1592
1788
|
session,
|
|
1593
|
-
artifacts = [],
|
|
1789
|
+
artifacts: artifactsProp = [],
|
|
1594
1790
|
activeArtifactId,
|
|
1595
1791
|
onArtifactChange,
|
|
1596
1792
|
onArtifactClose,
|
|
@@ -1599,6 +1795,7 @@ function SandboxWorkbench({
|
|
|
1599
1795
|
emptyArtifactState,
|
|
1600
1796
|
className
|
|
1601
1797
|
}) {
|
|
1798
|
+
const artifacts = useMemo4(() => sortPinnedFirst(artifactsProp), [artifactsProp]);
|
|
1602
1799
|
const [uncontrolledArtifactId, setUncontrolledArtifactId] = useState5(
|
|
1603
1800
|
activeArtifactId ?? artifacts[0]?.id
|
|
1604
1801
|
);
|
|
@@ -1621,7 +1818,7 @@ function SandboxWorkbench({
|
|
|
1621
1818
|
}
|
|
1622
1819
|
onArtifactChange?.(artifactId);
|
|
1623
1820
|
};
|
|
1624
|
-
const
|
|
1821
|
+
const brandedHeader = /* @__PURE__ */ jsxs9("div", { className: "flex min-w-0 items-start justify-between gap-4 rounded-[var(--radius-xl)] border border-[var(--md3-outline-variant)] bg-surface-container px-4 py-3.5", children: [
|
|
1625
1822
|
/* @__PURE__ */ jsxs9("div", { className: "min-w-0", children: [
|
|
1626
1823
|
/* @__PURE__ */ jsx10("div", { className: "text-[10px] font-semibold uppercase tracking-[0.18em] text-primary", children: "Tangle Sandbox" }),
|
|
1627
1824
|
/* @__PURE__ */ jsx10("div", { className: "truncate text-[17px] font-semibold tracking-[0.01em] text-foreground", children: title }),
|
|
@@ -1635,8 +1832,22 @@ function SandboxWorkbench({
|
|
|
1635
1832
|
] })
|
|
1636
1833
|
] })
|
|
1637
1834
|
] });
|
|
1835
|
+
const quiet = centerHeaderProp === null;
|
|
1836
|
+
const centerHeader = centerHeaderProp === void 0 ? brandedHeader : centerHeaderProp ?? void 0;
|
|
1638
1837
|
const { composerControls, ...chatSession } = session;
|
|
1639
|
-
const
|
|
1838
|
+
const transcript = /* @__PURE__ */ jsxs9("div", { className: cn("flex h-full min-h-0 flex-col", quiet && "bg-surface"), children: [
|
|
1839
|
+
/* @__PURE__ */ jsx10(
|
|
1840
|
+
ChatContainer,
|
|
1841
|
+
{
|
|
1842
|
+
...chatSession,
|
|
1843
|
+
className: "min-h-0 flex-1",
|
|
1844
|
+
presentation: session.presentation ?? "timeline"
|
|
1845
|
+
}
|
|
1846
|
+
),
|
|
1847
|
+
composerControls && /* @__PURE__ */ jsx10("div", { className: "shrink-0 border-t border-[var(--md3-outline-variant)] bg-surface-container-high px-3 py-2", children: composerControls }),
|
|
1848
|
+
composer && /* @__PURE__ */ jsx10("div", { className: "shrink-0", children: /* @__PURE__ */ jsx10("div", { className: "mx-auto w-full max-w-3xl px-3 pb-3", children: composer }) })
|
|
1849
|
+
] });
|
|
1850
|
+
const center = quiet ? transcript : /* @__PURE__ */ jsx10(
|
|
1640
1851
|
ArtifactPane2,
|
|
1641
1852
|
{
|
|
1642
1853
|
eyebrow: session.eyebrow ?? "Agent Session",
|
|
@@ -1646,17 +1857,7 @@ function SandboxWorkbench({
|
|
|
1646
1857
|
headerActions: session.headerActions,
|
|
1647
1858
|
className: "h-full",
|
|
1648
1859
|
contentClassName: "bg-surface-container",
|
|
1649
|
-
children:
|
|
1650
|
-
/* @__PURE__ */ jsx10(
|
|
1651
|
-
ChatContainer,
|
|
1652
|
-
{
|
|
1653
|
-
...chatSession,
|
|
1654
|
-
className: "min-h-0 flex-1",
|
|
1655
|
-
presentation: session.presentation ?? "timeline"
|
|
1656
|
-
}
|
|
1657
|
-
),
|
|
1658
|
-
composerControls && /* @__PURE__ */ jsx10("div", { className: "shrink-0 border-t border-[var(--md3-outline-variant)] bg-surface-container-high px-3 py-2", children: composerControls })
|
|
1659
|
-
] })
|
|
1860
|
+
children: transcript
|
|
1660
1861
|
}
|
|
1661
1862
|
);
|
|
1662
1863
|
const artifactPanel = artifacts.length > 0 ? /* @__PURE__ */ jsxs9("section", { className: "flex h-full min-h-0 flex-col bg-surface-container", children: [
|
|
@@ -1686,6 +1887,9 @@ function SandboxWorkbench({
|
|
|
1686
1887
|
right: [],
|
|
1687
1888
|
bottom: []
|
|
1688
1889
|
};
|
|
1890
|
+
if (rail) {
|
|
1891
|
+
regionSections.left.push({ key: "rail", content: rail });
|
|
1892
|
+
}
|
|
1689
1893
|
if (directory && directoryPlacement !== "hidden") {
|
|
1690
1894
|
regionSections[directoryPlacement].push({
|
|
1691
1895
|
key: "directory",
|
|
@@ -1707,6 +1911,7 @@ function SandboxWorkbench({
|
|
|
1707
1911
|
const left = renderRegion(regionSections.left, "left");
|
|
1708
1912
|
const right = renderRegion(regionSections.right, "right");
|
|
1709
1913
|
const bottom = renderRegion(regionSections.bottom, "bottom");
|
|
1914
|
+
const railOnly = regionSections.left.length === 1 && regionSections.left[0]?.key === "rail";
|
|
1710
1915
|
const genericPanelsHeader = /* @__PURE__ */ jsx10("span", { className: "text-xs font-semibold uppercase tracking-[0.12em] text-muted-foreground", children: "Workspace Panels" });
|
|
1711
1916
|
return /* @__PURE__ */ jsx10(
|
|
1712
1917
|
WorkspaceLayout,
|
|
@@ -1732,6 +1937,14 @@ function SandboxWorkbench({
|
|
|
1732
1937
|
minRightWidth: layout?.minRightWidth,
|
|
1733
1938
|
maxRightWidth: layout?.maxRightWidth,
|
|
1734
1939
|
resizable: layout?.resizable,
|
|
1940
|
+
leftOpen: layout?.leftOpen,
|
|
1941
|
+
onLeftOpenChange: layout?.onLeftOpenChange,
|
|
1942
|
+
rightOpen: layout?.rightOpen,
|
|
1943
|
+
onRightOpenChange: layout?.onRightOpenChange,
|
|
1944
|
+
keyboardShortcuts: layout?.keyboardShortcuts,
|
|
1945
|
+
leftCollapsedControl: layout?.leftCollapsedControl,
|
|
1946
|
+
leftContentClassName: railOnly ? "py-0" : void 0,
|
|
1947
|
+
centerHeaderVisibility: quiet ? "auto" : "always",
|
|
1735
1948
|
className: cn("p-3 lg:p-4", className)
|
|
1736
1949
|
}
|
|
1737
1950
|
);
|
|
@@ -2371,6 +2584,7 @@ export {
|
|
|
2371
2584
|
StatusBar,
|
|
2372
2585
|
TerminalPanel,
|
|
2373
2586
|
RuntimePane,
|
|
2587
|
+
formatRelativeAge,
|
|
2374
2588
|
SESSION_CREATED_EVENT,
|
|
2375
2589
|
dispatchSessionCreated,
|
|
2376
2590
|
useOptimisticSessionItems,
|
package/dist/globals.css
CHANGED
|
@@ -368,6 +368,9 @@
|
|
|
368
368
|
.top-full {
|
|
369
369
|
top: 100%;
|
|
370
370
|
}
|
|
371
|
+
.-right-0\.5 {
|
|
372
|
+
right: calc(var(--spacing) * -0.5);
|
|
373
|
+
}
|
|
371
374
|
.-right-1 {
|
|
372
375
|
right: calc(var(--spacing) * -1);
|
|
373
376
|
}
|
|
@@ -389,6 +392,9 @@
|
|
|
389
392
|
.right-4 {
|
|
390
393
|
right: calc(var(--spacing) * 4);
|
|
391
394
|
}
|
|
395
|
+
.-bottom-0\.5 {
|
|
396
|
+
bottom: calc(var(--spacing) * -0.5);
|
|
397
|
+
}
|
|
392
398
|
.bottom-0 {
|
|
393
399
|
bottom: 0px;
|
|
394
400
|
}
|
|
@@ -919,6 +925,9 @@
|
|
|
919
925
|
.min-h-0 {
|
|
920
926
|
min-height: 0px;
|
|
921
927
|
}
|
|
928
|
+
.min-h-8 {
|
|
929
|
+
min-height: calc(var(--spacing) * 8);
|
|
930
|
+
}
|
|
922
931
|
.min-h-24 {
|
|
923
932
|
min-height: calc(var(--spacing) * 24);
|
|
924
933
|
}
|
|
@@ -2706,6 +2715,9 @@
|
|
|
2706
2715
|
.px-\[var\(--tool-card-px\)\] {
|
|
2707
2716
|
padding-inline: var(--tool-card-px);
|
|
2708
2717
|
}
|
|
2718
|
+
.py-0 {
|
|
2719
|
+
padding-block: 0px;
|
|
2720
|
+
}
|
|
2709
2721
|
.py-0\.5 {
|
|
2710
2722
|
padding-block: calc(var(--spacing) * 0.5);
|
|
2711
2723
|
}
|
|
@@ -2811,6 +2823,9 @@
|
|
|
2811
2823
|
.pr-2\.5 {
|
|
2812
2824
|
padding-right: calc(var(--spacing) * 2.5);
|
|
2813
2825
|
}
|
|
2826
|
+
.pr-3 {
|
|
2827
|
+
padding-right: calc(var(--spacing) * 3);
|
|
2828
|
+
}
|
|
2814
2829
|
.pr-8 {
|
|
2815
2830
|
padding-right: calc(var(--spacing) * 8);
|
|
2816
2831
|
}
|
|
@@ -2980,6 +2995,10 @@
|
|
|
2980
2995
|
--tw-leading: calc(var(--spacing) * 4);
|
|
2981
2996
|
line-height: calc(var(--spacing) * 4);
|
|
2982
2997
|
}
|
|
2998
|
+
.leading-5 {
|
|
2999
|
+
--tw-leading: calc(var(--spacing) * 5);
|
|
3000
|
+
line-height: calc(var(--spacing) * 5);
|
|
3001
|
+
}
|
|
2983
3002
|
.leading-6 {
|
|
2984
3003
|
--tw-leading: calc(var(--spacing) * 6);
|
|
2985
3004
|
line-height: calc(var(--spacing) * 6);
|
|
@@ -3315,6 +3334,12 @@
|
|
|
3315
3334
|
color: color-mix(in oklab, var(--color-foreground) 70%, transparent);
|
|
3316
3335
|
}
|
|
3317
3336
|
}
|
|
3337
|
+
.text-foreground\/75 {
|
|
3338
|
+
color: color-mix(in srgb, hsl(var(--foreground)) 75%, transparent);
|
|
3339
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
3340
|
+
color: color-mix(in oklab, var(--color-foreground) 75%, transparent);
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3318
3343
|
.text-foreground\/80 {
|
|
3319
3344
|
color: color-mix(in srgb, hsl(var(--foreground)) 80%, transparent);
|
|
3320
3345
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -3486,6 +3511,10 @@
|
|
|
3486
3511
|
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
3487
3512
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
3488
3513
|
}
|
|
3514
|
+
.shadow-\[0_1px_2px_rgba\(0\,0\,0\,0\.2\)\] {
|
|
3515
|
+
--tw-shadow: 0 1px 2px var(--tw-shadow-color, rgba(0,0,0,0.2));
|
|
3516
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
3517
|
+
}
|
|
3489
3518
|
.shadow-\[0_1px_2px_rgba\(15\,23\,42\,0\.04\)\] {
|
|
3490
3519
|
--tw-shadow: 0 1px 2px var(--tw-shadow-color, rgba(15,23,42,0.04));
|
|
3491
3520
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
@@ -3739,6 +3768,9 @@
|
|
|
3739
3768
|
border-color: color-mix(in oklab, var(--color-primary) 40%, transparent);
|
|
3740
3769
|
}
|
|
3741
3770
|
}
|
|
3771
|
+
.group-hover\:text-foreground:is(:where(.group):hover *) {
|
|
3772
|
+
color: var(--color-foreground);
|
|
3773
|
+
}
|
|
3742
3774
|
.group-hover\:text-foreground\/40:is(:where(.group):hover *) {
|
|
3743
3775
|
color: color-mix(in srgb, hsl(var(--foreground)) 40%, transparent);
|
|
3744
3776
|
}
|
|
@@ -4345,6 +4377,9 @@
|
|
|
4345
4377
|
background-color: color-mix(in oklab, var(--color-primary) 40%, transparent);
|
|
4346
4378
|
}
|
|
4347
4379
|
}
|
|
4380
|
+
.focus-visible\:bg-surface-container:focus-visible {
|
|
4381
|
+
background-color: var(--color-surface-container);
|
|
4382
|
+
}
|
|
4348
4383
|
.focus-visible\:bg-transparent:focus-visible {
|
|
4349
4384
|
background-color: transparent;
|
|
4350
4385
|
}
|
|
@@ -4714,6 +4749,9 @@
|
|
|
4714
4749
|
.lg\:items-center {
|
|
4715
4750
|
align-items: center;
|
|
4716
4751
|
}
|
|
4752
|
+
.lg\:p-0 {
|
|
4753
|
+
padding: 0px;
|
|
4754
|
+
}
|
|
4717
4755
|
.lg\:p-4 {
|
|
4718
4756
|
padding: calc(var(--spacing) * 4);
|
|
4719
4757
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { ArtifactPane, ArtifactPaneProps, Avatar, AvatarFallback, AvatarImage, Badge, BadgeProps, Button, ButtonProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CodeBlock, CodeBlockProps, CopyButton, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropZone, DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, EmptyStateProps, FilterField, FilterFieldProps, InlineCode, InlineCodeProps, Input, InputProps, Label, Metric, MetricProps, MetricStrip, MetricStripProps, Progress, SegmentedControl, SegmentedControlOption, SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SidebarDropZone, SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, StatCard, StatCardProps, StatusPill, StatusPillProps, StatusTone, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TerminalDisplay, TerminalCursor as TerminalDisplayCursor, TerminalInput as TerminalDisplayInput, TerminalLine as TerminalDisplayLine, Textarea, TextareaProps, ThemeToggle, Toast, ToastContainer, ToastProvider, Toolbar, ToolbarProps, UploadFile, UploadProgress, UploadProgressProps, badgeVariants, buttonVariants, useTheme, useToast } from '@tangle-network/ui/primitives';
|
|
2
2
|
export { L as Logo, a as LogoProps, T as TangleKnot } from './logo-CaIvk3J1.js';
|
|
3
3
|
export { CodeBlock as CodeBlockDisplay, Markdown, MarkdownProps } from '@tangle-network/ui/markdown';
|
|
4
|
-
export { AgentWorkbench, ApprovalConfidenceStat, ApprovalItem, ApprovalQueue, ApprovalQueueProps, AuditCheck, AuditResults, AuditResultsProps, BannerType, CalendarEvent, CalendarView, CalendarViewProps, ContextBadge, DirectoryPane, DirectoryPaneProps, FormAudit, RuntimePane, RuntimePaneProps, SESSION_CREATED_EVENT, SandboxWorkbench, SandboxWorkbenchArtifact, SandboxWorkbenchCustomArtifact, SandboxWorkbenchFileArtifact, SandboxWorkbenchLayoutOptions, SandboxWorkbenchMarkdownArtifact, SandboxWorkbenchOpenUIArtifact, SandboxWorkbenchProps, SandboxWorkbenchSessionProps, SessionActivityMonitor, SessionActivityMonitorProps, SessionCreatedDetail, SessionOptimisticController, SessionSidebar, SessionSidebarBadge, SessionSidebarFilter, SessionSidebarItem, SessionSidebarLink, SessionSidebarProps, ShellShouldRevalidateArgs, ShellShouldRevalidateOptions, StatusBanner, StatusBannerProps, StatusBar, StatusBarProps, TaskBoard, TaskBoardColumn, TaskBoardItem, TaskBoardProps, TerminalLine, TerminalPanel, TerminalProps, UseOptimisticSessionItemsOptions, WorkspaceLayout, WorkspaceLayoutProps, WorkspacePaneHeader, WorkspacePaneHeaderProps, createShellShouldRevalidate, dispatchSessionCreated, shellShouldRevalidate, useOptimisticSessionItems } from './workspace.js';
|
|
4
|
+
export { AgentWorkbench, ApprovalConfidenceStat, ApprovalItem, ApprovalQueue, ApprovalQueueProps, AuditCheck, AuditResults, AuditResultsProps, BannerType, CalendarEvent, CalendarView, CalendarViewProps, ContextBadge, DirectoryPane, DirectoryPaneProps, FormAudit, RuntimePane, RuntimePaneProps, SESSION_CREATED_EVENT, SandboxWorkbench, SandboxWorkbenchArtifact, SandboxWorkbenchCustomArtifact, SandboxWorkbenchFileArtifact, SandboxWorkbenchLayoutOptions, SandboxWorkbenchMarkdownArtifact, SandboxWorkbenchOpenUIArtifact, SandboxWorkbenchProps, SandboxWorkbenchSessionProps, SessionActivityMonitor, SessionActivityMonitorProps, SessionCreatedDetail, SessionOptimisticController, SessionSidebar, SessionSidebarBadge, SessionSidebarFilter, SessionSidebarGroupBy, SessionSidebarItem, SessionSidebarLink, SessionSidebarProps, SessionSidebarVariant, ShellShouldRevalidateArgs, ShellShouldRevalidateOptions, StatusBanner, StatusBannerProps, StatusBar, StatusBarProps, TaskBoard, TaskBoardColumn, TaskBoardItem, TaskBoardProps, TerminalLine, TerminalPanel, TerminalProps, UseOptimisticSessionItemsOptions, WorkspaceLayout, WorkspaceLayoutProps, WorkspacePaneHeader, WorkspacePaneHeaderProps, createShellShouldRevalidate, dispatchSessionCreated, formatRelativeAge, shellShouldRevalidate, useOptimisticSessionItems } from './workspace.js';
|
|
5
5
|
export { ArtifactView, BRAND_PRISM_THEME, ChangedFile, ChangesPane, ChangesPaneProps, CodeSurface, CodeSurfaceProps, CodeView, CodeViewProps, DiffStats, DiffStatsBadge, DiffView, DiffViewProps, FileBreadcrumb, FileBreadcrumbProps, GitStatusBadge, PanelHeader, PanelHeaderProps, PillTabItem, PillTabs, PillTabsProps, PreviewView, PreviewViewProps, SandboxArtifact, SandboxArtifactPane, SandboxArtifactPaneProps, SandboxArtifactTerminal, buildUnifiedPatch, computeDiffStats, resolveLanguage } from './workbench.js';
|
|
6
6
|
export { OpenUIAction, OpenUIActionsNode, OpenUIArtifactRenderer, OpenUIArtifactRendererProps, OpenUIBadgeNode, OpenUICardNode, OpenUICodeNode, OpenUIComponentNode, OpenUIGridNode, OpenUIHeadingNode, OpenUIKeyValueNode, OpenUIMarkdownNode, OpenUIPrimitive, OpenUISeparatorNode, OpenUIStackNode, OpenUIStatNode, OpenUITableNode, OpenUITextNode } from '@tangle-network/ui/openui';
|
|
7
7
|
export { AgentTimeline, AgentTimelineArtifactItem, AgentTimelineCustomItem, AgentTimelineItem, AgentTimelineMessageItem, AgentTimelineProps, AgentTimelineStatusItem, AgentTimelineTone, AgentTimelineToolGroupItem, AgentTimelineToolItem, ChatContainer, ChatContainerProps, ChatMessage, ChatMessageProps, MessageList, MessageListProps, MessageRole, ThinkingIndicator, ThinkingIndicatorProps, UserMessage, UserMessageProps } from '@tangle-network/ui/chat';
|
|
@@ -25,6 +25,7 @@ export { AgentBranding, CustomToolRenderer, DisplayVariant, FinalTextPart, Group
|
|
|
25
25
|
export { Session } from './types.js';
|
|
26
26
|
export { TOOL_CATEGORY_ICONS, cn, copyText, formatBytes, formatDuration, formatUptime, getToolCategory, getToolDisplayMetadata, getToolErrorText, timeAgo, truncateText } from '@tangle-network/ui/utils';
|
|
27
27
|
import 'react';
|
|
28
|
+
import 'lucide-react';
|
|
28
29
|
import '@radix-ui/react-dropdown-menu';
|
|
29
30
|
import '@tanstack/react-query';
|
|
30
31
|
import '@tangle-network/ui/sdk-hooks';
|
package/dist/index.js
CHANGED
|
@@ -130,9 +130,10 @@ import {
|
|
|
130
130
|
WorkspacePaneHeader,
|
|
131
131
|
createShellShouldRevalidate,
|
|
132
132
|
dispatchSessionCreated,
|
|
133
|
+
formatRelativeAge,
|
|
133
134
|
shellShouldRevalidate,
|
|
134
135
|
useOptimisticSessionItems
|
|
135
|
-
} from "./chunk-
|
|
136
|
+
} from "./chunk-2Q3KDQX7.js";
|
|
136
137
|
import {
|
|
137
138
|
BRAND_PRISM_THEME,
|
|
138
139
|
ChangesPane,
|
|
@@ -608,6 +609,7 @@ export {
|
|
|
608
609
|
formatBytes,
|
|
609
610
|
formatDuration,
|
|
610
611
|
formatPrice,
|
|
612
|
+
formatRelativeAge,
|
|
611
613
|
formatUptime,
|
|
612
614
|
getActiveSession,
|
|
613
615
|
getAllActiveSessions,
|
package/dist/styles.css
CHANGED
|
@@ -368,6 +368,9 @@
|
|
|
368
368
|
.top-full {
|
|
369
369
|
top: 100%;
|
|
370
370
|
}
|
|
371
|
+
.-right-0\.5 {
|
|
372
|
+
right: calc(var(--spacing) * -0.5);
|
|
373
|
+
}
|
|
371
374
|
.-right-1 {
|
|
372
375
|
right: calc(var(--spacing) * -1);
|
|
373
376
|
}
|
|
@@ -389,6 +392,9 @@
|
|
|
389
392
|
.right-4 {
|
|
390
393
|
right: calc(var(--spacing) * 4);
|
|
391
394
|
}
|
|
395
|
+
.-bottom-0\.5 {
|
|
396
|
+
bottom: calc(var(--spacing) * -0.5);
|
|
397
|
+
}
|
|
392
398
|
.bottom-0 {
|
|
393
399
|
bottom: 0px;
|
|
394
400
|
}
|
|
@@ -919,6 +925,9 @@
|
|
|
919
925
|
.min-h-0 {
|
|
920
926
|
min-height: 0px;
|
|
921
927
|
}
|
|
928
|
+
.min-h-8 {
|
|
929
|
+
min-height: calc(var(--spacing) * 8);
|
|
930
|
+
}
|
|
922
931
|
.min-h-24 {
|
|
923
932
|
min-height: calc(var(--spacing) * 24);
|
|
924
933
|
}
|
|
@@ -2706,6 +2715,9 @@
|
|
|
2706
2715
|
.px-\[var\(--tool-card-px\)\] {
|
|
2707
2716
|
padding-inline: var(--tool-card-px);
|
|
2708
2717
|
}
|
|
2718
|
+
.py-0 {
|
|
2719
|
+
padding-block: 0px;
|
|
2720
|
+
}
|
|
2709
2721
|
.py-0\.5 {
|
|
2710
2722
|
padding-block: calc(var(--spacing) * 0.5);
|
|
2711
2723
|
}
|
|
@@ -2811,6 +2823,9 @@
|
|
|
2811
2823
|
.pr-2\.5 {
|
|
2812
2824
|
padding-right: calc(var(--spacing) * 2.5);
|
|
2813
2825
|
}
|
|
2826
|
+
.pr-3 {
|
|
2827
|
+
padding-right: calc(var(--spacing) * 3);
|
|
2828
|
+
}
|
|
2814
2829
|
.pr-8 {
|
|
2815
2830
|
padding-right: calc(var(--spacing) * 8);
|
|
2816
2831
|
}
|
|
@@ -2980,6 +2995,10 @@
|
|
|
2980
2995
|
--tw-leading: calc(var(--spacing) * 4);
|
|
2981
2996
|
line-height: calc(var(--spacing) * 4);
|
|
2982
2997
|
}
|
|
2998
|
+
.leading-5 {
|
|
2999
|
+
--tw-leading: calc(var(--spacing) * 5);
|
|
3000
|
+
line-height: calc(var(--spacing) * 5);
|
|
3001
|
+
}
|
|
2983
3002
|
.leading-6 {
|
|
2984
3003
|
--tw-leading: calc(var(--spacing) * 6);
|
|
2985
3004
|
line-height: calc(var(--spacing) * 6);
|
|
@@ -3315,6 +3334,12 @@
|
|
|
3315
3334
|
color: color-mix(in oklab, var(--color-foreground) 70%, transparent);
|
|
3316
3335
|
}
|
|
3317
3336
|
}
|
|
3337
|
+
.text-foreground\/75 {
|
|
3338
|
+
color: color-mix(in srgb, hsl(var(--foreground)) 75%, transparent);
|
|
3339
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
3340
|
+
color: color-mix(in oklab, var(--color-foreground) 75%, transparent);
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3318
3343
|
.text-foreground\/80 {
|
|
3319
3344
|
color: color-mix(in srgb, hsl(var(--foreground)) 80%, transparent);
|
|
3320
3345
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -3486,6 +3511,10 @@
|
|
|
3486
3511
|
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
3487
3512
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
3488
3513
|
}
|
|
3514
|
+
.shadow-\[0_1px_2px_rgba\(0\,0\,0\,0\.2\)\] {
|
|
3515
|
+
--tw-shadow: 0 1px 2px var(--tw-shadow-color, rgba(0,0,0,0.2));
|
|
3516
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
3517
|
+
}
|
|
3489
3518
|
.shadow-\[0_1px_2px_rgba\(15\,23\,42\,0\.04\)\] {
|
|
3490
3519
|
--tw-shadow: 0 1px 2px var(--tw-shadow-color, rgba(15,23,42,0.04));
|
|
3491
3520
|
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
@@ -3739,6 +3768,9 @@
|
|
|
3739
3768
|
border-color: color-mix(in oklab, var(--color-primary) 40%, transparent);
|
|
3740
3769
|
}
|
|
3741
3770
|
}
|
|
3771
|
+
.group-hover\:text-foreground:is(:where(.group):hover *) {
|
|
3772
|
+
color: var(--color-foreground);
|
|
3773
|
+
}
|
|
3742
3774
|
.group-hover\:text-foreground\/40:is(:where(.group):hover *) {
|
|
3743
3775
|
color: color-mix(in srgb, hsl(var(--foreground)) 40%, transparent);
|
|
3744
3776
|
}
|
|
@@ -4345,6 +4377,9 @@
|
|
|
4345
4377
|
background-color: color-mix(in oklab, var(--color-primary) 40%, transparent);
|
|
4346
4378
|
}
|
|
4347
4379
|
}
|
|
4380
|
+
.focus-visible\:bg-surface-container:focus-visible {
|
|
4381
|
+
background-color: var(--color-surface-container);
|
|
4382
|
+
}
|
|
4348
4383
|
.focus-visible\:bg-transparent:focus-visible {
|
|
4349
4384
|
background-color: transparent;
|
|
4350
4385
|
}
|
|
@@ -4714,6 +4749,9 @@
|
|
|
4714
4749
|
.lg\:items-center {
|
|
4715
4750
|
align-items: center;
|
|
4716
4751
|
}
|
|
4752
|
+
.lg\:p-0 {
|
|
4753
|
+
padding: 0px;
|
|
4754
|
+
}
|
|
4717
4755
|
.lg\:p-4 {
|
|
4718
4756
|
padding: calc(var(--spacing) * 4);
|
|
4719
4757
|
}
|
package/dist/workspace.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { ReactNode, HTMLAttributes, Ref } from 'react';
|
|
|
3
3
|
export { ArtifactPane, ArtifactPaneProps } from '@tangle-network/ui/primitives';
|
|
4
4
|
import { FileNode, FileTreeVisibilityOptions, FileTabData } from '@tangle-network/ui/files';
|
|
5
5
|
import { SessionProjectKey, ActiveSessionStatus, ActiveSessionRecord } from '@tangle-network/ui/stores';
|
|
6
|
+
import { LucideIcon } from 'lucide-react';
|
|
6
7
|
import { ChatContainerProps } from '@tangle-network/ui/chat';
|
|
7
8
|
import { OpenUIComponentNode, OpenUIAction } from '@tangle-network/ui/openui';
|
|
8
9
|
|
|
@@ -63,9 +64,42 @@ interface WorkspaceLayoutProps {
|
|
|
63
64
|
rightLabel?: string;
|
|
64
65
|
/** Accessible label for the bottom panel */
|
|
65
66
|
bottomLabel?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Controlled open state for the left pane. Omit to keep the pane
|
|
69
|
+
* uncontrolled (`defaultLeftOpen`, persisted under `persistenceKey`).
|
|
70
|
+
*/
|
|
71
|
+
leftOpen?: boolean;
|
|
72
|
+
/** Called with the next state whenever the layout would open or close the left pane. */
|
|
73
|
+
onLeftOpenChange?: (open: boolean) => void;
|
|
74
|
+
/** Controlled open state for the right pane; see `leftOpen`. */
|
|
75
|
+
rightOpen?: boolean;
|
|
76
|
+
/** Called with the next state whenever the layout would open or close the right pane. */
|
|
77
|
+
onRightOpenChange?: (open: boolean) => void;
|
|
78
|
+
/**
|
|
79
|
+
* ⌘B / Ctrl+B toggles the left pane and ⌘E / Ctrl+E the right pane. A
|
|
80
|
+
* chord with Alt or Shift, or one fired while an input, textarea, select, or
|
|
81
|
+
* contentEditable has focus, is left to the page. Off by default.
|
|
82
|
+
*/
|
|
83
|
+
keyboardShortcuts?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Replaces the default "Open left panel" button at the top-left of the
|
|
86
|
+
* center pane while a left pane is provided but closed.
|
|
87
|
+
*/
|
|
88
|
+
leftCollapsedControl?: ReactNode;
|
|
89
|
+
/** Extra classes for the left pane's scrolling content wrapper, e.g. `py-0` so a rail owns its own gutter. */
|
|
90
|
+
leftContentClassName?: string;
|
|
91
|
+
/** Extra classes for the right pane's scrolling content wrapper. */
|
|
92
|
+
rightContentClassName?: string;
|
|
93
|
+
/**
|
|
94
|
+
* `always` (default) keeps the center header row whenever a side or bottom
|
|
95
|
+
* pane exists, so pane headers line up across the shell even while the row
|
|
96
|
+
* is empty. `auto` renders the row only while it has content: a
|
|
97
|
+
* `centerHeader`, or an open-pane toggle for a closed pane.
|
|
98
|
+
*/
|
|
99
|
+
centerHeaderVisibility?: "always" | "auto";
|
|
66
100
|
className?: string;
|
|
67
101
|
}
|
|
68
|
-
declare function WorkspaceLayout({ left, leftHeader, center, centerHeader, centerFooter, right, rightHeader, bottom, bottomHeader, defaultLeftOpen, defaultRightOpen, defaultBottomOpen, defaultLeftWidth, defaultRightWidth, defaultBottomHeight, minLeftWidth, maxLeftWidth, minRightWidth, maxRightWidth, minBottomHeight, maxBottomHeight, persistenceKey, resizable, theme, density, leftLabel, rightLabel, bottomLabel, className, }: WorkspaceLayoutProps): React$1.JSX.Element;
|
|
102
|
+
declare function WorkspaceLayout({ left, leftHeader, center, centerHeader, centerFooter, right, rightHeader, bottom, bottomHeader, defaultLeftOpen, defaultRightOpen, defaultBottomOpen, defaultLeftWidth, defaultRightWidth, defaultBottomHeight, minLeftWidth, maxLeftWidth, minRightWidth, maxRightWidth, minBottomHeight, maxBottomHeight, persistenceKey, resizable, theme, density, leftLabel, rightLabel, bottomLabel, leftOpen: leftOpenProp, onLeftOpenChange, rightOpen: rightOpenProp, onRightOpenChange, keyboardShortcuts, leftCollapsedControl, leftContentClassName, rightContentClassName, centerHeaderVisibility, className, }: WorkspaceLayoutProps): React$1.JSX.Element;
|
|
69
103
|
|
|
70
104
|
type WorkspacePaneHeaderProps = HTMLAttributes<HTMLDivElement>;
|
|
71
105
|
/**
|
|
@@ -243,6 +277,17 @@ interface SessionSidebarItem {
|
|
|
243
277
|
category?: string;
|
|
244
278
|
isPinned?: boolean;
|
|
245
279
|
badges?: SessionSidebarBadge[];
|
|
280
|
+
/**
|
|
281
|
+
* Glyph rendered in a 16×20 slot before the title — a harness mark, for
|
|
282
|
+
* example. While an icon is present the status dot becomes a 6px badge on
|
|
283
|
+
* the icon's corner instead of a leading dot.
|
|
284
|
+
*/
|
|
285
|
+
icon?: ReactNode;
|
|
286
|
+
/**
|
|
287
|
+
* Muted 12px line under the title, e.g. `harness · age`. When omitted and
|
|
288
|
+
* `showUpdatedAt` is set, the row renders `updatedAt` as a relative age here.
|
|
289
|
+
*/
|
|
290
|
+
meta?: ReactNode;
|
|
246
291
|
}
|
|
247
292
|
interface SessionSidebarBadge {
|
|
248
293
|
id: string;
|
|
@@ -263,6 +308,8 @@ interface SessionSidebarFilter {
|
|
|
263
308
|
isActive: boolean;
|
|
264
309
|
}) => boolean;
|
|
265
310
|
}
|
|
311
|
+
type SessionSidebarVariant = "default" | "quiet";
|
|
312
|
+
type SessionSidebarGroupBy = "none" | "status";
|
|
266
313
|
interface SessionSidebarProps {
|
|
267
314
|
title: string;
|
|
268
315
|
subtitle?: string;
|
|
@@ -304,8 +351,45 @@ interface SessionSidebarProps {
|
|
|
304
351
|
* handlers. Only populated when `optimistic` is enabled.
|
|
305
352
|
*/
|
|
306
353
|
optimisticRef?: Ref<SessionOptimisticController | null>;
|
|
354
|
+
/**
|
|
355
|
+
* `default` is the branded panel: icon-in-a-box header, running-count chip,
|
|
356
|
+
* bordered search field, accent-filled selected row. `quiet` is the rail of a
|
|
357
|
+
* three-pane shell: the header is one row (a "new" text button plus the
|
|
358
|
+
* optional `onCollapse` button), rows are `rounded-lg` with a surface fill
|
|
359
|
+
* for hover and selection, only non-neutral badges render, and search is a
|
|
360
|
+
* borderless field.
|
|
361
|
+
*/
|
|
362
|
+
variant?: SessionSidebarVariant;
|
|
363
|
+
/**
|
|
364
|
+
* `status` partitions the list into "Needs input" (`attention-needed`),
|
|
365
|
+
* "Failed" (`error`), "Working" (`running`), and "Done" (everything else),
|
|
366
|
+
* in that order. Group labels render only while more than one group has
|
|
367
|
+
* items. Within a group the sort is unchanged: pinned first, then activity.
|
|
368
|
+
* Status comes from the active-sessions store record when one exists for the
|
|
369
|
+
* id, else from `item.status`.
|
|
370
|
+
*/
|
|
371
|
+
groupBy?: SessionSidebarGroupBy;
|
|
372
|
+
/** Render `updatedAt` as a relative age under the title for rows with no `meta`. */
|
|
373
|
+
showUpdatedAt?: boolean;
|
|
374
|
+
/** Renders a "Hide chats" button in the `quiet` header. */
|
|
375
|
+
onCollapse?: () => void;
|
|
376
|
+
/**
|
|
377
|
+
* Fill the parent instead of carrying the sidebar's own width: no inline
|
|
378
|
+
* width, `h-full w-full`. Use when a layout owns the pane size. Ignored while
|
|
379
|
+
* `resizable`, which needs the inline width it drags.
|
|
380
|
+
*/
|
|
381
|
+
fill?: boolean;
|
|
307
382
|
}
|
|
308
|
-
declare function SessionSidebar({ title, subtitle, projectId, items, currentItemId, createLabel, onCreate, onSelectItem, onSelectLink, links, className, emptyMessage, searchPlaceholder, enableSearch, activityMonitor, filters, defaultFilterId, resizable, defaultWidth, minWidth, maxWidth, onWidthChange, renderItemActions, optimistic, optimisticRef, }: SessionSidebarProps): React$1.JSX.Element;
|
|
383
|
+
declare function SessionSidebar({ title, subtitle, projectId, items, currentItemId, createLabel, onCreate, onSelectItem, onSelectLink, links, className, emptyMessage, searchPlaceholder, enableSearch, activityMonitor, filters, defaultFilterId, resizable, defaultWidth, minWidth, maxWidth, onWidthChange, renderItemActions, optimistic, optimisticRef, variant, groupBy, showUpdatedAt, onCollapse, fill, }: SessionSidebarProps): React$1.JSX.Element;
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Compact age for a session rail: `now`, `5m`, `3h`, `2d`, `3w`, `4mo`, `1y`.
|
|
387
|
+
* Unlike `timeAgo` from `@tangle-network/ui/utils` it accepts any date input,
|
|
388
|
+
* rolls past hours into days and beyond, and carries no "ago" suffix, so it
|
|
389
|
+
* fits a "codex · 2h" meta line. A future or unparseable date reads `now` /
|
|
390
|
+
* empty rather than a negative count. `now` is injectable for deterministic tests.
|
|
391
|
+
*/
|
|
392
|
+
declare function formatRelativeAge(date: string | number | Date, now?: number): string;
|
|
309
393
|
|
|
310
394
|
/**
|
|
311
395
|
* Snappy in-app navigation: a shared `shouldRevalidate` rule for the agent-app
|
|
@@ -402,6 +486,10 @@ interface SandboxWorkbenchArtifactBase {
|
|
|
402
486
|
headerActions?: ReactNode;
|
|
403
487
|
toolbar?: ReactNode;
|
|
404
488
|
footer?: ReactNode;
|
|
489
|
+
/** Tab glyph. Defaults per `kind`; a `custom` artifact usually names its own. */
|
|
490
|
+
icon?: LucideIcon;
|
|
491
|
+
/** A pinned artifact's tab sorts before the rest and carries no close button. */
|
|
492
|
+
pinned?: boolean;
|
|
405
493
|
}
|
|
406
494
|
interface SandboxWorkbenchFileArtifact extends SandboxWorkbenchArtifactBase {
|
|
407
495
|
kind: "file";
|
|
@@ -447,7 +535,7 @@ interface SandboxWorkbenchSessionProps extends Omit<ChatContainerProps, "classNa
|
|
|
447
535
|
renderUserMessageActions?: ChatContainerProps["renderUserMessageActions"];
|
|
448
536
|
renderToolActions?: ChatContainerProps["renderToolActions"];
|
|
449
537
|
}
|
|
450
|
-
interface SandboxWorkbenchLayoutOptions extends Pick<WorkspaceLayoutProps, "bottomHeader" | "defaultBottomOpen" | "defaultLeftOpen" | "defaultLeftWidth" | "defaultRightOpen" | "defaultRightWidth" | "density" | "maxLeftWidth" | "maxRightWidth" | "minLeftWidth" | "minRightWidth" | "persistenceKey" | "resizable" | "theme"> {
|
|
538
|
+
interface SandboxWorkbenchLayoutOptions extends Pick<WorkspaceLayoutProps, "bottomHeader" | "defaultBottomOpen" | "defaultLeftOpen" | "defaultLeftWidth" | "defaultRightOpen" | "defaultRightWidth" | "density" | "keyboardShortcuts" | "leftCollapsedControl" | "leftOpen" | "maxLeftWidth" | "maxRightWidth" | "minLeftWidth" | "minRightWidth" | "onLeftOpenChange" | "onRightOpenChange" | "persistenceKey" | "resizable" | "rightOpen" | "theme"> {
|
|
451
539
|
directoryPlacement?: SandboxWorkbenchPlacement;
|
|
452
540
|
artifactPlacement?: SandboxWorkbenchPlacement;
|
|
453
541
|
runtimePlacement?: SandboxWorkbenchPlacement;
|
|
@@ -456,6 +544,27 @@ interface SandboxWorkbenchProps {
|
|
|
456
544
|
title?: ReactNode;
|
|
457
545
|
subtitle?: ReactNode;
|
|
458
546
|
status?: ReactNode;
|
|
547
|
+
/**
|
|
548
|
+
* Header above the transcript. `undefined` keeps the branded session card
|
|
549
|
+
* (`Tangle Sandbox` / `title` / `status`), a node replaces it, and `null`
|
|
550
|
+
* removes it: the transcript then renders directly on `bg-surface` with no
|
|
551
|
+
* eyebrow/title frame around it, and the shell's center header row appears
|
|
552
|
+
* only while it holds an open-pane toggle.
|
|
553
|
+
*/
|
|
554
|
+
centerHeader?: ReactNode | null;
|
|
555
|
+
/**
|
|
556
|
+
* Composer rendered under the transcript on the panel background, inside the
|
|
557
|
+
* transcript's own `max-w-3xl` column. `session.composerControls`, when
|
|
558
|
+
* also given, sits above it as before.
|
|
559
|
+
*/
|
|
560
|
+
composer?: ReactNode;
|
|
561
|
+
/**
|
|
562
|
+
* First section of the left region, ahead of the directory pane — a
|
|
563
|
+
* `SessionSidebar` for a chats rail. A rail that is the only left section
|
|
564
|
+
* fills the pane: no region header, no gutter. Give it `fill` and
|
|
565
|
+
* `className="border-r-0"` so the layout's own divider is the only one.
|
|
566
|
+
*/
|
|
567
|
+
rail?: ReactNode;
|
|
459
568
|
directory?: DirectoryPaneProps;
|
|
460
569
|
session: SandboxWorkbenchSessionProps;
|
|
461
570
|
artifacts?: SandboxWorkbenchArtifact[];
|
|
@@ -472,7 +581,7 @@ interface SandboxWorkbenchProps {
|
|
|
472
581
|
* into a complete session surface: directory, agent timeline, artifacts, and
|
|
473
582
|
* runtime in one reusable shell.
|
|
474
583
|
*/
|
|
475
|
-
declare function SandboxWorkbench({ title, subtitle, status, directory, session, artifacts, activeArtifactId, onArtifactChange, onArtifactClose, runtime, layout, emptyArtifactState, className, }: SandboxWorkbenchProps): React$1.JSX.Element;
|
|
584
|
+
declare function SandboxWorkbench({ title, subtitle, status, centerHeader: centerHeaderProp, composer, rail, directory, session, artifacts: artifactsProp, activeArtifactId, onArtifactChange, onArtifactClose, runtime, layout, emptyArtifactState, className, }: SandboxWorkbenchProps): React$1.JSX.Element;
|
|
476
585
|
declare function AgentWorkbench(props: SandboxWorkbenchProps): React$1.JSX.Element;
|
|
477
586
|
|
|
478
587
|
/**
|
|
@@ -639,4 +748,4 @@ interface ApprovalQueueProps {
|
|
|
639
748
|
*/
|
|
640
749
|
declare function ApprovalQueue({ items, className, onApprove, onReject, renderItemDetail, renderTypeBadge, renderStats, canResolve, header, emptyState, showResolved: controlledShowResolved, }: ApprovalQueueProps): React$1.JSX.Element;
|
|
641
750
|
|
|
642
|
-
export { AgentWorkbench, type ApprovalConfidenceStat, type ApprovalItem, ApprovalQueue, type ApprovalQueueProps, type AuditCheck, AuditResults, type AuditResultsProps, type BannerType, type CalendarEvent, CalendarView, type CalendarViewProps, type ContextBadge, DirectoryPane, type DirectoryPaneProps, type FormAudit, RuntimePane, type RuntimePaneProps, SESSION_CREATED_EVENT, SandboxWorkbench, type SandboxWorkbenchArtifact, type SandboxWorkbenchCustomArtifact, type SandboxWorkbenchFileArtifact, type SandboxWorkbenchLayoutOptions, type SandboxWorkbenchMarkdownArtifact, type SandboxWorkbenchOpenUIArtifact, type SandboxWorkbenchProps, type SandboxWorkbenchSessionProps, SessionActivityMonitor, type SessionActivityMonitorProps, type SessionCreatedDetail, type SessionOptimisticController, SessionSidebar, type SessionSidebarBadge, type SessionSidebarFilter, type SessionSidebarItem, type SessionSidebarLink, type SessionSidebarProps, type ShellShouldRevalidateArgs, type ShellShouldRevalidateOptions, StatusBanner, type StatusBannerProps, StatusBar, type StatusBarProps, TaskBoard, type TaskBoardColumn, type TaskBoardItem, type TaskBoardProps, type TerminalLine, TerminalPanel, type TerminalProps, type UseOptimisticSessionItemsOptions, WorkspaceLayout, type WorkspaceLayoutProps, WorkspacePaneHeader, type WorkspacePaneHeaderProps, createShellShouldRevalidate, dispatchSessionCreated, shellShouldRevalidate, useOptimisticSessionItems };
|
|
751
|
+
export { AgentWorkbench, type ApprovalConfidenceStat, type ApprovalItem, ApprovalQueue, type ApprovalQueueProps, type AuditCheck, AuditResults, type AuditResultsProps, type BannerType, type CalendarEvent, CalendarView, type CalendarViewProps, type ContextBadge, DirectoryPane, type DirectoryPaneProps, type FormAudit, RuntimePane, type RuntimePaneProps, SESSION_CREATED_EVENT, SandboxWorkbench, type SandboxWorkbenchArtifact, type SandboxWorkbenchCustomArtifact, type SandboxWorkbenchFileArtifact, type SandboxWorkbenchLayoutOptions, type SandboxWorkbenchMarkdownArtifact, type SandboxWorkbenchOpenUIArtifact, type SandboxWorkbenchProps, type SandboxWorkbenchSessionProps, SessionActivityMonitor, type SessionActivityMonitorProps, type SessionCreatedDetail, type SessionOptimisticController, SessionSidebar, type SessionSidebarBadge, type SessionSidebarFilter, type SessionSidebarGroupBy, type SessionSidebarItem, type SessionSidebarLink, type SessionSidebarProps, type SessionSidebarVariant, type ShellShouldRevalidateArgs, type ShellShouldRevalidateOptions, StatusBanner, type StatusBannerProps, StatusBar, type StatusBarProps, TaskBoard, type TaskBoardColumn, type TaskBoardItem, type TaskBoardProps, type TerminalLine, TerminalPanel, type TerminalProps, type UseOptimisticSessionItemsOptions, WorkspaceLayout, type WorkspaceLayoutProps, WorkspacePaneHeader, type WorkspacePaneHeaderProps, createShellShouldRevalidate, dispatchSessionCreated, formatRelativeAge, shellShouldRevalidate, useOptimisticSessionItems };
|
package/dist/workspace.js
CHANGED
|
@@ -18,9 +18,10 @@ import {
|
|
|
18
18
|
WorkspacePaneHeader,
|
|
19
19
|
createShellShouldRevalidate,
|
|
20
20
|
dispatchSessionCreated,
|
|
21
|
+
formatRelativeAge,
|
|
21
22
|
shellShouldRevalidate,
|
|
22
23
|
useOptimisticSessionItems
|
|
23
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-2Q3KDQX7.js";
|
|
24
25
|
import "./chunk-BGVEHENC.js";
|
|
25
26
|
import "./chunk-EI44GEQ5.js";
|
|
26
27
|
import "./chunk-CZ7CSFO4.js";
|
|
@@ -44,6 +45,7 @@ export {
|
|
|
44
45
|
WorkspacePaneHeader,
|
|
45
46
|
createShellShouldRevalidate,
|
|
46
47
|
dispatchSessionCreated,
|
|
48
|
+
formatRelativeAge,
|
|
47
49
|
shellShouldRevalidate,
|
|
48
50
|
useOptimisticSessionItems
|
|
49
51
|
};
|
package/package.json
CHANGED