@tutti-os/agent-gui 0.0.10 → 0.0.12

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