@mcp-b/react-components 0.6.5 → 0.7.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 (91) hide show
  1. package/dist/AgentChat-403mckDG.d.ts +101 -0
  2. package/dist/BrowserLiveView-ZktFZiMD.d.ts +47 -0
  3. package/dist/BrowserReplay-6G-mnwcn.d.ts +40 -0
  4. package/dist/{CodeBlock-BK0sOAbV.js → CodeBlock-D9koxDA7.js} +1 -1
  5. package/dist/{FileTree-BWQZ0FSi.js → FileTree-BdK93Uuu.js} +1 -1
  6. package/dist/ModelSelector-MQvK-pNb.js +306 -0
  7. package/dist/PromptInput-D6-G24p7.d.ts +528 -0
  8. package/dist/ThinkChatActivity-CeHzk6-K.d.ts +73 -0
  9. package/dist/ThinkChatContext-CC94HL4u.d.ts +28 -0
  10. package/dist/ThinkChatToolParts-DnUiZgCC.d.ts +83 -0
  11. package/dist/components/Activity.js +1 -1
  12. package/dist/components/AgentChat.d.ts +1 -103
  13. package/dist/components/AgentChat.js +77 -58
  14. package/dist/components/AgentConnection.d.ts +43 -2
  15. package/dist/components/AgentConnection.js +154 -3
  16. package/dist/components/Artifact.js +1 -1
  17. package/dist/components/BrowserLiveView.d.ts +1 -46
  18. package/dist/components/BrowserLiveView.js +1 -1
  19. package/dist/components/BrowserReplay.d.ts +1 -39
  20. package/dist/components/BrowserReplay.js +1 -1
  21. package/dist/components/ChainOfThought.d.ts +1 -1
  22. package/dist/components/ChainOfThought.js +1 -1
  23. package/dist/components/ChatGptSignInScreen.d.ts +38 -0
  24. package/dist/components/ChatGptSignInScreen.js +201 -0
  25. package/dist/components/CodeBlock.js +1 -1
  26. package/dist/components/Commit.js +1 -1
  27. package/dist/components/Context.d.ts +6 -10
  28. package/dist/components/Context.js +4 -2
  29. package/dist/components/ContextMenu.js +1 -1
  30. package/dist/components/Conversation.d.ts +28 -28
  31. package/dist/components/Conversation.js +36 -55
  32. package/dist/components/Dialog.js +1 -1
  33. package/dist/components/EnvironmentVariables.js +1 -1
  34. package/dist/components/FileTree.js +1 -1
  35. package/dist/components/Marker.d.ts +57 -0
  36. package/dist/components/Marker.js +89 -0
  37. package/dist/components/McpServerPicker.js +1 -1
  38. package/dist/components/Menubar.js +1 -1
  39. package/dist/components/Message.js +1 -1
  40. package/dist/components/MessageScroller.d.ts +52 -0
  41. package/dist/components/MessageScroller.js +62 -0
  42. package/dist/components/ModelSelector.js +1 -305
  43. package/dist/components/NavigationMenu.js +1 -1
  44. package/dist/components/PromptInput.d.ts +2 -534
  45. package/dist/components/PromptInput.js +18 -12
  46. package/dist/components/Queue.js +1 -1
  47. package/dist/components/Reasoning.js +1 -1
  48. package/dist/components/Select.js +1 -1
  49. package/dist/components/Sources.js +1 -1
  50. package/dist/components/Stepper.js +1 -1
  51. package/dist/components/Task.js +1 -1
  52. package/dist/components/Terminal.js +2 -2
  53. package/dist/components/TestResults.js +1 -1
  54. package/dist/components/ThinkChat.d.ts +23 -80
  55. package/dist/components/ThinkChat.js +60 -857
  56. package/dist/components/ThinkChatActivity.d.ts +3 -0
  57. package/dist/components/ThinkChatActivity.js +429 -0
  58. package/dist/components/ThinkChatContext.d.ts +2 -0
  59. package/dist/components/ThinkChatContext.js +10 -0
  60. package/dist/components/ThinkChatToolPanels.d.ts +39 -0
  61. package/dist/components/ThinkChatToolPanels.js +355 -0
  62. package/dist/components/ThinkChatToolParts.d.ts +2 -0
  63. package/dist/components/ThinkChatToolParts.js +66 -0
  64. package/dist/components/ThinkFullApp.d.ts +23 -0
  65. package/dist/components/ThinkFullApp.js +175 -0
  66. package/dist/components/WebPreview.js +1 -1
  67. package/dist/components/WorkspaceExplorer.d.ts +1 -1
  68. package/dist/components/WorkspaceExplorer.js +3 -3
  69. package/dist/components/icons.d.ts +2 -2
  70. package/dist/components/icons.js +2 -2
  71. package/dist/components/useStickToBottom.d.ts +5 -2
  72. package/dist/components/useStickToBottom.js +5 -2
  73. package/dist/{copy-button-CB2MWcau.js → copy-button-TVhDAroI.js} +1 -1
  74. package/dist/{icons-BCNawx-T.js → icons-BAlTbWWP.js} +27 -1
  75. package/dist/{icons-BYpJY6L2.d.ts → icons-BRI54ATJ.d.ts} +2 -1
  76. package/dist/styles/agent-chat.css +15 -3
  77. package/dist/styles/agent-connection.css +33 -4
  78. package/dist/styles/chatgpt-sign-in-screen.css +224 -0
  79. package/dist/styles/code-block.css +6 -4
  80. package/dist/styles/conversation.css +10 -0
  81. package/dist/styles/index.css +4 -0
  82. package/dist/styles/marker.css +95 -0
  83. package/dist/styles/message-scroller.css +113 -0
  84. package/dist/styles/message.css +2 -1
  85. package/dist/styles/prompt-input.css +1 -0
  86. package/dist/styles/scrollbars.css +10 -2
  87. package/dist/styles/streamdown.css +2 -0
  88. package/dist/styles/think-full-app.css +318 -0
  89. package/dist/utils/mcp-server-catalog.d.ts +23 -1
  90. package/dist/utils/mcp-server-catalog.js +27 -1
  91. package/package.json +3 -2
