@tangle-network/sandbox-ui 0.116.8 → 0.117.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -89,6 +89,53 @@ Pass service-observed `readiness` and enforced `access` to show their status ins
89
89
  Show process and port state beside the pane if your runtime exposes those separately.
90
90
  Do not infer either state from the preview URL or iframe load.
91
91
 
92
+ ### Show a shared agent messaging connection
93
+
94
+ Use `AgentMessagingConnection` in any app that enrolls a member with a private agent target and a shared messaging route.
95
+ The host owns authentication, the member grant, canonical target resolution, and route readiness.
96
+
97
+ ```tsx
98
+ import {
99
+ AgentMessagingConnection,
100
+ type AgentEnrollmentViewState,
101
+ type SharedMessagingRouteViewState,
102
+ } from "@tangle-network/sandbox-ui/connections";
103
+
104
+ type MessagingConnectionProps = {
105
+ enrollment: AgentEnrollmentViewState;
106
+ route: SharedMessagingRouteViewState;
107
+ enroll: () => Promise<void>;
108
+ openMessages: () => void;
109
+ refresh: () => Promise<void>;
110
+ };
111
+
112
+ export function MessagingConnection({
113
+ enrollment,
114
+ route,
115
+ enroll,
116
+ openMessages,
117
+ refresh,
118
+ }: MessagingConnectionProps) {
119
+ return (
120
+ <AgentMessagingConnection
121
+ enrollment={enrollment}
122
+ route={route}
123
+ onEnroll={enroll}
124
+ onOpenMessages={openMessages}
125
+ onRetry={refresh}
126
+ />
127
+ );
128
+ }
129
+ ```
130
+
131
+ Report `eligible` only after the host checks the member's current grant.
132
+ Report `enrolled` only after it resolves the authorized, canonical private agent target.
133
+ Give the component display labels, not raw enrollment, instance, sandbox, or session IDs.
134
+ Report route `ready` only when the shared route is valid for this application and member.
135
+ An attached provider line on its own does not prove that state.
136
+ The component never attaches, buys, or reassigns a provider identity.
137
+ It shows a messaging action only when both the target and route are confirmed.
138
+
92
139
  ### Fonts
93
140
 
94
141
  sandbox-ui references the following font families in its design tokens but does **not** bundle them — consumer apps must load the fonts themselves. This is deliberate: a URL `@import` inside a library CSS bundle breaks when downstream apps chain-import the stylesheet (see CHANGELOG 0.10.9 for the full reasoning).
@@ -375,6 +422,8 @@ For that, compose directly from:
375
422
 
376
423
  Retheming is absolutely supported, but the documentation was thinner than it should be. The token layer is strong; the higher-level surfaces are themeable, but more opinionated. For a radically different product look, prefer keeping the token contract and wrapping the higher-level workbench/chat surfaces rather than fighting every internal class.
377
424
 
425
+ `DiffView` from `/workbench` defaults to a dark code theme. If the host app offers a light/dark switch, pass its selected theme as `themeType`. The diff renderer updates when that value changes.
426
+
378
427
  ## Docs
379
428
 
380
429
  | Guide | Description |
@@ -389,6 +438,7 @@ Retheming is absolutely supported, but the documentation was thinner than it sho
389
438
  | `/chat` | ChatContainer, ChatInput, ChatMessage, AgentTimeline, ThinkingIndicator |
390
439
  | `/run` | ToolCallFeed, RunGroup, InlineToolItem, ExpandedToolDetail |
391
440
  | `/workspace` | SandboxWorkbench, WorkspaceLayout, DirectoryPane, RuntimePane, StatusBar |
441
+ | `/workbench` | DiffView, ChangesPane, CodeView, artifact and preview components |
392
442
  | `/openui` | OpenUIArtifactRenderer and schema types for structured artifact rendering |
393
443
  | `/files` | FileTree, FilePreview, FileTabs, FileArtifactPane |
394
444
  | `/workbench/embedded-app` | EmbeddedAppView and preview status types without terminal or editor modules |
