@tangle-network/ui 11.10.0 → 11.11.1

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 (132) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +4 -1
  3. package/dist/active-sessions-store-Gt1R0rFG.js +262 -0
  4. package/dist/{active-sessions-store-CeOmXgv5.d.ts → active-sessions-store-nl70ZnMC.d.ts} +40 -41
  5. package/dist/artifact-pane-BL_DFWNl.d.ts +32 -0
  6. package/dist/artifact-pane-DMXT9a8U.js +70 -0
  7. package/dist/auth-DOETfnd9.js +154 -0
  8. package/dist/auth.d.ts +2 -74
  9. package/dist/auth.js +2 -16
  10. package/dist/branding-26d5ARIr.d.ts +14 -0
  11. package/dist/button-C87nEe2R.js +78 -0
  12. package/dist/button-yoIv77e2.d.ts +16 -0
  13. package/dist/chat-D4jAfEmj.js +667 -0
  14. package/dist/chat.d.ts +2 -201
  15. package/dist/chat.js +2 -31
  16. package/dist/code-block-B36KVUSN.js +165 -0
  17. package/dist/code-block-B9miUPht.d.ts +23 -0
  18. package/dist/diff-preview-BcK3nRXb.js +533 -0
  19. package/dist/document-editor-pane-BcoABlhn.d.ts +131 -0
  20. package/dist/document-editor-pane-BxlPjaTP.js +1287 -0
  21. package/dist/dropdown-menu-BpcLa5vF.js +101 -0
  22. package/dist/editor.d.ts +76 -78
  23. package/dist/editor.js +2 -34
  24. package/dist/file-format-BgXbr-Ib.js +160 -0
  25. package/dist/files-Bug33qCl.js +743 -0
  26. package/dist/files.d.ts +2 -243
  27. package/dist/files.js +3 -41
  28. package/dist/focus-BcE_SHqz.js +57 -0
  29. package/dist/format-DfcLWqMa.js +54 -0
  30. package/dist/hooks.d.ts +30 -37
  31. package/dist/hooks.js +111 -46
  32. package/dist/index-2UntyjBb.d.ts +52 -0
  33. package/dist/index-BgUHilZm.d.ts +108 -0
  34. package/dist/index-COgqsFAQ.d.ts +42 -0
  35. package/dist/index-CPDET_s1.d.ts +549 -0
  36. package/dist/index-CUhfHT_V.d.ts +204 -0
  37. package/dist/index-Cg6gYAqh.d.ts +73 -0
  38. package/dist/index-Cq-EJzqW.d.ts +16 -0
  39. package/dist/index-DhYmSaLF.d.ts +245 -0
  40. package/dist/index-DjKxO357.d.ts +128 -0
  41. package/dist/index.d.ts +26 -43
  42. package/dist/index.js +35 -472
  43. package/dist/markdown-BGqicV82.js +45 -0
  44. package/dist/markdown.d.ts +3 -18
  45. package/dist/markdown.js +3 -15
  46. package/dist/message-vhUI0c5G.d.ts +16 -0
  47. package/dist/nav.d.ts +6 -8
  48. package/dist/nav.js +29 -11
  49. package/dist/openui-artifact-renderer-D3E5bIAI.d.ts +114 -0
  50. package/dist/openui-artifact-renderer-DrU1AdVk.js +266 -0
  51. package/dist/openui.d.ts +2 -115
  52. package/dist/openui.js +2 -13
  53. package/dist/parts-5mhy9yJ3.d.ts +37 -0
  54. package/dist/primitives-Cb8GGVKr.js +1239 -0
  55. package/dist/primitives.d.ts +5 -525
  56. package/dist/primitives.js +9 -212
  57. package/dist/redaction-CGGB2ENG.js +74 -0
  58. package/dist/redaction.d.ts +2 -42
  59. package/dist/redaction.js +2 -7
  60. package/dist/run-OyWmIDqu.d.ts +41 -0
  61. package/dist/run-ZsIKPA6J.js +17 -0
  62. package/dist/run-group-BACLbCFl.js +410 -0
  63. package/dist/run.d.ts +3 -126
  64. package/dist/run.js +5 -40
  65. package/dist/sdk-hooks.d.ts +2 -285
  66. package/dist/sdk-hooks.js +3 -36
  67. package/dist/stores.d.ts +13 -14
  68. package/dist/stores.js +34 -76
  69. package/dist/table-Bss73DhB.js +146 -0
  70. package/dist/tabs-BVHR6NkO.js +40 -0
  71. package/dist/text-shimmer-BUUo6I-g.js +64 -0
  72. package/dist/tool-call-feed-BeB1_4pX.d.ts +47 -0
  73. package/dist/tool-call-feed-Djt2q11V.js +109 -0
  74. package/dist/tool-call-step-DNebqhmX.js +434 -0
  75. package/dist/tool-display-BAuAVa43.js +158 -0
  76. package/dist/{tool-display-z4JcDmMQ.d.ts → tool-display-DgmL5rIU.d.ts} +16 -16
  77. package/dist/tool-previews.d.ts +2 -48
  78. package/dist/tool-previews.js +2 -23
  79. package/dist/types.d.ts +6 -19
  80. package/dist/types.js +0 -1
  81. package/dist/use-auto-scroll-C5Pjeqon.js +153 -0
  82. package/dist/use-sse-stream-BVgO1QBN.js +884 -0
  83. package/dist/use-sse-stream-Dm6R5YWz.d.ts +282 -0
  84. package/dist/utils-Bl_CZ0Qp.js +37 -0
  85. package/dist/{chunk-RQHJBTEU.js → utils-C_uf36nf.js} +4 -6
  86. package/dist/utils.d.ts +2 -104
  87. package/dist/utils.js +6 -44
  88. package/package.json +39 -41
  89. package/src/lib/focus.ts +2 -1
  90. package/dist/artifact-pane-DpuWcAiF.d.ts +0 -33
  91. package/dist/button-CMQuQEW_.d.ts +0 -17
  92. package/dist/chunk-34A66VBG.js +0 -214
  93. package/dist/chunk-3OI2QKFD.js +0 -0
  94. package/dist/chunk-3XXBZL53.js +0 -174
  95. package/dist/chunk-42PAH5D2.js +0 -112
  96. package/dist/chunk-4CLN43XT.js +0 -45
  97. package/dist/chunk-55WHV7SS.js +0 -1604
  98. package/dist/chunk-565EATZZ.js +0 -156
  99. package/dist/chunk-5Z5ZYMOJ.js +0 -0
  100. package/dist/chunk-6BGQA4BQ.js +0 -0
  101. package/dist/chunk-BEBXZPHW.js +0 -299
  102. package/dist/chunk-C5WF4WMV.js +0 -734
  103. package/dist/chunk-HFL6R6IF.js +0 -37
  104. package/dist/chunk-HGML45QH.js +0 -104
  105. package/dist/chunk-HMAPIH7L.js +0 -595
  106. package/dist/chunk-K5XFRUS4.js +0 -1401
  107. package/dist/chunk-KFQGHD73.js +0 -198
  108. package/dist/chunk-L57WRIND.js +0 -59
  109. package/dist/chunk-LTEKI7YJ.js +0 -59
  110. package/dist/chunk-M3QZK62R.js +0 -233
  111. package/dist/chunk-ND3ZFXQK.js +0 -179
  112. package/dist/chunk-OEX7NZE3.js +0 -321
  113. package/dist/chunk-OL5GYLHV.js +0 -60
  114. package/dist/chunk-QGFYBNSO.js +0 -133
  115. package/dist/chunk-R7B3UWPF.js +0 -550
  116. package/dist/chunk-R7SUY4E3.js +0 -65
  117. package/dist/chunk-REJESC5U.js +0 -117
  118. package/dist/chunk-RQGKSCEZ.js +0 -0
  119. package/dist/chunk-SNLR2AEA.js +0 -40
  120. package/dist/chunk-WKWBTL2V.js +0 -15
  121. package/dist/chunk-X7CU776B.js +0 -1048
  122. package/dist/chunk-XU3HB5QL.js +0 -127
  123. package/dist/chunk-YTO5V6QS.js +0 -19
  124. package/dist/chunk-YU4E5J2N.js +0 -437
  125. package/dist/chunk-YZ6AK25N.js +0 -886
  126. package/dist/code-block-0kSpWMnf.d.ts +0 -25
  127. package/dist/document-editor-pane-IAEQn_Dl.d.ts +0 -128
  128. package/dist/document-editor-pane-QHDOBA43.js +0 -13
  129. package/dist/message-BHWbxBtT.d.ts +0 -15
  130. package/dist/parts-dj7AcUg0.d.ts +0 -36
  131. package/dist/run-PfLmDAox.d.ts +0 -41
  132. package/dist/tool-call-feed-D9iofJgW.d.ts +0 -46