@@ -0,0 +1,355 @@
1
+ import { ActivityOutput, ActivityPanel } from "./Activity.js";
2
+ import { Tab, TabPanel, Tabs, TabsList } from "./Tabs.js";
3
+ import { t as CodeBlock } from "../CodeBlock-D9koxDA7.js";
4
+ import { BrowserLiveView } from "./BrowserLiveView.js";
5
+ import { displayUrl } from "./ThinkChatToolParts.js";
6
+ import * as React from "react";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ import { getToolName } from "ai";
9
+ //#region src/components/ThinkChatToolPanels.tsx
10
+ function renderDeniedPanel(label, reason) {
11
+ return /* @__PURE__ */ jsx(ActivityPanel, {
12
+ label,
13
+ text: reason,
14
+ status: "denied",
15
+ error: true
16
+ });
17
+ }
18
+ function numberLines(content, from = 1) {
19
+ const lines = content.split("\n");
20
+ const width = String(from + lines.length - 1).length;
21
+ return lines.map((line, i) => `${String(from + i).padStart(width)} ${line}`).join("\n");
22
+ }
23
+ function prefixLines(text, prefix) {
24
+ return text.split("\n").map((line) => `${prefix}${line}`).join("\n");
25
+ }
26
+ /** Default panels for the Think workspace tools, Claude Code-style: read/write
27
+ show the file with line numbers, edit shows a mini diff, list/find/grep
28
+ show their result lists, bash gets the shell panel. Everything is typed by
29
+ the upstream tool contract. */
30
+ function ThinkChatWorkspacePanel({ part }) {
31
+ if (part.type === "tool-bash") return /* @__PURE__ */ jsx(ThinkChatShellPanel, { part });
32
+ if (part.state === "output-error") return /* @__PURE__ */ jsx(ActivityPanel, {
33
+ label: getToolName(part),
34
+ text: part.errorText,
35
+ status: "error",
36
+ error: true
37
+ });
38
+ if (part.state === "output-denied") return renderDeniedPanel(getToolName(part), part.approval.reason);
39
+ switch (part.type) {
40
+ case "tool-read": {
41
+ const label = part.input?.path ?? "file";
42
+ const output = part.state === "output-available" ? part.output : void 0;
43
+ if (output && "error" in output) return /* @__PURE__ */ jsx(ActivityPanel, {
44
+ label,
45
+ text: output.error,
46
+ status: "error",
47
+ error: true
48
+ });
49
+ if (output && "content" in output) return /* @__PURE__ */ jsx(ActivityPanel, {
50
+ label,
51
+ text: output.content,
52
+ status: `${output.totalLines} lines`
53
+ });
54
+ if (output) return /* @__PURE__ */ jsx(ActivityPanel, {
55
+ label,
56
+ text: `${output.name} · ${output.mediaType} · ${output.sizeBytes} bytes`
57
+ });
58
+ return /* @__PURE__ */ jsx(ActivityPanel, { label });
59
+ }
60
+ case "tool-write": {
61
+ const output = part.state === "output-available" ? part.output : void 0;
62
+ return /* @__PURE__ */ jsx(ActivityPanel, {
63
+ label: part.input?.path ?? "file",
64
+ text: part.input?.content ? numberLines(part.input.content) : void 0,
65
+ status: output ? `${output.lines} lines written` : void 0
66
+ });
67
+ }
68
+ case "tool-edit": {
69
+ const input = part.input;
70
+ const output = part.state === "output-available" ? part.output : void 0;
71
+ const status = !output ? void 0 : output.error ? output.error : output.created ? "created" : output.fuzzyMatch ? "replaced (fuzzy match)" : "replaced";
72
+ return /* @__PURE__ */ jsx(ActivityPanel, {
73
+ label: input?.path ?? "file",
74
+ status,
75
+ error: Boolean(output?.error),
76
+ children: input?.old_string !== void 0 && input.new_string !== void 0 ? /* @__PURE__ */ jsxs(ActivityOutput, { children: [
77
+ /* @__PURE__ */ jsx("span", {
78
+ className: "activity__diff-del",
79
+ children: prefixLines(input.old_string, "- ")
80
+ }),
81
+ "\n",
82
+ /* @__PURE__ */ jsx("span", {
83
+ className: "activity__diff-add",
84
+ children: prefixLines(input.new_string, "+ ")
85
+ })
86
+ ] }) : null
87
+ });
88
+ }
89
+ case "tool-list": {
90
+ const output = part.state === "output-available" ? part.output : void 0;
91
+ return /* @__PURE__ */ jsx(ActivityPanel, {
92
+ label: part.input?.path ?? "/",
93
+ text: output?.entries.join("\n"),
94
+ status: output ? `${output.count} entries` : void 0
95
+ });
96
+ }
97
+ case "tool-find": {
98
+ const output = part.state === "output-available" ? part.output : void 0;
99
+ const files = Array.isArray(output?.files) ? output.files.map(String) : [];
100
+ const count = typeof output?.count === "number" ? output.count : files.length;
101
+ return /* @__PURE__ */ jsx(ActivityPanel, {
102
+ label: part.input?.pattern ?? "files",
103
+ text: files.join("\n"),
104
+ status: output ? `${count} files${output.truncated ? " (truncated)" : ""}` : void 0
105
+ });
106
+ }
107
+ case "tool-grep": {
108
+ const output = part.state === "output-available" ? part.output : void 0;
109
+ const matches = Array.isArray(output?.matches) ? output.matches.map((m) => typeof m === "string" ? m : m.context ?? JSON.stringify(m)) : [];
110
+ const status = output && typeof output.totalMatches === "number" ? `${output.totalMatches} matches in ${String(output.filesWithMatches)} files` : void 0;
111
+ return /* @__PURE__ */ jsx(ActivityPanel, {
112
+ label: part.input?.query ?? "search",
113
+ text: matches.join("\n"),
114
+ status
115
+ });
116
+ }
117
+ default: return null;
118
+ }
119
+ }
120
+ /** Skill panels show what the model actually received: the activated skill's
121
+ body, the resource text, or the script result. */
122
+ function ThinkChatSkillPanel({ part }) {
123
+ if (part.state === "output-error") return /* @__PURE__ */ jsx(ActivityPanel, {
124
+ label: getToolName(part),
125
+ text: part.errorText,
126
+ status: "error",
127
+ error: true
128
+ });
129
+ if (part.state === "output-denied") return renderDeniedPanel(getToolName(part), part.approval.reason);
130
+ switch (part.type) {
131
+ case "tool-activate_skill": {
132
+ const output = part.state === "output-available" ? part.output : void 0;
133
+ return /* @__PURE__ */ jsx(ActivityPanel, {
134
+ label: part.input?.name ?? "skill",
135
+ text: output
136
+ });
137
+ }
138
+ case "tool-read_skill_resource": {
139
+ const output = part.state === "output-available" ? part.output : void 0;
140
+ return /* @__PURE__ */ jsx(ActivityPanel, {
141
+ label: part.input?.path ?? "resource",
142
+ text: output
143
+ });
144
+ }
145
+ case "tool-run_skill_script": {
146
+ const output = part.state === "output-available" ? part.output : void 0;
147
+ const text = output === void 0 ? void 0 : typeof output === "string" ? output : JSON.stringify(output, null, 2);
148
+ return /* @__PURE__ */ jsx(ActivityPanel, {
149
+ label: part.input?.path ?? "script",
150
+ text
151
+ });
152
+ }
153
+ }
154
+ }
155
+ function ThinkChatFetchPanel({ part }) {
156
+ const label = part.input?.url ?? part.input?.path ?? "fetch";
157
+ if (part.state === "output-error") return /* @__PURE__ */ jsx(ActivityPanel, {
158
+ label,
159
+ text: part.errorText,
160
+ status: "error",
161
+ error: true
162
+ });
163
+ if (part.state === "output-denied") return renderDeniedPanel(label, part.approval.reason);
164
+ const output = part.state === "output-available" ? part.output : void 0;
165
+ if (!output) return /* @__PURE__ */ jsx(ActivityPanel, { label });
166
+ if (!output.ok) return /* @__PURE__ */ jsx(ActivityPanel, {
167
+ label: output.finalUrl ?? label,
168
+ text: output.message,
169
+ status: output.code,
170
+ error: true
171
+ });
172
+ const body = output.body ?? (output.json !== void 0 ? JSON.stringify(output.json, null, 2) : output.path ? `saved to ${output.path}` : "");
173
+ return /* @__PURE__ */ jsx(ActivityPanel, {
174
+ label: output.finalUrl,
175
+ text: body || void 0,
176
+ status: `${output.status} · ${output.bytes} bytes${output.truncated ? " (truncated)" : ""}`
177
+ });
178
+ }
179
+ function findBrowserResultMedia(value, depth = 0) {
180
+ const media = {};
181
+ const visit = (node, level) => {
182
+ if (level > 4 || node === null) return;
183
+ if (typeof node === "string") {
184
+ if (!media.liveViewUrl && node.includes("live.browser.run")) media.liveViewUrl = node;
185
+ else if (!media.screenshot && node.startsWith("data:image/")) media.screenshot = node;
186
+ return;
187
+ }
188
+ if (Array.isArray(node)) {
189
+ for (const item of node) visit(item, level + 1);
190
+ return;
191
+ }
192
+ if (typeof node === "object") {
193
+ const record = node;
194
+ if (media.expiresInMs === void 0 && typeof record.url === "string" && typeof record.expiresInMs === "number") media.expiresInMs = record.expiresInMs;
195
+ for (const item of Object.values(record)) visit(item, level + 1);
196
+ }
197
+ };
198
+ visit(value, depth);
199
+ return media;
200
+ }
201
+ function ExecuteCodeView({ code, output, hideResult }) {
202
+ const sections = [
203
+ output && "logs" in output && output.logs?.length ? output.logs.join("\n") : "",
204
+ output?.status === "error" ? output.error : "",
205
+ output?.status === "paused" ? formatPendingActions(output.pending) : "",
206
+ output?.status === "completed" && output.result !== void 0 && !hideResult ? typeof output.result === "string" ? output.result : JSON.stringify(output.result, null, 2) : ""
207
+ ].filter(Boolean);
208
+ return /* @__PURE__ */ jsxs(Fragment, { children: [code ? /* @__PURE__ */ jsx(CodeBlock, {
209
+ className: "activity__code-block",
210
+ code,
211
+ language: "ts"
212
+ }) : null, sections.length ? /* @__PURE__ */ jsx(ActivityOutput, { children: sections.join("\n\n") }) : null] });
213
+ }
214
+ function formatPendingActions(pending) {
215
+ return pending.map((action) => {
216
+ const args = action.args === void 0 ? "" : JSON.stringify(action.args);
217
+ return `awaiting approval: ${action.connector}.${action.method}(${args})`;
218
+ }).join("\n");
219
+ }
220
+ function executeStatusText(output) {
221
+ if (!output) return void 0;
222
+ return output.status === "paused" ? "paused · needs approval" : output.status;
223
+ }
224
+ /** The codemode execute tool as an activity panel: highlighted TypeScript
225
+ plus logs, result, and the paused pending-approval list. */
226
+ function ThinkChatExecutePanel({ part }) {
227
+ if (part.state === "output-error") return /* @__PURE__ */ jsx(ActivityPanel, {
228
+ label: "Code",
229
+ text: part.errorText,
230
+ status: "error",
231
+ error: true
232
+ });
233
+ if (part.state === "output-denied") return renderDeniedPanel("Code", part.approval.reason);
234
+ const output = part.state === "output-available" ? part.output : void 0;
235
+ return /* @__PURE__ */ jsx(ActivityPanel, {
236
+ label: "Code",
237
+ status: executeStatusText(output),
238
+ error: output?.status === "error",
239
+ children: /* @__PURE__ */ jsx(ExecuteCodeView, {
240
+ code: part.input?.code ?? "",
241
+ output
242
+ })
243
+ });
244
+ }
245
+ function ThinkChatBrowserPanel({ part }) {
246
+ const [seenAt] = React.useState(() => Date.now());
247
+ if (part.state === "output-error") return /* @__PURE__ */ jsx(ActivityPanel, {
248
+ label: "Browser",
249
+ text: part.errorText,
250
+ status: "error",
251
+ error: true
252
+ });
253
+ if (part.state === "output-denied") return renderDeniedPanel("Browser", part.approval.reason);
254
+ if (part.type === "tool-browser_execute") {
255
+ const output = part.state === "output-available" ? part.output : void 0;
256
+ const code = part.input?.code ?? "";
257
+ const media = output?.status === "completed" ? findBrowserResultMedia(output.result) : {};
258
+ const hasMedia = Boolean(media.liveViewUrl || media.screenshot);
259
+ const browserView = media.liveViewUrl ? /* @__PURE__ */ jsx(BrowserLiveView, {
260
+ url: media.liveViewUrl,
261
+ expiresAt: seenAt + (media.expiresInMs ?? 300 * 1e3),
262
+ fallback: media.screenshot ? /* @__PURE__ */ jsx("img", {
263
+ src: media.screenshot,
264
+ alt: "Last browser state"
265
+ }) : void 0
266
+ }) : media.screenshot ? /* @__PURE__ */ jsx("img", {
267
+ className: "activity__browser-screenshot",
268
+ src: media.screenshot,
269
+ alt: "Browser screenshot"
270
+ }) : null;
271
+ const codeView = /* @__PURE__ */ jsx(ExecuteCodeView, {
272
+ code,
273
+ output,
274
+ hideResult: hasMedia
275
+ });
276
+ return /* @__PURE__ */ jsx(ActivityPanel, {
277
+ label: "Browser",
278
+ status: executeStatusText(output),
279
+ error: output?.status === "error",
280
+ children: browserView && code ? /* @__PURE__ */ jsxs(Tabs, {
281
+ className: "activity__browser-tabs",
282
+ defaultValue: "browser",
283
+ children: [
284
+ /* @__PURE__ */ jsxs(TabsList, {
285
+ variant: "line",
286
+ children: [/* @__PURE__ */ jsx(Tab, {
287
+ value: "browser",
288
+ children: "Preview"
289
+ }), /* @__PURE__ */ jsx(Tab, {
290
+ value: "code",
291
+ children: "Code"
292
+ })]
293
+ }),
294
+ /* @__PURE__ */ jsx(TabPanel, {
295
+ value: "browser",
296
+ children: browserView
297
+ }),
298
+ /* @__PURE__ */ jsx(TabPanel, {
299
+ value: "code",
300
+ children: codeView
301
+ })
302
+ ]
303
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [browserView, codeView] })
304
+ });
305
+ }
306
+ const output = part.state === "output-available" ? part.output : void 0;
307
+ return /* @__PURE__ */ jsx(ActivityPanel, {
308
+ label: displayUrl(part.input?.url) || "page",
309
+ text: output === void 0 ? void 0 : typeof output === "string" ? output : Array.isArray(output) ? output.map((item) => typeof item === "string" ? item : JSON.stringify(item)).join("\n") : JSON.stringify(output, null, 2),
310
+ status: part.type === "tool-browser_links" && Array.isArray(output) ? `${output.length} links` : void 0
311
+ });
312
+ }
313
+ function ThinkChatShellPanel({ part }) {
314
+ const output = part.state === "output-available" ? part.output : void 0;
315
+ const errorText = part.state === "output-error" ? part.errorText : "";
316
+ const deniedReason = part.state === "output-denied" ? part.approval.reason ?? "denied" : "";
317
+ const failed = Boolean(errorText) || Boolean(deniedReason) || output !== void 0 && (output.exitCode !== 0 || Boolean(output.errors?.length));
318
+ return /* @__PURE__ */ jsx(ActivityPanel, {
319
+ label: "Shell",
320
+ text: formatBashPanelText(part.input, output, errorText || deniedReason),
321
+ status: output !== void 0 || errorText || deniedReason ? getBashStatusText(output, errorText, deniedReason) : void 0,
322
+ error: failed
323
+ });
324
+ }
325
+ function formatBashPanelText(input, output, errorText) {
326
+ return [
327
+ input?.script?.trim() ? `$ bash\n${input.script}` : "",
328
+ output?.stdout,
329
+ output?.stderr,
330
+ errorText,
331
+ output?.skippedFiles?.length ? ["skipped files", ...output.skippedFiles].join("\n") : "",
332
+ output?.errors?.length ? ["sync errors", ...output.errors].join("\n") : "",
333
+ output ? formatChangedFiles(output.changedFiles) : ""
334
+ ].filter(Boolean).join("\n\n");
335
+ }
336
+ function formatChangedFiles(changedFiles) {
337
+ if (!changedFiles) return "";
338
+ const lines = [
339
+ ...changedFiles.created.map((path) => `created ${path}`),
340
+ ...changedFiles.updated.map((path) => `updated ${path}`),
341
+ ...changedFiles.deleted.map((path) => `deleted ${path}`),
342
+ ...changedFiles.directoriesCreated.map((path) => `created directory ${path}`),
343
+ ...changedFiles.directoriesDeleted.map((path) => `deleted directory ${path}`)
344
+ ];
345
+ return lines.length ? ["workspace changes", ...lines].join("\n") : "";
346
+ }
347
+ function getBashStatusText(output, errorText, deniedReason) {
348
+ if (errorText) return "error";
349
+ if (deniedReason) return "denied";
350
+ if (output?.errors?.length) return "sync errors";
351
+ if (output && output.exitCode !== 0) return `exit ${output.exitCode}`;
352
+ return "success";
353
+ }
354
+ //#endregion
355
+ export { ThinkChatBrowserPanel, ThinkChatExecutePanel, ThinkChatFetchPanel, ThinkChatSkillPanel, ThinkChatWorkspacePanel };
@@ -0,0 +1,2 @@
1
+ import { _ as isThinkChatActivityPart, a as ThinkBashToolOutput, c as ThinkWorkspaceToolName, d as isBrowserToolPart, f as isExecuteToolPart, g as isSkillToolPart, h as isPartWorking, i as SkillToolPart, l as WorkspaceToolPart, m as isPartFailed, n as ExecuteToolPart, o as ThinkBashToolPart, p as isFetchToolPart, r as FetchToolPart, s as ThinkChatPart, t as BrowserToolPart, u as displayUrl, v as isWorkspaceToolPart } from "../ThinkChatToolParts-DnUiZgCC.js";
2
+ export { BrowserToolPart, ExecuteToolPart, FetchToolPart, SkillToolPart, ThinkBashToolOutput, ThinkBashToolPart, ThinkChatPart, ThinkWorkspaceToolName, WorkspaceToolPart, displayUrl, isBrowserToolPart, isExecuteToolPart, isFetchToolPart, isPartFailed, isPartWorking, isSkillToolPart, isThinkChatActivityPart, isWorkspaceToolPart };
@@ -0,0 +1,66 @@
1
+ import { getStaticToolName, getToolName, isReasoningUIPart, isStaticToolUIPart, isToolUIPart } from "ai";
2
+ import { getToolPartState } from "@cloudflare/think/react";
3
+ //#region src/components/ThinkChatToolParts.ts
4
+ const WORKSPACE_TOOL_NAMES = new Set([
5
+ "read",
6
+ "write",
7
+ "edit",
8
+ "list",
9
+ "find",
10
+ "grep",
11
+ "delete",
12
+ "bash"
13
+ ]);
14
+ function isWorkspaceToolPart(part) {
15
+ return isStaticToolUIPart(part) && WORKSPACE_TOOL_NAMES.has(getStaticToolName(part));
16
+ }
17
+ const SKILL_TOOL_NAMES = new Set([
18
+ "activate_skill",
19
+ "read_skill_resource",
20
+ "run_skill_script"
21
+ ]);
22
+ function isSkillToolPart(part) {
23
+ return isStaticToolUIPart(part) && SKILL_TOOL_NAMES.has(getStaticToolName(part));
24
+ }
25
+ function isFetchToolPart(part) {
26
+ return isStaticToolUIPart(part) && getStaticToolName(part).startsWith("fetch_");
27
+ }
28
+ const BROWSER_TOOL_NAMES = new Set([
29
+ "browser_execute",
30
+ "browser_markdown",
31
+ "browser_extract",
32
+ "browser_links",
33
+ "browser_scrape",
34
+ "browser_content"
35
+ ]);
36
+ function isBrowserToolPart(part) {
37
+ return isStaticToolUIPart(part) && BROWSER_TOOL_NAMES.has(getStaticToolName(part));
38
+ }
39
+ function isExecuteToolPart(part) {
40
+ return isStaticToolUIPart(part) && getStaticToolName(part) === "execute";
41
+ }
42
+ /** Agent work (reasoning, tool calls, step boundaries) vs. content shown to the user. */
43
+ function isThinkChatActivityPart(part, excludeTools) {
44
+ if (part === void 0) return false;
45
+ if (isToolUIPart(part) && excludeTools?.has(getToolName(part))) return false;
46
+ return part.type === "step-start" || isReasoningUIPart(part) || isToolUIPart(part);
47
+ }
48
+ /** In-flight: the stream opened this part but hasn't delivered its result yet. */
49
+ function isPartWorking(part) {
50
+ if (isReasoningUIPart(part)) return part.state === "streaming";
51
+ if (isToolUIPart(part)) {
52
+ const state = getToolPartState(part);
53
+ return state === "loading" || state === "streaming" || state === "waiting-approval";
54
+ }
55
+ return false;
56
+ }
57
+ /** Errored or denied — upstream's simplified tool-part state vocabulary. */
58
+ function isPartFailed(part) {
59
+ const state = getToolPartState(part);
60
+ return state === "error" || state === "denied";
61
+ }
62
+ function displayUrl(url) {
63
+ return url ? url.replace(/^https?:\/\//, "") : "";
64
+ }
65
+ //#endregion
66
+ export { displayUrl, isBrowserToolPart, isExecuteToolPart, isFetchToolPart, isPartFailed, isPartWorking, isSkillToolPart, isThinkChatActivityPart, isWorkspaceToolPart };
@@ -0,0 +1,23 @@
1
+ import { WorkspaceSource } from "./WorkspaceExplorer.js";
2
+ import { ThinkApprovalStub, ThinkChatMessagesProps, ThinkChatProviderProps } from "./ThinkChat.js";
3
+ import * as React from "react";
4
+
5
+ //#region src/components/ThinkFullApp.d.ts
6
+ interface ThinkFullAppProps extends React.HTMLAttributes<HTMLDivElement> {
7
+ /** ThinkChat state and actions used by the chat surface. */
8
+ chat: ThinkChatProviderProps["chat"];
9
+ /** Optional Think agent stub used to resolve pending approval state. */
10
+ agentStub?: ThinkApprovalStub;
11
+ /** Optional workspace source shown in the file explorer pane. */
12
+ workspace?: WorkspaceSource;
13
+ /** Root path passed to the workspace explorer. */
14
+ workspaceRoot?: string;
15
+ /** Message rendering labels and approval overrides for ThinkChat. */
16
+ messages?: ThinkChatMessagesProps;
17
+ }
18
+ /** Combines ThinkChat with an optional resizable workspace file explorer shell. */
19
+ declare function ThinkFullApp(props: ThinkFullAppProps & {
20
+ ref?: React.Ref<HTMLDivElement>;
21
+ }): React.JSX.Element;
22
+ //#endregion
23
+ export { ThinkFullApp, ThinkFullAppProps };
@@ -0,0 +1,175 @@
1
+ import { t as cx } from "../class-names-9UtZwb0J.js";
2
+ import { h as FileIcon, n as ArrowLeftIcon } from "../icons-BAlTbWWP.js";
3
+ import { Button } from "./Button.js";
4
+ import { WorkspaceExplorer, useWorkspace } from "./WorkspaceExplorer.js";
5
+ import { ThinkChat, useThinkPendingApprovals } from "./ThinkChat.js";
6
+ import * as React from "react";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ //#region src/components/ThinkFullApp.tsx
9
+ const filesPanelDefaultWidth = 340;
10
+ const filesPanelMinWidth = 300;
11
+ const filesPanelMaxWidth = 600;
12
+ const filesPanelKeyboardStep = 24;
13
+ function clampFilesPanelWidth(width) {
14
+ return Math.min(filesPanelMaxWidth, Math.max(filesPanelMinWidth, width));
15
+ }
16
+ function beginFilesPanelResize(event, current, apply) {
17
+ event.preventDefault();
18
+ const startX = event.clientX;
19
+ const onMove = (move) => {
20
+ apply(clampFilesPanelWidth(current - (move.clientX - startX)));
21
+ };
22
+ const onUp = () => {
23
+ window.removeEventListener("pointermove", onMove);
24
+ window.removeEventListener("pointerup", onUp);
25
+ document.body.classList.remove("is-resizing-columns");
26
+ };
27
+ document.body.classList.add("is-resizing-columns");
28
+ window.addEventListener("pointermove", onMove);
29
+ window.addEventListener("pointerup", onUp);
30
+ }
31
+ function WorkspacePanel({ onBack, source, root }) {
32
+ return /* @__PURE__ */ jsx(WorkspaceExplorer, {
33
+ className: "think-full-app__workbench",
34
+ workspace: useWorkspace({
35
+ source,
36
+ root
37
+ }),
38
+ title: onBack ? /* @__PURE__ */ jsxs("span", {
39
+ className: "think-full-app__workspace-title",
40
+ children: [/* @__PURE__ */ jsx(Button, {
41
+ type: "button",
42
+ variant: "ghost",
43
+ color: "neutral",
44
+ size: "icon-sm",
45
+ className: "think-full-app__workspace-back",
46
+ "aria-label": "Show chat",
47
+ onClick: onBack,
48
+ children: /* @__PURE__ */ jsx(ArrowLeftIcon, {})
49
+ }), /* @__PURE__ */ jsx("span", { children: "Workspace" })]
50
+ }) : void 0
51
+ });
52
+ }
53
+ /** Combines ThinkChat with an optional resizable workspace file explorer shell. */
54
+ function ThinkFullApp(props) {
55
+ if (!props.agentStub) return /* @__PURE__ */ jsx(ThinkFullAppLayout, { ...props });
56
+ return /* @__PURE__ */ jsx(ThinkFullAppWithApprovals, {
57
+ ...props,
58
+ agentStub: props.agentStub
59
+ });
60
+ }
61
+ function ThinkFullAppWithApprovals({ agentStub, chat, messages, ...props }) {
62
+ const approvals = useThinkPendingApprovals(agentStub, `${chat.messages.length}:${chat.status}`);
63
+ const resolvedMessages = React.useMemo(() => ({
64
+ ...messages,
65
+ executionApprovals: messages?.executionApprovals ?? approvals.executionApprovals,
66
+ pendingApprovals: messages?.pendingApprovals ?? approvals.pendingApprovals
67
+ }), [
68
+ approvals.executionApprovals,
69
+ approvals.pendingApprovals,
70
+ messages
71
+ ]);
72
+ return /* @__PURE__ */ jsx(ThinkFullAppLayout, {
73
+ ...props,
74
+ chat,
75
+ messages: resolvedMessages
76
+ });
77
+ }
78
+ function ThinkFullAppLayout({ chat, className, messages, ref, style, workspace, workspaceRoot, ...props }) {
79
+ const hasWorkspace = workspace !== void 0;
80
+ const [mobileView, setMobileView] = React.useState("chat");
81
+ const [filesPanelWidth, setFilesPanelWidth] = React.useState(filesPanelDefaultWidth);
82
+ const activeMobileView = hasWorkspace && mobileView === "files" ? "files" : "chat";
83
+ const isMobileFilesView = activeMobileView === "files";
84
+ const rootStyle = {
85
+ ...style,
86
+ "--think-full-app-files-w": `${filesPanelWidth}px`
87
+ };
88
+ const resizeFilesPanelBy = (delta) => {
89
+ setFilesPanelWidth((current) => clampFilesPanelWidth(current + delta));
90
+ };
91
+ return /* @__PURE__ */ jsxs("div", {
92
+ ref,
93
+ className: cx("think-full-app", className),
94
+ "data-has-files": hasWorkspace ? "true" : "false",
95
+ "data-mobile-view": activeMobileView,
96
+ style: rootStyle,
97
+ ...props,
98
+ children: [
99
+ hasWorkspace && !isMobileFilesView ? /* @__PURE__ */ jsx("header", {
100
+ className: "think-full-app__mobile-header",
101
+ children: /* @__PURE__ */ jsx(Button, {
102
+ type: "button",
103
+ variant: "ghost",
104
+ color: "neutral",
105
+ size: "icon-sm",
106
+ className: "think-full-app__mobile-action",
107
+ "aria-label": "Show files",
108
+ onClick: () => setMobileView("files"),
109
+ children: /* @__PURE__ */ jsx(FileIcon, {})
110
+ })
111
+ }) : null,
112
+ /* @__PURE__ */ jsx("section", {
113
+ className: "think-full-app__chat-surface",
114
+ "aria-label": "Chat",
115
+ children: /* @__PURE__ */ jsx("div", {
116
+ className: "think-full-app__chat",
117
+ children: /* @__PURE__ */ jsxs("div", {
118
+ className: "think-full-app__chat-inner",
119
+ children: [/* @__PURE__ */ jsx(ThinkChat.Provider, {
120
+ chat,
121
+ children: /* @__PURE__ */ jsx(ThinkChat.Messages, { ...messages })
122
+ }), chat.error ? /* @__PURE__ */ jsxs("div", {
123
+ className: "think-full-app__error",
124
+ role: "alert",
125
+ children: [chat.error.message, /* @__PURE__ */ jsx("button", {
126
+ type: "button",
127
+ onClick: () => chat.clearError(),
128
+ children: "Dismiss"
129
+ })]
130
+ }) : null]
131
+ })
132
+ })
133
+ }),
134
+ workspace ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("button", {
135
+ type: "button",
136
+ role: "separator",
137
+ "aria-label": "Resize file panel",
138
+ "aria-orientation": "vertical",
139
+ "aria-valuemin": filesPanelMinWidth,
140
+ "aria-valuemax": filesPanelMaxWidth,
141
+ "aria-valuenow": filesPanelWidth,
142
+ className: "think-full-app__resizer",
143
+ onPointerDown: (event) => beginFilesPanelResize(event, filesPanelWidth, setFilesPanelWidth),
144
+ onKeyDown: (event) => {
145
+ if (event.key === "ArrowLeft") {
146
+ event.preventDefault();
147
+ resizeFilesPanelBy(filesPanelKeyboardStep);
148
+ } else if (event.key === "ArrowRight") {
149
+ event.preventDefault();
150
+ resizeFilesPanelBy(-24);
151
+ } else if (event.key === "Home") {
152
+ event.preventDefault();
153
+ setFilesPanelWidth(filesPanelMinWidth);
154
+ } else if (event.key === "End") {
155
+ event.preventDefault();
156
+ setFilesPanelWidth(filesPanelMaxWidth);
157
+ }
158
+ }
159
+ }), /* @__PURE__ */ jsx("aside", {
160
+ className: "think-full-app__aside",
161
+ "aria-label": "File explorer",
162
+ children: /* @__PURE__ */ jsx("div", {
163
+ className: "think-full-app__files-slot",
164
+ children: /* @__PURE__ */ jsx(WorkspacePanel, {
165
+ source: workspace,
166
+ root: workspaceRoot,
167
+ onBack: () => setMobileView("chat")
168
+ })
169
+ })
170
+ })] }) : null
171
+ ]
172
+ });
173
+ }
174
+ //#endregion
175
+ export { ThinkFullApp };
@@ -1,5 +1,5 @@
1
1
  import { t as cx } from "../class-names-9UtZwb0J.js";