@@ -1,6 +1,6 @@
1
1
  import { r as modelBrandFor, t as ModelBrandStack } from "./model-brand-hMyDTUqB.js";
2
2
  import { a as buildWorkflowGraph, c as triggerNodeIndex, d as providerLabel, f as shortModel, g as fmtTokens, h as fmtDuration, l as wfEdgeId, m as fmtCost, o as isStructuralKind, p as clampPreview, t as COMPACT_NODE_SIZE, u as worstSeverity } from "./model-I-NIxeM-.js";
3
- import { t as ProviderIcon } from "./provider-logo-DjqmConF.js";
3
+ import { t as ProviderIcon } from "./provider-logo-BiuiO_c2.js";
4
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
5
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
6
6
  import { AlertTriangle, Bell, Box, Cable, Camera, Circle, Clock, Code, GitBranch, Maximize2, Minimize2, Plus, Repeat, ScanSearch, Sparkles, UserCheck, Webhook, X, Zap } from "lucide-react";
package/dist/chat.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as ThinkingIndicator, c as createFetchTransport, d as AgentProfilePicker, f as DEFAULT_REASONING_LEVEL_OPTIONS, i as MessageList, l as modelProvider, m as ReasoningLevelPicker, n as ChatContainer, o as UserMessage, p as HARNESS_REASONING_OPTIONS, r as ChatMessage, s as ArtifactAgentDock, t as AgentTimeline, u as snapHarnessToModel } from "./chat-BOvFAe6p.js";
1
+ import { a as ThinkingIndicator, c as createFetchTransport, d as AgentProfilePicker, f as DEFAULT_REASONING_LEVEL_OPTIONS, i as MessageList, l as modelProvider, m as ReasoningLevelPicker, n as ChatContainer, o as UserMessage, p as HARNESS_REASONING_OPTIONS, r as ChatMessage, s as ArtifactAgentDock, t as AgentTimeline, u as snapHarnessToModel } from "./chat-Ci6Xi1rd.js";
2
2
  export { AgentProfilePicker, AgentTimeline, ArtifactAgentDock, ChatContainer, ChatMessage, DEFAULT_REASONING_LEVEL_OPTIONS, HARNESS_REASONING_OPTIONS, MessageList, ReasoningLevelPicker, ThinkingIndicator, UserMessage, createFetchTransport, modelProvider, snapHarnessToModel };
