@tangle-network/agent-app 0.43.1 → 0.43.3

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.
@@ -0,0 +1,46 @@
1
+ interface SandboxTerminalConnection {
2
+ runtimeUrl: string | null;
3
+ sidecarUrl: string | null;
4
+ token: string | null;
5
+ expiresAt: string | null;
6
+ status: string;
7
+ error: string | null;
8
+ loading: boolean;
9
+ sandboxId?: string;
10
+ }
11
+ interface SandboxTerminalConnectionResponse {
12
+ runtimeUrl?: string;
13
+ sidecarUrl?: string;
14
+ token?: string;
15
+ expiresAt?: string;
16
+ status?: string;
17
+ error?: string;
18
+ sandboxId?: string;
19
+ }
20
+ interface UseSandboxTerminalConnectionOptions {
21
+ workspaceId: string;
22
+ connectionUrl?: string | ((workspaceId: string) => string);
23
+ fetcher?: typeof fetch;
24
+ provisionPollIntervalMs?: number;
25
+ provisionPollTimeoutMs?: number;
26
+ tokenRefreshSkewMs?: number;
27
+ }
28
+ interface UseSandboxTerminalConnectionResult extends SandboxTerminalConnection {
29
+ connect: () => Promise<void>;
30
+ }
31
+ declare function useSandboxTerminalConnection(opts: UseSandboxTerminalConnectionOptions): UseSandboxTerminalConnectionResult;
32
+ /**
33
+ * Stable-per-tab, unique-per-client terminal connection id.
34
+ *
35
+ * Persists in `sessionStorage` so a reload in the same tab reuses the id (the
36
+ * sidecar restores the same PTY session via `TerminalView.connectionId`), while
37
+ * separate tabs/windows each get a distinct id. Pass the result as
38
+ * `TerminalView`'s `connectionId`. Without it (e.g. gtm-agent today) every tab
39
+ * shares one connection id and their reconnects evict each other.
40
+ *
41
+ * Falls back to an ephemeral id when `sessionStorage` is unavailable (SSR,
42
+ * privacy mode) — still unique per call, just not reload-stable.
43
+ */
44
+ declare function tabTerminalConnectionId(storageKey?: string): string;
45
+
46
+ export { type SandboxTerminalConnection as S, type UseSandboxTerminalConnectionOptions as U, type SandboxTerminalConnectionResponse as a, type UseSandboxTerminalConnectionResult as b, tabTerminalConnectionId as t, useSandboxTerminalConnection as u };
@@ -1,12 +1,12 @@
1
+ import {
2
+ InvitationsPanel
3
+ } from "../chunk-7C64WKAH.js";
1
4
  import {
2
5
  InviteAcceptPage
3
6
  } from "../chunk-VCPZ3HTN.js";
4
7
  import {
5
8
  MembersPanel
6
9
  } from "../chunk-GNL3MG5J.js";
7
- import {
8
- InvitationsPanel
9
- } from "../chunk-7C64WKAH.js";
10
10
  import "../chunk-63CE7FEZ.js";