2
- import { O as RefreshIcon, n as ArrowLeftIcon, o as ChevronDownIcon, r as ArrowRightIcon } from "../icons-BCNawx-T.js";
2
+ import { k as RefreshIcon, n as ArrowLeftIcon, o as ChevronDownIcon, r as ArrowRightIcon } from "../icons-BAlTbWWP.js";
3
3
  import { Button } from "./Button.js";
4
4
  import { Tooltip, TooltipPopup, TooltipPortal, TooltipPositioner, TooltipTrigger } from "./Tooltip.js";
5
5
  import { Badge } from "./Badge.js";
@@ -1,7 +1,7 @@
1
1
  import { A as CodeBlockLanguage } from "../CodeBlock-CxQXv3C4.js";
2
2
  import * as React from "react";
3
- import { FileInfo, Workspace } from "@cloudflare/shell";
4
3
  import { WorkspaceLike } from "@cloudflare/think/tools/workspace";
4
+ import { FileInfo, Workspace } from "@cloudflare/shell";
5
5
 
6
6
  //#region src/components/WorkspaceExplorer.d.ts
7
7
  /** Workspace summary, as returned by `Workspace.getWorkspaceInfo()` upstream. */
@@ -1,8 +1,8 @@
1
1
  import { t as cx } from "../class-names-9UtZwb0J.js";
