@tangle-network/sandbox-ui 2.0.18 → 2.0.20

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.
@@ -5,7 +5,7 @@ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } fr
5
5
  import { Brain, Settings, Timer } from "lucide-react";
6
6
  import { formatDuration, getToolCategory, getToolDisplayMetadata } from "@tangle-network/ui/utils";
7
7
  import { AgentTimelineColumn, AgentTimelineStep, SpeakerHeader, agentTimelineStepKind } from "@tangle-network/ui/chat";
8
- import { ExpandedToolDetail, InlineThinkingItem, RunRowShell } from "@tangle-network/ui/run";
8
+ import { ExpandedToolDetail, InlineThinkingItem, RunRowShell, RunStatusIcon, runStatus } from "@tangle-network/ui/run";
9
9
  // src/run/record/VirtualList.tsx
10
10
  /**
11
11
  * Renders only the rows near the viewport of `scroller`. Row heights are measured as they render; unmeasured
@@ -1516,4 +1516,82 @@ function withPrompts(record) {
1516
1516
  events
1517
1517
  };
1518
1518
  }
1519
- export { VirtualList as a, model_exports as i, Conversation as n, indexRecord as r, withPrompts as t };
1519
+ // src/run/record/AgentTree.tsx
1520
+ /** Retained identity and recorded time define the hierarchy; labels never join sessions or invent parents. */
1521
+ function AgentTree({ index, actor, cutoff, select }) {
1522
+ const roots = useMemo(() => {
1523
+ const nodes = index.actors.filter((node) => node.kind !== "finding");
1524
+ const byId = new Map(nodes.map((node) => [node.id, node]));
1525
+ const children = /* @__PURE__ */ new Map();
1526
+ for (const node of nodes) {
1527
+ if (!node.parent) continue;
1528
+ const parent = index.canonical(node.parent), siblings = children.get(parent) ?? [];
1529
+ siblings.push(node);
1530
+ children.set(parent, siblings);
1531
+ }
1532
+ const visited = /* @__PURE__ */ new Set();
1533
+ const visit = (node) => {
1534
+ if (visited.has(node.id)) return [];
1535
+ visited.add(node.id);
1536
+ return [{
1537
+ node,
1538
+ children: (children.get(node.id) ?? []).flatMap(visit)
1539
+ }];
1540
+ };
1541
+ const roots = nodes.filter((node) => !node.parent || !byId.has(index.canonical(node.parent))).flatMap(visit);
1542
+ for (const node of nodes) roots.push(...visit(node));
1543
+ return roots;
1544
+ }, [index]);
1545
+ const renderNodes = (entries, nested = false) => /* @__PURE__ */ jsx("ul", {
1546
+ className: nested ? "m-0 ml-3 list-none border-l border-border pl-2" : "m-0 grid list-none gap-1 p-0",
1547
+ children: entries.map(({ node, children }) => {
1548
+ const firstEvent = index.byActor.get(node.id)?.[0];
1549
+ const begin = node.start ? ms(node.start) : firstEvent ? ms(firstEvent.at) : void 0;
1550
+ const end = typeof node.end === "string" ? node.end : void 0;
1551
+ const future = begin !== void 0 && begin > cutoff, ended = end !== void 0 && ms(end) <= cutoff;
1552
+ const state = future ? "Not yet started" : ended ? node.status === "done" ? "Finished" : node.status === "down" ? "Stopped" : node.status ?? "Ended" : end ? "Not yet settled" : "No terminal record";
1553
+ return /* @__PURE__ */ jsxs("li", {
1554
+ className: "min-w-0",
1555
+ children: [/* @__PURE__ */ jsxs("button", {
1556
+ type: "button",
1557
+ className: "flex w-full min-w-0 items-start gap-2 rounded border border-transparent px-2 py-1.5 text-left text-sm text-foreground hover:border-border focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring aria-pressed:border-border aria-pressed:bg-muted data-[future]:opacity-55",
1558
+ "aria-label": "Read " + roleOf(node) + " " + node.label + " conversation. " + state + ".",
1559
+ "aria-pressed": actor === node.id,
1560
+ "data-node": node.id,
1561
+ "data-future": future ? "" : void 0,
1562
+ title: node.label + (node.assignment ? " · " + node.assignment : "") + " · " + state,
1563
+ onClick: () => select(node.id),
1564
+ children: [/* @__PURE__ */ jsx(RunStatusIcon, {
1565
+ status: runStatus(future ? "unknown" : node.status === "down" || node.status === "no-winner" ? "stopped" : node.status ?? "unknown"),
1566
+ className: "mt-0.5 size-3.5 shrink-0",
1567
+ "aria-hidden": true
1568
+ }), /* @__PURE__ */ jsxs("span", {
1569
+ className: "grid min-w-0 gap-0.5 break-words",
1570
+ children: [/* @__PURE__ */ jsx("span", {
1571
+ className: "font-semibold",
1572
+ children: node.label
1573
+ }), /* @__PURE__ */ jsxs("span", {
1574
+ className: "text-muted-foreground",
1575
+ children: [
1576
+ roleOf(node),
1577
+ " · ",
1578
+ state
1579
+ ]
1580
+ })]
1581
+ })]
1582
+ }), children.length > 0 && renderNodes(children, true)]
1583
+ }, node.id);
1584
+ })
1585
+ });
1586
+ return /* @__PURE__ */ jsx("div", {
1587
+ className: "record-agent-tree max-h-80 overflow-auto px-2 py-2",
1588
+ "data-graph": true,
1589
+ role: "group",
1590
+ "aria-label": "Recorded agent hierarchy. Select an agent to read its conversation.",
1591
+ children: roots.length ? renderNodes(roots) : /* @__PURE__ */ jsx("p", {
1592
+ className: "text-sm text-muted-foreground",
1593
+ children: "No agent topology was retained."
1594
+ })
1595
+ });
1596
+ }
1597
+ export { model_exports as a, indexRecord as i, withPrompts as n, VirtualList as o, Conversation as r, AgentTree as t };
@@ -1,4 +1,5 @@
1
1
  import { t as AgentStreamOpener } from "../agent-stream-CBZ2fXJ2.js";
