@tutti-os/agent-gui 0.0.3

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 (112) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +56 -0
  3. package/dist/agent-message-center/index.d.ts +218 -0
  4. package/dist/agent-message-center/index.js +1962 -0
  5. package/dist/agent-message-center/index.js.map +1 -0
  6. package/dist/agent-rich-text-at-provider.d.ts +49 -0
  7. package/dist/agent-rich-text-at-provider.js +7 -0
  8. package/dist/agent-rich-text-at-provider.js.map +1 -0
  9. package/dist/agent-title-text.d.ts +3 -0
  10. package/dist/agent-title-text.js +7 -0
  11. package/dist/agent-title-text.js.map +1 -0
  12. package/dist/app/renderer/agentactivity.css +6773 -0
  13. package/dist/app/renderer/assets/icons/agent-sessions-filled.svg +1 -0
  14. package/dist/app/renderer/assets/icons/agents/claude-rounded.png +0 -0
  15. package/dist/app/renderer/assets/icons/agents/codex-rounded.png +0 -0
  16. package/dist/app/renderer/assets/icons/agents/gemini-rounded.png +0 -0
  17. package/dist/app/renderer/assets/icons/agents/hermes-rounded.png +0 -0
  18. package/dist/app/renderer/assets/icons/agents/manage-agent-claude-code.png +0 -0
  19. package/dist/app/renderer/assets/icons/agents/manage-agent-codex.png +0 -0
  20. package/dist/app/renderer/assets/icons/agents/manage-agent-gemini.png +0 -0
  21. package/dist/app/renderer/assets/icons/agents/manage-agent-hermes.png +0 -0
  22. package/dist/app/renderer/assets/icons/agents/manage-agent-nextop.png +0 -0
  23. package/dist/app/renderer/assets/icons/agents/manage-agent-openclaw.png +0 -0
  24. package/dist/app/renderer/assets/icons/agents/nextop-doc-rounded.png +0 -0
  25. package/dist/app/renderer/assets/icons/agents/openclaw-rounded.png +0 -0
  26. package/dist/app/renderer/assets/icons/agents/workspace-dock-agent-claude-code.png +0 -0
  27. package/dist/app/renderer/assets/icons/agents/workspace-dock-agent-codex.png +0 -0
  28. package/dist/app/renderer/assets/icons/agents/workspace-dock-agent-gemini.png +0 -0
  29. package/dist/app/renderer/assets/icons/agents/workspace-dock-agent-nexight.png +0 -0
  30. package/dist/app/renderer/assets/icons/agents/workspace-dock-agent-openclaw.png +0 -0
  31. package/dist/app/renderer/assets/icons/code-filled.svg +1 -0
  32. package/dist/app/renderer/assets/icons/doc-filled.svg +1 -0
  33. package/dist/app/renderer/assets/icons/folder-filled.svg +1 -0
  34. package/dist/app/renderer/assets/icons/image-filled.svg +1 -0
  35. package/dist/app/renderer/assets/icons/issue-filled.svg +1 -0
  36. package/dist/app/renderer/assets/icons/product-filled.svg +1 -0
  37. package/dist/app/renderer/assets/icons/user-avatar-placeholder.png +0 -0
  38. package/dist/app/renderer/assets/icons/video-filled.svg +1 -0
  39. package/dist/chunk-22L4VWUR.js +70 -0
  40. package/dist/chunk-22L4VWUR.js.map +1 -0
  41. package/dist/chunk-3D5VTIKP.js +93 -0
  42. package/dist/chunk-3D5VTIKP.js.map +1 -0
  43. package/dist/chunk-AF5CXBJN.js +3075 -0
  44. package/dist/chunk-AF5CXBJN.js.map +1 -0
  45. package/dist/chunk-BABBC24I.js +28 -0
  46. package/dist/chunk-BABBC24I.js.map +1 -0
  47. package/dist/chunk-GCBDIQDX.js +22 -0
  48. package/dist/chunk-GCBDIQDX.js.map +1 -0
  49. package/dist/chunk-HSR5DI6O.js +4695 -0
  50. package/dist/chunk-HSR5DI6O.js.map +1 -0
  51. package/dist/chunk-IVPB4MLI.js +7 -0
  52. package/dist/chunk-IVPB4MLI.js.map +1 -0
  53. package/dist/chunk-KCC3GNPB.js +13 -0
  54. package/dist/chunk-KCC3GNPB.js.map +1 -0
  55. package/dist/chunk-PJP5BUU6.js +18 -0
  56. package/dist/chunk-PJP5BUU6.js.map +1 -0
  57. package/dist/chunk-RORLLV27.js +144 -0
  58. package/dist/chunk-RORLLV27.js.map +1 -0
  59. package/dist/chunk-UJWUGMWC.js +128 -0
  60. package/dist/chunk-UJWUGMWC.js.map +1 -0
  61. package/dist/chunk-UKQIGNN3.js +921 -0
  62. package/dist/chunk-UKQIGNN3.js.map +1 -0
  63. package/dist/chunk-ZP7P7DYO.js +270 -0
  64. package/dist/chunk-ZP7P7DYO.js.map +1 -0
  65. package/dist/chunk-ZX5PDYAS.js +346 -0
  66. package/dist/chunk-ZX5PDYAS.js.map +1 -0
  67. package/dist/claude-rounded-F6VPQETB.png +0 -0
  68. package/dist/codex-rounded-SC63MZAW.png +0 -0
  69. package/dist/gemini-rounded-O4KAJFIM.png +0 -0
  70. package/dist/hermes-rounded-QGDHBNRJ.png +0 -0
  71. package/dist/i18n/index.d.ts +4580 -0
  72. package/dist/i18n/index.js +19 -0
  73. package/dist/i18n/index.js.map +1 -0
  74. package/dist/index.d.ts +775 -0
  75. package/dist/index.js +33699 -0
  76. package/dist/index.js.map +1 -0
  77. package/dist/manage-agent-claude-code-F6VPQETB.png +0 -0
  78. package/dist/manage-agent-codex-SC63MZAW.png +0 -0
  79. package/dist/manage-agent-gemini-O4KAJFIM.png +0 -0
  80. package/dist/manage-agent-hermes-QGDHBNRJ.png +0 -0
  81. package/dist/manage-agent-nextop-UFAQ22K2.png +0 -0
  82. package/dist/manage-agent-openclaw-24U7O6CA.png +0 -0
  83. package/dist/mention-file-presentation.d.ts +16 -0
  84. package/dist/mention-file-presentation.js +10 -0
  85. package/dist/mention-file-presentation.js.map +1 -0
  86. package/dist/nextop-doc-rounded-UFAQ22K2.png +0 -0
  87. package/dist/openclaw-rounded-24U7O6CA.png +0 -0
  88. package/dist/user-avatar-placeholder-WP2373TS.png +0 -0
  89. package/dist/workbench/contribution.d.ts +42 -0
  90. package/dist/workbench/contribution.js +24 -0
  91. package/dist/workbench/contribution.js.map +1 -0
  92. package/dist/workbench/index.d.ts +24 -0
  93. package/dist/workbench/index.js +82 -0
  94. package/dist/workbench/index.js.map +1 -0
  95. package/dist/workbench/launch.d.ts +49 -0
  96. package/dist/workbench/launch.js +23 -0
  97. package/dist/workbench/launch.js.map +1 -0
  98. package/dist/workbench/providerCatalog.d.ts +15 -0
  99. package/dist/workbench/providerCatalog.js +27 -0
  100. package/dist/workbench/providerCatalog.js.map +1 -0
  101. package/dist/workbench/state.d.ts +22 -0
  102. package/dist/workbench/state.js +22 -0
  103. package/dist/workbench/state.js.map +1 -0
  104. package/dist/workbench/types.d.ts +43 -0
  105. package/dist/workbench/types.js +7 -0
  106. package/dist/workbench/types.js.map +1 -0
  107. package/dist/workspace-agent-generated-files.d.ts +2 -0
  108. package/dist/workspace-agent-generated-files.js +21 -0
  109. package/dist/workspace-agent-generated-files.js.map +1 -0
  110. package/dist/workspaceAgentActivityListViewModel-PvLQDj60.d.ts +309 -0
  111. package/dist/workspaceLinkActions-Bwa-phu8.d.ts +51 -0
  112. package/package.json +166 -0