2
- import { O as RefreshIcon, k as SearchIcon, m as FileIcon, n as ArrowLeftIcon } from "../icons-BCNawx-T.js";
2
+ import { A as SearchIcon, h as FileIcon, k as RefreshIcon, n as ArrowLeftIcon } from "../icons-BAlTbWWP.js";
3
3
  import { Button } from "./Button.js";
4
- import { a as CodeBlockCopyButton, i as CodeBlockContent, n as CodeBlockActions, o as CodeBlockFilename, p as CodeBlockTitle, r as CodeBlockContainer, s as CodeBlockHeader, t as CodeBlock } from "../CodeBlock-BK0sOAbV.js";
5
- import { i as FileTreeFolder, r as FileTreeFile, t as FileTree } from "../FileTree-BWQZ0FSi.js";
4
+ import { a as CodeBlockCopyButton, i as CodeBlockContent, n as CodeBlockActions, o as CodeBlockFilename, p as CodeBlockTitle, r as CodeBlockContainer, s as CodeBlockHeader, t as CodeBlock } from "../CodeBlock-D9koxDA7.js";
5
+ import { i as FileTreeFolder, r as FileTreeFile, t as FileTree } from "../FileTree-BdK93Uuu.js";
6
6
  import * as React from "react";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
  //#region src/components/WorkspaceExplorer.tsx
