@tutti-os/agent-gui 0.0.233 → 0.0.234

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 (87) hide show
  1. package/README.md +49 -0
  2. package/dist/{AgentRichTextReadonly-U3XUJYCW.js → AgentRichTextReadonly-CCELQPHE.js} +5 -5
  3. package/dist/agent-conversation/index.d.ts +17 -4
  4. package/dist/agent-conversation/index.js +13 -9
  5. package/dist/agent-conversation/index.js.map +1 -1
  6. package/dist/agent-gui.d.ts +19 -3
  7. package/dist/agent-gui.js +22 -16
  8. package/dist/agent-message-center/index.d.ts +1 -1
  9. package/dist/agent-message-center/index.js +10 -7
  10. package/dist/agent-message-center/index.js.map +1 -1
  11. package/dist/{agentGuiNodeTypes-DW7T--Y8.d.ts → agentGuiNodeTypes-Dgl7kQHA.d.ts} +2 -2
  12. package/dist/agents.d.ts +1 -1
  13. package/dist/app/renderer/agentactivity.css +17 -0
  14. package/dist/{chunk-M6WEFXPL.js → chunk-2MCNNB2P.js} +2 -24
  15. package/dist/chunk-2MCNNB2P.js.map +1 -0
  16. package/dist/{chunk-CQFT3MI5.js → chunk-3YYI6RXA.js} +7 -5
  17. package/dist/{chunk-CQFT3MI5.js.map → chunk-3YYI6RXA.js.map} +1 -1
  18. package/dist/{chunk-EDP4D42H.js → chunk-45KN5Z5F.js} +877 -871
  19. package/dist/chunk-45KN5Z5F.js.map +1 -0
  20. package/dist/{chunk-T57ZZWTC.js → chunk-4HAG3FOY.js} +2 -2
  21. package/dist/{chunk-ZBI6R46N.js → chunk-5DN5N2XS.js} +2 -2
  22. package/dist/{chunk-BCBB4HOV.js → chunk-634MNSI5.js} +2 -2
  23. package/dist/chunk-A4KKC324.js +4768 -0
  24. package/dist/chunk-A4KKC324.js.map +1 -0
  25. package/dist/chunk-ALAGL6VL.js +48 -0
  26. package/dist/chunk-ALAGL6VL.js.map +1 -0
  27. package/dist/{chunk-2STAUA73.js → chunk-AYTUAZE3.js} +5 -2
  28. package/dist/chunk-AYTUAZE3.js.map +1 -0
  29. package/dist/{chunk-SWO67UWQ.js → chunk-CZOZBUIM.js} +7 -7
  30. package/dist/{chunk-SWO67UWQ.js.map → chunk-CZOZBUIM.js.map} +1 -1
  31. package/dist/{chunk-2L2LVSOD.js → chunk-EHNPHZE4.js} +881 -5812
  32. package/dist/chunk-EHNPHZE4.js.map +1 -0
  33. package/dist/{chunk-N5356722.js → chunk-EKQ7UX2B.js} +13 -319
  34. package/dist/chunk-EKQ7UX2B.js.map +1 -0
  35. package/dist/{chunk-ZXEICU6J.js → chunk-KK7YXPTS.js} +3 -1
  36. package/dist/chunk-KK7YXPTS.js.map +1 -0
  37. package/dist/{chunk-WGCDSA7P.js → chunk-MBM7PJIF.js} +27 -506
  38. package/dist/chunk-MBM7PJIF.js.map +1 -0
  39. package/dist/chunk-RMC2MGL4.js +557 -0
  40. package/dist/chunk-RMC2MGL4.js.map +1 -0
  41. package/dist/{chunk-JA6XAKKE.js → chunk-TWF6JXPC.js} +2 -2
  42. package/dist/{chunk-7AYFKNLD.js → chunk-TWMV6YTX.js} +4 -4
  43. package/dist/chunk-VV3YIU5W.js +25 -0
  44. package/dist/chunk-VV3YIU5W.js.map +1 -0
  45. package/dist/{chunk-GLVENTN6.js → chunk-WXLO33YP.js} +2 -2
  46. package/dist/chunk-XWPHTXEM.js +529 -0
  47. package/dist/chunk-XWPHTXEM.js.map +1 -0
  48. package/dist/chunk-YEXRTXTE.js +315 -0
  49. package/dist/chunk-YEXRTXTE.js.map +1 -0
  50. package/dist/{chunk-WMJDOMG6.js → chunk-ZELGKLW5.js} +4 -4
  51. package/dist/composer-projection.d.ts +37 -0
  52. package/dist/composer-projection.js +21 -0
  53. package/dist/composer-projection.js.map +1 -0
  54. package/dist/context-mention-palette/index.js +9 -7
  55. package/dist/conversation-projection.d.ts +551 -0
  56. package/dist/conversation-projection.js +42 -0
  57. package/dist/conversation-projection.js.map +1 -0
  58. package/dist/conversation-rail-projection.js +3 -3
  59. package/dist/i18n/index.d.ts +2 -0
  60. package/dist/i18n/index.js +2 -2
  61. package/dist/index.d.ts +32 -13
  62. package/dist/index.js +22 -16
  63. package/dist/index.js.map +1 -1
  64. package/dist/mention-search.js +7 -5
  65. package/dist/{types-CHAMK2g7.d.ts → types-DtXXsISB.d.ts} +1 -1
  66. package/dist/workbench/contribution.js +4 -4
  67. package/dist/workbench/index.js +4 -4
  68. package/dist/workbench/sessionTitle.js +3 -3
  69. package/dist/workspace-agent-generated-files.d.ts +1 -12
  70. package/dist/workspaceAgentActivityListTypes-BUKNyMbh.d.ts +48 -0
  71. package/dist/{workspaceLinkActions-CzsbvGmC.d.ts → workspaceLinkActions-DxyzMy10.d.ts} +13 -12
  72. package/package.json +31 -17
  73. package/dist/chunk-2L2LVSOD.js.map +0 -1
  74. package/dist/chunk-2STAUA73.js.map +0 -1
  75. package/dist/chunk-EDP4D42H.js.map +0 -1
  76. package/dist/chunk-M6WEFXPL.js.map +0 -1
  77. package/dist/chunk-N5356722.js.map +0 -1
  78. package/dist/chunk-WGCDSA7P.js.map +0 -1
  79. package/dist/chunk-ZXEICU6J.js.map +0 -1
  80. /package/dist/{AgentRichTextReadonly-U3XUJYCW.js.map → AgentRichTextReadonly-CCELQPHE.js.map} +0 -0
  81. /package/dist/{chunk-T57ZZWTC.js.map → chunk-4HAG3FOY.js.map} +0 -0
  82. /package/dist/{chunk-ZBI6R46N.js.map → chunk-5DN5N2XS.js.map} +0 -0
  83. /package/dist/{chunk-BCBB4HOV.js.map → chunk-634MNSI5.js.map} +0 -0
  84. /package/dist/{chunk-JA6XAKKE.js.map → chunk-TWF6JXPC.js.map} +0 -0
  85. /package/dist/{chunk-7AYFKNLD.js.map → chunk-TWMV6YTX.js.map} +0 -0
  86. /package/dist/{chunk-GLVENTN6.js.map → chunk-WXLO33YP.js.map} +0 -0
  87. /package/dist/{chunk-WMJDOMG6.js.map → chunk-ZELGKLW5.js.map} +0 -0
