@tutti-os/agent-gui 0.0.4 → 0.0.5

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 (50) hide show
  1. package/dist/agent-message-center/index.js +3 -2
  2. package/dist/agent-message-center/index.js.map +1 -1
  3. package/dist/app/renderer/agentactivity.css +7 -0
  4. package/dist/app/renderer/assets/icons/arrow-left-filled.svg +1 -0
  5. package/dist/{chunk-RORLLV27.js → chunk-3735XYFZ.js} +2 -40
  6. package/dist/chunk-3735XYFZ.js.map +1 -0
  7. package/dist/{chunk-IVPB4MLI.js → chunk-6AZ2KF6R.js} +1 -1
  8. package/dist/chunk-6AZ2KF6R.js.map +1 -0
  9. package/dist/{chunk-UKQIGNN3.js → chunk-7ICAFTA2.js} +2 -2
  10. package/dist/{chunk-HSR5DI6O.js → chunk-BHCCGKOP.js} +3 -1
  11. package/dist/chunk-BHCCGKOP.js.map +1 -0
  12. package/dist/{chunk-ZX5PDYAS.js → chunk-C63Z2JWT.js} +8 -10
  13. package/dist/chunk-C63Z2JWT.js.map +1 -0
  14. package/dist/chunk-F55LU7IJ.js +3470 -0
  15. package/dist/chunk-F55LU7IJ.js.map +1 -0
  16. package/dist/{chunk-ZP7P7DYO.js → chunk-GEXHKJK5.js} +6 -47
  17. package/dist/chunk-GEXHKJK5.js.map +1 -0
  18. package/dist/{chunk-UJWUGMWC.js → chunk-GYG57VTA.js} +17 -32
  19. package/dist/{chunk-UJWUGMWC.js.map → chunk-GYG57VTA.js.map} +1 -1
  20. package/dist/{chunk-BABBC24I.js → chunk-LUGELG5V.js} +4 -1
  21. package/dist/chunk-LUGELG5V.js.map +1 -0
  22. package/dist/chunk-ZU3FKYMG.js +47 -0
  23. package/dist/chunk-ZU3FKYMG.js.map +1 -0
  24. package/dist/i18n/index.d.ts +2 -0
  25. package/dist/i18n/index.js +1 -1
  26. package/dist/index.d.ts +2 -11
  27. package/dist/index.js +120 -28
  28. package/dist/index.js.map +1 -1
  29. package/dist/mention-file-presentation.d.ts +2 -1
  30. package/dist/mention-file-presentation.js +1 -1
  31. package/dist/workbench/contribution.js +6 -5
  32. package/dist/workbench/index.d.ts +1 -1
  33. package/dist/workbench/index.js +6 -5
  34. package/dist/workbench/launch.d.ts +1 -7
  35. package/dist/workbench/launch.js +2 -2
  36. package/dist/workbench/state.js +1 -1
  37. package/dist/workbench/types.d.ts +1 -12
  38. package/dist/workbench/types.js +1 -1
  39. package/dist/workspace-agent-generated-files.js +2 -2
  40. package/package.json +10 -10
  41. package/dist/chunk-5Q36BEUM.js +0 -3478
  42. package/dist/chunk-5Q36BEUM.js.map +0 -1
  43. package/dist/chunk-BABBC24I.js.map +0 -1
  44. package/dist/chunk-HSR5DI6O.js.map +0 -1
  45. package/dist/chunk-IVPB4MLI.js.map +0 -1
  46. package/dist/chunk-RORLLV27.js.map +0 -1
  47. package/dist/chunk-ZP7P7DYO.js.map +0 -1
  48. package/dist/chunk-ZX5PDYAS.js.map +0 -1
  49. package/dist/user-avatar-placeholder-WP2373TS.png +0 -0
  50. /package/dist/{chunk-UKQIGNN3.js.map → chunk-7ICAFTA2.js.map} +0 -0