2
+ /** Keep one transport identity per authenticated account; changing it discards the previous view. */
2
3
  export interface LiveRunTransport {
3
4
  fetch?: typeof globalThis.fetch;
4
5
  openEventSource?: AgentStreamOpener;
package/dist/run/live.js CHANGED
@@ -2,9 +2,9 @@ import { t as WorkspaceFilesPane } from "../workspace-files-pane-DB9Nvwh4.js";
2
2
  import { t as DiffView } from "../diff-view-B9mNeTLF.js";
3
3
  import { t as CodeView } from "../code-view-BlhCS1SD.js";
4
4
  import { t as TraceWorkspace } from "../trace-workspace-C8dHRBDV.js";
5
- import { t as useDocument } from "../use-document-D6Z9oFLm.js";
5
+ import { useDocument } from "../hooks/use-document.js";
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
- import { useEffect, useMemo, useState } from "react";
7
+ import { useEffect, useMemo, useRef, useState } from "react";
8
8
  import { runStatus } from "@tangle-network/ui/run";
9
9
  // src/run/live-inspection.tsx
10
10
  /** The graph, conversation and files share one selected agent and one product-owned API. */
@@ -12,12 +12,12 @@ function useLiveInspection(url, live, fetcher) {
12
12
  const inventory = useDocument(url ?? null, live ? 3e3 : void 0, false, fetcher);
13
13
  const [selected, select] = useState();
14
14
  const [download, setDownload] = useState();
15
- const files = inventory.data?.files?.entries ?? [];
15
+ const files = inventory.error ? [] : inventory.data?.files?.entries ?? [];
16
16
  const entry = files.find((file) => file.path === selected) ?? files[0];
17
17
  const fileUrl = entry && url ? `${url}/file?path=${encodeURIComponent(entry.path)}` : null;
18
18
  const content = useDocument(fileUrl, live ? 3e3 : void 0, false, fetcher);
19
19
  const file = content.data?.file;
20
- const valid = file && entry && file.path === entry.path && file.sha256 === entry.sha256 && file.byteLength === entry.byteLength;
20
+ const valid = !inventory.error && !content.error && file && entry && file.path === entry.path && file.sha256 === entry.sha256 && file.byteLength === entry.byteLength;
21
21
  const fileKey = valid ? `${entry.path}:${entry.sha256}` : void 0;
22
22
  useEffect(() => {
23
23
  if (!fileKey || !file) return;
@@ -29,7 +29,11 @@ function useLiveInspection(url, live, fetcher) {
29
29
  return () => URL.revokeObjectURL(href);
30
30
  }, [fileKey, file?.content]);
31
31
  const coverage = inventory.data?.coverage;
32
- const scoreboard = inventory.status === 404 ? void 0 : coverage ? /* @__PURE__ */ jsxs("details", {
32
+ const scoreboard = inventory.error ? /* @__PURE__ */ jsxs("p", {
33
+ className: "ws-status",
34
+ role: "alert",
35
+ children: ["Conversation inspection unavailable: ", inventory.error]
36
+ }) : coverage ? /* @__PURE__ */ jsxs("details", {
33
37
  className: "ws-status",
34
38
  open: coverage.status !== "complete",
35
39
  "data-capture-status": coverage.status,
@@ -42,10 +46,6 @@ function useLiveInspection(url, live, fetcher) {
42
46
  }, `${row.at}:${index}`))] }),
43
47
  inventory.data?.files?.scope === "none" && /* @__PURE__ */ jsx("p", { children: inventory.data.files.reason ?? "No workspace inventory was captured." })
44
48
  ]
45
- }) : inventory.error ? /* @__PURE__ */ jsxs("p", {
46
- className: "ws-status",
47
- role: "alert",
48
- children: ["Conversation inspection unavailable: ", inventory.error]
49
49
  }) : void 0;
