@tangle-network/sandbox-ui 0.6.1 → 0.8.4

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 (67) hide show
  1. package/dist/auth.d.ts +10 -6
  2. package/dist/auth.js +3 -3
  3. package/dist/{chat-container-Cg-GwyiK.d.ts → chat-container-f4yEs6KN.d.ts} +9 -1
  4. package/dist/chat.d.ts +12 -2
  5. package/dist/chat.js +10 -10
  6. package/dist/{chunk-TSE423UF.js → chunk-2QZ6G7NM.js} +6 -6
  7. package/dist/{chunk-WBQ7VULC.js → chunk-34A66VBG.js} +7 -7
  8. package/dist/{chunk-JP725R4W.js → chunk-34I7UFSX.js} +2 -2
  9. package/dist/{chunk-YS66Q3RC.js → chunk-3CJ2SOEI.js} +2 -2
  10. package/dist/{chunk-CNWVHQFY.js → chunk-54SQQMMM.js} +6 -24
  11. package/dist/{chunk-DLCFZDGX.js → chunk-5UM2XMEJ.js} +39 -14
  12. package/dist/{chunk-YYGECNZZ.js → chunk-66EZOYZR.js} +3 -3
  13. package/dist/chunk-7U2Z23NE.js +49 -0
  14. package/dist/{chunk-RKXIRRKQ.js → chunk-BUOQTBTO.js} +70 -66
  15. package/dist/{chunk-DCPYTL4W.js → chunk-D4CZWJCD.js} +72 -148
  16. package/dist/{chunk-MXRQ4MJE.js → chunk-DXMIEK4K.js} +34 -23
  17. package/dist/{chunk-ZMWWE5RF.js → chunk-EXSOPXIY.js} +141 -123
  18. package/dist/{chunk-GW4GRAWJ.js → chunk-GSZA3TSY.js} +18 -12
  19. package/dist/{chunk-W4LM3QYZ.js → chunk-HB5Y37YU.js} +8 -8
  20. package/dist/{chunk-E2XT3G52.js → chunk-HFMAXUHV.js} +136 -137
  21. package/dist/{chunk-BRBTD7RH.js → chunk-MA7YKRUP.js} +28 -18
  22. package/dist/{chunk-MJUDMVRU.js → chunk-MT5FJ3ZT.js} +17 -17
  23. package/dist/chunk-OKLQVY3Y.js +139 -0
  24. package/dist/{chunk-KH5UDAJ2.js → chunk-QDH5GEGY.js} +58 -54
  25. package/dist/{chunk-33W2TLUL.js → chunk-QID2OOMG.js} +12 -3
  26. package/dist/{chunk-FJSVPBKY.js → chunk-S7OXQTST.js} +17 -3
  27. package/dist/chunk-T7HMZEVO.js +216 -0
  28. package/dist/{chunk-FNYJFCGU.js → chunk-U6QTHMY6.js} +145 -256
  29. package/dist/{chunk-565V6JTN.js → chunk-UXQMIR3D.js} +60 -99
  30. package/dist/{chunk-XTPAWK7L.js → chunk-VOUV7GGB.js} +25 -47
  31. package/dist/{chunk-OVNLOE3Y.js → chunk-WXK43R62.js} +41 -41
  32. package/dist/{chunk-6V4XVKFY.js → chunk-XXDFEF72.js} +340 -335
  33. package/dist/{chunk-TDYQBLL5.js → chunk-ZMNSRDMH.js} +6 -6
  34. package/dist/dashboard.d.ts +135 -3
  35. package/dist/dashboard.js +848 -8
  36. package/dist/{document-editor-pane-DWWUTTTZ.js → document-editor-pane-TLPVRBBU.js} +3 -3
  37. package/dist/editor.d.ts +9 -8
  38. package/dist/editor.js +3 -3
  39. package/dist/files.js +3 -3
  40. package/dist/globals.css +5304 -68
  41. package/dist/hooks.d.ts +1 -1
  42. package/dist/hooks.js +7 -7
  43. package/dist/index.d.ts +4 -4
  44. package/dist/index.js +28 -28
  45. package/dist/markdown.js +1 -1
  46. package/dist/openui.js +5 -5
  47. package/dist/pages.d.ts +47 -3
  48. package/dist/pages.js +911 -357
  49. package/dist/primitives.d.ts +5 -2
  50. package/dist/primitives.js +10 -10
  51. package/dist/run.js +4 -4
  52. package/dist/sdk-hooks.d.ts +2 -3
  53. package/dist/sdk-hooks.js +5 -5
  54. package/dist/styles.css +5304 -68
  55. package/dist/template-card-BAtvcAkU.d.ts +18 -0
  56. package/dist/terminal.d.ts +3 -1
  57. package/dist/terminal.js +66 -32
  58. package/dist/tokens.css +701 -40
  59. package/dist/{usage-chart-XCoB_7Xu.d.ts → usage-chart-SSiOgeQI.d.ts} +3 -1
  60. package/dist/{use-pty-session-COzVkhtc.d.ts → use-pty-session-0AOuwXgq.d.ts} +2 -0
  61. package/dist/{index-BT_-ecpc.d.ts → variant-list-C8wx2TqF.d.ts} +17 -8
  62. package/dist/workspace.d.ts +1 -1
  63. package/dist/workspace.js +13 -13
  64. package/package.json +3 -1
  65. package/tailwind.config.cjs +3 -2
  66. package/dist/chunk-3HW53XTH.js +0 -228
  67. package/dist/chunk-OKCIKTXQ.js +0 -63