@@ -1,3478 +0,0 @@
1
- import {
2
- translate,
3
- useTranslation
4
- } from "./chunk-HSR5DI6O.js";
5
- import {
6
- resolveAgentWorkspaceFileVisualKind
7
- } from "./chunk-PJP5BUU6.js";
8
-
9
- // agentActivityRuntime.tsx
10
- import {
11
- createContext,
12
- useContext,
13
- useSyncExternalStore
14
- } from "react";
15
- import { jsx } from "react/jsx-runtime";
16
- var AgentActivityRuntimeContext = createContext(
17
- null
18
- );
19
- var currentAgentActivityRuntime = null;
20
- function AgentActivityRuntimeProvider({
21
- children,
22
- runtime
23
- }) {
24
- currentAgentActivityRuntime = runtime ?? null;
25
- return /* @__PURE__ */ jsx(AgentActivityRuntimeContext.Provider, { value: runtime ?? null, children });
26
- }
27
- function useAgentActivityRuntime() {
28
- const runtime = useContext(AgentActivityRuntimeContext) ?? getTestAgentActivityRuntime();
29
- if (!runtime) {
30
- throw new Error(
31
- "AgentActivityRuntimeProvider is missing an AgentActivityRuntime instance."
32
- );
33
- }
34
- return runtime;
35
- }
36
- function useOptionalAgentActivityRuntime() {
37
- return useContext(AgentActivityRuntimeContext) ?? getTestAgentActivityRuntime();
38
- }
39
- function useAgentActivitySnapshot(workspaceId) {
40
- const runtime = useAgentActivityRuntime();
41
- const normalizedWorkspaceId = workspaceId.trim();
42
- return useSyncExternalStore(
43
- (listener) => runtime.subscribe(normalizedWorkspaceId, listener),
44
- () => runtime.getSnapshot(normalizedWorkspaceId),
45
- () => runtime.getSnapshot(normalizedWorkspaceId)
46
- );
47
- }
48
- function getAgentActivityRuntime() {
49
- const runtime = getExplicitWindowTestAgentActivityRuntime() ?? currentAgentActivityRuntime ?? getTestAgentActivityRuntime();
50
- if (!runtime) {
51
- throw new Error(
52
- "AgentActivityRuntimeProvider is missing an AgentActivityRuntime instance."
53
- );
54
- }
55
- return runtime;
56
- }
57
- function getOptionalAgentActivityRuntime() {
58
- return getExplicitWindowTestAgentActivityRuntime() ?? currentAgentActivityRuntime ?? getTestAgentActivityRuntime();
59
- }
60
- function resetAgentActivityRuntimeForTests() {
61
- if (process.env.NODE_ENV === "test") {
62
- currentAgentActivityRuntime = null;
63
- }
64
- }
65
- function setAgentActivityRuntimeForTests(runtime) {
66
- if (process.env.NODE_ENV === "test") {
67
- currentAgentActivityRuntime = runtime;
68
- }
69
- }
70
- function getTestAgentActivityRuntime() {
71
- if (process.env.NODE_ENV !== "test") {
72
- return null;
73
- }
74
- if (typeof window === "undefined") {
75
- return null;
76
- }
77
- const explicitRuntime = getExplicitWindowTestAgentActivityRuntime();
78
- if (explicitRuntime) {
79
- return explicitRuntime;
80
- }
81
- if (currentAgentActivityRuntime) {
82
- return currentAgentActivityRuntime;
83
- }
84
- const testRuntime = window.agentActivityRuntime;
85
- return testRuntime ?? null;
86
- }
87
- function getExplicitWindowTestAgentActivityRuntime() {
88
- if (process.env.NODE_ENV !== "test" || typeof window === "undefined") {
89
- return null;
90
- }
91
- const testDescriptor = Object.getOwnPropertyDescriptor(
92
- window,
93
- "agentActivityRuntime"
94
- );
95
- if (!testDescriptor || !("value" in testDescriptor)) {
96
- return null;
97
- }
98
- return testDescriptor.value ?? null;
99
- }
100
-
101
- // agentActivityHost.tsx
102
- import {
103
- createContext as createContext2,
104
- useContext as useContext2,
105
- useMemo
106
- } from "react";
107
-
108
- // host/agentHostApi.ts
109
- function toAgentHostRuntimeApi(hostApi) {
110
- return {
111
- account: hostApi.account,
112
- agentGuiBatch: hostApi.agentGuiBatch ?? {},
113
- clipboard: hostApi.clipboard,
114
- debug: hostApi.debug,
115
- filesystem: hostApi.filesystem,
116
- meta: hostApi.meta,
117
- onHostEvent: hostApi.onHostEvent,
118
- runtime: hostApi.runtime,
119
- userProjects: hostApi.userProjects,
120
- workspace: hostApi.workspace,
121
- workspaceAgentProbes: hostApi.workspaceAgentProbes
122
- };
123
- }
124
-
125
- // agentActivityHost.tsx
126
- import { jsx as jsx2 } from "react/jsx-runtime";
127
- var AgentActivityHostContext = createContext2(
128
- null
129
- );
130
- var currentAgentHostApi = null;
131
- function AgentActivityHostProvider({
132
- agentActivityRuntime,
133
- agentHostApi,
134
- children
135
- }) {
136
- const resolvedAgentHostApi = useMemo(
137
- () => agentHostApi ? toAgentHostRuntimeApi(agentHostApi) : null,
138
- [agentHostApi]
139
- );
140
- currentAgentHostApi = resolvedAgentHostApi;
141
- return /* @__PURE__ */ jsx2(AgentActivityRuntimeProvider, { runtime: agentActivityRuntime, children: /* @__PURE__ */ jsx2(AgentActivityHostContext.Provider, { value: resolvedAgentHostApi, children }) });
142
- }
143
- function useAgentHostApi() {
144
- const agentHostApi = useContext2(AgentActivityHostContext) ?? getTestAgentHostApi();
145
- if (!agentHostApi) {
146
- throw new Error(
147
- "AgentActivityHostProvider is missing an agentHostApi instance."
148
- );
149
- }
150
- return agentHostApi;
151
- }
152
- function useOptionalAgentHostApi() {
153
- return useContext2(AgentActivityHostContext) ?? getTestAgentHostApi();
154
- }
155
- function getOptionalAgentHostApi() {
156
- return getExplicitWindowTestAgentHostApi() ?? currentAgentHostApi ?? getTestAgentHostApi();
157
- }
158
- function getTestAgentHostApi() {
159
- if (process.env.NODE_ENV !== "test") {
160
- return null;
161
- }
162
- if (typeof window === "undefined") {
163
- return null;
164
- }
165
- const explicitAgentHostApi = getExplicitWindowTestAgentHostApi();
166
- if (explicitAgentHostApi) {
167
- return explicitAgentHostApi;
168
- }
169
- if (currentAgentHostApi) {
170
- return currentAgentHostApi;
171
- }
172
- const testAgentHostApi = window.agentHostApi;
173
- return testAgentHostApi ? toAgentHostRuntimeApi(testAgentHostApi) : null;
174
- }
175
- function getExplicitWindowTestAgentHostApi() {
176
- if (process.env.NODE_ENV !== "test" || typeof window === "undefined") {
177
- return null;
178
- }
179
- const testDescriptor = Object.getOwnPropertyDescriptor(
180
- window,
181
- "agentHostApi"
182
- );
183
- if (!testDescriptor || !("value" in testDescriptor)) {
184
- return null;
185
- }
186
- const testAgentHostApi = testDescriptor.value;
187
- return testAgentHostApi ? toAgentHostRuntimeApi(testAgentHostApi) : null;
188
- }
189
-
190
- // shared/managedAgentProviders.ts
191
- function normalizeManagedAgentProvider(provider) {
192
- const normalized = provider?.trim().toLowerCase().replace(/[_\s]+/gu, "-") ?? "";
193
- switch (normalized) {
194
- case "claude":
195
- case "claude-code":
196
- return "claude-code";
197
- case "nexight":
198
- case "nextop-doc":
199
- return "nextop";
200
- default:
201
- return normalized;
202
- }
203
- }
204
-
205
- // managedAgentIconAssets.ts
206
- function agentIconUrl(fileName) {
207
- return new URL(
208
- `./app/renderer/assets/icons/agents/${fileName}`,
209
- import.meta.url
210
- ).href;
211
- }
212
- var manageAgentClaudeCodeUrl = agentIconUrl(
213
- "manage-agent-claude-code.png"
214
- );
215
- var manageAgentCodexUrl = agentIconUrl("manage-agent-codex.png");
216
- var manageAgentGeminiUrl = agentIconUrl("manage-agent-gemini.png");
217
- var manageAgentHermesUrl = agentIconUrl("manage-agent-hermes.png");
218
- var manageAgentNextopUrl = agentIconUrl("manage-agent-nextop.png");
219
- var manageAgentOpenclawUrl = agentIconUrl("manage-agent-openclaw.png");
220
- var claudeRoundedUrl = agentIconUrl("claude-rounded.png");
221
- var codexRoundedUrl = agentIconUrl("codex-rounded.png");
222
- var geminiRoundedUrl = agentIconUrl("gemini-rounded.png");
223
- var hermesRoundedUrl = agentIconUrl("hermes-rounded.png");
224
- var nextopDocRoundedUrl = agentIconUrl("nextop-doc-rounded.png");
225
- var openclawRoundedUrl = agentIconUrl("openclaw-rounded.png");
226
-
227
- // shared/managedAgentIcons.ts
228
- var MANAGED_AGENT_ICON_URLS = {
229
- "claude-code": manageAgentClaudeCodeUrl,
230
- codex: manageAgentCodexUrl,
231
- gemini: manageAgentGeminiUrl,
232
- hermes: manageAgentHermesUrl,
233
- nextop: manageAgentNextopUrl,
234
- openclaw: manageAgentOpenclawUrl
235
- };
236
- var MANAGED_AGENT_ICON_ROUNDED_URLS = {
237
- "claude-code": claudeRoundedUrl,
238
- codex: codexRoundedUrl,
239
- gemini: geminiRoundedUrl,
240
- hermes: hermesRoundedUrl,
241
- nextop: nextopDocRoundedUrl,
242
- openclaw: openclawRoundedUrl
243
- };
244
- var MANAGED_AGENT_ROUNDED_ICON_FALLBACK_URL = nextopDocRoundedUrl;
245
- var MANAGED_AGENT_ICON_FALLBACK_URL = manageAgentNextopUrl;
246
- function managedAgentRoundedIconUrl(provider) {
247
- return MANAGED_AGENT_ICON_ROUNDED_URLS[normalizeManagedAgentProvider(provider)] ?? MANAGED_AGENT_ROUNDED_ICON_FALLBACK_URL;
248
- }
249
-
250
- // shared/agentConversation/approvalOptionPresentation.ts
251
- function approvalOptionDisplayLabel(option, intent = {}) {
252
- const idToken = normalizeApprovalOptionToken(option.id);
253
- const kindToken = normalizeApprovalOptionToken(option.kind);
254
- const label = option.label.trim();
255
- const specificTranslationKey = approvalOptionSpecificTranslationKey(
256
- idToken,
257
- label
258
- );
259
- if (specificTranslationKey) {
260
- return translate(specificTranslationKey);
261
- }
262
- const providerLabelTranslation = approvalOptionProviderLabelTranslation(label);
263
- if (providerLabelTranslation) {
264
- return translate(
265
- providerLabelTranslation.key,
266
- providerLabelTranslation.params
267
- );
268
- }
269
- if ((idToken === "allowonce" || kindToken === "allowonce") && isGenericAllowOnceLabel(label)) {
270
- return translate("agentHost.agentGui.approvalOptions.allowOnce");
271
- }
272
- if ((idToken === "allowalways" || idToken === "allowall") && isGenericApprovalLabel(label)) {
273
- return translate("agentHost.agentGui.approvalOptions.allowAlways");
274
- }
275
- if (idToken === "rejectalways" || kindToken === "rejectalways") {
276
- return translate("agentHost.agentGui.approvalOptions.rejectAlways");
277
- }
278
- if (idToken === "rejectonce" || idToken === "reject" || idToken === "deny" || kindToken === "rejectonce" || kindToken === "reject" || kindToken === "deny") {
279
- return intent.feedback ? translate("agentHost.agentGui.approvalOptions.rejectWithFollowUp") : translate("agentHost.agentGui.approvalOptions.rejectOnce");
280
- }
281
- return label || option.id;
282
- }
283
- function approvalOptionVisualPresentation(option, intent = {}) {
284
- const commandPrefix = approvalOptionCommandPrefix(option.label);
285
- if (commandPrefix) {
286
- return {
287
- label: translate(
288
- "agentHost.agentGui.approvalOptions.allowAlwaysForCommandPrefixLead"
289
- ),
290
- commandPrefix
291
- };
292
- }
293
- return {
294
- label: approvalOptionDisplayLabel(option, intent)
295
- };
296
- }
297
- function normalizeApprovalOptionToken(value) {
298
- return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "");
299
- }
300
- function approvalOptionSpecificTranslationKey(token, label) {
301
- const labelToken = normalizeApprovalOptionToken(label);
302
- switch (token) {
303
- case "bypasspermissions":
304
- return "agentHost.agentGui.approvalOptions.bypassPermissions";
305
- case "auto":
306
- return labelToken === "yesanduseautomode" ? "agentHost.agentGui.approvalOptions.autoMode" : null;
307
- case "acceptedits":
308
- return "agentHost.agentGui.approvalOptions.acceptEdits";
309
- case "default":
310
- return labelToken === "yesandmanuallyapproveedits" ? "agentHost.agentGui.approvalOptions.manualApproval" : null;
311
- default:
312
- return null;
313
- }
314
- }
315
- function approvalOptionProviderLabelTranslation(label) {
316
- const commandPrefix = approvalOptionCommandPrefix(label);
317
- if (commandPrefix) {
318
- return {
319
- key: "agentHost.agentGui.approvalOptions.allowAlwaysForCommandPrefix",
320
- params: { command: commandPrefix }
321
- };
322
- }
323
- const allowScopeMatch = label.match(/^Yes,\s*and don't ask again for (.+)$/i);
324
- if (allowScopeMatch?.[1]) {
325
- return {
326
- key: "agentHost.agentGui.approvalOptions.allowAlwaysForScope",
327
- params: { scope: allowScopeMatch[1] }
328
- };
329
- }
330
- const alwaysAllowMatch = label.match(/^Always Allow\s+(.+)$/i);
331
- if (alwaysAllowMatch?.[1]) {
332
- return {
333
- key: "agentHost.agentGui.approvalOptions.alwaysAllowScope",
334
- params: { scope: alwaysAllowMatch[1] }
335
- };
336
- }
337
- return null;
338
- }
339
- function approvalOptionCommandPrefix(label) {
340
- const commandPrefixMatch = label.match(
341
- /^Yes,\s*and don't ask again for commands that start with `([^`]+)`$/i
342
- );
343
- return commandPrefixMatch?.[1]?.trim() || null;
344
- }
345
- function isGenericApprovalLabel(label) {
346
- const token = normalizeApprovalOptionToken(label);
347
- return token === "" || token === "allowalways" || token === "allowall" || token === "alwaysallow" || token === "yesanddontaskagain";
348
- }
349
- function isGenericAllowOnceLabel(label) {
350
- const token = normalizeApprovalOptionToken(label);
351
- return token === "" || token === "allow" || token === "allowonce" || token === "yes" || token === "yesproceed" || token === "yesandproceed";
352
- }
353
-
354
- // shared/agentConversation/promptToolDetails.ts
355
- function getPromptToolDetails(input) {
356
- if (!input) {
357
- return [];
358
- }
359
- const detailInput = resolveToolDetailInput(input);
360
- const command = commandStringValue(detailInput.command) ?? commandStringValue(detailInput.cmd);
361
- if (command) {
362
- return [
363
- {
364
- kind: "command",
365
- value: command,
366
- ...stringValue(detailInput.description) ? { meta: stringValue(detailInput.description) } : {}
367
- }
368
- ];
369
- }
370
- const filePath = stringValue(detailInput.file_path) ?? stringValue(detailInput.filePath) ?? stringValue(detailInput.path) ?? stringValue(detailInput.notebook_path);
371
- if (filePath) {
372
- const lineRange = formatLineRange(detailInput);
373
- return [
374
- {
375
- kind: "path",
376
- value: filePath,
377
- ...lineRange ? { meta: lineRange } : {}
378
- }
379
- ];
380
- }
381
- const query = stringValue(detailInput.query) ?? stringValue(detailInput.search_query) ?? stringValue(detailInput.searchQuery) ?? stringValue(detailInput.pattern);
382
- if (query) {
383
- return [
384
- {
385
- kind: "query",
386
- value: query
387
- }
388
- ];
389
- }
390
- return [];
391
- }
392
- function isPromptRequestIdTitle(value) {
393
- return /^request(?:id|ID)\s*:/u.test(value.trim());
394
- }
395
- function resolveToolDetailInput(input) {
396
- const toolCall = objectValue(input.toolCall);
397
- return firstObjectValue(input, [
398
- "command",
399
- "cmd",
400
- "file_path",
401
- "filePath",
402
- "path",
403
- "notebook_path",
404
- "query",
405
- "search_query",
406
- "searchQuery",
407
- "pattern"
408
- ]) ?? firstObjectValue(toolCall, [
409
- "input",
410
- "rawInput",
411
- "raw_input",
412
- "arguments",
413
- "args"
414
- ]) ?? toolCall ?? input;
415
- }
416
- function firstObjectValue(input, keys) {
417
- if (!input) {
418
- return null;
419
- }
420
- if (keys.some((key) => stringValue(input[key]))) {
421
- return input;
422
- }
423
- for (const key of keys) {
424
- const value = objectValue(input[key]);
425
- if (value) {
426
- return value;
427
- }
428
- }
429
- return null;
430
- }
431
- function formatLineRange(input) {
432
- const start = numericValue(input.startLine) ?? numericValue(input.start_line);
433
- const end = numericValue(input.endLine) ?? numericValue(input.end_line);
434
- if (start === null || end === null) {
435
- return null;
436
- }
437
- return start === end ? `L${start}` : `L${start}-${end}`;
438
- }
439
- function stringValue(value) {
440
- return typeof value === "string" && value.trim() ? value.trim() : null;
441
- }
442
- function commandStringValue(value) {
443
- if (typeof value === "string") {
444
- return stringValue(value);
445
- }
446
- if (!Array.isArray(value)) {
447
- return null;
448
- }
449
- const shellFlag = stringValue(value[value.length - 2]);
450
- const shellCommand = stringValue(value[value.length - 1]);
451
- if ((shellFlag === "-c" || shellFlag === "-lc") && shellCommand) {
452
- return shellCommand;
453
- }
454
- const parts = value.flatMap((part) => {
455
- const text = stringValue(part);
456
- return text ? [text] : [];
457
- });
458
- return parts.length > 0 ? parts.join(" ") : null;
459
- }
460
- function objectValue(value) {
461
- return value && typeof value === "object" && !Array.isArray(value) ? value : null;
462
- }
463
- function numericValue(value) {
464
- return typeof value === "number" && Number.isFinite(value) ? value : null;
465
- }
466
-
467
- // shared/agentConversation/components/AgentInteractivePromptSurface.tsx
468
- import {
469
- useCallback as useCallback2,
470
- useEffect as useEffect2,
471
- useMemo as useMemo2,
472
- useRef as useRef2,
473
- useState
474
- } from "react";
475
-
476
- // app/renderer/components/icons/MessageSquareMoreIcon.tsx
477
- import {
478
- forwardRef,
479
- useCallback,
480
- useEffect,
481
- useImperativeHandle,
482
- useRef
483
- } from "react";
484
- import {
485
- motion,
486
- useAnimation,
487
- useReducedMotion
488
- } from "framer-motion";
489
-
490
- // app/renderer/lib/utils.ts
491
- import { clsx } from "clsx";
492
- import { twMerge } from "tailwind-merge";
493
- function cn(...inputs) {
494
- return twMerge(clsx(inputs));
495
- }
496
-
497
- // app/renderer/components/icons/MessageSquareMoreIcon.tsx
498
- import { jsx as jsx3, jsxs } from "react/jsx-runtime";
499
- var DOT_TRANSITION = {
500
- times: [0, 0.1, 0.1, 0.2, 0.5, 0.6, 0.6, 0.7],
501
- duration: 1.5
502
- };
503
- var DOT_VARIANTS = {
504
- normal: {
505
- opacity: 1
506
- },
507
- animate: (custom) => ({
508
- opacity: [1, 0, 0, 1, 1, 0, 0, 1],
509
- transition: {
510
- opacity: {
511
- ...DOT_TRANSITION,
512
- times: DOT_TRANSITION.times.map(
513
- (time, index) => index === 2 || index === 3 || index === 6 || index === 7 ? time + custom * 0.1 : time
514
- )
515
- }
516
- }
517
- }),
518
- active: (custom) => ({
519
- opacity: [1, 0, 0, 1, 1, 0, 0, 1],
520
- transition: {
521
- opacity: {
522
- ...DOT_TRANSITION,
523
- repeat: Infinity,
524
- times: DOT_TRANSITION.times.map(
525
- (time, index) => index === 2 || index === 3 || index === 6 || index === 7 ? time + custom * 0.1 : time
526
- )
527
- }
528
- }
529
- })
530
- };
531
- var MessageSquareMoreIcon = forwardRef(
532
- ({
533
- active = false,
534
- onMouseEnter,
535
- onMouseLeave,
536
- className,
537
- size = 28,
538
- ...props
539
- }, ref) => {
540
- const controls = useAnimation();
541
- const reduceMotion = useReducedMotion();
542
- const isControlledRef = useRef(false);
543
- const startAnimation = useCallback(() => {
544
- if (reduceMotion) {
545
- return;
546
- }
547
- void controls.start(active ? "active" : "animate");
548
- }, [active, controls, reduceMotion]);
549
- const stopAnimation = useCallback(() => {
550
- void controls.start("normal");
551
- }, [controls]);
552
- useImperativeHandle(ref, () => {
553
- isControlledRef.current = true;
554
- return {
555
- startAnimation,
556
- stopAnimation
557
- };
558
- });
559
- useEffect(() => {
560
- if (active) {
561
- startAnimation();
562
- return;
563
- }
564
- stopAnimation();
565
- }, [active, startAnimation, stopAnimation]);
566
- const handleMouseEnter = useCallback(
567
- (event) => {
568
- if (isControlledRef.current) {
569
- onMouseEnter?.(event);
570
- } else {
571
- startAnimation();
572
- }
573
- },
574
- [onMouseEnter, startAnimation]
575
- );
576
- const handleMouseLeave = useCallback(
577
- (event) => {
578
- if (isControlledRef.current) {
579
- onMouseLeave?.(event);
580
- } else {
581
- stopAnimation();
582
- }
583
- },
584
- [onMouseLeave, stopAnimation]
585
- );
586
- return /* @__PURE__ */ jsx3(
587
- "div",
588
- {
589
- className: cn("inline-flex items-center justify-center", className),
590
- onMouseEnter: handleMouseEnter,
591
- onMouseLeave: handleMouseLeave,
592
- ...props,
593
- children: /* @__PURE__ */ jsxs(
594
- "svg",
595
- {
596
- fill: "none",
597
- height: size,
598
- stroke: "currentColor",
599
- strokeLinecap: "round",
600
- strokeLinejoin: "round",
601
- strokeWidth: "2",
602
- viewBox: "0 0 24 24",
603
- width: size,
604
- xmlns: "http://www.w3.org/2000/svg",
605
- children: [
606
- /* @__PURE__ */ jsx3("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }),
607
- /* @__PURE__ */ jsx3(
608
- motion.path,
609
- {
610
- animate: controls,
611
- custom: 0,
612
- d: "M8 10h.01",
613
- variants: DOT_VARIANTS
614
- }
615
- ),
616
- /* @__PURE__ */ jsx3(
617
- motion.path,
618
- {
619
- animate: controls,
620
- custom: 1,
621
- d: "M12 10h.01",
622
- variants: DOT_VARIANTS
623
- }
624
- ),
625
- /* @__PURE__ */ jsx3(
626
- motion.path,
627
- {
628
- animate: controls,
629
- custom: 2,
630
- d: "M16 10h.01",
631
- variants: DOT_VARIANTS
632
- }
633
- )
634
- ]
635
- }
636
- )
637
- }
638
- );
639
- }
640
- );
641
- MessageSquareMoreIcon.displayName = "MessageSquareMoreIcon";
642
-
643
- // app/renderer/components/ui/spinner.tsx
644
- import { Spinner } from "@tutti-os/ui-system";
645
-
646
- // shared/agentConversation/components/AgentInteractivePromptSurface.tsx
647
- import {
648
- ShortcutBadge,
649
- Tooltip,
650
- TooltipContent,
651
- TooltipProvider,
652
- TooltipTrigger
653
- } from "@tutti-os/ui-system";
654
-
655
- // agent-gui/agentGuiNode/AgentGUIConversation.styles.ts
656
- var styles = {
657
- interactivePrompt: "agent-gui-conversation__interactive-prompt",
658
- interactivePromptCard: "agent-gui-conversation__interactive-prompt-card",
659
- interactivePromptHeader: "agent-gui-conversation__interactive-prompt-header",
660
- interactivePromptLead: "agent-gui-conversation__interactive-prompt-lead",
661
- interactivePromptMeta: "agent-gui-conversation__interactive-prompt-meta",
662
- interactivePromptQuestion: "agent-gui-conversation__interactive-prompt-question",
663
- interactivePromptOptions: "agent-gui-conversation__interactive-prompt-options",
664
- interactiveOptionDisplay: "agent-gui-conversation__interactive-option-display",
665
- interactiveOptionButton: "agent-gui-conversation__interactive-option-button",
666
- interactiveOptionTitle: "agent-gui-conversation__interactive-option-title",
667
- interactiveOptionDescription: "agent-gui-conversation__interactive-option-description",
668
- interactiveOptionCommandDescription: "agent-gui-conversation__interactive-option-command-description",
669
- interactiveOptionCommandTooltip: "agent-gui-conversation__interactive-option-command-tooltip",
670
- interactiveOptionShortcut: "agent-gui-conversation__interactive-option-shortcut",
671
- interactiveOptionSpinner: "agent-gui-conversation__interactive-option-spinner",
672
- interactiveFeedbackComposer: "agent-gui-conversation__interactive-feedback-composer",
673
- interactivePromptTextarea: "agent-gui-conversation__interactive-prompt-textarea",
674
- interactiveFeedbackSendButton: "agent-gui-conversation__interactive-feedback-send-button",
675
- interactivePromptFooter: "agent-gui-conversation__interactive-prompt-footer",
676
- interactivePromptActions: "agent-gui-conversation__interactive-prompt-actions",
677
- userMessageFlow: "agent-gui-conversation__user-message-flow",
678
- assistantMessageFlow: "agent-gui-conversation__assistant-message-flow",
679
- messageGroup: "agent-gui-conversation__message-group",
680
- userMessageBubble: "agent-gui-conversation__user-message-bubble",
681
- assistantMarkdown: "agent-gui-conversation__assistant-markdown"
682
- };
683
- var AgentGUIConversation_styles_default = styles;
684
-
685
- // shared/agentConversation/components/AgentInteractivePromptSurface.tsx
686
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
687
- var COMMAND_TOOLTIP_DELAY_MS = 1e3;
688
- function AgentInteractivePromptSurface({
689
- prompt,
690
- edgeGlow = false,
691
- embedded = false,
692
- keyboardShortcuts = true,
693
- isSubmitting,
694
- onSubmit,
695
- labels
696
- }) {
697
- "use memo";
698
- if (prompt.kind === "approval") {
699
- return /* @__PURE__ */ jsx4(
700
- ApprovalPromptSurface,
701
- {
702
- prompt,
703
- embedded,
704
- edgeGlow,
705
- keyboardShortcuts,
706
- isSubmitting,
707
- onSubmit,
708
- labels
709
- }
710
- );
711
- }
712
- if (prompt.kind === "exit-plan") {
713
- return /* @__PURE__ */ jsx4(
714
- ExitPlanPromptSurface,
715
- {
716
- prompt,
717
- embedded,
718
- edgeGlow,
719
- isSubmitting,
720
- onSubmit,
721
- labels
722
- }
723
- );
724
- }
725
- return /* @__PURE__ */ jsx4(
726
- AskUserPromptSurface,
727
- {
728
- prompt,
729
- embedded,
730
- edgeGlow,
731
- isSubmitting,
732
- onSubmit,
733
- labels
734
- }
735
- );
736
- }
737
- function ApprovalPromptSurface({
738
- prompt,
739
- embedded = false,
740
- edgeGlow = false,
741
- keyboardShortcuts = true,
742
- isSubmitting,
743
- onSubmit,
744
- labels
745
- }) {
746
- "use memo";
747
- const promptDetails = useMemo2(
748
- () => formatToolDetails(prompt.input ?? null),
749
- [prompt.input]
750
- );
751
- const visiblePromptTitle = approvalPromptTitle(
752
- prompt.title,
753
- promptDetails.length
754
- );
755
- const details = useMemo2(
756
- () => filterDuplicatePromptTitleDetails(promptDetails, visiblePromptTitle),
757
- [promptDetails, visiblePromptTitle]
758
- );
759
- const [submittingOptionId, setSubmittingOptionId] = useState(
760
- null
761
- );
762
- const [pendingFeedbackOptionId, setPendingFeedbackOptionId] = useState(null);
763
- const [feedback, setFeedback] = useState("");
764
- const feedbackTextareaRef = useRef2(null);
765
- const agentHostApi = useOptionalAgentHostApi() ?? getOptionalAgentHostApi();
766
- const isDarwin = isDarwinPlatform(agentHostApi?.meta?.platform);
767
- const feedbackOptionId = useMemo2(
768
- () => approvalFeedbackOptionId(prompt.options),
769
- [prompt.options]
770
- );
771
- const feedbackValue = feedback.trim();
772
- useEffect2(() => {
773
- setSubmittingOptionId(null);
774
- setPendingFeedbackOptionId(null);
775
- setFeedback("");
776
- }, [prompt.requestId]);
777
- useEffect2(() => {
778
- if (pendingFeedbackOptionId !== null) {
779
- feedbackTextareaRef.current?.focus();
780
- }
781
- }, [pendingFeedbackOptionId]);
782
- const submitOption = useCallback2(
783
- (optionId) => {
784
- const feedbackOption = feedbackOptionId === optionId;
785
- if (feedbackOption && pendingFeedbackOptionId !== optionId) {
786
- setFeedback("");
787
- setPendingFeedbackOptionId(optionId);
788
- return;
789
- }
790
- setSubmittingOptionId(optionId);
791
- onSubmit({
792
- requestId: prompt.requestId,
793
- ...feedbackOption ? { action: "deny" } : {},
794
- optionId,
795
- ...feedbackOption && feedbackValue ? { payload: { denyMessage: feedbackValue } } : {}
796
- });
797
- },
798
- [
799
- feedbackOptionId,
800
- feedbackValue,
801
- onSubmit,
802
- pendingFeedbackOptionId,
803
- prompt.requestId
804
- ]
805
- );
806
- useEffect2(() => {
807
- if (!keyboardShortcuts || isSubmitting || submittingOptionId !== null || prompt.options.length === 0) {
808
- return void 0;
809
- }
810
- const handleKeyDown = (event) => {
811
- if (!isEnterLikeKey(event) || isEditableKeyboardTarget(event.target) || event.isComposing || event.altKey || event.shiftKey) {
812
- return;
813
- }
814
- const optionIndex = event.metaKey || event.ctrlKey ? 1 : 0;
815
- const option = prompt.options[optionIndex];
816
- if (!option) {
817
- return;
818
- }
819
- event.preventDefault();
820
- event.stopPropagation();
821
- submitOption(option.id);
822
- };
823
- window.addEventListener("keydown", handleKeyDown, true);
824
- return () => window.removeEventListener("keydown", handleKeyDown, true);
825
- }, [
826
- isSubmitting,
827
- keyboardShortcuts,
828
- prompt.options,
829
- submitOption,
830
- submittingOptionId
831
- ]);
832
- return /* @__PURE__ */ jsx4("section", { className: interactivePromptClassName(embedded), children: /* @__PURE__ */ jsxs2("div", { className: interactivePromptCardClassName(edgeGlow), children: [
833
- /* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptLead, children: stripPromptTitlePunctuation(labels.approvalLead) }),
834
- visiblePromptTitle ? /* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptQuestion, children: visiblePromptTitle }) : null,
835
- details.length > 0 ? /* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptOptions, children: details.map((detail) => /* @__PURE__ */ jsxs2(
836
- "div",
837
- {
838
- className: AgentGUIConversation_styles_default.interactiveOptionDisplay,
839
- children: [
840
- /* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionTitle, children: detail.label }),
841
- /* @__PURE__ */ jsx4(PromptDetailValue, { detail }),
842
- detail.meta ? /* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionDescription, children: detail.meta }) : null
843
- ]
844
- },
845
- `${detail.label}:${detail.value}`
846
- )) }) : null,
847
- /* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptOptions, children: prompt.options.map((option, optionIndex) => {
848
- const showSpinner = submittingOptionId === option.id;
849
- const optionSupportsFeedback = feedbackOptionId === option.id;
850
- const optionLabel = approvalOptionDisplayLabel(option, {
851
- feedback: optionSupportsFeedback
852
- });
853
- const optionPresentation = approvalOptionVisualPresentation(
854
- option,
855
- { feedback: optionSupportsFeedback }
856
- );
857
- const shortcutLabel = approvalOptionShortcutLabel(
858
- optionIndex,
859
- isDarwin
860
- );
861
- const showFeedbackComposer = pendingFeedbackOptionId === option.id;
862
- if (showFeedbackComposer) {
863
- return /* @__PURE__ */ jsxs2(
864
- "div",
865
- {
866
- className: AgentGUIConversation_styles_default.interactiveFeedbackComposer,
867
- children: [
868
- /* @__PURE__ */ jsx4(
869
- "textarea",
870
- {
871
- ref: feedbackTextareaRef,
872
- value: feedback,
873
- placeholder: labels.feedbackPlaceholder,
874
- disabled: isSubmitting || submittingOptionId !== null,
875
- className: AgentGUIConversation_styles_default.interactivePromptTextarea,
876
- "aria-label": interactiveOptionLabel(
877
- optionLabel,
878
- option.description
879
- ),
880
- onChange: (event) => setFeedback(event.currentTarget.value),
881
- onKeyDown: (event) => {
882
- if (!keyboardShortcuts || event.key !== "Enter" || !event.metaKey && !event.ctrlKey || event.nativeEvent.isComposing) {
883
- return;
884
- }
885
- event.preventDefault();
886
- if (!feedbackValue) {
887
- feedbackTextareaRef.current?.focus();
888
- return;
889
- }
890
- submitOption(option.id);
891
- }
892
- }
893
- ),
894
- /* @__PURE__ */ jsx4(
895
- "button",
896
- {
897
- type: "button",
898
- className: AgentGUIConversation_styles_default.interactiveFeedbackSendButton,
899
- disabled: isSubmitting || submittingOptionId !== null || !feedbackValue,
900
- "aria-label": labels.sendFeedback,
901
- title: labels.sendFeedback,
902
- "aria-busy": showSpinner,
903
- onClick: () => {
904
- if (!feedbackValue) {
905
- feedbackTextareaRef.current?.focus();
906
- return;
907
- }
908
- submitOption(option.id);
909
- },
910
- children: showSpinner ? /* @__PURE__ */ jsx4(InteractiveOptionSpinner, {}) : /* @__PURE__ */ jsx4(SendFilledIcon, {})
911
- }
912
- )
913
- ]
914
- },
915
- option.id
916
- );
917
- }
918
- return /* @__PURE__ */ jsxs2(
919
- "button",
920
- {
921
- type: "button",
922
- className: AgentGUIConversation_styles_default.interactiveOptionButton,
923
- "aria-label": interactiveOptionLabel(
924
- optionLabel,
925
- option.description
926
- ),
927
- disabled: isSubmitting || submittingOptionId !== null,
928
- onClick: () => submitOption(option.id),
929
- children: [
930
- /* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionTitle, children: optionPresentation.label }),
931
- optionPresentation.commandPrefix ? /* @__PURE__ */ jsx4(
932
- CommandTextWithTooltip,
933
- {
934
- value: optionPresentation.commandPrefix,
935
- testId: "agent-interactive-command-prefix-option"
936
- }
937
- ) : null,
938
- option.description ? /* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionDescription, children: option.description }) : null,
939
- keyboardShortcuts && shortcutLabel && !showSpinner ? /* @__PURE__ */ jsx4(
940
- ShortcutBadge,
941
- {
942
- className: AgentGUIConversation_styles_default.interactiveOptionShortcut,
943
- "aria-hidden": "true",
944
- children: shortcutLabel
945
- }
946
- ) : null,
947
- showSpinner ? /* @__PURE__ */ jsx4(InteractiveOptionSpinner, {}) : null
948
- ]
949
- },
950
- option.id
951
- );
952
- }) })
953
- ] }) });
954
- }
955
- function ExitPlanPromptSurface({
956
- prompt,
957
- embedded = false,
958
- edgeGlow = false,
959
- isSubmitting,
960
- onSubmit,
961
- labels
962
- }) {
963
- "use memo";
964
- const [feedback, setFeedback] = useState("");
965
- const [submittingOptionId, setSubmittingOptionId] = useState(
966
- null
967
- );
968
- const trimmed = feedback.trim();
969
- const continueLabel = trimmed === "" ? labels.stayInPlan : labels.sendFeedback;
970
- useEffect2(() => {
971
- setSubmittingOptionId(null);
972
- }, [prompt.requestId]);
973
- return /* @__PURE__ */ jsx4("section", { className: interactivePromptClassName(embedded), children: /* @__PURE__ */ jsxs2("div", { className: interactivePromptCardClassName(edgeGlow), children: [
974
- /* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptLead, children: stripPromptTitlePunctuation(labels.planLead) }),
975
- /* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptOptions, children: labels.planModes.map((mode) => {
976
- const showSpinner = submittingOptionId === mode.id;
977
- return /* @__PURE__ */ jsxs2(
978
- "button",
979
- {
980
- type: "button",
981
- className: AgentGUIConversation_styles_default.interactiveOptionButton,
982
- "aria-label": interactiveOptionLabel(
983
- mode.label,
984
- mode.description
985
- ),
986
- disabled: isSubmitting || submittingOptionId !== null,
987
- onClick: () => {
988
- setSubmittingOptionId(mode.id);
989
- onSubmit({
990
- requestId: prompt.requestId,
991
- action: "allow",
992
- optionId: mode.id
993
- });
994
- },
995
- children: [
996
- /* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionTitle, children: mode.label }),
997
- /* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionDescription, children: mode.description }),
998
- showSpinner ? /* @__PURE__ */ jsx4(InteractiveOptionSpinner, {}) : null
999
- ]
1000
- },
1001
- mode.id
1002
- );
1003
- }) }),
1004
- /* @__PURE__ */ jsxs2("div", { className: AgentGUIConversation_styles_default.interactivePromptFooter, children: [
1005
- /* @__PURE__ */ jsx4(
1006
- "textarea",
1007
- {
1008
- value: feedback,
1009
- placeholder: labels.feedbackPlaceholder,
1010
- disabled: isSubmitting,
1011
- className: AgentGUIConversation_styles_default.interactivePromptTextarea,
1012
- onChange: (event) => setFeedback(event.currentTarget.value)
1013
- }
1014
- ),
1015
- /* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptActions, children: /* @__PURE__ */ jsx4(
1016
- "button",
1017
- {
1018
- type: "button",
1019
- disabled: isSubmitting,
1020
- onClick: () => onSubmit({
1021
- requestId: prompt.requestId,
1022
- action: "deny",
1023
- payload: trimmed ? { denyMessage: trimmed } : void 0
1024
- }),
1025
- children: continueLabel
1026
- }
1027
- ) })
1028
- ] })
1029
- ] }) });
1030
- }
1031
- function AskUserPromptSurface({
1032
- prompt,
1033
- embedded = false,
1034
- edgeGlow = false,
1035
- isSubmitting,
1036
- onSubmit,
1037
- labels
1038
- }) {
1039
- "use memo";
1040
- const [index, setIndex] = useState(0);
1041
- const [selectedByQuestionId, setSelectedByQuestionId] = useState({});
1042
- const [freeTextByQuestionId, setFreeTextByQuestionId] = useState({});
1043
- const question = prompt.questions[index] ?? null;
1044
- const selected = question ? selectedByQuestionId[question.id] ?? [] : [];
1045
- const freeText = question ? freeTextByQuestionId[question.id] ?? "" : "";
1046
- const canAdvance = question !== null && (selected.length > 0 || freeText.trim() !== "" || question.options.length === 0);
1047
- const isLast = index >= prompt.questions.length - 1;
1048
- const payload = useMemo2(() => {
1049
- const answersByQuestionId = {};
1050
- const answers = [];
1051
- for (const current of prompt.questions) {
1052
- const chosen = selectedByQuestionId[current.id] ?? [];
1053
- const other = (freeTextByQuestionId[current.id] ?? "").trim();
1054
- if (current.multiSelect) {
1055
- const value2 = other ? [...chosen, other] : chosen;
1056
- if (value2.length > 0) {
1057
- answersByQuestionId[current.id] = value2;
1058
- answers.push(value2.join(", "));
1059
- }
1060
- continue;
1061
- }
1062
- const value = other || chosen[0];
1063
- if (value) {
1064
- answersByQuestionId[current.id] = value;
1065
- answers.push(value);
1066
- }
1067
- }
1068
- return { answers, answersByQuestionId };
1069
- }, [freeTextByQuestionId, prompt.questions, selectedByQuestionId]);
1070
- if (!question) {
1071
- return /* @__PURE__ */ jsx4("section", { className: interactivePromptClassName(embedded), children: /* @__PURE__ */ jsx4("div", { className: interactivePromptCardClassName(edgeGlow), children: /* @__PURE__ */ jsxs2(
1072
- "div",
1073
- {
1074
- className: `${AgentGUIConversation_styles_default.interactivePromptLead} inline-flex items-center gap-1.5`,
1075
- children: [
1076
- /* @__PURE__ */ jsx4(
1077
- MessageSquareMoreIcon,
1078
- {
1079
- size: 15,
1080
- active: true,
1081
- "aria-hidden": "true",
1082
- className: "shrink-0"
1083
- }
1084
- ),
1085
- stripPromptTitlePunctuation(labels.waitingForAnswer)
1086
- ]
1087
- }
1088
- ) }) });
1089
- }
1090
- return /* @__PURE__ */ jsx4("section", { className: interactivePromptClassName(embedded), children: /* @__PURE__ */ jsxs2("div", { className: interactivePromptCardClassName(edgeGlow), children: [
1091
- /* @__PURE__ */ jsxs2("div", { className: AgentGUIConversation_styles_default.interactivePromptHeader, children: [
1092
- /* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactivePromptLead, children: stripPromptTitlePunctuation(question.header) }),
1093
- /* @__PURE__ */ jsxs2("span", { className: AgentGUIConversation_styles_default.interactivePromptMeta, children: [
1094
- index + 1,
1095
- "/",
1096
- prompt.questions.length
1097
- ] })
1098
- ] }),
1099
- /* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptQuestion, children: question.question }),
1100
- question.options.length > 0 ? /* @__PURE__ */ jsx4("div", { className: AgentGUIConversation_styles_default.interactivePromptOptions, children: question.options.map((option) => {
1101
- const active = selected.includes(option.label);
1102
- return /* @__PURE__ */ jsxs2(
1103
- "button",
1104
- {
1105
- type: "button",
1106
- className: AgentGUIConversation_styles_default.interactiveOptionButton,
1107
- "data-active": active,
1108
- "aria-label": interactiveOptionLabel(
1109
- option.label,
1110
- option.description
1111
- ),
1112
- disabled: isSubmitting,
1113
- onClick: () => {
1114
- setSelectedByQuestionId((current) => {
1115
- const existing = current[question.id] ?? [];
1116
- const next = question.multiSelect ? existing.includes(option.label) ? existing.filter((value) => value !== option.label) : [...existing, option.label] : existing.includes(option.label) ? [] : [option.label];
1117
- return { ...current, [question.id]: next };
1118
- });
1119
- },
1120
- children: [
1121
- /* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionTitle, children: option.label }),
1122
- /* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionDescription, children: option.description })
1123
- ]
1124
- },
1125
- option.label
1126
- );
1127
- }) }) : null,
1128
- /* @__PURE__ */ jsx4(
1129
- "textarea",
1130
- {
1131
- value: freeText,
1132
- placeholder: labels.answerPlaceholder,
1133
- disabled: isSubmitting,
1134
- className: AgentGUIConversation_styles_default.interactivePromptTextarea,
1135
- onChange: (event) => {
1136
- const value = event.currentTarget.value;
1137
- setFreeTextByQuestionId((current) => ({
1138
- ...current,
1139
- [question.id]: value
1140
- }));
1141
- }
1142
- }
1143
- ),
1144
- /* @__PURE__ */ jsxs2("div", { className: AgentGUIConversation_styles_default.interactivePromptActions, children: [
1145
- /* @__PURE__ */ jsx4(
1146
- "button",
1147
- {
1148
- type: "button",
1149
- disabled: isSubmitting || index === 0,
1150
- onClick: () => setIndex((current) => Math.max(current - 1, 0)),
1151
- children: labels.previousQuestion
1152
- }
1153
- ),
1154
- isLast ? /* @__PURE__ */ jsx4(
1155
- "button",
1156
- {
1157
- type: "button",
1158
- disabled: isSubmitting || Object.keys(payload.answersByQuestionId).length === 0,
1159
- onClick: () => onSubmit({
1160
- requestId: prompt.requestId,
1161
- action: "submit",
1162
- payload
1163
- }),
1164
- children: labels.submitAnswers
1165
- }
1166
- ) : /* @__PURE__ */ jsx4(
1167
- "button",
1168
- {
1169
- type: "button",
1170
- disabled: isSubmitting || !canAdvance,
1171
- onClick: () => setIndex(
1172
- (current) => Math.min(current + 1, prompt.questions.length - 1)
1173
- ),
1174
- children: labels.nextQuestion
1175
- }
1176
- )
1177
- ] })
1178
- ] }) });
1179
- }
1180
- function isEnterLikeKey(event) {
1181
- return event.key === "Enter" || event.code === "Enter" || event.code === "NumpadEnter";
1182
- }
1183
- function isEditableKeyboardTarget(target) {
1184
- if (!(target instanceof HTMLElement)) {
1185
- return false;
1186
- }
1187
- const tagName = target.tagName.toLowerCase();
1188
- return tagName === "input" || tagName === "textarea" || tagName === "select" || target.isContentEditable;
1189
- }
1190
- function approvalOptionShortcutLabel(optionIndex, isDarwin) {
1191
- if (optionIndex === 0) {
1192
- return translate("agentHost.agentGui.shortcutEnter");
1193
- }
1194
- if (optionIndex === 1) {
1195
- return isDarwin ? translate("agentHost.agentGui.shortcutCmdEnter") : translate("agentHost.agentGui.shortcutCtrEnter");
1196
- }
1197
- return null;
1198
- }
1199
- function isDarwinPlatform(platform) {
1200
- if (platform) {
1201
- return platform === "darwin";
1202
- }
1203
- if (typeof navigator === "undefined") {
1204
- return false;
1205
- }
1206
- const userAgentPlatform = "userAgentData" in navigator ? navigator.userAgentData?.platform : void 0;
1207
- const navigatorPlatform = userAgentPlatform ?? navigator.platform ?? "";
1208
- return /mac/i.test(navigatorPlatform);
1209
- }
1210
- function InteractiveOptionSpinner() {
1211
- "use memo";
1212
- return /* @__PURE__ */ jsx4(
1213
- Spinner,
1214
- {
1215
- className: AgentGUIConversation_styles_default.interactiveOptionSpinner,
1216
- testId: "agent-interactive-option-spinner"
1217
- }
1218
- );
1219
- }
1220
- function SendFilledIcon() {
1221
- "use memo";
1222
- return /* @__PURE__ */ jsx4(
1223
- "svg",
1224
- {
1225
- width: "24",
1226
- height: "24",
1227
- viewBox: "0 0 24 24",
1228
- fill: "none",
1229
- "aria-hidden": "true",
1230
- children: /* @__PURE__ */ jsx4(
1231
- "path",
1232
- {
1233
- d: "M2.74311 8.80587C2.84592 8.40096 3.14571 8.08844 3.54551 7.97033L18.5197 3.51569C18.9336 3.39383 19.3809 3.5054 19.6881 3.81262C19.9951 4.11984 20.1076 4.56798 19.9857 4.9817L15.5311 19.9559C15.413 20.3557 15.1005 20.6555 14.6956 20.7583C14.2895 20.8597 13.869 20.7438 13.5721 20.4469L10.455 15.1823C10.8585 14.6483 12.1563 12.9094 14.3475 9.96528C14.6086 9.70419 14.6382 9.31168 14.4138 9.08692C14.1891 8.86221 13.796 8.8913 13.5348 9.15252L8.31088 13.0423L3.05316 9.92799C2.7562 9.63104 2.64049 9.21071 2.74311 8.80587Z",
1234
- fill: "currentColor"
1235
- }
1236
- )
1237
- }
1238
- );
1239
- }
1240
- function interactivePromptClassName(embedded) {
1241
- return embedded ? `${AgentGUIConversation_styles_default.interactivePrompt} agent-gui-conversation__interactive-prompt--embedded` : AgentGUIConversation_styles_default.interactivePrompt;
1242
- }
1243
- function interactivePromptCardClassName(edgeGlow) {
1244
- return edgeGlow ? `${AgentGUIConversation_styles_default.interactivePromptCard} agent-gui-edge-glow` : AgentGUIConversation_styles_default.interactivePromptCard;
1245
- }
1246
- function formatToolDetails(input) {
1247
- return getPromptToolDetails(input).map((detail) => ({
1248
- kind: detail.kind,
1249
- label: promptToolDetailLabel(detail.kind),
1250
- value: detail.value,
1251
- ...detail.meta ? { meta: detail.meta } : {}
1252
- }));
1253
- }
1254
- function PromptDetailValue({
1255
- detail
1256
- }) {
1257
- "use memo";
1258
- if (detail.kind !== "command") {
1259
- return /* @__PURE__ */ jsx4("span", { className: AgentGUIConversation_styles_default.interactiveOptionDescription, children: detail.value });
1260
- }
1261
- return /* @__PURE__ */ jsx4(
1262
- CommandTextWithTooltip,
1263
- {
1264
- value: detail.value,
1265
- testId: "agent-interactive-command-detail"
1266
- }
1267
- );
1268
- }
1269
- function CommandTextWithTooltip({
1270
- value,
1271
- testId
1272
- }) {
1273
- "use memo";
1274
- return /* @__PURE__ */ jsx4(TooltipProvider, { delayDuration: COMMAND_TOOLTIP_DELAY_MS, children: /* @__PURE__ */ jsxs2(Tooltip, { children: [
1275
- /* @__PURE__ */ jsx4(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx4(
1276
- "span",
1277
- {
1278
- className: `${AgentGUIConversation_styles_default.interactiveOptionDescription} ${AgentGUIConversation_styles_default.interactiveOptionCommandDescription}`,
1279
- "data-agent-interactive-command-detail": testId === "agent-interactive-command-detail" ? "true" : void 0,
1280
- "data-agent-interactive-command-prefix-option": testId === "agent-interactive-command-prefix-option" ? "true" : void 0,
1281
- children: value
1282
- }
1283
- ) }),
1284
- /* @__PURE__ */ jsx4(TooltipContent, { className: AgentGUIConversation_styles_default.interactiveOptionCommandTooltip, children: value })
1285
- ] }) });
1286
- }
1287
- function promptToolDetailLabel(kind) {
1288
- switch (kind) {
1289
- case "command":
1290
- return translate("agentHost.agentTool.details.command");
1291
- case "path":
1292
- return translate("agentHost.agentTool.details.path");
1293
- case "query":
1294
- return translate("agentHost.agentTool.details.query");
1295
- }
1296
- }
1297
- function filterDuplicatePromptTitleDetails(details, title) {
1298
- const normalizedTitle = normalizePromptDetailText(title);
1299
- if (!normalizedTitle) {
1300
- return details;
1301
- }
1302
- return details.filter(
1303
- (detail) => normalizePromptDetailText(detail.value) !== normalizedTitle
1304
- );
1305
- }
1306
- function normalizePromptDetailText(value) {
1307
- return value?.trim() ?? "";
1308
- }
1309
- function isApprovalFeedbackOption(option) {
1310
- return isDenyApprovalOptionToken(option.id) || isDenyApprovalOptionToken(option.kind);
1311
- }
1312
- function approvalFeedbackOptionId(options) {
1313
- const explicitFeedbackOption = options.find(
1314
- (option) => isExplicitFeedbackDenyApprovalOption(option)
1315
- );
1316
- if (explicitFeedbackOption) {
1317
- return explicitFeedbackOption.id;
1318
- }
1319
- return options.find(isApprovalFeedbackOption)?.id ?? null;
1320
- }
1321
- function isExplicitFeedbackDenyApprovalOption(option) {
1322
- for (const value of [option.id, option.kind]) {
1323
- switch (normalizeApprovalOptionToken(value ?? "")) {
1324
- case "abort":
1325
- case "cancel":
1326
- case "cancelled":
1327
- case "canceled":
1328
- case "denywithfeedback":
1329
- case "rejectwithfeedback":
1330
- return true;
1331
- default:
1332
- break;
1333
- }
1334
- }
1335
- return false;
1336
- }
1337
- function isDenyApprovalOptionToken(value) {
1338
- switch (normalizeApprovalOptionToken(value ?? "")) {
1339
- case "abort":
1340
- case "cancel":
1341
- case "cancelled":
1342
- case "canceled":
1343
- case "deny":
1344
- case "denied":
1345
- case "reject":
1346
- case "rejected":
1347
- case "rejectonce":
1348
- case "disallow":
1349
- case "decline":
1350
- case "declined":
1351
- case "no":
1352
- return true;
1353
- default:
1354
- return false;
1355
- }
1356
- }
1357
- function approvalPromptTitle(value, detailCount) {
1358
- const title = value.trim();
1359
- return title && detailCount === 0 && !isPromptRequestIdTitle(title) ? title : null;
1360
- }
1361
- function stripPromptTitlePunctuation(value) {
1362
- return value.trim().replace(/[.。]+$/u, "");
1363
- }
1364
- function interactiveOptionLabel(label, description) {
1365
- const trimmedDescription = description?.trim();
1366
- return trimmedDescription ? `${label} ${trimmedDescription}` : label;
1367
- }
1368
-
1369
- // shared/AgentMessageMarkdown.tsx
1370
- import {
1371
- createContext as createContext3,
1372
- startTransition as startTransition2,
1373
- useCallback as useCallback3,
1374
- useEffect as useEffect4,
1375
- useContext as useContext3,
1376
- memo,
1377
- useMemo as useMemo3,
1378
- useState as useState3
1379
- } from "react";
1380
-
1381
- // app/renderer/components/ZoomableImage.tsx
1382
- import {
1383
- cloneElement
1384
- } from "react";
1385
- import Zoom from "react-medium-image-zoom";
1386
- import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1387
- function ZoomableImage({
1388
- className,
1389
- wrapElement = "div",
1390
- ...props
1391
- }) {
1392
- const { t } = useTranslation();
1393
- const renderZoomContent = ({
1394
- buttonUnzoom,
1395
- img
1396
- }) => /* @__PURE__ */ jsxs3(Fragment, { children: [
1397
- img,
1398
- cloneElement(buttonUnzoom, {
1399
- className: cn(
1400
- buttonUnzoom.props.className,
1401
- "nodrag tsh-desktop-no-drag"
1402
- )
1403
- })
1404
- ] });
1405
- return /* @__PURE__ */ jsx5(
1406
- Zoom,
1407
- {
1408
- a11yNameButtonZoom: t("common.expandImage"),
1409
- a11yNameButtonUnzoom: t("common.minimizeImage"),
1410
- classDialog: "tsh-zoom-dialog nodrag tsh-desktop-no-drag",
1411
- wrapElement,
1412
- zoomMargin: 24,
1413
- ZoomContent: renderZoomContent,
1414
- children: /* @__PURE__ */ jsx5(
1415
- "img",
1416
- {
1417
- ...props,
1418
- className: cn("nodrag tsh-desktop-no-drag cursor-zoom-in", className)
1419
- }
1420
- )
1421
- }
1422
- );
1423
- }
1424
-
1425
- // shared/AgentMessageMarkdown.tsx
1426
- import ReactMarkdown, { defaultUrlTransform } from "react-markdown";
1427
- import rehypeSanitize, {
1428
- defaultSchema
1429
- } from "rehype-sanitize";
1430
- import remarkGfm from "remark-gfm";
1431
- import {
1432
- resolveWorkspaceFileExtension,
1433
- resolveWorkspaceImageMimeType,
1434
- workspaceFileName as basenameWorkspacePath
1435
- } from "@tutti-os/workspace-file-manager/services";
1436
-
1437
- // shared/utils/websiteUrl.ts
1438
- var ALLOWED_WEBSITE_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
1439
- var LIKELY_HOST_PATTERN = /^(localhost|(\d{1,3}\.){3}\d{1,3}|(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,})(?::\d{1,5})?(?:[/?#][^\s]*)?$/i;
1440
- var EXPLICIT_PROTOCOL_PATTERN = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//;
1441
- var LOOPBACK_HOST_PATTERN = /^(localhost|127(?:\.\d{1,3}){3})(?::\d{1,5})?(?:[/?#][^\s]*)?$/i;
1442
- function defaultSchemeForHostInput(value) {
1443
- return LOOPBACK_HOST_PATTERN.test(value) ? "http" : "https";
1444
- }
1445
- function resolveWebsiteNavigationUrl(rawUrl) {
1446
- const trimmed = rawUrl.trim();
1447
- if (trimmed.length === 0) {
1448
- return { url: null, error: null };
1449
- }
1450
- if (EXPLICIT_PROTOCOL_PATTERN.test(trimmed)) {
1451
- try {
1452
- const parsed = new URL(trimmed);
1453
- if (!ALLOWED_WEBSITE_PROTOCOLS.has(parsed.protocol)) {
1454
- return { url: null, error: `Unsupported protocol: ${parsed.protocol}` };
1455
- }
1456
- return { url: parsed.toString(), error: null };
1457
- } catch {
1458
- return { url: null, error: "Invalid URL" };
1459
- }
1460
- }
1461
- if (!LIKELY_HOST_PATTERN.test(trimmed)) {
1462
- return { url: null, error: "Invalid URL" };
1463
- }
1464
- try {
1465
- const parsed = new URL(
1466
- `${defaultSchemeForHostInput(trimmed)}://${trimmed}`
1467
- );
1468
- return { url: parsed.toString(), error: null };
1469
- } catch {
1470
- return { url: null, error: "Invalid URL" };
1471
- }
1472
- }
1473
-
1474
- // actions/workspaceLinkActions.ts
1475
- import {
1476
- parseWorkspaceIssueMentionHref
1477
- } from "@tutti-os/workspace-issue-manager/core";
1478
- var URL_LIKE_LINK_PATTERN = /^[a-zA-Z][a-zA-Z\d+.-]*:|^#/;
1479
- function resolveWorkspaceFilePathCandidate({
1480
- path,
1481
- workspaceRoot,
1482
- basePath
1483
- }) {
1484
- const rawPath = decodeWorkspaceLinkPath(path.trim());
1485
- const root = normalizeWorkspaceFilePath(workspaceRoot?.trim() ?? "");
1486
- if (!rawPath || !root || isUrlLikeWorkspaceFilePath(rawPath)) {
1487
- return null;
1488
- }
1489
- const normalizedPath = normalizeWorkspaceFilePath(rawPath);
1490
- const base = normalizeWorkspaceFilePath(basePath?.trim() || root);
1491
- const resolvedPath = isAbsoluteLocalPath(normalizedPath) ? normalizedPath : normalizeWorkspaceFilePath(`${base}/${normalizedPath}`);
1492
- if (!isInsideOrEqual(resolvedPath, root) && !isDirectAgentGeneratedImagePath(resolvedPath)) {
1493
- return null;
1494
- }
1495
- return {
1496
- path: resolvedPath,
1497
- directoryPath: resolvedPath === root ? root : dirname(resolvedPath),
1498
- workspaceRoot: root
1499
- };
1500
- }
1501
- function resolveWorkspaceFileLinkAction({
1502
- path,
1503
- workspaceRoot,
1504
- basePath,
1505
- source
1506
- }) {
1507
- const candidate = resolveWorkspaceFilePathCandidate({
1508
- path,
1509
- workspaceRoot,
1510
- basePath
1511
- });
1512
- if (!candidate) {
1513
- return null;
1514
- }
1515
- return {
1516
- type: "open-workspace-file",
1517
- path: candidate.path,
1518
- directoryPath: candidate.directoryPath,
1519
- workspaceRoot: candidate.workspaceRoot,
1520
- source
1521
- };
1522
- }
1523
- function resolveWorkspaceUrlLinkAction({
1524
- url,
1525
- source
1526
- }) {
1527
- const resolved = resolveWebsiteNavigationUrl(url);
1528
- if (!resolved.url || resolved.error) {
1529
- return null;
1530
- }
1531
- return {
1532
- type: "open-url",
1533
- url: resolved.url,
1534
- source
1535
- };
1536
- }
1537
- function resolveWorkspaceMentionLinkAction({
1538
- href,
1539
- source
1540
- }) {
1541
- const rawHref = href.trim();
1542
- if (!rawHref.toLowerCase().startsWith("mention://")) {
1543
- return null;
1544
- }
1545
- let url;
1546
- try {
1547
- url = new URL(rawHref);
1548
- } catch {
1549
- return null;
1550
- }
1551
- const workspaceId = url.searchParams.get("workspaceId")?.trim() || "";
1552
- const targetId = url.searchParams.get("id")?.trim() || "";
1553
- if (!workspaceId || !targetId) {
1554
- return null;
1555
- }
1556
- if (url.hostname === "agent-session") {
1557
- const provider = url.searchParams.get("provider")?.trim() || null;
1558
- return {
1559
- type: "open-agent-session",
1560
- workspaceId,
1561
- agentSessionId: targetId,
1562
- ...provider ? { provider } : {},
1563
- source
1564
- };
1565
- }
1566
- if (url.hostname === "workspace-issue") {
1567
- const parsedIssueMention = parseWorkspaceIssueMentionHref(rawHref);
1568
- if (!parsedIssueMention) {
1569
- return null;
1570
- }
1571
- return {
1572
- type: "open-workspace-issue",
1573
- workspaceId: parsedIssueMention.workspaceId,
1574
- issueId: parsedIssueMention.issueId,
1575
- ...parsedIssueMention.mode ? { mode: parsedIssueMention.mode } : {},
1576
- ...parsedIssueMention.outputDir ? { outputDir: parsedIssueMention.outputDir } : {},
1577
- ...parsedIssueMention.runId ? { runId: parsedIssueMention.runId } : {},
1578
- ...parsedIssueMention.taskId ? { taskId: parsedIssueMention.taskId } : {},
1579
- ...parsedIssueMention.topicId ? { topicId: parsedIssueMention.topicId } : {},
1580
- source
1581
- };
1582
- }
1583
- return null;
1584
- }
1585
- function resolveWorkspaceLinkAction({
1586
- href,
1587
- workspaceRoot,
1588
- basePath,
1589
- source
1590
- }) {
1591
- return resolveWorkspaceMentionLinkAction({ href, source }) ?? resolveWorkspaceFileLinkAction({
1592
- path: href,
1593
- workspaceRoot,
1594
- basePath,
1595
- source
1596
- }) ?? resolveWorkspaceUrlLinkAction({ url: href, source });
1597
- }
1598
- function normalizeWorkspaceFilePath(path) {
1599
- const normalizedPath = path.trim().replaceAll("\\", "/");
1600
- const drive = /^[A-Za-z]:/.exec(normalizedPath)?.[0] ?? "";
1601
- const startsWithSlash = normalizedPath.startsWith("/");
1602
- const pathBody = drive ? normalizedPath.slice(drive.length) : startsWithSlash ? normalizedPath.slice(1) : normalizedPath;
1603
- const parts = [];
1604
- for (const part of pathBody.split("/")) {
1605
- if (!part || part === ".") {
1606
- continue;
1607
- }
1608
- if (part === "..") {
1609
- parts.pop();
1610
- continue;
1611
- }
1612
- parts.push(part);
1613
- }
1614
- if (drive) {
1615
- return parts.length > 0 ? `${drive}/${parts.join("/")}` : `${drive}/`;
1616
- }
1617
- if (startsWithSlash) {
1618
- return parts.length > 0 ? `/${parts.join("/")}` : "/";
1619
- }
1620
- return parts.join("/");
1621
- }
1622
- function isUrlLikeWorkspaceFilePath(path) {
1623
- if (path.startsWith("#")) {
1624
- return true;
1625
- }
1626
- if (isWindowsAbsolutePath(path.trim().replaceAll("\\", "/"))) {
1627
- return false;
1628
- }
1629
- return URL_LIKE_LINK_PATTERN.test(path);
1630
- }
1631
- function isAbsoluteLocalPath(path) {
1632
- return path.startsWith("/") || isWindowsAbsolutePath(path);
1633
- }
1634
- function isWindowsAbsolutePath(path) {
1635
- return /^[A-Za-z]:\//.test(path);
1636
- }
1637
- function decodeWorkspaceLinkPath(path) {
1638
- if (!path.includes("%")) {
1639
- return path;
1640
- }
1641
- try {
1642
- return decodeURI(path);
1643
- } catch {
1644
- return path;
1645
- }
1646
- }
1647
- function dirname(path) {
1648
- const index = path.lastIndexOf("/");
1649
- if (index <= 0) {
1650
- return "/";
1651
- }
1652
- return path.slice(0, index);
1653
- }
1654
- function isInsideOrEqual(path, root) {
1655
- if (root === "/") {
1656
- return path.startsWith("/");
1657
- }
1658
- const comparison = isWindowsAbsolutePath(root) || isWindowsAbsolutePath(path) ? { path: path.toLowerCase(), root: root.toLowerCase() } : { path, root };
1659
- return comparison.path === comparison.root || comparison.path.startsWith(`${comparison.root}/`);
1660
- }
1661
- function isDirectAgentGeneratedImagePath(path) {
1662
- if (!isAbsoluteLocalPath(path)) {
1663
- return false;
1664
- }
1665
- const segments = path.split("/").filter(Boolean);
1666
- const stateRootIndex = segments.findIndex(
1667
- (segment) => segment === ".nextop" || segment === ".nextop-dev"
1668
- );
1669
- if (stateRootIndex < 0) {
1670
- return false;
1671
- }
1672
- const statePath = segments.slice(stateRootIndex);
1673
- if (statePath[1] !== "agent" || statePath[2] !== "runs" || !statePath.includes("generated_images")) {
1674
- return false;
1675
- }
1676
- return /\.(?:png|jpe?g|gif|webp|bmp)$/i.test(path);
1677
- }
1678
-
1679
- // shared/streamingMarkdownTailStabilizer.ts
1680
- var DEFAULT_MAX_TAIL_CHARS = 4096;
1681
- function stabilizeStreamingMarkdownTail(content, options) {
1682
- if (!options.streaming || content.length === 0) {
1683
- return { content, changed: false };
1684
- }
1685
- const maxTailChars = Math.max(
1686
- 256,
1687
- options.maxTailChars ?? DEFAULT_MAX_TAIL_CHARS
1688
- );
1689
- const tailStart = Math.max(0, content.length - maxTailChars);
1690
- const tail = content.slice(tailStart);
1691
- const fence = findOpenFence(tail);
1692
- if (fence) {
1693
- return {
1694
- content: `${content}
1695
- ${fence.marker.repeat(fence.length)}`,
1696
- changed: true,
1697
- reason: "open-fence"
1698
- };
1699
- }
1700
- const incompleteLink = stabilizeIncompleteTailLink(content);
1701
- if (incompleteLink) {
1702
- return incompleteLink;
1703
- }
1704
- const listMarker = stabilizeDanglingListMarker(content);
1705
- if (listMarker) {
1706
- return listMarker;
1707
- }
1708
- const tableRow = stabilizePartialTableRow(content);
1709
- if (tableRow) {
1710
- return tableRow;
1711
- }
1712
- const inlineCode = findOpenInlineCodeSpan(tail);
1713
- if (inlineCode) {
1714
- return {
1715
- content: `${content}${"`".repeat(inlineCode.length)}`,
1716
- changed: true,
1717
- reason: "open-inline-code"
1718
- };
1719
- }
1720
- const emphasis = stabilizeTrailingEmphasisMarker(content);
1721
- if (emphasis) {
1722
- return emphasis;
1723
- }
1724
- return { content, changed: false };
1725
- }
1726
- function findOpenFence(tail) {
1727
- let openFence = null;
1728
- for (const line of tail.replace(/\r\n?/g, "\n").split("\n")) {
1729
- const fence = parseFenceLine(line);
1730
- if (!fence) {
1731
- continue;
1732
- }
1733
- if (!openFence) {
1734
- openFence = fence;
1735
- continue;
1736
- }
1737
- if (fence.marker === openFence.marker && fence.length >= openFence.length) {
1738
- openFence = null;
1739
- }
1740
- }
1741
- return openFence;
1742
- }
1743
- function parseFenceLine(line) {
1744
- let index = 0;
1745
- while (index < line.length && line[index] === " " && index < 4) {
1746
- index += 1;
1747
- }
1748
- const marker = line[index];
1749
- if (marker !== "`" && marker !== "~") {
1750
- return null;
1751
- }
1752
- let length = 0;
1753
- while (line[index + length] === marker) {
1754
- length += 1;
1755
- }
1756
- return length >= 3 ? { marker, length } : null;
1757
- }
1758
- function stabilizeIncompleteTailLink(content) {
1759
- const lineStart = content.lastIndexOf("\n") + 1;
1760
- const line = content.slice(lineStart);
1761
- const linkStart = line.lastIndexOf("[");
1762
- const imageStart = line.lastIndexOf("![");
1763
- const openBracketIndex = imageStart >= 0 && imageStart + 1 === linkStart ? imageStart : linkStart;
1764
- if (openBracketIndex < 0) {
1765
- return null;
1766
- }
1767
- const absoluteOpenIndex = lineStart + openBracketIndex;
1768
- const suffix = content.slice(absoluteOpenIndex);
1769
- const closeLabelIndex = suffix.indexOf("]");
1770
- if (closeLabelIndex < 0) {
1771
- const label2 = suffix.startsWith("![") ? suffix.slice(2) : suffix.slice(1);
1772
- return {
1773
- content: `${content.slice(0, absoluteOpenIndex)}${label2}`,
1774
- changed: true,
1775
- reason: "incomplete-link-label"
1776
- };
1777
- }
1778
- if (suffix[closeLabelIndex + 1] !== "(" || suffix.includes(")")) {
1779
- return null;
1780
- }
1781
- const label = suffix.startsWith("![") ? suffix.slice(2, closeLabelIndex) : suffix.slice(1, closeLabelIndex);
1782
- return {
1783
- content: `${content.slice(0, absoluteOpenIndex)}${label}`,
1784
- changed: true,
1785
- reason: "incomplete-link-target"
1786
- };
1787
- }
1788
- function stabilizeDanglingListMarker(content) {
1789
- const lineStart = content.lastIndexOf("\n") + 1;
1790
- const line = content.slice(lineStart);
1791
- const trimmed = line.trim();
1792
- const isBullet = trimmed === "-" || trimmed === "*" || trimmed === "+";
1793
- const isOrdered = trimmed.length >= 2 && trimmed.endsWith(".") && [...trimmed.slice(0, -1)].every((char) => char >= "0" && char <= "9");
1794
- if (!isBullet && !isOrdered) {
1795
- return null;
1796
- }
1797
- return {
1798
- content: content.slice(0, lineStart),
1799
- changed: true,
1800
- reason: "dangling-list-marker"
1801
- };
1802
- }
1803
- function stabilizePartialTableRow(content) {
1804
- if (content.endsWith("\n")) {
1805
- return null;
1806
- }
1807
- const lines = content.replace(/\r\n?/g, "\n").split("\n");
1808
- const currentLine = lines.at(-1) ?? "";
1809
- const previousLine = lines.at(-2) ?? "";
1810
- if (!currentLine.includes("|") || !previousLine.includes("|")) {
1811
- return null;
1812
- }
1813
- if (currentLine.trimEnd().endsWith("|")) {
1814
- return null;
1815
- }
1816
- if (countChar(previousLine, "|") < 2) {
1817
- return null;
1818
- }
1819
- return {
1820
- content: `${content} |`,
1821
- changed: true,
1822
- reason: "partial-table-row"
1823
- };
1824
- }
1825
- function findOpenInlineCodeSpan(tail) {
1826
- const lastParagraph = tail.slice(tail.lastIndexOf("\n\n") + 2);
1827
- let openLength = 0;
1828
- for (let index = 0; index < lastParagraph.length; index += 1) {
1829
- if (lastParagraph[index] !== "`") {
1830
- continue;
1831
- }
1832
- let length = 1;
1833
- while (lastParagraph[index + length] === "`") {
1834
- length += 1;
1835
- }
1836
- if (length >= 3) {
1837
- index += length - 1;
1838
- continue;
1839
- }
1840
- openLength = openLength === length ? 0 : length;
1841
- index += length - 1;
1842
- }
1843
- return openLength > 0 ? { length: openLength } : null;
1844
- }
1845
- function stabilizeTrailingEmphasisMarker(content) {
1846
- const marker = content.at(-1);
1847
- if (marker !== "*" && marker !== "_") {
1848
- return null;
1849
- }
1850
- const previous = content.at(-2);
1851
- const nextContent = previous === marker ? content.slice(0, -2) : content.slice(0, -1);
1852
- return {
1853
- content: nextContent,
1854
- changed: true,
1855
- reason: "trailing-emphasis-marker"
1856
- };
1857
- }
1858
- function countChar(value, char) {
1859
- let count = 0;
1860
- for (const current of value) {
1861
- if (current === char) {
1862
- count += 1;
1863
- }
1864
- }
1865
- return count;
1866
- }
1867
-
1868
- // shared/useStreamingVisibleText.ts
1869
- import {
1870
- startTransition,
1871
- useEffect as useEffect3,
1872
- useRef as useRef3,
1873
- useState as useState2
1874
- } from "react";
1875
- var DEFAULT_FRAME_MS = 24;
1876
- var DEFAULT_MAX_CHARS_PER_SECOND = 6e3;
1877
- var DEFAULT_TRAILING_FLUSH_CHARS = 0;
1878
- function useStreamingVisibleText(sourceText, options) {
1879
- const {
1880
- enabled,
1881
- frameMs = DEFAULT_FRAME_MS,
1882
- maxCharsPerSecond = DEFAULT_MAX_CHARS_PER_SECOND,
1883
- trailingFlushChars = DEFAULT_TRAILING_FLUSH_CHARS
1884
- } = options;
1885
- const [visibleText, setVisibleText] = useState2(sourceText);
1886
- const sourceRef = useRef3(sourceText);
1887
- const visibleRef = useRef3(visibleText);
1888
- const timerRef = useRef3(null);
1889
- useEffect3(() => {
1890
- visibleRef.current = visibleText;
1891
- }, [visibleText]);
1892
- useEffect3(
1893
- () => () => {
1894
- clearStreamingVisibleTextTimer(timerRef);
1895
- },
1896
- []
1897
- );
1898
- useEffect3(() => {
1899
- sourceRef.current = sourceText;
1900
- if (!enabled) {
1901
- clearStreamingVisibleTextTimer(timerRef);
1902
- visibleRef.current = sourceText;
1903
- setVisibleText(sourceText);
1904
- return;
1905
- }
1906
- if (sourceText === visibleRef.current || timerRef.current !== null) {
1907
- return;
1908
- }
1909
- timerRef.current = setTimeout(
1910
- () => {
1911
- timerRef.current = null;
1912
- const nextVisibleText = advanceStreamingVisibleText({
1913
- visibleText: visibleRef.current,
1914
- sourceText: sourceRef.current,
1915
- frameMs,
1916
- maxCharsPerSecond,
1917
- trailingFlushChars
1918
- });
1919
- if (nextVisibleText === visibleRef.current) {
1920
- return;
1921
- }
1922
- visibleRef.current = nextVisibleText;
1923
- startTransition(() => {
1924
- setVisibleText(nextVisibleText);
1925
- });
1926
- },
1927
- Math.max(1, frameMs)
1928
- );
1929
- return void 0;
1930
- }, [
1931
- enabled,
1932
- frameMs,
1933
- maxCharsPerSecond,
1934
- sourceText,
1935
- trailingFlushChars,
1936
- visibleText
1937
- ]);
1938
- return enabled ? visibleText : sourceText;
1939
- }
1940
- function advanceStreamingVisibleText({
1941
- visibleText,
1942
- sourceText,
1943
- frameMs = DEFAULT_FRAME_MS,
1944
- maxCharsPerSecond = DEFAULT_MAX_CHARS_PER_SECOND,
1945
- trailingFlushChars = DEFAULT_TRAILING_FLUSH_CHARS
1946
- }) {
1947
- if (visibleText === sourceText) {
1948
- return visibleText;
1949
- }
1950
- const prefixLength = sourceText.startsWith(visibleText) ? visibleText.length : commonPrefixLength(visibleText, sourceText);
1951
- const stablePrefix = sourceText.slice(0, prefixLength);
1952
- const remainingLength = sourceText.length - prefixLength;
1953
- if (remainingLength <= trailingFlushChars) {
1954
- return sourceText;
1955
- }
1956
- const charsPerFrame = Math.max(
1957
- 1,
1958
- Math.ceil(Math.max(1, maxCharsPerSecond) * Math.max(1, frameMs) / 1e3)
1959
- );
1960
- return sourceText.slice(
1961
- 0,
1962
- Math.min(sourceText.length, stablePrefix.length + charsPerFrame)
1963
- );
1964
- }
1965
- function commonPrefixLength(left, right) {
1966
- const maxLength = Math.min(left.length, right.length);
1967
- for (let index = 0; index < maxLength; index += 1) {
1968
- if (left.charCodeAt(index) !== right.charCodeAt(index)) {
1969
- return index;
1970
- }
1971
- }
1972
- return maxLength;
1973
- }
1974
- function clearStreamingVisibleTextTimer(timerRef) {
1975
- if (timerRef.current === null) {
1976
- return;
1977
- }
1978
- clearTimeout(timerRef.current);
1979
- timerRef.current = null;
1980
- }
1981
-
1982
- // shared/AgentMessageMarkdown.tsx
1983
- import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1984
- var COLLAPSED_LINE_LIMIT = 8;
1985
- var APPROX_CHARS_PER_LINE = 34;
1986
- var DEFERRED_LONG_MARKDOWN_CHAR_THRESHOLD = 4096;
1987
- var STREAMING_MARKDOWN_EMERGENCY_PLAIN_CHAR_THRESHOLD = 96e3;
1988
- var DEFERRED_LONG_MARKDOWN_FALLBACK_DELAY_MS = 80;
1989
- var DEFERRED_LONG_MARKDOWN_IDLE_TIMEOUT_MS = 700;
1990
- var STREAMING_MARKDOWN_FRAME_MS = 24;
1991
- var STREAMING_MARKDOWN_MAX_CHARS_PER_SECOND = 6e3;
1992
- var STREAMING_MARKDOWN_TAIL_FLUSH_CHARS = 0;
1993
- var PLAIN_SESSION_MENTION_AGENT_LABELS = [
1994
- "Claude Code",
1995
- "Nexight",
1996
- "Codex"
1997
- ];
1998
- var MARKDOWN_SANITIZE_SCHEMA = {
1999
- ...defaultSchema,
2000
- protocols: {
2001
- ...defaultSchema.protocols,
2002
- href: [...defaultSchema.protocols?.href ?? [], "mention"]
2003
- }
2004
- };
2005
- var EMPTY_WORKSPACE_APP_ICONS = [];
2006
- var MarkdownLinkContext = createContext3(false);
2007
- function AgentMessageMarkdown({
2008
- content,
2009
- onLinkClick,
2010
- onLinkAction,
2011
- workspaceLinkContext = null,
2012
- workspaceAppIcons = EMPTY_WORKSPACE_APP_ICONS,
2013
- collapsible = false,
2014
- expandLabel,
2015
- className,
2016
- inline = false,
2017
- normalizePlainIssueMentionTitle = false,
2018
- deferLongContentRender = false,
2019
- enableImageZoom = false,
2020
- streaming = false
2021
- }) {
2022
- "use memo";
2023
- const { t } = useTranslation();
2024
- const visibleContent = useStreamingVisibleText(content, {
2025
- enabled: streaming,
2026
- frameMs: STREAMING_MARKDOWN_FRAME_MS,
2027
- maxCharsPerSecond: STREAMING_MARKDOWN_MAX_CHARS_PER_SECOND,
2028
- trailingFlushChars: STREAMING_MARKDOWN_TAIL_FLUSH_CHARS
2029
- });
2030
- const stabilizedContent = useMemo3(
2031
- () => stabilizeStreamingMarkdownTail(visibleContent, {
2032
- streaming
2033
- }).content,
2034
- [streaming, visibleContent]
2035
- );
2036
- const workspaceRoot = workspaceLinkContext?.workspaceRoot ?? null;
2037
- const basePath = workspaceLinkContext?.basePath ?? null;
2038
- const workspaceLinkSource = workspaceLinkContext?.source ?? null;
2039
- const [isExpanded, setIsExpanded] = useState3(false);
2040
- const resolvedExpandLabel = expandLabel ?? t("agentHost.workspaceAgentMessageExpand");
2041
- const shouldCollapse = collapsible && isLikelyLongerThanLineLimit(stabilizedContent);
2042
- const isCollapsed = shouldCollapse && !isExpanded;
2043
- const ContainerTag = inline ? "span" : "div";
2044
- const contentSignature = useMemo3(
2045
- () => hashMarkdownProfilerContent(stabilizedContent),
2046
- [stabilizedContent]
2047
- );
2048
- const normalizedContent = useMemo3(
2049
- () => linkBareLocalAbsolutePaths(
2050
- normalizeMentionMarkdownLinks(
2051
- normalizePlainIssueMentionTitle ? normalizePlainIssueMentionTitleContent(
2052
- normalizePlainSessionMentionTitle(stabilizedContent)
2053
- ) : normalizePlainSessionMentionTitle(stabilizedContent)
2054
- )
2055
- ),
2056
- [normalizePlainIssueMentionTitle, stabilizedContent]
2057
- );
2058
- const isMentionOnly = isMentionOnlyMarkdownContent(normalizedContent);
2059
- const shouldDeferMarkdownRender = deferLongContentRender && !inline && content.length >= (streaming ? STREAMING_MARKDOWN_EMERGENCY_PLAIN_CHAR_THRESHOLD : DEFERRED_LONG_MARKDOWN_CHAR_THRESHOLD) && !isExpanded;
2060
- const markdownRenderReady = useDeferredMarkdownRenderReady(
2061
- contentSignature,
2062
- shouldDeferMarkdownRender
2063
- );
2064
- const handleLinkClick = useCallback3(
2065
- (href) => {
2066
- if (workspaceLinkSource && onLinkAction) {
2067
- const action = resolveWorkspaceLinkAction({
2068
- href,
2069
- workspaceRoot,
2070
- basePath,
2071
- source: workspaceLinkSource
2072
- });
2073
- if (action) {
2074
- onLinkAction(action);
2075
- return;
2076
- }
2077
- }
2078
- onLinkClick?.(href);
2079
- },
2080
- [basePath, onLinkAction, onLinkClick, workspaceLinkSource, workspaceRoot]
2081
- );
2082
- const handleAnchorClickCapture = useCallback3(
2083
- (event) => {
2084
- const href = resolveMarkdownAnchorHref(event.target);
2085
- if (!href) {
2086
- return;
2087
- }
2088
- event.preventDefault();
2089
- event.stopPropagation();
2090
- handleLinkClick(href);
2091
- },
2092
- [handleLinkClick]
2093
- );
2094
- const markdownComponents = useMemo3(
2095
- () => ({
2096
- a: (props) => /* @__PURE__ */ jsx6(
2097
- MarkdownLink,
2098
- {
2099
- ...props,
2100
- onLinkClick: handleLinkClick,
2101
- workspaceAppIcons
2102
- }
2103
- ),
2104
- code: (props) => /* @__PURE__ */ jsx6(MarkdownCode, { ...props, onLinkClick: handleLinkClick }),
2105
- img: (props) => /* @__PURE__ */ jsx6(MarkdownImage, { ...props, enableZoom: enableImageZoom }),
2106
- p: (props) => /* @__PURE__ */ jsx6(MarkdownParagraph, { ...props, inline }),
2107
- ul: MarkdownUnorderedList,
2108
- ol: MarkdownOrderedList,
2109
- li: MarkdownListItem
2110
- }),
2111
- [enableImageZoom, handleLinkClick, inline, workspaceAppIcons]
2112
- );
2113
- return /* @__PURE__ */ jsxs4(
2114
- ContainerTag,
2115
- {
2116
- className: "flex w-full min-w-0 flex-col items-start gap-1",
2117
- "data-workspace-agent-markdown-shell": "true",
2118
- children: [
2119
- /* @__PURE__ */ jsx6(
2120
- ContainerTag,
2121
- {
2122
- className: cn(
2123
- "relative w-full min-w-0 overflow-x-auto text-[13px] leading-[1.5] text-[var(--text-primary)] [overflow-wrap:anywhere]",
2124
- "[&_>table:first-child]:mt-0 [&_p]:mb-2 [&_pre]:mb-2 [&_blockquote]:mb-2",
2125
- "[&_hr]:my-4 [&_hr]:h-0 [&_hr]:border-0 [&_hr]:border-t [&_hr]:border-t-[color-mix(in_srgb,var(--text-primary)_14%,transparent)]",
2126
- "[&_ul]:my-2 [&_ul]:max-w-full [&_ul]:rounded-[8px] [&_ul]:border [&_ul]:border-[var(--line-2)] [&_ul]:bg-[var(--background-panel)] [&_ul]:px-4 [&_ul]:py-2",
2127
- "[&_ol]:my-2 [&_ol]:max-w-full [&_ol]:rounded-[8px] [&_ol]:border [&_ol]:border-[var(--line-2)] [&_ol]:bg-[var(--background-panel)] [&_ol]:px-4 [&_ol]:py-2",
2128
- "[&_li>ul]:mt-1.5 [&_li>ul]:mb-0.5 [&_li>ul]:border-0 [&_li>ul]:px-0 [&_li>ul]:py-1",
2129
- "[&_li>ol]:mt-1.5 [&_li>ol]:mb-0.5 [&_li>ol]:border-0 [&_li>ol]:px-0 [&_li>ol]:py-1",
2130
- "[&_table]:my-2 [&_table]:w-max [&_table]:min-w-full [&_table]:max-w-full [&_table]:border-separate [&_table]:border-spacing-0 [&_table]:overflow-hidden [&_table]:rounded-[8px] [&_table]:border [&_table]:border-[var(--line-2)] [&_table]:text-[13px] [&_table]:leading-[1.45]",
2131
- "[&_th]:max-w-[280px] [&_th]:border-r [&_th]:border-b [&_th]:border-[var(--line-2)] [&_th]:px-2 [&_th]:py-1.5 [&_th]:align-top [&_th]:font-semibold [&_th]:text-[var(--text-primary)] [&_th]:[overflow-wrap:anywhere] [&_th]:bg-[color-mix(in_srgb,var(--background-panel)_94%,var(--text-primary))]",
2132
- "[&_td]:max-w-[280px] [&_td]:border-r [&_td]:border-b [&_td]:border-[var(--line-2)] [&_td]:px-2 [&_td]:py-1.5 [&_td]:align-top [&_td]:[overflow-wrap:anywhere]",
2133
- "[&_tr:last-child_th]:border-b-0 [&_tr:last-child_td]:border-b-0 [&_th:last-child]:border-r-0 [&_td:last-child]:border-r-0",
2134
- "[&_a]:cursor-pointer [&_a]:font-semibold [&_a]:text-[var(--tutti-purple)] [&_a]:no-underline [&_a:hover]:underline [&_a:focus-visible]:underline",
2135
- "[&_strong]:font-semibold",
2136
- "[&_code]:inline [&_code]:rounded-[2px] [&_code]:bg-[var(--transparency-block)] [&_code]:px-1 [&_code]:py-[1px] [&_code]:font-[var(--tsh-font-mono)] [&_code]:text-[11px] [&_code]:leading-[1.35] [&_code]:text-[var(--text-primary)] [&_code]:[box-decoration-break:clone] [&_code]:[-webkit-box-decoration-break:clone] [&_code]:[overflow-wrap:anywhere] [&_code]:[word-break:break-word]",
2137
- "[&_pre]:box-border [&_pre]:overflow-auto [&_pre]:rounded-[6px] [&_pre]:bg-[var(--transparency-block)] [&_pre]:px-2.5 [&_pre]:py-2",
2138
- "[&_pre_code]:inline [&_pre_code]:h-auto [&_pre_code]:items-normal [&_pre_code]:rounded-none [&_pre_code]:bg-transparent [&_pre_code]:p-0 [&_pre_code]:text-[inherit] [&_pre_code]:leading-[inherit] [&_pre_code]:[white-space:pre-wrap] [&_pre_code]:[overflow-wrap:anywhere] [&_pre_code]:[word-break:break-word]",
2139
- "[&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
2140
- inline && "inline min-w-0 overflow-hidden align-baseline [&_p]:inline [&_p]:m-0",
2141
- shouldCollapse && "overflow-hidden transition-[max-height] duration-220 ease-out",
2142
- isCollapsed && "max-h-[calc(13px*1.5*8)] overflow-hidden [mask-image:linear-gradient(180deg,black_0%,black_calc(100%_-_36px),transparent_100%)] [-webkit-mask-image:linear-gradient(180deg,black_0%,black_calc(100%_-_36px),transparent_100%)] [&_pre]:overflow-hidden",
2143
- shouldCollapse && !isCollapsed && "max-h-[72rem]",
2144
- className
2145
- ),
2146
- "data-workspace-agent-markdown": "true",
2147
- "data-agent-mention-only": isMentionOnly ? "true" : void 0,
2148
- "data-collapsed": isCollapsed ? "true" : "false",
2149
- onClickCapture: handleAnchorClickCapture,
2150
- children: markdownRenderReady ? streaming ? /* @__PURE__ */ jsx6(
2151
- StreamingMarkdownBlocks,
2152
- {
2153
- content: normalizedContent,
2154
- components: markdownComponents
2155
- }
2156
- ) : /* @__PURE__ */ jsx6(
2157
- ReactMarkdown,
2158
- {
2159
- remarkPlugins: [remarkGfm],
2160
- rehypePlugins: [[rehypeSanitize, MARKDOWN_SANITIZE_SCHEMA]],
2161
- urlTransform: markdownUrlTransform,
2162
- components: markdownComponents,
2163
- children: normalizedContent
2164
- }
2165
- ) : /* @__PURE__ */ jsx6(
2166
- "div",
2167
- {
2168
- className: "whitespace-pre-wrap [overflow-wrap:anywhere]",
2169
- "data-workspace-agent-markdown-deferred": "true",
2170
- children: normalizedContent
2171
- }
2172
- )
2173
- }
2174
- ),
2175
- shouldCollapse && !isExpanded ? /* @__PURE__ */ jsx6(
2176
- "button",
2177
- {
2178
- type: "button",
2179
- className: "m-0 border-0 bg-transparent p-0 text-[11px] leading-[1.4] font-semibold text-[var(--tutti-purple)] hover:underline focus-visible:underline focus-visible:outline-none",
2180
- onClick: () => setIsExpanded(true),
2181
- children: resolvedExpandLabel
2182
- }
2183
- ) : null
2184
- ]
2185
- }
2186
- );
2187
- }
2188
- function StreamingMarkdownBlocks({
2189
- content,
2190
- components
2191
- }) {
2192
- const blocks = useMemo3(
2193
- () => splitStreamingMarkdownBlocks(content),
2194
- [content]
2195
- );
2196
- return /* @__PURE__ */ jsx6(Fragment2, { children: blocks.map((block, index) => /* @__PURE__ */ jsx6(
2197
- MemoizedMarkdownBlock,
2198
- {
2199
- content: block.content,
2200
- components
2201
- },
2202
- `${index}:${hashMarkdownProfilerContent(block.initialKeyContent)}`
2203
- )) });
2204
- }
2205
- var MemoizedMarkdownBlock = memo(function MemoizedMarkdownBlock2({
2206
- content,
2207
- components
2208
- }) {
2209
- return /* @__PURE__ */ jsx6(
2210
- ReactMarkdown,
2211
- {
2212
- remarkPlugins: [remarkGfm],
2213
- rehypePlugins: [[rehypeSanitize, MARKDOWN_SANITIZE_SCHEMA]],
2214
- urlTransform: markdownUrlTransform,
2215
- components,
2216
- children: content
2217
- }
2218
- );
2219
- });
2220
- function splitStreamingMarkdownBlocks(content) {
2221
- const normalized = content.replace(/\r\n?/g, "\n");
2222
- if (!normalized) {
2223
- return [{ content: "", initialKeyContent: "" }];
2224
- }
2225
- const lines = normalized.split("\n");
2226
- const blocks = [];
2227
- const current = [];
2228
- let fence = null;
2229
- for (const line of lines) {
2230
- current.push(line);
2231
- const lineFence = parseStreamingFence(line);
2232
- if (lineFence) {
2233
- if (!fence) {
2234
- fence = lineFence;
2235
- } else if (lineFence.marker === fence.marker && lineFence.length >= fence.length) {
2236
- fence = null;
2237
- }
2238
- continue;
2239
- }
2240
- if (!fence && line.trim() === "") {
2241
- pushStreamingMarkdownBlock(blocks, current);
2242
- }
2243
- }
2244
- pushStreamingMarkdownBlock(blocks, current);
2245
- return blocks.length > 0 ? blocks : [{ content: normalized, initialKeyContent: normalized }];
2246
- }
2247
- function pushStreamingMarkdownBlock(blocks, lines) {
2248
- if (lines.length === 0) {
2249
- return;
2250
- }
2251
- const content = lines.join("\n");
2252
- if (!content) {
2253
- lines.length = 0;
2254
- return;
2255
- }
2256
- blocks.push({
2257
- content,
2258
- initialKeyContent: content
2259
- });
2260
- lines.length = 0;
2261
- }
2262
- function parseStreamingFence(line) {
2263
- const trimmed = line.trimStart();
2264
- const marker = trimmed[0];
2265
- if (marker !== "`" && marker !== "~") {
2266
- return null;
2267
- }
2268
- let length = 0;
2269
- while (trimmed[length] === marker) {
2270
- length += 1;
2271
- }
2272
- return length >= 3 ? { marker, length } : null;
2273
- }
2274
- function resolveMarkdownAnchorHref(target) {
2275
- if (!(target instanceof Element)) {
2276
- return null;
2277
- }
2278
- const link = target.closest("[data-agent-link-href],a[href]");
2279
- if (!(link instanceof HTMLElement)) {
2280
- return null;
2281
- }
2282
- const dataHref = link.dataset.agentLinkHref?.trim();
2283
- if (dataHref) {
2284
- return dataHref;
2285
- }
2286
- if (link instanceof HTMLAnchorElement) {
2287
- return link.getAttribute("href")?.trim() || null;
2288
- }
2289
- return null;
2290
- }
2291
- function activateMarkdownLink(event, href, onLinkClick) {
2292
- const target = href.trim();
2293
- if (!target) {
2294
- return;
2295
- }
2296
- event.preventDefault();
2297
- event.stopPropagation();
2298
- onLinkClick?.(target);
2299
- }
2300
- function activateMarkdownLinkFromKey(event, href, onLinkClick) {
2301
- if (event.key !== "Enter" && event.key !== " ") {
2302
- return;
2303
- }
2304
- activateMarkdownLink(event, href, onLinkClick);
2305
- }
2306
- function activateMarkdownLinkFromPointer(event, href, onLinkClick) {
2307
- if (event.button !== 0) {
2308
- return;
2309
- }
2310
- activateMarkdownLink(event, href, onLinkClick);
2311
- }
2312
- function useDeferredMarkdownRenderReady(contentSignature, shouldDefer) {
2313
- const [readySignature, setReadySignature] = useState3(
2314
- shouldDefer ? null : contentSignature
2315
- );
2316
- const renderReady = !shouldDefer || readySignature === contentSignature;
2317
- useEffect4(() => {
2318
- if (!shouldDefer) {
2319
- setReadySignature(contentSignature);
2320
- return;
2321
- }
2322
- let canceled = false;
2323
- let timeoutId = null;
2324
- let idleCallbackId = null;
2325
- const markReady = () => {
2326
- if (canceled) {
2327
- return;
2328
- }
2329
- startTransition2(() => {
2330
- setReadySignature(contentSignature);
2331
- });
2332
- };
2333
- if ("requestIdleCallback" in window) {
2334
- idleCallbackId = window.requestIdleCallback(markReady, {
2335
- timeout: DEFERRED_LONG_MARKDOWN_IDLE_TIMEOUT_MS
2336
- });
2337
- } else {
2338
- timeoutId = setTimeout(
2339
- markReady,
2340
- DEFERRED_LONG_MARKDOWN_FALLBACK_DELAY_MS
2341
- );
2342
- }
2343
- return () => {
2344
- canceled = true;
2345
- if (idleCallbackId !== null) {
2346
- window.cancelIdleCallback(idleCallbackId);
2347
- }
2348
- if (timeoutId !== null) {
2349
- clearTimeout(timeoutId);
2350
- }
2351
- };
2352
- }, [contentSignature, shouldDefer]);
2353
- return renderReady;
2354
- }
2355
- function hashMarkdownProfilerContent(content) {
2356
- let hash = 0;
2357
- for (let index = 0; index < content.length; index += 1) {
2358
- hash = hash * 31 + content.charCodeAt(index) | 0;
2359
- }
2360
- return `${content.length}:${Math.abs(hash)}`;
2361
- }
2362
- function isLikelyLongerThanLineLimit(content) {
2363
- const normalizedLines = content.replace(/\r\n?/g, "\n").split("\n");
2364
- if (normalizedLines.length > COLLAPSED_LINE_LIMIT) {
2365
- return true;
2366
- }
2367
- const estimatedLineCount = normalizedLines.reduce((total, line) => {
2368
- const trimmed = line.trim();
2369
- const blockSpacing = /^(#{1,6}\s|\s*[-*+]\s|\s*\d+\.\s|>)/.test(trimmed) ? 1 : 0;
2370
- return total + Math.max(1, Math.ceil(trimmed.length / APPROX_CHARS_PER_LINE)) + blockSpacing;
2371
- }, 0);
2372
- return estimatedLineCount > COLLAPSED_LINE_LIMIT;
2373
- }
2374
- function MarkdownLink({
2375
- node: _node,
2376
- onClick: _onClick,
2377
- onLinkClick,
2378
- workspaceAppIcons,
2379
- href,
2380
- ...props
2381
- }) {
2382
- "use memo";
2383
- const { t } = useTranslation();
2384
- const targetHref = href?.trim() ?? "";
2385
- const mention = targetHref ? parseMentionLink(
2386
- targetHref,
2387
- textFromReactNode(props.children),
2388
- workspaceAppIcons ?? [],
2389
- t("agentHost.agentGui.workspaceAppFactoryMentionFallback")
2390
- ) : null;
2391
- if (mention) {
2392
- return /* @__PURE__ */ jsx6(
2393
- MentionLink,
2394
- {
2395
- ...props,
2396
- href: targetHref,
2397
- mention,
2398
- onLinkClick
2399
- }
2400
- );
2401
- }
2402
- const fileMention = targetHref ? parseWorkspaceFileMentionLink(
2403
- targetHref,
2404
- textFromReactNode(props.children)
2405
- ) : null;
2406
- if (fileMention) {
2407
- return /* @__PURE__ */ jsx6(
2408
- WorkspaceFileMentionLink,
2409
- {
2410
- ...props,
2411
- href: targetHref,
2412
- mention: fileMention,
2413
- onLinkClick
2414
- }
2415
- );
2416
- }
2417
- return /* @__PURE__ */ jsx6(MarkdownLinkContext.Provider, { value: true, children: /* @__PURE__ */ jsx6(
2418
- "a",
2419
- {
2420
- ...props,
2421
- "data-agent-link-href": targetHref,
2422
- role: "link",
2423
- tabIndex: 0,
2424
- onClick: (event) => {
2425
- activateMarkdownLink(event, targetHref, onLinkClick);
2426
- },
2427
- onPointerDown: (event) => {
2428
- activateMarkdownLinkFromPointer(event, targetHref, onLinkClick);
2429
- },
2430
- onKeyDown: (event) => {
2431
- activateMarkdownLinkFromKey(event, targetHref, onLinkClick);
2432
- }
2433
- }
2434
- ) });
2435
- }
2436
- function parseWorkspaceFileMentionTarget(href) {
2437
- const target = href.trim();
2438
- if (!isLocalAbsolutePath(target)) {
2439
- return null;
2440
- }
2441
- let url;
2442
- try {
2443
- url = new URL(target, "https://tsh.local");
2444
- } catch {
2445
- return null;
2446
- }
2447
- const explicitKindValue = url.searchParams.get("kind") ?? url.searchParams.get("refType") ?? url.searchParams.get("entryKind") ?? "";
2448
- const normalizedKind = explicitKindValue.trim().toLowerCase();
2449
- const explicitKind = normalizedKind === "folder" || normalizedKind === "directory" ? "directory" : normalizedKind === "file" ? "file" : null;
2450
- const path = url.pathname.replace(/\/+$/, "");
2451
- if (!path || path === "/") {
2452
- return null;
2453
- }
2454
- return {
2455
- path,
2456
- explicitKind: explicitKind ?? (url.pathname.endsWith("/") ? "directory" : null)
2457
- };
2458
- }
2459
- function resolveWorkspaceFileMentionEntryKind(path, label, explicitKind) {
2460
- if (explicitKind) {
2461
- return explicitKind;
2462
- }
2463
- if (resolveWorkspaceFileExtension(path)) {
2464
- return "file";
2465
- }
2466
- const basename = basenameWorkspacePath(path);
2467
- return basename === label ? "directory" : "file";
2468
- }
2469
- function parseWorkspaceFileMentionLink(href, rawLabel) {
2470
- const label = rawLabel.trim();
2471
- const target = parseWorkspaceFileMentionTarget(href);
2472
- if (!target || !label.startsWith("@")) {
2473
- return null;
2474
- }
2475
- const fileLabel = label.replace(/^@+/, "").trim();
2476
- if (!fileLabel) {
2477
- return null;
2478
- }
2479
- const entryKind = resolveWorkspaceFileMentionEntryKind(
2480
- target.path,
2481
- fileLabel,
2482
- target.explicitKind
2483
- );
2484
- return {
2485
- label: fileLabel,
2486
- href: target.path,
2487
- entryKind,
2488
- visualKind: resolveAgentWorkspaceFileVisualKind(target.path, {
2489
- refType: entryKind === "directory" ? "folder" : "file"
2490
- })
2491
- };
2492
- }
2493
- function WorkspaceFileMentionLink({
2494
- onClick: _onClick,
2495
- onLinkClick,
2496
- href: _href,
2497
- mention,
2498
- ...props
2499
- }) {
2500
- "use memo";
2501
- return /* @__PURE__ */ jsxs4(
2502
- "a",
2503
- {
2504
- ...props,
2505
- className: cn(
2506
- "tsh-workspace-file-link tsh-agent-object-token tsh-agent-object-token--file",
2507
- props.className
2508
- ),
2509
- "data-agent-file-mention": "true",
2510
- "data-agent-mention-kind": "file",
2511
- "data-agent-file-entry-kind": mention.entryKind,
2512
- "data-agent-file-visual-kind": mention.visualKind,
2513
- "data-agent-link-href": mention.href,
2514
- "data-agent-mention-href": mention.href,
2515
- "aria-label": mention.label,
2516
- role: "link",
2517
- tabIndex: 0,
2518
- onClick: (event) => {
2519
- activateMarkdownLink(event, mention.href, onLinkClick);
2520
- },
2521
- onPointerDown: (event) => {
2522
- activateMarkdownLinkFromPointer(event, mention.href, onLinkClick);
2523
- },
2524
- onKeyDown: (event) => {
2525
- activateMarkdownLinkFromKey(event, mention.href, onLinkClick);
2526
- },
2527
- children: [
2528
- /* @__PURE__ */ jsx6("span", { className: "tsh-agent-object-token__icon", "aria-hidden": "true" }),
2529
- /* @__PURE__ */ jsx6("span", { className: "tsh-agent-object-token__main", children: mention.label })
2530
- ]
2531
- }
2532
- );
2533
- }
2534
- function MentionLink({
2535
- onClick: _onClick,
2536
- onLinkClick,
2537
- href,
2538
- mention,
2539
- ...props
2540
- }) {
2541
- "use memo";
2542
- return /* @__PURE__ */ jsxs4(
2543
- "a",
2544
- {
2545
- ...props,
2546
- className: cn(
2547
- "tsh-agent-object-token tsh-agent-object-token--entity",
2548
- props.className
2549
- ),
2550
- "data-agent-file-mention": "true",
2551
- "data-agent-link-href": href,
2552
- "data-agent-mention-icon-url": mention.iconUrl,
2553
- "data-agent-mention-href": href,
2554
- "data-agent-mention-kind": mention.kind,
2555
- "aria-label": mention.label,
2556
- role: "link",
2557
- tabIndex: 0,
2558
- onClick: (event) => {
2559
- activateMarkdownLink(event, href, onLinkClick);
2560
- },
2561
- onPointerDown: (event) => {
2562
- activateMarkdownLinkFromPointer(event, href, onLinkClick);
2563
- },
2564
- onKeyDown: (event) => {
2565
- activateMarkdownLinkFromKey(event, href, onLinkClick);
2566
- },
2567
- children: [
2568
- mention.kind === "workspace-app" ? /* @__PURE__ */ jsx6(
2569
- "span",
2570
- {
2571
- className: "grid h-4 w-4 shrink-0 place-items-center overflow-hidden rounded-[4px] bg-block",
2572
- "aria-hidden": "true",
2573
- "data-agent-mention-app-icon": "true",
2574
- "data-workspace-app-icon": "true",
2575
- children: mention.iconUrl ? /* @__PURE__ */ jsx6(
2576
- "img",
2577
- {
2578
- src: mention.iconUrl,
2579
- alt: "",
2580
- className: "h-full w-full object-cover",
2581
- decoding: "async",
2582
- loading: "lazy",
2583
- draggable: false
2584
- }
2585
- ) : /* @__PURE__ */ jsx6("span", { className: "tsh-agent-object-token__kind-icon h-4 w-4" })
2586
- }
2587
- ) : /* @__PURE__ */ jsx6("span", { className: "tsh-agent-object-token__kind", "aria-hidden": "true", children: /* @__PURE__ */ jsx6(
2588
- "span",
2589
- {
2590
- className: "tsh-agent-object-token__kind-icon",
2591
- "aria-hidden": "true"
2592
- }
2593
- ) }),
2594
- mention.kind === "session" ? /* @__PURE__ */ jsxs4("span", { className: "tsh-agent-object-token__main", children: [
2595
- /* @__PURE__ */ jsx6("span", { className: "tsh-agent-object-token__participant", children: mention.participant }),
2596
- mention.summary ? /* @__PURE__ */ jsxs4("span", { className: "tsh-agent-object-token__summary", children: [
2597
- " ",
2598
- mention.summary
2599
- ] }) : null
2600
- ] }) : /* @__PURE__ */ jsx6("span", { className: "tsh-agent-object-token__main", children: mention.label })
2601
- ]
2602
- }
2603
- );
2604
- }
2605
- function MarkdownCode({
2606
- node: _node,
2607
- children,
2608
- className,
2609
- onLinkClick,
2610
- ...props
2611
- }) {
2612
- "use memo";
2613
- const text = textFromReactNode(children).trim();
2614
- if (!className && onLinkClick && (isLocalAbsolutePath(text) || isHttpUrl(text))) {
2615
- return /* @__PURE__ */ jsx6("code", { ...props, className, children: /* @__PURE__ */ jsx6(PathLink, { href: text, onLinkClick, children }) });
2616
- }
2617
- return /* @__PURE__ */ jsx6("code", { ...props, className, children });
2618
- }
2619
- var cachedMarkdownImages = /* @__PURE__ */ new Map();
2620
- var CACHED_MARKDOWN_IMAGE_REVOKE_DELAY_MS = 250;
2621
- function MarkdownImage({
2622
- node: _node,
2623
- src,
2624
- alt,
2625
- className,
2626
- enableZoom = false,
2627
- ...props
2628
- }) {
2629
- "use memo";
2630
- const { t } = useTranslation();
2631
- const isInsideLink = useContext3(MarkdownLinkContext);
2632
- const agentHostApi = useOptionalAgentHostApi() ?? getOptionalAgentHostApi();
2633
- const workspacePath = typeof src === "string" && isLocalAbsolutePath(src) ? src.trim() : null;
2634
- const readWorkspaceImage = workspacePath ? agentHostApi?.workspace?.readFile : void 0;
2635
- const canReadWorkspaceImage = Boolean(workspacePath && readWorkspaceImage);
2636
- const shouldEnableZoom = enableZoom && !isInsideLink;
2637
- const resolvedSrc = typeof src === "string" ? resolveRenderableMarkdownImageSrc(src) : src;
2638
- const [state, setState] = useState3(
2639
- () => canReadWorkspaceImage && workspacePath ? peekCachedMarkdownImageState(workspacePath) ?? { status: "loading" } : null
2640
- );
2641
- useEffect4(() => {
2642
- if (!workspacePath || !readWorkspaceImage) {
2643
- setState(null);
2644
- return;
2645
- }
2646
- const resolvedWorkspacePath = workspacePath;
2647
- const resolvedReadWorkspaceImage = readWorkspaceImage;
2648
- const cachedSrc = retainCachedMarkdownImage(resolvedWorkspacePath);
2649
- if (cachedSrc) {
2650
- setState({ status: "ready", src: cachedSrc });
2651
- return () => {
2652
- releaseCachedMarkdownImage(resolvedWorkspacePath, cachedSrc);
2653
- };
2654
- }
2655
- const resolvedMimeType = resolveWorkspaceImageMimeType(
2656
- resolvedWorkspacePath
2657
- );
2658
- if (!resolvedMimeType) {
2659
- setState({
2660
- status: "error",
2661
- reason: "unsupported"
2662
- });
2663
- return;
2664
- }
2665
- const imageMimeType = resolvedMimeType;
2666
- let canceled = false;
2667
- let objectUrl = null;
2668
- setState({ status: "loading" });
2669
- async function loadWorkspaceImage() {
2670
- try {
2671
- const result = await resolvedReadWorkspaceImage({
2672
- path: resolvedWorkspacePath
2673
- });
2674
- if (canceled) {
2675
- return;
2676
- }
2677
- const bytes = result.bytes instanceof Uint8Array ? result.bytes : new Uint8Array(result.bytes);
2678
- const arrayBuffer = bytes.buffer.slice(
2679
- bytes.byteOffset,
2680
- bytes.byteOffset + bytes.byteLength
2681
- );
2682
- objectUrl = cacheMarkdownImage(
2683
- resolvedWorkspacePath,
2684
- new Blob([arrayBuffer], { type: imageMimeType })
2685
- );
2686
- setState({ status: "ready", src: objectUrl });
2687
- } catch (error) {
2688
- if (!canceled) {
2689
- setState({
2690
- status: "error",
2691
- reason: "read-failed",
2692
- detail: error instanceof Error ? error.message : String(error)
2693
- });
2694
- }
2695
- }
2696
- }
2697
- void loadWorkspaceImage();
2698
- return () => {
2699
- canceled = true;
2700
- if (objectUrl) {
2701
- releaseCachedMarkdownImage(resolvedWorkspacePath, objectUrl);
2702
- }
2703
- };
2704
- }, [canReadWorkspaceImage, workspacePath]);
2705
- if (!workspacePath || !readWorkspaceImage) {
2706
- if (!shouldEnableZoom) {
2707
- return /* @__PURE__ */ jsx6("img", { ...props, src: resolvedSrc, alt, className });
2708
- }
2709
- return /* @__PURE__ */ jsx6(
2710
- ZoomableImage,
2711
- {
2712
- ...props,
2713
- src: resolvedSrc,
2714
- alt,
2715
- className,
2716
- wrapElement: "span"
2717
- }
2718
- );
2719
- }
2720
- if (state?.status === "ready") {
2721
- if (!shouldEnableZoom) {
2722
- return /* @__PURE__ */ jsx6(
2723
- "img",
2724
- {
2725
- ...props,
2726
- src: state.src,
2727
- alt,
2728
- className: cn(
2729
- "block max-h-[360px] max-w-full rounded-[8px] border border-[var(--line-2)] bg-[var(--background-panel)] object-contain",
2730
- className
2731
- )
2732
- }
2733
- );
2734
- }
2735
- return /* @__PURE__ */ jsx6(
2736
- ZoomableImage,
2737
- {
2738
- ...props,
2739
- src: state.src,
2740
- alt,
2741
- className: cn(
2742
- "block max-h-[360px] max-w-full rounded-[8px] border border-[var(--line-2)] bg-[var(--background-panel)] object-contain",
2743
- className
2744
- ),
2745
- wrapElement: "span"
2746
- }
2747
- );
2748
- }
2749
- return /* @__PURE__ */ jsx6("span", { className: "flex min-h-[160px] w-full items-center justify-center rounded-[8px] border border-[var(--line-2)] bg-[var(--background-panel)] px-5 py-5 text-center text-[13px] leading-5 text-[var(--text-tertiary)]", children: state?.status === "error" ? state.reason === "unsupported" ? t("agentHost.workspaceFileManager.previewUnsupported") : t("agentHost.workspaceFileManager.previewReadFailed", {
2750
- message: state.detail ?? ""
2751
- }) : t("agentHost.workspaceFileManager.previewLoading") });
2752
- }
2753
- var MARKDOWN_ORDERED_LIST_STYLE = {
2754
- listStylePosition: "outside",
2755
- margin: "12px 0 8px",
2756
- paddingInlineStart: 34,
2757
- paddingInlineEnd: 16
2758
- };
2759
- var MARKDOWN_UNORDERED_LIST_STYLE = {
2760
- margin: "12px 0 8px",
2761
- paddingInlineStart: 0
2762
- };
2763
- var MARKDOWN_LIST_ITEM_STYLE = {
2764
- margin: "4px 0"
2765
- };
2766
- function MarkdownUnorderedList({
2767
- node: _node,
2768
- className,
2769
- style,
2770
- ...props
2771
- }) {
2772
- "use memo";
2773
- return /* @__PURE__ */ jsx6(
2774
- "ul",
2775
- {
2776
- ...props,
2777
- className: cn(
2778
- '[&_li]:relative [&_li]:list-none [&_li]:pl-[34px] [&_li::before]:absolute [&_li::before]:left-4 [&_li::before]:top-[0.78em] [&_li::before]:h-1.5 [&_li::before]:w-1.5 [&_li::before]:-translate-y-1/2 [&_li::before]:rounded-full [&_li::before]:bg-[var(--text-tertiary)] [&_li::before]:content-[""]',
2779
- className
2780
- ),
2781
- style: { ...MARKDOWN_UNORDERED_LIST_STYLE, ...style }
2782
- }
2783
- );
2784
- }
2785
- function MarkdownOrderedList({
2786
- node: _node,
2787
- style,
2788
- ...props
2789
- }) {
2790
- "use memo";
2791
- return /* @__PURE__ */ jsx6(
2792
- "ol",
2793
- {
2794
- ...props,
2795
- style: {
2796
- ...MARKDOWN_ORDERED_LIST_STYLE,
2797
- listStyleType: "decimal",
2798
- ...style
2799
- }
2800
- }
2801
- );
2802
- }
2803
- function MarkdownListItem({
2804
- node: _node,
2805
- style,
2806
- ...props
2807
- }) {
2808
- "use memo";
2809
- return /* @__PURE__ */ jsx6("li", { ...props, style: { ...MARKDOWN_LIST_ITEM_STYLE, ...style } });
2810
- }
2811
- function MarkdownParagraph({
2812
- node: _node,
2813
- inline,
2814
- ...props
2815
- }) {
2816
- "use memo";
2817
- if (inline) {
2818
- return /* @__PURE__ */ jsx6("span", { ...props });
2819
- }
2820
- return /* @__PURE__ */ jsx6("p", { ...props });
2821
- }
2822
- function isLocalAbsolutePath(path) {
2823
- const candidate = path.trim();
2824
- return candidate.length > 1 && candidate.startsWith("/") && !candidate.startsWith("//") && !candidate.includes("://") && !/\s/.test(candidate);
2825
- }
2826
- function resolveRenderableMarkdownImageSrc(src) {
2827
- const trimmed = src.trim();
2828
- if (!trimmed) {
2829
- return src;
2830
- }
2831
- if (!isLocalAbsolutePath(trimmed) || trimmed.startsWith("/workspace/")) {
2832
- return src;
2833
- }
2834
- return new URL(trimmed, "file://").toString();
2835
- }
2836
- function peekCachedMarkdownImageState(path) {
2837
- const src = cachedMarkdownImages.get(path)?.objectUrl ?? null;
2838
- return src ? { status: "ready", src } : null;
2839
- }
2840
- function retainCachedMarkdownImage(path) {
2841
- const entry = cachedMarkdownImages.get(path);
2842
- if (!entry) {
2843
- return null;
2844
- }
2845
- entry.refCount += 1;
2846
- if (entry.revokeTimer) {
2847
- clearTimeout(entry.revokeTimer);
2848
- entry.revokeTimer = null;
2849
- }
2850
- return entry.objectUrl;
2851
- }
2852
- function cacheMarkdownImage(path, blob) {
2853
- const entry = cachedMarkdownImages.get(path);
2854
- if (entry) {
2855
- entry.refCount += 1;
2856
- if (entry.revokeTimer) {
2857
- clearTimeout(entry.revokeTimer);
2858
- entry.revokeTimer = null;
2859
- }
2860
- return entry.objectUrl;
2861
- }
2862
- const objectUrl = URL.createObjectURL(blob);
2863
- cachedMarkdownImages.set(path, {
2864
- objectUrl,
2865
- refCount: 1,
2866
- revokeTimer: null
2867
- });
2868
- return objectUrl;
2869
- }
2870
- function releaseCachedMarkdownImage(path, objectUrl) {
2871
- const entry = cachedMarkdownImages.get(path);
2872
- if (!entry || entry.objectUrl !== objectUrl) {
2873
- URL.revokeObjectURL(objectUrl);
2874
- return;
2875
- }
2876
- entry.refCount = Math.max(0, entry.refCount - 1);
2877
- if (entry.refCount > 0 || entry.revokeTimer) {
2878
- return;
2879
- }
2880
- entry.revokeTimer = setTimeout(() => {
2881
- const current = cachedMarkdownImages.get(path);
2882
- if (!current || current.objectUrl !== objectUrl || current.refCount > 0) {
2883
- return;
2884
- }
2885
- cachedMarkdownImages.delete(path);
2886
- URL.revokeObjectURL(objectUrl);
2887
- }, CACHED_MARKDOWN_IMAGE_REVOKE_DELAY_MS);
2888
- }
2889
- function isHttpUrl(value) {
2890
- const candidate = value.trim();
2891
- if (!candidate || /\s/.test(candidate)) {
2892
- return false;
2893
- }
2894
- try {
2895
- const url = new URL(candidate);
2896
- return url.protocol === "http:" || url.protocol === "https:";
2897
- } catch {
2898
- return false;
2899
- }
2900
- }
2901
- function linkBareLocalAbsolutePaths(content) {
2902
- let out = "";
2903
- for (let index = 0; index < content.length; ) {
2904
- const markdownLinkEnd = markdownLinkEndIndex(content, index);
2905
- if (markdownLinkEnd > index) {
2906
- out += content.slice(index, markdownLinkEnd);
2907
- index = markdownLinkEnd;
2908
- continue;
2909
- }
2910
- const codeSpanEnd = codeSpanEndIndex(content, index);
2911
- if (codeSpanEnd > index) {
2912
- out += content.slice(index, codeSpanEnd);
2913
- index = codeSpanEnd;
2914
- continue;
2915
- }
2916
- if (isLocalPathStart(content, index)) {
2917
- const end = bareLocalPathEndIndex(content, index);
2918
- const rawPath = trimTrailingPathPunctuation(content.slice(index, end));
2919
- const trailing = content.slice(index + rawPath.length, end);
2920
- if (isLocalAbsolutePath(rawPath)) {
2921
- out += `[${escapeMarkdownLinkLabel(rawPath)}](${rawPath})${trailing}`;
2922
- } else {
2923
- out += content.slice(index, end);
2924
- }
2925
- index = end;
2926
- continue;
2927
- }
2928
- out += content[index];
2929
- index += 1;
2930
- }
2931
- return out;
2932
- }
2933
- function normalizePlainIssueMentionTitleContent(content) {
2934
- const trimmed = content.trim();
2935
- if (trimmed !== content || !trimmed.startsWith("@") || trimmed.includes("\n") || markdownLinkEndIndex(trimmed, 0) === trimmed.length) {
2936
- return content;
2937
- }
2938
- const label = trimmed.replace(/^@+/, "").trim();
2939
- if (!label) {
2940
- return content;
2941
- }
2942
- return `[@${escapeMarkdownLinkLabel(label)}](mention://workspace-issue?source=plain-title)`;
2943
- }
2944
- function normalizeMentionMarkdownLinks(content) {
2945
- return content.replace(/\]([\t ]*\r?\n[\t ]*)+\((mention:\/\/)/g, "]($2").replace(/\]\((mention:\/\/[A-Za-z0-9.-]+)\)\?([^\s)]+)/g, "]($1?$2)");
2946
- }
2947
- function isMentionOnlyMarkdownContent(content) {
2948
- const trimmed = content.trim();
2949
- if (trimmed.length === 0) {
2950
- return false;
2951
- }
2952
- if (markdownLinkEndIndex(trimmed, 0) !== trimmed.length) {
2953
- return false;
2954
- }
2955
- const labelEnd = trimmed.indexOf("]");
2956
- return trimmed.slice(labelEnd + 2).startsWith("mention://");
2957
- }
2958
- function normalizePlainSessionMentionTitle(content) {
2959
- const trimmed = content.trim();
2960
- if (trimmed !== content || !trimmed.startsWith("@") || trimmed.includes("\n")) {
2961
- return content;
2962
- }
2963
- for (const agentLabel of PLAIN_SESSION_MENTION_AGENT_LABELS) {
2964
- const separator = ` & ${agentLabel}`;
2965
- const separatorIndex = trimmed.indexOf(separator);
2966
- if (separatorIndex <= 1) {
2967
- continue;
2968
- }
2969
- const userLabel = trimmed.slice(1, separatorIndex).trim();
2970
- const summary = trimmed.slice(separatorIndex + separator.length).trim();
2971
- if (!userLabel) {
2972
- continue;
2973
- }
2974
- const mentionLabel = [userLabel, agentLabel, summary].filter(Boolean).join(" \xB7 ");
2975
- return `[@${escapeMarkdownLinkLabel(mentionLabel)}](mention://agent-session?source=plain-title)`;
2976
- }
2977
- return content;
2978
- }
2979
- function markdownUrlTransform(value) {
2980
- return value.startsWith("mention://") ? value : defaultUrlTransform(value);
2981
- }
2982
- function parseMentionLink(href, rawLabel, workspaceAppIcons = [], appFactoryFallbackLabel = "Create app") {
2983
- let url;
2984
- try {
2985
- url = new URL(href);
2986
- } catch {
2987
- return null;
2988
- }
2989
- if (url.protocol !== "mention:") {
2990
- return null;
2991
- }
2992
- const resource = url.hostname.trim().toLowerCase();
2993
- const kind = resource === "agent-session" ? "session" : resource === "workspace-app" ? "workspace-app" : resource === "workspace-app-factory" ? "workspace-app-factory" : resource === "workspace-issue" ? "workspace-issue" : resource;
2994
- if (kind !== "session" && kind !== "workspace-app" && kind !== "workspace-app-factory" && kind !== "workspace-issue") {
2995
- return null;
2996
- }
2997
- const label = rawLabel.trim().replace(/^@+/, "").trim() || (kind === "workspace-app-factory" ? appFactoryFallbackLabel : "");
2998
- if (kind === "workspace-app" || kind === "workspace-app-factory") {
2999
- const appId = url.searchParams.get("appId")?.trim() || "";
3000
- const workspaceId = url.searchParams.get("workspaceId")?.trim() || "";
3001
- return {
3002
- kind,
3003
- ...kind === "workspace-app" ? { appId } : {},
3004
- label,
3005
- ...kind === "workspace-app" ? {
3006
- iconUrl: resolveWorkspaceAppMentionIconUrl({
3007
- appId,
3008
- workspaceAppIcons,
3009
- workspaceId
3010
- })
3011
- } : {},
3012
- participant: label,
3013
- summary: ""
3014
- };
3015
- }
3016
- if (kind === "workspace-issue") {
3017
- return {
3018
- kind,
3019
- label,
3020
- participant: label,
3021
- summary: ""
3022
- };
3023
- }
3024
- const sessionLabel = parseSessionMentionLabel(label);
3025
- return {
3026
- kind,
3027
- label,
3028
- participant: sessionLabel.participant,
3029
- summary: sessionLabel.summary
3030
- };
3031
- }
3032
- function resolveWorkspaceAppMentionIconUrl(input) {
3033
- const appId = input.appId.trim();
3034
- if (!appId) {
3035
- return void 0;
3036
- }
3037
- const workspaceId = input.workspaceId.trim();
3038
- const exactMatch = input.workspaceAppIcons.find(
3039
- (icon) => icon.appId.trim() === appId && (icon.workspaceId?.trim() ?? "") === workspaceId && icon.iconUrl?.trim()
3040
- );
3041
- const fallbackMatch = input.workspaceAppIcons.find(
3042
- (icon) => icon.appId.trim() === appId && icon.iconUrl?.trim()
3043
- );
3044
- return exactMatch?.iconUrl?.trim() || fallbackMatch?.iconUrl?.trim() || void 0;
3045
- }
3046
- function parseSessionMentionLabel(label) {
3047
- const dottedParts = label.split("\xB7").map((part) => part.trim()).filter(Boolean);
3048
- if (dottedParts.length >= 3) {
3049
- return {
3050
- participant: `${dottedParts[0]} & ${dottedParts[1]}`,
3051
- summary: dottedParts.slice(2).join(" ")
3052
- };
3053
- }
3054
- return {
3055
- participant: label,
3056
- summary: ""
3057
- };
3058
- }
3059
- function markdownLinkEndIndex(content, index) {
3060
- if (content[index] !== "[") {
3061
- return -1;
3062
- }
3063
- const labelEnd = content.indexOf("]", index + 1);
3064
- if (labelEnd < 0 || content[labelEnd + 1] !== "(") {
3065
- return -1;
3066
- }
3067
- const hrefEnd = content.indexOf(")", labelEnd + 2);
3068
- return hrefEnd < 0 ? -1 : hrefEnd + 1;
3069
- }
3070
- function codeSpanEndIndex(content, index) {
3071
- if (content[index] !== "`") {
3072
- return -1;
3073
- }
3074
- let tickCount = 1;
3075
- while (content[index + tickCount] === "`") {
3076
- tickCount += 1;
3077
- }
3078
- const fence = "`".repeat(tickCount);
3079
- const end = content.indexOf(fence, index + tickCount);
3080
- return end < 0 ? -1 : end + tickCount;
3081
- }
3082
- function isLocalPathStart(content, index) {
3083
- if (content[index] !== "/" || content[index + 1] === "/") {
3084
- return false;
3085
- }
3086
- const previous = content[index - 1];
3087
- return previous === void 0 || /\s/.test(previous) || previous === "(" || previous === "[";
3088
- }
3089
- function bareLocalPathEndIndex(content, index) {
3090
- let end = index;
3091
- while (end < content.length) {
3092
- const char = content[end];
3093
- if (!char || /[\s<>[\](){}"'`]/.test(char)) {
3094
- break;
3095
- }
3096
- end += 1;
3097
- }
3098
- return end;
3099
- }
3100
- function trimTrailingPathPunctuation(path) {
3101
- return path.replace(/[.,;:!?,。;:!?]+$/g, "");
3102
- }
3103
- function escapeMarkdownLinkLabel(label) {
3104
- return label.replace(/([\\[\]])/g, "\\$1");
3105
- }
3106
- function PathLink({
3107
- href,
3108
- children,
3109
- onLinkClick
3110
- }) {
3111
- "use memo";
3112
- return /* @__PURE__ */ jsx6(
3113
- "a",
3114
- {
3115
- className: "cursor-pointer",
3116
- "data-agent-link-href": href,
3117
- role: "link",
3118
- tabIndex: 0,
3119
- onClick: (event) => {
3120
- activateMarkdownLink(event, href, onLinkClick);
3121
- },
3122
- onPointerDown: (event) => {
3123
- activateMarkdownLinkFromPointer(event, href, onLinkClick);
3124
- },
3125
- onKeyDown: (event) => {
3126
- activateMarkdownLinkFromKey(event, href, onLinkClick);
3127
- },
3128
- children
3129
- }
3130
- );
3131
- }
3132
- function textFromReactNode(node) {
3133
- if (typeof node === "string" || typeof node === "number") {
3134
- return String(node);
3135
- }
3136
- if (Array.isArray(node)) {
3137
- return node.map(textFromReactNode).join("");
3138
- }
3139
- return "";
3140
- }
3141
-
3142
- // app/renderer/assets/icons/user-avatar-placeholder.png
3143
- var user_avatar_placeholder_default = "./user-avatar-placeholder-WP2373TS.png";
3144
-
3145
- // shared/workspaceAgentActivityStatusLabel.ts
3146
- function normalizeWorkspaceAgentActivityDisplayStatus(status) {
3147
- switch ((status ?? "").trim().toLowerCase()) {
3148
- case "working":
3149
- return "working";
3150
- case "waiting":
3151
- return "waiting";
3152
- case "idle":
3153
- case "ready":
3154
- return "completed";
3155
- case "completed":
3156
- case "end":
3157
- return "completed";
3158
- case "canceled":
3159
- return "canceled";
3160
- case "failed":
3161
- return "failed";
3162
- default:
3163
- return "idle";
3164
- }
3165
- }
3166
- function workspaceAgentActivityStatusLabel(status, t) {
3167
- const translateFn = t ?? translate;
3168
- switch (normalizeWorkspaceAgentActivityDisplayStatus(status)) {
3169
- case "working":
3170
- return translateFn("agentHost.workspaceAgentActivityStatusWorking");
3171
- case "waiting":
3172
- return translateFn("agentHost.workspaceAgentActivityStatusWaiting");
3173
- case "idle":
3174
- return translateFn("agentHost.workspaceAgentActivityStatusIdle");
3175
- case "completed":
3176
- return translateFn("agentHost.workspaceAgentActivityStatusEnd");
3177
- case "canceled":
3178
- return translateFn("agentHost.workspaceAgentActivityStatusCanceled");
3179
- case "failed":
3180
- return translateFn("agentHost.workspaceAgentActivityStatusFailed");
3181
- default:
3182
- return String(status);
3183
- }
3184
- }
3185
-
3186
- // app/renderer/components/ui/custom-scroll-area.tsx
3187
- import {
3188
- forwardRef as forwardRef2,
3189
- useCallback as useCallback4,
3190
- useEffect as useEffect5,
3191
- useRef as useRef4,
3192
- useState as useState4
3193
- } from "react";
3194
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
3195
- var MIN_THUMB_HEIGHT = 24;
3196
- function CustomScrollbar({
3197
- getViewport,
3198
- className,
3199
- thumbClassName,
3200
- testId,
3201
- thumbTestId,
3202
- syncKey
3203
- }) {
3204
- "use memo";
3205
- const trackRef = useRef4(null);
3206
- const dragStateRef = useRef4(null);
3207
- const [scrollbarState, setScrollbarState] = useState4({
3208
- scrollable: false,
3209
- thumbHeight: 0,
3210
- thumbTop: 0
3211
- });
3212
- const [dragging, setDragging] = useState4(false);
3213
- const syncScrollbarState = useCallback4(() => {
3214
- const viewport = getViewport();
3215
- if (!viewport) {
3216
- setScrollbarState({ scrollable: false, thumbHeight: 0, thumbTop: 0 });
3217
- return;
3218
- }
3219
- const { clientHeight, scrollHeight, scrollTop } = viewport;
3220
- const trackHeight = trackRef.current?.clientHeight ?? clientHeight;
3221
- const maxScrollTop = Math.max(0, scrollHeight - clientHeight);
3222
- if (clientHeight <= 0 || trackHeight <= 0 || maxScrollTop <= 0) {
3223
- setScrollbarState({ scrollable: false, thumbHeight: 0, thumbTop: 0 });
3224
- return;
3225
- }
3226
- const thumbHeight = Math.max(
3227
- MIN_THUMB_HEIGHT,
3228
- Math.round(clientHeight / scrollHeight * trackHeight)
3229
- );
3230
- const maxThumbTop = Math.max(0, trackHeight - thumbHeight);
3231
- const thumbTop = Math.round(scrollTop / maxScrollTop * maxThumbTop);
3232
- setScrollbarState(
3233
- (previous) => previous.scrollable && previous.thumbHeight === thumbHeight && previous.thumbTop === thumbTop ? previous : { scrollable: true, thumbHeight, thumbTop }
3234
- );
3235
- }, [getViewport]);
3236
- const scrollViewportToThumbTop = useCallback4(
3237
- (thumbTop) => {
3238
- const viewport = getViewport();
3239
- const track = trackRef.current;
3240
- if (!viewport || !track) {
3241
- return;
3242
- }
3243
- const maxScrollTop = Math.max(
3244
- 0,
3245
- viewport.scrollHeight - viewport.clientHeight
3246
- );
3247
- const maxThumbTop = Math.max(
3248
- 0,
3249
- track.clientHeight - scrollbarState.thumbHeight
3250
- );
3251
- if (maxScrollTop <= 0 || maxThumbTop <= 0) {
3252
- return;
3253
- }
3254
- viewport.scrollTop = clamp(thumbTop, 0, maxThumbTop) / maxThumbTop * maxScrollTop;
3255
- syncScrollbarState();
3256
- },
3257
- [getViewport, scrollbarState.thumbHeight, syncScrollbarState]
3258
- );
3259
- const handleTrackMouseDown = useCallback4(
3260
- (event) => {
3261
- if (event.button !== 0 || !scrollbarState.scrollable) {
3262
- return;
3263
- }
3264
- const track = trackRef.current;
3265
- if (!track) {
3266
- return;
3267
- }
3268
- event.preventDefault();
3269
- event.stopPropagation();
3270
- const trackRect = track.getBoundingClientRect();
3271
- scrollViewportToThumbTop(
3272
- event.clientY - trackRect.top - scrollbarState.thumbHeight / 2
3273
- );
3274
- },
3275
- [
3276
- scrollViewportToThumbTop,
3277
- scrollbarState.scrollable,
3278
- scrollbarState.thumbHeight
3279
- ]
3280
- );
3281
- const handleThumbMouseDown = useCallback4(
3282
- (event) => {
3283
- if (event.button !== 0 || !scrollbarState.scrollable) {
3284
- return;
3285
- }
3286
- const viewport = getViewport();
3287
- const track = trackRef.current;
3288
- if (!viewport || !track) {
3289
- return;
3290
- }
3291
- const maxScrollTop = Math.max(
3292
- 0,
3293
- viewport.scrollHeight - viewport.clientHeight
3294
- );
3295
- const maxThumbTop = Math.max(
3296
- 0,
3297
- track.clientHeight - scrollbarState.thumbHeight
3298
- );
3299
- if (maxScrollTop <= 0 || maxThumbTop <= 0) {
3300
- return;
3301
- }
3302
- event.preventDefault();
3303
- event.stopPropagation();
3304
- dragStateRef.current = {
3305
- maxScrollTop,
3306
- maxThumbTop,
3307
- startClientY: event.clientY,
3308
- startScrollTop: viewport.scrollTop
3309
- };
3310
- setDragging(true);
3311
- },
3312
- [getViewport, scrollbarState.scrollable, scrollbarState.thumbHeight]
3313
- );
3314
- useEffect5(() => {
3315
- if (!dragging) {
3316
- return;
3317
- }
3318
- const handleMouseMove = (event) => {
3319
- const dragState = dragStateRef.current;
3320
- const viewport = getViewport();
3321
- if (!dragState || !viewport) {
3322
- return;
3323
- }
3324
- const nextThumbTop = dragState.startScrollTop / dragState.maxScrollTop * dragState.maxThumbTop + (event.clientY - dragState.startClientY);
3325
- viewport.scrollTop = clamp(nextThumbTop, 0, dragState.maxThumbTop) / dragState.maxThumbTop * dragState.maxScrollTop;
3326
- syncScrollbarState();
3327
- };
3328
- const handleMouseUp = () => {
3329
- dragStateRef.current = null;
3330
- setDragging(false);
3331
- };
3332
- window.addEventListener("mousemove", handleMouseMove);
3333
- window.addEventListener("mouseup", handleMouseUp);
3334
- return () => {
3335
- window.removeEventListener("mousemove", handleMouseMove);
3336
- window.removeEventListener("mouseup", handleMouseUp);
3337
- };
3338
- }, [dragging, getViewport, syncScrollbarState]);
3339
- useEffect5(() => {
3340
- const viewport = getViewport();
3341
- if (!viewport) {
3342
- setScrollbarState({ scrollable: false, thumbHeight: 0, thumbTop: 0 });
3343
- return;
3344
- }
3345
- syncScrollbarState();
3346
- viewport.addEventListener("scroll", syncScrollbarState, { passive: true });
3347
- const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(syncScrollbarState) : null;
3348
- resizeObserver?.observe(viewport);
3349
- const animationFrameId = window.requestAnimationFrame(syncScrollbarState);
3350
- return () => {
3351
- window.cancelAnimationFrame(animationFrameId);
3352
- viewport.removeEventListener("scroll", syncScrollbarState);
3353
- resizeObserver?.disconnect();
3354
- };
3355
- }, [getViewport, syncKey, syncScrollbarState]);
3356
- return /* @__PURE__ */ jsx7(
3357
- "div",
3358
- {
3359
- ref: trackRef,
3360
- className: cn("tsh-custom-scrollbar", className),
3361
- "data-scrollable": scrollbarState.scrollable ? "true" : "false",
3362
- "data-dragging": dragging ? "true" : "false",
3363
- "data-testid": testId,
3364
- "aria-hidden": "true",
3365
- onMouseDown: handleTrackMouseDown,
3366
- children: /* @__PURE__ */ jsx7(
3367
- "div",
3368
- {
3369
- className: cn("tsh-custom-scrollbar__thumb", thumbClassName),
3370
- "data-testid": thumbTestId,
3371
- onMouseDown: handleThumbMouseDown,
3372
- style: {
3373
- height: `${scrollbarState.thumbHeight}px`,
3374
- transform: `translateY(${scrollbarState.thumbTop}px)`
3375
- }
3376
- }
3377
- )
3378
- }
3379
- );
3380
- }
3381
- var CustomScrollArea = forwardRef2(function CustomScrollArea2({
3382
- children,
3383
- className,
3384
- viewportClassName,
3385
- scrollbarClassName,
3386
- scrollbarThumbClassName,
3387
- scrollbarTestId,
3388
- scrollbarThumbTestId,
3389
- syncKey,
3390
- ...viewportProps
3391
- }, forwardedRef) {
3392
- "use memo";
3393
- const viewportRef = useRef4(null);
3394
- const getViewport = useCallback4(() => viewportRef.current, []);
3395
- return /* @__PURE__ */ jsxs5(
3396
- "div",
3397
- {
3398
- className: cn(
3399
- "tsh-custom-scroll-area relative min-h-0 min-w-0",
3400
- className
3401
- ),
3402
- children: [
3403
- /* @__PURE__ */ jsx7(
3404
- "div",
3405
- {
3406
- ref: setRefs(viewportRef, forwardedRef),
3407
- className: cn(
3408
- "overflow-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
3409
- viewportClassName
3410
- ),
3411
- ...viewportProps,
3412
- children
3413
- }
3414
- ),
3415
- /* @__PURE__ */ jsx7(
3416
- CustomScrollbar,
3417
- {
3418
- getViewport,
3419
- className: scrollbarClassName,
3420
- thumbClassName: scrollbarThumbClassName,
3421
- testId: scrollbarTestId,
3422
- thumbTestId: scrollbarThumbTestId,
3423
- syncKey: syncKey ?? children
3424
- }
3425
- )
3426
- ]
3427
- }
3428
- );
3429
- });
3430
- function setRefs(localRef, forwardedRef) {
3431
- return (node) => {
3432
- localRef.current = node;
3433
- if (typeof forwardedRef === "function") {
3434
- forwardedRef(node);
3435
- } else if (forwardedRef) {
3436
- forwardedRef.current = node;
3437
- }
3438
- };
3439
- }
3440
- function clamp(value, min, max) {
3441
- return Math.min(max, Math.max(min, value));
3442
- }
3443
-
3444
- export {
3445
- cn,
3446
- AgentActivityRuntimeProvider,
3447
- useAgentActivityRuntime,
3448
- useOptionalAgentActivityRuntime,
3449
- useAgentActivitySnapshot,
3450
- getAgentActivityRuntime,
3451
- getOptionalAgentActivityRuntime,
3452
- resetAgentActivityRuntimeForTests,
3453
- setAgentActivityRuntimeForTests,
3454
- AgentActivityHostProvider,
3455
- useAgentHostApi,
3456
- useOptionalAgentHostApi,
3457
- getOptionalAgentHostApi,
3458
- resolveWebsiteNavigationUrl,
3459
- ZoomableImage,
3460
- resolveWorkspaceLinkAction,
3461
- AgentMessageMarkdown,
3462
- AgentGUIConversation_styles_default,
3463
- CustomScrollArea,
3464
- MessageSquareMoreIcon,
3465
- normalizeManagedAgentProvider,
3466
- MANAGED_AGENT_ICON_URLS,
3467
- MANAGED_AGENT_ICON_FALLBACK_URL,
3468
- managedAgentRoundedIconUrl,
3469
- approvalOptionDisplayLabel,
3470
- Spinner,
3471
- getPromptToolDetails,
3472
- isPromptRequestIdTitle,
3473
- AgentInteractivePromptSurface,
3474
- user_avatar_placeholder_default,
3475
- normalizeWorkspaceAgentActivityDisplayStatus,
3476
- workspaceAgentActivityStatusLabel
3477
- };
3478
- //# sourceMappingURL=chunk-5Q36BEUM.js.map