@tangle-network/sandbox-ui 0.113.7 → 0.114.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.
Files changed (106) hide show
  1. package/dist/WorkflowGraph-B-NsdYz_.js +1961 -0
  2. package/dist/assets.d.ts +214 -206
  3. package/dist/assets.js +1057 -908
  4. package/dist/auth-CWe17Hly.js +37 -0
  5. package/dist/auth.d.ts +2 -30
  6. package/dist/auth.js +2 -15
  7. package/dist/chat-BOvFAe6p.js +903 -0
  8. package/dist/chat.d.ts +2 -230
  9. package/dist/chat.js +2 -34
  10. package/dist/connectors.d.ts +52 -49
  11. package/dist/connectors.js +595 -643
  12. package/dist/dashboard-CZ3VgNPR.js +4969 -0
  13. package/dist/dashboard.d.ts +4 -1297
  14. package/dist/dashboard.js +4 -152
  15. package/dist/editor.d.ts +2 -1
  16. package/dist/editor.js +2 -31
  17. package/dist/files.d.ts +2 -6
  18. package/dist/files.js +2 -33
  19. package/dist/globals.css +63 -3
  20. package/dist/hooks.d.ts +146 -148
  21. package/dist/hooks.js +222 -55
  22. package/dist/index-CKRaj1pM.d.ts +776 -0
  23. package/dist/index-CXX5IpH2.d.ts +2 -0
  24. package/dist/index-DPePq7c8.d.ts +1340 -0
  25. package/dist/index-DiyLLZuJ.d.ts +230 -0
  26. package/dist/index-DvmZLMT1.d.ts +30 -0
  27. package/dist/index-I8ZLVtHd.d.ts +330 -0
  28. package/dist/index-PRM636Ex.d.ts +86 -0
  29. package/dist/index.d.ts +21 -33
  30. package/dist/index.js +21 -701
  31. package/dist/info-panel-C9cqDzOL.js +594 -0
  32. package/dist/integrations.d.ts +133 -141
  33. package/dist/integrations.js +491 -673
  34. package/dist/markdown.d.ts +2 -1
  35. package/dist/markdown.js +2 -13
  36. package/dist/model-I-NIxeM-.js +1250 -0
  37. package/dist/model-brand-B9A4H9pJ.d.ts +98 -0
  38. package/dist/model-brand-hMyDTUqB.js +624 -0
  39. package/dist/motion-DkyBRJb9.js +37 -0
  40. package/dist/openui.d.ts +2 -1
  41. package/dist/openui.js +2 -7
  42. package/dist/pages.d.ts +307 -300
  43. package/dist/pages.js +4404 -4181
  44. package/dist/primitives-Dh1vG6J3.js +113 -0
  45. package/dist/primitives.d.ts +2 -74
  46. package/dist/primitives.js +2 -204
  47. package/dist/provider-logo-DjqmConF.js +311 -0
  48. package/dist/run.d.ts +2 -1
  49. package/dist/run.js +2 -23
  50. package/dist/sdk-hooks.d.ts +3 -4
  51. package/dist/sdk-hooks.js +3 -31
  52. package/dist/sidecar-DgH_vQ6m.d.ts +9 -0
  53. package/dist/stores.d.ts +14 -15
  54. package/dist/stores.js +13 -81
  55. package/dist/styles.css +63 -3
  56. package/dist/template-card-L-4gmjx2.d.ts +90 -0
  57. package/dist/terminal-CN9ZgHRt.js +197 -0
  58. package/dist/terminal.d.ts +60 -60
  59. package/dist/terminal.js +2 -10
  60. package/dist/tokens.css +51 -0
  61. package/dist/types.d.ts +4 -11
  62. package/dist/types.js +0 -1
  63. package/dist/use-pty-session-C8cE0adT.js +669 -0
  64. package/dist/use-sidecar-auth-CCTJcrq7.d.ts +145 -0
  65. package/dist/use-sidecar-auth-DkdcufOz.js +742 -0
  66. package/dist/utils-DzWbktWG.js +2 -0
  67. package/dist/utils.d.ts +2 -1
  68. package/dist/utils.js +2 -37
  69. package/dist/workbench-BCaCKl-J.js +8347 -0
  70. package/dist/workbench.d.ts +2 -310
  71. package/dist/workbench.js +2 -44
  72. package/dist/workflows.d.ts +341 -339
  73. package/dist/workflows.js +74 -109
  74. package/dist/workspace-B6AtI6ld.js +2510 -0
  75. package/dist/workspace.d.ts +2 -761
  76. package/dist/workspace.js +2 -51
  77. package/package.json +46 -40
  78. package/dist/WorkflowGraph-2QOORYIR.js +0 -1722
  79. package/dist/chunk-2BUPSB7O.js +0 -0
  80. package/dist/chunk-3KBNPQQF.js +0 -2697
  81. package/dist/chunk-3LIXVEEE.js +0 -279
  82. package/dist/chunk-72UF2H5H.js +0 -707
  83. package/dist/chunk-AI25G5MX.js +0 -944
  84. package/dist/chunk-ANSC5AFC.js +0 -314
  85. package/dist/chunk-AZ3AWMTM.js +0 -8
  86. package/dist/chunk-BGVEHENC.js +0 -10
  87. package/dist/chunk-CZ7CSFO4.js +0 -39
  88. package/dist/chunk-DYXXYGS4.js +0 -4700
  89. package/dist/chunk-EI44GEQ5.js +0 -6
  90. package/dist/chunk-IACRDXER.js +0 -219
  91. package/dist/chunk-IOB2PW5Z.js +0 -55
  92. package/dist/chunk-M4K7ZGR2.js +0 -24
  93. package/dist/chunk-MYZAW4RX.js +0 -665
  94. package/dist/chunk-OMUIPJQZ.js +0 -555
  95. package/dist/chunk-RQZRXKMR.js +0 -398
  96. package/dist/chunk-SOKKTB7W.js +0 -230
  97. package/dist/chunk-TADGS4Q7.js +0 -1010
  98. package/dist/chunk-UCQNOUN3.js +0 -7964
  99. package/dist/chunk-ULPLRBMF.js +0 -34
  100. package/dist/chunk-WID73FPH.js +0 -89
  101. package/dist/chunk-X3YXP7FG.js +0 -38
  102. package/dist/logo-DiAjq759.d.ts +0 -15
  103. package/dist/model-brand-BNnaUKKZ.d.ts +0 -99
  104. package/dist/ports-list-CDIvTNnX.d.ts +0 -17
  105. package/dist/sdk-hooks-Djkjq4cp.d.ts +0 -145
  106. package/dist/template-card-Bn-Bw5xC.d.ts +0 -87