50
50
  return {
51
51
  scoreboard: /* @__PURE__ */ jsxs(Fragment, { children: [scoreboard, inventory.data?.files && !inventory.data.files.complete && /* @__PURE__ */ jsxs("p", {
@@ -88,14 +88,23 @@ function useLiveInspection(url, live, fetcher) {
88
88
  className: "ws-status",
89
89
  children: [
90
90
  /* @__PURE__ */ jsx("summary", { children: "Provenance" }),
91
- /* @__PURE__ */ jsx("code", { children: entry.sha256 }),
91
+ /* @__PURE__ */ jsx("code", {
92
+ className: "break-all",
93
+ children: entry.sha256
94
+ }),
92
95
  file.before && /* @__PURE__ */ jsxs("p", { children: [
93
96
  "Compared with ",
94
97
  file.before.source.kind,
95
98
  " ",
96
- /* @__PURE__ */ jsx("code", { children: file.before.source.ref }),
99
+ /* @__PURE__ */ jsx("code", {
100
+ className: "break-all",
101
+ children: file.before.source.ref
102
+ }),
97
103
  ": ",
98
- /* @__PURE__ */ jsx("code", { children: file.before.sha256 })
104
+ /* @__PURE__ */ jsx("code", {
105
+ className: "break-all",
106
+ children: file.before.sha256
107
+ })
99
108
  ] }),
100
109
  /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("a", {
101
110
  href: download && download.key === fileKey ? download.href : void 0,
@@ -146,7 +155,21 @@ const isOpen = (status) => [
146
155
  ].includes(flowStatus(status));
147
156
  /** Both the Discovery host and agent-runtime-top mount this same stream consumer and shared run workspace. */
148
157
  function LiveRun(props) {
149
- return /* @__PURE__ */ jsx(LiveRunView, { ...props }, props.api);
158
+ const scope = useRef({
159
+ api: props.api,
160
+ transport: props.transport,
161
+ fetcher: props.transport?.fetch,
162
+ opener: props.transport?.openEventSource,
163
+ revision: 0
164
+ });
165
+ if (scope.current.api !== props.api || scope.current.transport !== props.transport || scope.current.fetcher !== props.transport?.fetch || scope.current.opener !== props.transport?.openEventSource) scope.current = {
166
+ api: props.api,
167
+ transport: props.transport,
168
+ fetcher: props.transport?.fetch,
169
+ opener: props.transport?.openEventSource,
170
+ revision: scope.current.revision + 1
171
+ };
172
+ return /* @__PURE__ */ jsx(LiveRunView, { ...props }, scope.current.revision);
150
173
  }
151
174
  function LiveRunView({ api, transport }) {
152
175
  const [snapshots, setSnapshots] = useState([]);
@@ -1,2 +1,2 @@
1
- import { a as EventFlag, c as indexRecord, d as ConversationNode, f as ConversationRecord, i as ConversationProps, l as model_d_exports, n as withPrompts, o as RecordIndex, r as Conversation, s as ToolCall, t as VirtualList, u as ConversationEvent } from "../index-DRLVHl-o.js";
2
- export { Conversation, type ConversationEvent, type ConversationNode, type ConversationProps, type ConversationRecord, type EventFlag, type RecordIndex, type ToolCall, VirtualList, indexRecord, model_d_exports as recordModel, withPrompts };
1
+ import { a as ConversationProps, c as ToolCall, d as ConversationEvent, f as ConversationNode, i as Conversation, l as indexRecord, n as VirtualList, o as EventFlag, p as ConversationRecord, r as withPrompts, s as RecordIndex, t as AgentTree, u as model_d_exports } from "../index-BYkigpIM.js";
2
+ export { AgentTree, Conversation, type ConversationEvent, type ConversationNode, type ConversationProps, type ConversationRecord, type EventFlag, type RecordIndex, type ToolCall, VirtualList, indexRecord, model_d_exports as recordModel, withPrompts };
@@ -1 +1 @@
1
- export { n as Conversation, a as VirtualList, r as indexRecord, i as recordModel, t as withPrompts } from "../record-Bqt1kE_Q.js";
1
+ export { t as AgentTree, r as Conversation, o as VirtualList, i as indexRecord, a as recordModel, n as withPrompts } from "../record-Cwyo2oHb.js";
package/dist/run.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as ToolCallData, B as taskStatus, C as RunStatusIcon, D as TaskListItem, E as TaskList, F as parseToolEvent, G as TraceWorkspaceProps, H as LatestEventsProps, I as runStatus, J as traceSpanMark, K as TraceWaterfall, L as showsTaskPriority, M as ToolCallFeedProps, N as ToolCallStatus, O as TaskListProps, P as ToolCallType, R as statusMeta, S as RunStatus, T as StatusMeta, U as TraceEvent, V as LatestEvents, W as TraceWorkspace, _ as RunPhaseList, a as ApprovalPlanStep, b as RunRowStatus, c as FeedSegment, d as InlineToolItem, f as InlineToolItemProps, g as RunPhase, h as RunGroupProps, i as ApprovalDiffSummary, j as ToolCallFeed, k as TaskStatus, l as InlineThinkingItem, m as RunGroup, n as ApprovalCardProps, o as ExpandedToolDetail, p as LiveDuration, q as TraceWaterfallProps, r as ApprovalDiffFile, s as ExpandedToolDetailProps, t as ApprovalCard, u as InlineThinkingItemProps, v as RunRowShell, w as RunStatusIconProps, x as RunRowStatusDot, y as RunRowShellProps, z as taskProgress } from "./index-BnaVprN6.js";
1
+ import { A as ToolCallData, B as taskStatus, C as RunStatusIcon, D as TaskListItem, E as TaskList, F as parseToolEvent, G as TraceWorkspaceProps, H as LatestEventsProps, I as runStatus, J as traceSpanMark, K as TraceWaterfall, L as showsTaskPriority, M as ToolCallFeedProps, N as ToolCallStatus, O as TaskListProps, P as ToolCallType, R as statusMeta, S as RunStatus, T as StatusMeta, U as TraceEvent, V as LatestEvents, W as TraceWorkspace, _ as RunPhaseList, a as ApprovalPlanStep, b as RunRowStatus, c as FeedSegment, d as InlineToolItem, f as InlineToolItemProps, g as RunPhase, h as RunGroupProps, i as ApprovalDiffSummary, j as ToolCallFeed, k as TaskStatus, l as InlineThinkingItem, m as RunGroup, n as ApprovalCardProps, o as ExpandedToolDetail, p as LiveDuration, q as TraceWaterfallProps, r as ApprovalDiffFile, s as ExpandedToolDetailProps, t as ApprovalCard, u as InlineThinkingItemProps, v as RunRowShell, w as RunStatusIconProps, x as RunRowStatusDot, y as RunRowShellProps, z as taskProgress } from "./index-ByNsP4VC.js";
2
2
  import { a as AgentTranscriptEntry, i as AgentStreamState, n as AgentStreamRow, o as foldAgentRows, r as AgentStreamSource, s as useAgentStream, t as AgentStreamOpener } from "./agent-stream-CBZ2fXJ2.js";
3
- import { a as EventFlag, c as indexRecord, d as ConversationNode, f as ConversationRecord, i as ConversationProps, l as model_d_exports, n as withPrompts, o as RecordIndex, r as Conversation, s as ToolCall, t as VirtualList, u as ConversationEvent } from "./index-DRLVHl-o.js";
4
- export { type AgentStreamOpener, type AgentStreamRow, type AgentStreamSource, type AgentStreamState, type AgentTranscriptEntry, ApprovalCard, type ApprovalCardProps, type ApprovalDiffFile, ApprovalDiffSummary, type ApprovalPlanStep, Conversation, type ConversationEvent, type ConversationNode, type ConversationProps, type ConversationRecord, type EventFlag, ExpandedToolDetail, type ExpandedToolDetailProps, type FeedSegment, InlineThinkingItem, type InlineThinkingItemProps, InlineToolItem, type InlineToolItemProps, LatestEvents, type LatestEventsProps, LiveDuration, type RecordIndex, RunGroup, type RunGroupProps, type RunPhase, RunPhaseList, RunRowShell, type RunRowShellProps, type RunRowStatus, RunRowStatusDot, type RunStatus, RunStatusIcon, type RunStatusIconProps, type StatusMeta, TaskList, type TaskListItem, type TaskListProps, type TaskStatus, type ToolCall, type ToolCallData, ToolCallFeed, type ToolCallFeedProps, type ToolCallStatus, type ToolCallType, type TraceEvent, TraceWaterfall, type TraceWaterfallProps, TraceWorkspace, type TraceWorkspaceProps, VirtualList, foldAgentRows, indexRecord, parseToolEvent, model_d_exports as recordModel, runStatus, showsTaskPriority, statusMeta, taskProgress, taskStatus, traceSpanMark, useAgentStream, withPrompts };
3
+ import { a as ConversationProps, c as ToolCall, d as ConversationEvent, f as ConversationNode, i as Conversation, l as indexRecord, n as VirtualList, o as EventFlag, p as ConversationRecord, r as withPrompts, s as RecordIndex, t as AgentTree, u as model_d_exports } from "./index-BYkigpIM.js";
4
+ export { type AgentStreamOpener, type AgentStreamRow, type AgentStreamSource, type AgentStreamState, type AgentTranscriptEntry, AgentTree, ApprovalCard, type ApprovalCardProps, type ApprovalDiffFile, ApprovalDiffSummary, type ApprovalPlanStep, Conversation, type ConversationEvent, type ConversationNode, type ConversationProps, type ConversationRecord, type EventFlag, ExpandedToolDetail, type ExpandedToolDetailProps, type FeedSegment, InlineThinkingItem, type InlineThinkingItemProps, InlineToolItem, type InlineToolItemProps, LatestEvents, type LatestEventsProps, LiveDuration, type RecordIndex, RunGroup, type RunGroupProps, type RunPhase, RunPhaseList, RunRowShell, type RunRowShellProps, type RunRowStatus, RunRowStatusDot, type RunStatus, RunStatusIcon, type RunStatusIconProps, type StatusMeta, TaskList, type TaskListItem, type TaskListProps, type TaskStatus, type ToolCall, type ToolCallData, ToolCallFeed, type ToolCallFeedProps, type ToolCallStatus, type ToolCallType, type TraceEvent, TraceWaterfall, type TraceWaterfallProps, TraceWorkspace, type TraceWorkspaceProps, VirtualList, foldAgentRows, indexRecord, parseToolEvent, model_d_exports as recordModel, runStatus, showsTaskPriority, statusMeta, taskProgress, taskStatus, traceSpanMark, useAgentStream, withPrompts };
package/dist/run.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import { a as TraceWaterfall, i as useAgentStream, n as LatestEvents, o as traceSpanMark, r as foldAgentRows, t as TraceWorkspace } from "./trace-workspace-C8dHRBDV.js";
2
- import { a as VirtualList, i as model_exports, n as Conversation, r as indexRecord, t as withPrompts } from "./record-Bqt1kE_Q.js";
2
+ import { a as model_exports, i as indexRecord, n as withPrompts, o as VirtualList, r as Conversation, t as AgentTree } from "./record-Cwyo2oHb.js";
3
3
  import { ApprovalCard, ApprovalDiffSummary, ExpandedToolDetail, InlineThinkingItem, InlineToolItem, LiveDuration, RunGroup, RunPhaseList, RunRowShell, RunRowStatusDot, RunStatusIcon, TaskList, ToolCallFeed, parseToolEvent, runStatus, showsTaskPriority, statusMeta, taskProgress, taskStatus } from "@tangle-network/ui/run";
4
- export { ApprovalCard, ApprovalDiffSummary, Conversation, ExpandedToolDetail, InlineThinkingItem, InlineToolItem, LatestEvents, LiveDuration, RunGroup, RunPhaseList, RunRowShell, RunRowStatusDot, RunStatusIcon, TaskList, ToolCallFeed, TraceWaterfall, TraceWorkspace, VirtualList, foldAgentRows, indexRecord, parseToolEvent, model_exports as recordModel, runStatus, showsTaskPriority, statusMeta, taskProgress, taskStatus, traceSpanMark, useAgentStream, withPrompts };
4
+ export { AgentTree, ApprovalCard, ApprovalDiffSummary, Conversation, ExpandedToolDetail, InlineThinkingItem, InlineToolItem, LatestEvents, LiveDuration, RunGroup, RunPhaseList, RunRowShell, RunRowStatusDot, RunStatusIcon, TaskList, ToolCallFeed, TraceWaterfall, TraceWorkspace, VirtualList, foldAgentRows, indexRecord, parseToolEvent, model_exports as recordModel, runStatus, showsTaskPriority, statusMeta, taskProgress, taskStatus, traceSpanMark, useAgentStream, withPrompts };
package/dist/styles.css CHANGED
@@ -1991,6 +1991,9 @@
1991
1991
  .\[scrollbar-gutter\:stable\] {
1992
1992
  scrollbar-gutter: stable;
1993
1993
  }
1994
+ .list-none {
1995
+ list-style-type: none;
1996
+ }
1994
1997
  .appearance-none {
1995
1998
  appearance: none;
1996
1999
  }
@@ -5617,15 +5620,25 @@
5617
5620
  outline-style: var(--tw-outline-style);
5618
5621
  outline-width: 1px;
5619
5622
  }
5623
+ .focus-visible\:outline-2:focus-visible {
5624
+ outline-style: var(--tw-outline-style);
5625
+ outline-width: 2px;
5626
+ }
5620
5627
  .focus-visible\:-outline-offset-1:focus-visible {
5621
5628
  outline-offset: calc(1px * -1);
5622
5629
  }
5623
5630
  .focus-visible\:outline-offset-0:focus-visible {
5624
5631
  outline-offset: 0px;
5625
5632
  }
5633
+ .focus-visible\:outline-offset-2:focus-visible {
5634
+ outline-offset: 2px;
5635
+ }
5626
5636
  .focus-visible\:outline-\[var\(--focus-border\)\]:focus-visible {
5627
5637
  outline-color: var(--focus-border);
5628
5638
  }
5639
+ .focus-visible\:outline-ring:focus-visible {
5640
+ outline-color: hsl(var(--ring));
5641
+ }
5629
5642
  .focus-visible\:outline-none:focus-visible {
5630
5643
  --tw-outline-style: none;
5631
5644
  outline-style: none;
@@ -5746,6 +5759,9 @@
5746
5759
  .aria-invalid\:focus\:ring-\[var\(--focus-halo-danger\)\][aria-invalid="true"]:focus {
5747
5760
  --tw-ring-color: var(--focus-halo-danger);
5748
5761
  }
5762
+ .aria-pressed\:border-border[aria-pressed="true"] {
5763
+ border-color: hsl(var(--border));
5764
+ }
5749
5765
  .aria-pressed\:bg-\[var\(--ix-sel-bg\)\][aria-pressed="true"] {
5750
5766
  background-color: var(--ix-sel-bg);
5751
5767
  }
@@ -5799,6 +5815,9 @@
5799
5815
  .data-\[disabled\]\:opacity-50[data-disabled] {
5800
5816
  opacity: 50%;
5801
5817
  }
5818
+ .data-\[future\]\:opacity-55[data-future] {
5819
+ opacity: 55%;
5820
+ }
5802
5821
  .data-\[highlighted\]\:bg-\[var\(--ix-sel-bg\)\][data-highlighted] {
5803
5822
  background-color: var(--ix-sel-bg);
5804
5823
  }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Same-origin JSON with ETag revalidation. `poll` refetches every `poll` ms while set; turning polling on or off keeps
3
+ * the document. With `keepPrevious`, a new URL (a record's next digest) keeps showing the previous document until the
4
+ * new one arrives, so a run being written never blanks between versions. A response marked stale is refetched until it is current.
5
+ */
6
+ declare function useDocument<T>(url: string | null, poll?: number, keepPrevious?: boolean, fetcher?: typeof fetch): {
7
+ url: string | null;
8
+ fetcher: typeof fetcher;
9
+ data?: T;
10
+ error?: string;
11
+ status?: number;
12
+ loading: boolean;
13
+ stale?: boolean;
14
+ failing?: string;
15
+ };
16
+ export { useDocument as t };
@@ -43989,91 +43989,112 @@ function SU({ trace: e, streamUrl: t, openEventSource: n, events: r, onTimeChang
43989
43989
  ]
43990
43990
  });
43991
43991
  }
43992
- // dist/use-document-D6Z9oFLm.js
43992
+ // dist/hooks/use-document.js
43993
43993
  var CU = 2500, wU = 6, TU = 4;
43994
43994
  function EU(e, t, n = !1, r = globalThis.fetch) {
43995
43995
  let [i, a] = (0, G.useState)({
43996
43996
  url: e,
43997
+ fetcher: r,
43997
43998
  loading: !!e
43998
43999
  }), o = (0, G.useRef)(null), s = (0, G.useRef)(void 0);
43999
44000
  return (0, G.useEffect)(() => {
44000
- if (s.current !== e && (s.current = e, o.current = null, a((t) => n && e && t.data !== void 0 ? {
44001
+ let i = s.current?.fetcher === r;
44002
+ if (s.current?.url === e && i || (s.current = {
44003
+ url: e,
44004
+ fetcher: r
44005
+ }, o.current = null, a((t) => i && n && e && t.data !== void 0 ? {
44001
44006
  ...t,
44002
44007
  url: e,
44003
44008
  loading: !0,
44004
44009
  error: void 0
44005
44010
  } : {
44006
44011
  url: e,
44012
+ fetcher: r,
44007
44013
  loading: !!e
44008
44014
  })), !e) return;
44009
- let i = !0, c = 0, l = !1, u = 0, d = 0, f = !1, p = new AbortController(), m = async () => {
44010
- f = !1;
44015
+ let c = !0, l = 0, u = !1, d = 0, f = 0, p = !1, m = new AbortController(), h = async () => {
44016
+ p = !1;
44011
44017
  try {
44012
44018
  let t = await r(e, {
44013
44019
  credentials: "same-origin",
44014
- signal: p.signal,
44020
+ cache: "no-store",
44021
+ signal: m.signal,
44015
44022
  headers: o.current ? { "If-None-Match": o.current } : {}
44016
44023
  });
44017
- if (!i) return;
44018
- d = 0, l = t.headers.get("X-Workspace-Stale") === "1";
44024
+ if (!c) return;
44025
+ f = 0, u = t.headers.get("X-Workspace-Stale") === "1";
44019
44026
  let n = t.headers.get("X-Workspace-Compose-Error") ?? void 0;
44020
- if (!l && (t.ok || t.status === 304) && (u = 0), t.status === 304) {
44021
- a((e) => e.stale === l && e.failing === n ? e : {
44027
+ if (!u && (t.ok || t.status === 304) && (d = 0), t.status === 304) {
44028
+ a((e) => !e.error && e.stale === u && e.failing === n ? e : {
44022
44029
  ...e,
44023
- stale: l,
44030
+ loading: !1,
44031
+ error: void 0,
44032
+ status: 304,
44033
+ stale: u,
44024
44034
  failing: n
44025
44035
  });
44026
44036
  return;
44027
44037
  }
44028
44038
  if (!t.ok) {
44029
- let e = `HTTP ${t.status}`;
44039
+ let n = `HTTP ${t.status}`;
44030
44040
  try {
44031
- let n = await t.json();
44032
- n && typeof n == "object" && typeof n.reason == "string" && (e = n.reason);
44041
+ let e = await t.json();
44042
+ e && typeof e == "object" && typeof e.reason == "string" && (n = e.reason);
44033
44043
  } catch {}
44034
- a((n) => ({
44035
- ...n,
44044
+ if (!c) return;
44045
+ let i = [
44046
+ 401,
44047
+ 403,
44048
+ 404
44049
+ ].includes(t.status);
44050
+ i && (o.current = null), a((a) => ({
44051
+ ...i ? {
44052
+ url: e,
44053
+ fetcher: r
44054
+ } : a,
44036
44055
  loading: !1,
44037
- error: e,
44056
+ error: n,
44038
44057
  status: t.status
44039
44058
  }));
44040
44059
  return;
44041
44060
  }
44042
44061
  o.current = t.headers.get("ETag");
44043
- let s = await t.json();
44044
- i && a({
44062
+ let i = await t.json();
44063
+ c && a({
44045
44064
  url: e,
44046
- data: s,
44065
+ fetcher: r,
44066
+ data: i,
44047
44067
  loading: !1,
44048
44068
  status: t.status,
44049
- stale: l,
44069
+ stale: u,
44050
44070
  failing: n
44051
44071
  });
44052
44072
  } catch (e) {
44053
- i && !p.signal.aborted && d < TU ? f = !0 : i && !p.signal.aborted && a((t) => ({
44073
+ c && !m.signal.aborted && f < TU ? p = !0 : c && !m.signal.aborted && a((t) => ({
44054
44074
  ...t,
44055
44075
  loading: !1,
44056
44076
  error: e instanceof Error ? e.message : "Request failed"
44057
44077
  }));
44058
44078
  } finally {
44059
- i && f ? (c = window.setTimeout(m, 1e3 * 2 ** d), d += 1) : i && l && u < wU ? (c = window.setTimeout(m, CU * 1.5 ** u), u += 1) : i && t && (c = window.setTimeout(m, t));
44079
+ c && p ? (l = window.setTimeout(h, 1e3 * 2 ** f), f += 1) : c && u && d < wU ? (l = window.setTimeout(h, CU * 1.5 ** d), d += 1) : c && t && (l = window.setTimeout(h, t));
44060
44080
  }
44061
44081
  };
44062
- return m(), () => {
44063
- i = !1, p.abort(), window.clearTimeout(c);
44082
+ return h(), () => {
44083
+ c = !1, m.abort(), window.clearTimeout(l);
44064
44084
  };
44065
44085
  }, [
44066
44086
  e,
44067
44087
  t,
44068
44088
  r
44069
- ]), n || i.url === e ? i : {
44089
+ ]), i.fetcher === r && (n || i.url === e) ? i : {
44070
44090
  url: e,
44091
+ fetcher: r,
44071
44092
  loading: !!e
44072
44093
  };
44073
44094
  }
44074
44095
  // dist/run/live.js
44075
44096
  function DU(e, t, n) {
44076
- let r = EU(e ?? null, t ? 3e3 : void 0, !1, n), [i, a] = (0, G.useState)(), [o, s] = (0, G.useState)(), c = r.data?.files?.entries ?? [], l = c.find((e) => e.path === i) ?? c[0], u = EU(l && e ? `${e}/file?path=${encodeURIComponent(l.path)}` : null, t ? 3e3 : void 0, !1, n), d = u.data?.file, f = d && l && d.path === l.path && d.sha256 === l.sha256 && d.byteLength === l.byteLength, p = f ? `${l.path}:${l.sha256}` : void 0;
44097
+ let r = EU(e ?? null, t ? 3e3 : void 0, !1, n), [i, a] = (0, G.useState)(), [o, s] = (0, G.useState)(), c = r.error ? [] : r.data?.files?.entries ?? [], l = c.find((e) => e.path === i) ?? c[0], u = EU(l && e ? `${e}/file?path=${encodeURIComponent(l.path)}` : null, t ? 3e3 : void 0, !1, n), d = u.data?.file, f = !r.error && !u.error && d && l && d.path === l.path && d.sha256 === l.sha256 && d.byteLength === l.byteLength, p = f ? `${l.path}:${l.sha256}` : void 0;
44077
44098
  (0, G.useEffect)(() => {
44078
44099
  if (!p || !d) return;
44079
44100
  let e = URL.createObjectURL(new Blob([d.content], { type: "text/plain;charset=utf-8" }));
@@ -44082,7 +44103,11 @@ function DU(e, t, n) {
44082
44103
  href: e
44083
44104
  }), () => URL.revokeObjectURL(e);
44084
44105
  }, [p, d?.content]);
44085
- let m = r.data?.coverage, h = r.status === 404 ? void 0 : m ? /* @__PURE__ */ (0, q.jsxs)("details", {
44106
+ let m = r.data?.coverage, h = r.error ? /* @__PURE__ */ (0, q.jsxs)("p", {
44107
+ className: "ws-status",
44108
+ role: "alert",
44109
+ children: ["Conversation inspection unavailable: ", r.error]
44110
+ }) : m ? /* @__PURE__ */ (0, q.jsxs)("details", {
44086
44111
  className: "ws-status",
44087
44112
  open: m.status !== "complete",
44088
44113
  "data-capture-status": m.status,
@@ -44095,10 +44120,6 @@ function DU(e, t, n) {
44095
44120
  }, `${e.at}:${t}`))] }),
44096
44121
  r.data?.files?.scope === "none" && /* @__PURE__ */ (0, q.jsx)("p", { children: r.data.files.reason ?? "No workspace inventory was captured." })
44097
44122
  ]
44098
- }) : r.error ? /* @__PURE__ */ (0, q.jsxs)("p", {
44099
- className: "ws-status",
44100
- role: "alert",
44101
- children: ["Conversation inspection unavailable: ", r.error]
44102
44123
  }) : void 0;
44103
44124
  return {
44104
44125
  scoreboard: /* @__PURE__ */ (0, q.jsxs)(q.Fragment, { children: [h, r.data?.files && !r.data.files.complete && /* @__PURE__ */ (0, q.jsxs)("p", {
@@ -44141,14 +44162,23 @@ function DU(e, t, n) {
44141
44162
  className: "ws-status",
44142
44163
  children: [
44143
44164
  /* @__PURE__ */ (0, q.jsx)("summary", { children: "Provenance" }),
44144
- /* @__PURE__ */ (0, q.jsx)("code", { children: l.sha256 }),
44165
+ /* @__PURE__ */ (0, q.jsx)("code", {
44166
+ className: "break-all",
44167
+ children: l.sha256
44168
+ }),
44145
44169
  d.before && /* @__PURE__ */ (0, q.jsxs)("p", { children: [
44146
44170
  "Compared with ",
44147
44171
  d.before.source.kind,
44148
44172
  " ",
44149
- /* @__PURE__ */ (0, q.jsx)("code", { children: d.before.source.ref }),
44173
+ /* @__PURE__ */ (0, q.jsx)("code", {
44174
+ className: "break-all",
44175
+ children: d.before.source.ref
44176
+ }),
44150
44177
  ": ",
44151
- /* @__PURE__ */ (0, q.jsx)("code", { children: d.before.sha256 })
44178
+ /* @__PURE__ */ (0, q.jsx)("code", {
44179
+ className: "break-all",
44180
+ children: d.before.sha256
44181
+ })
44152
44182
  ] }),
44153
44183
  /* @__PURE__ */ (0, q.jsx)("p", { children: /* @__PURE__ */ (0, q.jsx)("a", {
44154
44184
  href: o && o.key === p ? o.href : void 0,
@@ -44191,7 +44221,20 @@ var OU = (e) => {
44191
44221
  "needs-you"
44192
44222
  ].includes(MU(e));
44193
44223
  function FU(e) {
44194
- return /* @__PURE__ */ (0, q.jsx)(IU, { ...e }, e.api);
44224
+ let t = (0, G.useRef)({
44225
+ api: e.api,
44226
+ transport: e.transport,
44227
+ fetcher: e.transport?.fetch,
44228
+ opener: e.transport?.openEventSource,
44229
+ revision: 0
44230
+ });
44231
+ return (t.current.api !== e.api || t.current.transport !== e.transport || t.current.fetcher !== e.transport?.fetch || t.current.opener !== e.transport?.openEventSource) && (t.current = {
44232
+ api: e.api,
44233
+ transport: e.transport,
44234
+ fetcher: e.transport?.fetch,
44235
+ opener: e.transport?.openEventSource,
44236
+ revision: t.current.revision + 1
44237
+ }), /* @__PURE__ */ (0, q.jsx)(IU, { ...e }, t.current.revision);
44195
44238
  }
44196
44239
  function IU({ api: e, transport: t }) {
44197
44240
  let [n, r] = (0, G.useState)([]), [i, a] = (0, G.useState)(null), [o, s] = (0, G.useState)(!1), [c, l] = (0, G.useState)(!1), [u, d] = (0, G.useState)(""), [f, p] = (0, G.useState)(0), [m, h] = (0, G.useState)(), [g, _] = (0, G.useState)(!0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox-ui",
3
- "version": "2.0.18",
3
+ "version": "2.0.20",
4
4
  "license": "MIT",
5
5
  "description": "Unified UI component library for Tangle Sandbox — primitives, chat, dashboard, terminal, editor, and workspace components",
6
6
  "repository": {
@@ -99,6 +99,10 @@
99
99
  "import": "./dist/pages.js",
100
100
  "types": "./dist/pages.d.ts"
101
101
  },
102
+ "./hooks/use-document": {
103
+ "import": "./dist/hooks/use-document.js",
104
+ "types": "./dist/hooks/use-document.d.ts"
105
+ },
102
106
  "./hooks": {
103
107
  "import": "./dist/hooks.js",
104
108
  "types": "./dist/hooks.d.ts"