11
11
  export {
12
12
  InvitationsPanel,
@@ -1,8 +1,8 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { ComposerFile as ComposerFile$1 } from '@tangle-network/sandbox-ui/chat';
4
3
  import { S as StepAgentActivity } from '../agent-activity-C8ZG0F0M.js';
5
4
  import { a as FlowTrace } from '../flow-types-Cb_AblZs.js';
5
+ export { S as SandboxTerminalConnection, a as SandboxTerminalConnectionResponse, U as UseSandboxTerminalConnectionOptions, b as UseSandboxTerminalConnectionResult, t as tabTerminalConnectionId, u as useSandboxTerminalConnection } from '../sandbox-terminal-BIIC__CP.js';
6
6
  import { C as CatalogModel } from '../model-catalog-BEAEVDaa.js';
7
7
  import { Harness } from '../harness/index.js';
8
8
  import '@tangle-network/agent-interface';
@@ -80,8 +80,15 @@ interface StreamChatOptions {
80
80
  */
81
81
  declare function streamChatTurn(opts: StreamChatOptions): Promise<ConsumeChatStreamResult>;
82
82
 
83
- /** Re-exported from sandbox-ui — the staged-attachment chip shape. */
84
- type ComposerFile = ComposerFile$1;
83
+ interface ComposerFile {
84
+ id: string;
85
+ name: string;
86
+ size?: number;
87
+ kind: 'file' | 'folder';
88
+ /** Number of files inside, for a folder chip. */
89
+ fileCount?: number;
90
+ status: 'pending' | 'uploading' | 'ready' | 'error';
91
+ }
85
92
  interface ChatComposerProps {
86
93
  /** Send the trimmed, non-empty message. Attached files travel separately via
87
94
  * `onAttach` + `pendingFiles` (the host consumes and clears them on send). */
@@ -89,7 +96,8 @@ interface ChatComposerProps {
89
96
  /** Stop the in-flight turn; shown in place of Send while `isStreaming`. */
90
97
  onCancel?: () => void;
91
98
  isStreaming?: boolean;
92
- /** Block input + send (e.g. while restoring). */
99
+ /** Block input + send (e.g. while restoring). Distinct from `isStreaming`,
100
+ * which keeps the textarea editable so the next turn can be composed. */
93
101
  disabled?: boolean;
94
102
  placeholder?: string;
95
103
  /** Controlled value. Omit for self-managed internal state (cleared on send). */
@@ -97,13 +105,10 @@ interface ChatComposerProps {
97
105
  onValueChange?: (value: string) => void;
98
106
  /** Initial text in uncontrolled mode; ignored when `value` is provided. */
99
107
  initialValue?: string;
100
- /** Inline controls (e.g. `<AgentSessionControls/>`), rendered in the control row. */
108
+ /** Inline controls (e.g. `<ModelPicker/>` + `<EffortPicker/>` or
109
+ * `<AgentSessionControls/>`). Rendered in a row above the input by default. */
101
110
  controls?: ReactNode;
102
- /**
103
- * @deprecated The composer renders a single control row; this no longer moves
104
- * the controls above the input. Retained for API compatibility.
105
- */
106
- controlsPlacement?: "above" | "footer";
111
+ controlsPlacement?: 'above' | 'footer';
107
112
  /** Attachments are opt-in: pass `onAttach` to show the attach button, accept
108
113
  * drag-and-drop onto the input, and render `pendingFiles` chips. */
109
114
  onAttach?: (files: FileList) => void;
@@ -115,11 +120,11 @@ interface ChatComposerProps {
115
120
  dropDescription?: string;
116
121
  /** Cmd/Ctrl+L focuses the input and shows the hint. Default true. */
117
122
  focusShortcut?: boolean;
118
- /** Send button label (aria/title; the button is an icon). Default "Send". */
123
+ /** Send button label. Default "Send". */
119
124
  sendLabel?: string;
120
125
  className?: string;
121
126
  }
122
- declare function ChatComposer({ onSend, onCancel, isStreaming, disabled, placeholder, value, onValueChange, initialValue, controls, onAttach, onAttachFolder, pendingFiles, onRemoveFile, accept, dropTitle, dropDescription, focusShortcut, sendLabel, className, }: ChatComposerProps): react.JSX.Element;
127
+ declare function ChatComposer({ onSend, onCancel, isStreaming, disabled, placeholder, value, onValueChange, initialValue, controls, controlsPlacement, onAttach, onAttachFolder, pendingFiles, onRemoveFile, accept, dropTitle, dropDescription, focusShortcut, sendLabel, className, }: ChatComposerProps): react.JSX.Element;
123
128
 
124
129
  /**
125
130
  * Provider brand marks — real logo path data (simple-icons / SVG Logos, both
@@ -241,95 +246,6 @@ interface AgentActivityPanelProps {
241
246
  */
242
247
  declare function AgentActivityPanel({ fetchActivity, renderMissionRef, title, emptyLabel }: AgentActivityPanelProps): react.JSX.Element;
243
248
 
244
- interface SandboxTerminalConnection {
245
- runtimeUrl: string | null;
246
- sidecarUrl: string | null;
247
- token: string | null;
248
- expiresAt: string | null;
249
- status: string;
250
- error: string | null;
251
- loading: boolean;
252
- sandboxId?: string;
253
- }
254
- interface SandboxTerminalConnectionResponse {
255
- runtimeUrl?: string;
256
- sidecarUrl?: string;
257
- token?: string;
258
- expiresAt?: string;
259
- status?: string;
260
- error?: string;
261
- sandboxId?: string;
262
- }
263
- interface UseSandboxTerminalConnectionOptions {
264
- workspaceId: string;
265
- connectionUrl?: string | ((workspaceId: string) => string);
266
- fetcher?: typeof fetch;
267
- provisionPollIntervalMs?: number;
268
- provisionPollTimeoutMs?: number;
269
- tokenRefreshSkewMs?: number;
270
- }
271
- interface UseSandboxTerminalConnectionResult extends SandboxTerminalConnection {
272
- connect: () => Promise<void>;
273
- }
274
- declare function useSandboxTerminalConnection(opts: UseSandboxTerminalConnectionOptions): UseSandboxTerminalConnectionResult;
275
- /**
276
- * Stable-per-tab, unique-per-client terminal connection id.
277
- *
278
- * Persists in `sessionStorage` so a reload in the same tab reuses the id (the
279
- * sidecar restores the same PTY session via `TerminalView.connectionId`), while
280
- * separate tabs/windows each get a distinct id. Pass the result as
281
- * `TerminalView`'s `connectionId`. Without it (e.g. gtm-agent today) every tab
282
- * shares one connection id and their reconnects evict each other.
283
- *
284
- * Falls back to an ephemeral id when `sessionStorage` is unavailable (SSR,
285
- * privacy mode) — still unique per call, just not reload-stable.
286
- */
287
- declare function tabTerminalConnectionId(storageKey?: string): string;
288
-
289
- /**
290
- * `WorkspaceTerminalPanel` — the shared sandbox-terminal surface: a header with
291
- * a status badge, connect/provisioning/error states with a retry, and the lazy
292
- * `TerminalView` (from `@tangle-network/sandbox-ui`) mounted only once the
293
- * connection is live. creative-agent and gtm-agent each hand-roll a structurally
294
- * identical panel; only the copy and the status-tone map are app-specific, so
295
- * those are props and everything else lives here.
296
- *
297
- * Pair it with {@link useSandboxTerminalConnection} (the `connection` prop) and
298
- * {@link tabTerminalConnectionId} (the `connectionId` prop) so reloads restore
299
- * the same PTY and separate tabs don't evict each other.
300
- *
301
- * Styling matches the rest of `web-react`: Tailwind over the shared design
302
- * tokens; glyphs inline; no icon/UI library.
303
- */
304
-
305
- type TerminalStatusTone = 'idle' | 'connecting' | 'connected' | 'error';
306
- interface TerminalStatusDisplay {
307
- tone: TerminalStatusTone;
308
- label: string;
309
- }
310
- interface WorkspaceTerminalPanelProps {
311
- /** Live connection state (from {@link useSandboxTerminalConnection}). */
312
- connection: SandboxTerminalConnection;
313
- /** Stable per-tab id (from {@link tabTerminalConnectionId}) so the sidecar
314
- * restores the same PTY across remounts and tabs don't collide. */
315
- connectionId?: string;
316
- /** Header title. Default "Terminal". */
317
- title?: string;
318
- /** Header subtitle / sandbox label. */
319
- subtitle?: string;
320
- /** Whether the terminal tab is visible (forwarded to `TerminalView` for fit). */
321
- isActive?: boolean;
322
- /** Reconnect handler — wire to the hook's `connect`. Shown on idle/error. */
323
- onRetry?: () => void;
324
- /** Map a `connection.status` to a badge tone + label. The default covers
325
- * idle/provisioning/running/error; override for app-specific vocabulary. */
326
- statusDisplay?: (connection: SandboxTerminalConnection) => TerminalStatusDisplay;
327
- /** Extra header content, right-aligned (actions, sandbox id, …). */
328
- headerExtra?: ReactNode;
329
- className?: string;
330
- }
331
- declare function WorkspaceTerminalPanel({ connection, connectionId, title, subtitle, isActive, onRetry, statusDisplay, headerExtra, className, }: WorkspaceTerminalPanelProps): ReactNode;
332
-
333
249
  /**
334
250
  * `SeatPaywall` — the shared "unlock this product" screen every agent app
335
251
  * shows when a user has no active seat and has spent past the free tier. One
@@ -639,4 +555,4 @@ declare function useThinkingSeconds(active: boolean): number;
639
555
  */
640
556
  declare function ChatMessages({ messages, models, renderMarkdown, renderExtras, userLabel, agentLabel, loading, approval, onToolCallClick, toolRenderers, error, onRetry, renderEmpty, emptyState, header, }: ChatMessagesProps): react.JSX.Element;
641
557
 
642
- export { type ActivityTone, type AgentActivityPage, AgentActivityPanel, type AgentActivityPanelProps, type AgentActivityRecord, AgentSessionControls, type AgentSessionControlsProps, CatalogModel, ChatComposer, type ChatComposerProps, type ChatEmptyDoor, ChatEmptyState, type ChatEmptyStateProps, type ChatMessageMetrics, type ChatMessageSegment, ChatMessages, type ChatMessagesProps, type ChatStreamCallbacks, type ChatStreamToolCall, type ChatStreamToolResult, type ChatToolCallInfo, type ChatUiMessage, type ComposerFile, type ConsumeChatStreamResult, DEFAULT_EFFORT_LEVELS, type EffortLevel, EffortPicker, type EffortPickerProps, FlowWaterfall, type FlowWaterfallProps, MissionActivityLane, type MissionActivityLaneProps, ModelPicker, type ModelPickerProps, type ProposalApprovalHandlers, ProviderLogo, type ProviderLogoProps, RunDrillIn, type RunDrillInProps, type SandboxTerminalConnection, type SandboxTerminalConnectionResponse, SeatPaywall, type SeatPaywallProps, type SmoothRevealOptions, type StreamChatOptions, type TerminalStatusDisplay, type TerminalStatusTone, type ToolDetailRenderers, type ToolRunRecord, type ToolRunStep, type UseSandboxTerminalConnectionOptions, type UseSandboxTerminalConnectionResult, type WaterfallRow, WorkspaceTerminalPanel, type WorkspaceTerminalPanelProps, activityTone, consumeChatStream, dispatchChatStreamLine, formatActivityCost, formatActivityDuration, formatModelCost, formatTokensPerSecond, mergeActivityPages, nextRevealCount, pendingApprovalOf, streamChatTurn, tabTerminalConnectionId, usePending, usePopover, useSandboxTerminalConnection, useSmoothText, useThinkingSeconds, waterfallLayout };
558
+ export { type ActivityTone, type AgentActivityPage, AgentActivityPanel, type AgentActivityPanelProps, type AgentActivityRecord, AgentSessionControls, type AgentSessionControlsProps, CatalogModel, ChatComposer, type ChatComposerProps, type ChatEmptyDoor, ChatEmptyState, type ChatEmptyStateProps, type ChatMessageMetrics, type ChatMessageSegment, ChatMessages, type ChatMessagesProps, type ChatStreamCallbacks, type ChatStreamToolCall, type ChatStreamToolResult, type ChatToolCallInfo, type ChatUiMessage, type ComposerFile, type ConsumeChatStreamResult, DEFAULT_EFFORT_LEVELS, type EffortLevel, EffortPicker, type EffortPickerProps, FlowWaterfall, type FlowWaterfallProps, MissionActivityLane, type MissionActivityLaneProps, ModelPicker, type ModelPickerProps, type ProposalApprovalHandlers, ProviderLogo, type ProviderLogoProps, RunDrillIn, type RunDrillInProps, SeatPaywall, type SeatPaywallProps, type SmoothRevealOptions, type StreamChatOptions, type ToolDetailRenderers, type ToolRunRecord, type ToolRunStep, type WaterfallRow, activityTone, consumeChatStream, dispatchChatStreamLine, formatActivityCost, formatActivityDuration, formatModelCost, formatTokensPerSecond, mergeActivityPages, nextRevealCount, pendingApprovalOf, streamChatTurn, usePending, usePopover, useSmoothText, useThinkingSeconds, waterfallLayout };
@@ -12,7 +12,6 @@ import {
12
12
  ProviderLogo,
13
13
  RunDrillIn,
14
14
  SeatPaywall,
15
- WorkspaceTerminalPanel,
16
15
  activityTone,
17
16
  consumeChatStream,
18
17
  dispatchChatStreamLine,
@@ -24,14 +23,16 @@ import {
24
23
  nextRevealCount,
25
24
  pendingApprovalOf,
26
25
  streamChatTurn,
27
- tabTerminalConnectionId,
28
26
  usePending,
29
27
  usePopover,
30
- useSandboxTerminalConnection,
31
28
  useSmoothText,
32
29
  useThinkingSeconds,
33
30
  waterfallLayout
34
- } from "../chunk-7DPQ5VWR.js";
31
+ } from "../chunk-VKHB7VP4.js";
32
+ import {
33
+ tabTerminalConnectionId,
34
+ useSandboxTerminalConnection
35
+ } from "../chunk-65P3HJY3.js";
35
36
  import "../chunk-2QI7XV2T.js";
36
37
  import "../chunk-E7QYOOON.js";
37
38
  export {
@@ -48,7 +49,6 @@ export {
48
49
  ProviderLogo,
49
50
  RunDrillIn,
50
51
  SeatPaywall,
51
- WorkspaceTerminalPanel,
52
52
  activityTone,
53
53
  consumeChatStream,
54
54
  dispatchChatStreamLine,
@@ -0,0 +1,49 @@
1
+ import { S as SandboxTerminalConnection } from '../sandbox-terminal-BIIC__CP.js';
2
+ export { a as SandboxTerminalConnectionResponse, U as UseSandboxTerminalConnectionOptions, b as UseSandboxTerminalConnectionResult, t as tabTerminalConnectionId, u as useSandboxTerminalConnection } from '../sandbox-terminal-BIIC__CP.js';
3
+ import { ReactNode } from 'react';
4
+
5
+ /**
6
+ * `WorkspaceTerminalPanel` — the shared sandbox-terminal surface: a header with
7
+ * a status badge, connect/provisioning/error states with a retry, and the lazy
8
+ * `TerminalView` (from `@tangle-network/sandbox-ui`) mounted only once the
9
+ * connection is live. creative-agent and gtm-agent each hand-roll a structurally
10
+ * identical panel; only the copy and the status-tone map are app-specific, so
11
+ * those are props and everything else lives here.
12
+ *
13
+ * Pair it with {@link useSandboxTerminalConnection} (the `connection` prop) and
14
+ * {@link tabTerminalConnectionId} (the `connectionId` prop) so reloads restore
15
+ * the same PTY and separate tabs don't evict each other.
16
+ *
17
+ * Styling matches the rest of `web-react`: Tailwind over the shared design
18
+ * tokens; glyphs inline; no icon/UI library.
19
+ */
20
+
21
+ type TerminalStatusTone = 'idle' | 'connecting' | 'connected' | 'error';
22
+ interface TerminalStatusDisplay {
23
+ tone: TerminalStatusTone;
24
+ label: string;
25
+ }
26
+ interface WorkspaceTerminalPanelProps {
27
+ /** Live connection state (from {@link useSandboxTerminalConnection}). */
28
+ connection: SandboxTerminalConnection;
29
+ /** Stable per-tab id (from {@link tabTerminalConnectionId}) so the sidecar
30
+ * restores the same PTY across remounts and tabs don't collide. */
31
+ connectionId?: string;
32
+ /** Header title. Default "Terminal". */
33
+ title?: string;
34
+ /** Header subtitle / sandbox label. */
35
+ subtitle?: string;
36
+ /** Whether the terminal tab is visible (forwarded to `TerminalView` for fit). */
37
+ isActive?: boolean;
38
+ /** Reconnect handler — wire to the hook's `connect`. Shown on idle/error. */
39
+ onRetry?: () => void;
40
+ /** Map a `connection.status` to a badge tone + label. The default covers
41
+ * idle/provisioning/running/error; override for app-specific vocabulary. */
42
+ statusDisplay?: (connection: SandboxTerminalConnection) => TerminalStatusDisplay;
43
+ /** Extra header content, right-aligned (actions, sandbox id, …). */
44
+ headerExtra?: ReactNode;
45
+ className?: string;
46
+ }
47
+ declare function WorkspaceTerminalPanel({ connection, connectionId, title, subtitle, isActive, onRetry, statusDisplay, headerExtra, className, }: WorkspaceTerminalPanelProps): ReactNode;
48
+
49
+ export { SandboxTerminalConnection, type TerminalStatusDisplay, type TerminalStatusTone, WorkspaceTerminalPanel, type WorkspaceTerminalPanelProps };
@@ -0,0 +1,95 @@
1
+ import {
2
+ tabTerminalConnectionId,
3
+ useSandboxTerminalConnection
4
+ } from "../chunk-65P3HJY3.js";
5
+
6
+ // src/web-react/workspace-terminal-panel.tsx
7
+ import { lazy, Suspense } from "react";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+ var TerminalView = lazy(
10
+ () => import("@tangle-network/sandbox-ui/terminal").then((m) => ({ default: m.TerminalView }))
11
+ );
12
+ var TONE_DOT = {
13
+ idle: "bg-muted-foreground/50",
14
+ connecting: "animate-pulse bg-warning",
15
+ connected: "bg-success",
16
+ error: "bg-destructive"
17
+ };
18
+ function defaultStatusDisplay(conn) {
19
+ if (conn.error) return { tone: "error", label: "Disconnected" };
20
+ if (conn.runtimeUrl && conn.token) return { tone: "connected", label: "Connected" };
21
+ if (conn.loading) return { tone: "connecting", label: conn.status === "provisioning" ? "Provisioning\u2026" : "Connecting\u2026" };
22
+ return { tone: "idle", label: "Idle" };
23
+ }
24
+ function WorkspaceTerminalPanel({
25
+ connection,
26
+ connectionId,
27
+ title = "Terminal",
28
+ subtitle,
29
+ isActive,
30
+ onRetry,
31
+ statusDisplay,
32
+ headerExtra,
33
+ className
34
+ }) {
35
+ const status = (statusDisplay ?? defaultStatusDisplay)(connection);
36
+ const apiUrl = connection.runtimeUrl ?? connection.sidecarUrl;
37
+ const ready = Boolean(apiUrl && connection.token);
38
+ return /* @__PURE__ */ jsxs("div", { className: `flex h-full min-h-0 flex-col overflow-hidden rounded-xl border border-border bg-card ${className ?? ""}`, children: [
39
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 border-b border-border px-4 py-2.5", children: [
40
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
41
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-foreground", children: title }),
42
+ subtitle && /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-muted-foreground", children: subtitle })
43
+ ] }),
44
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
45
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
46
+ /* @__PURE__ */ jsx("span", { className: `h-1.5 w-1.5 rounded-full ${TONE_DOT[status.tone]}`, "aria-hidden": true }),
47
+ status.label
48
+ ] }),
49
+ headerExtra
50
+ ] })
51
+ ] }),
52
+ /* @__PURE__ */ jsx("div", { className: "relative min-h-0 flex-1", children: ready ? /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(TerminalMessage, { children: "Loading terminal\u2026" }), children: /* @__PURE__ */ jsx(
53
+ TerminalView,
54
+ {
55
+ apiUrl,
56
+ token: connection.token,
57
+ connectionId,
58
+ title,
59
+ subtitle,
60
+ isActive
61
+ }
62
+ ) }) : /* @__PURE__ */ jsx(TerminalMessage, { children: connection.error ? /* @__PURE__ */ jsxs(Fragment, { children: [
63
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: connection.error }),
64
+ onRetry && /* @__PURE__ */ jsx(
65
+ "button",
66
+ {
67
+ type: "button",
68
+ onClick: onRetry,
69
+ className: "mt-3 inline-flex items-center justify-center rounded-lg border border-border px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-muted",
70
+ children: "Reconnect"
71
+ }
72
+ )
73
+ ] }) : connection.loading ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: connection.status === "provisioning" ? "Provisioning sandbox\u2026" : "Connecting\u2026" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
74
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Terminal not connected." }),
75
+ onRetry && /* @__PURE__ */ jsx(
76
+ "button",
77
+ {
78
+ type: "button",
79
+ onClick: onRetry,
80
+ className: "mt-3 inline-flex items-center justify-center rounded-lg border border-border px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-muted",
81
+ children: "Connect"
82
+ }
83
+ )
84
+ ] }) }) })
85
+ ] });
86
+ }
87
+ function TerminalMessage({ children }) {
88
+ return /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex flex-col items-center justify-center p-6 text-center", children });
89
+ }
90
+ export {
91
+ WorkspaceTerminalPanel,
92
+ tabTerminalConnectionId,
93
+ useSandboxTerminalConnection
94
+ };
95
+ //# sourceMappingURL=terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/web-react/workspace-terminal-panel.tsx"],"sourcesContent":["/**\n * `WorkspaceTerminalPanel` — the shared sandbox-terminal surface: a header with\n * a status badge, connect/provisioning/error states with a retry, and the lazy\n * `TerminalView` (from `@tangle-network/sandbox-ui`) mounted only once the\n * connection is live. creative-agent and gtm-agent each hand-roll a structurally\n * identical panel; only the copy and the status-tone map are app-specific, so\n * those are props and everything else lives here.\n *\n * Pair it with {@link useSandboxTerminalConnection} (the `connection` prop) and\n * {@link tabTerminalConnectionId} (the `connectionId` prop) so reloads restore\n * the same PTY and separate tabs don't evict each other.\n *\n * Styling matches the rest of `web-react`: Tailwind over the shared design\n * tokens; glyphs inline; no icon/UI library.\n */\n\nimport { lazy, Suspense, type ReactNode } from 'react'\n\nimport type { SandboxTerminalConnection } from './sandbox-terminal'\n\nconst TerminalView = lazy(() =>\n import('@tangle-network/sandbox-ui/terminal').then((m) => ({ default: m.TerminalView })),\n)\n\nexport type TerminalStatusTone = 'idle' | 'connecting' | 'connected' | 'error'\n\nexport interface TerminalStatusDisplay {\n tone: TerminalStatusTone\n label: string\n}\n\nexport interface WorkspaceTerminalPanelProps {\n /** Live connection state (from {@link useSandboxTerminalConnection}). */\n connection: SandboxTerminalConnection\n /** Stable per-tab id (from {@link tabTerminalConnectionId}) so the sidecar\n * restores the same PTY across remounts and tabs don't collide. */\n connectionId?: string\n /** Header title. Default \"Terminal\". */\n title?: string\n /** Header subtitle / sandbox label. */\n subtitle?: string\n /** Whether the terminal tab is visible (forwarded to `TerminalView` for fit). */\n isActive?: boolean\n /** Reconnect handler — wire to the hook's `connect`. Shown on idle/error. */\n onRetry?: () => void\n /** Map a `connection.status` to a badge tone + label. The default covers\n * idle/provisioning/running/error; override for app-specific vocabulary. */\n statusDisplay?: (connection: SandboxTerminalConnection) => TerminalStatusDisplay\n /** Extra header content, right-aligned (actions, sandbox id, …). */\n headerExtra?: ReactNode\n className?: string\n}\n\nconst TONE_DOT: Record<TerminalStatusTone, string> = {\n idle: 'bg-muted-foreground/50',\n connecting: 'animate-pulse bg-warning',\n connected: 'bg-success',\n error: 'bg-destructive',\n}\n\nfunction defaultStatusDisplay(conn: SandboxTerminalConnection): TerminalStatusDisplay {\n if (conn.error) return { tone: 'error', label: 'Disconnected' }\n if (conn.runtimeUrl && conn.token) return { tone: 'connected', label: 'Connected' }\n if (conn.loading) return { tone: 'connecting', label: conn.status === 'provisioning' ? 'Provisioning…' : 'Connecting…' }\n return { tone: 'idle', label: 'Idle' }\n}\n\nexport function WorkspaceTerminalPanel({\n connection,\n connectionId,\n title = 'Terminal',\n subtitle,\n isActive,\n onRetry,\n statusDisplay,\n headerExtra,\n className,\n}: WorkspaceTerminalPanelProps): ReactNode {\n const status = (statusDisplay ?? defaultStatusDisplay)(connection)\n const apiUrl = connection.runtimeUrl ?? connection.sidecarUrl\n const ready = Boolean(apiUrl && connection.token)\n\n return (\n <div className={`flex h-full min-h-0 flex-col overflow-hidden rounded-xl border border-border bg-card ${className ?? ''}`}>\n <div className=\"flex items-center justify-between gap-3 border-b border-border px-4 py-2.5\">\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-foreground\">{title}</p>\n {subtitle && <p className=\"truncate text-xs text-muted-foreground\">{subtitle}</p>}\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <span className={`h-1.5 w-1.5 rounded-full ${TONE_DOT[status.tone]}`} aria-hidden />\n {status.label}\n </span>\n {headerExtra}\n </div>\n </div>\n\n <div className=\"relative min-h-0 flex-1\">\n {ready ? (\n <Suspense fallback={<TerminalMessage>Loading terminal…</TerminalMessage>}>\n <TerminalView\n apiUrl={apiUrl as string}\n token={connection.token as string}\n connectionId={connectionId}\n title={title}\n subtitle={subtitle}\n isActive={isActive}\n />\n </Suspense>\n ) : (\n <TerminalMessage>\n {connection.error ? (\n <>\n <p className=\"text-sm text-destructive\">{connection.error}</p>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"mt-3 inline-flex items-center justify-center rounded-lg border border-border px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-muted\"\n >\n Reconnect\n </button>\n )}\n </>\n ) : connection.loading ? (\n <p className=\"text-sm text-muted-foreground\">\n {connection.status === 'provisioning' ? 'Provisioning sandbox…' : 'Connecting…'}\n </p>\n ) : (\n <>\n <p className=\"text-sm text-muted-foreground\">Terminal not connected.</p>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"mt-3 inline-flex items-center justify-center rounded-lg border border-border px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-muted\"\n >\n Connect\n </button>\n )}\n </>\n )}\n </TerminalMessage>\n )}\n </div>\n </div>\n )\n}\n\nfunction TerminalMessage({ children }: { children: ReactNode }): ReactNode {\n return <div className=\"absolute inset-0 flex flex-col items-center justify-center p-6 text-center\">{children}</div>\n}\n"],"mappings":";;;;;;AAgBA,SAAS,MAAM,gBAAgC;AAqEvC,SA4BM,UA3BJ,KADF;AAjER,IAAM,eAAe;AAAA,EAAK,MACxB,OAAO,qCAAqC,EAAE,KAAK,CAAC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE;AACzF;AA+BA,IAAM,WAA+C;AAAA,EACnD,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,OAAO;AACT;AAEA,SAAS,qBAAqB,MAAwD;AACpF,MAAI,KAAK,MAAO,QAAO,EAAE,MAAM,SAAS,OAAO,eAAe;AAC9D,MAAI,KAAK,cAAc,KAAK,MAAO,QAAO,EAAE,MAAM,aAAa,OAAO,YAAY;AAClF,MAAI,KAAK,QAAS,QAAO,EAAE,MAAM,cAAc,OAAO,KAAK,WAAW,iBAAiB,uBAAkB,mBAAc;AACvH,SAAO,EAAE,MAAM,QAAQ,OAAO,OAAO;AACvC;AAEO,SAAS,uBAAuB;AAAA,EACrC;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA2C;AACzC,QAAM,UAAU,iBAAiB,sBAAsB,UAAU;AACjE,QAAM,SAAS,WAAW,cAAc,WAAW;AACnD,QAAM,QAAQ,QAAQ,UAAU,WAAW,KAAK;AAEhD,SACE,qBAAC,SAAI,WAAW,wFAAwF,aAAa,EAAE,IACrH;AAAA,yBAAC,SAAI,WAAU,8EACb;AAAA,2BAAC,SAAI,WAAU,WACb;AAAA,4BAAC,OAAE,WAAU,gDAAgD,iBAAM;AAAA,QAClE,YAAY,oBAAC,OAAE,WAAU,0CAA0C,oBAAS;AAAA,SAC/E;AAAA,MACA,qBAAC,SAAI,WAAU,2BACb;AAAA,6BAAC,UAAK,WAAU,2DACd;AAAA,8BAAC,UAAK,WAAW,4BAA4B,SAAS,OAAO,IAAI,CAAC,IAAI,eAAW,MAAC;AAAA,UACjF,OAAO;AAAA,WACV;AAAA,QACC;AAAA,SACH;AAAA,OACF;AAAA,IAEA,oBAAC,SAAI,WAAU,2BACZ,kBACC,oBAAC,YAAS,UAAU,oBAAC,mBAAgB,oCAAiB,GACpD;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,OAAO,WAAW;AAAA,QAClB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF,GACF,IAEA,oBAAC,mBACE,qBAAW,QACV,iCACE;AAAA,0BAAC,OAAE,WAAU,4BAA4B,qBAAW,OAAM;AAAA,MACzD,WACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OAEJ,IACE,WAAW,UACb,oBAAC,OAAE,WAAU,iCACV,qBAAW,WAAW,iBAAiB,+BAA0B,oBACpE,IAEA,iCACE;AAAA,0BAAC,OAAE,WAAU,iCAAgC,qCAAuB;AAAA,MACnE,WACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OAEJ,GAEJ,GAEJ;AAAA,KACF;AAEJ;AAEA,SAAS,gBAAgB,EAAE,SAAS,GAAuC;AACzE,SAAO,oBAAC,SAAI,WAAU,8EAA8E,UAAS;AAC/G;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-app",
3
- "version": "0.43.1",
3
+ "version": "0.43.3",
4
4
  "packageManager": "pnpm@10.33.4",
5
5
  "description": "Application-shell framework for Tangle agent products: a bounded tool loop, the structured agent→app tool side channel, integration-hub client, per-workspace billing, and crypto — composed over the Tangle agent substrate through typed seams.",
6
6
  "keywords": [
@@ -158,6 +158,11 @@
158
158
  "import": "./dist/web-react/index.js",
159
159
  "default": "./dist/web-react/index.js"
160
160
  },
161
+ "./web-react/terminal": {
162
+ "types": "./dist/web-react/terminal.d.ts",
163
+ "import": "./dist/web-react/terminal.js",
164
+ "default": "./dist/web-react/terminal.js"
165
+ },
161
166
  "./composer": {
162
167
  "types": "./dist/composer/index.d.ts",
163
168
  "import": "./dist/composer/index.js",