package/dist/auth.d.ts CHANGED
@@ -54,17 +54,21 @@ interface AuthHeaderProps {
54
54
  declare function AuthHeader({ user, loading, variant, apiBaseUrl, menuLinks, className, }: AuthHeaderProps): react_jsx_runtime.JSX.Element;
55
55
 
56
56
  interface LoginLayoutProps {
57
- brandName?: string;
58
- tagline?: React.ReactNode;
59
- subtitle?: string;
57
+ title?: React.ReactNode;
58
+ subtitle?: React.ReactNode;
59
+ brandIcon?: React.ReactNode;
60
+ children: React.ReactNode;
61
+ className?: string;
62
+ /** (Deprecated) terminal lines from legacy layout, kept for backwards compatibility */
60
63
  terminalLines?: string[];
64
+ /** (Deprecated) tagline, kept for backwards compatibility */
65
+ tagline?: React.ReactNode;
66
+ /** (Deprecated) footerLinks, kept for backwards compatibility */
61
67
  footerLinks?: {
62
68
  label: string;
63
69
  href: string;
64
70
  }[];
65
- children: React.ReactNode;
66
- className?: string;
67
71
  }
68
- declare function LoginLayout({ brandName, tagline, subtitle, terminalLines, footerLinks, children, className, }: LoginLayoutProps): react_jsx_runtime.JSX.Element;
72
+ declare function LoginLayout({ title, subtitle, brandIcon, children, className, }: LoginLayoutProps): react_jsx_runtime.JSX.Element;
69
73
 
70
74
  export { AuthHeader, type AuthHeaderProps, GitHubLoginButton, type GitHubLoginButtonProps, LoginLayout, type LoginLayoutProps, type SessionUser, UserMenu, type UserMenuProps };
package/dist/auth.js CHANGED
@@ -3,9 +3,9 @@ import {
3
3
  GitHubLoginButton,
4
4
  LoginLayout,
5
5
  UserMenu
6
- } from "./chunk-XTPAWK7L.js";
7
- import "./chunk-WBQ7VULC.js";
8
- import "./chunk-TSE423UF.js";
6
+ } from "./chunk-VOUV7GGB.js";
7
+ import "./chunk-34A66VBG.js";
8
+ import "./chunk-2QZ6G7NM.js";
9
9
  import "./chunk-RQHJBTEU.js";