@@ -0,0 +1,776 @@
1
+ import { ArtifactPane as ArtifactPane$1, ArtifactPaneProps } from "@tangle-network/ui/primitives";
2
+ import { HTMLAttributes, ReactNode, Ref } from "react";
3
+ import { LucideIcon } from "lucide-react";
4
+ import { FileNode, FileTabData, FileTreeVisibilityOptions } from "@tangle-network/ui/files";
5
+ import { ActiveSessionRecord, ActiveSessionStatus, SessionProjectKey } from "@tangle-network/ui/stores";
6
+ import { ChatContainerProps } from "@tangle-network/ui/chat";
7
+ import { OpenUIAction, OpenUIComponentNode } from "@tangle-network/ui/openui";
8
+ //#region src/workspace/workspace-layout.d.ts
9
+ interface WorkspaceLayoutProps {
10
+ /** Left sidebar content (file tree, navigation) */
11
+ left?: ReactNode;
12
+ /** Left sidebar header */
13
+ leftHeader?: ReactNode;
14
+ /** Center main content */
15
+ center: ReactNode;
16
+ /** Center header (session name, etc.) */
17
+ centerHeader?: ReactNode;
18
+ /** Center footer (input bar) */
19
+ centerFooter?: ReactNode;
20
+ /** Right panel content (preview, editor) */
21
+ right?: ReactNode;
22
+ /** Right panel header */
23
+ rightHeader?: ReactNode;
24
+ /** Bottom panel (terminal) */
25
+ bottom?: ReactNode;
26
+ /** Bottom panel header */
27
+ bottomHeader?: ReactNode;
28
+ /** Default left panel state */
29
+ defaultLeftOpen?: boolean;
30
+ /** Default right panel state */
31
+ defaultRightOpen?: boolean;
32
+ /** Default bottom panel state */
33
+ defaultBottomOpen?: boolean;
34
+ /** Default left panel width in px */
35
+ defaultLeftWidth?: number;
36
+ /** Default right panel width in px */
37
+ defaultRightWidth?: number;
38
+ /** Default bottom panel height in px */
39
+ defaultBottomHeight?: number;
40
+ /** Minimum left panel width in px */
41
+ minLeftWidth?: number;
42
+ /** Maximum left panel width in px */
43
+ maxLeftWidth?: number;
44
+ /** Minimum right panel width in px */
45
+ minRightWidth?: number;
46
+ /** Maximum right panel width in px */
47
+ maxRightWidth?: number;
48
+ /**
49
+ * Width in px the center column keeps on desktop. When the shell is too
50
+ * narrow for the stored pane widths, the right pane yields down to its
51
+ * minimum first, then the left; the stored widths return when room does.
52
+ */
53
+ minCenterWidth?: number;
54
+ /** Minimum bottom panel height in px */
55
+ minBottomHeight?: number;
56
+ /** Maximum bottom panel height in px */
57
+ maxBottomHeight?: number;
58
+ /** Persist panel state and sizes in localStorage */
59
+ persistenceKey?: string;
60
+ /** Disable resize handles */
61
+ resizable?: boolean;
62
+ /** Visual theme for sandbox surfaces */
63
+ theme?: "vault";
64
+ /** Density mode for control sizing */
65
+ density?: "comfortable" | "compact";
66
+ /** Accessible label for the left panel */
67
+ leftLabel?: string;
68
+ /** Accessible label for the right panel */
69
+ rightLabel?: string;
70
+ /** Accessible label for the bottom panel */
71
+ bottomLabel?: string;
72
+ /**
73
+ * Controlled open state for the left pane. Omit to keep the pane
74
+ * uncontrolled (`defaultLeftOpen`, persisted under `persistenceKey`).
75
+ */
76
+ leftOpen?: boolean;
77
+ /** Called with the next state whenever the layout would open or close the left pane. */
78
+ onLeftOpenChange?: (open: boolean) => void;
79
+ /** Controlled open state for the right pane; see `leftOpen`. */
80
+ rightOpen?: boolean;
81
+ /** Called with the next state whenever the layout would open or close the right pane. */
82
+ onRightOpenChange?: (open: boolean) => void;
83
+ /**
84
+ * ⌘B / Ctrl+B toggles the left pane and ⌘E / Ctrl+E the right pane. A
85
+ * chord with Alt or Shift, or one fired while an input, textarea, select, or
86
+ * contentEditable has focus, is left to the page. Off by default.
87
+ */
88
+ keyboardShortcuts?: boolean;
89
+ /**
90
+ * Replaces the default "Open left panel" button at the top-left of the
91
+ * center pane while a left pane is provided but closed.
92
+ */
93
+ leftCollapsedControl?: ReactNode;
94
+ /** Extra classes for the left pane's scrolling content wrapper, e.g. `py-0` so a rail owns its own gutter. */
95
+ leftContentClassName?: string;
96
+ /** Extra classes for the right pane's scrolling content wrapper. */
97
+ rightContentClassName?: string;
98
+ /**
99
+ * `always` (default) keeps the center header row whenever a side or bottom
100
+ * pane exists, so pane headers line up across the shell even while the row
101
+ * is empty. `auto` renders the row only while it has content: a
102
+ * `centerHeader`, or an open-pane toggle for a closed pane.
103
+ */
104
+ centerHeaderVisibility?: "always" | "auto";
105
+ className?: string;
106
+ }
107
+ declare function WorkspaceLayout({ left, leftHeader, center, centerHeader, centerFooter, right, rightHeader, bottom, bottomHeader, defaultLeftOpen, defaultRightOpen, defaultBottomOpen, defaultLeftWidth, defaultRightWidth, defaultBottomHeight, minLeftWidth, maxLeftWidth, minRightWidth, maxRightWidth, minCenterWidth, minBottomHeight, maxBottomHeight, persistenceKey, resizable, theme, density, leftLabel, rightLabel, bottomLabel, leftOpen: leftOpenProp, onLeftOpenChange, rightOpen: rightOpenProp, onRightOpenChange, keyboardShortcuts, leftCollapsedControl, leftContentClassName, rightContentClassName, centerHeaderVisibility, className }: WorkspaceLayoutProps): import("react").JSX.Element;
108
+ //#endregion
109
+ //#region src/workspace/workspace-pane-header.d.ts
110
+ type WorkspacePaneHeaderProps = HTMLAttributes<HTMLDivElement>;
111
+ /**
112
+ * The shared 56px header row for top-level workspace panes and drawers.
113
+ * Bottom runtime panels intentionally use their own compact header.
114
+ */
115
+ declare function WorkspacePaneHeader({ className, ...props }: WorkspacePaneHeaderProps): import("react").JSX.Element;
116
+ //#endregion
117
+ //#region src/workspace/directory-pane.d.ts
118
+ interface DirectoryPaneProps {
119
+ root: FileNode;
120
+ selectedPath?: string;
121
+ onSelect?: (path: string, node: FileNode) => void;
122
+ onRefresh?: () => void;
123
+ onUpload?: () => void;
124
+ title?: string;
125
+ subtitle?: string;
126
+ defaultExpanded?: boolean;
127
+ searchPlaceholder?: string;
128
+ visibility?: FileTreeVisibilityOptions;
129
+ className?: string;
130
+ }
131
+ /**
132
+ * DirectoryPane — searchable file-system navigation surface for sandbox
133
+ * sessions.
134
+ */
135
+ declare function DirectoryPane({ root, selectedPath, onSelect, onRefresh, onUpload, title, subtitle, defaultExpanded, searchPlaceholder, visibility, className }: DirectoryPaneProps): import("react").JSX.Element;
136
+ //#endregion
137
+ //#region src/workspace/status-banner.d.ts
138
+ /**
139
+ * StatusBanner — full-width notification banner for connection/provisioning states.
140
+ */
141
+ type BannerType = "provisioning" | "connecting" | "error" | "warning" | "success" | "info";
142
+ interface StatusBannerProps {
143
+ type: BannerType;
144
+ message: string;
145
+ detail?: string;
146
+ onDismiss?: () => void;
147
+ className?: string;
148
+ }
149
+ declare function StatusBanner({ type, message, detail, onDismiss, className }: StatusBannerProps): import("react").JSX.Element;
150
+ //#endregion
151
+ //#region src/workspace/status-bar.d.ts
152
+ /**
153
+ * StatusBar — compact bottom bar: connection state, file/artifact context
154
+ * badges, credits. The active model lives in the input box, not here.
155
+ */
156
+ interface ContextBadge {
157
+ id: string;
158
+ label: string;
159
+ count?: number;
160
+ }
161
+ interface StatusBarProps {
162
+ /** @deprecated The model now lives in the input box; the status bar no longer
163
+ * renders it. Retained so existing callers keep type-checking. */
164
+ modelLabel?: string;
165
+ /** @deprecated See `modelLabel`. */
166
+ onModelClick?: () => void;
167
+ credits?: number;
168
+ contextBadges?: ContextBadge[];
169
+ onRemoveBadge?: (id: string) => void;
170
+ status?: "connected" | "connecting" | "disconnected" | "provisioning";
171
+ className?: string;
172
+ }
173
+ declare function StatusBar({ credits, contextBadges, onRemoveBadge, status, className }: StatusBarProps): import("react").JSX.Element;
174
+ //#endregion
175
+ //#region src/workspace/terminal-panel.d.ts
176
+ /**
177
+ * Terminal — read-only terminal output panel.
178
+ *
179
+ * Shows agent's bash command output with basic ANSI color support.
180
+ * Collapsible, auto-scrolls to bottom.
181
+ */
182
+ interface TerminalLine {
183
+ id: string;
184
+ text: string;
185
+ type: "command" | "stdout" | "stderr" | "system";
186
+ timestamp?: number;
187
+ }
188
+ interface TerminalProps {
189
+ lines: TerminalLine[];
190
+ title?: string;
191
+ isCollapsed?: boolean;
192
+ onToggle?: () => void;
193
+ onClose?: () => void;
194
+ maxHeight?: number;
195
+ className?: string;
196
+ }
197
+ declare function TerminalPanel({ lines, title, isCollapsed, onToggle, onClose, maxHeight, className }: TerminalProps): import("react").JSX.Element;
198
+ //#endregion
199
+ //#region src/workspace/runtime-pane.d.ts
200
+ interface RuntimePaneProps {
201
+ title?: string;
202
+ subtitle?: string;
203
+ statusBanner?: StatusBannerProps;
204
+ statusBar?: StatusBarProps;
205
+ /** When provided, replaces the entire 2-column grid with custom content (e.g. a full-pane TerminalView). */
206
+ content?: React.ReactNode;
207
+ terminal?: TerminalProps;
208
+ audit?: React.ReactNode;
209
+ inspector?: React.ReactNode;
210
+ footer?: React.ReactNode;
211
+ className?: string;
212
+ }
213
+ /**
214
+ * RuntimePane — shared operating surface for sandbox session state, terminal
215
+ * output, audit results, and runtime metadata.
216
+ */
217
+ declare function RuntimePane({ title, subtitle, statusBanner, statusBar, content, terminal, audit, inspector, footer, className }: RuntimePaneProps): import("react").JSX.Element;
218
+ //#endregion
219
+ //#region src/workspace/session-optimistic.d.ts
220
+ /**
221
+ * Optimistic session/thread list: reflect a just-created / renamed / deleted
222
+ * item in the sidebar INSTANTLY, before the server loader round-trips.
223
+ *
224
+ * The shell loader is the source of truth and reconciles in the background
225
+ * (typically the app calls `useRevalidator().revalidate()` after its mutation
226
+ * fetch settles). Until that lands, a local mirror of the loader items carries
227
+ * the optimistic edit so a delete / rename / new-thread does not feel broken
228
+ * for the duration of a D1 round-trip.
229
+ *
230
+ * Two ways to drive it, usable together:
231
+ * 1. A window `CustomEvent` (default name {@link SESSION_CREATED_EVENT}) — the
232
+ * surface that creates a thread (often a different route from the sidebar's
233
+ * route) dispatches it; the sidebar prepends the item with no prop wiring.
234
+ * 2. The imperative {@link SessionOptimisticController} returned here — the
235
+ * sidebar's own action handlers (rename / delete / pin) call it directly.
236
+ */
237
+ /** Default window-event name for "a session/thread was just created". */
238
+ declare const SESSION_CREATED_EVENT = "sandbox-thread-created";
239
+ /**
240
+ * Payload of a {@link SESSION_CREATED_EVENT}. Only `id` + `title` are required;
241
+ * everything else mirrors {@link SessionSidebarItem}. `updatedAt` defaults to
242
+ * now so the new item sorts to the top.
243
+ */
244
+ interface SessionCreatedDetail extends Partial<Omit<SessionSidebarItem, "id" | "title">> {
245
+ id: string;
246
+ title: string;
247
+ }
248
+ /** Dispatch the shared "session created" event so any mounted sidebar updates. */
249
+ declare function dispatchSessionCreated(detail: SessionCreatedDetail, eventName?: string): void;
250
+ /** Imperative handle for driving optimistic edits from a mutation handler. */
251
+ interface SessionOptimisticController {
252
+ /** Prepend (or move to top) an item — call before the create fetch settles. */
253
+ add: (item: SessionCreatedDetail) => void;
254
+ /** Patch an existing item in place — e.g. a rename or category change. */
255
+ update: (id: string, patch: Partial<SessionSidebarItem>) => void;
256
+ /** Drop an item — call before the delete fetch settles. */
257
+ remove: (id: string) => void;
258
+ /** Discard all optimistic edits and snap back to the loader items. */
259
+ reset: () => void;
260
+ }
261
+ interface UseOptimisticSessionItemsOptions {
262
+ /**
263
+ * Listen for the shared window create-event and prepend its item. Set `false`
264
+ * to drive optimistic state purely through the imperative controller.
265
+ * Defaults to `true`.
266
+ */
267
+ listenForCreate?: boolean;
268
+ /** Override the window event name to listen for. */
269
+ eventName?: string;
270
+ }
271
+ /**
272
+ * Mirror `items` with optimistic add/update/remove on top. The mirror re-syncs
273
+ * whenever `items` changes (the loader is authoritative), so an optimistic edit
274
+ * is naturally superseded once the server result arrives.
275
+ */
276
+ declare function useOptimisticSessionItems(items: SessionSidebarItem[], options?: UseOptimisticSessionItemsOptions): {
277
+ items: SessionSidebarItem[];
278
+ controller: SessionOptimisticController;
279
+ };
280
+ //#endregion
281
+ //#region src/workspace/session-sidebar.d.ts
282
+ interface SessionSidebarItem {
283
+ id: string;
284
+ title: string;
285
+ subtitle?: string;
286
+ href?: string;
287
+ updatedAt?: string | number | Date;
288
+ projectId?: SessionProjectKey | null;
289
+ status?: ActiveSessionStatus;
290
+ category?: string;
291
+ isPinned?: boolean;
292
+ badges?: SessionSidebarBadge[];
293
+ /**
294
+ * Glyph rendered in a 16×20 slot before the title — a harness mark, for
295
+ * example. While an icon is present the status dot becomes a 6px badge on
296
+ * the icon's corner instead of a leading dot.
297
+ */
298
+ icon?: ReactNode;
299
+ /**
300
+ * Muted 12px line under the title, e.g. `harness · age`. When omitted and
301
+ * `showUpdatedAt` is set, the row renders `updatedAt` as a relative age here.
302
+ */
303
+ meta?: ReactNode;
304
+ }
305
+ interface SessionSidebarBadge {
306
+ id: string;
307
+ label: string;
308
+ tone?: "neutral" | "accent" | "success" | "warning" | "danger";
309
+ }
310
+ interface SessionSidebarLink {
311
+ id: string;
312
+ label: string;
313
+ href?: string;
314
+ icon?: "vault" | "settings" | "back";
315
+ }
316
+ interface SessionSidebarFilter {
317
+ id: string;
318
+ label: string;
319
+ matches: (item: SessionSidebarItem, options: {
320
+ session: ActiveSessionRecord | null;
321
+ isActive: boolean;
322
+ }) => boolean;
323
+ }
324
+ type SessionSidebarVariant = "default" | "quiet";
325
+ type SessionSidebarGroupBy = "none" | "status";
326
+ interface SessionSidebarProps {
327
+ title: string;
328
+ subtitle?: string;
329
+ projectId?: SessionProjectKey | null;
330
+ items: SessionSidebarItem[];
331
+ currentItemId?: string | null;
332
+ createLabel?: string;
333
+ onCreate?: () => void;
334
+ onSelectItem?: (item: SessionSidebarItem) => void;
335
+ onSelectLink?: (link: SessionSidebarLink) => void;
336
+ links?: SessionSidebarLink[];
337
+ className?: string;
338
+ emptyMessage?: string;
339
+ searchPlaceholder?: string;
340
+ enableSearch?: boolean;
341
+ activityMonitor?: ReactNode;
342
+ filters?: SessionSidebarFilter[];
343
+ defaultFilterId?: string;
344
+ resizable?: boolean;
345
+ defaultWidth?: number;
346
+ minWidth?: number;
347
+ maxWidth?: number;
348
+ onWidthChange?: (width: number) => void;
349
+ renderItemActions?: (item: SessionSidebarItem, options: {
350
+ session: ActiveSessionRecord | null;
351
+ isActive: boolean;
352
+ }) => ReactNode;
353
+ /**
354
+ * Opt into optimistic item updates: the sidebar keeps a local mirror of
355
+ * `items` so a just-created / renamed / deleted thread shows instantly,
356
+ * before the loader round-trips. Pass `true` for defaults, or an options
357
+ * object to tune the window create-event. Off by default — existing callers
358
+ * render `items` verbatim and are unaffected.
359
+ */
360
+ optimistic?: boolean | UseOptimisticSessionItemsOptions;
361
+ /**
362
+ * Ref to the imperative optimistic controller (`add` / `update` / `remove` /
363
+ * `reset`). Drive optimistic edits from the consumer's own rename/delete/pin
364
+ * handlers. Only populated when `optimistic` is enabled.
365
+ */
366
+ optimisticRef?: Ref<SessionOptimisticController | null>;
367
+ /**
368
+ * `default` is the branded panel: icon-in-a-box header, running-count chip,
369
+ * bordered search field, accent-filled selected row. `quiet` is the rail of a
370
+ * three-pane shell: the header is one row (a "new" text button plus the
371
+ * optional `onCollapse` button), rows are `rounded-lg` with a surface fill
372
+ * for hover and selection, only non-neutral badges render, and search is a
373
+ * borderless field.
374
+ */
375
+ variant?: SessionSidebarVariant;
376
+ /**
377
+ * `status` partitions the list into "Needs input" (`attention-needed`),
378
+ * "Failed" (`error`), "Working" (`running`), and "Done" (everything else),
379
+ * in that order. Group labels render only while more than one group has
380
+ * items. Within a group the sort is unchanged: pinned first, then activity.
381
+ * Status comes from the active-sessions store record when one exists for the
382
+ * id, else from `item.status`.
383
+ */
384
+ groupBy?: SessionSidebarGroupBy;
385
+ /** Render `updatedAt` as a relative age under the title for rows with no `meta`. */
386
+ showUpdatedAt?: boolean;
387
+ /** Renders a "Hide chats" button in the `quiet` header. */
388
+ onCollapse?: () => void;
389
+ /**
390
+ * Fill the parent instead of carrying the sidebar's own width: no inline
391
+ * width, `h-full w-full`. Use when a layout owns the pane size. Ignored while
392
+ * `resizable`, which needs the inline width it drags.
393
+ */
394
+ fill?: boolean;
395
+ }
396
+ 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): import("react").JSX.Element;
397
+ //#endregion
398
+ //#region src/lib/format-relative-age.d.ts
399
+ /**
400
+ * Compact age for a session rail: `now`, `5m`, `3h`, `2d`, `3w`, `4mo`, `1y`.
401
+ * Unlike `timeAgo` from `@tangle-network/ui/utils` it accepts any date input,
402
+ * rolls past hours into days and beyond, and carries no "ago" suffix, so it
403
+ * fits a "codex · 2h" meta line. A future or unparseable date reads `now` /
404
+ * empty rather than a negative count. `now` is injectable for deterministic tests.
405
+ */
406
+ declare function formatRelativeAge(date: string | number | Date, now?: number): string;
407
+ //#endregion
408
+ //#region src/workspace/shell-revalidation.d.ts
409
+ /**
410
+ * Snappy in-app navigation: a shared `shouldRevalidate` rule for the agent-app
411
+ * shell route(s) that own the workspace-list / sidebar loader.
412
+ *
413
+ * The shell loader (user + workspace list, sidebar state) runs on every
414
+ * navigation, but its data does not change just by moving between in-app pages.
415
+ * Refetching it on every internal GET nav adds a loader round-trip to each
416
+ * click — on Cloudflare Workers + D1 (HTTP-proxied) that is a visible stall.
417
+ *
418
+ * This helper encodes the rule that makes nav feel instant WITHOUT stranding
419
+ * freshly-mutated data:
420
+ *
421
+ * - Non-GET navigation (form submit / action) → always revalidate.
422
+ * - Internal app→app navigation that CHANGES the path → skip revalidation.
423
+ * - Imperative `useRevalidator().revalidate()` (which targets the SAME url,
424
+ * so `currentUrl.pathname === nextUrl.pathname`) → revalidate. Creating a
425
+ * project / thread typically goes through a raw `fetch`, so a same-url
426
+ * revalidate is the ONLY way the new row reaches the shell loader; the
427
+ * same-path carve-out below is what keeps that working. Suppressing it is
428
+ * the project-switcher regression — do not "simplify" it away.
429
+ * - Anything else (cross-path-prefix nav, entering/leaving the app) →
430
+ * defer to `defaultShouldRevalidate`.
431
+ *
432
+ * Framework-agnostic by design: sandbox-ui does not depend on react-router, so
433
+ * this takes a plain args object. The shape is a structural subset of
434
+ * react-router's `ShouldRevalidateFunctionArgs`, so an app can wire it as a
435
+ * route export with no adapter:
436
+ *
437
+ * ```ts
438
+ * // app/routes/app.tsx
439
+ * import { shellShouldRevalidate } from "@tangle-network/sandbox-ui/workspace";
440
+ * export const shouldRevalidate = shellShouldRevalidate;
441
+ * ```
442
+ *
443
+ * `shouldRevalidate` MUST be a per-app react-router route export — it cannot be
444
+ * exported FROM a library on the app's behalf — so the "out of the box" win is
445
+ * the one-line re-export above instead of every app re-deriving the rule (and
446
+ * re-introducing the same-url bug).
447
+ */
448
+ /**
449
+ * The subset of react-router's `ShouldRevalidateFunctionArgs` this rule reads.
450
+ * Kept structural so callers can pass the full react-router args object as-is.
451
+ */
452
+ interface ShellShouldRevalidateArgs {
453
+ currentUrl: URL;
454
+ nextUrl: URL;
455
+ formMethod?: string;
456
+ defaultShouldRevalidate: boolean;
457
+ }
458
+ interface ShellShouldRevalidateOptions {
459
+ /**
460
+ * Path prefix that marks "inside the app shell". Internal navigation between
461
+ * two paths under this prefix skips the shell-loader refetch. Defaults to
462
+ * `"/app"`.
463
+ */
464
+ appPathPrefix?: string;
465
+ }
466
+ /**
467
+ * Build a `shouldRevalidate` function for the shell route under `appPathPrefix`.
468
+ * Use this when the app mounts under a non-default prefix; otherwise prefer the
469
+ * ready-made {@link shellShouldRevalidate} export.
470
+ */
471
+ declare function createShellShouldRevalidate(options?: ShellShouldRevalidateOptions): (args: ShellShouldRevalidateArgs) => boolean;
472
+ /**
473
+ * Ready-made shell `shouldRevalidate` for apps mounted under `/app`. Wire it as
474
+ * a one-line route export:
475
+ *
476
+ * ```ts
477
+ * export const shouldRevalidate = shellShouldRevalidate;
478
+ * ```
479
+ *
480
+ * For a non-`/app` prefix, use {@link createShellShouldRevalidate}.
481
+ */
482
+ declare const shellShouldRevalidate: (args: ShellShouldRevalidateArgs) => boolean;
483
+ //#endregion
484
+ //#region src/workspace/session-activity-monitor.d.ts
485
+ interface SessionActivityMonitorProps {
486
+ className?: string;
487
+ compact?: boolean;
488
+ sessionsById?: Record<string, ActiveSessionRecord>;
489
+ emptyMessage?: string;
490
+ resolveProjectLabel?: (projectId: SessionProjectKey, label?: string) => string;
491
+ onSelectSession?: (session: ActiveSessionRecord) => void;
492
+ }
493
+ declare function SessionActivityMonitor({ className, compact, sessionsById, emptyMessage, resolveProjectLabel, onSelectSession }: SessionActivityMonitorProps): import("react").JSX.Element | null;
494
+ //#endregion
495
+ //#region src/workspace/sandbox-workbench.d.ts
496
+ type SandboxWorkbenchPlacement = "left" | "right" | "bottom" | "hidden";
497
+ interface SandboxWorkbenchArtifactBase {
498
+ id: string;
499
+ title: ReactNode;
500
+ subtitle?: ReactNode;
501
+ eyebrow?: ReactNode;
502
+ meta?: ReactNode;
503
+ headerActions?: ReactNode;
504
+ toolbar?: ReactNode;
505
+ footer?: ReactNode;
506
+ /** Tab glyph. Defaults per `kind`; a `custom` artifact usually names its own. */
507
+ icon?: LucideIcon;
508
+ /** A pinned artifact's tab sorts before the rest and carries no close button. */
509
+ pinned?: boolean;
510
+ }
511
+ interface SandboxWorkbenchFileArtifact extends SandboxWorkbenchArtifactBase {
512
+ kind: "file";
513
+ path: string;
514
+ filename: string;
515
+ content?: string;
516
+ blobUrl?: string;
517
+ mimeType?: string;
518
+ onDownload?: () => void;
519
+ tabs?: FileTabData[];
520
+ activeTabId?: string;
521
+ onTabSelect?: (id: string) => void;
522
+ onTabClose?: (id: string) => void;
523
+ }
524
+ interface SandboxWorkbenchMarkdownArtifact extends SandboxWorkbenchArtifactBase {
525
+ kind: "markdown";
526
+ content: string;
527
+ }
528
+ interface SandboxWorkbenchOpenUIArtifact extends SandboxWorkbenchArtifactBase {
529
+ kind: "openui";
530
+ schema: OpenUIComponentNode | OpenUIComponentNode[];
531
+ onAction?: (action: OpenUIAction) => void;
532
+ }
533
+ interface SandboxWorkbenchCustomArtifact extends SandboxWorkbenchArtifactBase {
534
+ kind: "custom";
535
+ content: ReactNode;
536
+ }
537
+ type SandboxWorkbenchArtifact = SandboxWorkbenchCustomArtifact | SandboxWorkbenchFileArtifact | SandboxWorkbenchMarkdownArtifact | SandboxWorkbenchOpenUIArtifact;
538
+ interface SandboxWorkbenchSessionProps extends Omit<ChatContainerProps, "className"> {
539
+ eyebrow?: ReactNode;
540
+ title?: ReactNode;
541
+ subtitle?: ReactNode;
542
+ meta?: ReactNode;
543
+ headerActions?: ReactNode;
544
+ /**
545
+ * Controls rendered as a strip attached beneath the chat composer —
546
+ * harness/model/effort pickers, token meters, etc. Use
547
+ * `AgentSessionControls` from `@tangle-network/agent-app/web-react` for the
548
+ * standard set.
549
+ */
550
+ composerControls?: ReactNode;
551
+ renderRunActions?: ChatContainerProps["renderRunActions"];
552
+ renderUserMessageActions?: ChatContainerProps["renderUserMessageActions"];
553
+ renderToolActions?: ChatContainerProps["renderToolActions"];
554
+ }
555
+ 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"> {
556
+ directoryPlacement?: SandboxWorkbenchPlacement;
557
+ artifactPlacement?: SandboxWorkbenchPlacement;
558
+ runtimePlacement?: SandboxWorkbenchPlacement;
559
+ }
560
+ interface SandboxWorkbenchProps {
561
+ title?: ReactNode;
562
+ subtitle?: ReactNode;
563
+ status?: ReactNode;
564
+ /**
565
+ * Header above the transcript. `undefined` keeps the branded session card
566
+ * (`Tangle Sandbox` / `title` / `status`), a node replaces it, and `null`
567
+ * removes it: the transcript then renders directly on `bg-surface` with no
568
+ * eyebrow/title frame around it, and the shell's center header row appears
569
+ * only while it holds an open-pane toggle.
570
+ */
571
+ centerHeader?: ReactNode | null;
572
+ /**
573
+ * Composer rendered under the transcript on the panel background, inside the
574
+ * transcript's own `max-w-3xl` column. `session.composerControls`, when
575
+ * also given, sits above it as before.
576
+ */
577
+ composer?: ReactNode;
578
+ /**
579
+ * First section of the left region, ahead of the directory pane — a
580
+ * `SessionSidebar` for a chats rail. A rail that is the only left section
581
+ * fills the pane: no region header, no gutter. Give it `fill` and
582
+ * `className="border-r-0"` so the layout's own divider is the only one.
583
+ */
584
+ rail?: ReactNode;
585
+ directory?: DirectoryPaneProps;
586
+ session: SandboxWorkbenchSessionProps;
587
+ artifacts?: SandboxWorkbenchArtifact[];
588
+ activeArtifactId?: string;
589
+ onArtifactChange?: (artifactId: string) => void;
590
+ onArtifactClose?: (artifactId: string) => void;
591
+ runtime?: RuntimePaneProps;
592
+ layout?: SandboxWorkbenchLayoutOptions;
593
+ /**
594
+ * Shown in the artifact region while no artifact is selected. When given,
595
+ * the region renders before the first artifact exists.
596
+ */
597
+ emptyArtifactState?: ReactNode;
598
+ className?: string;
599
+ }
600
+ /**
601
+ * SandboxWorkbench — high-level composition that turns sandbox-ui primitives
602
+ * into a complete session surface: directory, agent timeline, artifacts, and
603
+ * runtime in one reusable shell.
604
+ */
605
+ declare function SandboxWorkbench({ title, subtitle, status, centerHeader: centerHeaderProp, composer, rail, directory, session, artifacts: artifactsProp, activeArtifactId, onArtifactChange, onArtifactClose, runtime, layout, emptyArtifactState, className }: SandboxWorkbenchProps): import("react").JSX.Element;
606
+ declare function AgentWorkbench(props: SandboxWorkbenchProps): import("react").JSX.Element;
607
+ //#endregion
608
+ //#region src/workspace/audit-results.d.ts
609
+ /**
610
+ * AuditResults — structured pass/fail display for form audits.
611
+ */
612
+ interface AuditCheck {
613
+ label: string;
614
+ expected: string | number;
615
+ actual?: string | number | null;
616
+ passed: boolean;
617
+ tolerance?: number;
618
+ fieldPath?: string;
619
+ }
620
+ interface FormAudit {
621
+ formId: string;
622
+ formName?: string;
623
+ found: boolean;
624
+ checks: AuditCheck[];
625
+ passed: number;
626
+ failed: number;
627
+ }
628
+ interface AuditResultsProps {
629
+ forms: FormAudit[];
630
+ crossFormChecks?: AuditCheck[];
631
+ overallScore?: number;
632
+ className?: string;
633
+ }
634
+ declare function AuditResults({ forms, crossFormChecks, overallScore, className }: AuditResultsProps): import("react").JSX.Element;
635
+ //#endregion
636
+ //#region src/workspace/task-board.d.ts
637
+ interface TaskBoardItem {
638
+ id: string;
639
+ title: string;
640
+ description?: string | null;
641
+ status: string;
642
+ priority?: string | null;
643
+ tags?: string[];
644
+ dueDate?: Date | null;
645
+ assigneeId?: string | null;
646
+ meta?: Record<string, unknown>;
647
+ }
648
+ interface TaskBoardColumn {
649
+ id: string;
650
+ label: string;
651
+ accent?: string;
652
+ }
653
+ interface TaskBoardProps {
654
+ items: TaskBoardItem[];
655
+ columns: TaskBoardColumn[];
656
+ className?: string;
657
+ onMoveItem?: (itemId: string, toColumnId: string) => void;
658
+ onClickItem?: (item: TaskBoardItem) => void;
659
+ renderItemMeta?: (item: TaskBoardItem) => ReactNode;
660
+ renderColumnAction?: (column: TaskBoardColumn) => ReactNode;
661
+ renderBadge?: (value: string, type: "priority" | "tag") => ReactNode;
662
+ columnEmptyState?: ReactNode;
663
+ header?: ReactNode;
664
+ /**
665
+ * Wrap each column's item list container. Use this to inject a DnD
666
+ * droppable zone (e.g. Droppable from @hello-pangea/dnd).
667
+ *
668
+ * Receives the column ID, the default item list element, and the column's items.
669
+ * Return a ReactNode that wraps/replaces the default element.
670
+ *
671
+ * If not provided, the default unstyled div is rendered.
672
+ */
673
+ renderColumnBody?: (columnId: string, defaultChildren: ReactNode, items: TaskBoardItem[]) => ReactNode;
674
+ /**
675
+ * Wrap each item card. Use this to inject a DnD draggable
676
+ * (e.g. Draggable from @hello-pangea/dnd).
677
+ *
678
+ * Receives the item, its index, and the default card element.
679
+ * Return a ReactNode that wraps/replaces the default element.
680
+ *
681
+ * If not provided, the default card is rendered.
682
+ */
683
+ renderItemWrapper?: (item: TaskBoardItem, index: number, defaultCard: ReactNode) => ReactNode;
684
+ }
685
+ declare function TaskBoard({ items, columns, className, onMoveItem, onClickItem, renderItemMeta, renderColumnAction, renderBadge, columnEmptyState, header, renderColumnBody, renderItemWrapper }: TaskBoardProps): import("react").JSX.Element;
686
+ //#endregion
687
+ //#region src/workspace/calendar-view.d.ts
688
+ interface CalendarEvent {
689
+ id: string;
690
+ title: string;
691
+ type?: string;
692
+ startAt: Date | string;
693
+ endAt?: Date | string | null;
694
+ allDay?: boolean;
695
+ /** Arbitrary data passed through to render props */
696
+ meta?: Record<string, unknown>;
697
+ }
698
+ interface CalendarViewProps {
699
+ events: CalendarEvent[];
700
+ className?: string;
701
+ /** Controlled month (0-indexed). Defaults to current month. */
702
+ month?: number;
703
+ year?: number;
704
+ onMonthChange?: (year: number, month: number) => void;
705
+ /** Which day is selected (ISO date string YYYY-MM-DD) */
706
+ selectedDay?: string | null;
707
+ onSelectDay?: (dateKey: string) => void;
708
+ onDoubleClickDay?: (dateKey: string) => void;
709
+ /** Render an event dot/chip inside a calendar cell */
710
+ renderEventChip?: (event: CalendarEvent) => ReactNode;
711
+ /** Render the day detail panel (right side) */
712
+ renderDayDetail?: (dateKey: string, dayEvents: CalendarEvent[]) => ReactNode;
713
+ /** Header slot (left of navigation) */
714
+ headerLeft?: ReactNode;
715
+ /** Header slot (right of navigation) */
716
+ headerRight?: ReactNode;
717
+ /** Whether to show the day detail panel. Default true. */
718
+ showDayPanel?: boolean;
719
+ }
720
+ /**
721
+ * CalendarView — month grid calendar with event chips and optional day detail panel.
722
+ *
723
+ * Stateless by default (controlled month/selectedDay). Falls back to internal
724
+ * state when uncontrolled. All rendering is customizable via render props.
725
+ */
726
+ declare function CalendarView({ events, className, month: controlledMonth, year: controlledYear, onMonthChange, selectedDay: controlledSelectedDay, onSelectDay, onDoubleClickDay, renderEventChip, renderDayDetail, headerLeft, headerRight, showDayPanel }: CalendarViewProps): import("react").JSX.Element;
727
+ //#endregion
728
+ //#region src/workspace/approval-queue.d.ts
729
+ interface ApprovalItem {
730
+ id: string;
731
+ title: string;
732
+ description?: string | null;
733
+ type: string;
734
+ status: "pending" | "approved" | "rejected" | "executed";
735
+ createdAt?: Date | string | null;
736
+ resolvedAt?: Date | string | null;
737
+ /** Arbitrary metadata — e.g. rejectionReason, confidence, content preview */
738
+ meta?: Record<string, unknown>;
739
+ }
740
+ interface ApprovalConfidenceStat {
741
+ type: string;
742
+ approved: number;
743
+ rejected: number;
744
+ total: number;
745
+ rate: number;
746
+ }
747
+ interface ApprovalQueueProps {
748
+ items: ApprovalItem[];
749
+ className?: string;
750
+ onApprove?: (item: ApprovalItem) => void;
751
+ onReject?: (item: ApprovalItem, reason?: string) => void;
752
+ /** Render custom content inside each approval card */
753
+ renderItemDetail?: (item: ApprovalItem) => ReactNode;
754
+ /** Render a custom badge for the item type */
755
+ renderTypeBadge?: (type: string) => ReactNode;
756
+ /** Render custom stats at the top. If not provided, auto-computed confidence stats shown. */
757
+ renderStats?: (stats: ApprovalConfidenceStat[]) => ReactNode;
758
+ /** Whether the user can approve/reject. Default true. */
759
+ canResolve?: boolean;
760
+ /** Header slot */
761
+ header?: ReactNode;
762
+ /** Empty state */
763
+ emptyState?: ReactNode;
764
+ /** Whether to show resolved items. Default: collapsed toggle. */
765
+ showResolved?: boolean;
766
+ }
767
+ /**
768
+ * ApprovalQueue — review queue for agent-proposed actions.
769
+ *
770
+ * Shows pending items with approve/reject controls, confidence stats per type,
771
+ * and a collapsible resolved history. Designed for the agent approval feedback
772
+ * loop: agent proposes → user approves/rejects → rejection reasons feed back.
773
+ */
774
+ declare function ApprovalQueue({ items, className, onApprove, onReject, renderItemDetail, renderTypeBadge, renderStats, canResolve, header, emptyState, showResolved: controlledShowResolved }: ApprovalQueueProps): import("react").JSX.Element;
775
+ //#endregion
776
+ export { TerminalProps as $, ShellShouldRevalidateArgs as A, SessionSidebarLink as B, SandboxWorkbenchLayoutOptions as C, SandboxWorkbenchSessionProps as D, SandboxWorkbenchProps as E, SessionSidebar as F, SessionOptimisticController as G, SessionSidebarVariant as H, SessionSidebarBadge as I, useOptimisticSessionItems as J, UseOptimisticSessionItemsOptions as K, SessionSidebarFilter as L, createShellShouldRevalidate as M, shellShouldRevalidate as N, SessionActivityMonitor as O, formatRelativeAge as P, TerminalPanel as Q, SessionSidebarGroupBy as R, SandboxWorkbenchFileArtifact as S, SandboxWorkbenchOpenUIArtifact as T, SESSION_CREATED_EVENT as U, SessionSidebarProps as V, SessionCreatedDetail as W, RuntimePaneProps as X, RuntimePane as Y, TerminalLine as Z, FormAudit as _, ApprovalQueue as a, StatusBannerProps as at, SandboxWorkbenchArtifact as b, CalendarView as c, WorkspacePaneHeader as ct, TaskBoardColumn as d, WorkspaceLayoutProps as dt, ContextBadge as et, TaskBoardItem as f, AuditResultsProps as g, AuditResults as h, ApprovalItem as i, StatusBanner as it, ShellShouldRevalidateOptions as j, SessionActivityMonitorProps as k, CalendarViewProps as l, WorkspacePaneHeaderProps as lt, AuditCheck as m, ArtifactPaneProps as n, StatusBarProps as nt, ApprovalQueueProps as o, DirectoryPane as ot, TaskBoardProps as p, dispatchSessionCreated as q, ApprovalConfidenceStat as r, BannerType as rt, CalendarEvent as s, DirectoryPaneProps as st, ArtifactPane$1 as t, StatusBar as tt, TaskBoard as u, WorkspaceLayout as ut, AgentWorkbench as v, SandboxWorkbenchMarkdownArtifact as w, SandboxWorkbenchCustomArtifact as x, SandboxWorkbench as y, SessionSidebarItem as z };