@@ -0,0 +1,180 @@
1
+ import { Button } from "@tangle-network/ui/primitives";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React$1 from "react";
4
+ import { cn } from "@tangle-network/ui/utils";
5
+ import { AlertCircle, CheckCircle2, Loader2, MessageSquare, ShieldCheck } from "lucide-react";
6
+ //#region src/connections/agent-messaging-connection.tsx
7
+ function AgentStatus({ enrollment }) {
8
+ switch (enrollment.status) {
9
+ case "checking": return /* @__PURE__ */ jsx("span", { children: "Checking access…" });
10
+ case "eligible": return /* @__PURE__ */ jsx("span", { children: "Not connected" });
11
+ case "enrolling": return /* @__PURE__ */ jsx("span", { children: "Connecting your agent…" });
12
+ case "enrolled": return /* @__PURE__ */ jsxs("span", { children: [
13
+ "Connected to ",
14
+ /* @__PURE__ */ jsx("strong", {
15
+ className: "font-medium text-foreground",
16
+ children: enrollment.target.agentLabel
17
+ }),
18
+ enrollment.target.workspaceLabel && /* @__PURE__ */ jsxs(Fragment, { children: [" in ", enrollment.target.workspaceLabel] })
19
+ ] });
20
+ case "forbidden": return /* @__PURE__ */ jsx("span", { children: enrollment.message ?? "You cannot connect this agent." });
21
+ case "error": return /* @__PURE__ */ jsx("span", { children: enrollment.message ?? "Could not check agent access." });
22
+ }
23
+ }
24
+ function RouteStatus({ enrollment, route }) {
25
+ switch (route.status) {
26
+ case "checking": return /* @__PURE__ */ jsx("span", { children: "Checking messaging…" });
27
+ case "pending": return /* @__PURE__ */ jsx("span", { children: route.message ?? "Setting up messaging…" });
28
+ case "ready": return enrollment.status === "enrolled" ? /* @__PURE__ */ jsxs("span", { children: [
29
+ "Ready on ",
30
+ /* @__PURE__ */ jsx("strong", {
31
+ className: "font-medium text-foreground",
32
+ children: route.channelLabel
33
+ }),
34
+ /* @__PURE__ */ jsx("span", {
35
+ className: "block break-words",
36
+ children: route.destinationLabel
37
+ })
38
+ ] }) : enrollment.status === "eligible" ? /* @__PURE__ */ jsx("span", { children: "Connect your agent to use messaging." }) : /* @__PURE__ */ jsx("span", { children: "Agent connection is unconfirmed." });
39
+ case "unavailable": return /* @__PURE__ */ jsx("span", { children: route.message ?? "Messaging is unavailable right now." });
40
+ case "forbidden": return /* @__PURE__ */ jsx("span", { children: route.message ?? "You cannot use messaging in this app." });
41
+ case "error": return /* @__PURE__ */ jsx("span", { children: route.message ?? "Could not check messaging." });
42
+ }
43
+ }
44
+ function AgentMessagingConnection({ enrollment, route, onEnroll, onOpenMessages, onRetry, className }) {
45
+ const [submitting, setSubmitting] = React$1.useState(false);
46
+ const [actionError, setActionError] = React$1.useState(null);
47
+ const submittingRef = React$1.useRef(false);
48
+ const canMessage = enrollment.status === "enrolled" && route.status === "ready";
49
+ const canRetry = enrollment.status === "error" || route.status === "error";
50
+ React$1.useEffect(() => {
51
+ setActionError(null);
52
+ }, [enrollment.status, route.status]);
53
+ async function enroll() {
54
+ if (enrollment.status !== "eligible" || submittingRef.current) return;
55
+ submittingRef.current = true;
56
+ setSubmitting(true);
57
+ setActionError(null);
58
+ try {
59
+ await onEnroll();
60
+ } catch {
61
+ setActionError("Could not connect the agent. Try again.");
62
+ } finally {
63
+ submittingRef.current = false;
64
+ setSubmitting(false);
65
+ }
66
+ }
67
+ async function retry() {
68
+ if (!onRetry || submittingRef.current) return;
69
+ submittingRef.current = true;
70
+ setSubmitting(true);
71
+ setActionError(null);
72
+ try {
73
+ await onRetry();
74
+ } catch {
75
+ setActionError("Could not check messaging. Try again.");
76
+ } finally {
77
+ submittingRef.current = false;
78
+ setSubmitting(false);
79
+ }
80
+ }
81
+ return /* @__PURE__ */ jsxs("section", {
82
+ "aria-label": "Agent messaging connection",
83
+ className: cn("rounded-xl border border-border bg-card p-4 text-sm text-foreground sm:p-5", className),
84
+ children: [
85
+ /* @__PURE__ */ jsx("h2", {
86
+ className: "mb-4 text-base font-semibold",
87
+ children: "Agent messaging"
88
+ }),
89
+ /* @__PURE__ */ jsxs("div", {
90
+ className: "divide-y divide-border rounded-lg border border-border",
91
+ children: [/* @__PURE__ */ jsxs("div", {
92
+ className: "flex gap-3 p-3 sm:p-4",
93
+ children: [
94
+ /* @__PURE__ */ jsx(ShieldCheck, {
95
+ "aria-hidden": "true",
96
+ className: "mt-0.5 h-4 w-4 shrink-0 text-muted-foreground"
97
+ }),
98
+ /* @__PURE__ */ jsxs("div", {
99
+ className: "min-w-0",
100
+ children: [/* @__PURE__ */ jsx("p", {
101
+ className: "font-medium",
102
+ children: "Private agent"
103
+ }), /* @__PURE__ */ jsx("p", {
104
+ "aria-live": "polite",
105
+ className: "mt-0.5 break-words text-muted-foreground",
106
+ children: /* @__PURE__ */ jsx(AgentStatus, { enrollment })
107
+ })]
108
+ }),
109
+ enrollment.status === "enrolled" && /* @__PURE__ */ jsx(CheckCircle2, {
110
+ "aria-label": "Connected",
111
+ className: "ml-auto h-4 w-4 shrink-0 text-[var(--code-success)]"
112
+ })
113
+ ]
114
+ }), /* @__PURE__ */ jsxs("div", {
115
+ className: "flex gap-3 p-3 sm:p-4",
116
+ children: [
117
+ /* @__PURE__ */ jsx(MessageSquare, {
118
+ "aria-hidden": "true",
119
+ className: "mt-0.5 h-4 w-4 shrink-0 text-muted-foreground"
120
+ }),
121
+ /* @__PURE__ */ jsxs("div", {
122
+ className: "min-w-0",
123
+ children: [/* @__PURE__ */ jsx("p", {
124
+ className: "font-medium",
125
+ children: "Messaging"
126
+ }), /* @__PURE__ */ jsx("p", {
127
+ "aria-live": "polite",
128
+ className: "mt-0.5 break-words text-muted-foreground",
129
+ children: /* @__PURE__ */ jsx(RouteStatus, {
130
+ enrollment,
131
+ route
132
+ })
133
+ })]
134
+ }),
135
+ canMessage && /* @__PURE__ */ jsx(CheckCircle2, {
136
+ "aria-label": "Ready",
137
+ className: "ml-auto h-4 w-4 shrink-0 text-[var(--code-success)]"
138
+ })
139
+ ]
140
+ })]
141
+ }),
142
+ (enrollment.status === "eligible" || canMessage || canRetry && onRetry) && /* @__PURE__ */ jsxs("div", {
143
+ className: "mt-4 flex flex-wrap items-center gap-3",
144
+ children: [
145
+ enrollment.status === "eligible" && /* @__PURE__ */ jsxs(Button, {
146
+ type: "button",
147
+ onClick: enroll,
148
+ disabled: submitting,
149
+ children: [submitting ? /* @__PURE__ */ jsx(Loader2, {
150
+ "aria-hidden": "true",
151
+ className: "mr-2 h-4 w-4 animate-spin"
152
+ }) : null, submitting ? "Connecting agent…" : "Connect agent"]
153
+ }),
154
+ canMessage && onOpenMessages && /* @__PURE__ */ jsx(Button, {
155
+ type: "button",
156
+ onClick: onOpenMessages,
157
+ children: "Open messages"
158
+ }),
159
+ canRetry && onRetry && /* @__PURE__ */ jsx(Button, {
160
+ type: "button",
161
+ variant: "outline",
162
+ onClick: retry,
163
+ disabled: submitting,
164
+ children: submitting ? "Checking…" : "Check again"
165
+ })
166
+ ]
167
+ }),
168
+ actionError && /* @__PURE__ */ jsxs("p", {
169
+ role: "alert",
170
+ className: "mt-3 flex items-center gap-2 text-[var(--code-error)]",
171
+ children: [/* @__PURE__ */ jsx(AlertCircle, {
172
+ "aria-hidden": "true",
173
+ className: "h-4 w-4 shrink-0"
174
+ }), actionError]
175
+ })
176
+ ]
177
+ });
178
+ }
179
+ //#endregion
180
+ export { AgentMessagingConnection as t };
@@ -0,0 +1,2 @@
1
+ import { a as SharedMessagingRouteViewState, i as AgentTargetSummary, n as AgentMessagingConnection, r as AgentMessagingConnectionProps, t as AgentEnrollmentViewState } from "./index-ClRHbsoX.js";
2
+ export { type AgentEnrollmentViewState, AgentMessagingConnection, type AgentMessagingConnectionProps, type AgentTargetSummary, type SharedMessagingRouteViewState };
@@ -0,0 +1,2 @@
1
+ import { t as AgentMessagingConnection } from "./connections-DDRGYDvF.js";
2
+ export { AgentMessagingConnection };