@@ -0,0 +1,1962 @@
1
+ import {
2
+ AgentInteractivePromptSurface,
3
+ AgentMessageMarkdown,
4
+ CustomScrollArea,
5
+ approvalOptionDisplayLabel,
6
+ cn,
7
+ getPromptToolDetails,
8
+ isPromptRequestIdTitle,
9
+ managedAgentRoundedIconUrl,
10
+ user_avatar_placeholder_default,
11
+ workspaceAgentActivityStatusLabel
12
+ } from "../chunk-AF5CXBJN.js";
13
+ import {
14
+ resolveWorkspaceAgentSessionSortTimeUnixMs,
15
+ workspaceAgentProviderLabel
16
+ } from "../chunk-3D5VTIKP.js";
17
+ import {
18
+ normalizeAgentTitleText
19
+ } from "../chunk-GCBDIQDX.js";
20
+ import {
21
+ AgentGuiI18nProvider,
22
+ useTranslation
23
+ } from "../chunk-HSR5DI6O.js";
24
+ import "../chunk-PJP5BUU6.js";
25
+
26
+ // agent-message-center/WorkspaceAgentMessageCenterPanel.tsx
27
+ import {
28
+ memo,
29
+ useCallback as useCallback2,
30
+ useEffect as useEffect2,
31
+ useLayoutEffect as useLayoutEffect2,
32
+ useMemo,
33
+ useRef as useRef2,
34
+ useState as useState2
35
+ } from "react";
36
+ import {
37
+ Button as Button3,
38
+ cn as cn4,
39
+ Drawer,
40
+ DrawerContent,
41
+ TooltipProvider
42
+ } from "@tutti-os/ui-system";
43
+
44
+ // shared/AgentVerticalScrollArea.tsx
45
+ import {
46
+ forwardRef
47
+ } from "react";
48
+ import { jsx } from "react/jsx-runtime";
49
+ var AgentVerticalScrollArea = forwardRef(function AgentVerticalScrollArea2({
50
+ children,
51
+ className,
52
+ viewportClassName,
53
+ scrollbarClassName,
54
+ scrollbarThumbClassName,
55
+ syncKey,
56
+ ...props
57
+ }, forwardedRef) {
58
+ "use memo";
59
+ return /* @__PURE__ */ jsx(
60
+ CustomScrollArea,
61
+ {
62
+ ref: forwardedRef,
63
+ className: cn("agent-vertical-scroll-area min-h-0 min-w-0", className),
64
+ viewportClassName: cn(
65
+ "min-h-0 min-w-0 overflow-x-hidden overflow-y-auto",
66
+ viewportClassName
67
+ ),
68
+ scrollbarClassName: cn(
69
+ "agent-vertical-scroll-area__scrollbar top-2 right-2 bottom-2",
70
+ scrollbarClassName
71
+ ),
72
+ scrollbarThumbClassName: cn(
73
+ "agent-vertical-scroll-area__scrollbar-thumb",
74
+ scrollbarThumbClassName
75
+ ),
76
+ syncKey: syncKey ?? children,
77
+ ...props,
78
+ children
79
+ }
80
+ );
81
+ });
82
+
83
+ // agent-message-center/WorkspaceAgentMessageCenterViewControls.tsx
84
+ import { ListFilter } from "lucide-react";
85
+ import {
86
+ Button,
87
+ cn as cn2,
88
+ DropdownMenu,
89
+ DropdownMenuCheckboxItem,
90
+ DropdownMenuContent,
91
+ DropdownMenuGroup,
92
+ DropdownMenuItem,
93
+ DropdownMenuLabel,
94
+ DropdownMenuRadioGroup,
95
+ DropdownMenuRadioItem,
96
+ DropdownMenuSeparator,
97
+ DropdownMenuTrigger
98
+ } from "@tutti-os/ui-system";
99
+
100
+ // agent-message-center/workspaceAgentMessageCenterModel.ts
101
+ import {
102
+ selectNeedsAttentionItems,
103
+ selectSessionDisplayStatuses
104
+ } from "@tutti-os/agent-activity-core";
105
+ var EMPTY_COUNTS = {
106
+ all: 0,
107
+ working: 0,
108
+ waiting: 0,
109
+ completed: 0,
110
+ failed: 0
111
+ };
112
+ function buildWorkspaceAgentMessageCenterModel(snapshot, options = {}) {
113
+ const needsAttentionBySessionId = latestNeedsAttentionBySessionId(
114
+ selectNeedsAttentionItems(snapshot)
115
+ );
116
+ const displayStatuses = selectSessionDisplayStatuses(snapshot);
117
+ const items = snapshot.sessions.filter((session) => session.visible !== false).map((session) => {
118
+ const messages = resolveSessionMessages(snapshot, session);
119
+ const needsAttention = needsAttentionBySessionId.get(session.agentSessionId) ?? null;
120
+ const pendingPrompt = pendingPromptFromMessages(messages) ?? fallbackPromptFromNeedsAttention(
121
+ needsAttention,
122
+ options.promptFallbackLabels
123
+ );
124
+ const status = displayStatuses.get(session.agentSessionId) ?? "idle";
125
+ const lastAgentMessage = latestAgentMessage(messages);
126
+ const title = resolveSessionTitle(session, messages);
127
+ const sortTimeUnixMs = resolveWorkspaceAgentSessionSortTimeUnixMs(
128
+ session,
129
+ {
130
+ messages
131
+ }
132
+ );
133
+ return {
134
+ id: `message-center-${session.agentSessionId}`,
135
+ agentSessionId: session.agentSessionId,
136
+ provider: session.provider,
137
+ title,
138
+ identity: resolveMessageCenterIdentity(
139
+ session.agentSessionId,
140
+ options.identityBySessionId
141
+ ),
142
+ cwd: session.cwd,
143
+ status,
144
+ lastAgentMessageSummary: lastAgentMessage?.summary ?? needsAttention?.summary ?? title,
145
+ lastAgentMessageAtUnixMs: lastAgentMessage?.occurredAtUnixMs ?? null,
146
+ pendingPrompt,
147
+ needsAttentionKind: needsAttention?.kind ?? null,
148
+ needsAttentionSummary: needsAttention?.summary ?? null,
149
+ sortTimeUnixMs
150
+ };
151
+ });
152
+ return {
153
+ waitingCount: items.filter(isWaitingMessageCenterItem).length,
154
+ items: items.sort(compareMessageCenterItems),
155
+ counts: countMessageCenterItems(items)
156
+ };
157
+ }
158
+ function resolveMessageCenterIdentity(agentSessionId, identityBySessionId) {
159
+ const identity = identityBySessionId?.[agentSessionId];
160
+ if (!identity) {
161
+ return null;
162
+ }
163
+ const userName = identity.userName.trim();
164
+ const agentName = identity.agentName.trim();
165
+ if (!userName || !agentName) {
166
+ return null;
167
+ }
168
+ const userAvatarUrl = identity.userAvatarUrl?.trim() ?? "";
169
+ const agentAvatarUrl = identity.agentAvatarUrl?.trim() ?? "";
170
+ return {
171
+ userName,
172
+ ...userAvatarUrl ? { userAvatarUrl } : {},
173
+ agentName,
174
+ ...agentAvatarUrl ? { agentAvatarUrl } : {}
175
+ };
176
+ }
177
+ function isWaitingMessageCenterItem(item) {
178
+ return item.pendingPrompt !== null || item.needsAttentionKind !== null;
179
+ }
180
+ function isCompletedMessageCenterItem(item) {
181
+ return item.status === "completed" || item.status === "canceled" || item.status === "idle";
182
+ }
183
+ function latestNeedsAttentionBySessionId(items) {
184
+ const bySessionId = /* @__PURE__ */ new Map();
185
+ for (const item of items) {
186
+ const previous = bySessionId.get(item.agentSessionId);
187
+ if (!previous || item.occurredAtUnixMs > previous.occurredAtUnixMs) {
188
+ bySessionId.set(item.agentSessionId, item);
189
+ }
190
+ }
191
+ return bySessionId;
192
+ }
193
+ function resolveSessionMessages(snapshot, session) {
194
+ for (const sessionId of [session.agentSessionId, session.providerSessionId]) {
195
+ const normalized = sessionId?.trim() ?? "";
196
+ if (normalized && snapshot.sessionMessagesById[normalized]) {
197
+ return snapshot.sessionMessagesById[normalized];
198
+ }
199
+ }
200
+ return [];
201
+ }
202
+ function resolveSessionTitle(session, messages) {
203
+ const title = session.title.trim();
204
+ if (title) {
205
+ return title;
206
+ }
207
+ return firstUserMessageText(messages) || session.provider || session.agentSessionId;
208
+ }
209
+ function firstUserMessageText(messages) {
210
+ for (const message of messages) {
211
+ if (message.role.trim().toLowerCase() !== "user") {
212
+ continue;
213
+ }
214
+ const summary = messageSummary(message);
215
+ if (summary) {
216
+ return summary;
217
+ }
218
+ }
219
+ return "";
220
+ }
221
+ function pendingPromptFromMessages(messages) {
222
+ for (const message of [...messages].sort(compareMessagesByRecentTime)) {
223
+ if (isTerminalMessageStatus(message.status)) {
224
+ continue;
225
+ }
226
+ const approval = approvalPromptFromMessage(message);
227
+ if (approval) {
228
+ return approval;
229
+ }
230
+ const askUser = askUserPromptFromMessage(message);
231
+ if (askUser) {
232
+ return askUser;
233
+ }
234
+ const exitPlan = exitPlanPromptFromMessage(message);
235
+ if (exitPlan) {
236
+ return exitPlan;
237
+ }
238
+ }
239
+ return null;
240
+ }
241
+ function approvalPromptFromMessage(message) {
242
+ if (!isPermissionMessage(message)) {
243
+ return null;
244
+ }
245
+ const payload = recordValue(message.payload);
246
+ const input = recordValue(payload.input);
247
+ const requestId = stringValue(input.requestId) ?? stringValue(payload.requestId) ?? stringValue(payload.approvalRequestId) ?? message.messageId;
248
+ const options = [
249
+ ...arrayValue(input.options),
250
+ ...arrayValue(payload.options)
251
+ ].flatMap((option) => {
252
+ const record = recordValue(option);
253
+ const id = stringValue(record.optionId) ?? stringValue(record.id) ?? stringValue(record.kind);
254
+ if (!id) {
255
+ return [];
256
+ }
257
+ return [
258
+ {
259
+ id,
260
+ label: stringValue(record.name) ?? stringValue(record.label) ?? stringValue(record.title) ?? id,
261
+ kind: stringValue(record.kind) ?? id,
262
+ ...stringValue(record.description) ? { description: stringValue(record.description) } : {}
263
+ }
264
+ ];
265
+ });
266
+ if (options.length === 0) {
267
+ return null;
268
+ }
269
+ return {
270
+ kind: "approval",
271
+ id: `approval:${requestId}`,
272
+ turnId: message.turnId ?? "turn:unknown",
273
+ requestId,
274
+ callId: stringValue(payload.callId) ?? message.messageId,
275
+ title: firstNonEmptyString(
276
+ stringValue(payload.summary),
277
+ stringValue(payload.title),
278
+ stringValue(input.title),
279
+ stringValue(input.command),
280
+ messageSummary(message),
281
+ message.kind
282
+ ),
283
+ toolName: stringValue(payload.toolName) ?? stringValue(payload.name) ?? stringValue(payload.tool),
284
+ status: message.status ?? stringValue(payload.status),
285
+ input: Object.keys(input).length > 0 ? input : payload,
286
+ options,
287
+ output: null,
288
+ occurredAtUnixMs: messageTimeUnixMs(message) || null
289
+ };
290
+ }
291
+ function askUserPromptFromMessage(message) {
292
+ if (!isQuestionMessage(message)) {
293
+ return null;
294
+ }
295
+ const payload = recordValue(message.payload);
296
+ const questions = arrayValue(payload.questions).flatMap((value, index) => {
297
+ const question = recordValue(value);
298
+ const id = stringValue(question.id) ?? `question-${index + 1}`;
299
+ const label = stringValue(question.question) ?? stringValue(question.header) ?? stringValue(question.label);
300
+ if (!label) {
301
+ return [];
302
+ }
303
+ return [
304
+ {
305
+ id,
306
+ header: stringValue(question.header) ?? label,
307
+ question: label,
308
+ options: arrayValue(question.options).flatMap((optionValue) => {
309
+ const option = recordValue(optionValue);
310
+ const optionLabel = stringValue(option.label);
311
+ return optionLabel ? [
312
+ {
313
+ label: optionLabel,
314
+ description: stringValue(option.description) ?? ""
315
+ }
316
+ ] : [];
317
+ }),
318
+ multiSelect: Boolean(question.multiSelect),
319
+ answer: null
320
+ }
321
+ ];
322
+ });
323
+ if (questions.length === 0) {
324
+ return null;
325
+ }
326
+ return {
327
+ kind: "ask-user",
328
+ requestId: stringValue(payload.requestId) ?? stringValue(payload.interactiveRequestId) ?? message.messageId,
329
+ title: stringValue(payload.title) ?? stringValue(payload.summary) ?? messageSummary(message),
330
+ questions
331
+ };
332
+ }
333
+ function exitPlanPromptFromMessage(message) {
334
+ if (!includesAny(normalizedMetadataValues(message), ["exitplanmode"])) {
335
+ return null;
336
+ }
337
+ const payload = recordValue(message.payload);
338
+ return {
339
+ kind: "exit-plan",
340
+ requestId: stringValue(payload.requestId) ?? message.messageId,
341
+ title: stringValue(payload.title) ?? stringValue(payload.summary) ?? messageSummary(message)
342
+ };
343
+ }
344
+ function latestAgentMessage(messages) {
345
+ return messages.reduce(
346
+ (latest, message) => {
347
+ if (!isAgentMessageRole(message.role)) {
348
+ return latest;
349
+ }
350
+ const summary = messageSummary(message);
351
+ if (!summary) {
352
+ return latest;
353
+ }
354
+ const occurredAtUnixMs = messageTimeUnixMs(message);
355
+ if (!latest || occurredAtUnixMs >= latest.occurredAtUnixMs) {
356
+ return { summary, occurredAtUnixMs };
357
+ }
358
+ return latest;
359
+ },
360
+ null
361
+ );
362
+ }
363
+ function fallbackPromptFromNeedsAttention(item, labels) {
364
+ if (!item || item.kind === "permission" || !labels) {
365
+ return null;
366
+ }
367
+ return {
368
+ kind: "ask-user",
369
+ requestId: requestIdFromNeedsAttentionItem(item),
370
+ title: item.summary || item.title || labels.title,
371
+ questions: [
372
+ {
373
+ id: "response",
374
+ header: item.kind === "constraint" ? labels.constraintHeader : labels.inputHeader,
375
+ question: item.summary || item.title || labels.question,
376
+ options: [],
377
+ multiSelect: false,
378
+ answer: null
379
+ }
380
+ ]
381
+ };
382
+ }
383
+ function requestIdFromNeedsAttentionItem(item) {
384
+ const [, messageId] = item.id.split(":", 2);
385
+ return messageId?.trim() || item.id;
386
+ }
387
+ function countMessageCenterItems(items) {
388
+ return items.reduce(
389
+ (counts, item) => {
390
+ counts.all += 1;
391
+ if (isWaitingMessageCenterItem(item)) {
392
+ counts.waiting += 1;
393
+ return counts;
394
+ }
395
+ if (isCompletedMessageCenterItem(item)) {
396
+ counts.completed += 1;
397
+ return counts;
398
+ }
399
+ switch (item.status) {
400
+ case "working":
401
+ counts.working += 1;
402
+ break;
403
+ case "failed":
404
+ counts.failed += 1;
405
+ break;
406
+ default:
407
+ break;
408
+ }
409
+ return counts;
410
+ },
411
+ { ...EMPTY_COUNTS }
412
+ );
413
+ }
414
+ function compareMessageCenterItems(left, right) {
415
+ const leftWaiting = isWaitingMessageCenterItem(left);
416
+ const rightWaiting = isWaitingMessageCenterItem(right);
417
+ if (leftWaiting !== rightWaiting) {
418
+ return leftWaiting ? -1 : 1;
419
+ }
420
+ return right.sortTimeUnixMs - left.sortTimeUnixMs || left.agentSessionId.localeCompare(right.agentSessionId);
421
+ }
422
+ function isAgentMessageRole(role) {
423
+ const normalized = role.trim().toLowerCase();
424
+ return normalized === "assistant" || normalized === "agent";
425
+ }
426
+ function isTerminalMessageStatus(status) {
427
+ switch (status?.trim().toLowerCase()) {
428
+ case "answered":
429
+ case "canceled":
430
+ case "cancelled":
431
+ case "completed":
432
+ case "failed":
433
+ case "rejected":
434
+ case "resolved":
435
+ return true;
436
+ default:
437
+ return false;
438
+ }
439
+ }
440
+ function isPermissionMessage(message) {
441
+ return includesAny(normalizedMetadataValues(message), [
442
+ "permission",
443
+ "approval"
444
+ ]);
445
+ }
446
+ function isQuestionMessage(message) {
447
+ return includesAny(normalizedMetadataValues(message), [
448
+ "ask_user",
449
+ "ask-user",
450
+ "askuserquestion",
451
+ "question"
452
+ ]);
453
+ }
454
+ function normalizedMetadataValues(message) {
455
+ const payload = recordValue(message.payload);
456
+ const input = recordValue(payload.input);
457
+ return [
458
+ message.kind,
459
+ message.status ?? "",
460
+ stringValue(payload.type) ?? "",
461
+ stringValue(payload.action) ?? "",
462
+ stringValue(payload.requestType) ?? "",
463
+ stringValue(payload.callType) ?? "",
464
+ stringValue(payload.toolName) ?? "",
465
+ stringValue(payload.name) ?? "",
466
+ stringValue(payload.status) ?? "",
467
+ stringValue(input.type) ?? "",
468
+ stringValue(input.action) ?? "",
469
+ stringValue(input.requestType) ?? "",
470
+ stringValue(input.callType) ?? "",
471
+ stringValue(input.toolName) ?? "",
472
+ stringValue(input.name) ?? "",
473
+ stringValue(input.status) ?? ""
474
+ ].join(" ").replace(/[_\s-]+/g, "").toLowerCase();
475
+ }
476
+ function compareMessagesByRecentTime(left, right) {
477
+ return messageTimeUnixMs(right) - messageTimeUnixMs(left) || right.version - left.version || right.messageId.localeCompare(left.messageId);
478
+ }
479
+ function includesAny(value, needles) {
480
+ return needles.some(
481
+ (needle) => value.includes(needle.replace(/[_\s-]+/g, "").toLowerCase())
482
+ );
483
+ }
484
+ function messageSummary(message) {
485
+ return firstNonEmptyString(
486
+ stringValue(message.payload.summary),
487
+ stringValue(message.payload.text),
488
+ stringValue(message.payload.content),
489
+ stringValue(message.payload.message),
490
+ stringValue(message.payload.body),
491
+ stringValue(message.payload.title)
492
+ );
493
+ }
494
+ function messageTimeUnixMs(message) {
495
+ return positiveNumber(message.occurredAtUnixMs) ?? positiveNumber(message.completedAtUnixMs) ?? positiveNumber(message.startedAtUnixMs) ?? positiveNumber(message.version) ?? 0;
496
+ }
497
+ function firstNonEmptyString(...values) {
498
+ return values.find((value) => value !== null && value.length > 0) ?? "";
499
+ }
500
+ function stringValue(value) {
501
+ return typeof value === "string" && value.trim() ? value.trim() : null;
502
+ }
503
+ function recordValue(value) {
504
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
505
+ }
506
+ function arrayValue(value) {
507
+ return Array.isArray(value) ? value : [];
508
+ }
509
+ function positiveNumber(value) {
510
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
511
+ }
512
+
513
+ // agent-message-center/workspaceAgentMessageCenterViewModel.ts
514
+ function partitionMessageCenterItemsByProvider(items) {
515
+ const stacks = /* @__PURE__ */ new Map();
516
+ for (const item of items) {
517
+ const stack = stacks.get(item.provider);
518
+ if (stack) {
519
+ stack.items.push(item);
520
+ } else {
521
+ stacks.set(item.provider, { provider: item.provider, items: [item] });
522
+ }
523
+ }
524
+ return [...stacks.values()];
525
+ }
526
+ function buildMessageCenterStatusOptions(counts, t) {
527
+ return [
528
+ {
529
+ count: counts.waiting,
530
+ label: t("agentHost.workspaceAgentMessageCenterFilterWaiting"),
531
+ value: "waiting"
532
+ },
533
+ {
534
+ count: counts.failed,
535
+ label: t("agentHost.workspaceAgentMessageCenterFilterFailed"),
536
+ value: "failed"
537
+ },
538
+ {
539
+ count: counts.working,
540
+ label: t("agentHost.workspaceAgentMessageCenterFilterWorking"),
541
+ value: "working"
542
+ },
543
+ {
544
+ count: counts.completed,
545
+ label: t("agentHost.workspaceAgentMessageCenterFilterCompleted"),
546
+ value: "completed"
547
+ }
548
+ ];
549
+ }
550
+ function buildMessageCenterProviderOptions(items) {
551
+ const counts = /* @__PURE__ */ new Map();
552
+ for (const item of items) {
553
+ counts.set(item.provider, (counts.get(item.provider) ?? 0) + 1);
554
+ }
555
+ return [...counts.entries()].map(([value, count]) => ({
556
+ count,
557
+ label: workspaceAgentProviderLabel(value),
558
+ value
559
+ })).sort((left, right) => left.label.localeCompare(right.label));
560
+ }
561
+ function itemMatchesViewFilters({
562
+ item,
563
+ providerFilters,
564
+ statusFilters
565
+ }) {
566
+ if (statusFilters && !statusFilters.has(messageCenterStatusFilterValue(item))) {
567
+ return false;
568
+ }
569
+ if (providerFilters && !providerFilters.has(item.provider)) {
570
+ return false;
571
+ }
572
+ return true;
573
+ }
574
+ function messageCenterStatusFilterValue(item) {
575
+ if (isWaitingMessageCenterItem(item)) {
576
+ return "waiting";
577
+ }
578
+ if (item.status === "failed") {
579
+ return "failed";
580
+ }
581
+ if (item.status === "working") {
582
+ return "working";
583
+ }
584
+ return "completed";
585
+ }
586
+ function groupMessageCenterItems(items, groupBy, t) {
587
+ switch (groupBy) {
588
+ case "status":
589
+ return groupByFixedDefinitions(items, [
590
+ {
591
+ id: "waiting",
592
+ label: t("agentHost.workspaceAgentMessageCenterFilterWaiting"),
593
+ match: (item) => messageCenterStatusFilterValue(item) === "waiting"
594
+ },
595
+ {
596
+ id: "failed",
597
+ label: t("agentHost.workspaceAgentMessageCenterFilterFailed"),
598
+ match: (item) => messageCenterStatusFilterValue(item) === "failed"
599
+ },
600
+ {
601
+ id: "working",
602
+ label: t("agentHost.workspaceAgentMessageCenterFilterWorking"),
603
+ match: (item) => messageCenterStatusFilterValue(item) === "working"
604
+ },
605
+ {
606
+ id: "completed",
607
+ label: t("agentHost.workspaceAgentMessageCenterFilterCompleted"),
608
+ match: (item) => messageCenterStatusFilterValue(item) === "completed"
609
+ }
610
+ ]);
611
+ case "agent":
612
+ return groupByDynamicKey(items, (item) => ({
613
+ id: `agent:${item.provider}`,
614
+ label: workspaceAgentProviderLabel(item.provider)
615
+ }));
616
+ case "time":
617
+ return groupByFixedDefinitions(items, [
618
+ {
619
+ id: "today",
620
+ label: t("agentHost.workspaceAgentMessageCenterGroupToday"),
621
+ match: (item) => messageCenterTimeGroup(item) === "today"
622
+ },
623
+ {
624
+ id: "yesterday",
625
+ label: t("agentHost.workspaceAgentMessageCenterGroupYesterday"),
626
+ match: (item) => messageCenterTimeGroup(item) === "yesterday"
627
+ },
628
+ {
629
+ id: "previous-seven-days",
630
+ label: t(
631
+ "agentHost.workspaceAgentMessageCenterGroupPreviousSevenDays"
632
+ ),
633
+ match: (item) => messageCenterTimeGroup(item) === "previous-seven-days"
634
+ },
635
+ {
636
+ id: "older",
637
+ label: t("agentHost.workspaceAgentMessageCenterGroupOlder"),
638
+ match: (item) => messageCenterTimeGroup(item) === "older"
639
+ }
640
+ ]);
641
+ case "priority":
642
+ default: {
643
+ const nowUnixMs = Date.now();
644
+ return groupByFixedDefinitions(items, [
645
+ {
646
+ id: "needs-attention",
647
+ label: t("agentHost.workspaceAgentMessageCenterGroupNeedsAttention"),
648
+ match: (item) => messageCenterStatusFilterValue(item) === "waiting" || messageCenterStatusFilterValue(item) === "failed"
649
+ },
650
+ {
651
+ id: "working",
652
+ label: t("agentHost.workspaceAgentMessageCenterFilterWorking"),
653
+ match: (item) => messageCenterStatusFilterValue(item) === "working"
654
+ },
655
+ {
656
+ id: "recently-completed",
657
+ label: t(
658
+ "agentHost.workspaceAgentMessageCenterGroupRecentlyCompleted"
659
+ ),
660
+ match: (item) => isRecentlyCompletedMessageCenterItem(item, nowUnixMs)
661
+ },
662
+ {
663
+ id: "completed",
664
+ label: t("agentHost.workspaceAgentMessageCenterFilterCompleted"),
665
+ match: (item) => messageCenterStatusFilterValue(item) === "completed" && !isRecentlyCompletedMessageCenterItem(item, nowUnixMs)
666
+ }
667
+ ]);
668
+ }
669
+ }
670
+ }
671
+ var RECENTLY_COMPLETED_WINDOW_MS = 10 * 60 * 1e3;
672
+ function isRecentlyCompletedMessageCenterItem(item, nowUnixMs) {
673
+ if (messageCenterStatusFilterValue(item) !== "completed") {
674
+ return false;
675
+ }
676
+ const completedAtUnixMs = item.sortTimeUnixMs || item.lastAgentMessageAtUnixMs || 0;
677
+ if (completedAtUnixMs <= 0) {
678
+ return false;
679
+ }
680
+ return completedAtUnixMs >= nowUnixMs - RECENTLY_COMPLETED_WINDOW_MS;
681
+ }
682
+ function messageCenterGroupLabel(groupBy, t) {
683
+ switch (groupBy) {
684
+ case "status":
685
+ return t("agentHost.workspaceAgentMessageCenterGroupStatus");
686
+ case "agent":
687
+ return t("agentHost.workspaceAgentMessageCenterGroupAgent");
688
+ case "time":
689
+ return t("agentHost.workspaceAgentMessageCenterGroupTime");
690
+ case "priority":
691
+ default:
692
+ return t("agentHost.workspaceAgentMessageCenterGroupPriority");
693
+ }
694
+ }
695
+ function statusFilterSummary(statusFilters, statusOptions) {
696
+ if (statusFilters === null || statusFilters.size === statusOptions.length) {
697
+ return statusOptions.map((option) => option.label).join(", ");
698
+ }
699
+ return statusOptions.filter((option) => statusFilters.has(option.value)).map((option) => option.label).join(", ");
700
+ }
701
+ function groupByFixedDefinitions(items, definitions) {
702
+ return definitions.map((definition) => ({
703
+ id: definition.id,
704
+ label: definition.label,
705
+ items: items.filter(definition.match)
706
+ })).filter((group) => group.items.length > 0);
707
+ }
708
+ function groupByDynamicKey(items, keyForItem) {
709
+ const groups = /* @__PURE__ */ new Map();
710
+ for (const item of items) {
711
+ const key = keyForItem(item);
712
+ const group = groups.get(key.id);
713
+ if (group) {
714
+ group.items.push(item);
715
+ } else {
716
+ groups.set(key.id, { ...key, items: [item] });
717
+ }
718
+ }
719
+ return [...groups.values()];
720
+ }
721
+ function messageCenterTimeGroup(item) {
722
+ const timestamp = item.sortTimeUnixMs || item.lastAgentMessageAtUnixMs || 0;
723
+ if (timestamp <= 0) {
724
+ return "older";
725
+ }
726
+ const ageMs = Date.now() - timestamp;
727
+ const dayMs = 24 * 60 * 60 * 1e3;
728
+ if (ageMs < dayMs) {
729
+ return "today";
730
+ }
731
+ if (ageMs < dayMs * 2) {
732
+ return "yesterday";
733
+ }
734
+ if (ageMs < dayMs * 7) {
735
+ return "previous-seven-days";
736
+ }
737
+ return "older";
738
+ }
739
+
740
+ // agent-message-center/WorkspaceAgentMessageCenterViewControls.tsx
741
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
742
+ function MessageCenterViewMenu({
743
+ filtersActive = false,
744
+ groupBy,
745
+ providerFilters,
746
+ providerOptions,
747
+ statusFilters,
748
+ statusOptions,
749
+ onClearFilters,
750
+ onGroupByChange,
751
+ onProviderToggle,
752
+ onStatusToggle
753
+ }) {
754
+ "use memo";
755
+ const { t } = useTranslation();
756
+ return /* @__PURE__ */ jsxs(DropdownMenu, { modal: false, children: [
757
+ /* @__PURE__ */ jsx2(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
758
+ Button,
759
+ {
760
+ type: "button",
761
+ variant: "ghost",
762
+ size: "icon",
763
+ "aria-label": t("agentHost.workspaceAgentMessageCenterViewOptions"),
764
+ title: t("agentHost.workspaceAgentMessageCenterViewOptions"),
765
+ className: cn2(
766
+ "relative size-8 shrink-0 rounded-md border bg-[var(--background-fronted)] shadow-none",
767
+ filtersActive ? "border-[var(--border-focus)] text-[var(--accent)]" : "border-[var(--line-2)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]"
768
+ ),
769
+ children: [
770
+ /* @__PURE__ */ jsx2(ListFilter, { className: "size-4", strokeWidth: 2.1, "aria-hidden": "true" }),
771
+ filtersActive ? /* @__PURE__ */ jsx2(
772
+ "span",
773
+ {
774
+ "aria-label": t(
775
+ "agentHost.workspaceAgentMessageCenterFilterActive"
776
+ ),
777
+ className: "absolute -right-0.5 -top-0.5 size-2 rounded-full border border-[var(--background-panel)] bg-[var(--accent)]"
778
+ }
779
+ ) : null
780
+ ]
781
+ }
782
+ ) }),
783
+ /* @__PURE__ */ jsxs(
784
+ DropdownMenuContent,
785
+ {
786
+ align: "end",
787
+ sideOffset: 8,
788
+ className: "min-w-[240px] p-1.5",
789
+ style: { zIndex: "var(--z-dialog-popover)" },
790
+ children: [
791
+ /* @__PURE__ */ jsx2(DropdownMenuLabel, { children: t("agentHost.workspaceAgentMessageCenterGroupBy") }),
792
+ /* @__PURE__ */ jsx2(
793
+ DropdownMenuRadioGroup,
794
+ {
795
+ value: groupBy,
796
+ onValueChange: (value) => onGroupByChange(value),
797
+ children: ["priority", "status", "agent", "time"].map((value) => /* @__PURE__ */ jsx2(DropdownMenuRadioItem, { value, children: messageCenterGroupLabel(value, t) }, value))
798
+ }
799
+ ),
800
+ /* @__PURE__ */ jsx2(DropdownMenuSeparator, {}),
801
+ /* @__PURE__ */ jsx2(DropdownMenuLabel, { children: t("agentHost.workspaceAgentMessageCenterFilterStatus") }),
802
+ /* @__PURE__ */ jsx2(DropdownMenuGroup, { children: statusOptions.map((option) => /* @__PURE__ */ jsxs(
803
+ DropdownMenuCheckboxItem,
804
+ {
805
+ "aria-label": `${option.label} ${option.count}`,
806
+ checked: statusFilters === null || statusFilters.has(option.value),
807
+ onCheckedChange: () => onStatusToggle(option.value),
808
+ onSelect: (event) => event.preventDefault(),
809
+ children: [
810
+ /* @__PURE__ */ jsx2("span", { className: "min-w-0 flex-1 truncate", children: option.label }),
811
+ /* @__PURE__ */ jsx2("span", { className: "ml-auto text-[11px] text-[var(--text-tertiary)]", children: option.count })
812
+ ]
813
+ },
814
+ option.value
815
+ )) }),
816
+ providerOptions.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
817
+ /* @__PURE__ */ jsx2(DropdownMenuSeparator, {}),
818
+ /* @__PURE__ */ jsx2(DropdownMenuLabel, { children: t("agentHost.workspaceAgentMessageCenterFilterAgent") }),
819
+ /* @__PURE__ */ jsx2(DropdownMenuGroup, { children: providerOptions.map((option) => /* @__PURE__ */ jsxs(
820
+ DropdownMenuCheckboxItem,
821
+ {
822
+ "aria-label": `${option.label} ${option.count}`,
823
+ checked: providerFilters === null || providerFilters.has(option.value),
824
+ onCheckedChange: () => onProviderToggle(option.value),
825
+ onSelect: (event) => event.preventDefault(),
826
+ children: [
827
+ /* @__PURE__ */ jsx2("span", { className: "min-w-0 flex-1 truncate", children: option.label }),
828
+ /* @__PURE__ */ jsx2("span", { className: "ml-auto text-[11px] text-[var(--text-tertiary)]", children: option.count })
829
+ ]
830
+ },
831
+ option.value
832
+ )) })
833
+ ] }) : null,
834
+ /* @__PURE__ */ jsx2(DropdownMenuSeparator, {}),
835
+ /* @__PURE__ */ jsx2(DropdownMenuGroup, { children: /* @__PURE__ */ jsx2(DropdownMenuItem, { onClick: onClearFilters, children: t("agentHost.workspaceAgentMessageCenterClearFilters") }) })
836
+ ]
837
+ }
838
+ )
839
+ ] });
840
+ }
841
+
842
+ // agent-message-center/WorkspaceAgentMessageCenterCard.tsx
843
+ import {
844
+ useCallback,
845
+ useEffect,
846
+ useLayoutEffect,
847
+ useRef,
848
+ useState
849
+ } from "react";
850
+ import { ChevronDown, ChevronUp, ExternalLink, Info } from "lucide-react";
851
+ import {
852
+ Button as Button2,
853
+ cn as cn3,
854
+ StatusDot,
855
+ Tooltip,
856
+ TooltipContent,
857
+ TooltipTrigger
858
+ } from "@tutti-os/ui-system";
859
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
860
+ function stopMessageCenterTextPointerPropagation(event) {
861
+ event.stopPropagation();
862
+ }
863
+ function WorkspaceAgentMessageCenterCard({
864
+ cardRef,
865
+ highlighted = false,
866
+ item,
867
+ isSubmitting,
868
+ onLinkAction,
869
+ onOpenChat,
870
+ onSubmitPrompt
871
+ }) {
872
+ "use memo";
873
+ const { t } = useTranslation();
874
+ const prompt = item.pendingPrompt;
875
+ const displayTitle = normalizeAgentTitleText(item.title);
876
+ const summary = messageCenterVisibleSummary(item);
877
+ const displayStatus = statusClass(item);
878
+ const statusLabel = workspaceAgentActivityStatusLabel(displayStatus, t);
879
+ return /* @__PURE__ */ jsxs2(
880
+ "article",
881
+ {
882
+ ref: cardRef,
883
+ className: cn3(
884
+ "workspace-agent-message-center__card group/message-card flex min-w-0 flex-col gap-2.5 rounded-lg border border-[var(--line-2)] bg-[var(--background-fronted)] p-3.5 outline outline-0 outline-offset-2 outline-transparent transition-[background-color,border-color,outline-color]",
885
+ isWaitingMessageCenterItem(item) && "agent-gui-edge-glow border-[var(--tutti-purple-border)] bg-[var(--tutti-purple-bg)]",
886
+ highlighted && "outline-2 outline-[var(--accent)]"
887
+ ),
888
+ "data-highlighted": highlighted ? "true" : void 0,
889
+ "data-message-center-item-id": item.id,
890
+ "data-waiting": isWaitingMessageCenterItem(item) ? "true" : void 0,
891
+ "data-status": displayStatus,
892
+ tabIndex: highlighted ? -1 : void 0,
893
+ children: [
894
+ /* @__PURE__ */ jsxs2("div", { className: "flex min-w-0 items-center justify-between gap-2.5", children: [
895
+ /* @__PURE__ */ jsxs2("div", { className: "flex min-w-0 items-center gap-1.5", children: [
896
+ /* @__PURE__ */ jsxs2(Tooltip, { children: [
897
+ /* @__PURE__ */ jsx3(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(
898
+ "h3",
899
+ {
900
+ className: "workspace-agent-message-center__copy-text min-w-0 truncate text-[13px] font-bold leading-5 text-[var(--text-secondary)]",
901
+ onPointerDown: stopMessageCenterTextPointerPropagation,
902
+ children: displayTitle
903
+ }
904
+ ) }),
905
+ /* @__PURE__ */ jsx3(
906
+ TooltipContent,
907
+ {
908
+ side: "top",
909
+ align: "start",
910
+ className: "max-w-[min(360px,calc(100vw-32px))] whitespace-normal text-left [overflow-wrap:anywhere]",
911
+ children: displayTitle
912
+ }
913
+ )
914
+ ] }),
915
+ item.cwd ? /* @__PURE__ */ jsx3(ProjectPathInfo, { path: item.cwd }) : null
916
+ ] }),
917
+ /* @__PURE__ */ jsxs2(
918
+ "span",
919
+ {
920
+ className: "workspace-agent-message-center__status inline-flex shrink-0 items-center gap-1.5 text-[11px] font-semibold leading-4 text-[var(--text-secondary)]",
921
+ "data-status": displayStatus,
922
+ title: statusLabel,
923
+ children: [
924
+ /* @__PURE__ */ jsx3(
925
+ StatusDot,
926
+ {
927
+ tone: messageCenterStatusTone(item),
928
+ pulse: isWaitingMessageCenterItem(item) || item.status === "working",
929
+ size: "sm",
930
+ title: statusLabel
931
+ }
932
+ ),
933
+ /* @__PURE__ */ jsx3("span", { children: statusLabel })
934
+ ]
935
+ }
936
+ )
937
+ ] }),
938
+ summary ? /* @__PURE__ */ jsx3(
939
+ MessageCenterSummary,
940
+ {
941
+ item,
942
+ onLinkAction,
943
+ summary,
944
+ emptyLabel: t("agentHost.workspaceAgentMessageCenterNoSummary")
945
+ }
946
+ ) : null,
947
+ prompt ? /* @__PURE__ */ jsx3("div", { className: "min-w-0", children: /* @__PURE__ */ jsx3(
948
+ AgentInteractivePromptSurface,
949
+ {
950
+ embedded: true,
951
+ keyboardShortcuts: false,
952
+ prompt,
953
+ isSubmitting,
954
+ onSubmit: onSubmitPrompt,
955
+ labels: buildWorkspaceAgentInteractivePromptLabels(
956
+ t,
957
+ item.provider
958
+ )
959
+ }
960
+ ) }) : null,
961
+ /* @__PURE__ */ jsx3(
962
+ MessageCenterOpenChatButton,
963
+ {
964
+ provider: item.provider,
965
+ item,
966
+ label: t("agentHost.workspaceAgentMessageCenterOpenChat"),
967
+ onOpenChat
968
+ }
969
+ )
970
+ ]
971
+ }
972
+ );
973
+ }
974
+ var STACK_PRESENCE_FALLBACK_MS = 380;
975
+ function useStackRegionPresence(visible) {
976
+ const [mounted, setMounted] = useState(visible);
977
+ const closing = mounted && !visible;
978
+ useLayoutEffect(() => {
979
+ if (visible) {
980
+ setMounted(true);
981
+ }
982
+ }, [visible]);
983
+ useEffect(() => {
984
+ if (!closing) {
985
+ return void 0;
986
+ }
987
+ const timeoutId = window.setTimeout(() => {
988
+ setMounted(false);
989
+ }, STACK_PRESENCE_FALLBACK_MS);
990
+ return () => {
991
+ window.clearTimeout(timeoutId);
992
+ };
993
+ }, [closing]);
994
+ const onAnimationEnd = useCallback(
995
+ (event) => {
996
+ if (event.target === event.currentTarget && closing) {
997
+ setMounted(false);
998
+ }
999
+ },
1000
+ [closing]
1001
+ );
1002
+ return { closing, mounted, onAnimationEnd };
1003
+ }
1004
+ function WorkspaceAgentMessageCenterStack({
1005
+ className,
1006
+ expanded,
1007
+ groupId,
1008
+ items,
1009
+ renderCard,
1010
+ onCollapse,
1011
+ onExpand
1012
+ }) {
1013
+ "use memo";
1014
+ const { t } = useTranslation();
1015
+ const summaryRegion = useStackRegionPresence(!expanded);
1016
+ const cardsRegion = useStackRegionPresence(expanded);
1017
+ if (items.length < 2) {
1018
+ return null;
1019
+ }
1020
+ const collapseLabel = t(
1021
+ "agentHost.workspaceAgentMessageCenterCollapseStackAria"
1022
+ );
1023
+ return /* @__PURE__ */ jsxs2(
1024
+ "div",
1025
+ {
1026
+ className: cn3("relative flex min-w-0 flex-col", className),
1027
+ "data-stack-count": items.length,
1028
+ "data-stack-motion": "smooth",
1029
+ "data-stack-state": expanded ? "expanded" : "collapsed",
1030
+ "data-stack-top-item-id": items[0]?.id,
1031
+ "data-testid": `workspace-agent-message-stack-${groupId}`,
1032
+ children: [
1033
+ summaryRegion.mounted ? /* @__PURE__ */ jsx3(
1034
+ "div",
1035
+ {
1036
+ className: cn3(
1037
+ "workspace-agent-message-center__stack-rest min-w-0",
1038
+ summaryRegion.closing ? "workspace-agent-message-center__stack-rest--closing" : "workspace-agent-message-center__stack-rest--opening"
1039
+ ),
1040
+ onAnimationEnd: summaryRegion.onAnimationEnd,
1041
+ children: /* @__PURE__ */ jsx3(
1042
+ "div",
1043
+ {
1044
+ className: "min-h-0 min-w-0 overflow-hidden",
1045
+ "aria-hidden": summaryRegion.closing ? true : void 0,
1046
+ inert: summaryRegion.closing ? true : void 0,
1047
+ children: /* @__PURE__ */ jsx3(
1048
+ MessageCenterStackSummary,
1049
+ {
1050
+ groupId,
1051
+ items,
1052
+ onExpand
1053
+ }
1054
+ )
1055
+ }
1056
+ )
1057
+ }
1058
+ ) : null,
1059
+ cardsRegion.mounted ? /* @__PURE__ */ jsx3(
1060
+ "div",
1061
+ {
1062
+ className: cn3(
1063
+ "workspace-agent-message-center__stack-rest min-w-0",
1064
+ cardsRegion.closing ? "workspace-agent-message-center__stack-rest--closing" : "workspace-agent-message-center__stack-rest--opening"
1065
+ ),
1066
+ onAnimationEnd: cardsRegion.onAnimationEnd,
1067
+ children: /* @__PURE__ */ jsxs2(
1068
+ "div",
1069
+ {
1070
+ className: "min-h-0 min-w-0 overflow-hidden",
1071
+ "aria-hidden": cardsRegion.closing ? true : void 0,
1072
+ inert: cardsRegion.closing ? true : void 0,
1073
+ children: [
1074
+ /* @__PURE__ */ jsxs2("div", { className: "flex min-w-0 items-center justify-between gap-2 px-0.5 pb-1.5", children: [
1075
+ /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-center gap-1.5 text-[13px] font-semibold leading-4 text-[var(--text-tertiary)]", children: [
1076
+ /* @__PURE__ */ jsx3(
1077
+ "img",
1078
+ {
1079
+ src: managedAgentRoundedIconUrl(items[0]?.provider ?? ""),
1080
+ alt: "",
1081
+ className: "size-4 shrink-0 rounded-full",
1082
+ decoding: "async",
1083
+ loading: "lazy",
1084
+ draggable: false,
1085
+ "aria-hidden": "true"
1086
+ }
1087
+ ),
1088
+ /* @__PURE__ */ jsx3("span", { className: "min-w-0 truncate", children: t("agentHost.workspaceAgentMessageCenterStackSummaryCount", {
1089
+ count: items.length
1090
+ }) })
1091
+ ] }),
1092
+ /* @__PURE__ */ jsxs2(Tooltip, { children: [
1093
+ /* @__PURE__ */ jsx3(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(
1094
+ Button2,
1095
+ {
1096
+ type: "button",
1097
+ variant: "ghost",
1098
+ size: "icon-sm",
1099
+ "aria-label": collapseLabel,
1100
+ className: "size-6 text-[var(--text-tertiary)] hover:text-[var(--text-primary)]",
1101
+ onClick: onCollapse,
1102
+ children: /* @__PURE__ */ jsx3(ChevronUp, { className: "size-3.5", "aria-hidden": "true" })
1103
+ }
1104
+ ) }),
1105
+ /* @__PURE__ */ jsx3(TooltipContent, { side: "top", align: "center", children: collapseLabel })
1106
+ ] })
1107
+ ] }),
1108
+ /* @__PURE__ */ jsx3("div", { className: "flex min-w-0 flex-col gap-2.5", children: items.map(
1109
+ (item, stackedIndex) => renderCard(item, { stackedIndex })
1110
+ ) })
1111
+ ]
1112
+ }
1113
+ )
1114
+ }
1115
+ ) : null
1116
+ ]
1117
+ }
1118
+ );
1119
+ }
1120
+ function MessageCenterStackSummary({
1121
+ groupId,
1122
+ items,
1123
+ onExpand
1124
+ }) {
1125
+ "use memo";
1126
+ const { t } = useTranslation();
1127
+ const firstItem = items[0];
1128
+ const hasWaiting = items.some((item) => isWaitingMessageCenterItem(item));
1129
+ if (!firstItem) {
1130
+ return null;
1131
+ }
1132
+ return /* @__PURE__ */ jsx3(
1133
+ "button",
1134
+ {
1135
+ type: "button",
1136
+ "aria-label": t("agentHost.workspaceAgentMessageCenterExpandStackAria", {
1137
+ count: items.length
1138
+ }),
1139
+ className: cn3(
1140
+ "group/stack-peek relative block w-full min-w-0 rounded-lg text-left outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)]",
1141
+ items.length > 2 ? "pb-[18px]" : "pb-[10px]"
1142
+ ),
1143
+ "data-stack-summary-count": items.length,
1144
+ "data-stack-provider": firstItem.provider,
1145
+ "data-testid": `workspace-agent-message-stack-summary-${groupId}`,
1146
+ onClick: onExpand,
1147
+ children: /* @__PURE__ */ jsxs2(
1148
+ "span",
1149
+ {
1150
+ className: cn3(
1151
+ "relative z-10 flex min-w-0 flex-col gap-2 rounded-lg border border-[var(--line-2)] bg-[var(--background-fronted)] p-3.5 transition-[background-color,border-color] duration-200 group-hover/stack-peek:bg-[var(--transparency-hover)]",
1152
+ items.length > 2 ? "shadow-[0_7px_0_-4px_var(--background-fronted),0_7px_0_-3px_var(--line-2),0_14px_0_-8px_var(--background-fronted),0_14px_0_-7px_var(--line-2)]" : "shadow-[0_7px_0_-4px_var(--background-fronted),0_7px_0_-3px_var(--line-2)]",
1153
+ hasWaiting && "border-[var(--tutti-purple-border)] bg-[var(--tutti-purple-bg)]"
1154
+ ),
1155
+ children: [
1156
+ /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-center justify-between gap-2.5", children: [
1157
+ /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-center gap-2", children: [
1158
+ /* @__PURE__ */ jsx3(
1159
+ "img",
1160
+ {
1161
+ src: managedAgentRoundedIconUrl(firstItem.provider),
1162
+ alt: "",
1163
+ className: "size-5 shrink-0 rounded-full",
1164
+ decoding: "async",
1165
+ loading: "lazy",
1166
+ draggable: false,
1167
+ "aria-hidden": "true"
1168
+ }
1169
+ ),
1170
+ /* @__PURE__ */ jsx3("span", { className: "min-w-0 truncate text-[13px] font-bold leading-5 text-[var(--text-secondary)]", children: t("agentHost.workspaceAgentMessageCenterStackSummaryCount", {
1171
+ count: items.length
1172
+ }) })
1173
+ ] }),
1174
+ /* @__PURE__ */ jsx3(
1175
+ ChevronDown,
1176
+ {
1177
+ className: "size-4 shrink-0 text-[var(--text-tertiary)] transition-transform duration-200 group-hover/stack-peek:translate-y-0.5 motion-reduce:transition-none",
1178
+ "aria-hidden": "true"
1179
+ }
1180
+ )
1181
+ ] }),
1182
+ /* @__PURE__ */ jsx3("span", { className: "min-w-0 rounded-md bg-transparency-block p-2.5 text-[13px] leading-[1.45] text-[var(--text-primary)]", children: /* @__PURE__ */ jsx3("span", { className: "line-clamp-2 min-w-0 [overflow-wrap:anywhere]", children: messageCenterStackPreviewText(firstItem) }) })
1183
+ ]
1184
+ }
1185
+ )
1186
+ }
1187
+ );
1188
+ }
1189
+ function messageCenterStackPreviewText(item) {
1190
+ return item.lastAgentMessageSummary.trim() || normalizeAgentTitleText(item.title);
1191
+ }
1192
+ function resolveMessageCenterNotificationAction(item, input) {
1193
+ if (input.action) {
1194
+ return normalizeMessageCenterNotificationAction(input.action);
1195
+ }
1196
+ if (!input.optionId) {
1197
+ return null;
1198
+ }
1199
+ const prompt = item.pendingPrompt;
1200
+ const option = prompt && "options" in prompt ? prompt.options.find((candidate) => candidate.id === input.optionId) : null;
1201
+ const optionToken = `${option?.kind ?? ""}:${input.optionId}`.toLowerCase();
1202
+ if (optionToken.includes("allow") || optionToken.includes("accept")) {
1203
+ return "accept";
1204
+ }
1205
+ if (optionToken.includes("deny") || optionToken.includes("reject") || optionToken.includes("disallow")) {
1206
+ return "reject";
1207
+ }
1208
+ return input.optionId;
1209
+ }
1210
+ function buildWorkspaceAgentInteractivePromptLabels(t, provider) {
1211
+ return {
1212
+ approvalLead: t("agentHost.agentGui.approvalRequired", {
1213
+ provider: provider ? workspaceAgentProviderLabel(provider) : t("agentHost.workspaceAgentsGenericAgentName")
1214
+ }),
1215
+ planLead: t("agentHost.agentGui.planLead"),
1216
+ planModes: [
1217
+ {
1218
+ id: "acceptEdits",
1219
+ label: t("agentHost.agentGui.planModes.acceptEdits.label"),
1220
+ description: t("agentHost.agentGui.planModes.acceptEdits.description")
1221
+ },
1222
+ {
1223
+ id: "default",
1224
+ label: t("agentHost.agentGui.planModes.askFirst.label"),
1225
+ description: t("agentHost.agentGui.planModes.askFirst.description")
1226
+ },
1227
+ {
1228
+ id: "bypassPermissions",
1229
+ label: t("agentHost.agentGui.planModes.allowAll.label"),
1230
+ description: t("agentHost.agentGui.planModes.allowAll.description")
1231
+ }
1232
+ ],
1233
+ stayInPlan: t("agentHost.agentGui.stayInPlan"),
1234
+ sendFeedback: t("agentHost.agentGui.sendFeedback"),
1235
+ feedbackPlaceholder: t("agentHost.agentGui.feedbackPlaceholder"),
1236
+ previousQuestion: t("agentHost.agentGui.previousQuestion"),
1237
+ nextQuestion: t("agentHost.agentGui.nextQuestion"),
1238
+ submitAnswers: t("agentHost.agentGui.submitAnswers"),
1239
+ answerPlaceholder: t("agentHost.agentGui.answerPlaceholder"),
1240
+ waitingForAnswer: t("agentHost.agentGui.waitingForAnswer")
1241
+ };
1242
+ }
1243
+ function normalizeMessageCenterNotificationAction(action) {
1244
+ switch (action) {
1245
+ case "allow":
1246
+ return "accept";
1247
+ case "deny":
1248
+ return "reject";
1249
+ default:
1250
+ return action;
1251
+ }
1252
+ }
1253
+ function messageCenterVisibleSummary(item) {
1254
+ const summary = item.lastAgentMessageSummary.trim();
1255
+ if (item.pendingPrompt?.kind === "approval" && isGenericApprovalSummary(summary)) {
1256
+ return "";
1257
+ }
1258
+ return summary;
1259
+ }
1260
+ function isGenericApprovalSummary(summary) {
1261
+ const normalized = summary.trim().toLowerCase();
1262
+ return normalized === "approval";
1263
+ }
1264
+ function MessageCenterSummary({
1265
+ emptyLabel,
1266
+ item,
1267
+ onLinkAction,
1268
+ summary
1269
+ }) {
1270
+ "use memo";
1271
+ const summaryRef = useRef(null);
1272
+ const [isOverflowing, setIsOverflowing] = useState(false);
1273
+ const handleLinkAction = useCallback(
1274
+ (action) => {
1275
+ onLinkAction?.(
1276
+ action.type === "open-agent-session" && !action.provider ? { ...action, provider: item.provider } : action
1277
+ );
1278
+ },
1279
+ [item.provider, onLinkAction]
1280
+ );
1281
+ useLayoutEffect(() => {
1282
+ const element = summaryRef.current;
1283
+ if (!element) {
1284
+ return;
1285
+ }
1286
+ const updateOverflowState = () => {
1287
+ setIsOverflowing(element.scrollHeight > element.clientHeight + 1);
1288
+ };
1289
+ updateOverflowState();
1290
+ const resizeObserver = new ResizeObserver(updateOverflowState);
1291
+ resizeObserver.observe(element);
1292
+ return () => {
1293
+ resizeObserver.disconnect();
1294
+ };
1295
+ }, [summary]);
1296
+ return /* @__PURE__ */ jsx3(
1297
+ AgentVerticalScrollArea,
1298
+ {
1299
+ ref: summaryRef,
1300
+ className: cn3(
1301
+ "workspace-agent-message-center__summary workspace-agent-message-center__copy-text max-h-[160px] min-w-0 rounded-md bg-transparency-block text-[13px] leading-[1.45] text-[var(--text-primary)] [overflow-wrap:anywhere]",
1302
+ isOverflowing && "workspace-agent-message-center__summary--overflowing"
1303
+ ),
1304
+ viewportClassName: "workspace-agent-message-center__copy-text max-h-[160px] p-2.5 pr-4",
1305
+ onPointerDown: stopMessageCenterTextPointerPropagation,
1306
+ scrollbarClassName: "top-2 bottom-2 right-1.5",
1307
+ syncKey: summary,
1308
+ children: summary ? /* @__PURE__ */ jsx3(
1309
+ AgentMessageMarkdown,
1310
+ {
1311
+ content: summary,
1312
+ className: "[&_a]:text-[var(--tutti-purple)] [&_code]:text-[var(--text-secondary)] [&_hr]:border-t-[color-mix(in_srgb,var(--text-primary)_14%,transparent)] [&_ol]:!bg-transparent [&_p]:m-0 [&_th]:bg-[color-mix(in_srgb,var(--background-panel)_94%,var(--text-primary))] [&_th]:text-[var(--text-primary)] [&_ul]:!bg-transparent text-[var(--text-primary)]",
1313
+ onLinkAction: handleLinkAction,
1314
+ workspaceLinkContext: {
1315
+ workspaceRoot: item.cwd || null,
1316
+ basePath: item.cwd,
1317
+ source: "agent-markdown"
1318
+ },
1319
+ enableImageZoom: true
1320
+ }
1321
+ ) : emptyLabel
1322
+ }
1323
+ );
1324
+ }
1325
+ function MessageCenterOpenChatButton({
1326
+ item,
1327
+ label,
1328
+ onOpenChat,
1329
+ provider
1330
+ }) {
1331
+ "use memo";
1332
+ return /* @__PURE__ */ jsxs2("div", { className: "workspace-agent-message-center__footer flex min-w-0 items-center justify-between gap-2", children: [
1333
+ /* @__PURE__ */ jsx3(
1334
+ MessageCenterIdentityLabel,
1335
+ {
1336
+ identity: item.identity,
1337
+ provider
1338
+ }
1339
+ ),
1340
+ /* @__PURE__ */ jsxs2(
1341
+ Button2,
1342
+ {
1343
+ type: "button",
1344
+ variant: "ghost",
1345
+ size: "default",
1346
+ className: "workspace-agent-message-center__open-chat-button invisible h-auto gap-1.5 border-0 bg-transparent p-0 text-[var(--agent-gui-accent)] opacity-0 shadow-none transition-[color,opacity,visibility] group-hover/message-card:visible group-hover/message-card:opacity-100 group-focus-within/message-card:visible group-focus-within/message-card:opacity-100 hover:bg-transparent hover:text-[var(--agent-gui-accent)] focus-visible:bg-transparent focus-visible:text-[var(--agent-gui-accent)] active:bg-transparent",
1347
+ onClick: () => onOpenChat({
1348
+ agentSessionId: item.agentSessionId,
1349
+ provider: item.provider
1350
+ }),
1351
+ children: [
1352
+ /* @__PURE__ */ jsx3(
1353
+ ExternalLink,
1354
+ {
1355
+ className: "size-[15px]",
1356
+ strokeWidth: 2.2,
1357
+ "aria-hidden": "true"
1358
+ }
1359
+ ),
1360
+ label
1361
+ ]
1362
+ }
1363
+ )
1364
+ ] });
1365
+ }
1366
+ function MessageCenterIdentityLabel({
1367
+ identity,
1368
+ provider
1369
+ }) {
1370
+ "use memo";
1371
+ if (!identity) {
1372
+ return /* @__PURE__ */ jsx3(AgentProviderLabel, { provider });
1373
+ }
1374
+ const agentAvatarUrl = identity.agentAvatarUrl?.trim() || managedAgentRoundedIconUrl(provider);
1375
+ const title = `${identity.userName} & ${identity.agentName}`;
1376
+ return /* @__PURE__ */ jsxs2(
1377
+ "span",
1378
+ {
1379
+ className: "workspace-agent-message-center__identity inline-flex min-w-0 max-w-full items-center gap-2",
1380
+ title,
1381
+ children: [
1382
+ /* @__PURE__ */ jsx3(
1383
+ MessageCenterIdentityAvatarStack,
1384
+ {
1385
+ userAvatarUrl: identity.userAvatarUrl,
1386
+ userName: identity.userName,
1387
+ agentAvatarUrl
1388
+ }
1389
+ ),
1390
+ /* @__PURE__ */ jsxs2("span", { className: "workspace-agent-message-center__identity-names flex min-w-0 items-center gap-1 truncate text-[var(--text-secondary)]", children: [
1391
+ /* @__PURE__ */ jsx3("span", { className: "min-w-0 truncate", children: identity.userName }),
1392
+ /* @__PURE__ */ jsx3("span", { className: "shrink-0 text-[var(--text-tertiary)]", children: "&" }),
1393
+ /* @__PURE__ */ jsx3("span", { className: "min-w-0 truncate", children: identity.agentName })
1394
+ ] })
1395
+ ]
1396
+ }
1397
+ );
1398
+ }
1399
+ function MessageCenterIdentityAvatarStack({
1400
+ agentAvatarUrl,
1401
+ userAvatarUrl: rawUserAvatarUrl,
1402
+ userName
1403
+ }) {
1404
+ "use memo";
1405
+ const [userAvatarFailed, setUserAvatarFailed] = useState(false);
1406
+ const userAvatarUrl = rawUserAvatarUrl?.trim() ?? "";
1407
+ const userImageUrl = userAvatarUrl.length > 0 && !userAvatarFailed ? userAvatarUrl : user_avatar_placeholder_default;
1408
+ useEffect(() => {
1409
+ setUserAvatarFailed(false);
1410
+ }, [userAvatarUrl]);
1411
+ return /* @__PURE__ */ jsxs2(
1412
+ "span",
1413
+ {
1414
+ className: "workspace-agent-message-center__identity-avatar-stack inline-flex w-9 shrink-0 items-center",
1415
+ "aria-hidden": "true",
1416
+ children: [
1417
+ /* @__PURE__ */ jsx3("span", { className: "inline-flex size-5 shrink-0 overflow-hidden rounded-full bg-[var(--transparency-block)] ring-2 ring-[var(--background-fronted)]", children: /* @__PURE__ */ jsx3(
1418
+ "img",
1419
+ {
1420
+ src: userImageUrl,
1421
+ alt: userName,
1422
+ className: "size-full object-cover",
1423
+ decoding: "async",
1424
+ loading: "lazy",
1425
+ referrerPolicy: "no-referrer",
1426
+ draggable: false,
1427
+ onError: () => {
1428
+ setUserAvatarFailed(true);
1429
+ }
1430
+ }
1431
+ ) }),
1432
+ /* @__PURE__ */ jsx3("span", { className: "-ml-1.5 inline-flex size-5 shrink-0 overflow-hidden rounded-full bg-[var(--transparency-block)] ring-2 ring-[var(--background-fronted)]", children: /* @__PURE__ */ jsx3(
1433
+ "img",
1434
+ {
1435
+ src: agentAvatarUrl,
1436
+ alt: "",
1437
+ className: "size-full object-cover",
1438
+ decoding: "async",
1439
+ loading: "lazy",
1440
+ draggable: false
1441
+ }
1442
+ ) })
1443
+ ]
1444
+ }
1445
+ );
1446
+ }
1447
+ function ProjectPathInfo({ path }) {
1448
+ "use memo";
1449
+ return /* @__PURE__ */ jsxs2(Tooltip, { children: [
1450
+ /* @__PURE__ */ jsx3(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(
1451
+ "button",
1452
+ {
1453
+ type: "button",
1454
+ className: "workspace-agent-message-center__project-info-button invisible inline-flex size-5 shrink-0 items-center justify-center rounded-sm text-[var(--text-secondary)] opacity-0 transition-[background-color,color,opacity,visibility] group-hover/message-card:visible group-hover/message-card:opacity-100 group-focus-within/message-card:visible group-focus-within/message-card:opacity-100 hover:bg-[var(--transparency-hover)] hover:text-[var(--text-primary)] focus-visible:bg-[var(--transparency-hover)] focus-visible:text-[var(--text-primary)] focus-visible:outline-none",
1455
+ "aria-label": path,
1456
+ children: /* @__PURE__ */ jsx3(Info, { className: "size-3.5", strokeWidth: 2, "aria-hidden": "true" })
1457
+ }
1458
+ ) }),
1459
+ /* @__PURE__ */ jsx3(
1460
+ TooltipContent,
1461
+ {
1462
+ side: "top",
1463
+ align: "start",
1464
+ className: "max-w-[320px] text-[11px] [overflow-wrap:anywhere]",
1465
+ children: path
1466
+ }
1467
+ )
1468
+ ] });
1469
+ }
1470
+ function AgentProviderLabel({ provider }) {
1471
+ "use memo";
1472
+ const label = workspaceAgentProviderLabel(provider);
1473
+ return /* @__PURE__ */ jsxs2("span", { className: "workspace-agent-message-center__provider inline-flex min-w-0 max-w-full items-center gap-1.5", children: [
1474
+ /* @__PURE__ */ jsx3(
1475
+ "img",
1476
+ {
1477
+ src: managedAgentRoundedIconUrl(provider),
1478
+ alt: "",
1479
+ className: "workspace-agent-message-center__provider-icon size-5 shrink-0 rounded-full",
1480
+ decoding: "async",
1481
+ loading: "lazy",
1482
+ draggable: false,
1483
+ "aria-hidden": "true"
1484
+ }
1485
+ ),
1486
+ /* @__PURE__ */ jsx3("span", { className: "workspace-agent-message-center__provider-name min-w-0 truncate text-[var(--text-secondary)]", children: label })
1487
+ ] });
1488
+ }
1489
+ function statusClass(item) {
1490
+ if (isWaitingMessageCenterItem(item)) {
1491
+ return "waiting";
1492
+ }
1493
+ if (item.status === "idle") {
1494
+ return "completed";
1495
+ }
1496
+ return item.status;
1497
+ }
1498
+ function messageCenterStatusTone(item) {
1499
+ if (isWaitingMessageCenterItem(item)) {
1500
+ return "amber";
1501
+ }
1502
+ if (item.status === "completed" || item.status === "idle") {
1503
+ return "green";
1504
+ }
1505
+ if (item.status === "canceled") {
1506
+ return "amber";
1507
+ }
1508
+ if (item.status === "failed") {
1509
+ return "red";
1510
+ }
1511
+ if (item.status === "working") {
1512
+ return "blue";
1513
+ }
1514
+ return "neutral";
1515
+ }
1516
+
1517
+ // agent-message-center/WorkspaceAgentMessageCenterPanel.tsx
1518
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1519
+ var MESSAGE_CENTER_TOOLTIP_DELAY_MS = 300;
1520
+ var WorkspaceAgentMessageCenterPanel = memo(
1521
+ function WorkspaceAgentMessageCenterPanel2({
1522
+ open,
1523
+ i18n,
1524
+ locale,
1525
+ model,
1526
+ highlightedItemId = null,
1527
+ portalContainer = null,
1528
+ onClose,
1529
+ onHighlightedItemSettled,
1530
+ onLinkAction,
1531
+ onNotificationActioned,
1532
+ onOpenChat,
1533
+ onSubmitPrompt
1534
+ }) {
1535
+ "use memo";
1536
+ return /* @__PURE__ */ jsx4(AgentGuiI18nProvider, { runtime: i18n, locale, children: /* @__PURE__ */ jsx4(
1537
+ WorkspaceAgentMessageCenterPanelContent,
1538
+ {
1539
+ open,
1540
+ model,
1541
+ highlightedItemId,
1542
+ portalContainer,
1543
+ onClose,
1544
+ onHighlightedItemSettled,
1545
+ onLinkAction,
1546
+ onNotificationActioned,
1547
+ onOpenChat,
1548
+ onSubmitPrompt
1549
+ }
1550
+ ) });
1551
+ }
1552
+ );
1553
+ function WorkspaceAgentMessageCenterPanelContent({
1554
+ open,
1555
+ model,
1556
+ highlightedItemId = null,
1557
+ portalContainer = null,
1558
+ onClose,
1559
+ onHighlightedItemSettled,
1560
+ onLinkAction,
1561
+ onNotificationActioned,
1562
+ onOpenChat,
1563
+ onSubmitPrompt
1564
+ }) {
1565
+ "use memo";
1566
+ const { t } = useTranslation();
1567
+ const [groupBy, setGroupBy] = useState2("priority");
1568
+ const [statusFilters, setStatusFilters] = useState2(null);
1569
+ const [providerFilters, setProviderFilters] = useState2(
1570
+ null
1571
+ );
1572
+ const [expandedStackIds, setExpandedStackIds] = useState2(
1573
+ () => /* @__PURE__ */ new Set()
1574
+ );
1575
+ const [submittingPromptKey, setSubmittingPromptKey] = useState2(
1576
+ null
1577
+ );
1578
+ const itemNodesRef = useRef2(/* @__PURE__ */ new Map());
1579
+ const lastScrolledHighlightedItemIdRef = useRef2(null);
1580
+ const lastFilterResetHighlightedItemIdRef = useRef2(null);
1581
+ const statusOptions = useMemo(
1582
+ () => buildMessageCenterStatusOptions(model.counts, t),
1583
+ [model.counts, t]
1584
+ );
1585
+ const providerOptions = useMemo(
1586
+ () => buildMessageCenterProviderOptions(model.items),
1587
+ [model.items]
1588
+ );
1589
+ const visibleItems = useMemo(
1590
+ () => model.items.filter(
1591
+ (item) => itemMatchesViewFilters({
1592
+ item,
1593
+ providerFilters,
1594
+ statusFilters
1595
+ })
1596
+ ),
1597
+ [model.items, providerFilters, statusFilters]
1598
+ );
1599
+ const itemGroups = useMemo(
1600
+ () => groupMessageCenterItems(visibleItems, groupBy, t),
1601
+ [groupBy, t, visibleItems]
1602
+ );
1603
+ const highlightedItem = useMemo(
1604
+ () => highlightedItemId ? model.items.find((item) => item.id === highlightedItemId) ?? null : null,
1605
+ [highlightedItemId, model.items]
1606
+ );
1607
+ const activeStatusSummary = statusFilterSummary(statusFilters, statusOptions);
1608
+ const hasActiveFilters = statusFilters !== null || providerFilters !== null;
1609
+ const headerSummary = useMemo(() => {
1610
+ if (hasActiveFilters) {
1611
+ return t("agentHost.workspaceAgentMessageCenterSummaryFiltered", {
1612
+ count: visibleItems.length,
1613
+ total: model.counts.all
1614
+ });
1615
+ }
1616
+ if (model.counts.waiting > 0) {
1617
+ return t("agentHost.workspaceAgentMessageCenterSummaryWaiting", {
1618
+ count: model.counts.all,
1619
+ waiting: model.counts.waiting
1620
+ });
1621
+ }
1622
+ if (model.counts.completed > 0) {
1623
+ return t("agentHost.workspaceAgentMessageCenterSummaryCompleted", {
1624
+ count: model.counts.all,
1625
+ completed: model.counts.completed
1626
+ });
1627
+ }
1628
+ return t("agentHost.workspaceAgentMessageCenterSummaryCount", {
1629
+ count: model.counts.all
1630
+ });
1631
+ }, [
1632
+ hasActiveFilters,
1633
+ model.counts.all,
1634
+ model.counts.completed,
1635
+ model.counts.waiting,
1636
+ t,
1637
+ visibleItems.length
1638
+ ]);
1639
+ const submitPrompt = useCallback2(
1640
+ async (item, input) => {
1641
+ const promptKey = `${item.agentSessionId}:${input.requestId}`;
1642
+ setSubmittingPromptKey(promptKey);
1643
+ try {
1644
+ const notificationAction = resolveMessageCenterNotificationAction(
1645
+ item,
1646
+ input
1647
+ );
1648
+ if (notificationAction) {
1649
+ onNotificationActioned?.({
1650
+ action: notificationAction,
1651
+ provider: item.provider
1652
+ });
1653
+ }
1654
+ await onSubmitPrompt({
1655
+ ...input,
1656
+ agentSessionId: item.agentSessionId
1657
+ });
1658
+ } finally {
1659
+ setSubmittingPromptKey(
1660
+ (current) => current === promptKey ? null : current
1661
+ );
1662
+ }
1663
+ },
1664
+ [onNotificationActioned, onSubmitPrompt]
1665
+ );
1666
+ const setItemNode = useCallback2(
1667
+ (itemId, node) => {
1668
+ if (node) {
1669
+ itemNodesRef.current.set(itemId, node);
1670
+ } else {
1671
+ itemNodesRef.current.delete(itemId);
1672
+ }
1673
+ },
1674
+ []
1675
+ );
1676
+ const toggleStatusFilter = useCallback2(
1677
+ (status) => {
1678
+ setStatusFilters((current) => {
1679
+ const next = new Set(
1680
+ current ?? statusOptions.map((option) => option.value)
1681
+ );
1682
+ if (next.has(status)) {
1683
+ next.delete(status);
1684
+ } else {
1685
+ next.add(status);
1686
+ }
1687
+ return next.size === statusOptions.length ? null : next;
1688
+ });
1689
+ },
1690
+ [statusOptions]
1691
+ );
1692
+ const toggleProviderFilter = useCallback2(
1693
+ (provider) => {
1694
+ setProviderFilters((current) => {
1695
+ const next = new Set(
1696
+ current ?? providerOptions.map((option) => option.value)
1697
+ );
1698
+ if (next.has(provider)) {
1699
+ next.delete(provider);
1700
+ } else {
1701
+ next.add(provider);
1702
+ }
1703
+ return next.size === providerOptions.length ? null : next;
1704
+ });
1705
+ },
1706
+ [providerOptions]
1707
+ );
1708
+ const clearFilters = useCallback2(() => {
1709
+ setStatusFilters(null);
1710
+ setProviderFilters(null);
1711
+ }, []);
1712
+ const expandStack = useCallback2((groupId) => {
1713
+ setExpandedStackIds((current) => {
1714
+ if (current.has(groupId)) {
1715
+ return current;
1716
+ }
1717
+ const next = new Set(current);
1718
+ next.add(groupId);
1719
+ return next;
1720
+ });
1721
+ }, []);
1722
+ const collapseStack = useCallback2((groupId) => {
1723
+ setExpandedStackIds((current) => {
1724
+ if (!current.has(groupId)) {
1725
+ return current;
1726
+ }
1727
+ const next = new Set(current);
1728
+ next.delete(groupId);
1729
+ return next;
1730
+ });
1731
+ }, []);
1732
+ useLayoutEffect2(() => {
1733
+ if (!open || !highlightedItem) {
1734
+ return;
1735
+ }
1736
+ if (lastFilterResetHighlightedItemIdRef.current === highlightedItem.id) {
1737
+ return;
1738
+ }
1739
+ if (itemMatchesViewFilters({
1740
+ item: highlightedItem,
1741
+ providerFilters,
1742
+ statusFilters
1743
+ })) {
1744
+ return;
1745
+ }
1746
+ lastFilterResetHighlightedItemIdRef.current = highlightedItem.id;
1747
+ setStatusFilters(null);
1748
+ setProviderFilters(null);
1749
+ }, [highlightedItem, open, providerFilters, statusFilters]);
1750
+ useLayoutEffect2(() => {
1751
+ if (!open || !highlightedItemId) {
1752
+ return;
1753
+ }
1754
+ for (const group of itemGroups) {
1755
+ for (const stack of partitionMessageCenterItemsByProvider(group.items)) {
1756
+ if (stack.items.length > 1 && stack.items.some((item) => item.id === highlightedItemId)) {
1757
+ expandStack(`${group.id}:${stack.provider}`);
1758
+ return;
1759
+ }
1760
+ }
1761
+ }
1762
+ }, [expandStack, highlightedItemId, itemGroups, open]);
1763
+ useLayoutEffect2(() => {
1764
+ if (!open || !highlightedItemId) {
1765
+ lastScrolledHighlightedItemIdRef.current = null;
1766
+ return;
1767
+ }
1768
+ if (highlightedItem && !itemMatchesViewFilters({
1769
+ item: highlightedItem,
1770
+ providerFilters,
1771
+ statusFilters
1772
+ })) {
1773
+ return;
1774
+ }
1775
+ if (lastScrolledHighlightedItemIdRef.current === highlightedItemId) {
1776
+ return;
1777
+ }
1778
+ const target = itemNodesRef.current.get(highlightedItemId);
1779
+ if (!target) {
1780
+ return;
1781
+ }
1782
+ lastScrolledHighlightedItemIdRef.current = highlightedItemId;
1783
+ target.scrollIntoView({ behavior: "smooth", block: "center" });
1784
+ target.focus({ preventScroll: true });
1785
+ }, [
1786
+ expandedStackIds,
1787
+ highlightedItem,
1788
+ highlightedItemId,
1789
+ open,
1790
+ providerFilters,
1791
+ statusFilters,
1792
+ visibleItems
1793
+ ]);
1794
+ useEffect2(() => {
1795
+ if (!open || !highlightedItemId) {
1796
+ return void 0;
1797
+ }
1798
+ const timeoutId = window.setTimeout(() => {
1799
+ onHighlightedItemSettled?.(highlightedItemId);
1800
+ }, 3200);
1801
+ return () => {
1802
+ window.clearTimeout(timeoutId);
1803
+ };
1804
+ }, [highlightedItemId, onHighlightedItemSettled, open]);
1805
+ return /* @__PURE__ */ jsx4(
1806
+ Drawer,
1807
+ {
1808
+ open,
1809
+ direction: "right",
1810
+ handleOnly: true,
1811
+ onOpenChange: (nextOpen) => {
1812
+ if (!nextOpen) {
1813
+ onClose();
1814
+ }
1815
+ },
1816
+ children: /* @__PURE__ */ jsx4(
1817
+ DrawerContent,
1818
+ {
1819
+ className: cn4(
1820
+ "t-modal nodrag min-h-0 w-[min(440px,calc(100vw-16px))] max-w-none overflow-hidden rounded-none border-y-0 border-r-0 bg-[var(--background-panel)] text-[var(--text-primary)] shadow-side-panel data-[vaul-drawer-direction=right]:rounded-none",
1821
+ "[-webkit-app-region:no-drag]"
1822
+ ),
1823
+ "data-testid": "workspace-agent-message-center",
1824
+ portalContainer: portalContainer ?? void 0,
1825
+ showOverlay: false,
1826
+ "aria-label": t("agentHost.workspaceAgentMessageCenterTitle"),
1827
+ children: /* @__PURE__ */ jsxs3(TooltipProvider, { delayDuration: MESSAGE_CENTER_TOOLTIP_DELAY_MS, children: [
1828
+ /* @__PURE__ */ jsx4("div", { className: "flex-none border-b border-[var(--border-1)] px-3.5 pt-3 pb-3", children: /* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 items-center justify-between gap-3", children: [
1829
+ /* @__PURE__ */ jsxs3("div", { className: "min-w-0", children: [
1830
+ /* @__PURE__ */ jsx4("div", { className: "truncate text-[13px] font-semibold leading-5 text-[var(--text-primary)]", children: t("agentHost.workspaceAgentMessageCenterTitle") }),
1831
+ /* @__PURE__ */ jsx4("div", { className: "truncate text-[11px] leading-4 text-[var(--text-tertiary)]", children: headerSummary })
1832
+ ] }),
1833
+ /* @__PURE__ */ jsx4(
1834
+ MessageCenterViewMenu,
1835
+ {
1836
+ filtersActive: hasActiveFilters,
1837
+ groupBy,
1838
+ providerFilters,
1839
+ providerOptions,
1840
+ statusFilters,
1841
+ statusOptions,
1842
+ onClearFilters: clearFilters,
1843
+ onGroupByChange: setGroupBy,
1844
+ onProviderToggle: toggleProviderFilter,
1845
+ onStatusToggle: toggleStatusFilter
1846
+ }
1847
+ )
1848
+ ] }) }),
1849
+ /* @__PURE__ */ jsx4(
1850
+ AgentVerticalScrollArea,
1851
+ {
1852
+ className: "min-h-0 flex-1",
1853
+ viewportClassName: "flex h-full w-full flex-col px-3.5 pt-4 pb-4",
1854
+ scrollbarClassName: "top-4 bottom-4",
1855
+ syncKey: `${groupBy}:${activeStatusSummary}:${visibleItems.map((item) => item.id).join("|")}`,
1856
+ children: visibleItems.length > 0 ? /* @__PURE__ */ jsx4("div", { className: "flex w-full min-w-0 flex-col gap-4", children: itemGroups.map((group) => /* @__PURE__ */ jsxs3(
1857
+ "section",
1858
+ {
1859
+ className: "flex min-w-0 flex-col gap-2.5",
1860
+ "aria-label": `${group.label} ${group.items.length}`,
1861
+ children: [
1862
+ /* @__PURE__ */ jsx4("div", { className: "flex min-w-0 items-center justify-between gap-3 px-0.5", children: /* @__PURE__ */ jsxs3("h3", { className: "truncate text-[11px] font-normal leading-4 text-[var(--text-tertiary)]", children: [
1863
+ group.label,
1864
+ " \xB7 ",
1865
+ group.items.length
1866
+ ] }) }),
1867
+ (() => {
1868
+ const renderCard = (item, options = {}) => {
1869
+ const highlighted = item.id === highlightedItemId;
1870
+ const card = /* @__PURE__ */ jsx4(
1871
+ MessageCenterCard,
1872
+ {
1873
+ cardRef: (node) => setItemNode(item.id, node),
1874
+ highlighted,
1875
+ item,
1876
+ isSubmitting: submittingPromptKey === `${item.agentSessionId}:${item.pendingPrompt?.requestId}`,
1877
+ onLinkAction,
1878
+ onOpenChat,
1879
+ onSubmitPrompt: (input) => void submitPrompt(item, input)
1880
+ },
1881
+ item.agentSessionId
1882
+ );
1883
+ if (options.stackedIndex === void 0) {
1884
+ return card;
1885
+ }
1886
+ return /* @__PURE__ */ jsx4(
1887
+ "div",
1888
+ {
1889
+ className: "min-w-0 motion-safe:animate-in motion-safe:fade-in-0 motion-safe:slide-in-from-top-1 motion-safe:duration-200 motion-safe:ease-[cubic-bezier(0.22,1,0.36,1)] motion-reduce:animate-none",
1890
+ style: {
1891
+ animationDelay: `${Math.min(options.stackedIndex * 24, 96)}ms`
1892
+ },
1893
+ children: card
1894
+ },
1895
+ item.agentSessionId
1896
+ );
1897
+ };
1898
+ return partitionMessageCenterItemsByProvider(
1899
+ group.items
1900
+ ).map((stack) => {
1901
+ const firstItem = stack.items[0];
1902
+ if (!firstItem) {
1903
+ return null;
1904
+ }
1905
+ if (stack.items.length === 1) {
1906
+ return renderCard(firstItem);
1907
+ }
1908
+ const stackId = `${group.id}:${stack.provider}`;
1909
+ return /* @__PURE__ */ jsx4(
1910
+ MessageCenterStack,
1911
+ {
1912
+ expanded: expandedStackIds.has(stackId),
1913
+ groupId: stackId,
1914
+ items: stack.items,
1915
+ renderCard,
1916
+ onCollapse: () => collapseStack(stackId),
1917
+ onExpand: () => expandStack(stackId)
1918
+ },
1919
+ stackId
1920
+ );
1921
+ });
1922
+ })()
1923
+ ]
1924
+ },
1925
+ group.id
1926
+ )) }) : model.items.length > 0 ? /* @__PURE__ */ jsxs3("div", { className: "flex min-h-0 flex-1 flex-col items-center justify-center gap-2.5 px-6 py-8 text-center text-[13px] text-[var(--text-tertiary)]", children: [
1927
+ /* @__PURE__ */ jsx4("span", { children: t("agentHost.workspaceAgentMessageCenterFilteredEmpty") }),
1928
+ /* @__PURE__ */ jsx4(
1929
+ Button3,
1930
+ {
1931
+ type: "button",
1932
+ variant: "ghost",
1933
+ size: "sm",
1934
+ className: "border border-[var(--line-2)] bg-[var(--background-fronted)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]",
1935
+ onClick: clearFilters,
1936
+ children: t("agentHost.workspaceAgentMessageCenterClearFilters")
1937
+ }
1938
+ )
1939
+ ] }) : /* @__PURE__ */ jsx4("div", { className: "flex min-h-0 flex-1 items-center justify-center px-6 py-8 text-center text-[13px] text-[var(--text-tertiary)]", children: t("agentHost.workspaceAgentMessageCenterEmpty") })
1940
+ }
1941
+ )
1942
+ ] })
1943
+ }
1944
+ )
1945
+ }
1946
+ );
1947
+ }
1948
+ var MessageCenterCard = WorkspaceAgentMessageCenterCard;
1949
+ var MessageCenterStack = WorkspaceAgentMessageCenterStack;
1950
+ export {
1951
+ AgentInteractivePromptSurface,
1952
+ WorkspaceAgentMessageCenterCard,
1953
+ WorkspaceAgentMessageCenterPanel,
1954
+ approvalOptionDisplayLabel,
1955
+ buildWorkspaceAgentInteractivePromptLabels,
1956
+ buildWorkspaceAgentMessageCenterModel,
1957
+ getPromptToolDetails,
1958
+ isPromptRequestIdTitle,
1959
+ isWaitingMessageCenterItem,
1960
+ managedAgentRoundedIconUrl
1961
+ };
1962
+ //# sourceMappingURL=index.js.map