@tutti-os/agent-gui 0.0.9 → 0.0.11

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 (48) hide show
  1. package/dist/AgentMessageMarkdown-DeYPURtF.d.ts +7 -0
  2. package/dist/agent-conversation/index.d.ts +135 -0
  3. package/dist/agent-conversation/index.js +77 -0
  4. package/dist/agent-conversation/index.js.map +1 -0
  5. package/dist/agent-message-center/index.d.ts +45 -46
  6. package/dist/agent-message-center/index.js +1799 -1166
  7. package/dist/agent-message-center/index.js.map +1 -1
  8. package/dist/agent-rich-text-at-provider.d.ts +15 -1
  9. package/dist/agent-rich-text-at-provider.js +1 -1
  10. package/dist/agentConversationVM-BtHYOTgv.d.ts +342 -0
  11. package/dist/app/renderer/agentactivity.css +208 -0
  12. package/dist/{chunk-KCC3GNPB.js → chunk-77HBKGHF.js} +1 -1
  13. package/dist/chunk-77HBKGHF.js.map +1 -0
  14. package/dist/{chunk-T6U7AB7F.js → chunk-B7K776UD.js} +47 -3
  15. package/dist/chunk-B7K776UD.js.map +1 -0
  16. package/dist/{chunk-CUQJ3VO3.js → chunk-CGBRAWTD.js} +282 -2531
  17. package/dist/chunk-CGBRAWTD.js.map +1 -0
  18. package/dist/{chunk-3D5VTIKP.js → chunk-IBIMGLCD.js} +1 -28
  19. package/dist/chunk-IBIMGLCD.js.map +1 -0
  20. package/dist/{chunk-EHLA6MSQ.js → chunk-ITMKZRCT.js} +9 -19
  21. package/dist/chunk-ITMKZRCT.js.map +1 -0
  22. package/dist/chunk-MKHDRIGN.js +71 -0
  23. package/dist/chunk-MKHDRIGN.js.map +1 -0
  24. package/dist/chunk-QTZALZIV.js +2640 -0
  25. package/dist/chunk-QTZALZIV.js.map +1 -0
  26. package/dist/chunk-TYGL25EL.js +30 -0
  27. package/dist/chunk-TYGL25EL.js.map +1 -0
  28. package/dist/chunk-XJ34OIEQ.js +18 -0
  29. package/dist/chunk-XJ34OIEQ.js.map +1 -0
  30. package/dist/chunk-ZEFETOTS.js +13293 -0
  31. package/dist/chunk-ZEFETOTS.js.map +1 -0
  32. package/dist/i18n/index.d.ts +46 -2
  33. package/dist/i18n/index.js +1 -1
  34. package/dist/index.d.ts +9 -8
  35. package/dist/index.js +9713 -21513
  36. package/dist/index.js.map +1 -1
  37. package/dist/plan-decision-ops.d.ts +70 -0
  38. package/dist/plan-decision-ops.js +19 -0
  39. package/dist/plan-decision-ops.js.map +1 -0
  40. package/dist/workspace-agent-generated-files.d.ts +1 -1
  41. package/dist/workspace-agent-generated-files.js +5 -3
  42. package/dist/{workspaceAgentActivityListViewModel-Be4zm3nk.d.ts → workspaceAgentActivityListViewModel-BLLYGuFO.d.ts} +36 -2
  43. package/package.json +24 -10
  44. package/dist/chunk-3D5VTIKP.js.map +0 -1
  45. package/dist/chunk-CUQJ3VO3.js.map +0 -1
  46. package/dist/chunk-EHLA6MSQ.js.map +0 -1
  47. package/dist/chunk-KCC3GNPB.js.map +0 -1
  48. package/dist/chunk-T6U7AB7F.js.map +0 -1
@@ -1,42 +1,54 @@
1
1
  import {
2
2
  AgentInteractivePromptSurface,
3
- AgentMessageMarkdown,
4
- CustomScrollArea,
5
3
  approvalOptionDisplayLabel,
6
- cn,
7
4
  getPromptToolDetails,
8
5
  isPromptRequestIdTitle,
9
6
  managedAgentRoundedIconUrl,
10
7
  user_avatar_placeholder_default,
11
8
  workspaceAgentActivityStatusLabel
12
- } from "../chunk-CUQJ3VO3.js";
9
+ } from "../chunk-CGBRAWTD.js";
10
+ import "../chunk-4ASBZ4X7.js";
11
+ import {
12
+ resolveWorkspaceAgentSessionSortTimeUnixMs
13
+ } from "../chunk-IBIMGLCD.js";
14
+ import {
15
+ AgentMessageMarkdown,
16
+ CustomScrollArea,
17
+ cn,
18
+ extractAgentMcpToolTarget,
19
+ normalizeAskUserQuestions
20
+ } from "../chunk-QTZALZIV.js";
13
21
  import {
14
- resolveWorkspaceAgentSessionSortTimeUnixMs,
15
22
  workspaceAgentProviderLabel
16
- } from "../chunk-3D5VTIKP.js";
23
+ } from "../chunk-TYGL25EL.js";
17
24
  import {
18
25
  normalizeAgentTitleText
19
26
  } from "../chunk-GCBDIQDX.js";
20
27
  import {
21
28
  AgentGuiI18nProvider,
22
29
  useTranslation
23
- } from "../chunk-T6U7AB7F.js";
30
+ } from "../chunk-B7K776UD.js";
24
31
  import "../chunk-PJP5BUU6.js";
25
- import "../chunk-4ASBZ4X7.js";
32
+ import {
33
+ PLAN_IMPLEMENTATION_ACTION_IMPLEMENT,
34
+ PLAN_IMPLEMENTATION_PROMPT,
35
+ latestPlanTurnId,
36
+ planImplementationPromptFromPlanTurn
37
+ } from "../chunk-MKHDRIGN.js";
26
38
 
27
39
  // agent-message-center/WorkspaceAgentMessageCenterPanel.tsx
28
40
  import {
29
41
  memo,
30
42
  useCallback as useCallback2,
31
- useEffect as useEffect2,
43
+ useEffect as useEffect3,
32
44
  useLayoutEffect as useLayoutEffect2,
33
- useMemo,
34
- useRef as useRef2,
35
- useState as useState2
45
+ useMemo as useMemo2,
46
+ useRef as useRef3,
47
+ useState as useState3
36
48
  } from "react";