10
10
  export {
11
11
  AuthHeader,
@@ -50,8 +50,16 @@ interface ChatInputProps {
50
50
  /** Drop zone overlay description */
51
51
  dropDescription?: string;
52
52
  className?: string;
53
+ /** Label above the input. Set to null to hide. Default: "Agent Command Deck" */
54
+ inputLabel?: string | null;
55
+ /** Status text shown when idle. Set to null to hide. Default: "Ready for next instruction" */
56
+ idleStatus?: string | null;
57
+ /** Status text shown when streaming. Set to null to hide. Default: "Streaming response" */
58
+ streamingStatus?: string | null;
59
+ /** Hide the Cmd+L focus shortcut hint */
60
+ hideShortcutHint?: boolean;
53
61
  }
54
- declare function ChatInput({ onSend, onCancel, isStreaming, disabled, placeholder, modelLabel, onModelClick, pendingFiles, onRemoveFile, onAttach, onAttachFolder, accept, dropTitle, dropDescription, className, }: ChatInputProps): react_jsx_runtime.JSX.Element;
62
+ declare function ChatInput({ onSend, onCancel, isStreaming, disabled, placeholder, modelLabel, onModelClick, pendingFiles, onRemoveFile, onAttach, onAttachFolder, accept, dropTitle, dropDescription, className, inputLabel, idleStatus, streamingStatus, hideShortcutHint, }: ChatInputProps): react_jsx_runtime.JSX.Element;
55
63
 
56
64
  interface ChatContainerProps {
57
65
  messages: SessionMessage[];
package/dist/chat.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { C as ChatContainer, a as ChatContainerProps, b as ChatInput, c as ChatInputProps, P as PendingFile } from './chat-container-Cg-GwyiK.js';
1
+ export { C as ChatContainer, a as ChatContainerProps, b as ChatInput, c as ChatInputProps, P as PendingFile } from './chat-container-f4yEs6KN.js';
2
2
  import * as React from 'react';
3
3
  import { ReactNode } from 'react';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
@@ -20,8 +20,18 @@ interface ChatMessageProps {
20
20
  /** Timestamp */
21
21
  timestamp?: Date;
22
22
  className?: string;
23
+ /** Custom user label. Default: "You" */
24
+ userLabel?: string;
25
+ /** Custom assistant label. Default: "Agent" */
26
+ assistantLabel?: string;
27
+ /** Hide the role label row entirely */
28
+ hideRoleLabel?: boolean;
29
+ /** Hide the avatar icon */
30
+ hideAvatar?: boolean;
31
+ /** Custom avatar element (replaces default User/Bot icon) */
32
+ avatar?: ReactNode;
23
33
  }
24
- declare function ChatMessage({ role, content, toolCalls, isStreaming, timestamp, className, }: ChatMessageProps): react_jsx_runtime.JSX.Element;
34
+ declare function ChatMessage({ role, content, toolCalls, isStreaming, timestamp, className, userLabel, assistantLabel, hideRoleLabel, hideAvatar, avatar, }: ChatMessageProps): react_jsx_runtime.JSX.Element;
25
35
 
26
36
  interface MessageListProps {
27
37
  groups: GroupedMessage[];
package/dist/chat.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ChatMessage
3
- } from "./chunk-GW4GRAWJ.js";
3
+ } from "./chunk-GSZA3TSY.js";
4
4
  import {
5
5
  AgentTimeline,
6
6
  ChatContainer,
@@ -8,17 +8,17 @@ import {
8
8
  MessageList,
9
9
  ThinkingIndicator,
10
10
  UserMessage
11
- } from "./chunk-RKXIRRKQ.js";
12
- import "./chunk-CNWVHQFY.js";
13
- import "./chunk-ZMWWE5RF.js";
11
+ } from "./chunk-BUOQTBTO.js";
12
+ import "./chunk-54SQQMMM.js";
13
+ import "./chunk-EXSOPXIY.js";
14
14
  import "./chunk-HRMUF35V.js";
15
- import "./chunk-MJUDMVRU.js";
15
+ import "./chunk-MT5FJ3ZT.js";
16
16
  import "./chunk-BX6AQMUS.js";
17
- import "./chunk-OVNLOE3Y.js";
18
- import "./chunk-JP725R4W.js";
19
- import "./chunk-3HW53XTH.js";
20
- import "./chunk-TDYQBLL5.js";
21
- import "./chunk-TSE423UF.js";
17
+ import "./chunk-WXK43R62.js";
18
+ import "./chunk-34I7UFSX.js";
19
+ import "./chunk-T7HMZEVO.js";
20
+ import "./chunk-ZMNSRDMH.js";
21
+ import "./chunk-2QZ6G7NM.js";
22
22
  import "./chunk-RQHJBTEU.js";
23
23
  export {
24
24
  AgentTimeline,
@@ -12,13 +12,13 @@ var buttonVariants = cva(
12
12
  {
13
13
  variants: {
14
14
  variant: {
15
- default: "bg-[var(--btn-primary-bg)] text-primary-foreground shadow-[var(--shadow-accent)] hover:bg-[var(--btn-primary-hover)] active:scale-[0.97] duration-[var(--transition-fast)]",
16
- destructive: "bg-destructive/15 border border-destructive/25 text-destructive hover:bg-destructive/22 active:scale-[0.97] duration-[var(--transition-fast)]",
17
- outline: "border border-[var(--border-default)] bg-transparent hover:bg-[var(--bg-hover)] hover:border-[var(--border-hover)] active:scale-[0.97] duration-[var(--transition-fast)]",
18
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/70 active:scale-[0.97] duration-[var(--transition-fast)]",
19
- ghost: "hover:bg-[var(--bg-hover)] hover:text-foreground duration-[var(--transition-fast)]",
15
+ default: "bg-primary/20 border border-primary/30 text-primary hover:text-primary-foreground shadow-[var(--shadow-accent)] hover:bg-primary hover:shadow-[var(--shadow-glow)] active:scale-[0.97] duration-[var(--transition-fast)]",
16
+ destructive: "bg-destructive/10 border border-destructive/30 text-destructive hover:text-destructive-foreground hover:bg-destructive/80 active:scale-[0.97] duration-[var(--transition-fast)]",
17
+ outline: "border border-border bg-card/50 backdrop-blur-xl hover:bg-muted hover:border-primary/20 active:scale-[0.97] duration-[var(--transition-fast)] text-foreground shadow-sm",
18
+ secondary: "bg-muted/50 border border-border text-foreground backdrop-blur-xl hover:bg-muted active:scale-[0.97] duration-[var(--transition-fast)] shadow-sm",
19
+ ghost: "hover:bg-muted hover:text-foreground duration-[var(--transition-fast)] text-muted-foreground border border-transparent",
20
20
  link: "text-primary underline-offset-4 hover:underline",
21
- sandbox: "bg-[image:var(--accent-gradient-strong)] text-white shadow-[var(--shadow-accent)] hover:brightness-110 active:scale-[0.97] duration-[var(--transition-fast)]"
21
+ sandbox: "bg-[image:var(--accent-gradient-strong)] text-white shadow-[var(--shadow-accent)] backdrop-blur-2xl border border-[var(--border-accent)] hover:brightness-110 active:scale-[0.97] duration-[var(--transition-fast)]"
22
22
  },
23
23
  size: {
24
24
  default: "h-[var(--control-height)] px-4 py-2",
@@ -57,7 +57,7 @@ var DropdownMenuSubTrigger = React2.forwardRef(({ className, inset, children, ..
57
57
  ref,
58
58
  className: cn(
59
59
  "flex cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm outline-none",
60
- "focus:bg-accent data-[state=open]:bg-[var(--depth-3)]",
60
+ "focus:bg-accent data-[state=open]:bg-muted/50",
61
61
  inset && "pl-8",
62
62
  className
63
63
  ),
@@ -74,7 +74,7 @@ var DropdownMenuSubContent = React2.forwardRef(({ className, ...props }, ref) =>
74
74
  {
75
75
  ref,
76
76
  className: cn(
77
- "z-50 min-w-[8rem] overflow-hidden rounded-xl border border-[var(--border-subtle)] bg-[var(--depth-2)] p-1 text-[var(--text-primary)] shadow-[var(--shadow-card)]",
77
+ "z-50 min-w-[8rem] overflow-hidden rounded-xl border border-border bg-card p-1 text-foreground shadow-[var(--shadow-card)]",
78
78
  "data-[state=closed]:animate-out data-[state=open]:animate-in",
79
79
  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
80
80
  "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
@@ -92,7 +92,7 @@ var DropdownMenuContent = React2.forwardRef(({ className, sideOffset = 4, ...pro
92
92
  ref,
93
93
  sideOffset,
94
94
  className: cn(
95
- "z-50 min-w-[8rem] overflow-hidden rounded-xl border border-[var(--border-subtle)] bg-[var(--depth-2)] p-1 text-[var(--text-primary)] shadow-[var(--shadow-card)]",
95
+ "z-50 min-w-[8rem] overflow-hidden rounded-xl border border-border bg-card p-1 text-foreground shadow-[var(--shadow-card)]",
96
96
  "data-[state=closed]:animate-out data-[state=open]:animate-in",
97
97
  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
98
98
  "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
@@ -110,7 +110,7 @@ var DropdownMenuItem = React2.forwardRef(({ className, inset, ...props }, ref) =
110
110
  ref,
111
111
  className: cn(
112
112
  "relative flex cursor-pointer select-none items-center rounded-md px-2 py-1.5 text-sm outline-none transition-colors",
113
- "focus:bg-[var(--depth-3)] focus:text-[var(--text-primary)]",
113
+ "focus:bg-muted/50 focus:text-foreground",
114
114
  "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
115
115
  inset && "pl-8",
116
116
  className
@@ -125,7 +125,7 @@ var DropdownMenuCheckboxItem = React2.forwardRef(({ className, children, checked
125
125
  ref,
126
126
  className: cn(
127
127
  "relative flex cursor-pointer select-none items-center rounded-md py-1.5 pr-2 pl-8 text-sm outline-none transition-colors",
128
- "focus:bg-[var(--depth-3)] focus:text-[var(--text-primary)]",
128
+ "focus:bg-muted/50 focus:text-foreground",
129
129
  "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
130
130
  className
131
131
  ),
@@ -144,7 +144,7 @@ var DropdownMenuRadioItem = React2.forwardRef(({ className, children, ...props }
144
144
  ref,
145
145
  className: cn(
146
146
  "relative flex cursor-pointer select-none items-center rounded-md py-1.5 pr-2 pl-8 text-sm outline-none transition-colors",
147
- "focus:bg-[var(--depth-3)] focus:text-[var(--text-primary)]",
147
+ "focus:bg-muted/50 focus:text-foreground",
148
148
  "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
149
149
  className
150
150
  ),
@@ -173,7 +173,7 @@ var DropdownMenuSeparator = React2.forwardRef(({ className, ...props }, ref) =>
173
173
  DropdownMenuPrimitive.Separator,
174
174
  {
175
175
  ref,
176
- className: cn("-mx-1 my-1 h-px bg-[var(--border-subtle)]", className),
176
+ className: cn("-mx-1 my-1 h-px bg-border", className),
177
177
  ...props
178
178
  }
179
179
  ));
@@ -30,7 +30,7 @@ var TableFooter = React.forwardRef(({ className, ...props }, ref) => /* @__PURE_
30
30
  {
31
31
  ref,
32
32
  className: cn(
33
- "border-t bg-[var(--depth-2)] font-medium [&>tr]:last:border-b-0",
33
+ "border-t bg-card font-medium [&>tr]:last:border-b-0",
34
34
  className
35
35
  ),
36
36
  ...props
@@ -42,7 +42,7 @@ var TableRow = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ *
42
42
  {
43
43
  ref,
44
44
  className: cn(
45
- "border-border border-b transition-colors hover:bg-[var(--depth-3)] data-[state=selected]:bg-[var(--depth-3)]",
45
+ "border-border border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted/50",
46
46
  className
47
47
  ),
48
48
  ...props
@@ -16,7 +16,7 @@ var DialogOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PUR
16
16
  {
17
17
  ref,
18
18
  className: cn(
19
- "fixed inset-0 z-50 bg-black/85",
19
+ "fixed inset-0 z-50 bg-black/80 backdrop-blur-sm",
20
20
  "data-[state=closed]:animate-out data-[state=open]:animate-in",
21
21
  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
22
22
  className
@@ -38,7 +38,7 @@ var DialogContent = React.forwardRef(({ className, children, variant = "default"
38
38
  ref,
39
39
  className: cn(
40
40
  "fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%]",
41
- "gap-4 rounded-xl border bg-card p-6 shadow-xl duration-200",
41
+ "gap-4 rounded-2xl border bg-card/95 backdrop-blur-xl p-6 shadow-2xl duration-200",
42
42
  "data-[state=closed]:animate-out data-[state=open]:animate-in",
43
43
  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
44
44
  "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
@@ -91,26 +91,9 @@ function useRunGroups({
91
91
  }
92
92
 
93
93
  // src/hooks/use-run-collapse-state.ts
94
- import { useCallback, useEffect, useRef, useState } from "react";
95
- var AUTO_COLLAPSE_DELAY = 1e3;
94
+ import { useCallback, useState } from "react";
96
95
  function useRunCollapseState(runs) {
97
96
  const [collapsedMap, setCollapsedMap] = useState({});
98
- const userOverrides = useRef(/* @__PURE__ */ new Set());
99
- const completedRuns = useRef(/* @__PURE__ */ new Set());
100
- useEffect(() => {
101
- const timers = [];
102
- for (const run of runs) {
103
- if (run.isComplete && !completedRuns.current.has(run.id)) {
104
- completedRuns.current.add(run.id);
105
- if (userOverrides.current.has(run.id)) continue;
106
- const timer = setTimeout(() => {
107
- setCollapsedMap((prev) => ({ ...prev, [run.id]: true }));
108
- }, AUTO_COLLAPSE_DELAY);
109
- timers.push(timer);
110
- }
111
- }
112
- return () => timers.forEach(clearTimeout);
113
- }, [runs]);
114
97
  const isCollapsed = useCallback(
115
98
  (runId) => {
116
99
  return collapsedMap[runId] ?? false;
@@ -118,7 +101,6 @@ function useRunCollapseState(runs) {
118
101
  [collapsedMap]
119
102
  );
120
103
  const toggleCollapse = useCallback((runId) => {
121
- userOverrides.current.add(runId);
122
104
  setCollapsedMap((prev) => ({ ...prev, [runId]: !prev[runId] }));
123
105
  }, []);
124
106
  return { isCollapsed, toggleCollapse };
@@ -127,20 +109,20 @@ function useRunCollapseState(runs) {
127
109
  // src/hooks/use-auto-scroll.ts
128
110
  import {
129
111
  useCallback as useCallback2,
130
- useEffect as useEffect2,
131
- useRef as useRef2,
112
+ useEffect,
113
+ useRef,
132
114
  useState as useState2
133
115
  } from "react";
134
116
  var BOTTOM_THRESHOLD = 40;
135
117
  function useAutoScroll(containerRef, deps = []) {
136
118
  const [isAtBottom, setIsAtBottom] = useState2(true);
137
- const userScrolledUp = useRef2(false);
119
+ const userScrolledUp = useRef(false);
138
120
  const checkBottom = useCallback2(() => {
139
121
  const el = containerRef.current;
140
122
  if (!el) return true;
141
123
  return el.scrollHeight - el.scrollTop - el.clientHeight < BOTTOM_THRESHOLD;
142
124
  }, [containerRef]);
143
- useEffect2(() => {
125
+ useEffect(() => {
144
126
  const el = containerRef.current;
145
127
  if (!el) return;
146
128
  const onScroll = () => {
@@ -151,7 +133,7 @@ function useAutoScroll(containerRef, deps = []) {
151
133
  el.addEventListener("scroll", onScroll, { passive: true });
152
134
  return () => el.removeEventListener("scroll", onScroll);
153
135
  }, [containerRef, checkBottom]);
154
- useEffect2(() => {
136
+ useEffect(() => {
155
137
  if (userScrolledUp.current) return;
156
138
  const el = containerRef.current;
157
139
  if (!el) return;
@@ -9,7 +9,6 @@ function usePtySession({ apiUrl, token, onData }) {
9
9
  const retryCountRef = useRef(0);
10
10
  const mountedRef = useRef(true);
11
11
  const onDataRef = useRef(onData);
12
- onDataRef.current = onData;
13
12
  const connectStreamRef = useRef(null);
14
13
  const abortStream = useCallback(() => {
15
14
  if (retryTimerRef.current) {
@@ -117,6 +116,7 @@ function usePtySession({ apiUrl, token, onData }) {
117
116
  }
118
117
  }
119
118
  }, [apiUrl, token, abortStream]);
119
+ onDataRef.current = onData;
120
120
  connectStreamRef.current = connectStream;
121
121
  const connect = useCallback(async () => {
122
122
  cleanup();
@@ -149,21 +149,46 @@ function usePtySession({ apiUrl, token, onData }) {
149
149
  }
150
150
  }
151
151
  }, [apiUrl, token, cleanup, connectStream]);
152
+ const resizeTerminal = useCallback(async (cols, rows) => {
153
+ const sid = sessionIdRef.current;
154
+ if (!sid || cols <= 0 || rows <= 0) return;
155
+ try {
156
+ const res = await fetch(`${apiUrl}/terminals/${sid}`, {
157
+ method: "PATCH",
158
+ headers: {
159
+ Authorization: `Bearer ${token}`,
160
+ "Content-Type": "application/json"
161
+ },
162
+ credentials: "include",
163
+ body: JSON.stringify({ cols, rows })
164
+ });
165
+ if (!res.ok) {
166
+ console.error("Failed to resize terminal:", res.status);
167
+ }
168
+ } catch (err) {
169
+ console.error("Failed to resize terminal", err);
170
+ }
171
+ }, [apiUrl, token]);
152
172
  const sendCommand = useCallback(async (command) => {
153
173
  const sid = sessionIdRef.current;
154
174
  if (!sid) return;
155
- const res = await fetch(`${apiUrl}/terminals/${sid}/input`, {
156
- method: "POST",
157
- headers: {
158
- Authorization: `Bearer ${token}`,
159
- "Content-Type": "application/json"
160
- },
161
- credentials: "include",
162
- body: JSON.stringify({ data: command })
163
- });
164
- if (!res.ok) {
165
- const text = await res.text();
166
- throw new Error(text || `Input failed: ${res.status}`);
175
+ try {
176
+ const res = await fetch(`${apiUrl}/terminals/${sid}/input`, {
177
+ method: "POST",
178
+ headers: {
179
+ Authorization: `Bearer ${token}`,
180
+ "Content-Type": "application/json"
181
+ },
182
+ credentials: "include",
183
+ body: JSON.stringify({ data: command })
184
+ });
185
+ if (!res.ok) {
186
+ const text = await res.text();
187
+ throw new Error(text || `Input failed: ${res.status}`);
188
+ }
189
+ } catch (err) {
190
+ console.error("Failed to send command", err);
191
+ throw err;
167
192
  }
168
193
  }, [apiUrl, token]);
169
194
  useEffect(() => {
@@ -174,7 +199,7 @@ function usePtySession({ apiUrl, token, onData }) {
174
199
  cleanup();
175
200
  };
176
201
  }, [connect, cleanup]);
177
- return { isConnected, error, sendCommand, reconnect: connect };
202
+ return { isConnected, error, sendCommand, resizeTerminal, reconnect: connect };
178
203
  }
179
204
 
180
205
  export {
@@ -52,7 +52,7 @@ function Skeleton({
52
52
  return /* @__PURE__ */ jsx2(
53
53
  "div",
54
54
  {
55
- className: cn("animate-pulse rounded-lg bg-[var(--depth-3)]", className),
55
+ className: cn("animate-pulse rounded-lg bg-muted/50", className),
56
56
  ...props
57
57
  }
58
58
  );
@@ -62,7 +62,7 @@ function SkeletonCard({ className }) {
62
62
  "div",
63
63
  {
64
64
  className: cn(
65
- "space-y-4 rounded-xl border border-[var(--border-subtle)] bg-[var(--bg-card)] p-6",
65
+ "space-y-4 rounded-xl border border-border bg-card p-6",
66
66
  className
67
67
  ),
68
68
  children: [
@@ -79,7 +79,7 @@ function SkeletonCard({ className }) {
79
79
  }
80
80
  function SkeletonTable({ rows = 5 }) {
81
81
  return /* @__PURE__ */ jsxs2("div", { className: "space-y-3", children: [
82
- /* @__PURE__ */ jsxs2("div", { className: "flex gap-4 border-[var(--border-subtle)] border-b pb-2", children: [
82
+ /* @__PURE__ */ jsxs2("div", { className: "flex gap-4 border-border border-b pb-2", children: [
83
83
  /* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-1/4" }),
84
84
  /* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-1/4" }),
85
85
  /* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-1/4" }),
@@ -0,0 +1,49 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-RQHJBTEU.js";
4
+
5
+ // src/dashboard/template-card.tsx
6
+ import { ArrowRight } from "lucide-react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ function TemplateCard({ template, onUseTemplate, className }) {
9
+ return /* @__PURE__ */ jsxs(
10
+ "div",
11
+ {
12
+ className: cn(
13
+ "group relative flex flex-col justify-between rounded-2xl border border-border bg-card p-6 transition-all hover:border-primary/30 hover:shadow-md",
14
+ className
15
+ ),
16
+ children: [
17
+ /* @__PURE__ */ jsxs("div", { children: [
18
+ /* @__PURE__ */ jsx("div", { className: "mb-4 flex h-12 w-12 items-center justify-center rounded-xl bg-muted border border-border", children: template.icon ?? /* @__PURE__ */ jsx("span", { className: "text-lg font-bold text-primary", children: template.name.charAt(0).toUpperCase() }) }),
19
+ /* @__PURE__ */ jsx("h3", { className: "mb-1 text-base font-bold text-foreground", children: template.name }),
20
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground leading-relaxed line-clamp-2", children: template.description }),
21
+ template.tags && template.tags.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-3 flex flex-wrap gap-1.5", children: template.tags.map((tag, i) => /* @__PURE__ */ jsx(
22
+ "span",
23
+ {
24
+ className: "rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground",
25
+ children: tag
26
+ },
27
+ `${tag}-${i}`
28
+ )) })
29
+ ] }),
30
+ /* @__PURE__ */ jsxs(
31
+ "button",
32
+ {
33
+ type: "button",
34
+ onClick: () => onUseTemplate(template.id),
35
+ className: "mt-5 inline-flex w-full items-center justify-center gap-2 rounded-xl bg-primary/10 border border-primary/20 px-4 py-2.5 text-sm font-bold text-primary transition-colors hover:bg-primary hover:text-primary-foreground active:scale-[0.98]",
36
+ children: [
37
+ "Use Template",
38
+ /* @__PURE__ */ jsx(ArrowRight, { className: "h-4 w-4 transition-transform group-hover:translate-x-0.5" })
39
+ ]
40
+ }
41
+ )
42
+ ]
43
+ }
44
+ );
45
+ }
46
+
47
+ export {
48
+ TemplateCard
49
+ };