@@ -0,0 +1,4768 @@
1
+ import {
2
+ extractAgentMcpToolTarget,
3
+ extractExitPlanKeepPlanningOptionId,
4
+ extractExitPlanModeOptions,
5
+ isExitPlanSwitchModeInput,
6
+ normalizeAgentApprovalPurpose,
7
+ normalizeAskUserQuestions,
8
+ resolveWorkspaceFilePathCandidate
9
+ } from "./chunk-XWPHTXEM.js";
10
+ import {
11
+ isWorkspaceAgentSyntheticControlMessage
12
+ } from "./chunk-XJ34OIEQ.js";
13
+ import {
14
+ extractImageGenerationPreview,
15
+ isImageGenerationToolCall,
16
+ resolveImageGenerationCanonicalToolName
17
+ } from "./chunk-JDVP33S5.js";
18
+ import {
19
+ fileChangeCountFromChanges,
20
+ fileChangeEntriesFromChanges,
21
+ fileChangeTypeValue
22
+ } from "./chunk-F5UR6EJG.js";
23
+ import {
24
+ translate
25
+ } from "./chunk-WXLO33YP.js";
26
+ import {
27
+ AGENT_PASTED_TEXT_MENTION_KIND
28
+ } from "./chunk-FGLQZ6I4.js";
29
+
30
+ // shared/agentConversation/projection/agentMessageFinalTextProjection.ts
31
+ function projectAgentMessageFinalText(rows, detail) {
32
+ const finalTextTargetKeys = findLatestAssistantFinalTextTargetKeys(
33
+ rows,
34
+ buildAssistantFinalTextEligibleTurnIds(detail)
35
+ );
36
+ return rows.map((row) => {
37
+ if (row.kind !== "message") {
38
+ return row;
39
+ }
40
+ let changed = false;
41
+ const messages = row.messages.map((message) => {
42
+ const isTurnFinalText = row.speaker === "assistant" && finalTextTargetKeys.has(messagePresentationTargetKey(row, message));
43
+ const copyText = row.speaker === "user" ? copyTextForUserMessage(message) : isTurnFinalText ? message.body : null;
44
+ if ((message.copyText ?? null) === copyText && message.isTurnFinalText === (isTurnFinalText ? true : void 0)) {
45
+ return message;
46
+ }
47
+ changed = true;
48
+ const nextMessage = isTurnFinalText ? { ...message, isTurnFinalText: true } : omitTurnFinalText(message);
49
+ if (copyText) {
50
+ return { ...nextMessage, copyText };
51
+ }
52
+ const { copyText: _copyText, ...withoutCopyText } = nextMessage;
53
+ return withoutCopyText;
54
+ });
55
+ return changed ? { ...row, messages } : row;
56
+ });
57
+ }
58
+ function omitTurnFinalText(message) {
59
+ const { isTurnFinalText: _isTurnFinalText, ...withoutTurnFinalText } = message;
60
+ return withoutTurnFinalText;
61
+ }
62
+ function buildAssistantFinalTextEligibleTurnIds(detail) {
63
+ const ids = /* @__PURE__ */ new Set();
64
+ detail.turns.forEach((turn, index) => {
65
+ if (index < detail.turns.length - 1 || isLatestTranscriptTurnSettled(detail)) {
66
+ ids.add(turn.id);
67
+ }
68
+ });
69
+ return ids;
70
+ }
71
+ function isLatestTranscriptTurnSettled(detail) {
72
+ const latestTranscriptTurnId = detail.turns.at(-1)?.id;
73
+ const canonicalTurn = detail.sessionTurns?.find(
74
+ (turn) => turn.turnId === latestTranscriptTurnId
75
+ );
76
+ const activeTurn = detail.session.activeTurn;
77
+ if (activeTurn && activeTurn.turnId === latestTranscriptTurnId && activeTurn.phase !== "settled") {
78
+ return false;
79
+ }
80
+ if (canonicalTurn) {
81
+ return canonicalTurn.phase === "settled" && detail.showProcessingIndicator !== true;
82
+ }
83
+ const activePhase = activeTurn?.phase ?? "";
84
+ return detail.showProcessingIndicator !== true && !["submitted", "running", "waiting", "settling"].includes(activePhase);
85
+ }
86
+ function findLatestAssistantFinalTextTargetKeys(rows, eligibleTurnIds) {
87
+ const targetKeys = /* @__PURE__ */ new Set();
88
+ const coveredTurnIds = /* @__PURE__ */ new Set();
89
+ for (let rowIndex = rows.length - 1; rowIndex >= 0; rowIndex -= 1) {
90
+ const row = rows[rowIndex];
91
+ if (row?.kind !== "message" || row.speaker !== "assistant" || coveredTurnIds.has(row.turnId) || !eligibleTurnIds.has(row.turnId)) {
92
+ continue;
93
+ }
94
+ for (let messageIndex = row.messages.length - 1; messageIndex >= 0; messageIndex -= 1) {
95
+ const message = row.messages[messageIndex];
96
+ if (message && isSettledAssistantFinalTextCandidate(message)) {
97
+ targetKeys.add(messagePresentationTargetKey(row, message));
98
+ coveredTurnIds.add(row.turnId);
99
+ break;
100
+ }
101
+ }
102
+ }
103
+ return targetKeys;
104
+ }
105
+ function messagePresentationTargetKey(row, message) {
106
+ return `${row.id}\0${message.id}`;
107
+ }
108
+ function copyTextForUserMessage(message) {
109
+ return isVisibleTextMessage(message) ? message.body : null;
110
+ }
111
+ function isSettledAssistantFinalTextCandidate(message) {
112
+ return isVisibleTextMessage(message) && message.statusKind !== "working" && message.statusKind !== "waiting";
113
+ }
114
+ function isVisibleTextMessage(message) {
115
+ return message.body.trim() !== "" && message.contentKind !== "image-grid" && message.contentKind !== "collaboration" && !message.visibleError && !message.systemNotice;
116
+ }
117
+
118
+ // shared/agentConversation/projection/agentToolGroupingProjection.ts
119
+ var AVOID_GROUPING_EDITS = false;
120
+ function computeAgentToolGroups(sequence, {
121
+ avoidGroupingEdits = AVOID_GROUPING_EDITS
122
+ }) {
123
+ const groups = /* @__PURE__ */ new Map();
124
+ const groupedIndices = /* @__PURE__ */ new Set();
125
+ const suppressedIndices = /* @__PURE__ */ new Set();
126
+ let currentCalls = [];
127
+ let currentEntries = [];
128
+ let currentIndices = [];
129
+ let pendingBridgeEntries = [];
130
+ let pendingBridgeIndices = [];
131
+ let startIndex = -1;
132
+ const finalizeGroup = () => {
133
+ if (currentCalls.length >= 1 && startIndex >= 0 && currentIndices.length > 0) {
134
+ const endIndex = currentIndices[currentIndices.length - 1] ?? startIndex;
135
+ groups.set(startIndex, {
136
+ startIndex,
137
+ endIndex,
138
+ calls: [...currentCalls],
139
+ entries: [...currentEntries]
140
+ });
141
+ currentIndices.forEach((index) => groupedIndices.add(index));
142
+ }
143
+ currentCalls = [];
144
+ currentEntries = [];
145
+ currentIndices = [];
146
+ pendingBridgeEntries = [];
147
+ pendingBridgeIndices = [];
148
+ startIndex = -1;
149
+ };
150
+ for (let index = 0; index < sequence.length; index += 1) {
151
+ const item = sequence[index];
152
+ if (!item) {
153
+ continue;
154
+ }
155
+ if (item.kind === "tool-call" && isGroupableToolCall(item.call)) {
156
+ if (avoidGroupingEdits && isEditBoundaryToolCall(item.call)) {
157
+ finalizeGroup();
158
+ continue;
159
+ }
160
+ if (startIndex < 0) {
161
+ startIndex = index;
162
+ }
163
+ if (pendingBridgeEntries.length > 0) {
164
+ currentEntries.push(...pendingBridgeEntries);
165
+ currentIndices.push(...pendingBridgeIndices);
166
+ pendingBridgeEntries = [];
167
+ pendingBridgeIndices = [];
168
+ }
169
+ currentCalls.push(item.call);
170
+ currentEntries.push({ kind: "tool-call", call: item.call });
171
+ currentIndices.push(index);
172
+ continue;
173
+ }
174
+ if (item.kind === "thinking" && startIndex >= 0 && currentCalls.length > 0) {
175
+ pendingBridgeEntries.push({ kind: "thinking", thinking: item.thinking });
176
+ pendingBridgeIndices.push(index);
177
+ continue;
178
+ }
179
+ finalizeGroup();
180
+ }
181
+ finalizeGroup();
182
+ return {
183
+ groups,
184
+ groupedIndices,
185
+ suppressedIndices
186
+ };
187
+ }
188
+ function projectAgentToolGroupRowFromGroup(turnId, group, agentSessionId) {
189
+ const firstCallId = group.calls[0]?.id ?? "unknown";
190
+ return {
191
+ kind: "tool-group",
192
+ id: `tool-group:${turnId}:${group.calls.map((call) => call.id).join("+")}`,
193
+ expansionKey: ["tool-group", agentSessionId, turnId, firstCallId].filter(Boolean).join(":"),
194
+ turnId,
195
+ grouped: true,
196
+ calls: group.calls,
197
+ summary: summarizeToolCallGroup(group.calls),
198
+ entries: group.entries,
199
+ occurredAtUnixMs: group.calls.map((call) => call.occurredAtUnixMs ?? 0).reduce((latest, value) => value > latest ? value : latest, 0) || null
200
+ };
201
+ }
202
+ function projectAgentSingleToolRow(call, turnId = call.turnId) {
203
+ return {
204
+ kind: "tool-group",
205
+ id: `tool-row:${call.id}`,
206
+ expansionKey: `tool-group:${turnId}:${call.id}`,
207
+ turnId,
208
+ grouped: false,
209
+ calls: [call],
210
+ summary: null,
211
+ entries: [{ kind: "tool-call", call }],
212
+ occurredAtUnixMs: call.occurredAtUnixMs
213
+ };
214
+ }
215
+ function isGroupableToolCall(call) {
216
+ switch (call.rendererKind) {
217
+ case "approval":
218
+ case "ask-user":
219
+ case "plan-enter":
220
+ case "plan-exit":
221
+ case "task":
222
+ return false;
223
+ default:
224
+ return true;
225
+ }
226
+ }
227
+ function isEditBoundaryToolCall(call) {
228
+ return call.rendererKind === "edit" || call.rendererKind === "write";
229
+ }
230
+ function summarizeToolCallGroup(calls) {
231
+ if (calls.length < 2) {
232
+ return null;
233
+ }
234
+ const changedTargets = dedupeStrings(
235
+ calls.filter(
236
+ (call) => call.rendererKind === "edit" || call.rendererKind === "write"
237
+ ).map((call) => summarizeCallTarget(call.compactSummary ?? call.summary)).filter((value) => value !== null)
238
+ );
239
+ if (changedTargets.length === 0) {
240
+ return null;
241
+ }
242
+ if (changedTargets.length === 1) {
243
+ return `Changed ${changedTargets[0]}`;
244
+ }
245
+ return `Changed ${changedTargets[0]} and ${changedTargets.length - 1} more files`;
246
+ }
247
+ function summarizeCallTarget(summary) {
248
+ const normalized = summary.trim();
249
+ if (!normalized) {
250
+ return null;
251
+ }
252
+ const firstLine = normalized.split("\n")[0]?.trim() ?? normalized;
253
+ if (!firstLine) {
254
+ return null;
255
+ }
256
+ const segments = firstLine.split(/[\\/]/).filter(Boolean);
257
+ return segments.at(-1) ?? firstLine;
258
+ }
259
+ function dedupeStrings(values) {
260
+ return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
261
+ }
262
+
263
+ // shared/agentConversation/projection/agentToolRendererKind.ts
264
+ function resolveAgentToolRendererKind(call, approval = null, askUserQuestion = null, planMode = null, task = null) {
265
+ const normalizedToolName = normalizeToolName(call.toolName);
266
+ const normalizedCallType = normalizeCallType(call.callType);
267
+ if (approval) {
268
+ return "approval";
269
+ }
270
+ if (askUserQuestion) {
271
+ return "ask-user";
272
+ }
273
+ if (normalizedToolName === "askuserquestion") {
274
+ return "ask-user";
275
+ }
276
+ if (planMode?.kind === "enter") {
277
+ return "plan-enter";
278
+ }
279
+ if (normalizedToolName === "enterplanmode") {
280
+ return "plan-enter";
281
+ }
282
+ if (planMode?.kind === "exit") {
283
+ return "plan-exit";
284
+ }
285
+ if (normalizedToolName === "exitplanmode") {
286
+ return "plan-exit";
287
+ }
288
+ if (normalizedCallType === "approval" || normalizedToolName === "approval") {
289
+ return "approval";
290
+ }
291
+ if (task) {
292
+ return "task";
293
+ }
294
+ if (["task", "subagent", "delegatetask", "delegateagent", "agent"].includes(
295
+ normalizedToolName
296
+ )) {
297
+ return "task";
298
+ }
299
+ if (isImageGenerationToolCall({
300
+ toolName: call.toolName,
301
+ displayName: call.displayName,
302
+ content: call.content,
303
+ outputContent: call.output?.content,
304
+ outputSavedPath: call.output?.savedPath ?? call.output?.saved_path,
305
+ inputPrompt: call.input?.prompt
306
+ })) {
307
+ return "image-generation";
308
+ }
309
+ switch (normalizedToolName) {
310
+ case "read":
311
+ case "readfile":
312
+ return "read";
313
+ case "write":
314
+ case "writefile":
315
+ return "write";
316
+ case "edit":
317
+ case "editfile":
318
+ case "multiedit":
319
+ return "edit";
320
+ case "bash":
321
+ case "shell":
322
+ case "exec":
323
+ case "execcommand":
324
+ return "bash";
325
+ case "grep":
326
+ case "glob":
327
+ case "search":
328
+ case "searchfiles":
329
+ return "search";
330
+ case "websearch":
331
+ return "web-search";
332
+ case "webfetch":
333
+ return "web-fetch";
334
+ case "todowrite":
335
+ return "todo-write";
336
+ case "toolsearch":
337
+ return "tool-search";
338
+ case "skill":
339
+ return "skill";
340
+ default:
341
+ if (normalizedCallType === "mcp" || normalizedToolName.startsWith("mcp") || hasMcpMetadata(call.metadata)) {
342
+ return "mcp";
343
+ }
344
+ return "default";
345
+ }
346
+ }
347
+ function inferToolCallType(toolName) {
348
+ const normalizedToolName = normalizeToolName(toolName);
349
+ if (normalizedToolName === "approval") {
350
+ return "approval";
351
+ }
352
+ if (["askuserquestion", "enterplanmode", "exitplanmode"].includes(
353
+ normalizedToolName
354
+ )) {
355
+ return "interactive";
356
+ }
357
+ if (normalizedToolName.startsWith("mcp")) {
358
+ return "mcp";
359
+ }
360
+ return "tool";
361
+ }
362
+ function isApprovalToolCall(call) {
363
+ return normalizeCallType(call.callType) === "approval" || normalizeToolName(call.toolName) === "approval";
364
+ }
365
+ function normalizeToolName(value) {
366
+ return (value ?? "").replace(/[_\s-]+/g, "").trim().toLowerCase();
367
+ }
368
+ function hasMcpMetadata(metadata) {
369
+ return Boolean(
370
+ stringValue(metadata?.server) ?? stringValue(metadata?.serverName) ?? stringValue(metadata?.mcpServer)
371
+ );
372
+ }
373
+ function normalizeCallType(value) {
374
+ return (value ?? "").trim().toLowerCase();
375
+ }
376
+ function stringValue(value) {
377
+ return typeof value === "string" && value.trim() ? value.trim() : null;
378
+ }
379
+
380
+ // shared/agentConversation/projection/agentTranscriptPresentation.ts
381
+ function resolveAgentTranscriptPresentationKind(notice) {
382
+ if (notice?.command !== "compact") {
383
+ return "content";
384
+ }
385
+ if (notice.commandStatus === "running") {
386
+ return "specific-progress";
387
+ }
388
+ if (notice.commandStatus === "completed" || notice.commandStatus === "failed" || notice.commandStatus === "canceled") {
389
+ return "turn-boundary";
390
+ }
391
+ return "content";
392
+ }
393
+ function agentTranscriptRowHasPresentationKind(row, presentationKind) {
394
+ return Boolean(
395
+ row?.kind === "message" && row.messages.some(
396
+ (message) => message.presentationKind === presentationKind
397
+ )
398
+ );
399
+ }
400
+
401
+ // shared/agentConversation/projection/agentApprovalProjection.ts
402
+ function projectAgentApprovalItem(call, input, output) {
403
+ const callType = normalizeToken(call.callType);
404
+ const toolName = normalizeToken(call.toolName);
405
+ if (callType !== "approval" && toolName !== "approval") {
406
+ return null;
407
+ }
408
+ const requestId = stringValue2(input?.requestId) ?? stringValue2(call.payload?.requestId) ?? stringValue2(output?.requestId);
409
+ if (!requestId) {
410
+ return null;
411
+ }
412
+ const options = normalizeAgentApprovalOptions(
413
+ input?.options ?? call.payload?.options
414
+ );
415
+ if (isExitPlanSwitchModeInput(input)) {
416
+ return null;
417
+ }
418
+ const mcpTarget = extractAgentMcpToolTarget({
419
+ input,
420
+ payload: call.payload,
421
+ toolName: call.toolName,
422
+ name: call.name
423
+ });
424
+ const approvalPurpose = normalizeAgentApprovalPurpose(
425
+ call.payload?.approvalPurpose
426
+ );
427
+ return {
428
+ kind: "approval",
429
+ id: call.id,
430
+ turnId: call.turnId ?? "turn:unknown",
431
+ requestId,
432
+ callId: call.id.replace(/^call:/, ""),
433
+ ...approvalPurpose ? { approvalPurpose } : {},
434
+ title: mcpTarget?.displayName ?? (call.summary.trim() || call.name),
435
+ toolName: call.toolName,
436
+ status: stringValue2(call.payload?.status) ?? call.status,
437
+ input,
438
+ options,
439
+ output,
440
+ occurredAtUnixMs: call.occurredAtUnixMs ?? null
441
+ };
442
+ }
443
+ function normalizeAgentApprovalOptions(value) {
444
+ const values = arrayValue(value) ?? [];
445
+ return values.flatMap((value2) => {
446
+ const option = objectValue(value2);
447
+ const id = stringValue2(option?.optionId) ?? stringValue2(option?.id);
448
+ if (!id) {
449
+ return [];
450
+ }
451
+ const label = stringValue2(option?.name) ?? stringValue2(option?.label) ?? stringValue2(option?.title) ?? stringValue2(option?.kind) ?? id;
452
+ return [
453
+ {
454
+ id,
455
+ label,
456
+ kind: stringValue2(option?.kind) ?? "",
457
+ ...stringValue2(option?.description) ? { description: stringValue2(option?.description) } : {}
458
+ }
459
+ ];
460
+ });
461
+ }
462
+ function normalizeToken(value) {
463
+ return (value ?? "").trim().toLowerCase();
464
+ }
465
+ function stringValue2(value) {
466
+ return typeof value === "string" && value.trim() ? value.trim() : null;
467
+ }
468
+ function objectValue(value) {
469
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
470
+ }
471
+ function arrayValue(value) {
472
+ return Array.isArray(value) ? value : null;
473
+ }
474
+
475
+ // shared/agentConversation/projection/agentInteractiveProjection.ts
476
+ function projectAgentAskUserQuestionItem(call, input, output) {
477
+ if (normalizeToolName2(call.toolName) !== "askuserquestion") {
478
+ return null;
479
+ }
480
+ const questions = normalizeAskUserQuestions(input?.questions);
481
+ if (questions.length === 0) {
482
+ return null;
483
+ }
484
+ const answersByQuestionId = objectValue2(output?.answersByQuestionId) ?? {};
485
+ return {
486
+ kind: "ask-user",
487
+ id: call.id,
488
+ turnId: call.turnId ?? "turn:unknown",
489
+ requestId: stringValue3(input?.requestId) ?? stringValue3(call.payload?.requestId) ?? call.id.replace(/^call:/, ""),
490
+ title: call.name,
491
+ status: call.status,
492
+ questions: questions.map((question) => ({
493
+ ...question,
494
+ answer: answerForQuestion(question.id, answersByQuestionId, output)
495
+ })),
496
+ occurredAtUnixMs: call.occurredAtUnixMs ?? null
497
+ };
498
+ }
499
+ function projectAgentPlanModeItem(call, input) {
500
+ if (isExitPlanSwitchModeInput(input)) {
501
+ return {
502
+ itemKind: "plan-mode",
503
+ id: call.id,
504
+ turnId: call.turnId ?? "turn:unknown",
505
+ requestId: stringValue3(input?.requestId) ?? stringValue3(call.payload?.requestId) ?? call.id.replace(/^call:/, ""),
506
+ kind: "exit",
507
+ title: stringValue3(objectValue2(input?.toolCall)?.title) ?? call.name,
508
+ status: call.status,
509
+ plan: stringValue3(input?.plan) ?? stringValue3(call.payload?.plan) ?? (call.summary.trim() || null),
510
+ filePath: stringValue3(input?.filePath) ?? stringValue3(call.payload?.filePath),
511
+ options: extractExitPlanModeOptions(input),
512
+ ...keepPlanningOption(extractExitPlanKeepPlanningOptionId(input)),
513
+ occurredAtUnixMs: call.occurredAtUnixMs ?? null
514
+ };
515
+ }
516
+ const toolName = normalizeToolName2(call.toolName);
517
+ if (toolName === "enterplanmode") {
518
+ return {
519
+ itemKind: "plan-mode",
520
+ id: call.id,
521
+ turnId: call.turnId ?? "turn:unknown",
522
+ kind: "enter",
523
+ title: call.name,
524
+ status: call.status,
525
+ plan: stringValue3(input?.content) ?? (call.summary.trim() || null),
526
+ filePath: stringValue3(input?.filePath),
527
+ occurredAtUnixMs: call.occurredAtUnixMs ?? null
528
+ };
529
+ }
530
+ if (toolName !== "exitplanmode") {
531
+ return null;
532
+ }
533
+ return {
534
+ itemKind: "plan-mode",
535
+ id: call.id,
536
+ turnId: call.turnId ?? "turn:unknown",
537
+ requestId: stringValue3(input?.requestId) ?? stringValue3(call.payload?.requestId) ?? call.id.replace(/^call:/, ""),
538
+ kind: "exit",
539
+ title: call.name,
540
+ status: call.status,
541
+ plan: stringValue3(input?.plan) ?? stringValue3(call.payload?.plan) ?? (call.summary.trim() || null),
542
+ filePath: stringValue3(input?.filePath) ?? stringValue3(call.payload?.filePath),
543
+ occurredAtUnixMs: call.occurredAtUnixMs ?? null
544
+ };
545
+ }
546
+ function answerForQuestion(questionId, answersByQuestionId, output) {
547
+ const responsePayload = objectValue2(output?.payload);
548
+ const responseAnswersByQuestionId = objectValue2(responsePayload?.answersByQuestionId) ?? {};
549
+ const value = answersByQuestionId[questionId] ?? responseAnswersByQuestionId[questionId];
550
+ if (Array.isArray(value)) {
551
+ return value.flatMap(
552
+ (item) => typeof item === "string" && item.trim() ? [item.trim()] : []
553
+ );
554
+ }
555
+ if (typeof value === "string" && value.trim()) {
556
+ return value.trim();
557
+ }
558
+ const answers = arrayValue2(output?.answers) ?? arrayValue2(responsePayload?.answers);
559
+ return answers && answers.length > 0 ? answers.filter(
560
+ (item) => typeof item === "string" && item.trim().length > 0
561
+ ) : null;
562
+ }
563
+ function keepPlanningOption(optionId) {
564
+ return optionId ? { keepPlanningOptionId: optionId } : {};
565
+ }
566
+ function normalizeToolName2(value) {
567
+ return (value ?? "").replace(/[_\s-]+/g, "").trim().toLowerCase();
568
+ }
569
+ function stringValue3(value) {
570
+ return typeof value === "string" && value.trim() ? value.trim() : null;
571
+ }
572
+ function objectValue2(value) {
573
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
574
+ }
575
+ function arrayValue2(value) {
576
+ return Array.isArray(value) ? value : null;
577
+ }
578
+
579
+ // shared/agentConversation/projection/agentTaskProjection.ts
580
+ function projectAgentTaskItem(call, input, output, metadata) {
581
+ const toolName = normalizeToolName(call.toolName);
582
+ if (!["task", "subagent", "delegatetask", "delegateagent", "agent"].includes(
583
+ toolName
584
+ )) {
585
+ return null;
586
+ }
587
+ const claudeToolResponse = claudeCodeToolResponse(input) ?? claudeCodeToolResponse(output) ?? claudeCodeToolResponse(metadata);
588
+ const steps = normalizeTaskSteps(
589
+ arrayValue3(metadata?.steps) ?? arrayValue3(output?.steps) ?? arrayValue3(call.payload?.steps) ?? [],
590
+ call.turnId ?? "turn:unknown"
591
+ );
592
+ return {
593
+ kind: "task",
594
+ id: call.id,
595
+ turnId: call.turnId ?? "turn:unknown",
596
+ title: call.summary.trim() || call.name,
597
+ status: stringValue4(metadata?.taskStatus) ?? stringValue4(metadata?.subagentStatus) ?? call.status,
598
+ prompt: stringValue4(input?.prompt) ?? stringValue4(input?.description) ?? stringValue4(call.payload?.description) ?? stringValue4(claudeToolResponse?.prompt),
599
+ delegateSessionId: stringValue4(metadata?.childSessionID) ?? stringValue4(metadata?.child_session_id) ?? stringValue4(metadata?.subagentSessionID) ?? stringValue4(metadata?.subagent_session_id) ?? stringValue4(metadata?.subagentAgentId) ?? stringValue4(metadata?.agentId) ?? stringValue4(claudeToolResponse?.agentId),
600
+ steps,
601
+ result: firstNonEmptyText(output),
602
+ resultMarkdown: firstNonEmptyText(output),
603
+ durationMs: numberValue(metadata?.durationMs) ?? numberValue(output?.durationMs) ?? numberValue(claudeToolResponse?.totalDurationMs),
604
+ occurredAtUnixMs: call.occurredAtUnixMs ?? null
605
+ };
606
+ }
607
+ function normalizeTaskSteps(values, turnId) {
608
+ return values.flatMap((value, index) => {
609
+ const step = objectValue3(value);
610
+ if (!step) {
611
+ return [];
612
+ }
613
+ const toolName = stringValue4(step.toolName) ?? stringValue4(step.tool_name) ?? stringValue4(step.name);
614
+ const callType = stringValue4(step.callType) ?? stringValue4(step.call_type);
615
+ if (isApprovalToolCall({ toolName, callType })) {
616
+ return [];
617
+ }
618
+ const inputPayload = objectValue3(step.toolInput) ?? objectValue3(step.tool_input);
619
+ const outputPayload = objectValue3(step.toolResult) ?? objectValue3(step.tool_result);
620
+ const errorPayload = objectValue3(step.toolError) ?? objectValue3(step.tool_error);
621
+ const payload = objectValue3(step.payload);
622
+ const metadata = objectValue3(step.metadata);
623
+ const content = arrayValue3(step.content);
624
+ const locations = arrayValue3(step.locations);
625
+ return [
626
+ {
627
+ id: stringValue4(step.toolUseId) ?? stringValue4(step.id) ?? `step-${index + 1}`,
628
+ turnId,
629
+ name: toolName ? humanizeToolLabel(toolName) : `Step ${index + 1}`,
630
+ toolName: toolName ?? null,
631
+ status: stringValue4(step.status) ?? stringValue4(objectValue3(step.toolResult)?.status) ?? stringValue4(objectValue3(step.tool_result)?.status),
632
+ summary: firstNonEmptyText(outputPayload, inputPayload) ?? "",
633
+ payload: {
634
+ input: inputPayload,
635
+ output: outputPayload,
636
+ error: errorPayload
637
+ },
638
+ tool: projectAgentTaskStepTool({
639
+ id: stringValue4(step.toolUseId) ?? stringValue4(step.id) ?? `step-${index + 1}`,
640
+ turnId,
641
+ toolName,
642
+ name: stringValue4(step.name),
643
+ callType,
644
+ status: stringValue4(step.status) ?? stringValue4(outputPayload?.status),
645
+ summary: firstNonEmptyText(outputPayload, inputPayload) ?? "",
646
+ payload,
647
+ metadata,
648
+ input: inputPayload,
649
+ output: outputPayload,
650
+ error: errorPayload,
651
+ content,
652
+ locations,
653
+ occurredAtUnixMs: numberValue(step.occurredAtUnixMs)
654
+ }),
655
+ occurredAtUnixMs: numberValue(step.occurredAtUnixMs) ?? null
656
+ }
657
+ ];
658
+ });
659
+ }
660
+ function projectAgentTaskStepTool(step) {
661
+ const call = {
662
+ id: `call:${step.id}`,
663
+ turnId: step.turnId,
664
+ name: step.name ?? (step.toolName ? humanizeToolLabel(step.toolName) : "Tool"),
665
+ toolName: step.toolName,
666
+ callType: step.callType ?? inferToolCallType(step.toolName),
667
+ status: step.status,
668
+ statusKind: normalizeTaskStepStatus(step.status),
669
+ summary: step.summary,
670
+ compactSummary: step.summary || null,
671
+ payload: step.payload,
672
+ occurredAtUnixMs: step.occurredAtUnixMs
673
+ };
674
+ const approval = projectAgentApprovalItem(call, step.input, step.output);
675
+ const askUserQuestion = projectAgentAskUserQuestionItem(
676
+ call,
677
+ step.input,
678
+ step.output
679
+ );
680
+ const planMode = projectAgentPlanModeItem(call, step.input);
681
+ const task = projectAgentTaskItem(
682
+ call,
683
+ step.input,
684
+ step.output,
685
+ step.metadata
686
+ );
687
+ const rendererKind = resolveAgentToolRendererKind(
688
+ {
689
+ toolName: call.toolName,
690
+ displayName: call.name,
691
+ callType: call.callType,
692
+ input: step.input,
693
+ output: step.output,
694
+ content: step.content,
695
+ metadata: step.metadata
696
+ },
697
+ approval,
698
+ askUserQuestion,
699
+ planMode,
700
+ task
701
+ );
702
+ return {
703
+ kind: "tool-call",
704
+ ...call,
705
+ turnId: step.turnId,
706
+ compactSummary: call.compactSummary ?? null,
707
+ payload: step.payload,
708
+ toolState: null,
709
+ input: step.input,
710
+ output: step.output,
711
+ error: step.error,
712
+ metadata: step.metadata,
713
+ content: step.content,
714
+ locations: step.locations,
715
+ occurredAtUnixMs: call.occurredAtUnixMs ?? null,
716
+ rendererKind,
717
+ approval,
718
+ planMode,
719
+ askUserQuestion,
720
+ task
721
+ };
722
+ }
723
+ function humanizeToolLabel(value) {
724
+ return value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim().replace(/^\w/, (match) => match.toUpperCase());
725
+ }
726
+ function stringValue4(value) {
727
+ return typeof value === "string" && value.trim() ? value.trim() : null;
728
+ }
729
+ function numberValue(value) {
730
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
731
+ }
732
+ function normalizeTaskStepStatus(value) {
733
+ switch ((value ?? "").trim().toLowerCase()) {
734
+ case "completed":
735
+ case "done":
736
+ case "success":
737
+ case "succeeded":
738
+ return "completed";
739
+ case "failed":
740
+ case "error":
741
+ case "errored":
742
+ return "failed";
743
+ case "waiting":
744
+ case "waiting_input":
745
+ case "waiting_approval":
746
+ return "waiting";
747
+ case "running":
748
+ case "working":
749
+ case "active":
750
+ return "working";
751
+ default:
752
+ return null;
753
+ }
754
+ }
755
+ function objectValue3(value) {
756
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
757
+ }
758
+ function arrayValue3(value) {
759
+ return Array.isArray(value) ? value : null;
760
+ }
761
+ function claudeCodeToolResponse(value) {
762
+ const meta = objectValue3(value?._meta);
763
+ const claudeCode = objectValue3(meta?.claudeCode);
764
+ return objectValue3(claudeCode?.toolResponse);
765
+ }
766
+ function firstNonEmptyText(...values) {
767
+ for (const value of values) {
768
+ const text = extractText(value);
769
+ if (text) {
770
+ return text;
771
+ }
772
+ }
773
+ return null;
774
+ }
775
+ function extractText(value, depth = 0) {
776
+ if (depth > 4) {
777
+ return null;
778
+ }
779
+ if (typeof value === "string" && value.trim()) {
780
+ return value.trim();
781
+ }
782
+ if (Array.isArray(value)) {
783
+ for (const item of value) {
784
+ const text = extractText(item, depth + 1);
785
+ if (text) {
786
+ return text;
787
+ }
788
+ }
789
+ return null;
790
+ }
791
+ if (value && typeof value === "object") {
792
+ const record = value;
793
+ for (const key of [
794
+ "text",
795
+ "output",
796
+ "summary",
797
+ "message",
798
+ "patch",
799
+ "result"
800
+ ]) {
801
+ const text = extractText(record[key], depth + 1);
802
+ if (text) {
803
+ return text;
804
+ }
805
+ }
806
+ return extractText(record.content, depth + 1);
807
+ }
808
+ return null;
809
+ }
810
+
811
+ // shared/agentConversation/projection/agentToolProjection.ts
812
+ function projectAgentToolCall(call) {
813
+ const toolState = objectValue4(call.payload?.tool_state);
814
+ const input = normalizeStandardACPEnvelope(
815
+ objectValue4(call.payload?.input) ?? objectValue4(toolState?.input)
816
+ );
817
+ const output = normalizeStandardACPEnvelope(
818
+ objectValue4(call.payload?.output) ?? objectValue4(toolState?.output)
819
+ );
820
+ const error = normalizeStandardACPEnvelope(
821
+ objectValue4(call.payload?.error) ?? objectValue4(toolState?.error)
822
+ );
823
+ const metadata = objectValue4(call.payload?.metadata);
824
+ const content = arrayValue4(call.payload?.content);
825
+ const locations = arrayValue4(call.payload?.locations);
826
+ const approval = projectAgentApprovalItem(call, input, output);
827
+ const askUserQuestion = projectAgentAskUserQuestionItem(call, input, output);
828
+ const planMode = projectAgentPlanModeItem(call, input);
829
+ const task = projectAgentTaskItem(call, input, output, metadata);
830
+ const mcpTarget = extractAgentMcpToolTarget({
831
+ input,
832
+ metadata,
833
+ payload: call.payload,
834
+ toolName: call.toolName,
835
+ name: call.name
836
+ });
837
+ const rendererKind = resolveAgentToolRendererKind(
838
+ {
839
+ toolName: call.toolName,
840
+ displayName: call.name,
841
+ callType: call.callType,
842
+ input,
843
+ output,
844
+ content,
845
+ metadata
846
+ },
847
+ approval,
848
+ askUserQuestion,
849
+ planMode,
850
+ task
851
+ );
852
+ const projectedCall = {
853
+ kind: "tool-call",
854
+ ...call,
855
+ turnId: call.turnId ?? "turn:unknown",
856
+ name: mcpTarget?.displayName ?? call.name,
857
+ compactSummary: call.compactSummary ?? call.summary,
858
+ payload: call.payload ?? null,
859
+ toolState,
860
+ input,
861
+ output,
862
+ error,
863
+ metadata,
864
+ content,
865
+ locations,
866
+ rendererKind,
867
+ approval,
868
+ askUserQuestion,
869
+ planMode,
870
+ task,
871
+ occurredAtUnixMs: call.occurredAtUnixMs ?? null
872
+ };
873
+ if (call.sourceTimelineItems) {
874
+ projectedCall.sourceTimelineItems = call.sourceTimelineItems;
875
+ }
876
+ return projectedCall;
877
+ }
878
+ function objectValue4(value) {
879
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
880
+ }
881
+ function arrayValue4(value) {
882
+ return Array.isArray(value) ? value : null;
883
+ }
884
+ function normalizeStandardACPEnvelope(value) {
885
+ if (!value) return null;
886
+ const raw = objectValue4(value.rawInput) ?? objectValue4(value.rawOutput);
887
+ if (!raw) return value;
888
+ const metadata = objectValue4(raw.metadata);
889
+ return {
890
+ ...value,
891
+ ...raw,
892
+ ...metadata?.diff !== void 0 ? { diff: metadata.diff } : {},
893
+ ...metadata?.files !== void 0 ? { files: metadata.files } : {},
894
+ ...metadata?.structuredPatch !== void 0 ? { structuredPatch: metadata.structuredPatch } : {},
895
+ ...metadata?.detailedContent !== void 0 ? { detailedContent: metadata.detailedContent } : {},
896
+ ...metadata?.changes !== void 0 ? { changes: metadata.changes } : {},
897
+ ...metadata?.exit !== void 0 ? { exitCode: metadata.exit } : {}
898
+ };
899
+ }
900
+
901
+ // shared/agentConversation/projection/agentCollaborationProjection.ts
902
+ var COLLABORATION_TIMELINE_ITEM_TYPE = "collaboration";
903
+ function isCollaborationTimelineItem(item) {
904
+ return item.itemType.trim().toLowerCase() === COLLABORATION_TIMELINE_ITEM_TYPE;
905
+ }
906
+ function projectAgentCollaborationVM(item) {
907
+ const payload = normalizedPayload(item.payload);
908
+ if (!payload) {
909
+ return null;
910
+ }
911
+ const runId = stringField(payload, "runId");
912
+ const mode = stringField(payload, "mode");
913
+ if (!runId || !mode) {
914
+ return null;
915
+ }
916
+ const status = stringField(payload, "status") ?? item.status?.trim() ?? "running";
917
+ return {
918
+ kind: "collaboration",
919
+ runId,
920
+ workspaceId: item.workspaceId?.trim() || null,
921
+ agentSessionId: item.agentSessionId.trim() || null,
922
+ mode,
923
+ status,
924
+ triggerSource: stringField(payload, "triggerSource") ?? "user",
925
+ triggerReason: stringField(payload, "triggerReason"),
926
+ targetSessionId: stringField(payload, "targetSessionId"),
927
+ targetAgentTargetId: stringField(payload, "targetAgentTargetId"),
928
+ modelPlanId: stringField(payload, "modelPlanId"),
929
+ modelPlanName: stringField(payload, "modelPlanName") ?? stringField(payload, "planName"),
930
+ model: stringField(payload, "model"),
931
+ contextScope: stringField(payload, "contextScope"),
932
+ resultText: stringField(payload, "resultText"),
933
+ failureReason: stringField(payload, "failureReason"),
934
+ durationMs: positiveNumberField(payload, "durationMs"),
935
+ usage: usageField(payload),
936
+ adoption: stringField(payload, "adoption") ?? "not_applicable"
937
+ };
938
+ }
939
+ function usageField(payload) {
940
+ const usage = normalizedPayload(
941
+ payload.usage
942
+ );
943
+ if (!usage) {
944
+ return null;
945
+ }
946
+ const inputTokens = nonNegativeNumberValue(usage.inputTokens);
947
+ const outputTokens = nonNegativeNumberValue(usage.outputTokens);
948
+ if (inputTokens === null && outputTokens === null) {
949
+ return null;
950
+ }
951
+ return {
952
+ inputTokens: inputTokens ?? 0,
953
+ outputTokens: outputTokens ?? 0
954
+ };
955
+ }
956
+ function normalizedPayload(payload) {
957
+ return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : null;
958
+ }
959
+ function stringField(payload, key) {
960
+ const value = payload[key];
961
+ return typeof value === "string" && value.trim() ? value.trim() : null;
962
+ }
963
+ function positiveNumberField(payload, key) {
964
+ const value = nonNegativeNumberValue(payload[key]);
965
+ return value !== null && value > 0 ? value : null;
966
+ }
967
+ function nonNegativeNumberValue(value) {
968
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
969
+ }
970
+
971
+ // shared/pastedTextReferenceProjection.ts
972
+ import { createRichTextMentionMarkdown } from "@tutti-os/ui-rich-text/core";
973
+ var PASTED_TEXT_ARCHIVE_PATH_RE = /(?:\/|[A-Za-z]:\\)[^\n]*?agent-prompt-assets[^\n]*?\.txt/;
974
+ function pastedTextDraftDisplayName(index) {
975
+ return `pasted-text-${index + 1}.txt`;
976
+ }
977
+ function linkifyPastedTextReferences(text) {
978
+ if (!PASTED_TEXT_ARCHIVE_PATH_RE.test(text)) {
979
+ return text;
980
+ }
981
+ const lines = text.split("\n");
982
+ const out = [];
983
+ let refIndex = 0;
984
+ for (let index = 0; index < lines.length; index++) {
985
+ const line = lines[index] ?? "";
986
+ const path = firstPastedTextArchivePath(line);
987
+ if (path) {
988
+ out.push(
989
+ pastedTextReferenceMentionMarkdown(
990
+ firstQuotedPreview(line),
991
+ path,
992
+ refIndex
993
+ )
994
+ );
995
+ refIndex += 1;
996
+ continue;
997
+ }
998
+ const next = lines[index + 1];
999
+ if (next != null && firstPastedTextArchivePath(next)) {
1000
+ continue;
1001
+ }
1002
+ out.push(line);
1003
+ }
1004
+ return out.join("\n").trim();
1005
+ }
1006
+ function firstPastedTextArchivePath(line) {
1007
+ return line.match(PASTED_TEXT_ARCHIVE_PATH_RE)?.[0].trim() ?? null;
1008
+ }
1009
+ function pastedTextReferenceMentionMarkdown(preview, path, index) {
1010
+ return createRichTextMentionMarkdown({
1011
+ providerId: AGENT_PASTED_TEXT_MENTION_KIND,
1012
+ entityId: `ref-${index}`,
1013
+ label: preview.trim() || pastedTextDraftDisplayName(index),
1014
+ scope: { path }
1015
+ });
1016
+ }
1017
+ function firstQuotedPreview(line) {
1018
+ return line.match(/"([^"]*)"/)?.[1]?.trim() ?? "";
1019
+ }
1020
+
1021
+ // shared/agentConversation/projection/agentConversationUserProjection.ts
1022
+ function projectConversationUserRow(message, fallbackTurnId, workspaceId) {
1023
+ const turnId = message.turnId ?? fallbackTurnId;
1024
+ return {
1025
+ kind: "message",
1026
+ id: `message:user:${message.id}`,
1027
+ turnId,
1028
+ speaker: "user",
1029
+ messages: projectUserMessageContentParts(message, turnId, workspaceId),
1030
+ thinking: [],
1031
+ occurredAtUnixMs: message.occurredAtUnixMs ?? null
1032
+ };
1033
+ }
1034
+ function projectUserMessageContentParts(message, turnId, workspaceId) {
1035
+ const blocks = userPromptContentBlocks(message, workspaceId);
1036
+ if (blocks.length === 0) {
1037
+ return [textPart(message, turnId)];
1038
+ }
1039
+ const parts = [];
1040
+ const imageBlocks = blocks.filter(
1041
+ (block) => block.type === "image"
1042
+ );
1043
+ if (imageBlocks.length > 0) {
1044
+ parts.push({
1045
+ kind: "message-content",
1046
+ id: `${message.id}:images:0`,
1047
+ turnId,
1048
+ body: "",
1049
+ presentationKind: "content",
1050
+ contentKind: "image-grid",
1051
+ images: imageBlocks.map((image, index) => ({
1052
+ id: `${message.id}:image:${index}`,
1053
+ workspaceId: image.workspaceId,
1054
+ agentSessionId: image.agentSessionId,
1055
+ attachmentId: image.attachmentId,
1056
+ mimeType: image.mimeType,
1057
+ name: image.name,
1058
+ data: image.data,
1059
+ url: image.url,
1060
+ path: image.path
1061
+ })),
1062
+ occurredAtUnixMs: message.occurredAtUnixMs ?? null,
1063
+ sourceTimelineItems: message.sourceTimelineItems
1064
+ });
1065
+ }
1066
+ blocks.forEach((block, index) => {
1067
+ if (block.type === "image" || block.text.trim() === "") return;
1068
+ parts.push({
1069
+ kind: "message-content",
1070
+ id: `${message.id}:text:${index}`,
1071
+ turnId,
1072
+ body: block.text,
1073
+ presentationKind: "content",
1074
+ contentKind: "text",
1075
+ occurredAtUnixMs: message.occurredAtUnixMs ?? null,
1076
+ sourceTimelineItems: message.sourceTimelineItems
1077
+ });
1078
+ });
1079
+ return parts.length > 0 ? parts : [textPart(message, turnId)];
1080
+ }
1081
+ function textPart(message, turnId) {
1082
+ return {
1083
+ kind: "message-content",
1084
+ id: message.id,
1085
+ turnId,
1086
+ body: message.body,
1087
+ presentationKind: "content",
1088
+ contentKind: "text",
1089
+ occurredAtUnixMs: message.occurredAtUnixMs ?? null,
1090
+ sourceTimelineItems: message.sourceTimelineItems
1091
+ };
1092
+ }
1093
+ function userPromptContentBlocks(message, fallbackWorkspaceId) {
1094
+ const item = message.sourceTimelineItems?.find(
1095
+ (candidate) => Array.isArray(candidate.payload?.content)
1096
+ );
1097
+ const content = Array.isArray(item?.payload?.content) ? item.payload.content : null;
1098
+ if (!content) return [];
1099
+ const displayPrompt = firstString(
1100
+ message.sourceTimelineItems?.map(
1101
+ (candidate) => typeof candidate.payload?.displayPrompt === "string" ? candidate.payload.displayPrompt : ""
1102
+ ) ?? []
1103
+ );
1104
+ const visibleDisplayPrompt = isSyntheticImageOnlyDisplayPrompt(
1105
+ displayPrompt,
1106
+ content
1107
+ ) ? "" : displayPrompt;
1108
+ const blocks = content.flatMap((raw) => {
1109
+ const block = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
1110
+ if (!block) return [];
1111
+ if (block.type === "text" && typeof block.text === "string") {
1112
+ return visibleDisplayPrompt ? [] : [{ type: "text", text: linkifyPastedTextReferences(block.text) }];
1113
+ }
1114
+ if (block.type !== "image") return [];
1115
+ const mimeType = typeof block.mimeType === "string" ? block.mimeType.trim() : "";
1116
+ if (!mimeType) return [];
1117
+ return [
1118
+ {
1119
+ type: "image",
1120
+ workspaceId: item?.workspaceId ?? fallbackWorkspaceId ?? null,
1121
+ agentSessionId: item?.agentSessionId ?? message.id,
1122
+ attachmentId: optionalString(block.attachmentId),
1123
+ mimeType,
1124
+ name: optionalString(block.name),
1125
+ data: optionalString(block.data),
1126
+ url: optionalString(block.url),
1127
+ path: optionalString(block.path)
1128
+ }
1129
+ ];
1130
+ });
1131
+ return visibleDisplayPrompt ? [{ type: "text", text: visibleDisplayPrompt }, ...blocks] : blocks;
1132
+ }
1133
+ function isSyntheticImageOnlyDisplayPrompt(displayPrompt, content) {
1134
+ if (displayPrompt !== "[Image]" && displayPrompt !== "[Images]") {
1135
+ return false;
1136
+ }
1137
+ let imageCount = 0;
1138
+ for (const raw of content) {
1139
+ const block = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
1140
+ if (!block) continue;
1141
+ if (block.type === "text" && typeof block.text === "string" && block.text.trim()) {
1142
+ return false;
1143
+ }
1144
+ if (block.type === "image") {
1145
+ imageCount += 1;
1146
+ }
1147
+ }
1148
+ return displayPrompt === "[Image]" ? imageCount === 1 : imageCount > 1;
1149
+ }
1150
+ function optionalString(value) {
1151
+ return typeof value === "string" && value.trim() ? value.trim() : null;
1152
+ }
1153
+ function firstString(values) {
1154
+ for (const value of values) {
1155
+ const trimmed = value.trim();
1156
+ if (trimmed) return trimmed;
1157
+ }
1158
+ return "";
1159
+ }
1160
+
1161
+ // shared/agentConversation/projection/agentTurnSequenceProjection.ts
1162
+ function buildAgentTurnSequenceItems(turn, workspaceId) {
1163
+ const items = turn.rawAgentItems ?? turn.agentItems;
1164
+ const sequence = turn.userMessages.map(
1165
+ (message) => ({
1166
+ kind: "user-message",
1167
+ row: projectConversationUserRow(message, turn.id, workspaceId)
1168
+ })
1169
+ );
1170
+ items.forEach((item) => {
1171
+ if (item.kind === "message") {
1172
+ sequence.push({
1173
+ kind: "assistant-message",
1174
+ message: projectMessage(item.message, turn.id)
1175
+ });
1176
+ return;
1177
+ }
1178
+ if (item.kind === "thinking") {
1179
+ sequence.push({
1180
+ kind: "thinking",
1181
+ thinking: projectThinking(item.thinking, turn.id)
1182
+ });
1183
+ return;
1184
+ }
1185
+ const sourceEntries = item.groupEntries ?? item.toolCalls.map((call) => ({ kind: "tool-call", call }));
1186
+ sourceEntries.forEach((entry) => {
1187
+ if (entry.kind === "thinking") {
1188
+ sequence.push({
1189
+ kind: "thinking",
1190
+ thinking: projectThinking(entry.thinking, turn.id)
1191
+ });
1192
+ return;
1193
+ }
1194
+ if (isApprovalToolCall(entry.call)) {
1195
+ return;
1196
+ }
1197
+ sequence.push({
1198
+ kind: "tool-call",
1199
+ call: projectAgentToolCall(entry.call)
1200
+ });
1201
+ });
1202
+ });
1203
+ return sortTurnSequenceItems(sequence);
1204
+ }
1205
+ function sortTurnSequenceItems(sequence) {
1206
+ const positioned = sequence.map((item, sourceIndex) => ({
1207
+ item,
1208
+ sourceIndex,
1209
+ position: turnSequencePosition(item)
1210
+ }));
1211
+ if (positioned.every((entry) => entry.position.seq > 0)) {
1212
+ return positioned.sort(
1213
+ (left, right) => left.position.seq - right.position.seq || left.sourceIndex - right.sourceIndex
1214
+ ).map((entry) => entry.item);
1215
+ }
1216
+ if (positioned.every((entry) => entry.position.occurredAtUnixMs > 0)) {
1217
+ return positioned.sort(
1218
+ (left, right) => left.position.occurredAtUnixMs - right.position.occurredAtUnixMs || left.sourceIndex - right.sourceIndex
1219
+ ).map((entry) => entry.item);
1220
+ }
1221
+ return [...sequence];
1222
+ }
1223
+ function turnSequencePosition(item) {
1224
+ const sourceItems = turnSequenceSourceItems(item);
1225
+ const seq = minimumPositive(
1226
+ sourceItems.map((sourceItem) => sourceItem.seq ?? 0)
1227
+ );
1228
+ const occurredAtUnixMs = minimumPositive(
1229
+ sourceItems.map(
1230
+ (sourceItem) => sourceItem.occurredAtUnixMs ?? sourceItem.createdAtUnixMs ?? 0
1231
+ )
1232
+ );
1233
+ if (occurredAtUnixMs > 0) {
1234
+ return { seq, occurredAtUnixMs };
1235
+ }
1236
+ switch (item.kind) {
1237
+ case "user-message":
1238
+ return { seq, occurredAtUnixMs: item.row.occurredAtUnixMs ?? 0 };
1239
+ case "assistant-message":
1240
+ return { seq, occurredAtUnixMs: item.message.occurredAtUnixMs ?? 0 };
1241
+ case "thinking":
1242
+ return { seq, occurredAtUnixMs: item.thinking.occurredAtUnixMs ?? 0 };
1243
+ case "tool-call":
1244
+ return { seq, occurredAtUnixMs: item.call.occurredAtUnixMs ?? 0 };
1245
+ }
1246
+ }
1247
+ function turnSequenceSourceItems(item) {
1248
+ switch (item.kind) {
1249
+ case "user-message":
1250
+ return item.row.messages.flatMap(
1251
+ (message) => message.sourceTimelineItems ?? []
1252
+ );
1253
+ case "assistant-message":
1254
+ return item.message.sourceTimelineItems ?? [];
1255
+ case "thinking":
1256
+ return item.thinking.sourceTimelineItems ?? [];
1257
+ case "tool-call":
1258
+ return item.call.sourceTimelineItems ?? [];
1259
+ }
1260
+ }
1261
+ function minimumPositive(values) {
1262
+ return values.reduce(
1263
+ (minimum, value) => value > 0 && (minimum === 0 || value < minimum) ? value : minimum,
1264
+ 0
1265
+ );
1266
+ }
1267
+ function projectMessage(message, turnId) {
1268
+ const projected = {
1269
+ kind: "message-content",
1270
+ id: message.id,
1271
+ turnId: message.turnId ?? turnId,
1272
+ body: message.body,
1273
+ presentationKind: resolveAgentTranscriptPresentationKind(
1274
+ message.systemNotice ?? null
1275
+ ),
1276
+ statusKind: message.statusKind ?? null,
1277
+ occurredAtUnixMs: message.occurredAtUnixMs ?? null,
1278
+ visibleError: message.visibleError ?? null,
1279
+ systemNotice: message.systemNotice ?? null
1280
+ };
1281
+ if (message.sourceTimelineItems) {
1282
+ projected.sourceTimelineItems = message.sourceTimelineItems;
1283
+ if (message.sourceTimelineItems.some(
1284
+ (item) => item.payload?.messageKind === "plan"
1285
+ )) {
1286
+ projected.contentKind = "plan";
1287
+ }
1288
+ const collaborationItem = message.sourceTimelineItems.find(
1289
+ isCollaborationTimelineItem
1290
+ );
1291
+ if (collaborationItem) {
1292
+ const collaboration = projectAgentCollaborationVM(collaborationItem);
1293
+ if (collaboration) {
1294
+ projected.contentKind = "collaboration";
1295
+ projected.collaboration = collaboration;
1296
+ }
1297
+ }
1298
+ }
1299
+ return projected;
1300
+ }
1301
+ function projectThinking(thinking, turnId) {
1302
+ const projected = {
1303
+ kind: "thinking-content",
1304
+ id: thinking.id,
1305
+ turnId: thinking.turnId ?? turnId,
1306
+ body: thinking.body,
1307
+ statusKind: thinking.statusKind ?? null,
1308
+ occurredAtUnixMs: thinking.occurredAtUnixMs ?? null
1309
+ };
1310
+ if (thinking.sourceTimelineItems) {
1311
+ projected.sourceTimelineItems = thinking.sourceTimelineItems;
1312
+ }
1313
+ return projected;
1314
+ }
1315
+
1316
+ // shared/agentConversation/projection/chunkBy.ts
1317
+ function chunkBy(items, sameRun) {
1318
+ const runs = [];
1319
+ for (const item of items) {
1320
+ const current = runs.at(-1);
1321
+ if (current && sameRun(current.at(-1), item)) {
1322
+ current.push(item);
1323
+ continue;
1324
+ }
1325
+ runs.push([item]);
1326
+ }
1327
+ return runs;
1328
+ }
1329
+
1330
+ // shared/agentConversation/projection/agentTurnRowProjection.ts
1331
+ function thinkingAbsorbedByMessage(previous, current) {
1332
+ return previous.tag === "thinking" && current.tag === "message";
1333
+ }
1334
+ function toRenderUnits(sequence, groups, skippedIndices) {
1335
+ const units = [];
1336
+ for (let index = 0; index < sequence.length; index += 1) {
1337
+ const group = groups.get(index);
1338
+ if (group) {
1339
+ units.push({ tag: "tool-group", group });
1340
+ index = group.endIndex;
1341
+ continue;
1342
+ }
1343
+ if (skippedIndices.has(index)) {
1344
+ continue;
1345
+ }
1346
+ const item = sequence[index];
1347
+ if (!item) {
1348
+ continue;
1349
+ }
1350
+ switch (item.kind) {
1351
+ case "user-message":
1352
+ units.push({ tag: "user-message", row: item.row });
1353
+ break;
1354
+ case "assistant-message":
1355
+ units.push({ tag: "message", message: item.message });
1356
+ break;
1357
+ case "thinking":
1358
+ units.push({ tag: "thinking", thinking: item.thinking });
1359
+ break;
1360
+ case "tool-call":
1361
+ units.push({ tag: "tool", call: item.call });
1362
+ break;
1363
+ }
1364
+ }
1365
+ return units;
1366
+ }
1367
+ function renderRun(run, turnId, agentSessionId) {
1368
+ const last = run.at(-1);
1369
+ if (!last) {
1370
+ throw new Error("renderRun received an empty run");
1371
+ }
1372
+ if (last.tag === "tool-group") {
1373
+ return projectAgentToolGroupRowFromGroup(
1374
+ turnId,
1375
+ last.group,
1376
+ agentSessionId
1377
+ );
1378
+ }
1379
+ if (last.tag === "tool") {
1380
+ return projectAgentSingleToolRow(last.call, turnId);
1381
+ }
1382
+ if (last.tag === "user-message") {
1383
+ return last.row;
1384
+ }
1385
+ const thinking = run.filter(
1386
+ (unit) => unit.tag === "thinking"
1387
+ ).map((unit) => unit.thinking);
1388
+ if (last.tag === "message") {
1389
+ return {
1390
+ kind: "message",
1391
+ id: `message:assistant:${last.message.id}`,
1392
+ turnId: last.message.turnId,
1393
+ speaker: "assistant",
1394
+ messages: [last.message],
1395
+ thinking,
1396
+ occurredAtUnixMs: last.message.occurredAtUnixMs
1397
+ };
1398
+ }
1399
+ return {
1400
+ kind: "message",
1401
+ id: `message:thinking:${turnId}:${thinking.map((entry) => entry.id).join("+")}`,
1402
+ turnId,
1403
+ speaker: "assistant",
1404
+ messages: [],
1405
+ thinking,
1406
+ occurredAtUnixMs: thinking.at(-1)?.occurredAtUnixMs ?? thinking[0]?.occurredAtUnixMs ?? null
1407
+ };
1408
+ }
1409
+ function projectTurnRows(sequence, groups, skippedIndices, turnId, agentSessionId) {
1410
+ const units = toRenderUnits(sequence, groups, skippedIndices);
1411
+ return chunkBy(units, thinkingAbsorbedByMessage).map(
1412
+ (run) => renderRun(run, turnId, agentSessionId)
1413
+ );
1414
+ }
1415
+
1416
+ // shared/agentConversation/projection/agentProcessingProjection.ts
1417
+ function projectAgentProcessingRow(detail, rows) {
1418
+ if (!detail.showProcessingIndicator) {
1419
+ return null;
1420
+ }
1421
+ const activeTurnId = detail.session.activeTurnId;
1422
+ const canonicalTurn = detail.sessionTurns?.find(
1423
+ (turn) => turn.turnId === activeTurnId
1424
+ );
1425
+ if (canonicalTurn && canonicalTurn.phase !== "settled" && Number.isFinite(canonicalTurn.startedAtUnixMs)) {
1426
+ if (activeTurnId && hasTurnTimingHostRow(rows, activeTurnId)) {
1427
+ return null;
1428
+ }
1429
+ return processingRow(detail, activeTurnId);
1430
+ }
1431
+ const fallbackTurnId = activeTurnId ?? detail.turns.at(-1)?.id ?? null;
1432
+ if (fallbackTurnId && hasSpecificProgressRow(rows, fallbackTurnId)) {
1433
+ return null;
1434
+ }
1435
+ return processingRow(detail, fallbackTurnId);
1436
+ }
1437
+ function processingRow(detail, turnId) {
1438
+ return {
1439
+ kind: "processing",
1440
+ id: `processing:${turnId ?? "session"}`,
1441
+ turnId,
1442
+ occurredAtUnixMs: detail.session.updatedAtUnixMs ?? detail.session.createdAtUnixMs ?? null
1443
+ };
1444
+ }
1445
+ function hasTurnTimingHostRow(rows, activeTurnId) {
1446
+ return rows.some((row) => row.turnId === activeTurnId);
1447
+ }
1448
+ function hasSpecificProgressRow(rows, activeTurnId) {
1449
+ return rows.some((row) => {
1450
+ if (row.turnId !== activeTurnId) {
1451
+ return false;
1452
+ }
1453
+ return agentTranscriptRowHasPresentationKind(row, "specific-progress") || row.kind === "tool-group" && row.calls.some(
1454
+ (call) => call.statusKind === "working" || call.statusKind === "waiting"
1455
+ );
1456
+ });
1457
+ }
1458
+
1459
+ // shared/agentConversation/rules/agentPatchMetadata.ts
1460
+ function normalizeAgentPatchText(text) {
1461
+ if (!text) {
1462
+ return text;
1463
+ }
1464
+ const contentField = tryExtractContentField(text);
1465
+ if (contentField) {
1466
+ return normalizeAgentPatchText(contentField);
1467
+ }
1468
+ const expanded = !text.includes("\n") && text.includes("\\n") ? text.replace(/\\n/g, "\n") : text;
1469
+ return expanded.replace(/\r\n/g, "\n").split("\n").map(
1470
+ (line) => line.trimStart() === "\" ? "\" : line
1471
+ ).join("\n");
1472
+ }
1473
+ function extractAgentPatchPath(patchText) {
1474
+ const normalized = normalizeAgentPatchText(patchText ?? "");
1475
+ if (!normalized.trim()) {
1476
+ return null;
1477
+ }
1478
+ const applyPatchPath = extractApplyPatchPath(normalized);
1479
+ if (applyPatchPath) {
1480
+ return applyPatchPath;
1481
+ }
1482
+ const changeType = inferAgentPatchChangeType(normalized);
1483
+ const gitHeader = normalized.match(/^diff --git a\/(.+?) b\/(.+)$/m);
1484
+ const oldPath = gitHeader?.[1]?.trim() ?? null;
1485
+ const newPath = gitHeader?.[2]?.trim() ?? null;
1486
+ if (oldPath || newPath) {
1487
+ return changeType === "deleted" ? nonNullPath(oldPath) ?? nonNullPath(newPath) : nonNullPath(newPath) ?? nonNullPath(oldPath);
1488
+ }
1489
+ if (changeType === "deleted") {
1490
+ return extractOldHeaderPath(normalized);
1491
+ }
1492
+ return extractNewHeaderPath(normalized);
1493
+ }
1494
+ function inferAgentPatchChangeType(patchText) {
1495
+ const normalized = normalizeAgentPatchText(patchText ?? "").trim();
1496
+ if (!normalized) {
1497
+ return "modified";
1498
+ }
1499
+ if (/^(\*\*\* Delete File:|deleted file mode\b|\+\+\+ \/dev\/null$)/m.test(
1500
+ normalized
1501
+ )) {
1502
+ return "deleted";
1503
+ }
1504
+ if (/^(\*\*\* Add File:|new file mode\b|--- \/dev\/null$)/m.test(normalized)) {
1505
+ return "created";
1506
+ }
1507
+ return "modified";
1508
+ }
1509
+ function extractApplyPatchPath(text) {
1510
+ const match = text.match(/^\*\*\* (?:Add|Delete|Update) File:\s+(.+?)\s*$/m);
1511
+ return match?.[1]?.trim() || null;
1512
+ }
1513
+ function extractOldHeaderPath(text) {
1514
+ const match = text.match(/^---\s+(?:a\/)?([^\n]+)$/m);
1515
+ return nonNullPath(match?.[1]?.trim() ?? null);
1516
+ }
1517
+ function extractNewHeaderPath(text) {
1518
+ const match = text.match(/^\+\+\+\s+(?:b\/)?([^\n]+)$/m);
1519
+ return nonNullPath(match?.[1]?.trim() ?? null);
1520
+ }
1521
+ function nonNullPath(path) {
1522
+ if (!path || path === "/dev/null" || path === "dev/null") {
1523
+ return null;
1524
+ }
1525
+ return path;
1526
+ }
1527
+ function tryExtractContentField(text) {
1528
+ const trimmed = text.trim();
1529
+ if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
1530
+ return null;
1531
+ }
1532
+ try {
1533
+ const parsed = JSON.parse(trimmed);
1534
+ if (parsed && typeof parsed === "object" && typeof parsed.content === "string") {
1535
+ return parsed.content;
1536
+ }
1537
+ return null;
1538
+ } catch {
1539
+ return null;
1540
+ }
1541
+ }
1542
+
1543
+ // shared/agentConversation/projection/agentTurnSummaryFileProjection.ts
1544
+ function normalizedFilePath(value, options = {}) {
1545
+ const path = value?.trim() ?? "";
1546
+ if (!path || isStructuredPayloadPath(path) || isIgnoredFilePath(path)) {
1547
+ return null;
1548
+ }
1549
+ return resolveWorkspaceFilePathCandidate({
1550
+ path,
1551
+ workspaceRoot: options.workspaceRoot,
1552
+ basePath: options.defaultCwd
1553
+ }) ? path : null;
1554
+ }
1555
+ function isIgnoredFilePath(path) {
1556
+ const normalizedPath = path.replace(/\\/g, "/").replace(/\/+$/, "");
1557
+ return normalizedPath === "/dev/null" || normalizedPath === "NUL";
1558
+ }
1559
+ function isStructuredPayloadPath(path) {
1560
+ if (/[\r\n]/.test(path)) {
1561
+ return true;
1562
+ }
1563
+ if (!path.startsWith("{") && !path.startsWith("[")) {
1564
+ return false;
1565
+ }
1566
+ try {
1567
+ JSON.parse(path);
1568
+ return true;
1569
+ } catch {
1570
+ return false;
1571
+ }
1572
+ }
1573
+ function applyShortestUniqueFileLabels(files) {
1574
+ const suffixByPath = shortestUniquePathSuffixByPath(
1575
+ files.map((file) => file.path)
1576
+ );
1577
+ return files.map((file) => ({
1578
+ ...file,
1579
+ label: suffixByPath.get(file.path) ?? file.label
1580
+ }));
1581
+ }
1582
+ function shortestUniquePathSuffixByPath(paths) {
1583
+ const partsByPath = new Map(
1584
+ paths.map((path) => [path, splitPathSegments(path)])
1585
+ );
1586
+ const labels = /* @__PURE__ */ new Map();
1587
+ const unresolved = new Set(paths);
1588
+ for (let depth = 1; unresolved.size > 0; depth += 1) {
1589
+ const grouped = /* @__PURE__ */ new Map();
1590
+ for (const path of unresolved) {
1591
+ const parts = partsByPath.get(path) ?? [];
1592
+ const label = parts.slice(-Math.min(depth, parts.length)).join("/") || parts.at(-1) || path;
1593
+ grouped.set(label, [...grouped.get(label) ?? [], path]);
1594
+ }
1595
+ let resolvedCount = 0;
1596
+ for (const [label, group] of grouped) {
1597
+ if (group.length !== 1 || !group[0]) {
1598
+ continue;
1599
+ }
1600
+ labels.set(group[0], label);
1601
+ unresolved.delete(group[0]);
1602
+ resolvedCount += 1;
1603
+ }
1604
+ if (resolvedCount === 0) {
1605
+ for (const path of unresolved) {
1606
+ labels.set(path, path);
1607
+ }
1608
+ break;
1609
+ }
1610
+ }
1611
+ return labels;
1612
+ }
1613
+ function splitFilePath(path) {
1614
+ const normalized = path.trim();
1615
+ const parts = splitPathSegments(normalized);
1616
+ if (parts.length <= 1) {
1617
+ return { fileName: parts[0] ?? normalized, directory: null };
1618
+ }
1619
+ return {
1620
+ fileName: parts.at(-1) ?? normalized,
1621
+ directory: parts.slice(0, -1).join("/")
1622
+ };
1623
+ }
1624
+ function splitPathSegments(path) {
1625
+ return path.trim().split(/[\\/]/).filter(Boolean);
1626
+ }
1627
+ function normalizeChangeType(value) {
1628
+ switch ((value ?? "").trim().toLowerCase()) {
1629
+ case "add":
1630
+ case "added":
1631
+ case "create":
1632
+ case "created":
1633
+ case "new":
1634
+ return "created";
1635
+ case "modify":
1636
+ case "modified":
1637
+ case "edit":
1638
+ case "edited":
1639
+ case "change":
1640
+ case "changed":
1641
+ case "update":
1642
+ case "updated":
1643
+ return "modified";
1644
+ case "delete":
1645
+ case "deleted":
1646
+ case "remove":
1647
+ case "removed":
1648
+ return "deleted";
1649
+ default:
1650
+ return null;
1651
+ }
1652
+ }
1653
+ function isFailedToolStatus(value) {
1654
+ const normalized = (value ?? "").trim().toLowerCase();
1655
+ return ["failed", "error", "errored", "canceled", "cancelled"].includes(
1656
+ normalized
1657
+ );
1658
+ }
1659
+ function objectValue5(value) {
1660
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
1661
+ }
1662
+ function firstFileChangeValue(...values) {
1663
+ for (const value of values) {
1664
+ if (Array.isArray(value) || objectValue5(value)) {
1665
+ return value;
1666
+ }
1667
+ }
1668
+ return null;
1669
+ }
1670
+ function arrayValue5(value) {
1671
+ return Array.isArray(value) ? value : null;
1672
+ }
1673
+ function nestedTaskStepsFromPayload(payload, output) {
1674
+ const candidates = [
1675
+ arrayValue5(payload?.steps),
1676
+ arrayValue5(output?.steps),
1677
+ arrayValue5(objectValue5(payload?.metadata)?.steps),
1678
+ arrayValue5(objectValue5(output?.metadata)?.steps)
1679
+ ];
1680
+ return candidates.find((value) => value && value.length > 0) ?? [];
1681
+ }
1682
+ function nestedTaskStepStatusKind(step, fallback) {
1683
+ return stringValue5(step.statusKind) ?? stringValue5(step.status) ?? fallback ?? null;
1684
+ }
1685
+ function stringValue5(value) {
1686
+ return typeof value === "string" && value.trim() ? value.trim() : null;
1687
+ }
1688
+ function literalStringValue(value) {
1689
+ return typeof value === "string" ? value : null;
1690
+ }
1691
+ function firstNonEmptyString(...values) {
1692
+ for (const value of values) {
1693
+ if (typeof value === "string" && value.trim()) {
1694
+ return value.trim();
1695
+ }
1696
+ }
1697
+ return null;
1698
+ }
1699
+ function firstPresentString(...values) {
1700
+ for (const value of values) {
1701
+ if (typeof value === "string") {
1702
+ return value;
1703
+ }
1704
+ }
1705
+ return null;
1706
+ }
1707
+
1708
+ // shared/agentConversation/projection/agentTurnSummaryProjection.ts
1709
+ function projectAgentTurnSummaryRows(detail) {
1710
+ const transcriptTurnsById = new Map(
1711
+ detail.turns.map((turn) => [turn.id, turn])
1712
+ );
1713
+ return (detail.sessionTurns ?? []).flatMap((turn) => {
1714
+ const transcriptTurn = transcriptTurnsById.get(turn.turnId);
1715
+ if (!isSettledTurnSummaryVisible(detail, turn.turnId, turn.phase) || !turn.fileChanges || !transcriptTurn) {
1716
+ return [];
1717
+ }
1718
+ return projectAgentTurnSummaryRowForTurn(transcriptTurn, turn.fileChanges, {
1719
+ defaultCwd: detail.cwd,
1720
+ workspaceRoot: detail.workspaceRoot,
1721
+ occurredAtUnixMs: turn.updatedAtUnixMs
1722
+ });
1723
+ });
1724
+ }
1725
+ function isSettledTurnSummaryVisible(detail, turnId, phase) {
1726
+ if (phase !== "settled") return false;
1727
+ const activeTurn = detail.session.activeTurn;
1728
+ if (activeTurn?.turnId === turnId && activeTurn.phase !== "settled") {
1729
+ return false;
1730
+ }
1731
+ return detail.showProcessingIndicator !== true || detail.turns.at(-1)?.id !== turnId;
1732
+ }
1733
+ function projectAgentTurnSummaryRowForTurn(turn, fileChanges, options = {}) {
1734
+ const files = canonicalTurnFiles(turn.id, fileChanges, options);
1735
+ if (files.length === 0) {
1736
+ return [];
1737
+ }
1738
+ const visiblePaths = new Set(files.map((file) => file.path));
1739
+ const patchBatches = patchBatchesFromCalls(
1740
+ turnToolCallsForSummary(turn),
1741
+ options
1742
+ ).flatMap((batch) => {
1743
+ const changes = batch.changes.filter(
1744
+ (change) => visiblePaths.has(change.path)
1745
+ );
1746
+ return changes.length > 0 ? [{ ...batch, changes }] : [];
1747
+ });
1748
+ const createdCount = files.filter(
1749
+ (file) => file.changeType === "created"
1750
+ ).length;
1751
+ return [
1752
+ {
1753
+ kind: "turn-summary",
1754
+ id: `turn-summary:${turn.id}`,
1755
+ turnId: turn.id,
1756
+ files,
1757
+ ...patchBatches.length > 0 ? { patchBatches } : {},
1758
+ fileCount: files.length,
1759
+ modifiedCount: files.length - createdCount,
1760
+ createdCount,
1761
+ occurredAtUnixMs: options.occurredAtUnixMs ?? null
1762
+ }
1763
+ ];
1764
+ }
1765
+ function canonicalTurnFiles(turnId, fileChanges, options) {
1766
+ const byPath = /* @__PURE__ */ new Map();
1767
+ for (const [index, value] of (arrayValue5(objectValue5(fileChanges)?.files) ?? []).entries()) {
1768
+ const file = objectValue5(value);
1769
+ const path = normalizedFilePath(
1770
+ firstNonEmptyString(
1771
+ stringValue5(file?.path),
1772
+ stringValue5(file?.filePath),
1773
+ stringValue5(file?.file_path)
1774
+ ),
1775
+ options
1776
+ );
1777
+ if (!file || !path) {
1778
+ continue;
1779
+ }
1780
+ const parts = splitFilePath(path);
1781
+ byPath.set(path, {
1782
+ label: path,
1783
+ path,
1784
+ fileName: parts.fileName,
1785
+ directory: parts.directory,
1786
+ changeType: normalizeChangeType(
1787
+ firstNonEmptyString(
1788
+ stringValue5(file.change),
1789
+ stringValue5(file.type),
1790
+ stringValue5(file.status)
1791
+ )
1792
+ ) ?? "modified",
1793
+ toolName: null,
1794
+ messageId: `turn-summary:${turnId}:file:${index + 1}`,
1795
+ unifiedDiff: firstNonEmptyString(
1796
+ stringValue5(file.unifiedDiff),
1797
+ stringValue5(file.unified_diff),
1798
+ stringValue5(file.diff),
1799
+ stringValue5(file.patch)
1800
+ ) ?? null,
1801
+ oldString: firstPresentString(
1802
+ literalStringValue(file.oldString),
1803
+ literalStringValue(file.old_string)
1804
+ ),
1805
+ newString: firstPresentString(
1806
+ literalStringValue(file.newString),
1807
+ literalStringValue(file.new_string)
1808
+ ),
1809
+ content: literalStringValue(file.content),
1810
+ occurredAtUnixMs: options.occurredAtUnixMs ?? null
1811
+ });
1812
+ }
1813
+ return applyShortestUniqueFileLabels([...byPath.values()]);
1814
+ }
1815
+ function turnToolCallsForSummary(turn) {
1816
+ const callsById = /* @__PURE__ */ new Map();
1817
+ for (const call of turn.toolCalls) {
1818
+ callsById.set(call.id, call);
1819
+ }
1820
+ for (const item of turn.agentItems) {
1821
+ if (item.kind !== "tool-calls") {
1822
+ continue;
1823
+ }
1824
+ for (const call of item.toolCalls) {
1825
+ callsById.set(call.id, call);
1826
+ }
1827
+ for (const entry of item.groupEntries ?? []) {
1828
+ if (entry.kind === "tool-call") {
1829
+ callsById.set(entry.call.id, entry.call);
1830
+ }
1831
+ }
1832
+ }
1833
+ return [...callsById.values()];
1834
+ }
1835
+ function patchBatchesFromCalls(calls, options) {
1836
+ return calls.flatMap((call) => patchBatchesFromCall(call, options));
1837
+ }
1838
+ function patchBatchesFromCall(call, options) {
1839
+ const directBatch = isFailedToolStatus(call.statusKind ?? null) ? [] : patchBatchFromPayload(call.id, call.payload ?? null, null, null, options);
1840
+ const output = objectValue5(call.payload?.output);
1841
+ const nestedBatches = nestedTaskStepsFromPayload(
1842
+ call.payload,
1843
+ output
1844
+ ).flatMap((value, index) => {
1845
+ const step = objectValue5(value);
1846
+ if (!step || isFailedToolStatus(
1847
+ nestedTaskStepStatusKind(step, call.statusKind ?? null)
1848
+ )) {
1849
+ return [];
1850
+ }
1851
+ return patchBatchFromPayload(
1852
+ stringValue5(step.toolUseId) ?? stringValue5(step.id) ?? `${call.id}:step:${index + 1}`,
1853
+ objectValue5(step.payload),
1854
+ objectValue5(step.toolInput) ?? objectValue5(step.tool_input),
1855
+ objectValue5(step.toolResult) ?? objectValue5(step.tool_result),
1856
+ options
1857
+ );
1858
+ });
1859
+ return [...directBatch, ...nestedBatches];
1860
+ }
1861
+ function patchBatchFromPayload(id, payload, toolInput, toolOutput, options) {
1862
+ const toolState = objectValue5(payload?.tool_state);
1863
+ const metadata = objectValue5(payload?.metadata);
1864
+ const input = toolInput ?? objectValue5(payload?.input) ?? objectValue5(toolState?.input);
1865
+ const output = toolOutput ?? objectValue5(payload?.output) ?? objectValue5(toolState?.output);
1866
+ const rawInput = objectValue5(input?.rawInput);
1867
+ const changes = firstFileChangeValue(
1868
+ output?.changes,
1869
+ payload?.changes,
1870
+ input?.changes,
1871
+ rawInput?.changes
1872
+ );
1873
+ const patchChanges = patchChangesFromChangeMap(changes);
1874
+ if (patchChanges.length === 0) {
1875
+ return [];
1876
+ }
1877
+ return [
1878
+ {
1879
+ cwd: firstNonEmptyString(
1880
+ stringValue5(payload?.cwd),
1881
+ stringValue5(input?.cwd),
1882
+ stringValue5(rawInput?.cwd),
1883
+ stringValue5(output?.cwd),
1884
+ stringValue5(metadata?.cwd),
1885
+ options.defaultCwd ?? null
1886
+ ) ?? null,
1887
+ toolCallId: id,
1888
+ changes: patchChanges
1889
+ }
1890
+ ];
1891
+ }
1892
+ function patchChangesFromChangeMap(changes) {
1893
+ return fileChangeEntriesFromChanges(changes).flatMap((entry) => {
1894
+ const change = entry.change;
1895
+ const path = entry.path.trim();
1896
+ if (!path) {
1897
+ return [];
1898
+ }
1899
+ const changeType = normalizeChangeType(fileChangeTypeValue(change));
1900
+ const unifiedDiff = firstNonEmptyString(
1901
+ stringValue5(change.unified_diff),
1902
+ stringValue5(change.unifiedDiff),
1903
+ stringValue5(change.diff),
1904
+ stringValue5(change.patch)
1905
+ ) ?? null;
1906
+ let oldString = firstPresentString(
1907
+ literalStringValue(change.old_string),
1908
+ literalStringValue(change.oldString)
1909
+ );
1910
+ const explicitContent = literalStringValue(change.content);
1911
+ let newString = firstPresentString(
1912
+ literalStringValue(change.new_string),
1913
+ literalStringValue(change.newString),
1914
+ explicitContent
1915
+ );
1916
+ if (changeType === "created" && oldString === null && newString !== null) {
1917
+ oldString = "";
1918
+ }
1919
+ if (changeType === "deleted" && oldString === null && newString !== null) {
1920
+ oldString = newString;
1921
+ newString = "";
1922
+ }
1923
+ if (changeType === "deleted" && newString === null && oldString !== null) {
1924
+ newString = "";
1925
+ }
1926
+ const content = firstPresentString(
1927
+ changeType === "deleted" ? null : explicitContent,
1928
+ changeType === "created" ? newString : null
1929
+ );
1930
+ if (!unifiedDiff && oldString === null && newString === null && content === null) {
1931
+ return [];
1932
+ }
1933
+ return [
1934
+ {
1935
+ path,
1936
+ changeType: changeType ?? inferAgentPatchChangeType(unifiedDiff),
1937
+ unifiedDiff,
1938
+ oldString,
1939
+ newString,
1940
+ content
1941
+ }
1942
+ ];
1943
+ });
1944
+ }
1945
+
1946
+ // shared/agentConversation/projection/agentConversationProjection.ts
1947
+ var RENDER_IRRELEVANT_TRANSCRIPT_ROW_FIELDS = /* @__PURE__ */ new Set(["occurredAtUnixMs"]);
1948
+ var CODEX_SKILLS_CONTEXT_BUDGET_NOTICE_FRAGMENT = "skill descriptions were shortened to fit the 2% skills context budget";
1949
+ var CODEX_MODEL_METADATA_FALLBACK_NOTICE_FRAGMENT = "defaulting to fallback metadata";
1950
+ var MARKDOWN_IMAGE_PATTERN = /!\[[^\]]*]\(\s*(?:<([^>]+)>|([^)\s]+))(?:\s+["'][^"']*["'])?\s*\)/g;
1951
+ function projectAgentConversationVM(detail, options = {}) {
1952
+ const rows = [];
1953
+ const turns = detail.turns;
1954
+ const summariesByTurnId = new Map(
1955
+ projectAgentTurnSummaryRows(detail).map((summary) => [
1956
+ summary.turnId,
1957
+ summary
1958
+ ])
1959
+ );
1960
+ turns.forEach((turn) => {
1961
+ rows.push(
1962
+ ...projectTurnConversationRows(turn, detail.session.workspaceId, {
1963
+ agentSessionId: detail.session.agentSessionId,
1964
+ avoidGroupingEdits: options.avoidGroupingEdits
1965
+ })
1966
+ );
1967
+ const summary = summariesByTurnId.get(turn.id);
1968
+ if (summary) rows.push(summary);
1969
+ });
1970
+ const normalizedRows = dropCodexRuntimeDiagnosticNotices(
1971
+ dropRedundantErrorWarningNotices(
1972
+ mergeAdjacentAssistantMessageRows(
1973
+ dropRedundantCompactFailureEchoRows(
1974
+ mergeAdjacentTransportRetryNoticeRows(rows)
1975
+ )
1976
+ )
1977
+ )
1978
+ );
1979
+ const timelineRows = insertGoalControlRows(normalizedRows, detail);
1980
+ const processing = projectAgentProcessingRow(detail, timelineRows);
1981
+ const projectedRows = projectAgentMessageFinalText(
1982
+ processing ? [...timelineRows, processing] : timelineRows,
1983
+ detail
1984
+ );
1985
+ return {
1986
+ activity: detail.activity,
1987
+ workspaceRoot: detail.workspaceRoot,
1988
+ sourceDetail: detail,
1989
+ rows: projectedRows
1990
+ };
1991
+ }
1992
+ function insertGoalControlRows(rows, detail) {
1993
+ const controls = detail.goalControls ?? [];
1994
+ if (controls.length === 0) {
1995
+ return [...rows];
1996
+ }
1997
+ const merged = [...rows];
1998
+ for (const control of controls) {
1999
+ const row = {
2000
+ kind: "goal-control",
2001
+ id: `goal-control:${control.id}`,
2002
+ turnId: null,
2003
+ action: control.action,
2004
+ body: control.body,
2005
+ occurredAtUnixMs: control.occurredAtUnixMs ?? null,
2006
+ sourceTimelineItems: control.sourceTimelineItems
2007
+ };
2008
+ const insertionIndex = merged.findIndex(
2009
+ (candidate) => row.occurredAtUnixMs !== null && candidate.occurredAtUnixMs !== null && candidate.occurredAtUnixMs > row.occurredAtUnixMs
2010
+ );
2011
+ if (insertionIndex < 0) {
2012
+ merged.push(row);
2013
+ } else {
2014
+ merged.splice(insertionIndex, 0, row);
2015
+ }
2016
+ }
2017
+ return merged;
2018
+ }
2019
+ function dropRedundantCompactFailureEchoRows(rows) {
2020
+ const filtered = [];
2021
+ for (const row of rows) {
2022
+ const previous = filtered.at(-1);
2023
+ if (isSingleCompactFailureNoticeRow(previous) && isSinglePlainAssistantMessageRow(row) && previous.turnId === row.turnId && previous.messages[0]?.systemNotice?.detail?.trim() === row.messages[0]?.body.trim()) {
2024
+ continue;
2025
+ }
2026
+ filtered.push(row);
2027
+ }
2028
+ return filtered;
2029
+ }
2030
+ function isSingleCompactFailureNoticeRow(row) {
2031
+ if (!row || row.kind !== "message" || row.speaker !== "assistant" || row.thinking.length > 0 || row.messages.length !== 1) {
2032
+ return false;
2033
+ }
2034
+ const notice = row.messages[0]?.systemNotice;
2035
+ return notice?.command === "compact" && notice.commandStatus === "failed" && Boolean(notice.detail?.trim());
2036
+ }
2037
+ function isSinglePlainAssistantMessageRow(row) {
2038
+ return row.kind === "message" && row.speaker === "assistant" && row.thinking.length === 0 && row.messages.length === 1 && !row.messages[0]?.visibleError && !row.messages[0]?.systemNotice;
2039
+ }
2040
+ function latestAssistantMessageText(conversation) {
2041
+ if (!conversation) {
2042
+ return null;
2043
+ }
2044
+ for (let rowIndex = conversation.rows.length - 1; rowIndex >= 0; rowIndex--) {
2045
+ const row = conversation.rows[rowIndex];
2046
+ if (row?.kind !== "message" || row.speaker !== "assistant") {
2047
+ continue;
2048
+ }
2049
+ for (let messageIndex = row.messages.length - 1; messageIndex >= 0; messageIndex--) {
2050
+ const message = row.messages[messageIndex];
2051
+ if (!message || message.visibleError || message.systemNotice) {
2052
+ continue;
2053
+ }
2054
+ if (message.contentKind && message.contentKind !== "text") {
2055
+ continue;
2056
+ }
2057
+ const body = message.body.trim();
2058
+ if (body) {
2059
+ return body;
2060
+ }
2061
+ }
2062
+ }
2063
+ return null;
2064
+ }
2065
+ function reconcileProjectedAgentConversationVM(previous, next) {
2066
+ if (!previous) {
2067
+ return next;
2068
+ }
2069
+ const previousRowsById = new Map(previous.rows.map((row) => [row.id, row]));
2070
+ let reusedRowCount = 0;
2071
+ const rows = next.rows.map((row) => {
2072
+ const previousRow = previousRowsById.get(row.id);
2073
+ if (previousRow && equivalentTranscriptRowForRender(previousRow, row)) {
2074
+ reusedRowCount += 1;
2075
+ return previousRow;
2076
+ }
2077
+ return row;
2078
+ });
2079
+ const rowsArrayReused = reusedRowCount === next.rows.length && next.rows.length === previous.rows.length && next.rows.every((_row, index) => rows[index] === previous.rows[index]);
2080
+ return {
2081
+ ...next,
2082
+ rows: rowsArrayReused ? previous.rows : rows
2083
+ };
2084
+ }
2085
+ function equivalentTranscriptRowForRender(previous, next) {
2086
+ return equivalentValueIgnoringKeys(
2087
+ previous,
2088
+ next,
2089
+ RENDER_IRRELEVANT_TRANSCRIPT_ROW_FIELDS
2090
+ );
2091
+ }
2092
+ function equivalentValueIgnoringKeys(left, right, ignoredKeys) {
2093
+ if (Object.is(left, right)) {
2094
+ return true;
2095
+ }
2096
+ if (typeof left !== typeof right || left === null || right === null) {
2097
+ return false;
2098
+ }
2099
+ if (Array.isArray(left) || Array.isArray(right)) {
2100
+ return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every(
2101
+ (value, index) => equivalentValueIgnoringKeys(value, right[index], ignoredKeys)
2102
+ );
2103
+ }
2104
+ if (typeof left !== "object" || typeof right !== "object") {
2105
+ return false;
2106
+ }
2107
+ const leftRecord = left;
2108
+ const rightRecord = right;
2109
+ const leftKeys = Object.keys(leftRecord).filter(
2110
+ (key) => !ignoredKeys.has(key)
2111
+ );
2112
+ const rightKeys = Object.keys(rightRecord).filter(
2113
+ (key) => !ignoredKeys.has(key)
2114
+ );
2115
+ return leftKeys.length === rightKeys.length && leftKeys.every(
2116
+ (key) => Object.prototype.hasOwnProperty.call(rightRecord, key) && equivalentValueIgnoringKeys(
2117
+ leftRecord[key],
2118
+ rightRecord[key],
2119
+ ignoredKeys
2120
+ )
2121
+ );
2122
+ }
2123
+ function mergeAdjacentAssistantMessageRows(rows) {
2124
+ const merged = [];
2125
+ for (const row of rows) {
2126
+ const previous = merged.at(-1);
2127
+ if (isMergeableAssistantMessageRow(previous) && canMergeAdjacentAssistantMessageRows(previous, row)) {
2128
+ const lastMessage = previous.messages.at(-1);
2129
+ const nextMessage = row.messages[0];
2130
+ if (lastMessage && nextMessage) {
2131
+ lastMessage.body += nextMessage.body;
2132
+ lastMessage.statusKind = nextMessage.statusKind ?? lastMessage.statusKind ?? null;
2133
+ lastMessage.occurredAtUnixMs = nextMessage.occurredAtUnixMs ?? lastMessage.occurredAtUnixMs;
2134
+ }
2135
+ if (row.messages.length > 1) {
2136
+ previous.messages.push(...row.messages.slice(1));
2137
+ }
2138
+ previous.occurredAtUnixMs = row.occurredAtUnixMs ?? previous.occurredAtUnixMs;
2139
+ continue;
2140
+ }
2141
+ merged.push(row);
2142
+ }
2143
+ return merged;
2144
+ }
2145
+ function dropCodexRuntimeDiagnosticNotices(rows) {
2146
+ const filteredRows = [];
2147
+ for (const row of rows) {
2148
+ if (row.kind !== "message" || row.speaker !== "assistant") {
2149
+ filteredRows.push(row);
2150
+ continue;
2151
+ }
2152
+ const messages = row.messages.filter(
2153
+ (message) => !isCodexSkillsContextBudgetNotice(message)
2154
+ );
2155
+ if (messages.length === 0 && row.thinking.length === 0) {
2156
+ continue;
2157
+ }
2158
+ if (messages.length === row.messages.length) {
2159
+ filteredRows.push(row);
2160
+ continue;
2161
+ }
2162
+ filteredRows.push({ ...row, messages });
2163
+ }
2164
+ return filteredRows;
2165
+ }
2166
+ function isCodexSkillsContextBudgetNotice(message) {
2167
+ const notice = message.systemNotice;
2168
+ if (!notice || notice.noticeKind !== "warning") {
2169
+ return false;
2170
+ }
2171
+ if (notice.source !== "runtime") {
2172
+ return false;
2173
+ }
2174
+ const text = [notice.title, notice.detail, message.body].filter(Boolean).join("\n").toLowerCase();
2175
+ return text.includes(CODEX_SKILLS_CONTEXT_BUDGET_NOTICE_FRAGMENT) || text.includes(CODEX_MODEL_METADATA_FALLBACK_NOTICE_FRAGMENT);
2176
+ }
2177
+ function dropRedundantErrorWarningNotices(rows) {
2178
+ const turnsWithVisibleError = /* @__PURE__ */ new Set();
2179
+ for (const row of rows) {
2180
+ if (row.kind !== "message" || row.speaker !== "assistant") {
2181
+ continue;
2182
+ }
2183
+ for (const message of row.messages) {
2184
+ if (message.visibleError) {
2185
+ turnsWithVisibleError.add(row.turnId);
2186
+ }
2187
+ }
2188
+ }
2189
+ if (turnsWithVisibleError.size === 0) {
2190
+ return [...rows];
2191
+ }
2192
+ const filteredRows = [];
2193
+ for (const row of rows) {
2194
+ if (row.kind !== "message" || row.speaker !== "assistant") {
2195
+ filteredRows.push(row);
2196
+ continue;
2197
+ }
2198
+ if (!turnsWithVisibleError.has(row.turnId)) {
2199
+ filteredRows.push(row);
2200
+ continue;
2201
+ }
2202
+ const messages = row.messages.filter(
2203
+ (message) => !isRedundantErrorWarningNotice(message)
2204
+ );
2205
+ if (messages.length === 0) {
2206
+ continue;
2207
+ }
2208
+ if (messages.length === row.messages.length) {
2209
+ filteredRows.push(row);
2210
+ continue;
2211
+ }
2212
+ filteredRows.push({ ...row, messages });
2213
+ }
2214
+ return filteredRows;
2215
+ }
2216
+ function isRedundantErrorWarningNotice(message) {
2217
+ const notice = message.systemNotice;
2218
+ if (!notice || notice.noticeKind !== "warning") {
2219
+ return false;
2220
+ }
2221
+ const title = notice.title?.trim() ?? "";
2222
+ return title === "Codex reported an error.";
2223
+ }
2224
+ function mergeAdjacentTransportRetryNoticeRows(rows) {
2225
+ const merged = [];
2226
+ for (const row of rows) {
2227
+ const previous = merged.at(-1);
2228
+ if (isSingleTransportRetryNoticeRow(previous) && isSingleTransportRetryNoticeRow(row) && previous.turnId === row.turnId) {
2229
+ const previousMessage = previous.messages[0];
2230
+ const nextMessage = row.messages[0];
2231
+ if (!previousMessage || !nextMessage) {
2232
+ merged.push(row);
2233
+ continue;
2234
+ }
2235
+ const sourceTimelineItems = mergeSourceTimelineItems(
2236
+ previousMessage.sourceTimelineItems,
2237
+ nextMessage.sourceTimelineItems
2238
+ );
2239
+ previous.messages[0] = {
2240
+ ...previousMessage,
2241
+ body: nextMessage.body || previousMessage.body,
2242
+ systemNotice: nextMessage.systemNotice ?? previousMessage.systemNotice,
2243
+ statusKind: nextMessage.statusKind ?? previousMessage.statusKind ?? null,
2244
+ occurredAtUnixMs: nextMessage.occurredAtUnixMs ?? previousMessage.occurredAtUnixMs,
2245
+ ...sourceTimelineItems ? { sourceTimelineItems } : {}
2246
+ };
2247
+ previous.occurredAtUnixMs = row.occurredAtUnixMs ?? previous.occurredAtUnixMs;
2248
+ continue;
2249
+ }
2250
+ merged.push(row);
2251
+ }
2252
+ return merged;
2253
+ }
2254
+ function isSingleTransportRetryNoticeRow(row) {
2255
+ if (!row || row.kind !== "message" || row.speaker !== "assistant" || row.thinking.length > 0 || row.messages.length !== 1) {
2256
+ return false;
2257
+ }
2258
+ return row.messages[0]?.systemNotice?.noticeKind === "transport_retry";
2259
+ }
2260
+ function mergeSourceTimelineItems(previous, next) {
2261
+ if (!previous || previous.length === 0) {
2262
+ return next;
2263
+ }
2264
+ if (!next || next.length === 0) {
2265
+ return previous;
2266
+ }
2267
+ return [...previous, ...next];
2268
+ }
2269
+ function isMergeableAssistantMessageRow(row) {
2270
+ return Boolean(
2271
+ row && row.kind === "message" && row.speaker === "assistant" && row.thinking.length === 0 && !row.messages.some(isSpecialAssistantMessage)
2272
+ );
2273
+ }
2274
+ function canMergeAdjacentAssistantMessageRows(previous, next) {
2275
+ return next.kind === "message" && next.speaker === "assistant" && next.thinking.length === 0 && previous.turnId === next.turnId && !next.messages.some(isSpecialAssistantMessage);
2276
+ }
2277
+ function isSpecialAssistantMessage(message) {
2278
+ return Boolean(
2279
+ message.visibleError || message.systemNotice || message.contentKind === "plan" || message.contentKind === "collaboration"
2280
+ );
2281
+ }
2282
+ function projectTurnConversationRows(turn, workspaceId, options) {
2283
+ const sequence = buildAgentTurnSequenceItems(turn, workspaceId);
2284
+ const { groups, groupedIndices, suppressedIndices } = computeAgentToolGroups(
2285
+ sequence,
2286
+ options
2287
+ );
2288
+ const skippedIndices = /* @__PURE__ */ new Set([...groupedIndices, ...suppressedIndices]);
2289
+ return promoteGeneratedImageRows(
2290
+ projectTurnRows(
2291
+ sequence,
2292
+ groups,
2293
+ skippedIndices,
2294
+ turn.id,
2295
+ options.agentSessionId
2296
+ )
2297
+ );
2298
+ }
2299
+ function promoteGeneratedImageRows(rows) {
2300
+ const promoted = [];
2301
+ for (const row of rows) {
2302
+ promoted.push(row);
2303
+ if (row.kind !== "tool-group") {
2304
+ continue;
2305
+ }
2306
+ for (const call of row.calls) {
2307
+ const artifact = projectGeneratedImageRow(call, row.turnId);
2308
+ if (artifact) {
2309
+ promoted.push(artifact);
2310
+ }
2311
+ }
2312
+ }
2313
+ return dropDuplicateGeneratedImageMarkdown(promoted);
2314
+ }
2315
+ function dropDuplicateGeneratedImageMarkdown(rows) {
2316
+ const generatedImagesByTurn = /* @__PURE__ */ new Map();
2317
+ for (const row of rows) {
2318
+ if (row.kind !== "generated-image") {
2319
+ continue;
2320
+ }
2321
+ const reference = normalizeGeneratedImageReference(row.uri);
2322
+ if (!reference) {
2323
+ continue;
2324
+ }
2325
+ const references = generatedImagesByTurn.get(row.turnId) ?? /* @__PURE__ */ new Set();
2326
+ references.add(reference);
2327
+ generatedImagesByTurn.set(row.turnId, references);
2328
+ }
2329
+ if (generatedImagesByTurn.size === 0) {
2330
+ return [...rows];
2331
+ }
2332
+ const filtered = [];
2333
+ for (const row of rows) {
2334
+ if (row.kind !== "message" || row.speaker !== "assistant") {
2335
+ filtered.push(row);
2336
+ continue;
2337
+ }
2338
+ const generatedImages = generatedImagesByTurn.get(row.turnId);
2339
+ if (!generatedImages) {
2340
+ filtered.push(row);
2341
+ continue;
2342
+ }
2343
+ let changed = false;
2344
+ const messages = row.messages.flatMap((message) => {
2345
+ const body = removeGeneratedImageMarkdown(message.body, generatedImages);
2346
+ if (body === message.body) {
2347
+ return [message];
2348
+ }
2349
+ changed = true;
2350
+ return body ? [{ ...message, body }] : [];
2351
+ });
2352
+ if (messages.length === 0 && row.thinking.length === 0) {
2353
+ continue;
2354
+ }
2355
+ filtered.push(changed ? { ...row, messages } : row);
2356
+ }
2357
+ return filtered;
2358
+ }
2359
+ function removeGeneratedImageMarkdown(body, generatedImages) {
2360
+ let removed = false;
2361
+ const next = body.replace(
2362
+ MARKDOWN_IMAGE_PATTERN,
2363
+ (match, angleReference, plainReference) => {
2364
+ const reference = normalizeGeneratedImageReference(
2365
+ angleReference ?? plainReference ?? ""
2366
+ );
2367
+ if (!reference || !generatedImages.has(reference)) {
2368
+ return match;
2369
+ }
2370
+ removed = true;
2371
+ return "";
2372
+ }
2373
+ );
2374
+ return removed ? next.replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n").trim() : body;
2375
+ }
2376
+ function normalizeGeneratedImageReference(reference) {
2377
+ let normalized = reference.trim();
2378
+ if (!normalized) {
2379
+ return null;
2380
+ }
2381
+ if (/^file:\/\//i.test(normalized)) {
2382
+ if (!URL.canParse(normalized)) {
2383
+ return null;
2384
+ }
2385
+ normalized = new URL(normalized).pathname;
2386
+ } else if (/^[a-z][a-z\d+.-]*:\/\//i.test(normalized)) {
2387
+ return URL.canParse(normalized) ? new URL(normalized).href : normalized;
2388
+ }
2389
+ normalized = decodePercentEncodedReference(normalized);
2390
+ normalized = normalized.replaceAll("\\", "/");
2391
+ const prefix = normalized.startsWith("/") ? "/" : "";
2392
+ const parts = [];
2393
+ for (const part of normalized.split("/")) {
2394
+ if (!part || part === ".") {
2395
+ continue;
2396
+ }
2397
+ if (part === ".." && parts.length > 0) {
2398
+ parts.pop();
2399
+ continue;
2400
+ }
2401
+ parts.push(part);
2402
+ }
2403
+ const collapsed = `${prefix}${parts.join("/")}`;
2404
+ return /^[a-z]:\//i.test(collapsed) ? collapsed.toLowerCase() : collapsed;
2405
+ }
2406
+ function decodePercentEncodedReference(reference) {
2407
+ return reference.replace(/(?:%[a-f\d]{2})+/gi, (encodedRun) => {
2408
+ const bytes = encodedRun.slice(1).split("%").map((hex) => Number.parseInt(hex, 16));
2409
+ return new TextDecoder().decode(Uint8Array.from(bytes));
2410
+ });
2411
+ }
2412
+ function projectGeneratedImageRow(call, turnId) {
2413
+ if (call.rendererKind !== "image-generation" || call.statusKind !== "completed") {
2414
+ return null;
2415
+ }
2416
+ const image = extractImageGenerationPreview({
2417
+ toolName: call.toolName,
2418
+ displayName: call.name,
2419
+ content: call.content,
2420
+ outputContent: call.output?.content,
2421
+ outputSavedPath: call.output?.savedPath ?? call.output?.saved_path,
2422
+ inputPrompt: call.input?.prompt,
2423
+ payloadInputPrompt: call.payload?.input && typeof call.payload.input === "object" && !Array.isArray(call.payload.input) ? call.payload.input.prompt : null
2424
+ });
2425
+ if (!image.imageUri) {
2426
+ return null;
2427
+ }
2428
+ return {
2429
+ kind: "generated-image",
2430
+ id: `generated-image:${call.id}`,
2431
+ turnId,
2432
+ sourceCallId: call.id,
2433
+ uri: image.imageUri,
2434
+ mimeType: image.mimeType,
2435
+ prompt: image.prompt,
2436
+ occurredAtUnixMs: call.occurredAtUnixMs
2437
+ };
2438
+ }
2439
+
2440
+ // shared/workspaceAgentSystemNoticeSemantics.ts
2441
+ function resolveWorkspaceAgentNoticeCommandSemantics(input) {
2442
+ const semanticCommand = noticeCommand(input.messageSemantics?.noticeCommand);
2443
+ const semanticCommandStatus = noticeCommandStatus(
2444
+ input.messageSemantics?.noticeCommandStatus
2445
+ );
2446
+ const payloadCommand = noticeCommand(
2447
+ recordString(input.payload, "noticeCommand")
2448
+ );
2449
+ const payloadCommandStatus = noticeCommandStatus(
2450
+ recordString(input.payload, "noticeCommandStatus")
2451
+ );
2452
+ const command = semanticCommand ?? payloadCommand;
2453
+ const commandStatus = semanticCommandStatus ?? payloadCommandStatus;
2454
+ if (command && commandStatus) {
2455
+ return { command, commandStatus };
2456
+ }
2457
+ const source = recordString(input.payload, "source");
2458
+ const hasCompactIdentity = source === "compact" || /^(?:claude-sdk:compact:|compaction:)/u.test(input.eventId?.trim() ?? "");
2459
+ if (!hasCompactIdentity) {
2460
+ return null;
2461
+ }
2462
+ const legacyCompactStatus = compactTitleStatus(recordString(input.payload, "title"), input.status) ?? (source === "compact" ? compactStreamStatus(input.status) : null);
2463
+ if (!legacyCompactStatus) {
2464
+ return null;
2465
+ }
2466
+ return {
2467
+ command: "compact",
2468
+ commandStatus: legacyCompactStatus
2469
+ };
2470
+ }
2471
+ function noticeCommand(value) {
2472
+ switch (value) {
2473
+ case "compact":
2474
+ case "review":
2475
+ case "undo":
2476
+ case "goal":
2477
+ return value;
2478
+ default:
2479
+ return null;
2480
+ }
2481
+ }
2482
+ function noticeCommandStatus(value) {
2483
+ switch (value) {
2484
+ case "running":
2485
+ case "completed":
2486
+ case "failed":
2487
+ case "canceled":
2488
+ return value;
2489
+ default:
2490
+ return null;
2491
+ }
2492
+ }
2493
+ function compactTitleStatus(title, status) {
2494
+ switch (title) {
2495
+ case "Compacting context.":
2496
+ return "running";
2497
+ case "Context compacted.":
2498
+ return "completed";
2499
+ case "Context compaction interrupted.":
2500
+ return compactStreamStatus(status) === "canceled" ? "canceled" : "failed";
2501
+ default:
2502
+ return null;
2503
+ }
2504
+ }
2505
+ function compactStreamStatus(status) {
2506
+ switch (status?.trim().toLowerCase()) {
2507
+ case "completed":
2508
+ case "complete":
2509
+ case "done":
2510
+ case "success":
2511
+ case "succeeded":
2512
+ return "completed";
2513
+ case "failed":
2514
+ case "error":
2515
+ return "failed";
2516
+ case "canceled":
2517
+ case "cancelled":
2518
+ case "stopped":
2519
+ return "canceled";
2520
+ default:
2521
+ return "running";
2522
+ }
2523
+ }
2524
+ function recordString(record, key) {
2525
+ const value = record?.[key];
2526
+ return typeof value === "string" && value.trim() ? value.trim() : null;
2527
+ }
2528
+
2529
+ // shared/workspaceAgentToolCallIdentifiers.ts
2530
+ function looksLikeOpaqueToolCallIdentifier(value) {
2531
+ return /^call[_:-](?:function[_:-])?[a-z0-9][a-z0-9_-]{11,}$/i.test(value);
2532
+ }
2533
+ function isOpaqueWorkspaceAgentToolCallIdentifier(value, item) {
2534
+ const trimmed = value?.trim();
2535
+ if (!trimmed) {
2536
+ return false;
2537
+ }
2538
+ const knownCallId = firstPresentString2(
2539
+ stringRecordValue(item.payload, "callId"),
2540
+ stringRecordValue(item.payload, "callID"),
2541
+ stringRecordValue(item.payload, "call_id"),
2542
+ item.callId
2543
+ );
2544
+ if (knownCallId && normalizeOpaqueToolCallIdentifier(trimmed) === normalizeOpaqueToolCallIdentifier(knownCallId)) {
2545
+ return true;
2546
+ }
2547
+ return looksLikeOpaqueToolCallIdentifier(trimmed);
2548
+ }
2549
+ function normalizeOpaqueToolCallIdentifier(value) {
2550
+ return value.trim().toLowerCase().replace(/^call:/, "call").replace(/[\s_-]+/gu, "");
2551
+ }
2552
+ function firstPresentString2(...values) {
2553
+ for (const value of values) {
2554
+ const normalized = value?.trim();
2555
+ if (normalized) {
2556
+ return normalized;
2557
+ }
2558
+ }
2559
+ return "";
2560
+ }
2561
+ function stringRecordValue(record, key) {
2562
+ if (!record || typeof record !== "object" || Array.isArray(record)) {
2563
+ return void 0;
2564
+ }
2565
+ const value = record[key];
2566
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
2567
+ }
2568
+
2569
+ // shared/workspaceAgentToolCallLabels.ts
2570
+ var TOOL_ACTIVITY_KIND_TRANSLATION_KEYS = {
2571
+ run_command: "agentHost.agentTool.labels.runCommand",
2572
+ read_file: "agentHost.agentTool.labels.readFile",
2573
+ write_file: "agentHost.agentTool.labels.writeFile",
2574
+ edit_file: "agentHost.agentTool.labels.editFile",
2575
+ list_files: "agentHost.agentTool.labels.listFiles",
2576
+ search_files: "agentHost.agentTool.labels.searchFiles",
2577
+ web_search: "agentHost.agentTool.labels.webSearch",
2578
+ web_fetch: "agentHost.agentTool.labels.webFetch",
2579
+ apply_patch: "agentHost.agentTool.labels.applyPatch",
2580
+ use_tool: "agentHost.agentTool.labels.useTool",
2581
+ find_files: "agentHost.agentTool.labels.findFiles",
2582
+ read_command_output: "agentHost.agentTool.labels.readCommandOutput",
2583
+ stop_command: "agentHost.agentTool.labels.stopCommand",
2584
+ read_notebook: "agentHost.agentTool.labels.readNotebook",
2585
+ edit_notebook: "agentHost.agentTool.labels.editNotebook",
2586
+ update_todos: "agentHost.agentTool.labels.updateTodos",
2587
+ delegate_agent: "agentHost.agentTool.labels.delegateAgent",
2588
+ thinking: "agentHost.agentTool.labels.thinking",
2589
+ responding: "agentHost.agentTool.labels.responding",
2590
+ notification: "agentHost.agentTool.labels.notification"
2591
+ };
2592
+ var AGENT_ACTIVITY_KINDS = /* @__PURE__ */ new Set([
2593
+ "thinking",
2594
+ "responding",
2595
+ "notification"
2596
+ ]);
2597
+ var TOOL_NAME_TRANSLATION_KEYS = {
2598
+ bash: "agentHost.agentTool.labels.runCommand",
2599
+ read: "agentHost.agentTool.labels.readFile",
2600
+ write: "agentHost.agentTool.labels.writeFile",
2601
+ edit: "agentHost.agentTool.labels.editFile",
2602
+ glob: "agentHost.agentTool.labels.findFiles",
2603
+ grep: "agentHost.agentTool.labels.searchFiles",
2604
+ websearch: "agentHost.agentTool.labels.webSearch",
2605
+ webfetch: "agentHost.agentTool.labels.webFetch",
2606
+ todowrite: "agentHost.agentTool.labels.updateTodos",
2607
+ task: "agentHost.agentTool.labels.delegateAgent",
2608
+ currenttask: "agentHost.agentTool.labels.currentIssue",
2609
+ agent: "agentHost.agentTool.labels.delegateAgent",
2610
+ closeagent: "agentHost.agentTool.labels.closeAgent",
2611
+ wait: "agentHost.agentTool.labels.waitAgent"
2612
+ };
2613
+ function legacyKindToToolName(kind) {
2614
+ switch (kind) {
2615
+ case "run_command":
2616
+ case "read_command_output":
2617
+ case "stop_command":
2618
+ return "Bash";
2619
+ case "read_file":
2620
+ case "read_notebook":
2621
+ case "list_files":
2622
+ return "Read";
2623
+ case "write_file":
2624
+ return "Write";
2625
+ case "edit_file":
2626
+ case "edit_notebook":
2627
+ case "apply_patch":
2628
+ return "Edit";
2629
+ case "find_files":
2630
+ return "Glob";
2631
+ case "search_files":
2632
+ return "Grep";
2633
+ case "web_search":
2634
+ return "WebSearch";
2635
+ case "web_fetch":
2636
+ return "WebFetch";
2637
+ case "update_todos":
2638
+ return "TodoWrite";
2639
+ case "delegate_agent":
2640
+ return "Task";
2641
+ default:
2642
+ return null;
2643
+ }
2644
+ }
2645
+
2646
+ // shared/workspaceAgentToolCallCanonical.ts
2647
+ function resolveCanonicalToolName(toolName) {
2648
+ const normalized = normalizeToolNameToken(toolName);
2649
+ switch (normalized) {
2650
+ case "imagegeneration":
2651
+ case "imagegen":
2652
+ case "generateimage":
2653
+ case "generatingimage":
2654
+ case "imagegenerate":
2655
+ case "imagegenerator":
2656
+ return "ImageGeneration";
2657
+ case "approval":
2658
+ return "Approval";
2659
+ case "askuserquestion":
2660
+ return "AskUserQuestion";
2661
+ case "enterplanmode":
2662
+ return "EnterPlanMode";
2663
+ case "exitplanmode":
2664
+ return "ExitPlanMode";
2665
+ case "toolsearch":
2666
+ return "ToolSearch";
2667
+ case "skill":
2668
+ return "Skill";
2669
+ case "think":
2670
+ return "Think";
2671
+ case "bash":
2672
+ return "Bash";
2673
+ case "read":
2674
+ return "Read";
2675
+ case "write":
2676
+ return "Write";
2677
+ case "edit":
2678
+ return "Edit";
2679
+ case "glob":
2680
+ return "Glob";
2681
+ case "grep":
2682
+ return "Grep";
2683
+ case "websearch":
2684
+ return "WebSearch";
2685
+ case "webfetch":
2686
+ return "WebFetch";
2687
+ case "todowrite":
2688
+ return "TodoWrite";
2689
+ case "task":
2690
+ case "subagent":
2691
+ case "runsubagent":
2692
+ case "delegatetask":
2693
+ case "delegateagent":
2694
+ return "Agent";
2695
+ case "agent":
2696
+ return "Agent";
2697
+ default:
2698
+ return resolveLegacySnakeCaseToolName(toolName);
2699
+ }
2700
+ }
2701
+ function resolveLegacySnakeCaseToolName(toolName) {
2702
+ const trimmed = toolName?.trim() ?? "";
2703
+ if (!trimmed || !(trimmed in TOOL_ACTIVITY_KIND_TRANSLATION_KEYS)) {
2704
+ return null;
2705
+ }
2706
+ return legacyKindToToolName(trimmed);
2707
+ }
2708
+ function resolveLiveCanonicalToolName(item, rawPayloadToolName, legacyACPToolName) {
2709
+ const itemName = (item.name ?? "").trim();
2710
+ if (rawPayloadToolName && looksLikeOpaqueToolCallID(rawPayloadToolName, item)) {
2711
+ return null;
2712
+ }
2713
+ if (rawPayloadToolName && isCanonicalMcpToolName(rawPayloadToolName, item.callType, item.payload)) {
2714
+ return rawPayloadToolName.trim();
2715
+ }
2716
+ if (!isLiveCanonicalToolCall(item) || !hasCanonicalACPPayload(item.payload)) {
2717
+ return void 0;
2718
+ }
2719
+ if (rawPayloadToolName) {
2720
+ if (!shouldFallBackToLegacyACPToolName(
2721
+ rawPayloadToolName,
2722
+ itemName,
2723
+ legacyACPToolName
2724
+ )) {
2725
+ return rawPayloadToolName.trim();
2726
+ }
2727
+ return null;
2728
+ }
2729
+ const normalizedCallType = (item.callType ?? stringPayloadValue(item.payload, "callType") ?? "").trim().toLowerCase();
2730
+ if (normalizedCallType === "tool" || normalizedCallType === "mcp") {
2731
+ return null;
2732
+ }
2733
+ return void 0;
2734
+ }
2735
+ function shouldFallBackToLegacyACPToolName(rawPayloadToolName, itemName, legacyACPToolName) {
2736
+ const trimmed = rawPayloadToolName.trim();
2737
+ if (!trimmed) {
2738
+ return false;
2739
+ }
2740
+ if (looksLikeOpaqueToolCallIdentifier(trimmed)) {
2741
+ return true;
2742
+ }
2743
+ if (legacyACPToolName === null) {
2744
+ return false;
2745
+ }
2746
+ if (trimmed === itemName) {
2747
+ return true;
2748
+ }
2749
+ return looksLikeOpaqueACPFunctionAlias(trimmed);
2750
+ }
2751
+ function looksLikeOpaqueACPFunctionAlias(value) {
2752
+ return /^[A-Z][a-z0-9]{9,}$/.test(value);
2753
+ }
2754
+ function looksLikeOpaqueToolCallID(value, item) {
2755
+ const trimmed = value.trim();
2756
+ if (!trimmed) {
2757
+ return false;
2758
+ }
2759
+ const payloadCallID = stringPayloadValue(item.payload, "callId") ?? stringPayloadValue(item.payload, "callID") ?? stringPayloadValue(item.payload, "call_id");
2760
+ if (trimmed === item.callId?.trim() || trimmed === payloadCallID?.trim()) {
2761
+ return true;
2762
+ }
2763
+ const lower = trimmed.toLowerCase();
2764
+ if (lower.startsWith("call_")) {
2765
+ return isOpaqueIdentifierTail(trimmed.slice("call_".length));
2766
+ }
2767
+ if (lower.startsWith("ws_")) {
2768
+ return isOpaqueIdentifierTail(trimmed.slice("ws_".length));
2769
+ }
2770
+ return false;
2771
+ }
2772
+ function isOpaqueIdentifierTail(value) {
2773
+ return value.length >= 12 && /^[a-z0-9]+$/i.test(value);
2774
+ }
2775
+ function isCanonicalMcpToolName(toolName, callType, payload) {
2776
+ const trimmed = toolName.trim();
2777
+ if (!trimmed) {
2778
+ return false;
2779
+ }
2780
+ if (trimmed.toLowerCase().startsWith("mcp__")) {
2781
+ return true;
2782
+ }
2783
+ const payloadCallType = stringPayloadValue(payload, "callType");
2784
+ return (callType ?? "").trim().toLowerCase() === "mcp" || (payloadCallType ?? "").trim().toLowerCase() === "mcp";
2785
+ }
2786
+ function isLiveCanonicalToolCall(item) {
2787
+ const itemType = item.itemType.trim().toLowerCase();
2788
+ return itemType === "call.started" || itemType === "call.completed" || itemType === "call.errored";
2789
+ }
2790
+ function hasCanonicalACPPayload(payload) {
2791
+ return Boolean(
2792
+ recordPayloadValue(payload, "acp") || stringPayloadValue(payload, "sessionUpdate")
2793
+ );
2794
+ }
2795
+ function normalizeToolNameToken(value) {
2796
+ return (value ?? "").trim().toLowerCase().replace(/[_\s-]+/g, "");
2797
+ }
2798
+ function recordPayloadValue(value, key) {
2799
+ const nested = value?.[key];
2800
+ return nested && typeof nested === "object" && !Array.isArray(nested) ? nested : void 0;
2801
+ }
2802
+ function stringPayloadValue(value, key) {
2803
+ const nested = value?.[key];
2804
+ return typeof nested === "string" ? nested : void 0;
2805
+ }
2806
+
2807
+ // shared/workspaceAgentToolCallAgentActivity.ts
2808
+ var AGENT_ACTIVITY_KINDS2 = /* @__PURE__ */ new Set([
2809
+ "thinking",
2810
+ "responding",
2811
+ "notification"
2812
+ ]);
2813
+ function isAgentActivityTimelineItem(item) {
2814
+ const activityKey = activityPayloadKey(item);
2815
+ if (activityKey.startsWith("agent.")) {
2816
+ return true;
2817
+ }
2818
+ const metadata = recordValue(item.payload, "metadata");
2819
+ const normalizedKind = normalizeToolToken(
2820
+ firstPresentString3(
2821
+ stringRecordValue2(item.payload, "activityKind"),
2822
+ stringRecordValue2(item.payload, "activity_kind"),
2823
+ stringRecordValue2(metadata, "activityKind"),
2824
+ stringRecordValue2(metadata, "activity_kind")
2825
+ )
2826
+ );
2827
+ if (AGENT_ACTIVITY_KINDS2.has(normalizedKind)) {
2828
+ return true;
2829
+ }
2830
+ const normalizedName = (item.name ?? "").trim().toLowerCase().replace(/[.\-\s]+/gu, "_");
2831
+ return normalizedName.startsWith("agent_");
2832
+ }
2833
+ function activityPayloadKey(item) {
2834
+ const metadata = recordValue(item.payload, "metadata");
2835
+ return firstPresentString3(
2836
+ stringRecordValue2(item.payload, "activityKey"),
2837
+ stringRecordValue2(item.payload, "activity_key"),
2838
+ stringRecordValue2(metadata, "activityKey"),
2839
+ stringRecordValue2(metadata, "activity_key")
2840
+ ).trim().toLowerCase();
2841
+ }
2842
+ function normalizeToolToken(value) {
2843
+ return value?.trim().toLowerCase().replace(/[-\s]+/gu, "_") ?? "";
2844
+ }
2845
+ function recordValue(value, key) {
2846
+ const entry = value?.[key];
2847
+ return typeof entry === "object" && entry !== null && !Array.isArray(entry) ? entry : void 0;
2848
+ }
2849
+ function stringRecordValue2(value, key) {
2850
+ const entry = value?.[key];
2851
+ return typeof entry === "string" ? entry : void 0;
2852
+ }
2853
+ function firstPresentString3(...values) {
2854
+ return values.find(
2855
+ (value) => typeof value === "string" && value.trim().length > 0
2856
+ ) ?? "";
2857
+ }
2858
+
2859
+ // shared/workspaceAgentToolCallSummary.ts
2860
+ function recordValue2(value, key) {
2861
+ const nested = value?.[key];
2862
+ return nested && typeof nested === "object" && !Array.isArray(nested) ? nested : void 0;
2863
+ }
2864
+ function stringRecordValue3(value, key) {
2865
+ const nested = value?.[key];
2866
+ return typeof nested === "string" ? nested : void 0;
2867
+ }
2868
+ function stringArrayRecordValue(value, key) {
2869
+ const nested = value?.[key];
2870
+ return Array.isArray(nested) ? nested.flatMap(
2871
+ (item) => typeof item === "string" && item.trim() ? [item.trim()] : []
2872
+ ) : [];
2873
+ }
2874
+ function stringArrayFirstRecordValue(value, key) {
2875
+ return stringArrayRecordValue(value, key)[0];
2876
+ }
2877
+ function arrayRecordValue(value, key) {
2878
+ const nested = value?.[key];
2879
+ return Array.isArray(nested) ? nested.flatMap(
2880
+ (item) => item && typeof item === "object" && !Array.isArray(item) ? [item] : []
2881
+ ) : [];
2882
+ }
2883
+ function collectToolPaths(metadata, metadataInput, payloadInput) {
2884
+ return Array.from(
2885
+ /* @__PURE__ */ new Set([
2886
+ ...stringArrayRecordValue(metadata, "paths"),
2887
+ ...toolInputPaths(metadataInput),
2888
+ ...toolInputPaths(payloadInput)
2889
+ ])
2890
+ );
2891
+ }
2892
+ function summarizeToolInput(value) {
2893
+ if (!value) return "";
2894
+ for (const key of [
2895
+ "path",
2896
+ "file_path",
2897
+ "filePath",
2898
+ "filepath",
2899
+ "fileName",
2900
+ "filename",
2901
+ "target_path",
2902
+ "targetPath",
2903
+ "url",
2904
+ "uri",
2905
+ "query",
2906
+ "pattern",
2907
+ "prompt",
2908
+ "instruction",
2909
+ "task",
2910
+ "title",
2911
+ "message",
2912
+ "text",
2913
+ "cmd",
2914
+ "command"
2915
+ ]) {
2916
+ const text = summarizeInputField(value, key);
2917
+ if (text) return text;
2918
+ }
2919
+ for (const [key, fieldValue] of Object.entries(value)) {
2920
+ if (isSensitiveKey(key)) continue;
2921
+ const text = summarizeInputValue(key, fieldValue);
2922
+ if (text) return text;
2923
+ }
2924
+ return "";
2925
+ }
2926
+ function summarizeFileChangeCount(...values) {
2927
+ for (const value of values) {
2928
+ const structuredPatch = arrayRecordValue(value, "structuredPatch");
2929
+ if (structuredPatch.length > 1) return `${structuredPatch.length} files`;
2930
+ const files = arrayRecordValue(recordValue2(value, "fileChanges"), "files");
2931
+ if (files.length > 1) return `${files.length} files`;
2932
+ const count = fileChangeCountFromChanges(value?.changes);
2933
+ if (count > 1) return `${count} files`;
2934
+ }
2935
+ return null;
2936
+ }
2937
+ function summarizeTodoProgress(value) {
2938
+ const todos = arrayRecordValue(value, "todos");
2939
+ if (todos.length === 0) return null;
2940
+ const completed = todos.filter(
2941
+ (todo) => normalizeToolToken2(stringRecordValue3(todo, "status")) === "completed"
2942
+ ).length;
2943
+ return `${completed}/${todos.length} completed`;
2944
+ }
2945
+ function summarizeWebDomain(value) {
2946
+ if (!value) return null;
2947
+ try {
2948
+ return new URL(value).hostname.replace(/^www\./, "");
2949
+ } catch {
2950
+ return null;
2951
+ }
2952
+ }
2953
+ function firstPath(paths) {
2954
+ return paths[0] ?? "";
2955
+ }
2956
+ function firstPresentString4(...values) {
2957
+ for (const value of values) {
2958
+ const normalized = value?.trim();
2959
+ if (normalized) return normalized;
2960
+ }
2961
+ return "";
2962
+ }
2963
+ function toolInputPaths(value) {
2964
+ if (!value) return [];
2965
+ return [
2966
+ ...stringValues(
2967
+ value,
2968
+ "path",
2969
+ "file_path",
2970
+ "filePath",
2971
+ "filepath",
2972
+ "fileName",
2973
+ "filename",
2974
+ "target_path",
2975
+ "targetPath"
2976
+ ),
2977
+ ...stringArrayRecordValue(value, "paths"),
2978
+ ...stringArrayRecordValue(value, "file_paths"),
2979
+ ...stringArrayRecordValue(value, "filePaths"),
2980
+ ...stringArrayRecordValue(value, "file_names"),
2981
+ ...stringArrayRecordValue(value, "fileNames"),
2982
+ ...stringArrayRecordValue(value, "filenames")
2983
+ ];
2984
+ }
2985
+ function summarizeInputField(value, key) {
2986
+ const fieldValue = value[key];
2987
+ if (typeof fieldValue === "string")
2988
+ return formatInputSummary(key, fieldValue);
2989
+ if (Array.isArray(fieldValue)) {
2990
+ const items = fieldValue.flatMap(
2991
+ (item) => typeof item === "string" && item.trim() ? [item.trim()] : []
2992
+ ).slice(0, 3);
2993
+ if (items.length > 0) return formatInputSummary(key, items.join(", "));
2994
+ }
2995
+ if (fieldValue && typeof fieldValue === "object" && !Array.isArray(fieldValue)) {
2996
+ for (const [nestedKey, nestedValue] of Object.entries(
2997
+ fieldValue
2998
+ )) {
2999
+ if (isSensitiveKey(nestedKey)) continue;
3000
+ const text = summarizeInputValue(`${key}.${nestedKey}`, nestedValue);
3001
+ if (text) return text;
3002
+ }
3003
+ }
3004
+ return "";
3005
+ }
3006
+ function summarizeInputValue(key, value) {
3007
+ return typeof value === "string" && value.trim() ? formatInputSummary(key, value) : "";
3008
+ }
3009
+ function formatInputSummary(key, value) {
3010
+ const trimmed = value.trim();
3011
+ if (!trimmed) return "";
3012
+ const prefixless = new Set(
3013
+ [
3014
+ "path",
3015
+ "file_path",
3016
+ "filePath",
3017
+ "filepath",
3018
+ "fileName",
3019
+ "filename",
3020
+ "target_path",
3021
+ "targetPath",
3022
+ "url",
3023
+ "uri",
3024
+ "query",
3025
+ "pattern",
3026
+ "cmd",
3027
+ "command"
3028
+ ].map(normalizeToolToken2)
3029
+ );
3030
+ const text = trimmed.length > 140 ? `${trimmed.slice(0, 139)}\u2026` : trimmed;
3031
+ return prefixless.has(normalizeToolToken2(key)) ? text : `${key}: ${text}`;
3032
+ }
3033
+ function isSensitiveKey(key) {
3034
+ const normalized = normalizeToolToken2(key);
3035
+ return [
3036
+ "token",
3037
+ "password",
3038
+ "secret",
3039
+ "api_key",
3040
+ "apikey",
3041
+ "authorization"
3042
+ ].some((part) => normalized.includes(part));
3043
+ }
3044
+ function stringValues(value, ...keys) {
3045
+ return keys.flatMap((key) => {
3046
+ const text = stringRecordValue3(value, key)?.trim();
3047
+ return text ? [text] : [];
3048
+ });
3049
+ }
3050
+ function normalizeToolToken2(value) {
3051
+ return value?.trim().toLowerCase().replace(/[-\s]+/gu, "_") ?? "";
3052
+ }
3053
+
3054
+ // shared/workspaceAgentToolCallPresentation.ts
3055
+ function itemId(item) {
3056
+ return item.eventId.trim() || `id:${item.id}`;
3057
+ }
3058
+ function isGenericToolLabel(normalizedTitle) {
3059
+ return normalizedTitle === "tool" || normalizedTitle === "usetool";
3060
+ }
3061
+ function looksLikeOpaqueToolCallID2(value, item) {
3062
+ const trimmed = value?.trim() ?? "";
3063
+ if (!trimmed) return false;
3064
+ const metadata = recordValue2(item.payload, "metadata");
3065
+ const callID = firstPresentString4(
3066
+ item.callId,
3067
+ stringRecordValue3(item.payload, "callId"),
3068
+ stringRecordValue3(item.payload, "callID"),
3069
+ stringRecordValue3(item.payload, "call_id"),
3070
+ stringRecordValue3(metadata, "callId"),
3071
+ stringRecordValue3(metadata, "callID"),
3072
+ stringRecordValue3(metadata, "call_id")
3073
+ );
3074
+ if (callID && trimmed === callID) return true;
3075
+ const lower = trimmed.toLowerCase();
3076
+ if (lower.startsWith("call_")) return isOpaqueTail(trimmed.slice(5));
3077
+ if (lower.startsWith("ws_")) return isOpaqueTail(trimmed.slice(3));
3078
+ return false;
3079
+ }
3080
+ function toolCallLabel(toolName) {
3081
+ const normalized = normalizeToolNameToken2(toolName);
3082
+ const translationKey = normalized ? TOOL_NAME_TRANSLATION_KEYS[normalized] : null;
3083
+ if (translationKey) return translate(translationKey);
3084
+ if (toolName?.trim()) return humanizeToolName(toolName);
3085
+ return translate("agentHost.agentTool.fallbackName");
3086
+ }
3087
+ function normalizeToolNameToken2(value) {
3088
+ return (value ?? "").trim().toLowerCase().replace(/[_\s-]+/gu, "");
3089
+ }
3090
+ function isOpaqueTail(value) {
3091
+ return value.length >= 12 && /^[a-z0-9]+$/i.test(value);
3092
+ }
3093
+ function humanizeToolName(value) {
3094
+ return value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim().replace(/\b\w/g, (char) => char.toUpperCase());
3095
+ }
3096
+
3097
+ // shared/workspaceAgentToolCallDisplay.ts
3098
+ function isWorkspaceAgentToolCallItem(item) {
3099
+ const itemType = item.itemType.trim().toLowerCase();
3100
+ if (isAgentActivityTimelineItem(item)) {
3101
+ return false;
3102
+ }
3103
+ if (itemType === "call" || itemType.startsWith("call.")) {
3104
+ return true;
3105
+ }
3106
+ if (itemType.startsWith("approval.") || itemType.startsWith("interactive.")) {
3107
+ return true;
3108
+ }
3109
+ const payloadCallType = stringRecordValue3(item.payload, "callType");
3110
+ if (payloadCallType === "approval" || payloadCallType === "interactive") {
3111
+ return true;
3112
+ }
3113
+ return isToolActivityTimelineItem(item);
3114
+ }
3115
+ function buildWorkspaceAgentToolCallDisplay(item) {
3116
+ const toolName = resolveWorkspaceAgentToolName(item);
3117
+ const detail = toolCallDetail(item, toolName);
3118
+ return {
3119
+ id: toolCallId(item),
3120
+ name: toolCallLabel(toolName),
3121
+ ...toolCallStatus(item),
3122
+ ...detail ? { detail } : {}
3123
+ };
3124
+ }
3125
+ function toolCallId(item) {
3126
+ const metadata = recordValue2(item.payload, "metadata");
3127
+ const callId = firstPresentString4(
3128
+ stringRecordValue3(item.payload, "callId"),
3129
+ stringRecordValue3(item.payload, "callID"),
3130
+ stringRecordValue3(item.payload, "call_id"),
3131
+ stringRecordValue3(metadata, "callId"),
3132
+ stringRecordValue3(metadata, "callID"),
3133
+ stringRecordValue3(metadata, "call_id"),
3134
+ item.callId
3135
+ );
3136
+ return callId ? `call:${callId}` : itemId(item);
3137
+ }
3138
+ function resolveWorkspaceAgentToolName(item) {
3139
+ const metadata = recordValue2(item.payload, "metadata");
3140
+ const input = recordValue2(item.payload, "input");
3141
+ const output = recordValue2(item.payload, "output");
3142
+ const rawPayloadToolName = firstPresentString4(
3143
+ stringRecordValue3(item.payload, "toolName"),
3144
+ stringRecordValue3(metadata, "toolName"),
3145
+ claudeCodeToolName(input),
3146
+ claudeCodeToolName(output)
3147
+ );
3148
+ const imageGenerationToolName = resolveImageGenerationCanonicalToolName({
3149
+ toolName: rawPayloadToolName,
3150
+ displayName: item.name,
3151
+ content: item.payload?.content,
3152
+ outputContent: output?.content,
3153
+ inputPrompt: input?.prompt
3154
+ });
3155
+ if (imageGenerationToolName) {
3156
+ return imageGenerationToolName;
3157
+ }
3158
+ const canonicalToolName = resolveCanonicalToolName(rawPayloadToolName);
3159
+ if (canonicalToolName) {
3160
+ return canonicalToolName;
3161
+ }
3162
+ const liveCanonicalToolName = resolveLiveCanonicalToolName(
3163
+ item,
3164
+ rawPayloadToolName,
3165
+ resolveLegacyACPToolName(item)
3166
+ );
3167
+ if (typeof liveCanonicalToolName === "string" && liveCanonicalToolName.trim()) {
3168
+ return liveCanonicalToolName;
3169
+ }
3170
+ if (liveCanonicalToolName === null && !rawPayloadToolName) {
3171
+ return null;
3172
+ }
3173
+ return resolveLegacyToolName(item) ?? resolveLegacyNamedToolName(item);
3174
+ }
3175
+ function resolveFetchToolName(payload) {
3176
+ const input = recordValue2(payload, "input");
3177
+ const action = recordValue2(input, "action");
3178
+ const actionType = normalizeToolToken3(stringRecordValue3(action, "type"));
3179
+ switch (actionType) {
3180
+ case "search":
3181
+ case "search_query":
3182
+ case "web_search":
3183
+ return "WebSearch";
3184
+ case "open_page":
3185
+ case "open":
3186
+ case "fetch":
3187
+ case "web_fetch":
3188
+ return "WebFetch";
3189
+ default:
3190
+ break;
3191
+ }
3192
+ if (firstPresentString4(
3193
+ stringRecordValue3(action, "url"),
3194
+ stringRecordValue3(input, "url")
3195
+ )) {
3196
+ return "WebFetch";
3197
+ }
3198
+ if (firstPresentString4(
3199
+ stringRecordValue3(action, "query"),
3200
+ stringRecordValue3(input, "query"),
3201
+ stringRecordValue3(input, "search_query"),
3202
+ stringRecordValue3(input, "searchQuery")
3203
+ )) {
3204
+ return "WebSearch";
3205
+ }
3206
+ return null;
3207
+ }
3208
+ function resolveLegacyToolName(item) {
3209
+ const metadata = recordValue2(item.payload, "metadata");
3210
+ const rawKind = stringRecordValue3(item.payload, "activityKind") ?? stringRecordValue3(item.payload, "activity_kind") ?? stringRecordValue3(metadata, "activityKind") ?? stringRecordValue3(metadata, "activity_kind");
3211
+ const normalizedKind = normalizeToolToken3(rawKind);
3212
+ if (AGENT_ACTIVITY_KINDS.has(normalizedKind)) {
3213
+ return null;
3214
+ }
3215
+ if (isToolActivityKind(normalizedKind)) {
3216
+ return legacyKindToToolName(normalizedKind);
3217
+ }
3218
+ return resolveLegacyACPToolName(item);
3219
+ }
3220
+ function resolveLegacyACPToolName(item) {
3221
+ const input = recordValue2(item.payload, "input");
3222
+ const normalizedKind = normalizeToolToken3(
3223
+ firstPresentString4(
3224
+ stringRecordValue3(item.payload, "kind"),
3225
+ stringRecordValue3(input, "kind")
3226
+ )
3227
+ );
3228
+ const normalizedTitle = normalizeToolToken3(
3229
+ firstPresentString4(
3230
+ stringRecordValue3(item.payload, "title"),
3231
+ stringRecordValue3(input, "title"),
3232
+ item.name
3233
+ )
3234
+ );
3235
+ const fetchToolName = resolveFetchToolName(item.payload);
3236
+ if (fetchToolName) {
3237
+ return fetchToolName;
3238
+ }
3239
+ if (normalizedKind === "fetch") {
3240
+ return "WebFetch";
3241
+ }
3242
+ if (normalizedKind === "read") {
3243
+ return stringRecordValue3(input, "pattern") ? "Glob" : "Read";
3244
+ }
3245
+ if (normalizedKind === "think") {
3246
+ return normalizedTitle === "update_todo" || Array.isArray(input?.todos) ? "TodoWrite" : "Think";
3247
+ }
3248
+ if (normalizedKind === "search") {
3249
+ switch (normalizedTitle) {
3250
+ case "glob":
3251
+ case "find":
3252
+ case "fd":
3253
+ case "file_search":
3254
+ return "Glob";
3255
+ case "grep":
3256
+ case "rg":
3257
+ case "ripgrep":
3258
+ case "codebase_search":
3259
+ return "Grep";
3260
+ default:
3261
+ return "Bash";
3262
+ }
3263
+ }
3264
+ if (normalizedKind === "other") {
3265
+ switch (normalizedTitle) {
3266
+ case "todowrite":
3267
+ case "updatetodo":
3268
+ return "TodoWrite";
3269
+ case "skill":
3270
+ return "Skill";
3271
+ case "task":
3272
+ case "subagent":
3273
+ case "runsubagent":
3274
+ case "delegatetask":
3275
+ case "delegateagent":
3276
+ case "agent":
3277
+ return "Agent";
3278
+ case "rg":
3279
+ case "ripgrep":
3280
+ return "Grep";
3281
+ case "find":
3282
+ case "fd":
3283
+ return "Glob";
3284
+ default:
3285
+ return null;
3286
+ }
3287
+ }
3288
+ switch (normalizedKind) {
3289
+ case "execute":
3290
+ case "exec":
3291
+ case "command":
3292
+ case "shell":
3293
+ return "Bash";
3294
+ case "edit":
3295
+ case "move":
3296
+ return "Edit";
3297
+ case "delete":
3298
+ return "Write";
3299
+ default:
3300
+ return null;
3301
+ }
3302
+ }
3303
+ function resolveLegacyNamedToolName(item) {
3304
+ const metadata = recordValue2(item.payload, "metadata");
3305
+ const rawTitle = firstPresentString4(
3306
+ stringRecordValue3(item.payload, "tool"),
3307
+ stringRecordValue3(metadata, "tool"),
3308
+ item.name
3309
+ );
3310
+ if (looksLikeOpaqueToolCallID2(rawTitle, item)) {
3311
+ return null;
3312
+ }
3313
+ const normalizedTitle = normalizeToolNameToken2(rawTitle);
3314
+ switch (normalizedTitle) {
3315
+ case "approval":
3316
+ return "Approval";
3317
+ case "askuserquestion":
3318
+ return "AskUserQuestion";
3319
+ case "enterplanmode":
3320
+ return "EnterPlanMode";
3321
+ case "exitplanmode":
3322
+ return "ExitPlanMode";
3323
+ case "toolsearch":
3324
+ return "ToolSearch";
3325
+ case "skill":
3326
+ return "Skill";
3327
+ case "bash":
3328
+ case "shell":
3329
+ case "exec":
3330
+ case "execcommand":
3331
+ case "runshellcommand":
3332
+ return "Bash";
3333
+ case "read":
3334
+ case "readfile":
3335
+ return "Read";
3336
+ case "write":
3337
+ case "writefile":
3338
+ return "Write";
3339
+ case "edit":
3340
+ case "editfile":
3341
+ case "multiedit":
3342
+ return "Edit";
3343
+ case "grep":
3344
+ return "Grep";
3345
+ case "glob":
3346
+ return "Glob";
3347
+ case "websearch":
3348
+ return "WebSearch";
3349
+ case "webfetch":
3350
+ return "WebFetch";
3351
+ case "todowrite":
3352
+ return "TodoWrite";
3353
+ case "task":
3354
+ case "subagent":
3355
+ case "runsubagent":
3356
+ case "delegatetask":
3357
+ case "delegateagent":
3358
+ case "agent":
3359
+ return "Agent";
3360
+ default:
3361
+ break;
3362
+ }
3363
+ const lowerTitle = rawTitle.trim().toLowerCase();
3364
+ if (lowerTitle.startsWith("read ")) {
3365
+ return "Read";
3366
+ }
3367
+ if (lowerTitle.startsWith("write ")) {
3368
+ return "Write";
3369
+ }
3370
+ if (lowerTitle.startsWith("edit ")) {
3371
+ return "Edit";
3372
+ }
3373
+ if (!normalizedTitle || isGenericToolLabel(normalizedTitle) || isOpaqueWorkspaceAgentToolCallIdentifier(rawTitle, item)) {
3374
+ return null;
3375
+ }
3376
+ return rawTitle.trim();
3377
+ }
3378
+ function toolCallStatus(item) {
3379
+ const payloadStatus = firstPresentString4(
3380
+ item.status,
3381
+ stringRecordValue3(item.payload, "status"),
3382
+ stringRecordValue3(item.payload, "activityStatus"),
3383
+ statusFromActivityEventType(activityEventType(item))
3384
+ );
3385
+ switch (normalizeToolToken3(payloadStatus)) {
3386
+ case "active":
3387
+ case "running":
3388
+ case "working":
3389
+ return {
3390
+ status: translate("agentHost.agentTool.statusWorking"),
3391
+ statusKind: "working"
3392
+ };
3393
+ case "completed":
3394
+ case "done":
3395
+ case "success":
3396
+ case "succeeded":
3397
+ return {
3398
+ status: translate("agentHost.agentTool.statusCompleted"),
3399
+ statusKind: "completed"
3400
+ };
3401
+ case "failed":
3402
+ case "error":
3403
+ return {
3404
+ status: translate("agentHost.agentTool.statusFailed"),
3405
+ statusKind: "failed"
3406
+ };
3407
+ case "canceled":
3408
+ return {
3409
+ status: translate("agentHost.agentTool.statusCanceled"),
3410
+ statusKind: "canceled"
3411
+ };
3412
+ case "pending":
3413
+ case "waiting":
3414
+ case "awaiting_approval":
3415
+ case "waiting_approval":
3416
+ case "waiting_input":
3417
+ return {
3418
+ status: translate("agentHost.agentTool.statusWaiting"),
3419
+ statusKind: "waiting"
3420
+ };
3421
+ default:
3422
+ return { status: null, statusKind: null };
3423
+ }
3424
+ }
3425
+ function toolCallDetail(item, toolName) {
3426
+ const metadata = recordValue2(item.payload, "metadata");
3427
+ const metadataInput = recordValue2(metadata, "input");
3428
+ const metadataError = recordValue2(metadata, "error");
3429
+ const payloadInput = recordValue2(item.payload, "input");
3430
+ const payloadOutput = recordValue2(item.payload, "output");
3431
+ const payloadError = recordValue2(item.payload, "error");
3432
+ const paths = collectToolPaths(metadata, metadataInput, payloadInput);
3433
+ const rawToolName = firstPresentString4(
3434
+ stringRecordValue3(metadata, "tool"),
3435
+ stringRecordValue3(item.payload, "tool"),
3436
+ toolNameFromActivityKey(toolActivityKey(item)),
3437
+ item.name
3438
+ );
3439
+ const visibleRawToolName = isOpaqueWorkspaceAgentToolCallIdentifier(
3440
+ rawToolName,
3441
+ item
3442
+ ) ? "" : rawToolName;
3443
+ const fallback = firstPresentString4(
3444
+ commandDetail(
3445
+ item.payload,
3446
+ metadata,
3447
+ metadataInput,
3448
+ metadataError,
3449
+ payloadInput,
3450
+ payloadError
3451
+ ),
3452
+ toolContentDetail(
3453
+ item.payload,
3454
+ metadata,
3455
+ metadataInput,
3456
+ metadataError,
3457
+ payloadInput,
3458
+ payloadError
3459
+ ),
3460
+ item.content,
3461
+ stringRecordValue3(item.payload, "summary"),
3462
+ stringRecordValue3(item.payload, "content"),
3463
+ stringRecordValue3(item.payload, "text"),
3464
+ stringRecordValue3(metadata, "summary")
3465
+ );
3466
+ const query = firstPresentString4(
3467
+ stringRecordValue3(item.payload, "query"),
3468
+ stringArrayFirstRecordValue(item.payload, "search_query"),
3469
+ stringArrayFirstRecordValue(item.payload, "searchQuery"),
3470
+ stringRecordValue3(metadata, "query"),
3471
+ stringRecordValue3(metadataInput, "query"),
3472
+ stringArrayFirstRecordValue(metadataInput, "search_query"),
3473
+ stringArrayFirstRecordValue(metadataInput, "searchQuery"),
3474
+ stringRecordValue3(payloadInput, "query"),
3475
+ stringArrayFirstRecordValue(payloadInput, "search_query"),
3476
+ stringArrayFirstRecordValue(payloadInput, "searchQuery"),
3477
+ stringRecordValue3(recordValue2(payloadInput, "action"), "query"),
3478
+ stringRecordValue3(recordValue2(payloadInput, "action"), "url")
3479
+ );
3480
+ const webTarget = firstPresentString4(
3481
+ query,
3482
+ stringRecordValue3(metadataInput, "url"),
3483
+ stringRecordValue3(payloadInput, "url")
3484
+ );
3485
+ const pattern = firstPresentString4(
3486
+ stringRecordValue3(item.payload, "pattern"),
3487
+ stringRecordValue3(metadata, "pattern"),
3488
+ stringRecordValue3(metadataInput, "pattern"),
3489
+ stringRecordValue3(payloadInput, "pattern")
3490
+ );
3491
+ const command = firstPresentString4(
3492
+ stringRecordValue3(metadata, "command"),
3493
+ stringRecordValue3(metadataInput, "cmd"),
3494
+ stringRecordValue3(metadataInput, "command"),
3495
+ stringRecordValue3(payloadInput, "cmd"),
3496
+ stringRecordValue3(payloadInput, "command")
3497
+ );
3498
+ const path = firstPresentString4(
3499
+ stringRecordValue3(metadataInput, "path"),
3500
+ stringRecordValue3(metadataInput, "file_path"),
3501
+ stringRecordValue3(metadataInput, "fileName"),
3502
+ stringRecordValue3(metadataInput, "filename"),
3503
+ stringRecordValue3(payloadInput, "path"),
3504
+ stringRecordValue3(payloadInput, "file_path"),
3505
+ stringRecordValue3(payloadInput, "fileName"),
3506
+ stringRecordValue3(payloadInput, "filename")
3507
+ );
3508
+ const inputSummary = firstPresentString4(
3509
+ summarizeToolInput(metadataInput),
3510
+ summarizeToolInput(payloadInput)
3511
+ );
3512
+ const normalizedToolName = normalizeToolNameToken2(toolName);
3513
+ const multiFileSummary = summarizeFileChangeCount(
3514
+ payloadOutput,
3515
+ payloadInput,
3516
+ item.payload,
3517
+ metadataInput
3518
+ );
3519
+ const todoSummary = summarizeTodoProgress(payloadInput);
3520
+ const webDomainSummary = summarizeWebDomain(webTarget);
3521
+ const imageGeneration = extractImageGenerationPreview({
3522
+ toolName,
3523
+ displayName: visibleRawToolName,
3524
+ content: item.payload?.content,
3525
+ outputContent: payloadOutput?.content,
3526
+ outputSavedPath: payloadOutput?.savedPath ?? payloadOutput?.saved_path,
3527
+ inputPrompt: payloadInput?.prompt,
3528
+ payloadInputPrompt: metadataInput?.prompt
3529
+ });
3530
+ switch (normalizedToolName) {
3531
+ case "imagegeneration":
3532
+ return imageGeneration.prompt || imageGeneration.imageUri || fallback || inputSummary || null;
3533
+ case "read":
3534
+ case "write":
3535
+ case "edit":
3536
+ case "multiedit":
3537
+ return multiFileSummary || path || firstPath(paths) || fallback || inputSummary || command || null;
3538
+ case "glob":
3539
+ return pattern || query || path || firstPath(paths) || fallback || inputSummary || null;
3540
+ case "bash":
3541
+ return command || path || firstPath(paths) || fallback || inputSummary || null;
3542
+ case "grep":
3543
+ return query || pattern || fallback || inputSummary || command || firstPath(paths) || null;
3544
+ case "websearch":
3545
+ return query || webDomainSummary || pattern || fallback || inputSummary || command || firstPath(paths) || null;
3546
+ case "webfetch":
3547
+ return webDomainSummary || query || pattern || fallback || inputSummary || command || firstPath(paths) || null;
3548
+ case "todowrite":
3549
+ return todoSummary || inputSummary || fallback || null;
3550
+ case "toolsearch":
3551
+ case "skill":
3552
+ case "task":
3553
+ case "agent":
3554
+ return inputSummary || fallback || path || firstPath(paths) || query || pattern || command || visibleRawToolName || null;
3555
+ default:
3556
+ return fallback || command || path || firstPath(paths) || query || pattern || inputSummary || visibleRawToolName || null;
3557
+ }
3558
+ }
3559
+ function commandDetail(payload, metadata, metadataInput, metadataError, payloadInput, payloadError) {
3560
+ const payloadRawInput = recordValue2(payloadInput, "rawInput");
3561
+ return firstPresentString4(
3562
+ stringRecordValue3(payload, "command"),
3563
+ stringRecordValue3(payload, "cmd"),
3564
+ stringRecordValue3(metadata, "command"),
3565
+ stringRecordValue3(metadata, "cmd"),
3566
+ stringRecordValue3(metadataInput, "cmd"),
3567
+ stringRecordValue3(metadataInput, "command"),
3568
+ stringRecordValue3(metadataError, "cmd"),
3569
+ stringRecordValue3(metadataError, "command"),
3570
+ stringRecordValue3(payloadInput, "cmd"),
3571
+ stringRecordValue3(payloadInput, "command"),
3572
+ stringRecordValue3(payloadRawInput, "cmd"),
3573
+ stringRecordValue3(payloadRawInput, "command"),
3574
+ stringRecordValue3(payloadError, "cmd"),
3575
+ stringRecordValue3(payloadError, "command")
3576
+ );
3577
+ }
3578
+ function claudeCodeToolName(value) {
3579
+ const meta = recordValue2(value, "_meta");
3580
+ const claudeCode = recordValue2(meta, "claudeCode");
3581
+ return stringRecordValue3(claudeCode, "toolName");
3582
+ }
3583
+ function toolContentDetail(payload, metadata, metadataInput, metadataError, payloadInput, payloadError) {
3584
+ return firstPresentString4(
3585
+ stringRecordValue3(payload, "query"),
3586
+ stringRecordValue3(payload, "search_query"),
3587
+ stringRecordValue3(payload, "searchQuery"),
3588
+ stringRecordValue3(payload, "pattern"),
3589
+ stringRecordValue3(payload, "glob"),
3590
+ stringRecordValue3(payload, "regex"),
3591
+ stringRecordValue3(payload, "url"),
3592
+ stringRecordValue3(payload, "patch"),
3593
+ stringRecordValue3(metadata, "query"),
3594
+ stringRecordValue3(metadata, "pattern"),
3595
+ stringRecordValue3(metadata, "glob"),
3596
+ stringRecordValue3(metadata, "regex"),
3597
+ stringRecordValue3(metadata, "url"),
3598
+ stringRecordValue3(metadata, "patch"),
3599
+ stringRecordValue3(metadataInput, "query"),
3600
+ stringRecordValue3(metadataInput, "pattern"),
3601
+ stringRecordValue3(metadataInput, "glob"),
3602
+ stringRecordValue3(metadataInput, "regex"),
3603
+ stringRecordValue3(metadataInput, "url"),
3604
+ stringRecordValue3(metadataInput, "patch"),
3605
+ stringRecordValue3(metadataError, "query"),
3606
+ stringRecordValue3(metadataError, "pattern"),
3607
+ stringRecordValue3(metadataError, "url"),
3608
+ stringRecordValue3(payloadInput, "query"),
3609
+ stringRecordValue3(payloadInput, "search_query"),
3610
+ stringRecordValue3(payloadInput, "searchQuery"),
3611
+ stringRecordValue3(payloadInput, "pattern"),
3612
+ stringRecordValue3(payloadInput, "glob"),
3613
+ stringRecordValue3(payloadInput, "regex"),
3614
+ stringRecordValue3(payloadInput, "url"),
3615
+ stringRecordValue3(payloadInput, "patch"),
3616
+ stringRecordValue3(payloadError, "query"),
3617
+ stringRecordValue3(payloadError, "pattern"),
3618
+ stringRecordValue3(payloadError, "url")
3619
+ );
3620
+ }
3621
+ function isToolActivityTimelineItem(item) {
3622
+ const eventType = activityEventType(item);
3623
+ if (!eventType.startsWith("activity.")) {
3624
+ return false;
3625
+ }
3626
+ const activityKey = toolActivityKey(item);
3627
+ if (activityKey.startsWith("tool.")) {
3628
+ return true;
3629
+ }
3630
+ return resolveLegacyToolName(item) !== null;
3631
+ }
3632
+ function activityEventType(item) {
3633
+ const itemType = item.itemType.trim().toLowerCase();
3634
+ if (itemType.startsWith("activity.")) {
3635
+ return itemType;
3636
+ }
3637
+ return firstPresentString4(
3638
+ stringRecordValue3(item.payload, "eventKey"),
3639
+ item.itemType
3640
+ ).trim().toLowerCase();
3641
+ }
3642
+ function statusFromActivityEventType(eventType) {
3643
+ switch (eventType) {
3644
+ case "activity.started":
3645
+ case "call.started":
3646
+ return "running";
3647
+ case "activity.completed":
3648
+ case "call.completed":
3649
+ return "completed";
3650
+ case "activity.failed":
3651
+ case "call.failed":
3652
+ case "call.errored":
3653
+ return "failed";
3654
+ default:
3655
+ return "";
3656
+ }
3657
+ }
3658
+ function toolActivityKey(item) {
3659
+ const metadata = recordValue2(item.payload, "metadata");
3660
+ return firstPresentString4(
3661
+ stringRecordValue3(item.payload, "activityKey"),
3662
+ stringRecordValue3(item.payload, "activity_key"),
3663
+ stringRecordValue3(metadata, "activityKey"),
3664
+ stringRecordValue3(metadata, "activity_key")
3665
+ ).trim().toLowerCase();
3666
+ }
3667
+ function toolNameFromActivityKey(activityKey) {
3668
+ return activityKey.startsWith("tool.") ? activityKey.slice("tool.".length) : "";
3669
+ }
3670
+ function isToolActivityKind(value) {
3671
+ return value in TOOL_ACTIVITY_KIND_TRANSLATION_KEYS;
3672
+ }
3673
+ function normalizeToolToken3(value) {
3674
+ return value?.trim().toLowerCase().replace(/[-\s]+/gu, "_") ?? "";
3675
+ }
3676
+
3677
+ // shared/workspaceAgentTimelineProjectionHelpers.ts
3678
+ function delegatedToolStepFromCall(call) {
3679
+ const payload = normalizedPayload2(call.payload ?? void 0);
3680
+ return {
3681
+ id: call.id,
3682
+ toolUseId: call.id.replace(/^call:/, ""),
3683
+ name: call.name,
3684
+ toolName: call.toolName,
3685
+ callType: call.callType,
3686
+ status: call.status,
3687
+ toolInput: normalizedPayload2(
3688
+ payload?.input
3689
+ ),
3690
+ toolResult: normalizedPayload2(
3691
+ payload?.output
3692
+ ),
3693
+ toolError: normalizedPayload2(
3694
+ payload?.error
3695
+ ),
3696
+ payload,
3697
+ metadata: normalizedPayload2(
3698
+ payload?.metadata
3699
+ ),
3700
+ content: Array.isArray(payload?.content) ? payload.content : null,
3701
+ locations: Array.isArray(payload?.locations) ? payload.locations : null,
3702
+ occurredAtUnixMs: call.occurredAtUnixMs ?? null
3703
+ };
3704
+ }
3705
+ function compareToolCallsAscending(left, right) {
3706
+ return (left.occurredAtUnixMs ?? 0) - (right.occurredAtUnixMs ?? 0) || left.id.localeCompare(right.id);
3707
+ }
3708
+ function parentToolUseIdFromCall(call) {
3709
+ const metadata = normalizedPayload2(
3710
+ call.payload?.metadata
3711
+ );
3712
+ const input = normalizedPayload2(
3713
+ call.payload?.input
3714
+ );
3715
+ const output = normalizedPayload2(
3716
+ call.payload?.output
3717
+ );
3718
+ const error = normalizedPayload2(
3719
+ call.payload?.error
3720
+ );
3721
+ return firstPresentString5(
3722
+ stringRecordValue4(metadata, "parentToolUseId"),
3723
+ stringRecordValue4(call.payload, "parentToolUseId"),
3724
+ claudeCodeMetaValue(input, "parentToolUseId"),
3725
+ claudeCodeMetaValue(output, "parentToolUseId"),
3726
+ claudeCodeMetaValue(error, "parentToolUseId")
3727
+ );
3728
+ }
3729
+ function isTaskLikeToolCall(call) {
3730
+ return [
3731
+ "task",
3732
+ "subagent",
3733
+ "delegatetask",
3734
+ "delegateagent",
3735
+ "agent"
3736
+ ].includes(normalizeToolName3(call.toolName));
3737
+ }
3738
+ function toolCallView(item) {
3739
+ const display = buildWorkspaceAgentToolCallDisplay(item);
3740
+ const preserveTitle = item.itemType.trim().toLowerCase().startsWith("approval.") || item.itemType.trim().toLowerCase().startsWith("interactive.") || firstPresentString5(
3741
+ item.callType,
3742
+ stringRecordValue4(item.payload, "callType")
3743
+ ) === "approval";
3744
+ const fallbackName = preserveTitle ? firstPresentString5(item.name, display.name) : display.name;
3745
+ return withSourceTimelineItems(
3746
+ {
3747
+ id: display.id,
3748
+ name: fallbackName || display.name,
3749
+ toolName: resolveWorkspaceAgentToolName(item),
3750
+ callType: firstPresentString5(
3751
+ item.callType,
3752
+ stringRecordValue4(item.payload, "callType")
3753
+ ),
3754
+ status: display.status,
3755
+ statusKind: display.statusKind,
3756
+ summary: display.detail ?? "",
3757
+ payload: normalizedPayload2(item.payload),
3758
+ turnId: item.turnId?.trim() || void 0,
3759
+ compactSummary: display.detail ?? "",
3760
+ occurredAtUnixMs: item.occurredAtUnixMs ?? item.createdAtUnixMs ?? null
3761
+ },
3762
+ [item]
3763
+ );
3764
+ }
3765
+ function withSourceTimelineItems(value, sourceTimelineItems) {
3766
+ if (!sourceTimelineItems || sourceTimelineItems.length === 0) return value;
3767
+ Object.defineProperty(value, "sourceTimelineItems", {
3768
+ configurable: true,
3769
+ enumerable: false,
3770
+ value: [...sourceTimelineItems],
3771
+ writable: true
3772
+ });
3773
+ return value;
3774
+ }
3775
+ function mergeSourceTimelineItems2(previous, next) {
3776
+ const merged = [...previous ?? [], ...next ?? []];
3777
+ if (merged.length === 0) return void 0;
3778
+ const byKey = /* @__PURE__ */ new Map();
3779
+ for (const item of merged) byKey.set(sourceTimelineItemKey(item), item);
3780
+ return [...byKey.values()].sort(compareTimelineItemsAscending);
3781
+ }
3782
+ function normalizedPayload2(payload) {
3783
+ return payload && typeof payload === "object" ? payload : null;
3784
+ }
3785
+ function visibleErrorFromPayload(payload) {
3786
+ if (stringRecordValue4(payload, "kind") !== "agent_visible_error") return null;
3787
+ return {
3788
+ code: stringRecordValue4(payload, "code"),
3789
+ phase: stringRecordValue4(payload, "phase"),
3790
+ provider: stringRecordValue4(payload, "provider"),
3791
+ detail: stringRecordValue4(payload, "detail"),
3792
+ retryable: booleanRecordValue(payload, "retryable")
3793
+ };
3794
+ }
3795
+ function systemNoticeFromPayload(payload, context) {
3796
+ const commandSemantics = resolveWorkspaceAgentNoticeCommandSemantics({
3797
+ eventId: context.eventId,
3798
+ messageSemantics: context.messageSemantics,
3799
+ payload,
3800
+ status: context.status
3801
+ });
3802
+ if (stringRecordValue4(payload, "kind") !== "agent_system_notice" && !commandSemantics) {
3803
+ return null;
3804
+ }
3805
+ const source = stringRecordValue4(payload, "source");
3806
+ return {
3807
+ noticeKind: stringRecordValue4(payload, "noticeKind"),
3808
+ severity: stringRecordValue4(payload, "severity"),
3809
+ ...source ? { source } : {},
3810
+ ...commandSemantics ? {
3811
+ command: commandSemantics.command,
3812
+ commandStatus: commandSemantics.commandStatus
3813
+ } : {},
3814
+ title: stringRecordValue4(payload, "title"),
3815
+ detail: stringRecordValue4(payload, "detail"),
3816
+ retryable: booleanRecordValue(payload, "retryable")
3817
+ };
3818
+ }
3819
+ function stringRecordValue4(record, key) {
3820
+ if (!record || typeof record !== "object" || Array.isArray(record))
3821
+ return null;
3822
+ const value = record[key];
3823
+ return typeof value === "string" && value.trim() ? value.trim() : null;
3824
+ }
3825
+ function claudeCodeMetaValue(record, key) {
3826
+ const meta = normalizedPayload2(
3827
+ record?._meta
3828
+ );
3829
+ const claudeCode = normalizedPayload2(
3830
+ meta?.claudeCode
3831
+ );
3832
+ return stringRecordValue4(claudeCode, key);
3833
+ }
3834
+ function firstPresentString5(...values) {
3835
+ for (const value of values) {
3836
+ if (typeof value === "string" && value.trim()) return value.trim();
3837
+ }
3838
+ return null;
3839
+ }
3840
+ function summarizeToolCallGroup2(calls) {
3841
+ if (calls.length < 2) return null;
3842
+ const targets = [
3843
+ ...new Set(
3844
+ calls.filter(
3845
+ (call) => ["edit", "multiedit", "write"].includes(
3846
+ normalizeToolName3(call.toolName)
3847
+ )
3848
+ ).map((call) => summarizeCallTarget2(call.summary)).filter((value) => value !== null)
3849
+ )
3850
+ ];
3851
+ if (targets.length === 0) return null;
3852
+ return targets.length === 1 ? `Changed ${targets[0]}` : `Changed ${targets[0]} and ${targets.length - 1} more files`;
3853
+ }
3854
+ function shouldShowProcessingIndicator(session, turns) {
3855
+ if (!sessionHasRunnableIndicatorState(session)) return false;
3856
+ const lastTurn = turns.at(-1);
3857
+ if (!lastTurn) return true;
3858
+ const lastAgentItem = lastTurn.agentItems.at(-1);
3859
+ if (lastAgentItem?.kind === "message" && isTerminalAgentMessageStatus(lastAgentItem.message.statusKind) && !hasActiveRunningTurn(session)) {
3860
+ return false;
3861
+ }
3862
+ return !lastTurn.toolCalls.some(
3863
+ (call) => call.statusKind === "working" || call.statusKind === "waiting"
3864
+ );
3865
+ }
3866
+ function sourceTimelineItemKey(item) {
3867
+ const eventId = item.eventId?.trim();
3868
+ if (eventId) return `event:${eventId}`;
3869
+ if (Number.isFinite(item.id) && item.id > 0) return `id:${item.id}`;
3870
+ const seq = item.seq ?? 0;
3871
+ return seq > 0 ? `seq:${seq}` : `local:${item.itemType}:${item.occurredAtUnixMs ?? 0}`;
3872
+ }
3873
+ function compareTimelineItemsAscending(left, right) {
3874
+ return (left.seq ?? 0) - (right.seq ?? 0) || (left.occurredAtUnixMs ?? left.createdAtUnixMs ?? 0) - (right.occurredAtUnixMs ?? right.createdAtUnixMs ?? 0) || left.id - right.id;
3875
+ }
3876
+ function booleanRecordValue(record, key) {
3877
+ if (!record || typeof record !== "object" || Array.isArray(record))
3878
+ return null;
3879
+ const value = record[key];
3880
+ return typeof value === "boolean" ? value : null;
3881
+ }
3882
+ function normalizeToolName3(name) {
3883
+ return (name ?? "").trim().replace(/[_\s-]+/g, "").toLowerCase();
3884
+ }
3885
+ function summarizeCallTarget2(summary) {
3886
+ const firstLine = summary.trim().split("\n")[0]?.trim() ?? "";
3887
+ if (!firstLine) return null;
3888
+ return firstLine.split(/[\\/]/).filter(Boolean).at(-1) ?? firstLine;
3889
+ }
3890
+ function hasActiveRunningTurn(session) {
3891
+ const activeTurn = session.activeTurn;
3892
+ return Boolean(activeTurn && activeTurn.phase !== "settled");
3893
+ }
3894
+ function sessionHasRunnableIndicatorState(session) {
3895
+ return session.activeTurn ? session.activeTurn.phase !== "settled" : false;
3896
+ }
3897
+ function isTerminalAgentMessageStatus(status) {
3898
+ return status === "completed" || status === "failed" || status === "canceled";
3899
+ }
3900
+
3901
+ // shared/workspaceAgentGoalControlProjection.ts
3902
+ function appendWorkspaceAgentGoalControl(target, item, id, body) {
3903
+ if (item.itemType !== "goal.control") {
3904
+ return false;
3905
+ }
3906
+ const action = normalizedPayload2(item.payload)?.action;
3907
+ if (action !== "pause" && action !== "resume" && action !== "clear" && action !== "set") {
3908
+ return true;
3909
+ }
3910
+ const normalizedBody = body.trim();
3911
+ if (!normalizedBody) {
3912
+ return true;
3913
+ }
3914
+ target.push({
3915
+ id,
3916
+ action,
3917
+ body: normalizedBody,
3918
+ occurredAtUnixMs: item.occurredAtUnixMs ?? item.createdAtUnixMs ?? null,
3919
+ sourceTimelineItems: [item]
3920
+ });
3921
+ return true;
3922
+ }
3923
+
3924
+ // shared/workspaceAgentTimelineMessageHelpers.ts
3925
+ function messageRole(item) {
3926
+ const explicitRole = item.role?.trim().toLowerCase();
3927
+ if (explicitRole === "user") {
3928
+ return "user";
3929
+ }
3930
+ if (explicitRole === "assistant_thinking") {
3931
+ return "thinking";
3932
+ }
3933
+ if (explicitRole === "assistant" || explicitRole === "agent") {
3934
+ return "agent";
3935
+ }
3936
+ const itemType = item.itemType.trim().toLowerCase();
3937
+ if (itemType === "message.user") {
3938
+ return "user";
3939
+ }
3940
+ if (itemType === "message.agent" || itemType === "message.assistant") {
3941
+ return "agent";
3942
+ }
3943
+ if (itemType === "message.assistant_thinking") {
3944
+ return "thinking";
3945
+ }
3946
+ return null;
3947
+ }
3948
+ function messageBody(item) {
3949
+ const payloadContent = item.payload?.content;
3950
+ if (typeof payloadContent === "string" && payloadContent.trim()) {
3951
+ const content2 = payloadContent.trim();
3952
+ return isWorkspaceAgentSyntheticControlMessage(content2) ? "" : content2;
3953
+ }
3954
+ const content = item.content?.trim();
3955
+ if (content) {
3956
+ return isWorkspaceAgentSyntheticControlMessage(content) ? "" : content;
3957
+ }
3958
+ const payloadText = item.payload?.text;
3959
+ if (typeof payloadText !== "string") {
3960
+ return "";
3961
+ }
3962
+ const text = payloadText.trim();
3963
+ return isWorkspaceAgentSyntheticControlMessage(text) ? "" : text;
3964
+ }
3965
+ function thinkingStatusKind(item) {
3966
+ const status = firstPresentString6(
3967
+ item.status,
3968
+ stringRecordValue5(item.payload, "status"),
3969
+ stringRecordValue5(item.payload, "streamState"),
3970
+ stringRecordValue5(item.payload, "messageStreamState")
3971
+ );
3972
+ return messageStatusKind(status);
3973
+ }
3974
+ function messageStatusKind(status) {
3975
+ switch (normalizeStatusToken(status)) {
3976
+ case "active":
3977
+ case "running":
3978
+ case "streaming":
3979
+ case "working":
3980
+ case "inprogress":
3981
+ case "in_progress":
3982
+ return "working";
3983
+ case "completed":
3984
+ case "complete":
3985
+ case "done":
3986
+ case "success":
3987
+ case "succeeded":
3988
+ return "completed";
3989
+ case "failed":
3990
+ case "error":
3991
+ return "failed";
3992
+ case "canceled":
3993
+ return "canceled";
3994
+ case "pending":
3995
+ case "waiting":
3996
+ return "waiting";
3997
+ default:
3998
+ return null;
3999
+ }
4000
+ }
4001
+ function isPlaceholderThinkingBody(body) {
4002
+ const normalized = body.trim();
4003
+ return normalized === "..." || normalized === "\u2026";
4004
+ }
4005
+ var reviewProcessSummaryTitlePattern = /^\*\*(.+?)\*\*(?:\r?\n\s*)?/;
4006
+ function stripReviewProcessSummaryTitle(body) {
4007
+ const match = body.match(reviewProcessSummaryTitlePattern);
4008
+ if (!match) {
4009
+ return body;
4010
+ }
4011
+ return body.slice(match[0].length).trimStart();
4012
+ }
4013
+ function normalizedMessageBody(body) {
4014
+ return body.trim().replace(/\s+/g, " ");
4015
+ }
4016
+ function userMessageProjectionKey(item, body) {
4017
+ const normalizedBody = normalizedMessageBody(body);
4018
+ if (normalizedBody) {
4019
+ return `text:${normalizedBody}`;
4020
+ }
4021
+ if (!hasRenderableUserPromptContent(item.payload?.content)) {
4022
+ return null;
4023
+ }
4024
+ const clientSubmitId = stringRecordValue5(item.payload, "clientSubmitId");
4025
+ return clientSubmitId ? `client-submit:${clientSubmitId}` : `event:${item.eventId}`;
4026
+ }
4027
+ function isRecentDuplicateUserMessage(previous, current) {
4028
+ if (!previous) {
4029
+ return false;
4030
+ }
4031
+ const previousTurnId = previous.turnId?.trim();
4032
+ const currentTurnId = current.turnId?.trim();
4033
+ if (previousTurnId && currentTurnId && previousTurnId === currentTurnId) {
4034
+ return true;
4035
+ }
4036
+ if (previousTurnId && currentTurnId) {
4037
+ return false;
4038
+ }
4039
+ const previousOccurredAt = previous.occurredAtUnixMs ?? 0;
4040
+ const currentOccurredAt = current.occurredAtUnixMs ?? 0;
4041
+ if (previousOccurredAt > 0 && currentOccurredAt > 0) {
4042
+ return Math.abs(currentOccurredAt - previousOccurredAt) <= 6e4;
4043
+ }
4044
+ const previousSeq = previous.seq ?? 0;
4045
+ const currentSeq = current.seq ?? 0;
4046
+ if (previousSeq > 0 && currentSeq > 0) {
4047
+ return Math.abs(currentSeq - previousSeq) <= 5;
4048
+ }
4049
+ return false;
4050
+ }
4051
+ function hasRenderableUserPromptContent(content) {
4052
+ if (!Array.isArray(content)) {
4053
+ return false;
4054
+ }
4055
+ return content.some((candidate) => {
4056
+ if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) {
4057
+ return false;
4058
+ }
4059
+ const block = candidate;
4060
+ if (block.type === "text") {
4061
+ return typeof block.text === "string" && block.text.trim().length > 0;
4062
+ }
4063
+ return block.type === "image" && typeof block.mimeType === "string" && block.mimeType.trim().length > 0;
4064
+ });
4065
+ }
4066
+ function stringRecordValue5(record, key) {
4067
+ if (!record || typeof record !== "object") {
4068
+ return null;
4069
+ }
4070
+ const value = record[key];
4071
+ return typeof value === "string" && value.trim() ? value.trim() : null;
4072
+ }
4073
+ function firstPresentString6(...values) {
4074
+ for (const value of values) {
4075
+ const normalized = value?.trim();
4076
+ if (normalized) {
4077
+ return normalized;
4078
+ }
4079
+ }
4080
+ return null;
4081
+ }
4082
+ function normalizeStatusToken(value) {
4083
+ return (value ?? "").trim().toLowerCase().replace(/[\s-]+/g, "_");
4084
+ }
4085
+
4086
+ // shared/workspaceAgentTurnErrorProjection.ts
4087
+ function enrichProjectedTurnsWithCanonicalErrors({
4088
+ turns,
4089
+ sessionTurns,
4090
+ provider,
4091
+ agentSessionId
4092
+ }) {
4093
+ for (const canonicalTurn of sessionTurns) {
4094
+ if (canonicalTurn.outcome !== "failed" && canonicalTurn.outcome !== "interrupted") {
4095
+ continue;
4096
+ }
4097
+ const detail = canonicalTurn.error?.message.trim() ?? "";
4098
+ if (!detail) {
4099
+ continue;
4100
+ }
4101
+ const turn = turns.get(canonicalTurn.turnId);
4102
+ if (!turn) {
4103
+ continue;
4104
+ }
4105
+ if (turn.agentMessages.some((message2) => message2.visibleError)) {
4106
+ continue;
4107
+ }
4108
+ const matchingMessage = turn.agentMessages.find(
4109
+ (message2) => message2.body.trim() === detail
4110
+ );
4111
+ if (matchingMessage) {
4112
+ matchingMessage.status = "failed";
4113
+ matchingMessage.statusKind = "failed";
4114
+ matchingMessage.visibleError = visibleErrorFromCanonicalTurn(
4115
+ canonicalTurn,
4116
+ provider
4117
+ );
4118
+ continue;
4119
+ }
4120
+ const message = {
4121
+ id: `turn-error:${agentSessionId}:${canonicalTurn.turnId}`,
4122
+ body: detail,
4123
+ status: "failed",
4124
+ statusKind: "failed",
4125
+ turnId: canonicalTurn.turnId,
4126
+ occurredAtUnixMs: canonicalTurn.settledAtUnixMs ?? canonicalTurn.updatedAtUnixMs,
4127
+ visibleError: visibleErrorFromCanonicalTurn(canonicalTurn, provider)
4128
+ };
4129
+ turn.agentMessages.push(message);
4130
+ turn.agentItems.push({ kind: "message", message });
4131
+ }
4132
+ }
4133
+ function visibleErrorFromCanonicalTurn(turn, provider) {
4134
+ return {
4135
+ code: turn.error?.code?.trim() || null,
4136
+ phase: "turn",
4137
+ provider: provider.trim() || null,
4138
+ detail: turn.error?.message.trim() || null,
4139
+ retryable: null
4140
+ };
4141
+ }
4142
+
4143
+ // shared/workspaceAgentTimelineSuppression.ts
4144
+ function toolNameFromItem(item) {
4145
+ return resolveWorkspaceAgentToolName(item);
4146
+ }
4147
+ function normalizeToolName4(name) {
4148
+ return (name ?? "").trim().replace(/[_\s-]+/g, "").toLowerCase();
4149
+ }
4150
+ function suppressedUnavailableAskUserQuestionCallIds(items) {
4151
+ const suppressed = /* @__PURE__ */ new Set();
4152
+ for (const item of items) {
4153
+ if (normalizeToolName4(toolNameFromItem(item)) !== "askuserquestion" || !isUnavailableAskUserQuestionFailure(item)) {
4154
+ continue;
4155
+ }
4156
+ const callId = toolCallSuppressionId(item);
4157
+ if (callId) {
4158
+ suppressed.add(callId);
4159
+ }
4160
+ }
4161
+ return suppressed;
4162
+ }
4163
+ function shouldSuppressToolCall(item, suppressedToolCallIds) {
4164
+ const callId = toolCallSuppressionId(item);
4165
+ return callId ? suppressedToolCallIds.has(callId) : false;
4166
+ }
4167
+ function toolCallSuppressionId(item) {
4168
+ return firstPresentString5(
4169
+ item.callId,
4170
+ stringRecordValue4(item.payload, "callId"),
4171
+ stringRecordValue4(item.payload, "toolCallId")
4172
+ );
4173
+ }
4174
+ function isUnavailableAskUserQuestionFailure(item) {
4175
+ const status = firstPresentString5(
4176
+ item.status,
4177
+ stringRecordValue4(item.payload, "status")
4178
+ );
4179
+ if (status !== "failed") {
4180
+ return false;
4181
+ }
4182
+ const payload = normalizedPayload2(item.payload);
4183
+ const output = normalizedPayload2(
4184
+ payload?.output
4185
+ );
4186
+ const error = normalizedPayload2(
4187
+ payload?.error
4188
+ );
4189
+ const message = firstPresentString5(
4190
+ stringRecordValue4(output, "output"),
4191
+ stringRecordValue4(output, "text"),
4192
+ stringRecordValue4(output, "message"),
4193
+ stringRecordValue4(error, "error"),
4194
+ stringRecordValue4(error, "message"),
4195
+ stringRecordValue4(payload, "error"),
4196
+ stringRecordValue4(payload, "message")
4197
+ );
4198
+ return message?.includes("No such tool available: AskUserQuestion") ?? false;
4199
+ }
4200
+
4201
+ // shared/workspaceAgentTimelineCanonical.ts
4202
+ function buildCanonicalWorkspaceAgentDetailView({
4203
+ activity,
4204
+ session,
4205
+ sessionTurns = [],
4206
+ timelineItems,
4207
+ workspaceRoot = null
4208
+ }) {
4209
+ const turns = /* @__PURE__ */ new Map();
4210
+ const goalControls = [];
4211
+ const recentUserMessages = /* @__PURE__ */ new Map();
4212
+ const seenThinkingMessages = /* @__PURE__ */ new Set();
4213
+ let activeSequenceTurnId = null;
4214
+ const sortedTimelineItems = [...timelineItems].sort(
4215
+ compareTimelineItemsAscending2
4216
+ );
4217
+ const suppressedToolCallIds = suppressedUnavailableAskUserQuestionCallIds(sortedTimelineItems);
4218
+ for (const item of sortedTimelineItems) {
4219
+ const role = messageRole(item);
4220
+ const body = messageBody(item);
4221
+ const explicitTurnId = item.turnId?.trim();
4222
+ if (appendWorkspaceAgentGoalControl(goalControls, item, itemId2(item), body)) {
4223
+ continue;
4224
+ }
4225
+ if (role === "user") {
4226
+ const turnId2 = explicitTurnId || `seq:${item.seq || item.id}`;
4227
+ const projectionKey = userMessageProjectionKey(item, body);
4228
+ if (!projectionKey) {
4229
+ continue;
4230
+ }
4231
+ if (isRecentDuplicateUserMessage(
4232
+ recentUserMessages.get(projectionKey),
4233
+ item
4234
+ )) {
4235
+ continue;
4236
+ }
4237
+ activeSequenceTurnId = turnId2;
4238
+ const turn2 = getTurn(turns, turnId2);
4239
+ const message = withSourceTimelineItems(
4240
+ {
4241
+ id: itemId2(item),
4242
+ body,
4243
+ turnId: turnId2,
4244
+ occurredAtUnixMs: item.occurredAtUnixMs ?? item.createdAtUnixMs ?? null
4245
+ },
4246
+ [item]
4247
+ );
4248
+ turn2.userMessages.push(message);
4249
+ turn2.userMessage ??= message;
4250
+ recentUserMessages.set(projectionKey, item);
4251
+ continue;
4252
+ }
4253
+ const turnId = explicitTurnId || activeSequenceTurnId || `seq:${item.seq || item.id}`;
4254
+ const turn = getTurn(turns, turnId);
4255
+ if (isCollaborationTimelineItem(item)) {
4256
+ const status = firstPresentString5(
4257
+ item.status,
4258
+ stringRecordValue4(item.payload, "status")
4259
+ );
4260
+ const statusKind = messageStatusKind(status);
4261
+ const message = withSourceTimelineItems(
4262
+ {
4263
+ id: itemId2(item),
4264
+ body,
4265
+ ...status ? { status } : {},
4266
+ ...statusKind ? { statusKind } : {},
4267
+ turnId,
4268
+ occurredAtUnixMs: item.occurredAtUnixMs ?? item.createdAtUnixMs ?? null
4269
+ },
4270
+ [item]
4271
+ );
4272
+ turn.agentMessages.push(message);
4273
+ turn.agentItems.push({ kind: "message", message });
4274
+ continue;
4275
+ }
4276
+ if (isWorkspaceAgentToolCallItem(item)) {
4277
+ if (shouldSuppressToolCall(item, suppressedToolCallIds)) {
4278
+ continue;
4279
+ }
4280
+ upsertToolCall(turn, item);
4281
+ continue;
4282
+ }
4283
+ if (role === "thinking" && body) {
4284
+ const payload = normalizedPayload2(item.payload);
4285
+ if (payload?.messageKind === "review-process") {
4286
+ const status = firstPresentString5(
4287
+ item.status,
4288
+ stringRecordValue4(payload, "status")
4289
+ );
4290
+ const statusKind2 = messageStatusKind(status);
4291
+ const message = withSourceTimelineItems(
4292
+ {
4293
+ id: itemId2(item),
4294
+ body: stripReviewProcessSummaryTitle(body),
4295
+ ...status ? { status } : {},
4296
+ ...statusKind2 ? { statusKind: statusKind2 } : {},
4297
+ turnId,
4298
+ occurredAtUnixMs: item.occurredAtUnixMs ?? item.createdAtUnixMs ?? null
4299
+ },
4300
+ [item]
4301
+ );
4302
+ turn.agentMessages.push(message);
4303
+ turn.agentItems.push({ kind: "message", message });
4304
+ continue;
4305
+ }
4306
+ if (isPlaceholderThinkingBody(body)) {
4307
+ continue;
4308
+ }
4309
+ const duplicateKey = `${turnId}\0${normalizedMessageBody(body)}`;
4310
+ if (seenThinkingMessages.has(duplicateKey)) {
4311
+ continue;
4312
+ }
4313
+ seenThinkingMessages.add(duplicateKey);
4314
+ const statusKind = thinkingStatusKind(item);
4315
+ const thinking = withSourceTimelineItems(
4316
+ {
4317
+ id: itemId2(item),
4318
+ body,
4319
+ ...statusKind ? { statusKind } : {},
4320
+ turnId,
4321
+ occurredAtUnixMs: item.occurredAtUnixMs ?? item.createdAtUnixMs ?? null
4322
+ },
4323
+ [item]
4324
+ );
4325
+ turn.agentItems.push({ kind: "thinking", thinking });
4326
+ continue;
4327
+ }
4328
+ if (role === "agent" && body) {
4329
+ const payload = normalizedPayload2(item.payload);
4330
+ const visibleError = visibleErrorFromPayload(payload);
4331
+ const systemNotice = systemNoticeFromPayload(payload, item);
4332
+ const status = firstPresentString5(
4333
+ item.status,
4334
+ stringRecordValue4(payload, "status")
4335
+ );
4336
+ const statusKind = messageStatusKind(status);
4337
+ const message = withSourceTimelineItems(
4338
+ {
4339
+ id: itemId2(item),
4340
+ body,
4341
+ ...status ? { status } : {},
4342
+ ...statusKind ? { statusKind } : {},
4343
+ turnId,
4344
+ occurredAtUnixMs: item.occurredAtUnixMs ?? item.createdAtUnixMs ?? null,
4345
+ ...visibleError ? { visibleError } : {},
4346
+ ...systemNotice ? { systemNotice } : {}
4347
+ },
4348
+ [item]
4349
+ );
4350
+ turn.agentMessages.push(message);
4351
+ turn.agentItems.push({ kind: "message", message });
4352
+ }
4353
+ }
4354
+ enrichProjectedTurnsWithCanonicalErrors({
4355
+ turns,
4356
+ sessionTurns: sessionTurns.length > 0 ? sessionTurns : session.latestTurn ? [session.latestTurn] : [],
4357
+ provider: session.provider,
4358
+ agentSessionId: session.agentSessionId
4359
+ });
4360
+ const visibleTurns = [...turns.values()].filter(
4361
+ (turn) => turn.userMessages.length > 0 || turn.agentItems.length > 0
4362
+ );
4363
+ nestDelegatedToolCallsAcrossTurns(visibleTurns);
4364
+ visibleTurns.forEach(mergeBackgroundTerminalContinuations);
4365
+ visibleTurns.forEach((turn) => {
4366
+ turn.rawAgentItems = [...turn.agentItems];
4367
+ turn.agentItems = regroupAgentItems(turn.agentItems);
4368
+ });
4369
+ return {
4370
+ activity,
4371
+ session,
4372
+ sessionTurns,
4373
+ cwd: session.cwd.trim(),
4374
+ workspaceRoot: workspaceRoot?.trim() || null,
4375
+ goalControls,
4376
+ turns: visibleTurns,
4377
+ showProcessingIndicator: shouldShowProcessingIndicator(
4378
+ session,
4379
+ visibleTurns
4380
+ )
4381
+ };
4382
+ }
4383
+ function getTurn(turns, id) {
4384
+ const existing = turns.get(id);
4385
+ if (existing) {
4386
+ return existing;
4387
+ }
4388
+ const turn = {
4389
+ id,
4390
+ userMessage: null,
4391
+ userMessages: [],
4392
+ agentMessages: [],
4393
+ toolCalls: [],
4394
+ toolCallCount: 0,
4395
+ hasFailedToolCall: false,
4396
+ agentItems: []
4397
+ };
4398
+ turns.set(id, turn);
4399
+ return turn;
4400
+ }
4401
+ function compareTimelineItemsAscending2(left, right) {
4402
+ const leftSeq = left.seq ?? 0;
4403
+ const rightSeq = right.seq ?? 0;
4404
+ if (leftSeq > 0 && rightSeq > 0 && leftSeq !== rightSeq) {
4405
+ return leftSeq - rightSeq;
4406
+ }
4407
+ return (left.occurredAtUnixMs ?? left.createdAtUnixMs ?? 0) - (right.occurredAtUnixMs ?? right.createdAtUnixMs ?? 0) || leftSeq - rightSeq || left.id - right.id;
4408
+ }
4409
+ function itemId2(item) {
4410
+ const eventId = item.eventId?.trim();
4411
+ if (eventId) {
4412
+ return eventId;
4413
+ }
4414
+ const seq = item.seq ?? 0;
4415
+ return seq > 0 ? `seq:${seq}` : `id:${item.id}`;
4416
+ }
4417
+ function upsertToolCall(turn, item) {
4418
+ const call = toolCallView(item);
4419
+ const existingIndex = turn.toolCalls.findIndex(
4420
+ (existing) => existing.id === call.id
4421
+ );
4422
+ if (existingIndex >= 0) {
4423
+ const existing = turn.toolCalls[existingIndex];
4424
+ if (!existing) {
4425
+ return;
4426
+ }
4427
+ turn.toolCalls[existingIndex] = mergeToolCallDetail(existing, call);
4428
+ } else {
4429
+ turn.toolCalls.push(call);
4430
+ }
4431
+ turn.toolCallCount = turn.toolCalls.length;
4432
+ turn.hasFailedToolCall = turn.toolCalls.some(
4433
+ (existing) => existing.statusKind === "failed"
4434
+ );
4435
+ upsertToolCallAgentItem(turn, call, itemId2(item));
4436
+ }
4437
+ function upsertToolCallAgentItem(turn, call, sourceId) {
4438
+ for (const entry2 of turn.agentItems) {
4439
+ if (entry2.kind !== "tool-calls") {
4440
+ continue;
4441
+ }
4442
+ const existingIndex = entry2.toolCalls.findIndex(
4443
+ (existing) => existing.id === call.id
4444
+ );
4445
+ if (existingIndex >= 0) {
4446
+ const existing = entry2.toolCalls[existingIndex];
4447
+ if (!existing) {
4448
+ continue;
4449
+ }
4450
+ entry2.toolCalls[existingIndex] = mergeToolCallDetail(existing, call);
4451
+ refreshToolCallAgentItem(entry2);
4452
+ return;
4453
+ }
4454
+ }
4455
+ const entry = {
4456
+ kind: "tool-calls",
4457
+ id: `tools:${sourceId}`,
4458
+ toolCalls: [call],
4459
+ toolCallCount: 1,
4460
+ hasFailedToolCall: call.statusKind === "failed"
4461
+ };
4462
+ turn.agentItems.push(entry);
4463
+ }
4464
+ function refreshToolCallAgentItem(entry) {
4465
+ entry.toolCallCount = entry.toolCalls.length;
4466
+ entry.hasFailedToolCall = entry.toolCalls.some(
4467
+ (existing) => existing.statusKind === "failed"
4468
+ );
4469
+ const summary = summarizeToolCallGroup2(entry.toolCalls);
4470
+ if (summary) {
4471
+ entry.summary = summary;
4472
+ } else {
4473
+ delete entry.summary;
4474
+ }
4475
+ }
4476
+ function regroupAgentItems(items) {
4477
+ const regrouped = [];
4478
+ let pending = [];
4479
+ const flushPending = () => {
4480
+ if (pending.length === 0) {
4481
+ return;
4482
+ }
4483
+ const groupedCalls = pending.flatMap((item) => item.toolCalls);
4484
+ if (groupedCalls.length >= 2) {
4485
+ regrouped.push({
4486
+ kind: "tool-calls",
4487
+ id: pending.map((item) => item.id).join("+"),
4488
+ toolCalls: groupedCalls,
4489
+ toolCallCount: groupedCalls.length,
4490
+ hasFailedToolCall: groupedCalls.some(
4491
+ (call) => call.statusKind === "failed"
4492
+ ),
4493
+ summary: summarizeToolCallGroup2(groupedCalls),
4494
+ groupEntries: pending.flatMap(
4495
+ (item) => item.toolCalls.map((call) => ({ kind: "tool-call", call }))
4496
+ )
4497
+ });
4498
+ } else {
4499
+ regrouped.push(...pending);
4500
+ }
4501
+ pending = [];
4502
+ };
4503
+ for (const item of items) {
4504
+ if (item.kind === "tool-calls" && isGroupableToolCallItem(item)) {
4505
+ pending.push(item);
4506
+ continue;
4507
+ }
4508
+ flushPending();
4509
+ regrouped.push(item);
4510
+ }
4511
+ flushPending();
4512
+ return regrouped;
4513
+ }
4514
+ function isGroupableToolCallItem(item) {
4515
+ return item.toolCalls.length === 1 && item.toolCalls.every((call) => isGroupableToolCall2(call));
4516
+ }
4517
+ function mergeToolCallDetail(previous, next) {
4518
+ return withSourceTimelineItems(
4519
+ {
4520
+ ...next,
4521
+ name: next.name || previous.name,
4522
+ toolName: next.toolName || previous.toolName,
4523
+ callType: next.callType || previous.callType,
4524
+ summary: next.summary || previous.summary,
4525
+ payload: next.payload ?? previous.payload
4526
+ },
4527
+ mergeSourceTimelineItems2(
4528
+ previous.sourceTimelineItems,
4529
+ next.sourceTimelineItems
4530
+ )
4531
+ );
4532
+ }
4533
+ function mergeBackgroundTerminalContinuations(turn) {
4534
+ if (turn.agentItems.length === 0 || turn.toolCalls.length === 0) {
4535
+ return;
4536
+ }
4537
+ const removedCallIDs = /* @__PURE__ */ new Set();
4538
+ const singleCallItems = turn.agentItems.filter(
4539
+ (item) => item.kind === "tool-calls" && item.toolCalls.length === 1
4540
+ );
4541
+ const turnToolIndexByID = new Map(
4542
+ turn.toolCalls.map((call, index) => [call.id, index])
4543
+ );
4544
+ for (let index = 0; index < singleCallItems.length - 1; index += 1) {
4545
+ const item = singleCallItems[index];
4546
+ const primaryCall = item?.toolCalls[0];
4547
+ if (!item || !primaryCall) {
4548
+ continue;
4549
+ }
4550
+ const terminalSessionID = backgroundTerminalSessionID(primaryCall);
4551
+ if (!terminalSessionID) {
4552
+ continue;
4553
+ }
4554
+ const continuationCall = singleCallItems[index + 1]?.toolCalls[0];
4555
+ if (!continuationCall || !isBackgroundTerminalContinuation(continuationCall, terminalSessionID)) {
4556
+ continue;
4557
+ }
4558
+ const mergedCall = mergeBackgroundTerminalCall(
4559
+ primaryCall,
4560
+ continuationCall
4561
+ );
4562
+ item.toolCalls[0] = mergedCall;
4563
+ const turnToolIndex = turnToolIndexByID.get(primaryCall.id);
4564
+ if (turnToolIndex !== void 0) {
4565
+ turn.toolCalls[turnToolIndex] = mergedCall;
4566
+ }
4567
+ refreshToolCallAgentItem(item);
4568
+ removedCallIDs.add(continuationCall.id);
4569
+ index += 1;
4570
+ }
4571
+ if (removedCallIDs.size === 0) {
4572
+ return;
4573
+ }
4574
+ turn.agentItems = turn.agentItems.filter(
4575
+ (item) => item.kind !== "tool-calls" || item.toolCalls.every((call) => !removedCallIDs.has(call.id))
4576
+ );
4577
+ turn.toolCalls = turn.toolCalls.filter(
4578
+ (call) => !removedCallIDs.has(call.id)
4579
+ );
4580
+ turn.toolCallCount = turn.toolCalls.length;
4581
+ turn.hasFailedToolCall = turn.toolCalls.some(
4582
+ (existing) => existing.statusKind === "failed"
4583
+ );
4584
+ }
4585
+ function mergeBackgroundTerminalCall(primary, continuation) {
4586
+ const continuationOutput = normalizedPayload2(
4587
+ continuation.payload?.output
4588
+ );
4589
+ const mergedPayload = primary.payload ? { ...primary.payload } : {};
4590
+ if (continuationOutput) {
4591
+ mergedPayload.output = continuationOutput;
4592
+ }
4593
+ return {
4594
+ ...primary,
4595
+ status: continuation.status || primary.status,
4596
+ statusKind: continuation.statusKind || primary.statusKind,
4597
+ payload: Object.keys(mergedPayload).length > 0 ? mergedPayload : primary.payload,
4598
+ occurredAtUnixMs: continuation.occurredAtUnixMs ?? primary.occurredAtUnixMs
4599
+ };
4600
+ }
4601
+ function nestDelegatedToolCallsAcrossTurns(turns) {
4602
+ if (turns.length === 0) {
4603
+ return;
4604
+ }
4605
+ const parentCalls = /* @__PURE__ */ new Map();
4606
+ const callTurnByID = /* @__PURE__ */ new Map();
4607
+ for (const turn of turns) {
4608
+ for (const call of turn.toolCalls) {
4609
+ parentCalls.set(call.id, call);
4610
+ parentCalls.set(call.id.replace(/^call:/, ""), call);
4611
+ callTurnByID.set(call.id, turn);
4612
+ callTurnByID.set(call.id.replace(/^call:/, ""), turn);
4613
+ }
4614
+ }
4615
+ const childCallsByParent = /* @__PURE__ */ new Map();
4616
+ for (const turn of turns) {
4617
+ for (const call of turn.toolCalls) {
4618
+ const parentToolUseId = parentToolUseIdFromCall(call);
4619
+ if (!parentToolUseId) {
4620
+ continue;
4621
+ }
4622
+ const parentCall = parentCalls.get(parentToolUseId);
4623
+ if (!parentCall || !isTaskLikeToolCall(parentCall)) {
4624
+ continue;
4625
+ }
4626
+ const children = childCallsByParent.get(parentToolUseId) ?? [];
4627
+ children.push(call);
4628
+ childCallsByParent.set(parentToolUseId, children);
4629
+ }
4630
+ }
4631
+ if (childCallsByParent.size === 0) {
4632
+ return;
4633
+ }
4634
+ const removeIDsByTurn = /* @__PURE__ */ new Map();
4635
+ for (const [parentID, childCalls] of childCallsByParent.entries()) {
4636
+ const parentCall = parentCalls.get(parentID);
4637
+ if (!parentCall) {
4638
+ continue;
4639
+ }
4640
+ appendDelegatedToolSteps(parentCall, childCalls);
4641
+ for (const childCall of childCalls) {
4642
+ const childTurn = callTurnByID.get(childCall.id);
4643
+ if (!childTurn) {
4644
+ continue;
4645
+ }
4646
+ const removeIDs = removeIDsByTurn.get(childTurn) ?? /* @__PURE__ */ new Set();
4647
+ removeIDs.add(childCall.id);
4648
+ removeIDsByTurn.set(childTurn, removeIDs);
4649
+ }
4650
+ }
4651
+ for (const [turn, removeIDs] of removeIDsByTurn.entries()) {
4652
+ pruneTurnToolCalls(turn, removeIDs);
4653
+ }
4654
+ }
4655
+ function backgroundTerminalSessionID(call) {
4656
+ const outputText = stringRecordValue4(call.payload?.output, "output");
4657
+ if (!outputText) {
4658
+ return null;
4659
+ }
4660
+ const match = outputText.match(/Process running with session ID (\d+)/i);
4661
+ return match?.[1] ?? null;
4662
+ }
4663
+ function isBackgroundTerminalContinuation(call, sessionID) {
4664
+ const input = normalizedPayload2(
4665
+ call.payload?.input
4666
+ );
4667
+ const inputSessionID = firstPresentString5(
4668
+ stringRecordValue4(input, "session_id"),
4669
+ stringRecordValue4(input, "sessionId")
4670
+ );
4671
+ if (inputSessionID !== sessionID) {
4672
+ return false;
4673
+ }
4674
+ const chars = firstPresentString5(stringRecordValue4(input, "chars")) ?? "";
4675
+ if (chars !== "") {
4676
+ return false;
4677
+ }
4678
+ return stringRecordValue4(call.payload?.output, "output") !== null;
4679
+ }
4680
+ function isGroupableToolCall2(call) {
4681
+ if (call.callType === "approval" || call.callType === "interactive" || call.callType === "subagent") {
4682
+ return false;
4683
+ }
4684
+ switch (normalizeToolName4(call.toolName)) {
4685
+ case "askuserquestion":
4686
+ case "enterplanmode":
4687
+ case "exitplanmode":
4688
+ case "task":
4689
+ case "subagent":
4690
+ case "delegatetask":
4691
+ return false;
4692
+ default:
4693
+ return true;
4694
+ }
4695
+ }
4696
+ function pruneTurnToolCalls(turn, removeIDs) {
4697
+ if (removeIDs.size === 0) {
4698
+ return;
4699
+ }
4700
+ turn.toolCalls = turn.toolCalls.filter((call) => !removeIDs.has(call.id));
4701
+ turn.toolCallCount = turn.toolCalls.length;
4702
+ turn.hasFailedToolCall = turn.toolCalls.some(
4703
+ (existing) => existing.statusKind === "failed"
4704
+ );
4705
+ turn.agentItems = turn.agentItems.flatMap((item) => {
4706
+ if (item.kind !== "tool-calls") {
4707
+ return [item];
4708
+ }
4709
+ const toolCalls = item.toolCalls.filter(
4710
+ (call) => !removeIDs.has(call.id)
4711
+ );
4712
+ if (toolCalls.length === 0) {
4713
+ return [];
4714
+ }
4715
+ const nextItem = {
4716
+ ...item,
4717
+ toolCalls
4718
+ };
4719
+ refreshToolCallAgentItem(nextItem);
4720
+ return [nextItem];
4721
+ });
4722
+ }
4723
+ function appendDelegatedToolSteps(parentCall, childCalls) {
4724
+ const nextPayload = parentCall.payload ? { ...parentCall.payload } : {};
4725
+ const nextMetadata = normalizedPayload2(
4726
+ nextPayload.metadata
4727
+ ) ?? {};
4728
+ const existingSteps = Array.isArray(nextMetadata.steps) ? [...nextMetadata.steps] : [];
4729
+ const existingStepIDs = new Set(
4730
+ existingSteps.map(
4731
+ (step) => normalizedPayload2(step)
4732
+ ).map(
4733
+ (step) => stringRecordValue4(step, "toolUseId") ?? stringRecordValue4(step, "id")
4734
+ ).filter((value) => Boolean(value))
4735
+ );
4736
+ for (const childCall of [...childCalls].sort(compareToolCallsAscending)) {
4737
+ const step = delegatedToolStepFromCall(childCall);
4738
+ const stepID = stringRecordValue4(step, "toolUseId") ?? stringRecordValue4(step, "id");
4739
+ if (stepID && existingStepIDs.has(stepID)) {
4740
+ continue;
4741
+ }
4742
+ if (stepID) {
4743
+ existingStepIDs.add(stepID);
4744
+ }
4745
+ existingSteps.push(step);
4746
+ }
4747
+ nextMetadata.steps = existingSteps;
4748
+ nextPayload.metadata = nextMetadata;
4749
+ parentCall.payload = nextPayload;
4750
+ }
4751
+
4752
+ export {
4753
+ resolveWorkspaceAgentNoticeCommandSemantics,
4754
+ isWorkspaceAgentToolCallItem,
4755
+ resolveWorkspaceAgentToolName,
4756
+ buildCanonicalWorkspaceAgentDetailView,
4757
+ agentTranscriptRowHasPresentationKind,
4758
+ normalizeAgentApprovalOptions,
4759
+ projectAgentTaskStepTool,
4760
+ pastedTextDraftDisplayName,
4761
+ normalizeAgentPatchText,
4762
+ extractAgentPatchPath,
4763
+ inferAgentPatchChangeType,
4764
+ projectAgentConversationVM,
4765
+ latestAssistantMessageText,
4766
+ reconcileProjectedAgentConversationVM
4767
+ };
4768
+ //# sourceMappingURL=chunk-A4KKC324.js.map