37
49
  import {
38
50
  Button as Button3,
39
- cn as cn4,
51
+ cn as cn5,
40
52
  Drawer,
41
53
  DrawerContent,
42
54
  TooltipProvider
@@ -81,28 +93,360 @@ var AgentVerticalScrollArea = forwardRef(function AgentVerticalScrollArea2({
81
93
  );
82
94
  });
83
95
 
84
- // agent-message-center/WorkspaceAgentMessageCenterViewControls.tsx
85
- import { ListFilter } from "lucide-react";
86
- import {
87
- Button,
88
- cn as cn2,
89
- DropdownMenu,
90
- DropdownMenuCheckboxItem,
91
- DropdownMenuContent,
92
- DropdownMenuGroup,
93
- DropdownMenuItem,
94
- DropdownMenuLabel,
95
- DropdownMenuRadioGroup,
96
- DropdownMenuRadioItem,
97
- DropdownMenuSeparator,
98
- DropdownMenuTrigger
99
- } from "@tutti-os/ui-system";
100
-
101
96
  // agent-message-center/workspaceAgentMessageCenterModel.ts
102
97
  import {
103
98
  selectNeedsAttentionItems,
104
99
  selectSessionDisplayStatuses
105
100
  } from "@tutti-os/agent-activity-core";
101
+
102
+ // agent-message-center/workspaceAgentMessageCenterDigest.ts
103
+ function buildWorkspaceAgentMessageCenterDigest({
104
+ fallbackTitle,
105
+ messages,
106
+ needsAttention,
107
+ pendingPrompt,
108
+ status
109
+ }) {
110
+ const latestAgentMessage2 = latestAgentMessageSummary(messages);
111
+ const fallbackSummary = firstNonEmptyString(
112
+ latestAgentMessage2?.summary ?? null,
113
+ needsAttention?.summary ?? null,
114
+ pendingPromptSummary(pendingPrompt),
115
+ fallbackTitle
116
+ );
117
+ if (pendingPrompt || needsAttention) {
118
+ return {
119
+ primary: {
120
+ kind: "input-required",
121
+ summary: firstNonEmptyString(
122
+ pendingPromptSummary(pendingPrompt),
123
+ needsAttention?.summary ?? null,
124
+ fallbackSummary
125
+ ),
126
+ occurredAtUnixMs: needsAttention?.occurredAtUnixMs ?? promptTimeUnixMs(pendingPrompt) ?? latestAgentMessage2?.occurredAtUnixMs ?? null
127
+ }
128
+ };
129
+ }
130
+ if (status === "failed") {
131
+ return {
132
+ primary: {
133
+ kind: "error",
134
+ summary: fallbackSummary,
135
+ occurredAtUnixMs: latestAgentMessage2?.occurredAtUnixMs ?? null
136
+ }
137
+ };
138
+ }
139
+ if (status === "completed" || status === "canceled" || status === "idle") {
140
+ return {
141
+ primary: {
142
+ kind: "outcome",
143
+ summary: fallbackSummary,
144
+ occurredAtUnixMs: latestAgentMessage2?.occurredAtUnixMs ?? null
145
+ }
146
+ };
147
+ }
148
+ if (status === "working") {
149
+ return {
150
+ primary: {
151
+ kind: "progress",
152
+ summary: fallbackSummary,
153
+ occurredAtUnixMs: latestAgentMessage2?.occurredAtUnixMs ?? null
154
+ }
155
+ };
156
+ }
157
+ return {
158
+ primary: {
159
+ kind: "summary",
160
+ summary: fallbackSummary,
161
+ occurredAtUnixMs: latestAgentMessage2?.occurredAtUnixMs ?? null
162
+ }
163
+ };
164
+ }
165
+ function latestAgentMessageSummary(messages) {
166
+ return messages.reduce(
167
+ (latest, message) => {
168
+ if (!isAgentMessageRole(message.role)) {
169
+ return latest;
170
+ }
171
+ const summary = meaningfulMessageSummary(message);
172
+ if (!summary) {
173
+ return latest;
174
+ }
175
+ const occurredAtUnixMs = messageTimeUnixMs(message);
176
+ if (!latest || occurredAtUnixMs >= latest.occurredAtUnixMs) {
177
+ return { summary, occurredAtUnixMs };
178
+ }
179
+ return latest;
180
+ },
181
+ null
182
+ );
183
+ }
184
+ function pendingPromptSummary(prompt) {
185
+ if (!prompt) {
186
+ return null;
187
+ }
188
+ switch (prompt.kind) {
189
+ case "ask-user":
190
+ return firstNonEmptyString(
191
+ prompt.title,
192
+ prompt.questions[0]?.question ?? null
193
+ );
194
+ case "approval":
195
+ case "exit-plan":
196
+ case "plan-implementation":
197
+ return prompt.title;
198
+ }
199
+ }
200
+ function promptTimeUnixMs(prompt) {
201
+ if (!prompt || !("occurredAtUnixMs" in prompt)) {
202
+ return null;
203
+ }
204
+ return positiveNumber(prompt.occurredAtUnixMs);
205
+ }
206
+ function isAgentMessageRole(role) {
207
+ const normalized = role.trim().toLowerCase();
208
+ return normalized === "assistant" || normalized === "agent";
209
+ }
210
+ function meaningfulMessageSummary(message) {
211
+ for (const candidate of messageSummaryCandidates(message)) {
212
+ if (!isGenericToolLabelSummary(message, candidate)) {
213
+ return decorateMessageSummary(message, candidate);
214
+ }
215
+ }
216
+ return "";
217
+ }
218
+ function messageSummaryCandidates(message) {
219
+ const explicitCandidates = [
220
+ summaryCandidate("payload.summary", message.payload.summary),
221
+ summaryCandidate("payload.text", message.payload.text),
222
+ summaryCandidate("payload.content", message.payload.content),
223
+ summaryCandidate("payload.message", message.payload.message),
224
+ summaryCandidate("payload.body", message.payload.body)
225
+ ];
226
+ if (!isToolLikeMessage(message)) {
227
+ return [
228
+ ...explicitCandidates,
229
+ summaryCandidate("payload.title", message.payload.title)
230
+ ].filter(
231
+ (candidate) => Boolean(candidate)
232
+ );
233
+ }
234
+ return [
235
+ ...explicitCandidates,
236
+ toolErrorSummaryCandidate(message.payload),
237
+ toolOutputSummaryCandidate(message.payload),
238
+ toolInputSummaryCandidate(message.payload),
239
+ summaryCandidate("payload.title", message.payload.title)
240
+ ].filter(
241
+ (candidate) => Boolean(candidate)
242
+ );
243
+ }
244
+ function summaryCandidate(source, value) {
245
+ const summary = normalizeSummaryText(stringValue(value));
246
+ return summary ? { source, summary } : null;
247
+ }
248
+ function toolErrorSummaryCandidate(payload) {
249
+ const error = recordValue(payload.error);
250
+ const rawOutput = recordValue(error.rawOutput);
251
+ return summaryCandidate(
252
+ "tool.error",
253
+ firstNonEmptyString(
254
+ stringValue(payload.error),
255
+ stringValue(error.summary),
256
+ stringValue(error.message),
257
+ stringValue(error.detail),
258
+ stringValue(error.text),
259
+ textFromContentValue(error.content),
260
+ stringValue(error.output),
261
+ stringValue(error.stdout),
262
+ stringValue(error.stderr),
263
+ stringValue(error.aggregated_output),
264
+ stringValue(error.formatted_output),
265
+ stringValue(rawOutput.stdout),
266
+ stringValue(rawOutput.stderr),
267
+ stringValue(rawOutput.aggregated_output),
268
+ stringValue(rawOutput.formatted_output),
269
+ stringValue(error.error)
270
+ )
271
+ );
272
+ }
273
+ function toolOutputSummaryCandidate(payload) {
274
+ const output = recordValue(payload.output);
275
+ const rawOutput = recordValue(output.rawOutput);
276
+ return summaryCandidate(
277
+ "tool.output",
278
+ firstNonEmptyString(
279
+ stringValue(output.summary),
280
+ stringValue(output.message),
281
+ stringValue(output.text),
282
+ textFromContentValue(output.content),
283
+ stringValue(output.content),
284
+ stringValue(output.result),
285
+ stringValue(output.output),
286
+ stringValue(output.stdout),
287
+ stringValue(output.stderr),
288
+ stringValue(output.aggregated_output),
289
+ stringValue(output.formatted_output),
290
+ stringValue(rawOutput.stdout),
291
+ stringValue(rawOutput.stderr),
292
+ stringValue(rawOutput.aggregated_output),
293
+ stringValue(rawOutput.formatted_output),
294
+ stringValue(payload.result)
295
+ )
296
+ );
297
+ }
298
+ function toolInputSummaryCandidate(payload) {
299
+ const input = recordValue(payload.input);
300
+ const rawInput = recordValue(input.rawInput);
301
+ const action = recordValue(input.action);
302
+ return summaryCandidate(
303
+ "tool.input",
304
+ firstNonEmptyString(
305
+ stringValue(input.summary),
306
+ stringValue(input.command),
307
+ stringValue(input.cmd),
308
+ stringValue(rawInput.command),
309
+ stringValue(rawInput.cmd),
310
+ stringValue(input.path),
311
+ stringValue(input.file_path),
312
+ stringValue(input.fileName),
313
+ stringValue(input.filename),
314
+ stringValue(input.query),
315
+ stringArrayFirstValue(input.search_query),
316
+ stringArrayFirstValue(input.searchQuery),
317
+ stringValue(input.url),
318
+ stringValue(input.pattern),
319
+ stringValue(input.glob),
320
+ stringValue(input.regex),
321
+ stringValue(input.prompt),
322
+ stringValue(action.query),
323
+ stringValue(action.url)
324
+ )
325
+ );
326
+ }
327
+ function isGenericToolLabelSummary(message, candidate) {
328
+ if (!isToolLikeMessage(message)) {
329
+ return false;
330
+ }
331
+ const normalizedSummary = normalizeToken(candidate.summary);
332
+ if (!normalizedSummary) {
333
+ return true;
334
+ }
335
+ if (structuralToolLabelTokens(message).has(normalizedSummary)) {
336
+ return true;
337
+ }
338
+ return candidate.source === "payload.title" && !hasToolDigestSignal(message) && looksLikeBareLabel(candidate.summary);
339
+ }
340
+ function decorateMessageSummary(message, candidate) {
341
+ if (!isToolLikeMessage(message)) {
342
+ return candidate.summary;
343
+ }
344
+ const mcpTarget = extractAgentMcpToolTarget({ payload: message.payload });
345
+ if (!mcpTarget) {
346
+ return candidate.summary;
347
+ }
348
+ if (candidate.summary.includes(mcpTarget.displayName)) {
349
+ return candidate.summary;
350
+ }
351
+ return `${mcpTarget.displayName}: ${candidate.summary}`;
352
+ }
353
+ function isToolLikeMessage(message) {
354
+ const payload = recordValue(message.payload);
355
+ const normalizedKind = normalizeToken(message.kind);
356
+ const normalizedType = [
357
+ stringValue(payload.type),
358
+ stringValue(payload.action),
359
+ stringValue(payload.requestType)
360
+ ].map((value) => normalizeToken(value ?? "")).join(" ");
361
+ return includesAny(normalizedKind, ["call", "tool"]) || includesAny(normalizedType, ["call", "tool"]) || Boolean(
362
+ stringValue(payload.callType) || stringValue(payload.toolName) || stringValue(payload.tool) || hasRecordValue(payload.input) || hasRecordValue(payload.output) || hasRecordValue(payload.error)
363
+ );
364
+ }
365
+ function structuralToolLabelTokens(message) {
366
+ const payload = recordValue(message.payload);
367
+ const metadata = recordValue(payload.metadata);
368
+ return new Set(
369
+ [
370
+ message.kind,
371
+ message.status,
372
+ stringValue(payload.type),
373
+ stringValue(payload.action),
374
+ stringValue(payload.requestType),
375
+ stringValue(payload.callType),
376
+ stringValue(payload.toolName),
377
+ stringValue(payload.name),
378
+ stringValue(payload.tool),
379
+ stringValue(metadata.callType),
380
+ stringValue(metadata.toolName),
381
+ stringValue(metadata.name),
382
+ stringValue(metadata.tool)
383
+ ].map((value) => normalizeToken(value ?? "")).filter(Boolean)
384
+ );
385
+ }
386
+ function includesAny(value, needles) {
387
+ return needles.some((needle) => value.includes(normalizeToken(needle)));
388
+ }
389
+ function hasToolDigestSignal(message) {
390
+ const payload = recordValue(message.payload);
391
+ return Boolean(
392
+ toolErrorSummaryCandidate(payload) || toolOutputSummaryCandidate(payload) || toolInputSummaryCandidate(payload)
393
+ );
394
+ }
395
+ function looksLikeBareLabel(value) {
396
+ const trimmed = value.trim();
397
+ return trimmed.length > 0 && trimmed.length <= 40 && !/\s/u.test(trimmed) && !/[/:\\.[\]{}()=#?&]/u.test(trimmed);
398
+ }
399
+ function normalizeToken(value) {
400
+ return value.replace(/[_\s.-]+/g, "").toLowerCase();
401
+ }
402
+ function messageTimeUnixMs(message) {
403
+ return positiveNumber(message.occurredAtUnixMs) ?? positiveNumber(message.completedAtUnixMs) ?? positiveNumber(message.startedAtUnixMs) ?? positiveNumber(message.version) ?? 0;
404
+ }
405
+ function firstNonEmptyString(...values) {
406
+ return values.find((value) => value !== null && value.trim().length > 0) ?? "";
407
+ }
408
+ function stringValue(value) {
409
+ return typeof value === "string" && value.trim() ? value.trim() : null;
410
+ }
411
+ function stringArrayFirstValue(value) {
412
+ if (!Array.isArray(value)) {
413
+ return null;
414
+ }
415
+ return value.map(stringValue).find((item) => Boolean(item)) ?? null;
416
+ }
417
+ function textFromContentValue(value) {
418
+ if (typeof value === "string") {
419
+ return stringValue(value);
420
+ }
421
+ if (Array.isArray(value)) {
422
+ return value.map(textFromContentValue).find((item) => Boolean(item)) ?? null;
423
+ }
424
+ if (!value || typeof value !== "object") {
425
+ return null;
426
+ }
427
+ const record = value;
428
+ return firstNonEmptyString(
429
+ stringValue(record.text),
430
+ "content" in record ? textFromContentValue(record.content) : null
431
+ );
432
+ }
433
+ function normalizeSummaryText(value) {
434
+ if (!value) {
435
+ return null;
436
+ }
437
+ return value.replace(/^#{1,6}\s+error\s*\n+/iu, "").replace(/\s+/gu, " ").trim();
438
+ }
439
+ function recordValue(value) {
440
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
441
+ }
442
+ function hasRecordValue(value) {
443
+ return Object.keys(recordValue(value)).length > 0;
444
+ }
445
+ function positiveNumber(value) {
446
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
447
+ }
448
+
449
+ // agent-message-center/workspaceAgentMessageCenterModel.ts
106
450
  var EMPTY_COUNTS = {
107
451
  all: 0,
108
452
  working: 0,
@@ -118,13 +462,20 @@ function buildWorkspaceAgentMessageCenterModel(snapshot, options = {}) {
118
462
  const items = snapshot.sessions.filter((session) => session.visible !== false).map((session) => {
119
463
  const messages = resolveSessionMessages(snapshot, session);
120
464
  const needsAttention = needsAttentionBySessionId.get(session.agentSessionId) ?? null;
121
- const pendingPrompt = pendingPromptFromMessages(messages) ?? fallbackPromptFromNeedsAttention(
122
- needsAttention,
123
- options.promptFallbackLabels
124
- );
125
465
  const status = displayStatuses.get(session.agentSessionId) ?? "idle";
126
466
  const lastAgentMessage = latestAgentMessage(messages);
127
467
  const title = resolveSessionTitle(session, messages);
468
+ const pendingPrompt = pendingPromptFromMessages(messages) ?? codexPlanImplementationPrompt(session, status, messages) ?? fallbackPromptFromNeedsAttention(
469
+ needsAttention,
470
+ options.promptFallbackLabels
471
+ );
472
+ const digest = buildWorkspaceAgentMessageCenterDigest({
473
+ fallbackTitle: resolveDigestFallbackTitle(session),
474
+ messages,
475
+ needsAttention,
476
+ pendingPrompt,
477
+ status
478
+ });
128
479
  const sortTimeUnixMs = resolveWorkspaceAgentSessionSortTimeUnixMs(
129
480
  session,
130
481
  {
@@ -143,11 +494,13 @@ function buildWorkspaceAgentMessageCenterModel(snapshot, options = {}) {
143
494
  ),
144
495
  cwd: session.cwd,
145
496
  status,
497
+ digest,
146
498
  lastAgentMessageSummary: lastAgentMessage?.summary ?? needsAttention?.summary ?? title,
147
499
  lastAgentMessageAtUnixMs: lastAgentMessage?.occurredAtUnixMs ?? null,
148
500
  pendingPrompt,
149
501
  needsAttentionKind: needsAttention?.kind ?? null,
150
502
  needsAttentionSummary: needsAttention?.summary ?? null,
503
+ latestTurnOutcome: latestTurnOutcome(session.agentSessionId, messages),
151
504
  sortTimeUnixMs
152
505
  };
153
506
  });
@@ -179,6 +532,12 @@ function resolveMessageCenterIdentity(agentSessionId, identityBySessionId) {
179
532
  function isWaitingMessageCenterItem(item) {
180
533
  return item.pendingPrompt !== null || item.needsAttentionKind !== null;
181
534
  }
535
+ function isInteractiveMessageCenterItem(item) {
536
+ return item.pendingPrompt !== null;
537
+ }
538
+ function selectMessageCenterAttentionDeckItems(items) {
539
+ return items.filter(isInteractiveMessageCenterItem);
540
+ }
182
541
  function isCompletedMessageCenterItem(item) {
183
542
  return item.status === "completed" || item.status === "canceled" || item.status === "idle";
184
543
  }
@@ -208,6 +567,9 @@ function resolveSessionTitle(session, messages) {
208
567
  }
209
568
  return firstUserMessageText(messages) || session.provider || session.agentSessionId;
210
569
  }
570
+ function resolveDigestFallbackTitle(session) {
571
+ return session.title.trim() || session.provider || session.agentSessionId;
572
+ }
211
573
  function firstUserMessageText(messages) {
212
574
  for (const message of messages) {
213
575
  if (message.role.trim().toLowerCase() !== "user") {
@@ -244,116 +606,112 @@ function approvalPromptFromMessage(message) {
244
606
  if (!isPermissionMessage(message)) {
245
607
  return null;
246
608
  }
247
- const payload = recordValue(message.payload);
248
- const input = recordValue(payload.input);
249
- const requestId = stringValue(input.requestId) ?? stringValue(payload.requestId) ?? stringValue(payload.approvalRequestId) ?? message.messageId;
609
+ const payload = recordValue2(message.payload);
610
+ const input = recordValue2(payload.input);
611
+ const requestId = stringValue2(input.requestId) ?? stringValue2(payload.requestId) ?? stringValue2(payload.approvalRequestId) ?? message.messageId;
250
612
  const options = [
251
613
  ...arrayValue(input.options),
252
614
  ...arrayValue(payload.options)
253
615
  ].flatMap((option) => {
254
- const record = recordValue(option);
255
- const id = stringValue(record.optionId) ?? stringValue(record.id) ?? stringValue(record.kind);
616
+ const record = recordValue2(option);
617
+ const id = stringValue2(record.optionId) ?? stringValue2(record.id) ?? stringValue2(record.kind);
256
618
  if (!id) {
257
619
  return [];
258
620
  }
259
621
  return [
260
622
  {
261
623
  id,
262
- label: stringValue(record.name) ?? stringValue(record.label) ?? stringValue(record.title) ?? id,
263
- kind: stringValue(record.kind) ?? id,
264
- ...stringValue(record.description) ? { description: stringValue(record.description) } : {}
624
+ label: stringValue2(record.name) ?? stringValue2(record.label) ?? stringValue2(record.title) ?? id,
625
+ kind: stringValue2(record.kind) ?? id,
626
+ ...stringValue2(record.description) ? { description: stringValue2(record.description) } : {}
265
627
  }
266
628
  ];
267
629
  });
268
630
  if (options.length === 0) {
269
631
  return null;
270
632
  }
633
+ const mcpTarget = extractAgentMcpToolTarget({ payload });
271
634
  return {
272
635
  kind: "approval",
273
636
  id: `approval:${requestId}`,
274
637
  turnId: message.turnId ?? "turn:unknown",
275
638
  requestId,
276
- callId: stringValue(payload.callId) ?? message.messageId,
277
- title: firstNonEmptyString(
278
- stringValue(payload.summary),
279
- stringValue(payload.title),
280
- stringValue(input.title),
281
- stringValue(input.command),
639
+ callId: stringValue2(payload.callId) ?? message.messageId,
640
+ title: firstNonEmptyString2(
641
+ mcpTarget?.displayName ?? null,
642
+ stringValue2(payload.summary),
643
+ stringValue2(payload.title),
644
+ stringValue2(input.title),
645
+ stringValue2(input.command),
282
646
  messageSummary(message),
283
647
  message.kind
284
648
  ),
285
- toolName: stringValue(payload.toolName) ?? stringValue(payload.name) ?? stringValue(payload.tool),
286
- status: message.status ?? stringValue(payload.status),
649
+ toolName: stringValue2(payload.toolName) ?? stringValue2(payload.name) ?? stringValue2(payload.tool),
650
+ status: message.status ?? stringValue2(payload.status),
287
651
  input: Object.keys(input).length > 0 ? input : payload,
288
652
  options,
289
653
  output: null,
290
- occurredAtUnixMs: messageTimeUnixMs(message) || null
654
+ occurredAtUnixMs: messageTimeUnixMs2(message) || null
291
655
  };
292
656
  }
293
657
  function askUserPromptFromMessage(message) {
294
658
  if (!isQuestionMessage(message)) {
295
659
  return null;
296
660
  }
297
- const payload = recordValue(message.payload);
298
- const questions = arrayValue(payload.questions).flatMap((value, index) => {
299
- const question = recordValue(value);
300
- const id = stringValue(question.id) ?? `question-${index + 1}`;
301
- const label = stringValue(question.question) ?? stringValue(question.header) ?? stringValue(question.label);
302
- if (!label) {
303
- return [];
304
- }
305
- return [
306
- {
307
- id,
308
- header: stringValue(question.header) ?? label,
309
- question: label,
310
- options: arrayValue(question.options).flatMap((optionValue) => {
311
- const option = recordValue(optionValue);
312
- const optionLabel = stringValue(option.label);
313
- return optionLabel ? [
314
- {
315
- label: optionLabel,
316
- description: stringValue(option.description) ?? ""
317
- }
318
- ] : [];
319
- }),
320
- multiSelect: Boolean(question.multiSelect),
321
- answer: null
322
- }
323
- ];
324
- });
661
+ const payload = recordValue2(message.payload);
662
+ const toolState = recordValue2(payload.tool_state);
663
+ const input = Object.keys(recordValue2(payload.input)).length > 0 ? recordValue2(payload.input) : recordValue2(toolState.input);
664
+ const rawQuestions = arrayValue(input.questions).length > 0 ? input.questions : payload.questions;
665
+ const questions = normalizeAskUserQuestions(rawQuestions);
325
666
  if (questions.length === 0) {
326
667
  return null;
327
668
  }
328
669
  return {
329
670
  kind: "ask-user",
330
- requestId: stringValue(payload.requestId) ?? stringValue(payload.interactiveRequestId) ?? message.messageId,
331
- title: stringValue(payload.title) ?? stringValue(payload.summary) ?? messageSummary(message),
671
+ requestId: stringValue2(input.requestId) ?? stringValue2(payload.requestId) ?? stringValue2(payload.interactiveRequestId) ?? message.messageId,
672
+ title: stringValue2(payload.title) ?? stringValue2(payload.summary) ?? messageSummary(message),
332
673
  questions
333
674
  };
334
675
  }
335
676
  function exitPlanPromptFromMessage(message) {
336
- if (!includesAny(normalizedMetadataValues(message), ["exitplanmode"])) {
677
+ if (!includesAny2(normalizedMetadataValues(message), ["exitplanmode"])) {
337
678
  return null;
338
679
  }
339
- const payload = recordValue(message.payload);
680
+ const payload = recordValue2(message.payload);
340
681
  return {
341
682
  kind: "exit-plan",
342
- requestId: stringValue(payload.requestId) ?? message.messageId,
343
- title: stringValue(payload.title) ?? stringValue(payload.summary) ?? messageSummary(message)
683
+ requestId: stringValue2(payload.requestId) ?? message.messageId,
684
+ title: stringValue2(payload.title) ?? stringValue2(payload.summary) ?? messageSummary(message)
344
685
  };
345
686
  }
687
+ function codexPlanImplementationPrompt(session, status, messages) {
688
+ if (session.provider.trim().toLowerCase() !== "codex") {
689
+ return null;
690
+ }
691
+ if (status !== "completed" && status !== "idle") {
692
+ return null;
693
+ }
694
+ const planTurnId = latestPlanTurnId(messages);
695
+ if (!planTurnId) {
696
+ return null;
697
+ }
698
+ const planMessage = messages.find(
699
+ (item) => item.turnId?.trim() === planTurnId && recordValue2(item.payload).messageKind === "plan"
700
+ );
701
+ const title = planMessage ? messageSummary(planMessage) : "";
702
+ return planImplementationPromptFromPlanTurn(planTurnId, title);
703
+ }
346
704
  function latestAgentMessage(messages) {
347
705
  return messages.reduce(
348
706
  (latest, message) => {
349
- if (!isAgentMessageRole(message.role)) {
707
+ if (!isAgentMessageRole2(message.role)) {
350
708
  return latest;
351
709
  }
352
710
  const summary = messageSummary(message);
353
711
  if (!summary) {
354
712
  return latest;
355
713
  }
356
- const occurredAtUnixMs = messageTimeUnixMs(message);
714
+ const occurredAtUnixMs = messageTimeUnixMs2(message);
357
715
  if (!latest || occurredAtUnixMs >= latest.occurredAtUnixMs) {
358
716
  return { summary, occurredAtUnixMs };
359
717
  }
@@ -362,6 +720,54 @@ function latestAgentMessage(messages) {
362
720
  null
363
721
  );
364
722
  }
723
+ function latestTurnOutcome(agentSessionId, messages) {
724
+ const latest = messages.flatMap((message) => {
725
+ const status = outcomeStatusFromMessage(message);
726
+ if (!status) {
727
+ return [];
728
+ }
729
+ const turnId = message.turnId?.trim() || null;
730
+ const messageId = message.messageId.trim();
731
+ const notificationSubject = turnId ? `turn:${turnId}` : `message:${messageId}`;
732
+ return [
733
+ {
734
+ notificationKey: `${agentSessionId}:${notificationSubject}:${status}`,
735
+ status,
736
+ turnId,
737
+ sortMessage: message
738
+ }
739
+ ];
740
+ }).sort(
741
+ (left, right) => compareMessagesByRecentTime(left.sortMessage, right.sortMessage)
742
+ )[0];
743
+ if (!latest) {
744
+ return null;
745
+ }
746
+ return {
747
+ notificationKey: latest.notificationKey,
748
+ status: latest.status,
749
+ turnId: latest.turnId
750
+ };
751
+ }
752
+ function outcomeStatusFromMessage(message) {
753
+ if (!isAgentMessageRole2(message.role)) {
754
+ return null;
755
+ }
756
+ const payload = recordValue2(message.payload);
757
+ const status = (message.status ?? stringValue2(payload.status) ?? "").trim().toLowerCase();
758
+ switch (status) {
759
+ case "completed":
760
+ case "done":
761
+ case "success":
762
+ case "succeeded":
763
+ return "completed";
764
+ case "error":
765
+ case "failed":
766
+ return "failed";
767
+ default:
768
+ return null;
769
+ }
770
+ }
365
771
  function fallbackPromptFromNeedsAttention(item, labels) {
366
772
  if (!item || item.kind === "permission" || !labels) {
367
773
  return null;
@@ -421,7 +827,7 @@ function compareMessageCenterItems(left, right) {
421
827
  }
422
828
  return right.sortTimeUnixMs - left.sortTimeUnixMs || left.agentSessionId.localeCompare(right.agentSessionId);
423
829
  }
424
- function isAgentMessageRole(role) {
830
+ function isAgentMessageRole2(role) {
425
831
  const normalized = role.trim().toLowerCase();
426
832
  return normalized === "assistant" || normalized === "agent";
427
833
  }
@@ -440,13 +846,13 @@ function isTerminalMessageStatus(status) {
440
846
  }
441
847
  }
442
848
  function isPermissionMessage(message) {
443
- return includesAny(normalizedMetadataValues(message), [
849
+ return includesAny2(normalizedMetadataValues(message), [
444
850
  "permission",
445
851
  "approval"
446
852
  ]);
447
853
  }
448
854
  function isQuestionMessage(message) {
449
- return includesAny(normalizedMetadataValues(message), [
855
+ return includesAny2(normalizedMetadataValues(message), [
450
856
  "ask_user",
451
857
  "ask-user",
452
858
  "askuserquestion",
@@ -454,1117 +860,1319 @@ function isQuestionMessage(message) {
454
860
  ]);
455
861
  }
456
862
  function normalizedMetadataValues(message) {
457
- const payload = recordValue(message.payload);
458
- const input = recordValue(payload.input);
863
+ const payload = recordValue2(message.payload);
864
+ const input = recordValue2(payload.input);
459
865
  return [
460
866
  message.kind,
461
867
  message.status ?? "",
462
- stringValue(payload.type) ?? "",
463
- stringValue(payload.action) ?? "",
464
- stringValue(payload.requestType) ?? "",
465
- stringValue(payload.callType) ?? "",
466
- stringValue(payload.toolName) ?? "",
467
- stringValue(payload.name) ?? "",
468
- stringValue(payload.status) ?? "",
469
- stringValue(input.type) ?? "",
470
- stringValue(input.action) ?? "",
471
- stringValue(input.requestType) ?? "",
472
- stringValue(input.callType) ?? "",
473
- stringValue(input.toolName) ?? "",
474
- stringValue(input.name) ?? "",
475
- stringValue(input.status) ?? ""
868
+ stringValue2(payload.type) ?? "",
869
+ stringValue2(payload.action) ?? "",
870
+ stringValue2(payload.requestType) ?? "",
871
+ stringValue2(payload.callType) ?? "",
872
+ stringValue2(payload.toolName) ?? "",
873
+ stringValue2(payload.name) ?? "",
874
+ stringValue2(payload.status) ?? "",
875
+ stringValue2(input.type) ?? "",
876
+ stringValue2(input.action) ?? "",
877
+ stringValue2(input.requestType) ?? "",
878
+ stringValue2(input.callType) ?? "",
879
+ stringValue2(input.toolName) ?? "",
880
+ stringValue2(input.name) ?? "",
881
+ stringValue2(input.status) ?? ""
476
882
  ].join(" ").replace(/[_\s-]+/g, "").toLowerCase();
477
883
  }
478
884
  function compareMessagesByRecentTime(left, right) {
479
- return messageTimeUnixMs(right) - messageTimeUnixMs(left) || right.version - left.version || right.messageId.localeCompare(left.messageId);
885
+ return messageTimeUnixMs2(right) - messageTimeUnixMs2(left) || right.version - left.version || right.messageId.localeCompare(left.messageId);
480
886
  }
481
- function includesAny(value, needles) {
887
+ function includesAny2(value, needles) {
482
888
  return needles.some(
483
889
  (needle) => value.includes(needle.replace(/[_\s-]+/g, "").toLowerCase())
484
890
  );
485
891
  }
486
892
  function messageSummary(message) {
487
- return firstNonEmptyString(
488
- stringValue(message.payload.summary),
489
- stringValue(message.payload.text),
490
- stringValue(message.payload.content),
491
- stringValue(message.payload.message),
492
- stringValue(message.payload.body),
493
- stringValue(message.payload.title)
893
+ return firstNonEmptyString2(
894
+ stringValue2(message.payload.summary),
895
+ stringValue2(message.payload.text),
896
+ stringValue2(message.payload.content),
897
+ stringValue2(message.payload.message),
898
+ stringValue2(message.payload.body),
899
+ stringValue2(message.payload.title)
494
900
  );
495
901
  }
496
- function messageTimeUnixMs(message) {
497
- return positiveNumber(message.occurredAtUnixMs) ?? positiveNumber(message.completedAtUnixMs) ?? positiveNumber(message.startedAtUnixMs) ?? positiveNumber(message.version) ?? 0;
902
+ function messageTimeUnixMs2(message) {
903
+ return positiveNumber2(message.occurredAtUnixMs) ?? positiveNumber2(message.completedAtUnixMs) ?? positiveNumber2(message.startedAtUnixMs) ?? positiveNumber2(message.version) ?? 0;
498
904
  }
499
- function firstNonEmptyString(...values) {
905
+ function firstNonEmptyString2(...values) {
500
906
  return values.find((value) => value !== null && value.length > 0) ?? "";
501
907
  }
502
- function stringValue(value) {
908
+ function stringValue2(value) {
503
909
  return typeof value === "string" && value.trim() ? value.trim() : null;
504
910
  }
505
- function recordValue(value) {
911
+ function recordValue2(value) {
506
912
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
507
913
  }
508
914
  function arrayValue(value) {
509
915
  return Array.isArray(value) ? value : [];
510
916
  }
511
- function positiveNumber(value) {
917
+ function positiveNumber2(value) {
512
918
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
513
919
  }
514
920
 
515
- // agent-message-center/workspaceAgentMessageCenterViewModel.ts
516
- function partitionMessageCenterItemsByAgentUser(items) {
517
- const stacks = /* @__PURE__ */ new Map();
518
- for (const item of items) {
519
- const stackId = messageCenterAgentUserStackId(item);
520
- const stack = stacks.get(stackId);
521
- if (stack) {
522
- stack.items.push(item);
523
- } else {
524
- stacks.set(stackId, {
525
- id: stackId,
526
- provider: item.provider,
527
- userId: item.userId,
528
- items: [item]
529
- });
530
- }
531
- }
532
- return [...stacks.values()];
533
- }
534
- function messageCenterAgentUserStackId(item) {
535
- const provider = item.provider.trim().toLowerCase() || "unknown-agent";
536
- const userId = item.userId?.trim() || "unknown-user";
537
- return `agent-user:${provider}:${userId}`;
538
- }
539
- function buildMessageCenterStatusOptions(counts, t) {
540
- return [
541
- {
542
- count: counts.waiting,
543
- label: t("agentHost.workspaceAgentMessageCenterFilterWaiting"),
544
- value: "waiting"
545
- },
546
- {
547
- count: counts.failed,
548
- label: t("agentHost.workspaceAgentMessageCenterFilterFailed"),
549
- value: "failed"
550
- },
551
- {
552
- count: counts.working,
553
- label: t("agentHost.workspaceAgentMessageCenterFilterWorking"),
554
- value: "working"
555
- },
921
+ // agent-message-center/WorkspaceAgentMessageCenterAttentionDeck.tsx
922
+ import { useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
923
+ import { cn as cn3 } from "@tutti-os/ui-system";
924
+
925
+ // agent-message-center/WorkspaceAgentMessageCenterCard.tsx
926
+ import {
927
+ useCallback,
928
+ useEffect,
929
+ useLayoutEffect,
930
+ useRef,
931
+ useState
932
+ } from "react";
933
+ import { ChevronDown, ChevronUp, ExternalLink, Info } from "lucide-react";
934
+ import {
935
+ Button,
936
+ cn as cn2,
937
+ StatusDot,
938
+ Tooltip,
939
+ TooltipContent,
940
+ TooltipTrigger
941
+ } from "@tutti-os/ui-system";
942
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
943
+ function stopMessageCenterTextPointerPropagation(event) {
944
+ event.stopPropagation();
945
+ }
946
+ function WorkspaceAgentMessageCenterCard({
947
+ cardRef,
948
+ highlighted = false,
949
+ interactive = true,
950
+ item,
951
+ isSubmitting,
952
+ onLinkAction,
953
+ onOpenChat,
954
+ onSubmitPrompt
955
+ }) {
956
+ "use memo";
957
+ const { t } = useTranslation();
958
+ const prompt = item.pendingPrompt;
959
+ const displayTitle = normalizeAgentTitleText(item.title);
960
+ const summary = messageCenterVisibleSummary(item);
961
+ const displayStatus = statusClass(item);
962
+ const statusLabel = workspaceAgentActivityStatusLabel(displayStatus, t);
963
+ return /* @__PURE__ */ jsxs(
964
+ "article",
556
965
  {
557
- count: counts.completed,
558
- label: t("agentHost.workspaceAgentMessageCenterFilterCompleted"),
559
- value: "completed"
966
+ ref: cardRef,
967
+ className: cn2(
968
+ "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]",
969
+ isWaitingMessageCenterItem(item) && "agent-gui-edge-glow border-[var(--tutti-purple-border)] bg-[var(--tutti-purple-bg)]",
970
+ highlighted && "outline-2 outline-[var(--accent)]"
971
+ ),
972
+ "data-highlighted": highlighted ? "true" : void 0,
973
+ "data-message-center-digest-kind": item.digest.primary.kind,
974
+ "data-message-center-item-id": item.id,
975
+ "data-waiting": isWaitingMessageCenterItem(item) ? "true" : void 0,
976
+ "data-status": displayStatus,
977
+ tabIndex: highlighted ? -1 : void 0,
978
+ children: [
979
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center justify-between gap-2.5", children: [
980
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-1.5", children: [
981
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
982
+ /* @__PURE__ */ jsx2(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx2(
983
+ "h3",
984
+ {
985
+ className: "workspace-agent-message-center__copy-text min-w-0 truncate text-[13px] font-bold leading-5 text-[var(--text-secondary)]",
986
+ onPointerDown: stopMessageCenterTextPointerPropagation,
987
+ children: displayTitle
988
+ }
989
+ ) }),
990
+ /* @__PURE__ */ jsx2(
991
+ TooltipContent,
992
+ {
993
+ side: "top",
994
+ align: "start",
995
+ className: "max-w-[min(360px,calc(100vw-32px))] whitespace-normal text-left [overflow-wrap:anywhere]",
996
+ children: displayTitle
997
+ }
998
+ )
999
+ ] }),
1000
+ item.cwd ? /* @__PURE__ */ jsx2(ProjectPathInfo, { path: item.cwd }) : null
1001
+ ] }),
1002
+ /* @__PURE__ */ jsxs(
1003
+ "span",
1004
+ {
1005
+ 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)]",
1006
+ "data-status": displayStatus,
1007
+ title: statusLabel,
1008
+ children: [
1009
+ /* @__PURE__ */ jsx2(
1010
+ StatusDot,
1011
+ {
1012
+ tone: messageCenterStatusTone(item),
1013
+ pulse: isWaitingMessageCenterItem(item) || item.status === "working",
1014
+ size: "sm",
1015
+ title: statusLabel
1016
+ }
1017
+ ),
1018
+ /* @__PURE__ */ jsx2("span", { children: statusLabel })
1019
+ ]
1020
+ }
1021
+ )
1022
+ ] }),
1023
+ summary ? /* @__PURE__ */ jsx2(
1024
+ MessageCenterSummary,
1025
+ {
1026
+ item,
1027
+ onLinkAction,
1028
+ summary,
1029
+ emptyLabel: t("agentHost.workspaceAgentMessageCenterNoSummary")
1030
+ }
1031
+ ) : null,
1032
+ prompt && interactive ? /* @__PURE__ */ jsx2("div", { className: "min-w-0", children: /* @__PURE__ */ jsx2(
1033
+ AgentInteractivePromptSurface,
1034
+ {
1035
+ embedded: true,
1036
+ variant: "compact",
1037
+ keyboardShortcuts: false,
1038
+ prompt,
1039
+ isSubmitting,
1040
+ onSubmit: onSubmitPrompt,
1041
+ labels: buildWorkspaceAgentInteractivePromptLabels(
1042
+ t,
1043
+ item.provider
1044
+ )
1045
+ }
1046
+ ) }) : null,
1047
+ /* @__PURE__ */ jsx2(
1048
+ MessageCenterOpenChatButton,
1049
+ {
1050
+ provider: item.provider,
1051
+ item,
1052
+ label: t("agentHost.workspaceAgentMessageCenterOpenChat"),
1053
+ onOpenChat,
1054
+ alwaysVisible: interactive && prompt !== null
1055
+ }
1056
+ )
1057
+ ]
560
1058
  }
561
- ];
1059
+ );
562
1060
  }
563
- function buildMessageCenterProviderOptions(items) {
564
- const counts = /* @__PURE__ */ new Map();
565
- for (const item of items) {
566
- counts.set(item.provider, (counts.get(item.provider) ?? 0) + 1);
567
- }
568
- return [...counts.entries()].map(([value, count]) => ({
569
- count,
570
- label: workspaceAgentProviderLabel(value),
571
- value
572
- })).sort((left, right) => left.label.localeCompare(right.label));
1061
+ var STACK_PRESENCE_FALLBACK_MS = 380;
1062
+ function useStackRegionPresence(visible) {
1063
+ const [mounted, setMounted] = useState(visible);
1064
+ const closing = mounted && !visible;
1065
+ useLayoutEffect(() => {
1066
+ if (visible) {
1067
+ setMounted(true);
1068
+ }
1069
+ }, [visible]);
1070
+ useEffect(() => {
1071
+ if (!closing) {
1072
+ return void 0;
1073
+ }
1074
+ const timeoutId = window.setTimeout(() => {
1075
+ setMounted(false);
1076
+ }, STACK_PRESENCE_FALLBACK_MS);
1077
+ return () => {
1078
+ window.clearTimeout(timeoutId);
1079
+ };
1080
+ }, [closing]);
1081
+ const onAnimationEnd = useCallback(
1082
+ (event) => {
1083
+ if (event.target === event.currentTarget && closing) {
1084
+ setMounted(false);
1085
+ }
1086
+ },
1087
+ [closing]
1088
+ );
1089
+ return { closing, mounted, onAnimationEnd };
573
1090
  }
574
- function itemMatchesViewFilters({
575
- item,
576
- providerFilters,
577
- statusFilters
1091
+ function WorkspaceAgentMessageCenterStack({
1092
+ className,
1093
+ expanded,
1094
+ groupId,
1095
+ items,
1096
+ renderCard,
1097
+ onCollapse,
1098
+ onExpand
578
1099
  }) {
579
- if (statusFilters && !statusFilters.has(messageCenterStatusFilterValue(item))) {
580
- return false;
581
- }
582
- if (providerFilters && !providerFilters.has(item.provider)) {
583
- return false;
1100
+ "use memo";
1101
+ const { t } = useTranslation();
1102
+ const summaryRegion = useStackRegionPresence(!expanded);
1103
+ const cardsRegion = useStackRegionPresence(expanded);
1104
+ if (items.length < 2) {
1105
+ return null;
584
1106
  }
585
- return true;
1107
+ const collapseLabel = t(
1108
+ "agentHost.workspaceAgentMessageCenterCollapseStackAria"
1109
+ );
1110
+ return /* @__PURE__ */ jsxs(
1111
+ "div",
1112
+ {
1113
+ className: cn2("relative flex min-w-0 flex-col", className),
1114
+ "data-stack-count": items.length,
1115
+ "data-stack-motion": "smooth",
1116
+ "data-stack-state": expanded ? "expanded" : "collapsed",
1117
+ "data-stack-top-item-id": items[0]?.id,
1118
+ "data-testid": `workspace-agent-message-stack-${groupId}`,
1119
+ children: [
1120
+ summaryRegion.mounted ? /* @__PURE__ */ jsx2(
1121
+ "div",
1122
+ {
1123
+ className: cn2(
1124
+ "workspace-agent-message-center__stack-rest min-w-0",
1125
+ summaryRegion.closing ? "workspace-agent-message-center__stack-rest--closing" : "workspace-agent-message-center__stack-rest--opening"
1126
+ ),
1127
+ onAnimationEnd: summaryRegion.onAnimationEnd,
1128
+ children: /* @__PURE__ */ jsx2(
1129
+ "div",
1130
+ {
1131
+ className: "min-h-0 min-w-0 overflow-hidden",
1132
+ "aria-hidden": summaryRegion.closing ? true : void 0,
1133
+ inert: summaryRegion.closing ? true : void 0,
1134
+ children: /* @__PURE__ */ jsx2(
1135
+ MessageCenterStackSummary,
1136
+ {
1137
+ groupId,
1138
+ items,
1139
+ onExpand
1140
+ }
1141
+ )
1142
+ }
1143
+ )
1144
+ }
1145
+ ) : null,
1146
+ cardsRegion.mounted ? /* @__PURE__ */ jsx2(
1147
+ "div",
1148
+ {
1149
+ className: cn2(
1150
+ "workspace-agent-message-center__stack-rest min-w-0",
1151
+ cardsRegion.closing ? "workspace-agent-message-center__stack-rest--closing" : "workspace-agent-message-center__stack-rest--opening"
1152
+ ),
1153
+ onAnimationEnd: cardsRegion.onAnimationEnd,
1154
+ children: /* @__PURE__ */ jsxs(
1155
+ "div",
1156
+ {
1157
+ className: "min-h-0 min-w-0 overflow-hidden",
1158
+ "aria-hidden": cardsRegion.closing ? true : void 0,
1159
+ inert: cardsRegion.closing ? true : void 0,
1160
+ children: [
1161
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center justify-between gap-2 px-0.5 pb-1.5", children: [
1162
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-1.5 text-[13px] font-semibold leading-4 text-[var(--text-tertiary)]", children: [
1163
+ /* @__PURE__ */ jsx2(
1164
+ MessageCenterIdentityAvatarMark,
1165
+ {
1166
+ identity: items[0]?.identity ?? null,
1167
+ provider: items[0]?.provider ?? "",
1168
+ userId: items[0]?.userId ?? null
1169
+ }
1170
+ ),
1171
+ /* @__PURE__ */ jsx2("span", { className: "min-w-0 truncate", children: t("agentHost.workspaceAgentMessageCenterStackSummaryCount", {
1172
+ count: items.length
1173
+ }) })
1174
+ ] }),
1175
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
1176
+ /* @__PURE__ */ jsx2(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx2(
1177
+ Button,
1178
+ {
1179
+ type: "button",
1180
+ variant: "ghost",
1181
+ size: "icon-sm",
1182
+ "aria-label": collapseLabel,
1183
+ className: "size-6 text-[var(--text-tertiary)] hover:text-[var(--text-primary)]",
1184
+ onClick: onCollapse,
1185
+ children: /* @__PURE__ */ jsx2(ChevronUp, { className: "size-3.5", "aria-hidden": "true" })
1186
+ }
1187
+ ) }),
1188
+ /* @__PURE__ */ jsx2(TooltipContent, { side: "top", align: "center", children: collapseLabel })
1189
+ ] })
1190
+ ] }),
1191
+ /* @__PURE__ */ jsx2("div", { className: "flex min-w-0 flex-col gap-2.5", children: items.map(
1192
+ (item, stackedIndex) => renderCard(item, { stackedIndex })
1193
+ ) })
1194
+ ]
1195
+ }
1196
+ )
1197
+ }
1198
+ ) : null
1199
+ ]
1200
+ }
1201
+ );
586
1202
  }
587
- function messageCenterStatusFilterValue(item) {
588
- if (isWaitingMessageCenterItem(item)) {
589
- return "waiting";
590
- }
591
- if (item.status === "failed") {
592
- return "failed";
593
- }
594
- if (item.status === "working") {
595
- return "working";
1203
+ function MessageCenterStackSummary({
1204
+ groupId,
1205
+ items,
1206
+ onExpand
1207
+ }) {
1208
+ "use memo";
1209
+ const { t } = useTranslation();
1210
+ const firstItem = items[0];
1211
+ const hasWaiting = items.some((item) => isWaitingMessageCenterItem(item));
1212
+ if (!firstItem) {
1213
+ return null;
596
1214
  }
597
- return "completed";
598
- }
599
- function groupMessageCenterItems(items, groupBy, t) {
600
- switch (groupBy) {
601
- case "status":
602
- return groupByFixedDefinitions(items, [
603
- {
604
- id: "waiting",
605
- label: t("agentHost.workspaceAgentMessageCenterFilterWaiting"),
606
- match: (item) => messageCenterStatusFilterValue(item) === "waiting"
607
- },
608
- {
609
- id: "failed",
610
- label: t("agentHost.workspaceAgentMessageCenterFilterFailed"),
611
- match: (item) => messageCenterStatusFilterValue(item) === "failed"
612
- },
613
- {
614
- id: "working",
615
- label: t("agentHost.workspaceAgentMessageCenterFilterWorking"),
616
- match: (item) => messageCenterStatusFilterValue(item) === "working"
617
- },
618
- {
619
- id: "completed",
620
- label: t("agentHost.workspaceAgentMessageCenterFilterCompleted"),
621
- match: (item) => messageCenterStatusFilterValue(item) === "completed"
622
- }
623
- ]);
624
- case "agent":
625
- return groupByDynamicKey(items, (item) => ({
626
- id: messageCenterAgentUserStackId(item),
627
- identity: item.identity,
628
- label: messageCenterAgentUserGroupLabel(item),
629
- provider: item.provider,
630
- userId: item.userId
631
- }));
632
- case "time":
633
- return groupByFixedDefinitions(items, [
634
- {
635
- id: "today",
636
- label: t("agentHost.workspaceAgentMessageCenterGroupToday"),
637
- match: (item) => messageCenterTimeGroup(item) === "today"
638
- },
639
- {
640
- id: "yesterday",
641
- label: t("agentHost.workspaceAgentMessageCenterGroupYesterday"),
642
- match: (item) => messageCenterTimeGroup(item) === "yesterday"
643
- },
644
- {
645
- id: "previous-seven-days",
646
- label: t(
647
- "agentHost.workspaceAgentMessageCenterGroupPreviousSevenDays"
648
- ),
649
- match: (item) => messageCenterTimeGroup(item) === "previous-seven-days"
650
- },
651
- {
652
- id: "older",
653
- label: t("agentHost.workspaceAgentMessageCenterGroupOlder"),
654
- match: (item) => messageCenterTimeGroup(item) === "older"
655
- }
656
- ]);
657
- case "priority":
658
- default: {
659
- const nowUnixMs = Date.now();
660
- return groupByFixedDefinitions(items, [
661
- {
662
- id: "needs-attention",
663
- label: t("agentHost.workspaceAgentMessageCenterGroupNeedsAttention"),
664
- match: (item) => messageCenterStatusFilterValue(item) === "waiting" || messageCenterStatusFilterValue(item) === "failed"
665
- },
666
- {
667
- id: "working",
668
- label: t("agentHost.workspaceAgentMessageCenterFilterWorking"),
669
- match: (item) => messageCenterStatusFilterValue(item) === "working"
670
- },
1215
+ return /* @__PURE__ */ jsx2(
1216
+ "button",
1217
+ {
1218
+ type: "button",
1219
+ "aria-label": t("agentHost.workspaceAgentMessageCenterExpandStackAria", {
1220
+ count: items.length
1221
+ }),
1222
+ className: cn2(
1223
+ "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)]",
1224
+ items.length > 2 ? "pb-[18px]" : "pb-[10px]"
1225
+ ),
1226
+ "data-stack-summary-count": items.length,
1227
+ "data-stack-provider": firstItem.provider,
1228
+ "data-stack-user-id": firstItem.userId ?? "",
1229
+ "data-testid": `workspace-agent-message-stack-summary-${groupId}`,
1230
+ onClick: onExpand,
1231
+ children: /* @__PURE__ */ jsxs(
1232
+ "span",
671
1233
  {
672
- id: "recently-completed",
673
- label: t(
674
- "agentHost.workspaceAgentMessageCenterGroupRecentlyCompleted"
1234
+ className: cn2(
1235
+ "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)]",
1236
+ 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)]",
1237
+ hasWaiting && "border-[var(--tutti-purple-border)] bg-[var(--tutti-purple-bg)]"
675
1238
  ),
676
- match: (item) => isRecentlyCompletedMessageCenterItem(item, nowUnixMs)
677
- },
678
- {
679
- id: "completed",
680
- label: t("agentHost.workspaceAgentMessageCenterFilterCompleted"),
681
- match: (item) => messageCenterStatusFilterValue(item) === "completed" && !isRecentlyCompletedMessageCenterItem(item, nowUnixMs)
1239
+ children: [
1240
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center justify-between gap-2.5", children: [
1241
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-2", children: [
1242
+ /* @__PURE__ */ jsx2(
1243
+ MessageCenterIdentityAvatarMark,
1244
+ {
1245
+ identity: firstItem.identity,
1246
+ provider: firstItem.provider,
1247
+ userId: firstItem.userId
1248
+ }
1249
+ ),
1250
+ /* @__PURE__ */ jsx2("span", { className: "min-w-0 truncate text-[13px] font-bold leading-5 text-[var(--text-secondary)]", children: t("agentHost.workspaceAgentMessageCenterStackSummaryCount", {
1251
+ count: items.length
1252
+ }) })
1253
+ ] }),
1254
+ /* @__PURE__ */ jsx2(
1255
+ ChevronDown,
1256
+ {
1257
+ 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",
1258
+ "aria-hidden": "true"
1259
+ }
1260
+ )
1261
+ ] }),
1262
+ /* @__PURE__ */ jsx2("span", { className: "min-w-0 rounded-md bg-transparency-block p-2.5 text-[13px] leading-[1.45] text-[var(--text-primary)]", children: /* @__PURE__ */ jsx2("span", { className: "line-clamp-2 min-w-0 [overflow-wrap:anywhere]", children: messageCenterStackPreviewText(firstItem) }) })
1263
+ ]
682
1264
  }
683
- ]);
1265
+ )
684
1266
  }
685
- }
1267
+ );
686
1268
  }
687
- function messageCenterAgentUserGroupLabel(item) {
688
- if (item.identity) {
689
- return `${item.identity.userName} & ${item.identity.agentName}`;
690
- }
691
- return workspaceAgentProviderLabel(item.provider);
1269
+ function messageCenterStackPreviewText(item) {
1270
+ return item.digest.primary.summary.trim() || item.lastAgentMessageSummary.trim() || normalizeAgentTitleText(item.title);
692
1271
  }
693
- var RECENTLY_COMPLETED_WINDOW_MS = 10 * 60 * 1e3;
694
- function isRecentlyCompletedMessageCenterItem(item, nowUnixMs) {
695
- if (messageCenterStatusFilterValue(item) !== "completed") {
696
- return false;
1272
+ function resolveMessageCenterNotificationAction(item, input) {
1273
+ if (input.action) {
1274
+ return normalizeMessageCenterNotificationAction(input.action);
697
1275
  }
698
- const completedAtUnixMs = item.sortTimeUnixMs || item.lastAgentMessageAtUnixMs || 0;
699
- if (completedAtUnixMs <= 0) {
700
- return false;
1276
+ if (!input.optionId) {
1277
+ return null;
701
1278
  }
702
- return completedAtUnixMs >= nowUnixMs - RECENTLY_COMPLETED_WINDOW_MS;
1279
+ const prompt = item.pendingPrompt;
1280
+ const option = prompt && "options" in prompt ? prompt.options.find((candidate) => candidate.id === input.optionId) : null;
1281
+ const optionToken = `${option?.kind ?? ""}:${input.optionId}`.toLowerCase();
1282
+ if (optionToken.includes("allow") || optionToken.includes("accept")) {
1283
+ return "accept";
1284
+ }
1285
+ if (optionToken.includes("deny") || optionToken.includes("reject") || optionToken.includes("disallow")) {
1286
+ return "reject";
1287
+ }
1288
+ return input.optionId;
1289
+ }
1290
+ function buildWorkspaceAgentInteractivePromptLabels(t, provider) {
1291
+ return {
1292
+ approvalLead: t("agentHost.agentGui.approvalRequired", {
1293
+ provider: provider ? workspaceAgentProviderLabel(provider) : t("agentHost.workspaceAgentsGenericAgentName")
1294
+ }),
1295
+ planLead: t("agentHost.agentGui.planLead"),
1296
+ planModes: [
1297
+ {
1298
+ id: "acceptEdits",
1299
+ label: t("agentHost.agentGui.planModes.acceptEdits.label"),
1300
+ description: t("agentHost.agentGui.planModes.acceptEdits.description")
1301
+ },
1302
+ {
1303
+ id: "default",
1304
+ label: t("agentHost.agentGui.planModes.askFirst.label"),
1305
+ description: t("agentHost.agentGui.planModes.askFirst.description")
1306
+ },
1307
+ {
1308
+ id: "bypassPermissions",
1309
+ label: t("agentHost.agentGui.planModes.allowAll.label"),
1310
+ description: t("agentHost.agentGui.planModes.allowAll.description")
1311
+ }
1312
+ ],
1313
+ stayInPlan: t("agentHost.agentGui.stayInPlan"),
1314
+ sendFeedback: t("agentHost.agentGui.sendFeedback"),
1315
+ feedbackPlaceholder: t("agentHost.agentGui.feedbackPlaceholder"),
1316
+ previousQuestion: t("agentHost.agentGui.previousQuestion"),
1317
+ nextQuestion: t("agentHost.agentGui.nextQuestion"),
1318
+ submitAnswers: t("agentHost.agentGui.submitAnswers"),
1319
+ answerPlaceholder: t("agentHost.agentGui.answerPlaceholder"),
1320
+ waitingForAnswer: t("agentHost.agentGui.waitingForAnswer"),
1321
+ planImplementationLead: t("agentHost.agentGui.planImplementationLead"),
1322
+ planImplementationConfirm: t(
1323
+ "agentHost.agentGui.planImplementationConfirm"
1324
+ ),
1325
+ planImplementationFeedbackPlaceholder: t(
1326
+ "agentHost.agentGui.planImplementationFeedbackPlaceholder"
1327
+ ),
1328
+ planImplementationSend: t("agentHost.agentGui.planImplementationSend"),
1329
+ planImplementationSkip: t("agentHost.agentGui.planImplementationSkip")
1330
+ };
703
1331
  }
704
- function messageCenterGroupLabel(groupBy, t) {
705
- switch (groupBy) {
706
- case "status":
707
- return t("agentHost.workspaceAgentMessageCenterGroupStatus");
708
- case "agent":
709
- return t("agentHost.workspaceAgentMessageCenterGroupAgent");
710
- case "time":
711
- return t("agentHost.workspaceAgentMessageCenterGroupTime");
712
- case "priority":
1332
+ function normalizeMessageCenterNotificationAction(action) {
1333
+ switch (action) {
1334
+ case "allow":
1335
+ return "accept";
1336
+ case "deny":
1337
+ return "reject";
713
1338
  default:
714
- return t("agentHost.workspaceAgentMessageCenterGroupPriority");
1339
+ return action;
715
1340
  }
716
1341
  }
717
- function statusFilterSummary(statusFilters, statusOptions) {
718
- if (statusFilters === null || statusFilters.size === statusOptions.length) {
719
- return statusOptions.map((option) => option.label).join(", ");
1342
+ function messageCenterVisibleSummary(item) {
1343
+ const summary = item.digest.primary.summary.trim();
1344
+ if (item.pendingPrompt?.kind === "approval" && isGenericApprovalSummary(summary)) {
1345
+ return "";
720
1346
  }
721
- return statusOptions.filter((option) => statusFilters.has(option.value)).map((option) => option.label).join(", ");
1347
+ return summary;
722
1348
  }
723
- function groupByFixedDefinitions(items, definitions) {
724
- return definitions.map((definition) => ({
725
- id: definition.id,
726
- label: definition.label,
727
- items: items.filter(definition.match)
728
- })).filter((group) => group.items.length > 0);
1349
+ function isGenericApprovalSummary(summary) {
1350
+ const normalized = summary.trim().toLowerCase();
1351
+ return normalized === "approval";
729
1352
  }
730
- function groupByDynamicKey(items, keyForItem) {
731
- const groups = /* @__PURE__ */ new Map();
732
- for (const item of items) {
733
- const key = keyForItem(item);
734
- const group = groups.get(key.id);
735
- if (group) {
736
- group.items.push(item);
737
- if (!group.identity && key.identity) {
738
- group.identity = key.identity;
739
- group.label = key.label;
740
- }
741
- } else {
742
- groups.set(key.id, { ...key, items: [item] });
1353
+ function MessageCenterSummary({
1354
+ emptyLabel,
1355
+ item,
1356
+ onLinkAction,
1357
+ summary
1358
+ }) {
1359
+ "use memo";
1360
+ const summaryRef = useRef(null);
1361
+ const [isOverflowing, setIsOverflowing] = useState(false);
1362
+ const handleLinkAction = useCallback(
1363
+ (action) => {
1364
+ onLinkAction?.(
1365
+ action.type === "open-agent-session" && !action.provider ? { ...action, provider: item.provider } : action
1366
+ );
1367
+ },
1368
+ [item.provider, onLinkAction]
1369
+ );
1370
+ useLayoutEffect(() => {
1371
+ const element = summaryRef.current;
1372
+ if (!element) {
1373
+ return;
743
1374
  }
744
- }
745
- return [...groups.values()];
746
- }
747
- function messageCenterTimeGroup(item) {
748
- const timestamp = item.sortTimeUnixMs || item.lastAgentMessageAtUnixMs || 0;
749
- if (timestamp <= 0) {
750
- return "older";
751
- }
752
- const ageMs = Date.now() - timestamp;
753
- const dayMs = 24 * 60 * 60 * 1e3;
754
- if (ageMs < dayMs) {
755
- return "today";
756
- }
757
- if (ageMs < dayMs * 2) {
758
- return "yesterday";
759
- }
760
- if (ageMs < dayMs * 7) {
761
- return "previous-seven-days";
762
- }
763
- return "older";
1375
+ const updateOverflowState = () => {
1376
+ setIsOverflowing(element.scrollHeight > element.clientHeight + 1);
1377
+ };
1378
+ updateOverflowState();
1379
+ const resizeObserver = new ResizeObserver(updateOverflowState);
1380
+ resizeObserver.observe(element);
1381
+ return () => {
1382
+ resizeObserver.disconnect();
1383
+ };
1384
+ }, [summary]);
1385
+ return /* @__PURE__ */ jsx2(
1386
+ AgentVerticalScrollArea,
1387
+ {
1388
+ ref: summaryRef,
1389
+ className: cn2(
1390
+ "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]",
1391
+ isOverflowing && "workspace-agent-message-center__summary--overflowing"
1392
+ ),
1393
+ viewportClassName: "workspace-agent-message-center__copy-text max-h-[160px] p-2.5 pr-4",
1394
+ onPointerDown: stopMessageCenterTextPointerPropagation,
1395
+ scrollbarClassName: "top-2 bottom-2 right-1.5",
1396
+ syncKey: summary,
1397
+ children: summary ? /* @__PURE__ */ jsx2(
1398
+ AgentMessageMarkdown,
1399
+ {
1400
+ content: summary,
1401
+ 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)]",
1402
+ onLinkAction: handleLinkAction,
1403
+ workspaceLinkContext: {
1404
+ workspaceRoot: item.cwd || null,
1405
+ basePath: item.cwd,
1406
+ source: "agent-markdown"
1407
+ },
1408
+ enableImageZoom: true
1409
+ }
1410
+ ) : emptyLabel
1411
+ }
1412
+ );
764
1413
  }
765
-
766
- // agent-message-center/WorkspaceAgentMessageCenterViewControls.tsx
767
- import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
768
- function MessageCenterViewMenu({
769
- filtersActive = false,
770
- groupBy,
771
- providerFilters,
772
- providerOptions,
773
- statusFilters,
774
- statusOptions,
775
- onClearFilters,
776
- onGroupByChange,
777
- onProviderToggle,
778
- onStatusToggle
1414
+ function MessageCenterOpenChatButton({
1415
+ alwaysVisible = false,
1416
+ item,
1417
+ label,
1418
+ onOpenChat,
1419
+ provider
779
1420
  }) {
780
1421
  "use memo";
781
- const { t } = useTranslation();
782
- return /* @__PURE__ */ jsxs(DropdownMenu, { modal: false, children: [
783
- /* @__PURE__ */ jsx2(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
1422
+ return /* @__PURE__ */ jsxs("div", { className: "workspace-agent-message-center__footer flex min-w-0 items-center justify-between gap-2", children: [
1423
+ /* @__PURE__ */ jsx2(
1424
+ MessageCenterIdentityLabel,
1425
+ {
1426
+ identity: item.identity,
1427
+ provider
1428
+ }
1429
+ ),
1430
+ /* @__PURE__ */ jsxs(
784
1431
  Button,
785
1432
  {
786
1433
  type: "button",
787
1434
  variant: "ghost",
788
- size: "icon",
789
- "aria-label": t("agentHost.workspaceAgentMessageCenterViewOptions"),
790
- title: t("agentHost.workspaceAgentMessageCenterViewOptions"),
1435
+ size: "default",
791
1436
  className: cn2(
792
- "relative size-8 shrink-0 rounded-md border bg-[var(--background-fronted)] shadow-none",
793
- filtersActive ? "border-[var(--border-focus)] text-[var(--accent)]" : "border-[var(--line-2)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]"
1437
+ "workspace-agent-message-center__open-chat-button h-auto gap-1.5 border-0 bg-transparent p-0 text-[var(--agent-gui-accent)] shadow-none transition-[color,opacity,visibility] hover:bg-transparent hover:text-[var(--agent-gui-accent)] focus-visible:bg-transparent focus-visible:text-[var(--agent-gui-accent)] active:bg-transparent",
1438
+ !alwaysVisible && "invisible opacity-0 group-hover/message-card:visible group-hover/message-card:opacity-100 group-focus-within/message-card:visible group-focus-within/message-card:opacity-100"
794
1439
  ),
1440
+ onClick: () => onOpenChat({
1441
+ agentSessionId: item.agentSessionId,
1442
+ provider: item.provider
1443
+ }),
795
1444
  children: [
796
- /* @__PURE__ */ jsx2(ListFilter, { className: "size-4", strokeWidth: 2.1, "aria-hidden": "true" }),
797
- filtersActive ? /* @__PURE__ */ jsx2(
798
- "span",
799
- {
800
- "aria-label": t(
801
- "agentHost.workspaceAgentMessageCenterFilterActive"
802
- ),
803
- className: "absolute -right-0.5 -top-0.5 size-2 rounded-full border border-[var(--background-panel)] bg-[var(--accent)]"
804
- }
805
- ) : null
806
- ]
807
- }
808
- ) }),
809
- /* @__PURE__ */ jsxs(
810
- DropdownMenuContent,
811
- {
812
- align: "end",
813
- sideOffset: 8,
814
- className: "min-w-[240px] p-1.5",
815
- style: { zIndex: "var(--z-dialog-popover)" },
816
- children: [
817
- /* @__PURE__ */ jsx2(DropdownMenuLabel, { children: t("agentHost.workspaceAgentMessageCenterGroupBy") }),
818
1445
  /* @__PURE__ */ jsx2(
819
- DropdownMenuRadioGroup,
1446
+ ExternalLink,
820
1447
  {
821
- value: groupBy,
822
- onValueChange: (value) => onGroupByChange(value),
823
- children: ["priority", "status", "agent", "time"].map((value) => /* @__PURE__ */ jsx2(DropdownMenuRadioItem, { value, children: messageCenterGroupLabel(value, t) }, value))
1448
+ className: "size-[15px]",
1449
+ strokeWidth: 2.2,
1450
+ "aria-hidden": "true"
824
1451
  }
825
1452
  ),
826
- /* @__PURE__ */ jsx2(DropdownMenuSeparator, {}),
827
- /* @__PURE__ */ jsx2(DropdownMenuLabel, { children: t("agentHost.workspaceAgentMessageCenterFilterStatus") }),
828
- /* @__PURE__ */ jsx2(DropdownMenuGroup, { children: statusOptions.map((option) => /* @__PURE__ */ jsxs(
829
- DropdownMenuCheckboxItem,
830
- {
831
- "aria-label": `${option.label} ${option.count}`,
832
- checked: statusFilters === null || statusFilters.has(option.value),
833
- onCheckedChange: () => onStatusToggle(option.value),
834
- onSelect: (event) => event.preventDefault(),
835
- children: [
836
- /* @__PURE__ */ jsx2("span", { className: "min-w-0 flex-1 truncate", children: option.label }),
837
- /* @__PURE__ */ jsx2("span", { className: "ml-auto text-[11px] text-[var(--text-tertiary)]", children: option.count })
838
- ]
839
- },
840
- option.value
841
- )) }),
842
- providerOptions.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
843
- /* @__PURE__ */ jsx2(DropdownMenuSeparator, {}),
844
- /* @__PURE__ */ jsx2(DropdownMenuLabel, { children: t("agentHost.workspaceAgentMessageCenterFilterAgent") }),
845
- /* @__PURE__ */ jsx2(DropdownMenuGroup, { children: providerOptions.map((option) => /* @__PURE__ */ jsxs(
846
- DropdownMenuCheckboxItem,
847
- {
848
- "aria-label": `${option.label} ${option.count}`,
849
- checked: providerFilters === null || providerFilters.has(option.value),
850
- onCheckedChange: () => onProviderToggle(option.value),
851
- onSelect: (event) => event.preventDefault(),
852
- children: [
853
- /* @__PURE__ */ jsx2("span", { className: "min-w-0 flex-1 truncate", children: option.label }),
854
- /* @__PURE__ */ jsx2("span", { className: "ml-auto text-[11px] text-[var(--text-tertiary)]", children: option.count })
855
- ]
856
- },
857
- option.value
858
- )) })
859
- ] }) : null,
860
- /* @__PURE__ */ jsx2(DropdownMenuSeparator, {}),
861
- /* @__PURE__ */ jsx2(DropdownMenuGroup, { children: /* @__PURE__ */ jsx2(DropdownMenuItem, { onClick: onClearFilters, children: t("agentHost.workspaceAgentMessageCenterClearFilters") }) })
1453
+ label
862
1454
  ]
863
1455
  }
864
1456
  )
865
1457
  ] });
866
1458
  }
867
-
868
- // agent-message-center/WorkspaceAgentMessageCenterCard.tsx
869
- import {
870
- useCallback,
871
- useEffect,
872
- useLayoutEffect,
873
- useRef,
874
- useState
875
- } from "react";
876
- import { ChevronDown, ChevronUp, ExternalLink, Info } from "lucide-react";
877
- import {
878
- Button as Button2,
879
- cn as cn3,
880
- StatusDot,
881
- Tooltip,
882
- TooltipContent,
883
- TooltipTrigger
884
- } from "@tutti-os/ui-system";
885
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
886
- function stopMessageCenterTextPointerPropagation(event) {
887
- event.stopPropagation();
1459
+ function MessageCenterIdentityLabel({
1460
+ identity,
1461
+ provider
1462
+ }) {
1463
+ "use memo";
1464
+ if (!identity) {
1465
+ return /* @__PURE__ */ jsx2(AgentProviderLabel, { provider });
1466
+ }
1467
+ const agentAvatarUrl = identity.agentAvatarUrl?.trim() || managedAgentRoundedIconUrl(provider);
1468
+ const title = `${identity.userName} & ${identity.agentName}`;
1469
+ return /* @__PURE__ */ jsxs(
1470
+ "span",
1471
+ {
1472
+ className: "workspace-agent-message-center__identity inline-flex min-w-0 max-w-full items-center gap-2",
1473
+ title,
1474
+ children: [
1475
+ /* @__PURE__ */ jsx2(
1476
+ MessageCenterIdentityAvatarStack,
1477
+ {
1478
+ userAvatarUrl: identity.userAvatarUrl,
1479
+ userName: identity.userName,
1480
+ agentAvatarUrl
1481
+ }
1482
+ ),
1483
+ /* @__PURE__ */ jsxs("span", { className: "workspace-agent-message-center__identity-names flex min-w-0 items-center gap-1 truncate text-[var(--text-secondary)]", children: [
1484
+ /* @__PURE__ */ jsx2("span", { className: "min-w-0 truncate", children: identity.userName }),
1485
+ /* @__PURE__ */ jsx2("span", { className: "shrink-0 text-[var(--text-tertiary)]", children: "&" }),
1486
+ /* @__PURE__ */ jsx2("span", { className: "min-w-0 truncate", children: identity.agentName })
1487
+ ] })
1488
+ ]
1489
+ }
1490
+ );
888
1491
  }
889
- function WorkspaceAgentMessageCenterCard({
890
- cardRef,
891
- highlighted = false,
892
- item,
893
- isSubmitting,
894
- onLinkAction,
895
- onOpenChat,
896
- onSubmitPrompt
1492
+ function MessageCenterIdentityAvatarMark({
1493
+ identity,
1494
+ provider,
1495
+ userId
897
1496
  }) {
898
1497
  "use memo";
899
- const { t } = useTranslation();
900
- const prompt = item.pendingPrompt;
901
- const displayTitle = normalizeAgentTitleText(item.title);
902
- const summary = messageCenterVisibleSummary(item);
903
- const displayStatus = statusClass(item);
904
- const statusLabel = workspaceAgentActivityStatusLabel(displayStatus, t);
905
- return /* @__PURE__ */ jsxs2(
906
- "article",
1498
+ const userName = identity?.userName.trim() || userId?.trim() || "";
1499
+ if (!userName) {
1500
+ return /* @__PURE__ */ jsx2(
1501
+ "img",
1502
+ {
1503
+ src: managedAgentRoundedIconUrl(provider),
1504
+ alt: "",
1505
+ className: "size-5 shrink-0 rounded-full",
1506
+ decoding: "async",
1507
+ loading: "lazy",
1508
+ draggable: false,
1509
+ "aria-hidden": "true"
1510
+ }
1511
+ );
1512
+ }
1513
+ return /* @__PURE__ */ jsx2(
1514
+ MessageCenterIdentityAvatarStack,
907
1515
  {
908
- ref: cardRef,
909
- className: cn3(
910
- "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]",
911
- isWaitingMessageCenterItem(item) && "agent-gui-edge-glow border-[var(--tutti-purple-border)] bg-[var(--tutti-purple-bg)]",
912
- highlighted && "outline-2 outline-[var(--accent)]"
913
- ),
914
- "data-highlighted": highlighted ? "true" : void 0,
915
- "data-message-center-item-id": item.id,
916
- "data-waiting": isWaitingMessageCenterItem(item) ? "true" : void 0,
917
- "data-status": displayStatus,
918
- tabIndex: highlighted ? -1 : void 0,
1516
+ userAvatarUrl: identity?.userAvatarUrl,
1517
+ userName,
1518
+ agentAvatarUrl: identity?.agentAvatarUrl?.trim() || managedAgentRoundedIconUrl(provider)
1519
+ }
1520
+ );
1521
+ }
1522
+ function MessageCenterIdentityAvatarStack({
1523
+ agentAvatarUrl,
1524
+ userAvatarUrl: rawUserAvatarUrl,
1525
+ userName
1526
+ }) {
1527
+ "use memo";
1528
+ const [userAvatarFailed, setUserAvatarFailed] = useState(false);
1529
+ const userAvatarUrl = rawUserAvatarUrl?.trim() ?? "";
1530
+ const userImageUrl = userAvatarUrl.length > 0 && !userAvatarFailed ? userAvatarUrl : user_avatar_placeholder_default;
1531
+ useEffect(() => {
1532
+ setUserAvatarFailed(false);
1533
+ }, [userAvatarUrl]);
1534
+ return /* @__PURE__ */ jsxs(
1535
+ "span",
1536
+ {
1537
+ className: "workspace-agent-message-center__identity-avatar-stack inline-flex w-9 shrink-0 items-center",
1538
+ "aria-hidden": "true",
919
1539
  children: [
920
- /* @__PURE__ */ jsxs2("div", { className: "flex min-w-0 items-center justify-between gap-2.5", children: [
921
- /* @__PURE__ */ jsxs2("div", { className: "flex min-w-0 items-center gap-1.5", children: [
922
- /* @__PURE__ */ jsxs2(Tooltip, { children: [
923
- /* @__PURE__ */ jsx3(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(
924
- "h3",
925
- {
926
- className: "workspace-agent-message-center__copy-text min-w-0 truncate text-[13px] font-bold leading-5 text-[var(--text-secondary)]",
927
- onPointerDown: stopMessageCenterTextPointerPropagation,
928
- children: displayTitle
929
- }
930
- ) }),
931
- /* @__PURE__ */ jsx3(
932
- TooltipContent,
933
- {
934
- side: "top",
935
- align: "start",
936
- className: "max-w-[min(360px,calc(100vw-32px))] whitespace-normal text-left [overflow-wrap:anywhere]",
937
- children: displayTitle
938
- }
939
- )
940
- ] }),
941
- item.cwd ? /* @__PURE__ */ jsx3(ProjectPathInfo, { path: item.cwd }) : null
942
- ] }),
943
- /* @__PURE__ */ jsxs2(
944
- "span",
945
- {
946
- 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)]",
947
- "data-status": displayStatus,
948
- title: statusLabel,
949
- children: [
950
- /* @__PURE__ */ jsx3(
951
- StatusDot,
952
- {
953
- tone: messageCenterStatusTone(item),
954
- pulse: isWaitingMessageCenterItem(item) || item.status === "working",
955
- size: "sm",
956
- title: statusLabel
957
- }
958
- ),
959
- /* @__PURE__ */ jsx3("span", { children: statusLabel })
960
- ]
961
- }
962
- )
963
- ] }),
964
- summary ? /* @__PURE__ */ jsx3(
965
- MessageCenterSummary,
966
- {
967
- item,
968
- onLinkAction,
969
- summary,
970
- emptyLabel: t("agentHost.workspaceAgentMessageCenterNoSummary")
971
- }
972
- ) : null,
973
- prompt ? /* @__PURE__ */ jsx3("div", { className: "min-w-0", children: /* @__PURE__ */ jsx3(
974
- AgentInteractivePromptSurface,
1540
+ /* @__PURE__ */ jsx2("span", { className: "inline-flex size-5 shrink-0 overflow-hidden rounded-full bg-[var(--transparency-block)] ring-2 ring-[var(--background-fronted)]", children: /* @__PURE__ */ jsx2(
1541
+ "img",
975
1542
  {
976
- embedded: true,
977
- keyboardShortcuts: false,
978
- prompt,
979
- isSubmitting,
980
- onSubmit: onSubmitPrompt,
981
- labels: buildWorkspaceAgentInteractivePromptLabels(
982
- t,
983
- item.provider
984
- )
1543
+ src: userImageUrl,
1544
+ alt: userName,
1545
+ className: "size-full object-cover",
1546
+ decoding: "async",
1547
+ loading: "lazy",
1548
+ referrerPolicy: "no-referrer",
1549
+ draggable: false,
1550
+ onError: () => {
1551
+ setUserAvatarFailed(true);
1552
+ }
985
1553
  }
986
- ) }) : null,
987
- /* @__PURE__ */ jsx3(
988
- MessageCenterOpenChatButton,
1554
+ ) }),
1555
+ /* @__PURE__ */ jsx2("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__ */ jsx2(
1556
+ "img",
989
1557
  {
990
- provider: item.provider,
991
- item,
992
- label: t("agentHost.workspaceAgentMessageCenterOpenChat"),
993
- onOpenChat
1558
+ src: agentAvatarUrl,
1559
+ alt: "",
1560
+ className: "size-full object-cover",
1561
+ decoding: "async",
1562
+ loading: "lazy",
1563
+ draggable: false
994
1564
  }
995
- )
1565
+ ) })
996
1566
  ]
997
1567
  }
998
1568
  );
999
1569
  }
1000
- var STACK_PRESENCE_FALLBACK_MS = 380;
1001
- function useStackRegionPresence(visible) {
1002
- const [mounted, setMounted] = useState(visible);
1003
- const closing = mounted && !visible;
1004
- useLayoutEffect(() => {
1005
- if (visible) {
1006
- setMounted(true);
1007
- }
1008
- }, [visible]);
1009
- useEffect(() => {
1010
- if (!closing) {
1011
- return void 0;
1012
- }
1013
- const timeoutId = window.setTimeout(() => {
1014
- setMounted(false);
1015
- }, STACK_PRESENCE_FALLBACK_MS);
1016
- return () => {
1017
- window.clearTimeout(timeoutId);
1018
- };
1019
- }, [closing]);
1020
- const onAnimationEnd = useCallback(
1021
- (event) => {
1022
- if (event.target === event.currentTarget && closing) {
1023
- setMounted(false);
1570
+ function ProjectPathInfo({ path }) {
1571
+ "use memo";
1572
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
1573
+ /* @__PURE__ */ jsx2(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx2(
1574
+ "button",
1575
+ {
1576
+ type: "button",
1577
+ 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",
1578
+ "aria-label": path,
1579
+ children: /* @__PURE__ */ jsx2(Info, { className: "size-3.5", strokeWidth: 2, "aria-hidden": "true" })
1024
1580
  }
1025
- },
1026
- [closing]
1027
- );
1028
- return { closing, mounted, onAnimationEnd };
1581
+ ) }),
1582
+ /* @__PURE__ */ jsx2(
1583
+ TooltipContent,
1584
+ {
1585
+ side: "top",
1586
+ align: "start",
1587
+ className: "max-w-[320px] text-[11px] [overflow-wrap:anywhere]",
1588
+ children: path
1589
+ }
1590
+ )
1591
+ ] });
1029
1592
  }
1030
- function WorkspaceAgentMessageCenterStack({
1031
- className,
1032
- expanded,
1033
- groupId,
1593
+ function AgentProviderLabel({ provider }) {
1594
+ "use memo";
1595
+ const label = workspaceAgentProviderLabel(provider);
1596
+ return /* @__PURE__ */ jsxs("span", { className: "workspace-agent-message-center__provider inline-flex min-w-0 max-w-full items-center gap-1.5", children: [
1597
+ /* @__PURE__ */ jsx2(
1598
+ "img",
1599
+ {
1600
+ src: managedAgentRoundedIconUrl(provider),
1601
+ alt: "",
1602
+ className: "workspace-agent-message-center__provider-icon size-5 shrink-0 rounded-full",
1603
+ decoding: "async",
1604
+ loading: "lazy",
1605
+ draggable: false,
1606
+ "aria-hidden": "true"
1607
+ }
1608
+ ),
1609
+ /* @__PURE__ */ jsx2("span", { className: "workspace-agent-message-center__provider-name min-w-0 truncate text-[var(--text-secondary)]", children: label })
1610
+ ] });
1611
+ }
1612
+ function statusClass(item) {
1613
+ if (isWaitingMessageCenterItem(item)) {
1614
+ return "waiting";
1615
+ }
1616
+ if (item.status === "idle") {
1617
+ return "completed";
1618
+ }
1619
+ return item.status;
1620
+ }
1621
+ function messageCenterStatusTone(item) {
1622
+ if (isWaitingMessageCenterItem(item)) {
1623
+ return "amber";
1624
+ }
1625
+ if (item.status === "completed" || item.status === "idle") {
1626
+ return "green";
1627
+ }
1628
+ if (item.status === "canceled") {
1629
+ return "amber";
1630
+ }
1631
+ if (item.status === "failed") {
1632
+ return "red";
1633
+ }
1634
+ if (item.status === "working") {
1635
+ return "blue";
1636
+ }
1637
+ return "neutral";
1638
+ }
1639
+
1640
+ // agent-message-center/WorkspaceAgentMessageCenterAttentionDeck.tsx
1641
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1642
+ var DECK_MAX_PEEK = 2;
1643
+ var DECK_NEW_CARD_COOLDOWN_MS = 500;
1644
+ var DECK_LEAVE_ANIMATION_FALLBACK_MS = 420;
1645
+ function WorkspaceAgentMessageCenterAttentionDeck({
1034
1646
  items,
1035
- renderCard,
1036
- onCollapse,
1037
- onExpand
1647
+ highlightedItemId = null,
1648
+ submittingPromptKey,
1649
+ registerNode,
1650
+ onLinkAction,
1651
+ onOpenChat,
1652
+ onSubmitPrompt
1038
1653
  }) {
1039
1654
  "use memo";
1040
1655
  const { t } = useTranslation();
1041
- const summaryRegion = useStackRegionPresence(!expanded);
1042
- const cardsRegion = useStackRegionPresence(expanded);
1043
- if (items.length < 2) {
1656
+ const ordered = useMemo(
1657
+ () => orderDeckItems(items, highlightedItemId),
1658
+ [items, highlightedItemId]
1659
+ );
1660
+ const topRequestId = ordered[0]?.pendingPrompt?.requestId ?? null;
1661
+ const topPromotedByHighlight = ordered[0]?.id === highlightedItemId && highlightedItemId !== null;
1662
+ const previousTopRequestIdRef = useRef2(null);
1663
+ const [cooldownRequestId, setCooldownRequestId] = useState2(
1664
+ null
1665
+ );
1666
+ useEffect2(() => {
1667
+ const previousTopRequestId = previousTopRequestIdRef.current;
1668
+ previousTopRequestIdRef.current = topRequestId;
1669
+ if (!topRequestId || topPromotedByHighlight || previousTopRequestId === null || previousTopRequestId === topRequestId) {
1670
+ return void 0;
1671
+ }
1672
+ setCooldownRequestId(topRequestId);
1673
+ const timeoutId = window.setTimeout(() => {
1674
+ setCooldownRequestId(
1675
+ (current) => current === topRequestId ? null : current
1676
+ );
1677
+ }, DECK_NEW_CARD_COOLDOWN_MS);
1678
+ return () => {
1679
+ window.clearTimeout(timeoutId);
1680
+ };
1681
+ }, [topPromotedByHighlight, topRequestId]);
1682
+ const isTopCoolingDown = cooldownRequestId !== null && cooldownRequestId === topRequestId;
1683
+ const previousTopItemRef = useRef2(
1684
+ null
1685
+ );
1686
+ const [leavingItem, setLeavingItem] = useState2(null);
1687
+ useEffect2(() => {
1688
+ const previousTopItem = previousTopItemRef.current;
1689
+ previousTopItemRef.current = ordered[0] ?? null;
1690
+ if (previousTopItem && previousTopItem.id !== (ordered[0]?.id ?? null) && !items.some((item) => item.id === previousTopItem.id)) {
1691
+ setLeavingItem(previousTopItem);
1692
+ const timeoutId = window.setTimeout(() => {
1693
+ setLeavingItem(
1694
+ (current) => current?.id === previousTopItem.id ? null : current
1695
+ );
1696
+ }, DECK_LEAVE_ANIMATION_FALLBACK_MS);
1697
+ return () => {
1698
+ window.clearTimeout(timeoutId);
1699
+ };
1700
+ }
1701
+ return void 0;
1702
+ }, [items, ordered]);
1703
+ const topItem = ordered[0];
1704
+ if (!topItem) {
1044
1705
  return null;
1045
1706
  }
1046
- const collapseLabel = t(
1047
- "agentHost.workspaceAgentMessageCenterCollapseStackAria"
1048
- );
1707
+ const peekCount = Math.min(ordered.length - 1, DECK_MAX_PEEK);
1708
+ const topIsSubmitting = submittingPromptKey === `${topItem.agentSessionId}:${topItem.pendingPrompt?.requestId}`;
1049
1709
  return /* @__PURE__ */ jsxs2(
1050
- "div",
1710
+ "section",
1051
1711
  {
1052
- className: cn3("relative flex min-w-0 flex-col", className),
1053
- "data-stack-count": items.length,
1054
- "data-stack-motion": "smooth",
1055
- "data-stack-state": expanded ? "expanded" : "collapsed",
1056
- "data-stack-top-item-id": items[0]?.id,
1057
- "data-testid": `workspace-agent-message-stack-${groupId}`,
1712
+ className: "flex min-w-0 flex-col gap-2.5",
1713
+ "aria-label": t("agentHost.workspaceAgentMessageCenterGroupNeedsAttention"),
1058
1714
  children: [
1059
- summaryRegion.mounted ? /* @__PURE__ */ jsx3(
1060
- "div",
1061
- {
1062
- className: cn3(
1063
- "workspace-agent-message-center__stack-rest min-w-0",
1064
- summaryRegion.closing ? "workspace-agent-message-center__stack-rest--closing" : "workspace-agent-message-center__stack-rest--opening"
1065
- ),
1066
- onAnimationEnd: summaryRegion.onAnimationEnd,
1067
- children: /* @__PURE__ */ jsx3(
1068
- "div",
1069
- {
1070
- className: "min-h-0 min-w-0 overflow-hidden",
1071
- "aria-hidden": summaryRegion.closing ? true : void 0,
1072
- inert: summaryRegion.closing ? true : void 0,
1073
- children: /* @__PURE__ */ jsx3(
1074
- MessageCenterStackSummary,
1075
- {
1076
- groupId,
1077
- items,
1078
- onExpand
1079
- }
1080
- )
1081
- }
1082
- )
1083
- }
1084
- ) : null,
1085
- cardsRegion.mounted ? /* @__PURE__ */ jsx3(
1715
+ /* @__PURE__ */ jsx3("div", { className: "flex min-w-0 items-center justify-between gap-3 px-0.5", children: /* @__PURE__ */ jsxs2("div", { className: "truncate text-xs font-bold leading-4 text-[var(--text-tertiary)]", children: [
1716
+ t("agentHost.workspaceAgentMessageCenterGroupNeedsAttention"),
1717
+ " \xB7",
1718
+ " ",
1719
+ ordered.length
1720
+ ] }) }),
1721
+ /* @__PURE__ */ jsxs2(
1086
1722
  "div",
1087
1723
  {
1088
1724
  className: cn3(
1089
- "workspace-agent-message-center__stack-rest min-w-0",
1090
- cardsRegion.closing ? "workspace-agent-message-center__stack-rest--closing" : "workspace-agent-message-center__stack-rest--opening"
1725
+ "relative min-w-0",
1726
+ peekCount > 1 ? "pb-[18px]" : peekCount > 0 && "pb-[10px]"
1091
1727
  ),
1092
- onAnimationEnd: cardsRegion.onAnimationEnd,
1093
- children: /* @__PURE__ */ jsxs2(
1094
- "div",
1095
- {
1096
- className: "min-h-0 min-w-0 overflow-hidden",
1097
- "aria-hidden": cardsRegion.closing ? true : void 0,
1098
- inert: cardsRegion.closing ? true : void 0,
1099
- children: [
1100
- /* @__PURE__ */ jsxs2("div", { className: "flex min-w-0 items-center justify-between gap-2 px-0.5 pb-1.5", children: [
1101
- /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-center gap-1.5 text-[13px] font-semibold leading-4 text-[var(--text-tertiary)]", children: [
1102
- /* @__PURE__ */ jsx3(
1103
- MessageCenterIdentityAvatarMark,
1104
- {
1105
- identity: items[0]?.identity ?? null,
1106
- provider: items[0]?.provider ?? "",
1107
- userId: items[0]?.userId ?? null
1108
- }
1109
- ),
1110
- /* @__PURE__ */ jsx3("span", { className: "min-w-0 truncate", children: t("agentHost.workspaceAgentMessageCenterStackSummaryCount", {
1111
- count: items.length
1112
- }) })
1113
- ] }),
1114
- /* @__PURE__ */ jsxs2(Tooltip, { children: [
1115
- /* @__PURE__ */ jsx3(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(
1116
- Button2,
1117
- {
1118
- type: "button",
1119
- variant: "ghost",
1120
- size: "icon-sm",
1121
- "aria-label": collapseLabel,
1122
- className: "size-6 text-[var(--text-tertiary)] hover:text-[var(--text-primary)]",
1123
- onClick: onCollapse,
1124
- children: /* @__PURE__ */ jsx3(ChevronUp, { className: "size-3.5", "aria-hidden": "true" })
1125
- }
1126
- ) }),
1127
- /* @__PURE__ */ jsx3(TooltipContent, { side: "top", align: "center", children: collapseLabel })
1128
- ] })
1129
- ] }),
1130
- /* @__PURE__ */ jsx3("div", { className: "flex min-w-0 flex-col gap-2.5", children: items.map(
1131
- (item, stackedIndex) => renderCard(item, { stackedIndex })
1132
- ) })
1133
- ]
1134
- }
1135
- )
1728
+ "data-testid": "workspace-agent-message-center-attention-deck",
1729
+ "data-deck-count": ordered.length,
1730
+ "data-deck-peek-count": peekCount,
1731
+ "data-deck-top-item-id": topItem.id,
1732
+ children: [
1733
+ leavingItem ? /* @__PURE__ */ jsx3(
1734
+ "div",
1735
+ {
1736
+ "aria-hidden": "true",
1737
+ inert: true,
1738
+ "data-deck-leaving-item-id": leavingItem.id,
1739
+ className: "pointer-events-none absolute inset-x-0 top-0 z-20 min-w-0 motion-safe:animate-out motion-safe:fade-out-0 motion-safe:slide-out-to-top-2 motion-safe:duration-300 motion-safe:ease-[cubic-bezier(0.4,0,0.2,1)] motion-reduce:hidden",
1740
+ onAnimationEnd: (event) => {
1741
+ if (event.target === event.currentTarget) {
1742
+ setLeavingItem(
1743
+ (current) => current?.id === leavingItem.id ? null : current
1744
+ );
1745
+ }
1746
+ },
1747
+ children: /* @__PURE__ */ jsx3(
1748
+ WorkspaceAgentMessageCenterCard,
1749
+ {
1750
+ interactive: false,
1751
+ isSubmitting: false,
1752
+ item: leavingItem,
1753
+ onOpenChat,
1754
+ onSubmitPrompt: () => {
1755
+ }
1756
+ }
1757
+ )
1758
+ },
1759
+ `leaving-${leavingItem.agentSessionId}`
1760
+ ) : null,
1761
+ /* @__PURE__ */ jsx3(
1762
+ "div",
1763
+ {
1764
+ className: cn3(
1765
+ "relative min-w-0 rounded-lg motion-safe:animate-in motion-safe:fade-in-0 motion-safe:slide-in-from-top-1 motion-safe:duration-300 motion-reduce:animate-none",
1766
+ peekCount > 1 ? "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)]" : peekCount > 0 && "shadow-[0_7px_0_-4px_var(--background-fronted),0_7px_0_-3px_var(--line-2)]"
1767
+ ),
1768
+ children: /* @__PURE__ */ jsx3(
1769
+ WorkspaceAgentMessageCenterCard,
1770
+ {
1771
+ cardRef: registerNode ? (node) => registerNode(topItem.id, node) : void 0,
1772
+ highlighted: topItem.id === highlightedItemId,
1773
+ interactive: true,
1774
+ isSubmitting: topIsSubmitting || isTopCoolingDown,
1775
+ item: topItem,
1776
+ onLinkAction,
1777
+ onOpenChat,
1778
+ onSubmitPrompt: (input) => onSubmitPrompt(topItem, input)
1779
+ }
1780
+ )
1781
+ },
1782
+ topItem.id
1783
+ )
1784
+ ]
1136
1785
  }
1137
- ) : null
1786
+ )
1138
1787
  ]
1139
1788
  }
1140
1789
  );
1141
1790
  }
1142
- function MessageCenterStackSummary({
1143
- groupId,
1144
- items,
1145
- onExpand
1146
- }) {
1147
- "use memo";
1148
- const { t } = useTranslation();
1149
- const firstItem = items[0];
1150
- const hasWaiting = items.some((item) => isWaitingMessageCenterItem(item));
1151
- if (!firstItem) {
1152
- return null;
1791
+ function orderDeckItems(items, highlightedItemId) {
1792
+ if (!highlightedItemId) {
1793
+ return [...items];
1153
1794
  }
1154
- return /* @__PURE__ */ jsx3(
1155
- "button",
1795
+ const index = items.findIndex((item) => item.id === highlightedItemId);
1796
+ if (index <= 0) {
1797
+ return [...items];
1798
+ }
1799
+ const next = [...items];
1800
+ const [picked] = next.splice(index, 1);
1801
+ return picked ? [picked, ...next] : next;
1802
+ }
1803
+
1804
+ // agent-message-center/WorkspaceAgentMessageCenterViewControls.tsx
1805
+ import { ListFilter } from "lucide-react";
1806
+ import {
1807
+ Button as Button2,
1808
+ cn as cn4,
1809
+ DropdownMenu,
1810
+ DropdownMenuCheckboxItem,
1811
+ DropdownMenuContent,
1812
+ DropdownMenuGroup,
1813
+ DropdownMenuItem,
1814
+ DropdownMenuLabel,
1815
+ DropdownMenuRadioGroup,
1816
+ DropdownMenuRadioItem,
1817
+ DropdownMenuSeparator,
1818
+ DropdownMenuTrigger
1819
+ } from "@tutti-os/ui-system";
1820
+
1821
+ // agent-message-center/workspaceAgentMessageCenterViewModel.ts
1822
+ function partitionMessageCenterItemsByAgentUser(items) {
1823
+ const stacks = /* @__PURE__ */ new Map();
1824
+ for (const item of items) {
1825
+ const stackId = messageCenterAgentUserStackId(item);
1826
+ const stack = stacks.get(stackId);
1827
+ if (stack) {
1828
+ stack.items.push(item);
1829
+ } else {
1830
+ stacks.set(stackId, {
1831
+ id: stackId,
1832
+ provider: item.provider,
1833
+ userId: item.userId,
1834
+ items: [item]
1835
+ });
1836
+ }
1837
+ }
1838
+ return [...stacks.values()];
1839
+ }
1840
+ function messageCenterAgentUserStackId(item) {
1841
+ const provider = item.provider.trim().toLowerCase() || "unknown-agent";
1842
+ const userId = item.userId?.trim() || "unknown-user";
1843
+ return `agent-user:${provider}:${userId}`;
1844
+ }
1845
+ function buildMessageCenterStatusOptions(counts, t) {
1846
+ return [
1156
1847
  {
1157
- type: "button",
1158
- "aria-label": t("agentHost.workspaceAgentMessageCenterExpandStackAria", {
1159
- count: items.length
1160
- }),
1161
- className: cn3(
1162
- "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)]",
1163
- items.length > 2 ? "pb-[18px]" : "pb-[10px]"
1164
- ),
1165
- "data-stack-summary-count": items.length,
1166
- "data-stack-provider": firstItem.provider,
1167
- "data-stack-user-id": firstItem.userId ?? "",
1168
- "data-testid": `workspace-agent-message-stack-summary-${groupId}`,
1169
- onClick: onExpand,
1170
- children: /* @__PURE__ */ jsxs2(
1171
- "span",
1848
+ count: counts.waiting,
1849
+ label: t("agentHost.workspaceAgentMessageCenterFilterWaiting"),
1850
+ value: "waiting"
1851
+ },
1852
+ {
1853
+ count: counts.failed,
1854
+ label: t("agentHost.workspaceAgentMessageCenterFilterFailed"),
1855
+ value: "failed"
1856
+ },
1857
+ {
1858
+ count: counts.working,
1859
+ label: t("agentHost.workspaceAgentMessageCenterFilterWorking"),
1860
+ value: "working"
1861
+ },
1862
+ {
1863
+ count: counts.completed,
1864
+ label: t("agentHost.workspaceAgentMessageCenterFilterCompleted"),
1865
+ value: "completed"
1866
+ }
1867
+ ];
1868
+ }
1869
+ function buildMessageCenterProviderOptions(items) {
1870
+ const counts = /* @__PURE__ */ new Map();
1871
+ for (const item of items) {
1872
+ counts.set(item.provider, (counts.get(item.provider) ?? 0) + 1);
1873
+ }
1874
+ return [...counts.entries()].map(([value, count]) => ({
1875
+ count,
1876
+ label: workspaceAgentProviderLabel(value),
1877
+ value
1878
+ })).sort((left, right) => left.label.localeCompare(right.label));
1879
+ }
1880
+ function itemMatchesViewFilters({
1881
+ item,
1882
+ providerFilters,
1883
+ statusFilters
1884
+ }) {
1885
+ if (statusFilters && !statusFilters.has(messageCenterStatusFilterValue(item))) {
1886
+ return false;
1887
+ }
1888
+ if (providerFilters && !providerFilters.has(item.provider)) {
1889
+ return false;
1890
+ }
1891
+ return true;
1892
+ }
1893
+ function messageCenterStatusFilterValue(item) {
1894
+ if (isWaitingMessageCenterItem(item)) {
1895
+ return "waiting";
1896
+ }
1897
+ if (item.status === "failed") {
1898
+ return "failed";
1899
+ }
1900
+ if (item.status === "working") {
1901
+ return "working";
1902
+ }
1903
+ return "completed";
1904
+ }
1905
+ function groupMessageCenterItems(items, groupBy, t) {
1906
+ switch (groupBy) {
1907
+ case "status":
1908
+ return groupByFixedDefinitions(items, [
1909
+ {
1910
+ id: "waiting",
1911
+ label: t("agentHost.workspaceAgentMessageCenterFilterWaiting"),
1912
+ match: (item) => messageCenterStatusFilterValue(item) === "waiting"
1913
+ },
1914
+ {
1915
+ id: "failed",
1916
+ label: t("agentHost.workspaceAgentMessageCenterFilterFailed"),
1917
+ match: (item) => messageCenterStatusFilterValue(item) === "failed"
1918
+ },
1919
+ {
1920
+ id: "working",
1921
+ label: t("agentHost.workspaceAgentMessageCenterFilterWorking"),
1922
+ match: (item) => messageCenterStatusFilterValue(item) === "working"
1923
+ },
1924
+ {
1925
+ id: "completed",
1926
+ label: t("agentHost.workspaceAgentMessageCenterFilterCompleted"),
1927
+ match: (item) => messageCenterStatusFilterValue(item) === "completed"
1928
+ }
1929
+ ]);
1930
+ case "agent":
1931
+ return groupByDynamicKey(items, (item) => ({
1932
+ id: messageCenterAgentUserStackId(item),
1933
+ identity: item.identity,
1934
+ label: messageCenterAgentUserGroupLabel(item),
1935
+ provider: item.provider,
1936
+ userId: item.userId
1937
+ }));
1938
+ case "time":
1939
+ return groupByFixedDefinitions(items, [
1172
1940
  {
1173
- className: cn3(
1174
- "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)]",
1175
- 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)]",
1176
- hasWaiting && "border-[var(--tutti-purple-border)] bg-[var(--tutti-purple-bg)]"
1941
+ id: "today",
1942
+ label: t("agentHost.workspaceAgentMessageCenterGroupToday"),
1943
+ match: (item) => messageCenterTimeGroup(item) === "today"
1944
+ },
1945
+ {
1946
+ id: "yesterday",
1947
+ label: t("agentHost.workspaceAgentMessageCenterGroupYesterday"),
1948
+ match: (item) => messageCenterTimeGroup(item) === "yesterday"
1949
+ },
1950
+ {
1951
+ id: "previous-seven-days",
1952
+ label: t(
1953
+ "agentHost.workspaceAgentMessageCenterGroupPreviousSevenDays"
1177
1954
  ),
1178
- children: [
1179
- /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-center justify-between gap-2.5", children: [
1180
- /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-center gap-2", children: [
1181
- /* @__PURE__ */ jsx3(
1182
- MessageCenterIdentityAvatarMark,
1183
- {
1184
- identity: firstItem.identity,
1185
- provider: firstItem.provider,
1186
- userId: firstItem.userId
1187
- }
1188
- ),
1189
- /* @__PURE__ */ jsx3("span", { className: "min-w-0 truncate text-[13px] font-bold leading-5 text-[var(--text-secondary)]", children: t("agentHost.workspaceAgentMessageCenterStackSummaryCount", {
1190
- count: items.length
1191
- }) })
1192
- ] }),
1193
- /* @__PURE__ */ jsx3(
1194
- ChevronDown,
1195
- {
1196
- 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",
1197
- "aria-hidden": "true"
1198
- }
1199
- )
1200
- ] }),
1201
- /* @__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) }) })
1202
- ]
1955
+ match: (item) => messageCenterTimeGroup(item) === "previous-seven-days"
1956
+ },
1957
+ {
1958
+ id: "older",
1959
+ label: t("agentHost.workspaceAgentMessageCenterGroupOlder"),
1960
+ match: (item) => messageCenterTimeGroup(item) === "older"
1203
1961
  }
1204
- )
1962
+ ]);
1963
+ case "priority":
1964
+ default: {
1965
+ const nowUnixMs = Date.now();
1966
+ return groupByFixedDefinitions(items, [
1967
+ {
1968
+ id: "needs-attention",
1969
+ label: t("agentHost.workspaceAgentMessageCenterGroupNeedsAttention"),
1970
+ match: (item) => messageCenterStatusFilterValue(item) === "waiting" || messageCenterStatusFilterValue(item) === "failed"
1971
+ },
1972
+ {
1973
+ id: "working",
1974
+ label: t("agentHost.workspaceAgentMessageCenterFilterWorking"),
1975
+ match: (item) => messageCenterStatusFilterValue(item) === "working"
1976
+ },
1977
+ {
1978
+ id: "recently-completed",
1979
+ label: t(
1980
+ "agentHost.workspaceAgentMessageCenterGroupRecentlyCompleted"
1981
+ ),
1982
+ match: (item) => isRecentlyCompletedMessageCenterItem(item, nowUnixMs)
1983
+ },
1984
+ {
1985
+ id: "completed",
1986
+ label: t("agentHost.workspaceAgentMessageCenterFilterCompleted"),
1987
+ match: (item) => messageCenterStatusFilterValue(item) === "completed" && !isRecentlyCompletedMessageCenterItem(item, nowUnixMs)
1988
+ }
1989
+ ]);
1205
1990
  }
1206
- );
1207
- }
1208
- function messageCenterStackPreviewText(item) {
1209
- return item.lastAgentMessageSummary.trim() || normalizeAgentTitleText(item.title);
1210
- }
1211
- function resolveMessageCenterNotificationAction(item, input) {
1212
- if (input.action) {
1213
- return normalizeMessageCenterNotificationAction(input.action);
1214
1991
  }
1215
- if (!input.optionId) {
1216
- return null;
1992
+ }
1993
+ function messageCenterAgentUserGroupLabel(item) {
1994
+ if (item.identity) {
1995
+ return `${item.identity.userName} & ${item.identity.agentName}`;
1217
1996
  }
1218
- const prompt = item.pendingPrompt;
1219
- const option = prompt && "options" in prompt ? prompt.options.find((candidate) => candidate.id === input.optionId) : null;
1220
- const optionToken = `${option?.kind ?? ""}:${input.optionId}`.toLowerCase();
1221
- if (optionToken.includes("allow") || optionToken.includes("accept")) {
1222
- return "accept";
1997
+ return workspaceAgentProviderLabel(item.provider);
1998
+ }
1999
+ var RECENTLY_COMPLETED_WINDOW_MS = 10 * 60 * 1e3;
2000
+ function isRecentlyCompletedMessageCenterItem(item, nowUnixMs) {
2001
+ if (messageCenterStatusFilterValue(item) !== "completed") {
2002
+ return false;
1223
2003
  }
1224
- if (optionToken.includes("deny") || optionToken.includes("reject") || optionToken.includes("disallow")) {
1225
- return "reject";
2004
+ const completedAtUnixMs = item.sortTimeUnixMs || item.lastAgentMessageAtUnixMs || 0;
2005
+ if (completedAtUnixMs <= 0) {
2006
+ return false;
1226
2007
  }
1227
- return input.optionId;
1228
- }
1229
- function buildWorkspaceAgentInteractivePromptLabels(t, provider) {
1230
- return {
1231
- approvalLead: t("agentHost.agentGui.approvalRequired", {
1232
- provider: provider ? workspaceAgentProviderLabel(provider) : t("agentHost.workspaceAgentsGenericAgentName")
1233
- }),
1234
- planLead: t("agentHost.agentGui.planLead"),
1235
- planModes: [
1236
- {
1237
- id: "acceptEdits",
1238
- label: t("agentHost.agentGui.planModes.acceptEdits.label"),
1239
- description: t("agentHost.agentGui.planModes.acceptEdits.description")
1240
- },
1241
- {
1242
- id: "default",
1243
- label: t("agentHost.agentGui.planModes.askFirst.label"),
1244
- description: t("agentHost.agentGui.planModes.askFirst.description")
1245
- },
1246
- {
1247
- id: "bypassPermissions",
1248
- label: t("agentHost.agentGui.planModes.allowAll.label"),
1249
- description: t("agentHost.agentGui.planModes.allowAll.description")
1250
- }
1251
- ],
1252
- stayInPlan: t("agentHost.agentGui.stayInPlan"),
1253
- sendFeedback: t("agentHost.agentGui.sendFeedback"),
1254
- feedbackPlaceholder: t("agentHost.agentGui.feedbackPlaceholder"),
1255
- previousQuestion: t("agentHost.agentGui.previousQuestion"),
1256
- nextQuestion: t("agentHost.agentGui.nextQuestion"),
1257
- submitAnswers: t("agentHost.agentGui.submitAnswers"),
1258
- answerPlaceholder: t("agentHost.agentGui.answerPlaceholder"),
1259
- waitingForAnswer: t("agentHost.agentGui.waitingForAnswer")
1260
- };
2008
+ return completedAtUnixMs >= nowUnixMs - RECENTLY_COMPLETED_WINDOW_MS;
1261
2009
  }
1262
- function normalizeMessageCenterNotificationAction(action) {
1263
- switch (action) {
1264
- case "allow":
1265
- return "accept";
1266
- case "deny":
1267
- return "reject";
2010
+ function messageCenterGroupLabel(groupBy, t) {
2011
+ switch (groupBy) {
2012
+ case "status":
2013
+ return t("agentHost.workspaceAgentMessageCenterGroupStatus");
2014
+ case "agent":
2015
+ return t("agentHost.workspaceAgentMessageCenterGroupAgent");
2016
+ case "time":
2017
+ return t("agentHost.workspaceAgentMessageCenterGroupTime");
2018
+ case "priority":
1268
2019
  default:
1269
- return action;
2020
+ return t("agentHost.workspaceAgentMessageCenterGroupPriority");
1270
2021
  }
1271
2022
  }
1272
- function messageCenterVisibleSummary(item) {
1273
- const summary = item.lastAgentMessageSummary.trim();
1274
- if (item.pendingPrompt?.kind === "approval" && isGenericApprovalSummary(summary)) {
1275
- return "";
2023
+ function statusFilterSummary(statusFilters, statusOptions) {
2024
+ if (statusFilters === null || statusFilters.size === statusOptions.length) {
2025
+ return statusOptions.map((option) => option.label).join(", ");
1276
2026
  }
1277
- return summary;
2027
+ return statusOptions.filter((option) => statusFilters.has(option.value)).map((option) => option.label).join(", ");
1278
2028
  }
1279
- function isGenericApprovalSummary(summary) {
1280
- const normalized = summary.trim().toLowerCase();
1281
- return normalized === "approval";
2029
+ function groupByFixedDefinitions(items, definitions) {
2030
+ return definitions.map((definition) => ({
2031
+ id: definition.id,
2032
+ label: definition.label,
2033
+ items: items.filter(definition.match)
2034
+ })).filter((group) => group.items.length > 0);
1282
2035
  }
1283
- function MessageCenterSummary({
1284
- emptyLabel,
1285
- item,
1286
- onLinkAction,
1287
- summary
1288
- }) {
1289
- "use memo";
1290
- const summaryRef = useRef(null);
1291
- const [isOverflowing, setIsOverflowing] = useState(false);
1292
- const handleLinkAction = useCallback(
1293
- (action) => {
1294
- onLinkAction?.(
1295
- action.type === "open-agent-session" && !action.provider ? { ...action, provider: item.provider } : action
1296
- );
1297
- },
1298
- [item.provider, onLinkAction]
1299
- );
1300
- useLayoutEffect(() => {
1301
- const element = summaryRef.current;
1302
- if (!element) {
1303
- return;
1304
- }
1305
- const updateOverflowState = () => {
1306
- setIsOverflowing(element.scrollHeight > element.clientHeight + 1);
1307
- };
1308
- updateOverflowState();
1309
- const resizeObserver = new ResizeObserver(updateOverflowState);
1310
- resizeObserver.observe(element);
1311
- return () => {
1312
- resizeObserver.disconnect();
1313
- };
1314
- }, [summary]);
1315
- return /* @__PURE__ */ jsx3(
1316
- AgentVerticalScrollArea,
1317
- {
1318
- ref: summaryRef,
1319
- className: cn3(
1320
- "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]",
1321
- isOverflowing && "workspace-agent-message-center__summary--overflowing"
1322
- ),
1323
- viewportClassName: "workspace-agent-message-center__copy-text max-h-[160px] p-2.5 pr-4",
1324
- onPointerDown: stopMessageCenterTextPointerPropagation,
1325
- scrollbarClassName: "top-2 bottom-2 right-1.5",
1326
- syncKey: summary,
1327
- children: summary ? /* @__PURE__ */ jsx3(
1328
- AgentMessageMarkdown,
1329
- {
1330
- content: summary,
1331
- 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)]",
1332
- onLinkAction: handleLinkAction,
1333
- workspaceLinkContext: {
1334
- workspaceRoot: item.cwd || null,
1335
- basePath: item.cwd,
1336
- source: "agent-markdown"
1337
- },
1338
- enableImageZoom: true
1339
- }
1340
- ) : emptyLabel
2036
+ function groupByDynamicKey(items, keyForItem) {
2037
+ const groups = /* @__PURE__ */ new Map();
2038
+ for (const item of items) {
2039
+ const key = keyForItem(item);
2040
+ const group = groups.get(key.id);
2041
+ if (group) {
2042
+ group.items.push(item);
2043
+ if (!group.identity && key.identity) {
2044
+ group.identity = key.identity;
2045
+ group.label = key.label;
2046
+ }
2047
+ } else {
2048
+ groups.set(key.id, { ...key, items: [item] });
1341
2049
  }
1342
- );
2050
+ }
2051
+ return [...groups.values()];
2052
+ }
2053
+ function messageCenterTimeGroup(item) {
2054
+ const timestamp = item.sortTimeUnixMs || item.lastAgentMessageAtUnixMs || 0;
2055
+ if (timestamp <= 0) {
2056
+ return "older";
2057
+ }
2058
+ const ageMs = Date.now() - timestamp;
2059
+ const dayMs = 24 * 60 * 60 * 1e3;
2060
+ if (ageMs < dayMs) {
2061
+ return "today";
2062
+ }
2063
+ if (ageMs < dayMs * 2) {
2064
+ return "yesterday";
2065
+ }
2066
+ if (ageMs < dayMs * 7) {
2067
+ return "previous-seven-days";
2068
+ }
2069
+ return "older";
1343
2070
  }
1344
- function MessageCenterOpenChatButton({
1345
- item,
1346
- label,
1347
- onOpenChat,
1348
- provider
2071
+
2072
+ // agent-message-center/WorkspaceAgentMessageCenterViewControls.tsx
2073
+ import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
2074
+ function MessageCenterViewMenu({
2075
+ filtersActive = false,
2076
+ groupBy,
2077
+ providerFilters,
2078
+ providerOptions,
2079
+ statusFilters,
2080
+ statusOptions,
2081
+ onClearFilters,
2082
+ onGroupByChange,
2083
+ onProviderToggle,
2084
+ onStatusToggle
1349
2085
  }) {
1350
2086
  "use memo";
1351
- return /* @__PURE__ */ jsxs2("div", { className: "workspace-agent-message-center__footer flex min-w-0 items-center justify-between gap-2", children: [
1352
- /* @__PURE__ */ jsx3(
1353
- MessageCenterIdentityLabel,
1354
- {
1355
- identity: item.identity,
1356
- provider
1357
- }
1358
- ),
1359
- /* @__PURE__ */ jsxs2(
2087
+ const { t } = useTranslation();
2088
+ return /* @__PURE__ */ jsxs3(DropdownMenu, { modal: false, children: [
2089
+ /* @__PURE__ */ jsx4(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs3(
1360
2090
  Button2,
1361
2091
  {
1362
2092
  type: "button",
1363
2093
  variant: "ghost",
1364
- size: "default",
1365
- 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",
1366
- onClick: () => onOpenChat({
1367
- agentSessionId: item.agentSessionId,
1368
- provider: item.provider
1369
- }),
2094
+ size: "icon",
2095
+ "aria-label": t("agentHost.workspaceAgentMessageCenterViewOptions"),
2096
+ title: t("agentHost.workspaceAgentMessageCenterViewOptions"),
2097
+ className: cn4(
2098
+ "relative size-8 shrink-0 rounded-md border bg-[var(--background-fronted)] shadow-none",
2099
+ filtersActive ? "border-[var(--border-focus)] text-[var(--accent)]" : "border-[var(--line-2)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]"
2100
+ ),
1370
2101
  children: [
1371
- /* @__PURE__ */ jsx3(
1372
- ExternalLink,
2102
+ /* @__PURE__ */ jsx4(ListFilter, { className: "size-4", strokeWidth: 2.1, "aria-hidden": "true" }),
2103
+ filtersActive ? /* @__PURE__ */ jsx4(
2104
+ "span",
1373
2105
  {
1374
- className: "size-[15px]",
1375
- strokeWidth: 2.2,
1376
- "aria-hidden": "true"
2106
+ "aria-label": t(
2107
+ "agentHost.workspaceAgentMessageCenterFilterActive"
2108
+ ),
2109
+ className: "absolute -right-0.5 -top-0.5 size-2 rounded-full border border-[var(--background-panel)] bg-[var(--accent)]"
1377
2110
  }
1378
- ),
1379
- label
2111
+ ) : null
1380
2112
  ]
1381
2113
  }
1382
- )
1383
- ] });
1384
- }
1385
- function MessageCenterIdentityLabel({
1386
- identity,
1387
- provider
1388
- }) {
1389
- "use memo";
1390
- if (!identity) {
1391
- return /* @__PURE__ */ jsx3(AgentProviderLabel, { provider });
1392
- }
1393
- const agentAvatarUrl = identity.agentAvatarUrl?.trim() || managedAgentRoundedIconUrl(provider);
1394
- const title = `${identity.userName} & ${identity.agentName}`;
1395
- return /* @__PURE__ */ jsxs2(
1396
- "span",
1397
- {
1398
- className: "workspace-agent-message-center__identity inline-flex min-w-0 max-w-full items-center gap-2",
1399
- title,
1400
- children: [
1401
- /* @__PURE__ */ jsx3(
1402
- MessageCenterIdentityAvatarStack,
1403
- {
1404
- userAvatarUrl: identity.userAvatarUrl,
1405
- userName: identity.userName,
1406
- agentAvatarUrl
1407
- }
1408
- ),
1409
- /* @__PURE__ */ jsxs2("span", { className: "workspace-agent-message-center__identity-names flex min-w-0 items-center gap-1 truncate text-[var(--text-secondary)]", children: [
1410
- /* @__PURE__ */ jsx3("span", { className: "min-w-0 truncate", children: identity.userName }),
1411
- /* @__PURE__ */ jsx3("span", { className: "shrink-0 text-[var(--text-tertiary)]", children: "&" }),
1412
- /* @__PURE__ */ jsx3("span", { className: "min-w-0 truncate", children: identity.agentName })
1413
- ] })
1414
- ]
1415
- }
1416
- );
1417
- }
1418
- function MessageCenterIdentityAvatarMark({
1419
- identity,
1420
- provider,
1421
- userId
1422
- }) {
1423
- "use memo";
1424
- const userName = identity?.userName.trim() || userId?.trim() || "";
1425
- if (!userName) {
1426
- return /* @__PURE__ */ jsx3(
1427
- "img",
1428
- {
1429
- src: managedAgentRoundedIconUrl(provider),
1430
- alt: "",
1431
- className: "size-5 shrink-0 rounded-full",
1432
- decoding: "async",
1433
- loading: "lazy",
1434
- draggable: false,
1435
- "aria-hidden": "true"
1436
- }
1437
- );
1438
- }
1439
- return /* @__PURE__ */ jsx3(
1440
- MessageCenterIdentityAvatarStack,
1441
- {
1442
- userAvatarUrl: identity?.userAvatarUrl,
1443
- userName,
1444
- agentAvatarUrl: identity?.agentAvatarUrl?.trim() || managedAgentRoundedIconUrl(provider)
1445
- }
1446
- );
1447
- }
1448
- function MessageCenterIdentityAvatarStack({
1449
- agentAvatarUrl,
1450
- userAvatarUrl: rawUserAvatarUrl,
1451
- userName
1452
- }) {
1453
- "use memo";
1454
- const [userAvatarFailed, setUserAvatarFailed] = useState(false);
1455
- const userAvatarUrl = rawUserAvatarUrl?.trim() ?? "";
1456
- const userImageUrl = userAvatarUrl.length > 0 && !userAvatarFailed ? userAvatarUrl : user_avatar_placeholder_default;
1457
- useEffect(() => {
1458
- setUserAvatarFailed(false);
1459
- }, [userAvatarUrl]);
1460
- return /* @__PURE__ */ jsxs2(
1461
- "span",
1462
- {
1463
- className: "workspace-agent-message-center__identity-avatar-stack inline-flex w-9 shrink-0 items-center",
1464
- "aria-hidden": "true",
1465
- children: [
1466
- /* @__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(
1467
- "img",
1468
- {
1469
- src: userImageUrl,
1470
- alt: userName,
1471
- className: "size-full object-cover",
1472
- decoding: "async",
1473
- loading: "lazy",
1474
- referrerPolicy: "no-referrer",
1475
- draggable: false,
1476
- onError: () => {
1477
- setUserAvatarFailed(true);
1478
- }
1479
- }
1480
- ) }),
1481
- /* @__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(
1482
- "img",
1483
- {
1484
- src: agentAvatarUrl,
1485
- alt: "",
1486
- className: "size-full object-cover",
1487
- decoding: "async",
1488
- loading: "lazy",
1489
- draggable: false
1490
- }
1491
- ) })
1492
- ]
1493
- }
1494
- );
1495
- }
1496
- function ProjectPathInfo({ path }) {
1497
- "use memo";
1498
- return /* @__PURE__ */ jsxs2(Tooltip, { children: [
1499
- /* @__PURE__ */ jsx3(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(
1500
- "button",
1501
- {
1502
- type: "button",
1503
- 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",
1504
- "aria-label": path,
1505
- children: /* @__PURE__ */ jsx3(Info, { className: "size-3.5", strokeWidth: 2, "aria-hidden": "true" })
1506
- }
1507
2114
  ) }),
1508
- /* @__PURE__ */ jsx3(
1509
- TooltipContent,
2115
+ /* @__PURE__ */ jsxs3(
2116
+ DropdownMenuContent,
1510
2117
  {
1511
- side: "top",
1512
- align: "start",
1513
- className: "max-w-[320px] text-[11px] [overflow-wrap:anywhere]",
1514
- children: path
2118
+ align: "end",
2119
+ sideOffset: 8,
2120
+ className: "min-w-[240px] p-1.5",
2121
+ style: { zIndex: "var(--z-dialog-popover)" },
2122
+ children: [
2123
+ /* @__PURE__ */ jsx4(DropdownMenuLabel, { children: t("agentHost.workspaceAgentMessageCenterGroupBy") }),
2124
+ /* @__PURE__ */ jsx4(
2125
+ DropdownMenuRadioGroup,
2126
+ {
2127
+ value: groupBy,
2128
+ onValueChange: (value) => onGroupByChange(value),
2129
+ children: ["priority", "status", "agent", "time"].map((value) => /* @__PURE__ */ jsx4(DropdownMenuRadioItem, { value, children: messageCenterGroupLabel(value, t) }, value))
2130
+ }
2131
+ ),
2132
+ /* @__PURE__ */ jsx4(DropdownMenuSeparator, {}),
2133
+ /* @__PURE__ */ jsx4(DropdownMenuLabel, { children: t("agentHost.workspaceAgentMessageCenterFilterStatus") }),
2134
+ /* @__PURE__ */ jsx4(DropdownMenuGroup, { children: statusOptions.map((option) => /* @__PURE__ */ jsxs3(
2135
+ DropdownMenuCheckboxItem,
2136
+ {
2137
+ "aria-label": `${option.label} ${option.count}`,
2138
+ checked: statusFilters === null || statusFilters.has(option.value),
2139
+ onCheckedChange: () => onStatusToggle(option.value),
2140
+ onSelect: (event) => event.preventDefault(),
2141
+ children: [
2142
+ /* @__PURE__ */ jsx4("span", { className: "min-w-0 flex-1 truncate", children: option.label }),
2143
+ /* @__PURE__ */ jsx4("span", { className: "ml-auto text-[11px] text-[var(--text-tertiary)]", children: option.count })
2144
+ ]
2145
+ },
2146
+ option.value
2147
+ )) }),
2148
+ providerOptions.length > 0 ? /* @__PURE__ */ jsxs3(Fragment, { children: [
2149
+ /* @__PURE__ */ jsx4(DropdownMenuSeparator, {}),
2150
+ /* @__PURE__ */ jsx4(DropdownMenuLabel, { children: t("agentHost.workspaceAgentMessageCenterFilterAgent") }),
2151
+ /* @__PURE__ */ jsx4(DropdownMenuGroup, { children: providerOptions.map((option) => /* @__PURE__ */ jsxs3(
2152
+ DropdownMenuCheckboxItem,
2153
+ {
2154
+ "aria-label": `${option.label} ${option.count}`,
2155
+ checked: providerFilters === null || providerFilters.has(option.value),
2156
+ onCheckedChange: () => onProviderToggle(option.value),
2157
+ onSelect: (event) => event.preventDefault(),
2158
+ children: [
2159
+ /* @__PURE__ */ jsx4("span", { className: "min-w-0 flex-1 truncate", children: option.label }),
2160
+ /* @__PURE__ */ jsx4("span", { className: "ml-auto text-[11px] text-[var(--text-tertiary)]", children: option.count })
2161
+ ]
2162
+ },
2163
+ option.value
2164
+ )) })
2165
+ ] }) : null,
2166
+ /* @__PURE__ */ jsx4(DropdownMenuSeparator, {}),
2167
+ /* @__PURE__ */ jsx4(DropdownMenuGroup, { children: /* @__PURE__ */ jsx4(DropdownMenuItem, { onClick: onClearFilters, children: t("agentHost.workspaceAgentMessageCenterClearFilters") }) })
2168
+ ]
1515
2169
  }
1516
2170
  )
1517
2171
  ] });
1518
2172
  }
1519
- function AgentProviderLabel({ provider }) {
1520
- "use memo";
1521
- const label = workspaceAgentProviderLabel(provider);
1522
- return /* @__PURE__ */ jsxs2("span", { className: "workspace-agent-message-center__provider inline-flex min-w-0 max-w-full items-center gap-1.5", children: [
1523
- /* @__PURE__ */ jsx3(
1524
- "img",
1525
- {
1526
- src: managedAgentRoundedIconUrl(provider),
1527
- alt: "",
1528
- className: "workspace-agent-message-center__provider-icon size-5 shrink-0 rounded-full",
1529
- decoding: "async",
1530
- loading: "lazy",
1531
- draggable: false,
1532
- "aria-hidden": "true"
1533
- }
1534
- ),
1535
- /* @__PURE__ */ jsx3("span", { className: "workspace-agent-message-center__provider-name min-w-0 truncate text-[var(--text-secondary)]", children: label })
1536
- ] });
1537
- }
1538
- function statusClass(item) {
1539
- if (isWaitingMessageCenterItem(item)) {
1540
- return "waiting";
1541
- }
1542
- if (item.status === "idle") {
1543
- return "completed";
1544
- }
1545
- return item.status;
1546
- }
1547
- function messageCenterStatusTone(item) {
1548
- if (isWaitingMessageCenterItem(item)) {
1549
- return "amber";
1550
- }
1551
- if (item.status === "completed" || item.status === "idle") {
1552
- return "green";
1553
- }
1554
- if (item.status === "canceled") {
1555
- return "amber";
1556
- }
1557
- if (item.status === "failed") {
1558
- return "red";
1559
- }
1560
- if (item.status === "working") {
1561
- return "blue";
1562
- }
1563
- return "neutral";
1564
- }
1565
2173
 
1566
2174
  // agent-message-center/WorkspaceAgentMessageCenterPanel.tsx
1567
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
2175
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1568
2176
  var MESSAGE_CENTER_TOOLTIP_DELAY_MS = 300;
1569
2177
  var WorkspaceAgentMessageCenterPanel = memo(
1570
2178
  function WorkspaceAgentMessageCenterPanel2({
@@ -1582,7 +2190,7 @@ var WorkspaceAgentMessageCenterPanel = memo(
1582
2190
  onSubmitPrompt
1583
2191
  }) {
1584
2192
  "use memo";
1585
- return /* @__PURE__ */ jsx4(AgentGuiI18nProvider, { runtime: i18n, locale, children: /* @__PURE__ */ jsx4(
2193
+ return /* @__PURE__ */ jsx5(AgentGuiI18nProvider, { runtime: i18n, locale, children: /* @__PURE__ */ jsx5(
1586
2194
  WorkspaceAgentMessageCenterPanelContent,
1587
2195
  {
1588
2196
  open,
@@ -1613,29 +2221,29 @@ function WorkspaceAgentMessageCenterPanelContent({
1613
2221
  }) {
1614
2222
  "use memo";
1615
2223
  const { t } = useTranslation();
1616
- const [groupBy, setGroupBy] = useState2("priority");
1617
- const [statusFilters, setStatusFilters] = useState2(null);
1618
- const [providerFilters, setProviderFilters] = useState2(
2224
+ const [groupBy, setGroupBy] = useState3("priority");
2225
+ const [statusFilters, setStatusFilters] = useState3(null);
2226
+ const [providerFilters, setProviderFilters] = useState3(
1619
2227
  null
1620
2228
  );
1621
- const [expandedStackIds, setExpandedStackIds] = useState2(
2229
+ const [expandedStackIds, setExpandedStackIds] = useState3(
1622
2230
  () => /* @__PURE__ */ new Set()
1623
2231
  );
1624
- const [submittingPromptKey, setSubmittingPromptKey] = useState2(
2232
+ const [submittingPromptKey, setSubmittingPromptKey] = useState3(
1625
2233
  null
1626
2234
  );
1627
- const itemNodesRef = useRef2(/* @__PURE__ */ new Map());
1628
- const lastScrolledHighlightedItemIdRef = useRef2(null);
1629
- const lastFilterResetHighlightedItemIdRef = useRef2(null);
1630
- const statusOptions = useMemo(
2235
+ const itemNodesRef = useRef3(/* @__PURE__ */ new Map());
2236
+ const lastScrolledHighlightedItemIdRef = useRef3(null);
2237
+ const lastFilterResetHighlightedItemIdRef = useRef3(null);
2238
+ const statusOptions = useMemo2(
1631
2239
  () => buildMessageCenterStatusOptions(model.counts, t),
1632
2240
  [model.counts, t]
1633
2241
  );
1634
- const providerOptions = useMemo(
2242
+ const providerOptions = useMemo2(
1635
2243
  () => buildMessageCenterProviderOptions(model.items),
1636
2244
  [model.items]
1637
2245
  );
1638
- const visibleItems = useMemo(
2246
+ const visibleItems = useMemo2(
1639
2247
  () => model.items.filter(
1640
2248
  (item) => itemMatchesViewFilters({
1641
2249
  item,
@@ -1645,17 +2253,25 @@ function WorkspaceAgentMessageCenterPanelContent({
1645
2253
  ),
1646
2254
  [model.items, providerFilters, statusFilters]
1647
2255
  );
1648
- const itemGroups = useMemo(
1649
- () => groupMessageCenterItems(visibleItems, groupBy, t),
1650
- [groupBy, t, visibleItems]
2256
+ const deckItems = useMemo2(
2257
+ () => selectMessageCenterAttentionDeckItems(visibleItems),
2258
+ [visibleItems]
2259
+ );
2260
+ const listItems = useMemo2(
2261
+ () => visibleItems.filter((item) => !isInteractiveMessageCenterItem(item)),
2262
+ [visibleItems]
1651
2263
  );
1652
- const highlightedItem = useMemo(
2264
+ const itemGroups = useMemo2(
2265
+ () => groupMessageCenterItems(listItems, groupBy, t),
2266
+ [groupBy, t, listItems]
2267
+ );
2268
+ const highlightedItem = useMemo2(
1653
2269
  () => highlightedItemId ? model.items.find((item) => item.id === highlightedItemId) ?? null : null,
1654
2270
  [highlightedItemId, model.items]
1655
2271
  );
1656
2272
  const activeStatusSummary = statusFilterSummary(statusFilters, statusOptions);
1657
2273
  const hasActiveFilters = statusFilters !== null || providerFilters !== null;
1658
- const headerSummary = useMemo(() => {
2274
+ const headerSummary = useMemo2(() => {
1659
2275
  if (hasActiveFilters) {
1660
2276
  return t("agentHost.workspaceAgentMessageCenterSummaryFiltered", {
1661
2277
  count: visibleItems.length,
@@ -1702,7 +2318,8 @@ function WorkspaceAgentMessageCenterPanelContent({
1702
2318
  }
1703
2319
  await onSubmitPrompt({
1704
2320
  ...input,
1705
- agentSessionId: item.agentSessionId
2321
+ agentSessionId: item.agentSessionId,
2322
+ promptKind: item.pendingPrompt?.kind
1706
2323
  });
1707
2324
  } finally {
1708
2325
  setSubmittingPromptKey(
@@ -1840,7 +2457,7 @@ function WorkspaceAgentMessageCenterPanelContent({
1840
2457
  statusFilters,
1841
2458
  visibleItems
1842
2459
  ]);
1843
- useEffect2(() => {
2460
+ useEffect3(() => {
1844
2461
  if (!open || !highlightedItemId) {
1845
2462
  return void 0;
1846
2463
  }
@@ -1851,7 +2468,7 @@ function WorkspaceAgentMessageCenterPanelContent({
1851
2468
  window.clearTimeout(timeoutId);
1852
2469
  };
1853
2470
  }, [highlightedItemId, onHighlightedItemSettled, open]);
1854
- return /* @__PURE__ */ jsx4(
2471
+ return /* @__PURE__ */ jsx5(
1855
2472
  Drawer,
1856
2473
  {
1857
2474
  open,
@@ -1862,10 +2479,10 @@ function WorkspaceAgentMessageCenterPanelContent({
1862
2479
  onClose();
1863
2480
  }
1864
2481
  },
1865
- children: /* @__PURE__ */ jsx4(
2482
+ children: /* @__PURE__ */ jsx5(
1866
2483
  DrawerContent,
1867
2484
  {
1868
- className: cn4(
2485
+ className: cn5(
1869
2486
  "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",
1870
2487
  "[-webkit-app-region:no-drag]"
1871
2488
  ),
@@ -1873,13 +2490,13 @@ function WorkspaceAgentMessageCenterPanelContent({
1873
2490
  portalContainer: portalContainer ?? void 0,
1874
2491
  showOverlay: false,
1875
2492
  "aria-label": t("agentHost.workspaceAgentMessageCenterTitle"),
1876
- children: /* @__PURE__ */ jsxs3(TooltipProvider, { delayDuration: MESSAGE_CENTER_TOOLTIP_DELAY_MS, children: [
1877
- /* @__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: [
1878
- /* @__PURE__ */ jsxs3("div", { className: "min-w-0", children: [
1879
- /* @__PURE__ */ jsx4("div", { className: "truncate text-[13px] font-semibold leading-5 text-[var(--text-primary)]", children: t("agentHost.workspaceAgentMessageCenterTitle") }),
1880
- /* @__PURE__ */ jsx4("div", { className: "truncate text-[11px] leading-4 text-[var(--text-tertiary)]", children: headerSummary })
2493
+ children: /* @__PURE__ */ jsxs4(TooltipProvider, { delayDuration: MESSAGE_CENTER_TOOLTIP_DELAY_MS, children: [
2494
+ /* @__PURE__ */ jsx5("div", { className: "flex-none border-b border-[var(--border-1)] px-3.5 pt-3 pb-3", children: /* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 items-center justify-between gap-3", children: [
2495
+ /* @__PURE__ */ jsxs4("div", { className: "min-w-0", children: [
2496
+ /* @__PURE__ */ jsx5("div", { className: "truncate text-[13px] font-semibold leading-5 text-[var(--text-primary)]", children: t("agentHost.workspaceAgentMessageCenterTitle") }),
2497
+ /* @__PURE__ */ jsx5("div", { className: "truncate text-[11px] leading-4 text-[var(--text-tertiary)]", children: headerSummary })
1881
2498
  ] }),
1882
- /* @__PURE__ */ jsx4(
2499
+ /* @__PURE__ */ jsx5(
1883
2500
  MessageCenterViewMenu,
1884
2501
  {
1885
2502
  filtersActive: hasActiveFilters,
@@ -1895,82 +2512,96 @@ function WorkspaceAgentMessageCenterPanelContent({
1895
2512
  }
1896
2513
  )
1897
2514
  ] }) }),
1898
- /* @__PURE__ */ jsx4(
2515
+ /* @__PURE__ */ jsx5(
1899
2516
  AgentVerticalScrollArea,
1900
2517
  {
1901
2518
  className: "min-h-0 flex-1",
1902
2519
  viewportClassName: "flex h-full w-full flex-col px-3.5 pt-4 pb-4",
1903
2520
  scrollbarClassName: "top-4 bottom-4",
1904
- syncKey: `${groupBy}:${activeStatusSummary}:${visibleItems.map((item) => item.id).join("|")}`,
1905
- children: visibleItems.length > 0 ? /* @__PURE__ */ jsx4("div", { className: "flex w-full min-w-0 flex-col gap-4", children: itemGroups.map((group) => /* @__PURE__ */ jsxs3(
1906
- "section",
1907
- {
1908
- className: "flex min-w-0 flex-col gap-2.5",
1909
- "aria-label": `${group.label} ${group.items.length}`,
1910
- children: [
1911
- /* @__PURE__ */ jsx4("div", { className: "flex min-w-0 items-center justify-between gap-3 px-0.5", children: /* @__PURE__ */ jsx4(MessageCenterGroupHeading, { group }) }),
1912
- (() => {
1913
- const renderCard = (item, options = {}) => {
1914
- const highlighted = item.id === highlightedItemId;
1915
- const card = /* @__PURE__ */ jsx4(
1916
- MessageCenterCard,
1917
- {
1918
- cardRef: (node) => setItemNode(item.id, node),
1919
- highlighted,
1920
- item,
1921
- isSubmitting: submittingPromptKey === `${item.agentSessionId}:${item.pendingPrompt?.requestId}`,
1922
- onLinkAction,
1923
- onOpenChat,
1924
- onSubmitPrompt: (input) => void submitPrompt(item, input)
1925
- },
1926
- item.agentSessionId
1927
- );
1928
- if (options.stackedIndex === void 0) {
1929
- return card;
1930
- }
1931
- return /* @__PURE__ */ jsx4(
1932
- "div",
1933
- {
1934
- 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",
1935
- style: {
1936
- animationDelay: `${Math.min(options.stackedIndex * 24, 96)}ms`
2521
+ syncKey: `${groupBy}:${activeStatusSummary}:${[...deckItems, ...visibleItems].map((item) => item.id).join("|")}`,
2522
+ children: deckItems.length > 0 || listItems.length > 0 ? /* @__PURE__ */ jsxs4("div", { className: "flex w-full min-w-0 flex-col gap-4", children: [
2523
+ deckItems.length > 0 ? /* @__PURE__ */ jsx5(
2524
+ WorkspaceAgentMessageCenterAttentionDeck,
2525
+ {
2526
+ items: deckItems,
2527
+ highlightedItemId,
2528
+ submittingPromptKey,
2529
+ registerNode: setItemNode,
2530
+ onLinkAction,
2531
+ onOpenChat,
2532
+ onSubmitPrompt: (item, input) => void submitPrompt(item, input)
2533
+ }
2534
+ ) : null,
2535
+ itemGroups.map((group) => /* @__PURE__ */ jsxs4(
2536
+ "section",
2537
+ {
2538
+ className: "flex min-w-0 flex-col gap-2.5",
2539
+ "aria-label": `${group.label} ${group.items.length}`,
2540
+ children: [
2541
+ /* @__PURE__ */ jsx5("div", { className: "flex min-w-0 items-center justify-between gap-3 px-0.5", children: /* @__PURE__ */ jsx5(MessageCenterGroupHeading, { group }) }),
2542
+ (() => {
2543
+ const renderCard = (item, options = {}) => {
2544
+ const highlighted = item.id === highlightedItemId;
2545
+ const card = /* @__PURE__ */ jsx5(
2546
+ MessageCenterCard,
2547
+ {
2548
+ cardRef: (node) => setItemNode(item.id, node),
2549
+ highlighted,
2550
+ item,
2551
+ isSubmitting: submittingPromptKey === `${item.agentSessionId}:${item.pendingPrompt?.requestId}`,
2552
+ onLinkAction,
2553
+ onOpenChat,
2554
+ onSubmitPrompt: (input) => void submitPrompt(item, input)
1937
2555
  },
1938
- children: card
1939
- },
1940
- item.agentSessionId
1941
- );
1942
- };
1943
- return partitionMessageCenterItemsByAgentUser(
1944
- group.items
1945
- ).map((stack) => {
1946
- const firstItem = stack.items[0];
1947
- if (!firstItem) {
1948
- return null;
1949
- }
1950
- if (stack.items.length === 1) {
1951
- return renderCard(firstItem);
1952
- }
1953
- const stackId = group.id === stack.id ? stack.id : `${group.id}:${stack.id}`;
1954
- return /* @__PURE__ */ jsx4(
1955
- MessageCenterStack,
1956
- {
1957
- expanded: expandedStackIds.has(stackId),
1958
- groupId: stackId,
1959
- items: stack.items,
1960
- renderCard,
1961
- onCollapse: () => collapseStack(stackId),
1962
- onExpand: () => expandStack(stackId)
1963
- },
1964
- stackId
1965
- );
1966
- });
1967
- })()
1968
- ]
1969
- },
1970
- group.id
1971
- )) }) : 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: [
1972
- /* @__PURE__ */ jsx4("span", { children: t("agentHost.workspaceAgentMessageCenterFilteredEmpty") }),
1973
- /* @__PURE__ */ jsx4(
2556
+ item.agentSessionId
2557
+ );
2558
+ if (options.stackedIndex === void 0) {
2559
+ return card;
2560
+ }
2561
+ return /* @__PURE__ */ jsx5(
2562
+ "div",
2563
+ {
2564
+ 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",
2565
+ style: {
2566
+ animationDelay: `${Math.min(options.stackedIndex * 24, 96)}ms`
2567
+ },
2568
+ children: card
2569
+ },
2570
+ item.agentSessionId
2571
+ );
2572
+ };
2573
+ return partitionMessageCenterItemsByAgentUser(
2574
+ group.items
2575
+ ).map((stack) => {
2576
+ const firstItem = stack.items[0];
2577
+ if (!firstItem) {
2578
+ return null;
2579
+ }
2580
+ if (stack.items.length === 1) {
2581
+ return renderCard(firstItem);
2582
+ }
2583
+ const stackId = group.id === stack.id ? stack.id : `${group.id}:${stack.id}`;
2584
+ return /* @__PURE__ */ jsx5(
2585
+ MessageCenterStack,
2586
+ {
2587
+ expanded: expandedStackIds.has(stackId),
2588
+ groupId: stackId,
2589
+ items: stack.items,
2590
+ renderCard,
2591
+ onCollapse: () => collapseStack(stackId),
2592
+ onExpand: () => expandStack(stackId)
2593
+ },
2594
+ stackId
2595
+ );
2596
+ });
2597
+ })()
2598
+ ]
2599
+ },
2600
+ group.id
2601
+ ))
2602
+ ] }) : model.items.length > 0 ? /* @__PURE__ */ jsxs4("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: [
2603
+ /* @__PURE__ */ jsx5("span", { children: t("agentHost.workspaceAgentMessageCenterFilteredEmpty") }),
2604
+ /* @__PURE__ */ jsx5(
1974
2605
  Button3,
1975
2606
  {
1976
2607
  type: "button",
@@ -1981,7 +2612,7 @@ function WorkspaceAgentMessageCenterPanelContent({
1981
2612
  children: t("agentHost.workspaceAgentMessageCenterClearFilters")
1982
2613
  }
1983
2614
  )
1984
- ] }) : /* @__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") })
2615
+ ] }) : /* @__PURE__ */ jsx5("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") })
1985
2616
  }
1986
2617
  )
1987
2618
  ] })
@@ -1997,21 +2628,21 @@ function MessageCenterGroupHeading({
1997
2628
  }) {
1998
2629
  "use memo";
1999
2630
  if (group.provider) {
2000
- return /* @__PURE__ */ jsxs3(
2631
+ return /* @__PURE__ */ jsxs4(
2001
2632
  "h3",
2002
2633
  {
2003
2634
  "aria-label": `${group.label} \xB7 ${group.items.length}`,
2004
2635
  className: "flex min-w-0 items-center gap-1.5 text-[11px] font-normal leading-4 text-[var(--text-tertiary)]",
2005
2636
  title: `${group.label} \xB7 ${group.items.length}`,
2006
2637
  children: [
2007
- group.identity ? /* @__PURE__ */ jsx4(
2638
+ group.identity ? /* @__PURE__ */ jsx5(
2008
2639
  MessageCenterIdentityLabel,
2009
2640
  {
2010
2641
  identity: group.identity,
2011
2642
  provider: group.provider
2012
2643
  }
2013
- ) : /* @__PURE__ */ jsxs3("span", { className: "inline-flex min-w-0 items-center gap-1.5", children: [
2014
- /* @__PURE__ */ jsx4(
2644
+ ) : /* @__PURE__ */ jsxs4("span", { className: "inline-flex min-w-0 items-center gap-1.5", children: [
2645
+ /* @__PURE__ */ jsx5(
2015
2646
  MessageCenterIdentityAvatarMark,
2016
2647
  {
2017
2648
  identity: null,
@@ -2019,9 +2650,9 @@ function MessageCenterGroupHeading({
2019
2650
  userId: group.userId ?? null
2020
2651
  }
2021
2652
  ),
2022
- /* @__PURE__ */ jsx4("span", { className: "min-w-0 truncate", children: group.label })
2653
+ /* @__PURE__ */ jsx5("span", { className: "min-w-0 truncate", children: group.label })
2023
2654
  ] }),
2024
- /* @__PURE__ */ jsxs3("span", { className: "shrink-0", children: [
2655
+ /* @__PURE__ */ jsxs4("span", { className: "shrink-0", children: [
2025
2656
  "\xB7 ",
2026
2657
  group.items.length
2027
2658
  ] })
@@ -2029,7 +2660,7 @@ function MessageCenterGroupHeading({
2029
2660
  }
2030
2661
  );
2031
2662
  }
2032
- return /* @__PURE__ */ jsxs3("h3", { className: "truncate text-[11px] font-normal leading-4 text-[var(--text-tertiary)]", children: [
2663
+ return /* @__PURE__ */ jsxs4("h3", { className: "truncate text-[11px] font-normal leading-4 text-[var(--text-tertiary)]", children: [
2033
2664
  group.label,
2034
2665
  " \xB7 ",
2035
2666
  group.items.length
@@ -2037,6 +2668,8 @@ function MessageCenterGroupHeading({
2037
2668
  }
2038
2669
  export {
2039
2670
  AgentInteractivePromptSurface,
2671
+ PLAN_IMPLEMENTATION_ACTION_IMPLEMENT,
2672
+ PLAN_IMPLEMENTATION_PROMPT,
2040
2673
  WorkspaceAgentMessageCenterCard,
2041
2674
  WorkspaceAgentMessageCenterPanel,
2042
2675
  approvalOptionDisplayLabel,