@@ -1,2 +1,2 @@
1
- import { A as SearchIcon, C as MonitorIcon, D as PlayIcon, E as PencilIcon, F as WrenchIcon, I as XIcon, M as SquareIcon, N as TerminalIcon, O as PlusIcon, P as WarningIcon, S as MinusIcon, T as PauseIcon, _ as IconProps, a as CheckIcon, b as LinkIcon, c as ChevronRightIcon, d as DownloadIcon, f as EyeIcon, g as FolderOpenIcon, h as FolderIcon, i as ArrowUpIcon, j as SpinnerIcon, k as RefreshIcon, l as CopyIcon, m as FileIcon, n as ArrowLeftIcon, o as ChevronDownIcon, p as EyeOffIcon, r as ArrowRightIcon, s as ChevronLeftIcon, t as ArrowDownIcon, u as DotIcon, v as ImageIcon, w as PaperclipIcon, x as MaximizeIcon, y as InfoIcon } from "../icons-BYpJY6L2.js";
2
- export { ArrowDownIcon, ArrowLeftIcon, ArrowRightIcon, ArrowUpIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, CopyIcon, DotIcon, DownloadIcon, EyeIcon, EyeOffIcon, FileIcon, FolderIcon, FolderOpenIcon, IconProps, ImageIcon, InfoIcon, LinkIcon, MaximizeIcon, MinusIcon, MonitorIcon, PaperclipIcon, PauseIcon, PencilIcon, PlayIcon, PlusIcon, RefreshIcon, SearchIcon, SpinnerIcon, SquareIcon, TerminalIcon, WarningIcon, WrenchIcon, XIcon };
1
+ import { A as RefreshIcon, C as MinusIcon, D as PencilIcon, E as PauseIcon, F as WarningIcon, I as WrenchIcon, L as XIcon, M as SpinnerIcon, N as SquareIcon, O as PlayIcon, P as TerminalIcon, S as MaximizeIcon, T as PaperclipIcon, _ as FolderOpenIcon, a as CheckIcon, b as InfoIcon, c as ChevronRightIcon, d as DownloadIcon, f as EllipsisIcon, g as FolderIcon, h as FileIcon, i as ArrowUpIcon, j as SearchIcon, k as PlusIcon, l as CopyIcon, m as EyeOffIcon, n as ArrowLeftIcon, o as ChevronDownIcon, p as EyeIcon, r as ArrowRightIcon, s as ChevronLeftIcon, t as ArrowDownIcon, u as DotIcon, v as IconProps, w as MonitorIcon, x as LinkIcon, y as ImageIcon } from "../icons-BRI54ATJ.js";
2
+ export { ArrowDownIcon, ArrowLeftIcon, ArrowRightIcon, ArrowUpIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, CopyIcon, DotIcon, DownloadIcon, EllipsisIcon, EyeIcon, EyeOffIcon, FileIcon, FolderIcon, FolderOpenIcon, IconProps, ImageIcon, InfoIcon, LinkIcon, MaximizeIcon, MinusIcon, MonitorIcon, PaperclipIcon, PauseIcon, PencilIcon, PlayIcon, PlusIcon, RefreshIcon, SearchIcon, SpinnerIcon, SquareIcon, TerminalIcon, WarningIcon, WrenchIcon, XIcon };