@@ -0,0 +1,64 @@
1
+ import { t as cn } from "./utils-C_uf36nf.js";
2
+ import { useEffect, useLayoutEffect } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/primitives/text-shimmer.tsx
5
+ const CLASS_NAME = "tangle-text-shimmer";
6
+ const STYLE_ID = "tangle-text-shimmer-styles";
7
+ /**
8
+ * The sweep is a MASK over the text's own colour, not a gradient background
9
+ * clipped to the glyphs: if this stylesheet is missing the text still renders
10
+ * in its normal colour instead of disappearing (`color: transparent`).
11
+ *
12
+ * Mask geometry mirrors the background variant: a 250%-wide tile whose bright
13
+ * band sits at 45–60%, slid from 150% to -50% so one band crosses the text per
14
+ * cycle. The tile repeats, so the .72 floor covers every glyph at every frame —
15
+ * the label reads at ~72% foreground opacity with a brighter sweep through it.
16
+ */
17
+ const SHIMMER_CSS = `
18
+ @keyframes ${CLASS_NAME} {
19
+ from { -webkit-mask-position: 150% center; mask-position: 150% center; }
20
+ to { -webkit-mask-position: -50% center; mask-position: -50% center; }
21
+ }
22
+ .${CLASS_NAME} {
23
+ -webkit-mask-image: linear-gradient(90deg, rgba(0,0,0,0.72) 0%, #000 45%, rgba(0,0,0,0.72) 60%);
24
+ mask-image: linear-gradient(90deg, rgba(0,0,0,0.72) 0%, #000 45%, rgba(0,0,0,0.72) 60%);
25
+ -webkit-mask-size: 250% 100%;
26
+ mask-size: 250% 100%;
27
+ animation: ${CLASS_NAME} 1.4s linear infinite;
28
+ }
29
+ @media (prefers-reduced-motion: reduce) {
30
+ .${CLASS_NAME} {
31
+ animation: none;
32
+ -webkit-mask-image: none;
33
+ mask-image: none;
34
+ text-decoration: underline dotted currentColor;
35
+ text-underline-offset: 3px;
36
+ }
37
+ }
38
+ `;
39
+ /** Inject the shimmer stylesheet once per document. A no-op on the server. */
40
+ function ensureShimmerStyles() {
41
+ if (typeof document === "undefined") return;
42
+ if (document.getElementById(STYLE_ID)) return;
43
+ const style = document.createElement("style");
44
+ style.id = STYLE_ID;
45
+ style.textContent = SHIMMER_CSS;
46
+ document.head.appendChild(style);
47
+ }
48
+ const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
49
+ /**
50
+ * Inline text with a gradient-mask sweep — the in-flight signal for a run row
51
+ * label ("Thinking…", a tool verb while its call is running). Carries the
52
+ * styles it needs, so a consumer that only scans this package for Tailwind
53
+ * classes still gets the animation.
54
+ */
55
+ function TextShimmer({ children, className, durationMs = 1400 }) {
56
+ useIsomorphicLayoutEffect(ensureShimmerStyles, []);
57
+ return /* @__PURE__ */ jsx("span", {
58
+ className: cn(CLASS_NAME, "text-foreground", className),
59
+ style: { animationDuration: `${durationMs}ms` },
60
+ children
61
+ });
62
+ }
63
+ //#endregion
64
+ export { TextShimmer as t };
@@ -0,0 +1,47 @@
1
+ import { ReactNode } from "react";
2
+ //#region src/run/tool-call-step.d.ts
3
+ type ToolCallType = "bash" | "read" | "write" | "edit" | "glob" | "grep" | "list" | "download" | "inspect" | "audit" | "unknown";
4
+ type ToolCallStatus = "running" | "success" | "error";
5
+ //#endregion
6
+ //#region src/run/tool-call-feed.d.ts
7
+ interface ToolCallData {
8
+ id: string;
9
+ type: ToolCallType;
10
+ label: string;
11
+ status: ToolCallStatus;
12
+ detail?: string;
13
+ output?: string;
14
+ duration?: number;
15
+ }
16
+ type FeedSegment = {
17
+ kind: "text";
18
+ content: string;
19
+ } | {
20
+ kind: "tool_call";
21
+ call: ToolCallData;
22
+ } | {
23
+ kind: "tool_group";
24
+ title?: string;
25
+ calls: ToolCallData[];
26
+ };
27
+ interface ToolCallFeedProps {
28
+ segments: FeedSegment[];
29
+ className?: string;
30
+ }
31
+ /**
32
+ * Renders a feed of interleaved text and tool calls.
33
+ */
34
+ declare function ToolCallFeed({ segments, className }: ToolCallFeedProps): import("react").JSX.Element | null;
35
+ /**
36
+ * Parse raw SSE tool events into FeedSegments.
37
+ *
38
+ * This is the bridge between the orchestrator's SSE stream format
39
+ * and the ToolCallFeed component. Consumers call this in their
40
+ * useToolCallStream hook.
41
+ */
42
+ declare function parseToolEvent(event: {
43
+ type: string;
44
+ data: Record<string, unknown>;
45
+ }): ToolCallData | null;
46
+ //#endregion
47
+ export { parseToolEvent as a, ToolCallFeedProps as i, ToolCallData as n, ToolCallStatus as o, ToolCallFeed as r, ToolCallType as s, FeedSegment as t };
@@ -0,0 +1,109 @@
1
+ import { t as cn } from "./utils-C_uf36nf.js";
2
+ import { n as ToolCallStep, t as ToolCallGroup } from "./tool-call-step-DNebqhmX.js";
3
+ import { t as Markdown } from "./markdown-BGqicV82.js";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/run/tool-call-feed.tsx
6
+ /**
7
+ * Renders a feed of interleaved text and tool calls.
8
+ */
9
+ function ToolCallFeed({ segments, className }) {
10
+ if (segments.length === 0) return null;
11
+ return /* @__PURE__ */ jsx("div", {
12
+ className: cn("space-y-1", className),
13
+ children: segments.map((segment, i) => {
14
+ if (segment.kind === "text") return segment.content.trim() ? /* @__PURE__ */ jsx(Markdown, { children: segment.content }, i) : null;
15
+ if (segment.kind === "tool_call") return /* @__PURE__ */ jsx(ToolCallStep, {
16
+ type: segment.call.type,
17
+ label: segment.call.label,
18
+ status: segment.call.status,
19
+ detail: segment.call.detail,
20
+ output: segment.call.output,
21
+ duration: segment.call.duration
22
+ }, segment.call.id || i);
23
+ if (segment.kind === "tool_group") return /* @__PURE__ */ jsx(ToolCallGroup, {
24
+ title: segment.title,
25
+ children: segment.calls.map((call) => /* @__PURE__ */ jsx(ToolCallStep, {
26
+ type: call.type,
27
+ label: call.label,
28
+ status: call.status,
29
+ detail: call.detail,
30
+ output: call.output,
31
+ duration: call.duration
32
+ }, call.id))
33
+ }, i);
34
+ return null;
35
+ })
36
+ });
37
+ }
38
+ /**
39
+ * Parse raw SSE tool events into FeedSegments.
40
+ *
41
+ * This is the bridge between the orchestrator's SSE stream format
42
+ * and the ToolCallFeed component. Consumers call this in their
43
+ * useToolCallStream hook.
44
+ */
45
+ function parseToolEvent(event) {
46
+ const { type, data } = event;
47
+ if (type === "tool.invocation" || type === "tool_use") {
48
+ const toolName = data.name || data.tool || "unknown";
49
+ const input = data.input;
50
+ return {
51
+ id: data.id || data.toolUseId || createId(),
52
+ type: mapToolName(toolName),
53
+ label: formatToolLabel(toolName, input),
54
+ status: "running",
55
+ detail: input ? formatToolInput(toolName, input) : void 0
56
+ };
57
+ }
58
+ if (type === "tool.result" || type === "tool_result") return {
59
+ id: data.id || data.toolUseId || "",
60
+ type: mapToolName(data.name || data.tool || "unknown"),
61
+ label: formatToolLabel(data.name || data.tool || "unknown"),
62
+ status: data.error ? "error" : "success",
63
+ output: truncate(data.output || data.result || "", 500),
64
+ duration: data.duration
65
+ };
66
+ return null;
67
+ }
68
+ function createId() {
69
+ if (typeof globalThis.crypto !== "undefined" && typeof globalThis.crypto.randomUUID === "function") try {
70
+ return globalThis.crypto.randomUUID();
71
+ } catch {}
72
+ return `tool_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
73
+ }
74
+ function mapToolName(name) {
75
+ const lower = name.toLowerCase();
76
+ if (lower.includes("bash") || lower.includes("terminal") || lower.includes("exec")) return "bash";
77
+ if (lower.includes("read") || lower.includes("cat")) return "read";
78
+ if (lower.includes("write") || lower.includes("create")) return "write";
79
+ if (lower.includes("edit") || lower.includes("replace")) return "edit";
80
+ if (lower.includes("glob") || lower.includes("find")) return "glob";
81
+ if (lower.includes("grep") || lower.includes("search")) return "grep";
82
+ if (lower.includes("list") || lower.includes("ls")) return "list";
83
+ if (lower.includes("inspect")) return "inspect";
84
+ if (lower.includes("audit")) return "audit";
85
+ return "unknown";
86
+ }
87
+ function formatToolLabel(toolName, input) {
88
+ const lower = toolName.toLowerCase();
89
+ if (lower.includes("bash") && input?.command) {
90
+ const cmd = String(input.command);
91
+ return cmd.length > 80 ? `${cmd.slice(0, 77)}...` : cmd;
92
+ }
93
+ if ((lower.includes("read") || lower.includes("cat")) && input?.path) return `Read ${input.path}`;
94
+ if (lower.includes("write") && input?.path) return `Write ${input.path}`;
95
+ if (lower.includes("edit") && input?.path) return `Edit ${input.path}`;
96
+ if (lower.includes("glob") && input?.pattern) return `Find ${input.pattern}`;
97
+ if (lower.includes("grep") && input?.pattern) return `Search for ${input.pattern}`;
98
+ return toolName;
99
+ }
100
+ function formatToolInput(toolName, input) {
101
+ if (input.command) return String(input.command);
102
+ if (input.path) return String(input.path);
103
+ return JSON.stringify(input, null, 2).slice(0, 300);
104
+ }
105
+ function truncate(text, max) {
106
+ return text.length > max ? text.slice(0, max - 3) + "..." : text;
107
+ }
108
+ //#endregion
109
+ export { parseToolEvent as n, ToolCallFeed as t };
@@ -0,0 +1,434 @@
1
+ import { t as cn } from "./utils-C_uf36nf.js";
2
+ import { t as TextShimmer } from "./text-shimmer-BUUo6I-g.js";
3
+ import { t as CodeBlock } from "./code-block-B36KVUSN.js";
4
+ import { i as getToolErrorText, n as getToolCategory, r as getToolDisplayMetadata } from "./tool-display-BAuAVa43.js";
5
+ import { n as formatDuration } from "./format-DfcLWqMa.js";
6
+ import { a as GrepResultsPreview, i as GlobResultsPreview, n as QuestionPreview, o as WriteFilePreview, r as WebSearchPreview, s as CommandPreview, t as DiffPreview } from "./diff-preview-BcK3nRXb.js";
7
+ import { memo, useEffect, useRef, useState } from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ import { AlertCircle, ArrowLeft, ArrowRight, Bot, ChevronRight, ClipboardList, FileEdit, FileSearch, FileText, Globe, Loader2, PencilLine, Search, Settings, Terminal } from "lucide-react";
10
+ import * as Collapsible from "@radix-ui/react-collapsible";
11
+ //#region src/run/expandable-content.tsx
12
+ /**
13
+ * Clamps tall content to a fixed height with a bottom fade and a
14
+ * "Show more / Show less" toggle. Content shorter than the cap renders
15
+ * as-is with no toggle.
16
+ */
17
+ function ExpandableContent({ children, collapsedMaxPx = 180, fadeClassName = "from-muted", className }) {
18
+ const [expanded, setExpanded] = useState(false);
19
+ const [overflowing, setOverflowing] = useState(false);
20
+ const contentRef = useRef(null);
21
+ useEffect(() => {
22
+ const el = contentRef.current;
23
+ if (!el) return;
24
+ const measure = () => setOverflowing(el.scrollHeight > collapsedMaxPx + 4);
25
+ measure();
26
+ if (typeof ResizeObserver === "undefined") return;
27
+ const observer = new ResizeObserver(measure);
28
+ observer.observe(el);
29
+ return () => observer.disconnect();
30
+ }, [collapsedMaxPx]);
31
+ const clamped = overflowing && !expanded;
32
+ return /* @__PURE__ */ jsxs("div", {
33
+ className,
34
+ children: [/* @__PURE__ */ jsxs("div", {
35
+ ref: contentRef,
36
+ className: "relative overflow-hidden",
37
+ style: clamped ? { maxHeight: collapsedMaxPx } : void 0,
38
+ children: [children, clamped ? /* @__PURE__ */ jsx("div", { className: cn("pointer-events-none absolute inset-x-0 bottom-0 h-10 bg-gradient-to-t to-transparent", fadeClassName) }) : null]
39
+ }), overflowing ? /* @__PURE__ */ jsx("button", {
40
+ type: "button",
41
+ onClick: () => setExpanded((value) => !value),
42
+ className: "mt-1 text-[11px] font-medium text-muted-foreground transition-colors hover:text-foreground",
43
+ children: expanded ? "Show less" : "Show more"
44
+ }) : null]
45
+ });
46
+ }
47
+ //#endregion
48
+ //#region src/run/expanded-tool-detail.tsx
49
+ const EXT_LANG = {
50
+ ts: "typescript",
51
+ tsx: "tsx",
52
+ js: "javascript",
53
+ jsx: "jsx",
54
+ rs: "rust",
55
+ py: "python",
56
+ go: "go",
57
+ rb: "ruby",
58
+ json: "json",
59
+ yaml: "yaml",
60
+ yml: "yaml",
61
+ toml: "toml",
62
+ md: "markdown",
63
+ css: "css",
64
+ scss: "scss",
65
+ html: "html",
66
+ sh: "bash",
67
+ bash: "bash",
68
+ zsh: "bash",
69
+ sql: "sql",
70
+ sol: "solidity",
71
+ proto: "protobuf"
72
+ };
73
+ function langFromPath(path) {
74
+ if (!path) return void 0;
75
+ const ext = path.split(".").pop()?.toLowerCase();
76
+ return ext ? EXT_LANG[ext] : void 0;
77
+ }
78
+ /** Format an unknown value as a displayable string. */
79
+ function formatOutput(value) {
80
+ if (value == null) return "";
81
+ if (typeof value === "string") return value;
82
+ try {
83
+ return JSON.stringify(value, null, 2);
84
+ } catch {
85
+ return String(value);
86
+ }
87
+ }
88
+ /**
89
+ * Renders full tool details when a tool item is expanded.
90
+ * Dispatches to specialised previews (CommandPreview, WriteFilePreview)
91
+ * or falls back to a generic input/output code view.
92
+ */
93
+ const ExpandedToolDetail = memo(({ part }) => {
94
+ const meta = getToolDisplayMetadata(part);
95
+ const { status, input, output, error } = part.state;
96
+ if (meta.displayVariant === "command") return /* @__PURE__ */ jsx(CommandPreview, { part });
97
+ if (meta.displayVariant === "write-file") return /* @__PURE__ */ jsx(WriteFilePreview, { part });
98
+ if (meta.displayVariant === "grep") return /* @__PURE__ */ jsx(GrepResultsPreview, { part });
99
+ if (meta.displayVariant === "glob") return /* @__PURE__ */ jsx(GlobResultsPreview, { part });
100
+ if (meta.displayVariant === "web-search") return /* @__PURE__ */ jsx(WebSearchPreview, { part });
101
+ if (meta.displayVariant === "question") return /* @__PURE__ */ jsx(QuestionPreview, { part });
102
+ if (meta.displayVariant === "diff") return /* @__PURE__ */ jsx(DiffPreview, { part });
103
+ if (meta.displayVariant === "read-file") return /* @__PURE__ */ jsxs("div", {
104
+ className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card shadow-[var(--shadow-card)]",
105
+ children: [/* @__PURE__ */ jsxs("div", {
106
+ className: "flex items-center gap-2.5 border-b border-border bg-card px-3 py-2",
107
+ children: [/* @__PURE__ */ jsx("div", {
108
+ className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-[var(--radius-sm)] border border-[var(--border-accent)] bg-muted text-primary",
109
+ children: /* @__PURE__ */ jsx(FileText, { className: "h-3.5 w-3.5" })
110
+ }), /* @__PURE__ */ jsxs("div", {
111
+ className: "min-w-0 flex items-center gap-2",
112
+ children: [/* @__PURE__ */ jsx("span", {
113
+ className: "text-xs font-semibold text-foreground",
114
+ children: "Read file"
115
+ }), meta.targetPath ? /* @__PURE__ */ jsx("span", {
116
+ className: "truncate text-xs font-mono text-muted-foreground",
117
+ children: meta.targetPath
118
+ }) : null]
119
+ })]
120
+ }), /* @__PURE__ */ jsxs("div", {
121
+ className: "space-y-2 px-3 py-2.5",
122
+ children: [typeof output === "string" ? /* @__PURE__ */ jsx(CodeBlock, {
123
+ code: output,
124
+ language: langFromPath(meta.targetPath) ?? "text",
125
+ className: "rounded-[var(--radius-md)]"
126
+ }) : /* @__PURE__ */ jsx("div", {
127
+ className: "rounded-[var(--radius-md)] border border-dashed border-border bg-muted px-3 py-4 text-sm text-muted-foreground",
128
+ children: "No readable file content was returned."
129
+ }), error ? /* @__PURE__ */ jsx("div", {
130
+ className: "rounded-[var(--radius-md)] border border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] px-3 py-3 text-sm text-[var(--surface-danger-text)]",
131
+ children: error
132
+ }) : null]
133
+ })]
134
+ });
135
+ const inputStr = formatOutput(input);
136
+ const outputStr = formatOutput(output);
137
+ return /* @__PURE__ */ jsxs("div", {
138
+ className: "space-y-3",
139
+ children: [
140
+ inputStr && /* @__PURE__ */ jsxs("div", {
141
+ className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card",
142
+ children: [/* @__PURE__ */ jsxs("div", {
143
+ className: "flex items-center gap-2 border-b border-border bg-background px-3 py-2",
144
+ children: [/* @__PURE__ */ jsx(ArrowRight, { className: "h-3 w-3 text-primary" }), /* @__PURE__ */ jsx("span", {
145
+ className: "text-xs font-medium uppercase tracking-[0.08em] text-muted-foreground",
146
+ children: "Input"
147
+ })]
148
+ }), /* @__PURE__ */ jsx(CodeBlock, {
149
+ code: inputStr,
150
+ language: "json",
151
+ className: "rounded-none border-0"
152
+ })]
153
+ }),
154
+ status === "completed" && outputStr && /* @__PURE__ */ jsxs("div", {
155
+ className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card",
156
+ children: [/* @__PURE__ */ jsxs("div", {
157
+ className: "flex items-center gap-2 border-b border-border bg-background px-3 py-2",
158
+ children: [/* @__PURE__ */ jsx(ArrowLeft, { className: "h-3 w-3 text-primary" }), /* @__PURE__ */ jsx("span", {
159
+ className: "text-xs font-medium uppercase tracking-[0.08em] text-muted-foreground",
160
+ children: "Output"
161
+ })]
162
+ }), /* @__PURE__ */ jsx(ExpandableContent, {
163
+ fadeClassName: "from-card",
164
+ children: /* @__PURE__ */ jsx(CodeBlock, {
165
+ code: outputStr.length > 2e3 ? outputStr.slice(0, 2e3) + "\n...(truncated)" : outputStr,
166
+ language: "json",
167
+ className: "rounded-none border-0"
168
+ })
169
+ })]
170
+ }),
171
+ error && /* @__PURE__ */ jsxs("div", {
172
+ className: "overflow-hidden rounded-[var(--radius-lg)] border border-[var(--surface-danger-border)]",
173
+ children: [/* @__PURE__ */ jsxs("div", {
174
+ className: "flex items-center gap-2 border-b border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] px-3 py-2",
175
+ children: [/* @__PURE__ */ jsx(AlertCircle, { className: "h-3 w-3 text-[var(--surface-danger-text)]" }), /* @__PURE__ */ jsx("span", {
176
+ className: "text-xs font-medium uppercase tracking-[0.08em] text-[var(--surface-danger-text)]",
177
+ children: "Error"
178
+ })]
179
+ }), /* @__PURE__ */ jsx(ExpandableContent, {
180
+ fadeClassName: "from-[var(--surface-danger-bg)]",
181
+ children: /* @__PURE__ */ jsx("pre", {
182
+ className: "bg-[var(--surface-danger-bg)] p-3 text-xs font-mono whitespace-pre-wrap break-all text-[var(--surface-danger-text)]",
183
+ children: error
184
+ })
185
+ })]
186
+ }),
187
+ (status === "pending" || status === "running") && /* @__PURE__ */ jsxs("div", {
188
+ className: "flex items-center gap-2 rounded-[var(--radius-md)] border border-border bg-muted px-3 py-3 text-xs text-muted-foreground",
189
+ children: [/* @__PURE__ */ jsx(Loader2, { className: cn("h-3 w-3 animate-spin text-primary") }), "Running…"]
190
+ })
191
+ ]
192
+ });
193
+ });
194
+ ExpandedToolDetail.displayName = "ExpandedToolDetail";
195
+ //#endregion
196
+ //#region src/run/run-row-shell.tsx
197
+ /**
198
+ * Trailing status indicator shared by every run row. Only `error` draws a
199
+ * mark (a red dot). Success is silence, and a running row carries its state in
200
+ * the title — a `TextShimmer` sweep — so neither renders anything here.
201
+ */
202
+ function RunRowStatusDot({ status }) {
203
+ if (status !== "error") return null;
204
+ return /* @__PURE__ */ jsx("span", {
205
+ "data-run-row-status": "error",
206
+ className: "h-1.5 w-1.5 shrink-0 rounded-full bg-[var(--surface-danger-text)]"
207
+ });
208
+ }
209
+ const SHAPE_CLASS = {
210
+ single: "rounded-[var(--radius-lg)]",
211
+ first: "rounded-t-[var(--radius-lg)] rounded-b-[var(--radius-sm)]",
212
+ middle: "rounded-[var(--radius-sm)]",
213
+ last: "rounded-t-[var(--radius-sm)] rounded-b-[var(--radius-lg)]"
214
+ };
215
+ const HEADER_INSET = "px-2 py-1";
216
+ const ERROR_INDENT = "pl-[2.375rem]";
217
+ /**
218
+ * Shared shell for the agent activity rows (reasoning + tool). A quiet
219
+ * one-liner at rest — bare glyph, muted title and description, no fill, no
220
+ * border — that becomes a bordered card only while open. The border is always
221
+ * present (transparent at rest) so hover and expand never shift layout.
222
+ * Both row kinds render through it so they read as one family.
223
+ */
224
+ function RunRowShell({ icon, title, description, descriptionMono = false, status = "idle", durationMs, groupPosition = "single", collapsedError, actions, open: openProp, onOpenChange, defaultOpen = false, className, contentClassName, children }) {
225
+ const [openState, setOpenState] = useState(defaultOpen);
226
+ const isControlled = openProp !== void 0;
227
+ const open = isControlled ? openProp : openState;
228
+ const setOpen = (next) => {
229
+ if (!isControlled) setOpenState(next);
230
+ onOpenChange?.(next);
231
+ };
232
+ const isRunning = status === "running";
233
+ const expandable = children != null;
234
+ return /* @__PURE__ */ jsx(Collapsible.Root, {
235
+ open,
236
+ onOpenChange: setOpen,
237
+ children: /* @__PURE__ */ jsxs("div", {
238
+ className: "flex items-start gap-2",
239
+ children: [/* @__PURE__ */ jsxs("div", {
240
+ "data-run-row": "",
241
+ "data-state": open ? "open" : "closed",
242
+ className: cn("group min-w-0 flex-1 overflow-hidden border transition-colors", open ? "border-border bg-[var(--md3-surface-container)]" : "border-transparent bg-transparent", expandable && !open && "hover:bg-[var(--md3-surface-container)]", SHAPE_CLASS[groupPosition], className),
243
+ children: [
244
+ /* @__PURE__ */ jsx(Collapsible.Trigger, {
245
+ asChild: true,
246
+ disabled: !expandable,
247
+ children: /* @__PURE__ */ jsxs("button", {
248
+ type: "button",
249
+ className: cn("flex w-full items-center gap-2 text-left", HEADER_INSET, expandable ? "cursor-pointer" : "cursor-default"),
250
+ children: [
251
+ /* @__PURE__ */ jsxs("span", {
252
+ "aria-hidden": true,
253
+ className: "flex h-[1.375rem] w-[1.375rem] shrink-0 items-center justify-center text-muted-foreground",
254
+ children: [/* @__PURE__ */ jsx("span", {
255
+ "data-run-row-glyph": "",
256
+ className: cn("flex items-center justify-center", expandable && "group-hover:hidden", open && "hidden"),
257
+ children: icon
258
+ }), expandable ? /* @__PURE__ */ jsx(ChevronRight, {
259
+ "data-run-row-chevron": "",
260
+ className: cn("hidden h-3.5 w-3.5 transition-transform group-hover:block", open && "block rotate-90")
261
+ }) : null]
262
+ }),
263
+ /* @__PURE__ */ jsx("span", {
264
+ className: cn("shrink-0 whitespace-nowrap text-sm font-normal text-muted-foreground transition-colors group-hover:text-foreground", open && "text-foreground"),
265
+ children: title
266
+ }),
267
+ description ? /* @__PURE__ */ jsx("span", {
268
+ className: cn("hidden min-w-0 flex-1 truncate text-sm text-muted-foreground transition-colors group-hover:text-foreground sm:inline", descriptionMono && "font-mono"),
269
+ children: description
270
+ }) : null,
271
+ /* @__PURE__ */ jsxs("span", {
272
+ className: "ml-auto flex shrink-0 items-center gap-1.5",
273
+ children: [!isRunning && durationMs != null ? /* @__PURE__ */ jsx("span", {
274
+ "data-run-row-duration": "",
275
+ className: "font-mono text-[10px] tabular-nums text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100",
276
+ children: formatDuration(durationMs)
277
+ }) : null, /* @__PURE__ */ jsx(RunRowStatusDot, { status })]
278
+ })
279
+ ]
280
+ })
281
+ }),
282
+ collapsedError && !open ? /* @__PURE__ */ jsx("div", {
283
+ className: cn("pb-1.5 pr-2 text-xs leading-snug text-[var(--surface-danger-text)]", ERROR_INDENT),
284
+ children: collapsedError
285
+ }) : null,
286
+ expandable ? /* @__PURE__ */ jsx(Collapsible.Content, {
287
+ className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp",
288
+ children: /* @__PURE__ */ jsx("div", {
289
+ className: cn("border-t border-border", contentClassName),
290
+ children
291
+ })
292
+ }) : null
293
+ ]
294
+ }), actions ? /* @__PURE__ */ jsx("div", {
295
+ className: "flex shrink-0 flex-wrap items-center justify-end gap-1.5 pt-1",
296
+ onClick: (event) => event.stopPropagation(),
297
+ children: actions
298
+ }) : null]
299
+ })
300
+ });
301
+ }
302
+ //#endregion
303
+ //#region src/run/inline-tool-item.tsx
304
+ /** Map tool category to a lucide-react icon component. */
305
+ const TOOL_CATEGORY_ICON_MAP = {
306
+ command: Terminal,
307
+ write: FileEdit,
308
+ read: FileSearch,
309
+ search: Search,
310
+ edit: PencilLine,
311
+ task: Bot,
312
+ web: Globe,
313
+ todo: ClipboardList,
314
+ other: Settings
315
+ };
316
+ /** Map the tool part status onto the shared row status vocabulary. */
317
+ function toRowStatus(status) {
318
+ if (status === "pending" || status === "running") return "running";
319
+ if (status === "error") return "error";
320
+ return "success";
321
+ }
322
+ /**
323
+ * Compact single-line tool call display: a category glyph, the tool verb, and
324
+ * the path or command it acted on. While the call runs the verb shimmers;
325
+ * once it completes the row goes quiet (duration on hover, a red dot only on
326
+ * error). Expands on click to show ExpandedToolDetail. Rendered through the
327
+ * shared RunRowShell so it stays consistent with the reasoning row.
328
+ */
329
+ const InlineToolItem = memo(({ part, renderToolDetail, groupPosition = "single", className, contentClassName, actions, title: titleOverride, description: descriptionOverride }) => {
330
+ const meta = getToolDisplayMetadata(part);
331
+ const title = titleOverride ?? meta.title;
332
+ const description = descriptionOverride ?? meta.description;
333
+ const errorText = getToolErrorText(part);
334
+ const startTime = part.state.time?.start;
335
+ const endTime = part.state.time?.end;
336
+ const durationMs = startTime != null && endTime != null ? endTime - startTime : void 0;
337
+ const category = getToolCategory(part.tool);
338
+ const DefaultIcon = TOOL_CATEGORY_ICON_MAP[category] ?? Settings;
339
+ const status = toRowStatus(part.state.status);
340
+ return /* @__PURE__ */ jsx(RunRowShell, {
341
+ icon: /* @__PURE__ */ jsx(DefaultIcon, { className: "h-3.5 w-3.5" }),
342
+ title: status === "running" ? /* @__PURE__ */ jsx(TextShimmer, { children: title }) : title,
343
+ description,
344
+ descriptionMono: true,
345
+ status,
346
+ durationMs,
347
+ groupPosition,
348
+ collapsedError: errorText ?? void 0,
349
+ actions,
350
+ className,
351
+ contentClassName: cn("p-2", contentClassName),
352
+ children: renderToolDetail?.(part) ?? /* @__PURE__ */ jsx(ExpandedToolDetail, { part })
353
+ });
354
+ });
355
+ InlineToolItem.displayName = "InlineToolItem";
356
+ //#endregion
357
+ //#region src/run/tool-call-step.tsx
358
+ const EXT_LANGUAGE = {
359
+ ts: "typescript",
360
+ tsx: "typescript",
361
+ js: "javascript",
362
+ jsx: "javascript",
363
+ mjs: "javascript",
364
+ cjs: "javascript",
365
+ css: "css",
366
+ scss: "scss",
367
+ json: "json",
368
+ jsonc: "json",
369
+ md: "markdown",
370
+ mdx: "markdown",
371
+ py: "python",
372
+ sh: "bash",
373
+ bash: "bash",
374
+ zsh: "bash",
375
+ html: "html",
376
+ htm: "html",
377
+ yaml: "yaml",
378
+ yml: "yaml",
379
+ toml: "toml",
380
+ rs: "rust",
381
+ go: "go",
382
+ sql: "sql",
383
+ xml: "xml"
384
+ };
385
+ function inferLanguage(detail, language) {
386
+ if (language) return language;
387
+ if (!detail) return void 0;
388
+ const ext = detail.split(".").pop()?.toLowerCase();
389
+ return ext ? EXT_LANGUAGE[ext] : void 0;
390
+ }
391
+ const STATUS_MAP = {
392
+ running: "running",
393
+ success: "completed",
394
+ error: "error"
395
+ };
396
+ function ToolCallStep({ type, label, status, detail, output, language, duration, className, actions, part }) {
397
+ const resolvedPart = part ?? {
398
+ type: "tool",
399
+ id: `${type}:${label}`,
400
+ tool: type,
401
+ state: {
402
+ status: STATUS_MAP[status],
403
+ input: detail ? { detail } : void 0,
404
+ output,
405
+ time: duration != null ? {
406
+ start: 0,
407
+ end: duration
408
+ } : void 0
409
+ }
410
+ };
411
+ const lang = inferLanguage(detail, language);
412
+ return /* @__PURE__ */ jsx(InlineToolItem, {
413
+ part: resolvedPart,
414
+ title: label,
415
+ description: detail,
416
+ className,
417
+ actions,
418
+ renderToolDetail: part ? void 0 : output ? () => /* @__PURE__ */ jsx(CodeBlock, {
419
+ code: output,
420
+ language: lang,
421
+ className: "max-h-72 overflow-auto text-xs"
422
+ }) : () => null
423
+ });
424
+ }
425
+ function ToolCallGroup({ title, children, className }) {
426
+ return /* @__PURE__ */ jsx("div", {
427
+ role: "group",
428
+ "aria-label": title,
429
+ className: cn("flex flex-col gap-1", className),
430
+ children
431
+ });
432
+ }
433
+ //#endregion
434
+ export { RunRowStatusDot as a, RunRowShell as i, ToolCallStep as n, ExpandedToolDetail as o, InlineToolItem as r, ExpandableContent as s, ToolCallGroup as t };