@drisp/cli 0.4.2 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@ import "./chunk-HXBCZAP7.js";
3
3
  import {
4
4
  channelSidecarDir,
5
5
  rotateGatewayToken
6
- } from "./chunk-6TJHAUNB.js";
6
+ } from "./chunk-M44KEGM7.js";
7
7
  import {
8
8
  CREDENTIAL_SOURCES_TRIED,
9
9
  EXEC_EXIT_CODE,
@@ -34,8 +34,9 @@ import {
34
34
  getGlyphs,
35
35
  getMostRecentAthenaSession,
36
36
  getSessionMeta,
37
- handleEvent,
38
37
  hintGlyphs,
38
+ ingestRuntimeDecision,
39
+ ingestRuntimeEvent,
39
40
  isScopedPermissionsRequest,
40
41
  isSubagentTool,
41
42
  isSupportedGatewayUrl,
@@ -49,10 +50,12 @@ import {
49
50
  probeSkipReason,
50
51
  processRegistry,
51
52
  progressGlyphs,
53
+ readAttachmentMirror,
52
54
  readGatewayClientConfig,
53
55
  readPidLock,
54
56
  register,
55
57
  registerCleanupOnExit,
58
+ removeAttachmentMirror,
56
59
  resolveClaudeBinary,
57
60
  resolveClaudeSettingsSurfacePaths,
58
61
  resolveHarnessAdapter,
@@ -67,9 +70,10 @@ import {
67
70
  startSessionBridge,
68
71
  supportsSessionApproval,
69
72
  todoGlyphSet,
73
+ writeAttachmentMirror,
70
74
  writeGatewayClientConfig,
71
75
  wsClientOptionsForEndpoint
72
- } from "./chunk-WHELLVBL.js";
76
+ } from "./chunk-PJUDHH4R.js";
73
77
  import {
74
78
  generateId as generateId2
75
79
  } from "./chunk-BTKQ67RE.js";
@@ -128,7 +132,7 @@ import {
128
132
  useWorkflowSessionController,
129
133
  writeGlobalConfig,
130
134
  writeProjectConfig
131
- } from "./chunk-GE6PPB6Z.js";
135
+ } from "./chunk-5VK2ZMVV.js";
132
136
 
133
137
  // src/app/entry/cli.tsx
134
138
  import { render } from "ink";
@@ -144,7 +148,7 @@ import process6 from "process";
144
148
  import React9, {
145
149
  Profiler,
146
150
  useState as useState18,
147
- useCallback as useCallback18,
151
+ useCallback as useCallback19,
148
152
  useRef as useRef16,
149
153
  useEffect as useEffect14,
150
154
  useMemo as useMemo17
@@ -1726,7 +1730,7 @@ function useFeed(runtime, messages = [], initialAllowedTools, sessionStore, opti
1726
1730
  const [isServerRunning, setIsServerRunning] = useState4(
1727
1731
  () => runtime.getStatus() === "running"
1728
1732
  );
1729
- const [runtimeError, setRuntimeError] = useState4(
1733
+ const [runtimeError2, setRuntimeError] = useState4(
1730
1734
  () => runtime.getLastError()
1731
1735
  );
1732
1736
  const restoredTokens = useMemo3(
@@ -1934,19 +1938,16 @@ function useFeed(runtime, messages = [], initialAllowedTools, sessionStore, opti
1934
1938
  `useFeed permission event relay-enabled id=${runtimeEvent.id} tool=${runtimeEvent.toolName ?? ""}`
1935
1939
  );
1936
1940
  }
1937
- const result = handleEvent(runtimeEvent, controllerCallbacks);
1938
- if (result.handled && result.decision) {
1939
- runtime.sendDecision(runtimeEvent.id, result.decision);
1940
- }
1941
- const newFeedEvents = mapperRef.current.mapEvent(runtimeEvent);
1942
- if (sessionStoreRef.current) {
1943
- try {
1944
- sessionStoreRef.current.recordEvent(runtimeEvent, newFeedEvents);
1945
- } catch (err) {
1946
- sessionStoreRef.current.markDegraded(
1947
- `recordEvent failed: ${err instanceof Error ? err.message : err}`
1948
- );
1941
+ const { feedEvents: newFeedEvents, decision } = ingestRuntimeEvent(
1942
+ runtimeEvent,
1943
+ {
1944
+ mapper: mapperRef.current,
1945
+ store: sessionStoreRef.current,
1946
+ controllerCallbacks
1949
1947
  }
1948
+ );
1949
+ if (decision) {
1950
+ runtime.sendDecision(runtimeEvent.id, decision);
1950
1951
  }
1951
1952
  if (!abortRef.current.signal.aborted && newFeedEvents.length > 0) {
1952
1953
  for (const fe of newFeedEvents) {
@@ -1984,17 +1985,11 @@ function useFeed(runtime, messages = [], initialAllowedTools, sessionStore, opti
1984
1985
  if (decision.intent?.kind === "question_answer" || decision.source === "timeout") {
1985
1986
  dequeueQuestion(eventId);
1986
1987
  }
1987
- const feedEvent = mapperRef.current.mapDecision(eventId, decision);
1988
+ const feedEvent = ingestRuntimeDecision(eventId, decision, {
1989
+ mapper: mapperRef.current,
1990
+ store: sessionStoreRef.current
1991
+ });
1988
1992
  if (feedEvent) {
1989
- if (sessionStoreRef.current) {
1990
- try {
1991
- sessionStoreRef.current.recordFeedEvents([feedEvent]);
1992
- } catch (err) {
1993
- sessionStoreRef.current.markDegraded(
1994
- `recordFeedEvents failed: ${err instanceof Error ? err.message : err}`
1995
- );
1996
- }
1997
- }
1998
1993
  feedStoreRef.current.pushEvents([feedEvent]);
1999
1994
  if (feedEvent.kind === "permission.decision" && feedEvent.cause?.hook_request_id) {
2000
1995
  dequeuePermission(feedEvent.cause.hook_request_id);
@@ -2049,7 +2044,7 @@ function useFeed(runtime, messages = [], initialAllowedTools, sessionStore, opti
2049
2044
  currentRun: mapperRef.current.getCurrentRun(),
2050
2045
  actors: mapperRef.current.getActors(),
2051
2046
  isServerRunning,
2052
- runtimeError,
2047
+ runtimeError: runtimeError2,
2053
2048
  currentPermissionRequest,
2054
2049
  permissionQueueCount: permissionQueue.length,
2055
2050
  resolvePermission,
@@ -5018,31 +5013,7 @@ function useTodoDisplayItems({
5018
5013
  }
5019
5014
 
5020
5015
  // src/ui/hooks/useTimeline.ts
5021
- import { useMemo as useMemo9, useRef as useRef9 } from "react";
5022
-
5023
- // src/core/feed/defaultRender.ts
5024
- var DEFAULT_RENDER = /* @__PURE__ */ new Set([
5025
- "compact.post",
5026
- "task.created",
5027
- "cwd.changed",
5028
- "file.changed",
5029
- "stop.failure",
5030
- "permission.denied",
5031
- "elicitation.request",
5032
- "elicitation.result",
5033
- "channel.permission.relayed",
5034
- "channel.permission.resolved",
5035
- "channel.question.relayed",
5036
- "channel.question.resolved",
5037
- "channel.chat.inbound",
5038
- "channel.chat.outbound",
5039
- "gateway.function.invoked",
5040
- "gateway.function.completed",
5041
- "gateway.function.failed"
5042
- ]);
5043
- function isDefaultRenderKind(k) {
5044
- return DEFAULT_RENDER.has(k);
5045
- }
5016
+ import { useMemo as useMemo9, useRef as useRef9, useCallback as useCallback10 } from "react";
5046
5017
 
5047
5018
  // src/shared/utils/toolResponse.ts
5048
5019
  function isRecord(value) {
@@ -5267,207 +5238,24 @@ function computeDuplicateActors(entries) {
5267
5238
  entries[i].duplicateActor = sameActor && !isBreak;
5268
5239
  }
5269
5240
  }
5270
- function eventOperation(event) {
5271
- if (isDefaultRenderKind(event.kind)) return "event";
5272
- switch (event.kind) {
5273
- case "run.start":
5274
- return "run.start";
5275
- case "run.end":
5276
- if (event.data.status === "completed") return "run.ok";
5277
- if (event.data.status === "failed") return "run.fail";
5278
- return "run.abort";
5279
- case "user.prompt":
5280
- return "prompt";
5281
- case "plan.update":
5282
- return "plan.upd";
5283
- case "reasoning.summary":
5284
- return "reason";
5285
- case "usage.update":
5286
- return "usage.upd";
5287
- case "tool.delta":
5288
- return "tool.call";
5289
- case "tool.pre":
5290
- return "tool.call";
5291
- case "tool.post":
5292
- return "tool.ok";
5293
- case "tool.failure":
5294
- return "tool.fail";
5295
- case "subagent.start":
5296
- return "sub.start";
5297
- case "subagent.stop":
5298
- return "sub.stop";
5299
- case "permission.request":
5300
- return "perm.req";
5301
- case "permission.decision":
5302
- return `perm.${event.data.decision_type}`;
5303
- case "stop.request":
5304
- return "stop.req";
5305
- case "stop.decision":
5306
- return `stop.${event.data.decision_type}`;
5307
- case "session.start":
5308
- return "sess.start";
5309
- case "session.end":
5310
- return "sess.end";
5311
- case "notification":
5312
- return "notify";
5313
- case "runtime.error":
5314
- return "error";
5315
- case "thread.status":
5316
- return "thread";
5317
- case "turn.diff":
5318
- return "diff";
5319
- case "server.request.resolved":
5320
- return "req.done";
5321
- case "web.search":
5322
- return "web.search";
5323
- case "review.status":
5324
- return "review";
5325
- case "image.view":
5326
- return "image";
5327
- case "context.compaction":
5328
- return "compact";
5329
- case "mcp.progress":
5330
- return "mcp.prog";
5331
- case "terminal.input":
5332
- return "term.in";
5333
- case "skills.changed":
5334
- return "skills";
5335
- case "skills.loaded":
5336
- return "skills";
5337
- case "compact.pre":
5338
- return "compact";
5339
- case "setup":
5340
- return "setup";
5341
- case "unknown.hook":
5342
- return "unknown";
5343
- case "todo.add":
5344
- return "todo.add";
5345
- case "todo.update":
5346
- return "todo.upd";
5347
- case "todo.done":
5348
- return "todo.done";
5349
- case "agent.message":
5350
- return "agent.msg";
5351
- case "teammate.idle":
5352
- return "tm.idle";
5353
- case "task.completed":
5354
- return "task.ok";
5355
- case "config.change":
5356
- return "cfg.chg";
5357
- default:
5358
- return "event";
5359
- }
5241
+ function stripMarkdownInline(text) {
5242
+ return text.replace(/#{1,6}\s+/g, "").replace(/\*\*(.+?)\*\*/g, "$1").replace(/__(.+?)__/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/`(.+?)`/g, "$1").replace(/~~(.+?)~~/g, "$1");
5360
5243
  }
5361
- function eventLabel(event) {
5362
- if (isDefaultRenderKind(event.kind)) return "Event";
5363
- switch (event.kind) {
5364
- case "run.start":
5365
- return "Run Start";
5366
- case "run.end":
5367
- if (event.data.status === "completed") return "Run OK";
5368
- if (event.data.status === "failed") return "Run Fail";
5369
- return "Run Abort";
5370
- case "user.prompt":
5371
- return "User Prompt";
5372
- case "plan.update":
5373
- return "Plan Update";
5374
- case "reasoning.summary":
5375
- return "Reasoning";
5376
- case "usage.update":
5377
- return "Usage Update";
5378
- case "tool.delta":
5379
- return "Tool Call";
5380
- case "tool.pre":
5381
- return "Tool Call";
5382
- case "tool.post":
5383
- return "Tool OK";
5384
- case "tool.failure":
5385
- return "Tool Fail";
5386
- case "subagent.start":
5387
- return "Sub Start";
5388
- case "subagent.stop":
5389
- return "Sub Stop";
5390
- case "permission.request":
5391
- return "Perm Request";
5392
- case "permission.decision":
5393
- switch (event.data.decision_type) {
5394
- case "allow":
5395
- return "Perm Allow";
5396
- case "deny":
5397
- return "Perm Deny";
5398
- case "ask":
5399
- return "Perm Ask";
5400
- case "no_opinion":
5401
- return "Perm Skip";
5402
- default:
5403
- return "Perm Decision";
5404
- }
5405
- case "stop.request":
5406
- return "Stop Request";
5407
- case "stop.decision":
5408
- switch (event.data.decision_type) {
5409
- case "block":
5410
- return "Stop Block";
5411
- case "allow":
5412
- return "Stop Allow";
5413
- case "no_opinion":
5414
- return "Stop Skip";
5415
- default:
5416
- return "Stop Decision";
5417
- }
5418
- case "session.start":
5419
- return "Sess Start";
5420
- case "session.end":
5421
- return "Sess End";
5422
- case "notification":
5423
- return "Notify";
5424
- case "runtime.error":
5425
- return "Error";
5426
- case "thread.status":
5427
- return "Thread";
5428
- case "turn.diff":
5429
- return "Diff";
5430
- case "server.request.resolved":
5431
- return "Request";
5432
- case "web.search":
5433
- return "Web Search";
5434
- case "review.status":
5435
- return "Review";
5436
- case "image.view":
5437
- return "Image";
5438
- case "context.compaction":
5439
- return "Compaction";
5440
- case "mcp.progress":
5441
- return "MCP Progress";
5442
- case "terminal.input":
5443
- return "Terminal In";
5444
- case "skills.changed":
5445
- return "Skills";
5446
- case "skills.loaded":
5447
- return "Skills";
5448
- case "compact.pre":
5449
- return "Compact";
5450
- case "setup":
5451
- return "Setup";
5452
- case "unknown.hook":
5453
- return "Unknown";
5454
- case "todo.add":
5455
- return "Todo Add";
5456
- case "todo.update":
5457
- return "Todo Update";
5458
- case "todo.done":
5459
- return "Todo Done";
5460
- case "agent.message":
5461
- return "Agent Msg";
5462
- case "teammate.idle":
5463
- return "Team Idle";
5464
- case "task.completed":
5465
- return "Task OK";
5466
- case "config.change":
5467
- return "Config Chg";
5468
- default:
5469
- return "Event";
5244
+ function firstSentence(text) {
5245
+ const nlIdx = text.indexOf("\n");
5246
+ const sentIdx = text.indexOf(". ");
5247
+ const nlEnd = nlIdx === -1 ? Infinity : nlIdx;
5248
+ const sentEnd = sentIdx === -1 ? Infinity : sentIdx + 1;
5249
+ const end = Math.min(nlEnd, sentEnd, text.length);
5250
+ return text.slice(0, end).trim();
5251
+ }
5252
+ function resolveDisplayName(toolName) {
5253
+ const parsed = parseToolName(toolName);
5254
+ if (parsed.isMcp && parsed.mcpServer && parsed.mcpAction) {
5255
+ const friendlyServer = extractFriendlyServerName(parsed.mcpServer);
5256
+ return `[${friendlyServer}] ${parsed.mcpAction}`;
5470
5257
  }
5258
+ return toolName;
5471
5259
  }
5472
5260
  var PATH_TOOLS = /* @__PURE__ */ new Set(["Read", "Write", "Edit", "Glob", "Grep"]);
5473
5261
  function withMcpServerContext(parsed, primaryInput) {
@@ -5520,89 +5308,6 @@ function formatToolSummary(toolName, toolInput, errorSuffix) {
5520
5308
  ]
5521
5309
  };
5522
5310
  }
5523
- function eventSummary(event) {
5524
- const harness = harnessSummary(event);
5525
- if (harness) return harness;
5526
- switch (event.kind) {
5527
- case "tool.delta":
5528
- case "tool.pre":
5529
- case "tool.post":
5530
- return formatToolSummary(event.data.tool_name, event.data.tool_input);
5531
- case "permission.request":
5532
- return formatPermissionSummary(event);
5533
- case "tool.failure":
5534
- return formatToolSummary(
5535
- event.data.tool_name,
5536
- event.data.tool_input,
5537
- event.data.error
5538
- );
5539
- case "subagent.start":
5540
- case "subagent.stop": {
5541
- const text = compactText(
5542
- event.data.description?.trim() || `id:${event.data.agent_id}`,
5543
- 200
5544
- );
5545
- return { text, segments: [{ text, role: "target" }] };
5546
- }
5547
- case "agent.message": {
5548
- const text = eventSummaryText(event);
5549
- return { text, segments: [{ text, role: "plain" }] };
5550
- }
5551
- case "setup":
5552
- case "session.start":
5553
- case "session.end":
5554
- case "run.start":
5555
- case "run.end":
5556
- case "user.prompt":
5557
- case "plan.update":
5558
- case "reasoning.summary":
5559
- case "usage.update":
5560
- case "permission.decision":
5561
- case "permission.denied":
5562
- case "stop.request":
5563
- case "stop.decision":
5564
- case "stop.failure":
5565
- case "notification":
5566
- case "runtime.error":
5567
- case "thread.status":
5568
- case "turn.diff":
5569
- case "server.request.resolved":
5570
- case "web.search":
5571
- case "review.status":
5572
- case "image.view":
5573
- case "context.compaction":
5574
- case "mcp.progress":
5575
- case "terminal.input":
5576
- case "skills.changed":
5577
- case "skills.loaded":
5578
- case "compact.pre":
5579
- case "compact.post":
5580
- case "unknown.hook":
5581
- case "todo.add":
5582
- case "todo.update":
5583
- case "todo.done":
5584
- case "teammate.idle":
5585
- case "task.created":
5586
- case "task.completed":
5587
- case "config.change":
5588
- case "cwd.changed":
5589
- case "file.changed":
5590
- case "elicitation.request":
5591
- case "elicitation.result":
5592
- case "channel.permission.relayed":
5593
- case "channel.permission.resolved":
5594
- case "channel.question.relayed":
5595
- case "channel.question.resolved":
5596
- case "channel.chat.inbound":
5597
- case "channel.chat.outbound":
5598
- case "gateway.function.invoked":
5599
- case "gateway.function.completed":
5600
- case "gateway.function.failed": {
5601
- const text = eventSummaryText(event);
5602
- return { text, segments: [{ text, role: "target" }] };
5603
- }
5604
- }
5605
- }
5606
5311
  function formatPermissionSummary(event) {
5607
5312
  const base = formatToolSummary(event.data.tool_name, event.data.tool_input);
5608
5313
  const host = event.data.network_context?.host;
@@ -5617,369 +5322,619 @@ function formatPermissionSummary(event) {
5617
5322
  segments: [...base.segments, { text: suffix, role: "target" }]
5618
5323
  };
5619
5324
  }
5620
- function stripMarkdownInline(text) {
5621
- return text.replace(/#{1,6}\s+/g, "").replace(/\*\*(.+?)\*\*/g, "$1").replace(/__(.+?)__/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/`(.+?)`/g, "$1").replace(/~~(.+?)~~/g, "$1");
5325
+ function formatRunEndSummary(event) {
5326
+ const toolText = `${event.data.counters.tool_uses} tool${event.data.counters.tool_uses === 1 ? "" : "s"}`;
5327
+ const failureCount = event.data.counters.tool_failures;
5328
+ if (failureCount > 0) {
5329
+ return `${event.data.status} \xB7 ${toolText}, ${failureCount} failure${failureCount === 1 ? "" : "s"}`;
5330
+ }
5331
+ return `${event.data.status} \xB7 ${toolText}`;
5622
5332
  }
5623
- function firstSentence(text) {
5624
- const nlIdx = text.indexOf("\n");
5625
- const sentIdx = text.indexOf(". ");
5626
- const nlEnd = nlIdx === -1 ? Infinity : nlIdx;
5627
- const sentEnd = sentIdx === -1 ? Infinity : sentIdx + 1;
5628
- const end = Math.min(nlEnd, sentEnd, text.length);
5629
- return text.slice(0, end).trim();
5333
+ function harnessSummary(event) {
5334
+ const title = event.display?.title?.trim();
5335
+ if (!title) return void 0;
5336
+ const text = compactText(title, 200);
5337
+ return { text, segments: [{ text, role: "target" }] };
5630
5338
  }
5631
- function eventSummaryText(event) {
5632
- switch (event.kind) {
5633
- case "run.start":
5634
- return compactText(
5635
- event.data.trigger.prompt_preview || "interactive",
5636
- 200
5637
- );
5638
- case "run.end":
5639
- return compactText(formatRunEndSummary(event), 200);
5640
- case "user.prompt":
5641
- return compactText(event.data.prompt, 200);
5642
- case "plan.update": {
5643
- if (event.data.explanation) {
5644
- return compactText(event.data.explanation, 200);
5645
- }
5646
- if (event.data.plan && event.data.plan.length > 0) {
5647
- const completed = event.data.plan.filter(
5648
- (step) => step.status === "completed"
5649
- ).length;
5650
- return compactText(`${completed}/${event.data.plan.length} steps`, 200);
5651
- }
5652
- return compactText(event.data.delta || "plan updated", 200);
5653
- }
5654
- case "reasoning.summary":
5655
- return compactText(
5656
- firstSentence(stripMarkdownInline(event.data.message)),
5657
- 200
5658
- );
5659
- case "usage.update": {
5660
- const total = event.data.usage?.total;
5661
- const delta = event.data.delta?.total;
5662
- if (typeof total === "number" && typeof delta === "number") {
5663
- return compactText(
5664
- `${total.toLocaleString()} total (+${delta.toLocaleString()})`,
5665
- 200
5666
- );
5667
- }
5668
- if (typeof total === "number") {
5669
- return compactText(`${total.toLocaleString()} total`, 200);
5670
- }
5671
- return compactText("usage updated", 200);
5672
- }
5673
- case "permission.decision": {
5674
- const detail = event.data.decision_type === "deny" ? event.data.message || event.data.reason : event.data.reason;
5675
- return compactText(detail || event.data.decision_type, 200);
5676
- }
5677
- case "stop.request":
5678
- return compactText(
5679
- event.data.stop_hook_active ? "Stop hook active" : "Stop hook inactive",
5680
- 200
5681
- );
5682
- case "stop.decision":
5683
- return compactText(event.data.reason || event.data.decision_type, 200);
5684
- case "session.start":
5685
- return compactText(event.data.source, 200);
5686
- case "session.end":
5687
- return compactText(event.data.reason, 200);
5688
- case "notification":
5689
- return compactText(stripMarkdownInline(event.data.message), 200);
5690
- case "runtime.error":
5691
- return compactText(stripMarkdownInline(event.data.message), 200);
5692
- case "thread.status":
5693
- return compactText(event.data.message, 200);
5694
- case "turn.diff":
5695
- return compactText(event.data.message, 200);
5696
- case "server.request.resolved":
5697
- return compactText(event.data.message, 200);
5698
- case "web.search":
5699
- return compactText(event.data.message, 200);
5700
- case "review.status":
5701
- return compactText(event.data.message, 200);
5702
- case "image.view":
5703
- return compactText(event.data.message, 200);
5704
- case "context.compaction":
5705
- return compactText(event.data.message, 200);
5706
- case "mcp.progress":
5707
- return compactText(event.data.message, 200);
5708
- case "terminal.input":
5709
- return compactText(event.data.message, 200);
5710
- case "skills.changed":
5711
- case "skills.loaded":
5712
- return compactText(event.data.message, 200);
5713
- case "compact.pre":
5714
- return compactText(event.data.trigger, 200);
5715
- case "setup":
5716
- return compactText(event.data.trigger, 200);
5717
- case "unknown.hook":
5718
- return compactText(event.data.hook_event_name, 200);
5719
- case "todo.add":
5720
- return compactText(
5721
- `${event.data.priority?.toUpperCase() ?? "P1"} ${event.data.text}`,
5722
- 200
5723
- );
5724
- case "todo.update": {
5725
- const patchFields = Object.keys(event.data.patch);
5726
- return compactText(
5727
- `${event.data.todo_id} ${patchFields.length > 0 ? patchFields.join(",") : "update"}`,
5728
- 200
5729
- );
5730
- }
5731
- case "todo.done":
5732
- return compactText(
5733
- `${event.data.todo_id} ${event.data.reason || "done"}`,
5734
- 200
5735
- );
5736
- case "agent.message":
5737
- return compactText(
5738
- firstSentence(stripMarkdownInline(event.data.message)),
5739
- 200
5740
- );
5741
- case "teammate.idle":
5742
- return compactText(
5743
- `${event.data.teammate_name} idle in ${event.data.team_name}`,
5744
- 200
5745
- );
5746
- case "task.created":
5747
- case "task.completed":
5748
- return compactText(event.data.task_subject, 200);
5749
- case "config.change":
5750
- return compactText(
5751
- `${event.data.source}${event.data.file_path ? ` ${event.data.file_path}` : ""}`,
5752
- 200
5753
- );
5754
- case "cwd.changed":
5755
- return compactText(`cwd \u2192 ${event.data.cwd}`, 200);
5756
- case "file.changed":
5757
- return compactText(`changed ${event.data.file_path}`, 200);
5758
- case "stop.failure":
5759
- return compactText(
5760
- `${event.data.error_type}${event.data.error_message ? `: ${event.data.error_message}` : ""}`,
5761
- 200
5762
- );
5763
- case "permission.denied":
5764
- return compactText(
5765
- `${event.data.tool_name}${event.data.reason ? `: ${event.data.reason}` : ""}`,
5766
- 200
5767
- );
5768
- case "elicitation.request":
5769
- return compactText(`elicitation from ${event.data.mcp_server}`, 200);
5770
- case "elicitation.result":
5771
- return compactText(
5772
- `${event.data.mcp_server} \u2192 ${event.data.action}`,
5773
- 200
5774
- );
5775
- case "channel.permission.relayed":
5776
- return compactText(
5777
- `${event.data.channel_name}: ${event.data.tool_name} (${event.data.channel_request_id})`,
5778
- 200
5779
- );
5780
- case "channel.permission.resolved":
5781
- return compactText(
5782
- `${event.data.channel_name} ${event.data.source} ${event.data.tool_name}`,
5783
- 200
5784
- );
5785
- case "channel.question.relayed":
5786
- return compactText(
5787
- `${event.data.channel_name}: ${event.data.title} (${event.data.channel_request_id})`,
5788
- 200
5789
- );
5790
- case "channel.question.resolved":
5791
- return compactText(
5792
- `${event.data.channel_name || event.data.source} ${event.data.source} ${event.data.title}`,
5793
- 200
5794
- );
5795
- case "channel.chat.inbound":
5796
- return compactText(
5797
- `${event.data.channel_name}: ${event.data.content}`,
5798
- 200
5799
- );
5800
- case "channel.chat.outbound":
5801
- return compactText(
5802
- `${event.data.channel_name} \u2192 ${event.data.target_peer_id}: ${event.data.content}`,
5803
- 200
5804
- );
5805
- case "gateway.function.invoked":
5806
- return compactText(
5807
- `fn invoked: ${event.data.function_name} (${event.data.caller_kind})`,
5808
- 200
5809
- );
5810
- case "gateway.function.completed":
5811
- return compactText(
5812
- `fn ok: ${event.data.function_name} ${event.data.duration_ms}ms`,
5813
- 200
5814
- );
5815
- case "gateway.function.failed":
5816
- return compactText(
5817
- `fn ${event.data.reason}: ${event.data.function_name} \u2014 ${event.data.error_message}`,
5818
- 200
5819
- );
5820
- case "compact.post":
5821
- return compactText(`compacted (${event.data.trigger})`, 200);
5822
- case "tool.pre":
5823
- case "tool.delta":
5824
- case "tool.post":
5825
- case "tool.failure":
5826
- case "permission.request":
5827
- case "subagent.start":
5828
- case "subagent.stop":
5829
- return compactText("event", 200);
5339
+ function postOutcome(postEvent) {
5340
+ if (postEvent.kind === "tool.failure") {
5341
+ return summarizeToolResult(
5342
+ postEvent.data.tool_name,
5343
+ postEvent.data.tool_input,
5344
+ void 0,
5345
+ postEvent.data.error
5346
+ );
5830
5347
  }
5831
- }
5832
- function formatRunEndSummary(event) {
5833
- const toolText = `${event.data.counters.tool_uses} tool${event.data.counters.tool_uses === 1 ? "" : "s"}`;
5834
- const failureCount = event.data.counters.tool_failures;
5835
- if (failureCount > 0) {
5836
- return `${event.data.status} \xB7 ${toolText}, ${failureCount} failure${failureCount === 1 ? "" : "s"}`;
5348
+ if (postEvent.kind === "tool.post") {
5349
+ return summarizeToolResult(
5350
+ postEvent.data.tool_name,
5351
+ postEvent.data.tool_input,
5352
+ postEvent.data.tool_response
5353
+ );
5837
5354
  }
5838
- return `${event.data.status} \xB7 ${toolText}`;
5355
+ return void 0;
5839
5356
  }
5840
- function expansionForEvent(event) {
5841
- switch (event.kind) {
5842
- case "tool.pre":
5843
- case "tool.delta":
5844
- return JSON.stringify(
5845
- { tool: event.data.tool_name, args: event.data.tool_input },
5846
- null,
5847
- 2
5848
- );
5849
- case "tool.post":
5850
- return JSON.stringify(
5851
- {
5852
- tool: event.data.tool_name,
5853
- args: event.data.tool_input,
5854
- result: event.data.tool_response
5855
- },
5856
- null,
5857
- 2
5858
- );
5859
- case "tool.failure":
5860
- return JSON.stringify(
5861
- {
5862
- tool: event.data.tool_name,
5863
- args: event.data.tool_input,
5864
- error: event.data.error,
5865
- interrupt: event.data.is_interrupt
5866
- },
5867
- null,
5868
- 2
5869
- );
5870
- case "permission.request":
5871
- return JSON.stringify(
5872
- {
5873
- tool: event.data.tool_name,
5874
- args: event.data.tool_input,
5875
- suggestions: event.data.permission_suggestions
5876
- },
5877
- null,
5878
- 2
5357
+ function plainSummary(text) {
5358
+ const compact = compactText(text, 200);
5359
+ return { text: compact, segments: [{ text: compact, role: "target" }] };
5360
+ }
5361
+ function dataExpansion(event) {
5362
+ return JSON.stringify(event.data, null, 2);
5363
+ }
5364
+ function rawOrDataExpansion(event) {
5365
+ return JSON.stringify(event.raw ?? event.data, null, 2);
5366
+ }
5367
+ function defaultRenderer(summarize2) {
5368
+ return {
5369
+ operation: () => "event",
5370
+ label: () => "Event",
5371
+ detail: () => "\u2500",
5372
+ summary: (event) => plainSummary(summarize2(event)),
5373
+ expansion: rawOrDataExpansion
5374
+ };
5375
+ }
5376
+ var sessionStart = {
5377
+ operation: () => "sess.start",
5378
+ label: () => "Sess Start",
5379
+ detail: (event) => event.data.source,
5380
+ summary: (event) => plainSummary(event.data.source),
5381
+ expansion: rawOrDataExpansion
5382
+ };
5383
+ var sessionEnd = {
5384
+ operation: () => "sess.end",
5385
+ label: () => "Sess End",
5386
+ detail: () => "\u2500",
5387
+ summary: (event) => plainSummary(event.data.reason),
5388
+ expansion: rawOrDataExpansion
5389
+ };
5390
+ var runStart = {
5391
+ operation: () => "run.start",
5392
+ label: () => "Run Start",
5393
+ detail: () => "\u2500",
5394
+ summary: (event) => plainSummary(event.data.trigger.prompt_preview || "interactive"),
5395
+ expansion: rawOrDataExpansion
5396
+ };
5397
+ var runEnd = {
5398
+ operation: (event) => {
5399
+ if (event.data.status === "completed") return "run.ok";
5400
+ if (event.data.status === "failed") return "run.fail";
5401
+ return "run.abort";
5402
+ },
5403
+ label: (event) => {
5404
+ if (event.data.status === "completed") return "Run OK";
5405
+ if (event.data.status === "failed") return "Run Fail";
5406
+ return "Run Abort";
5407
+ },
5408
+ detail: () => "\u2500",
5409
+ summary: (event) => plainSummary(formatRunEndSummary(event)),
5410
+ expansion: dataExpansion,
5411
+ isError: (event) => event.data.status !== "completed"
5412
+ };
5413
+ var userPrompt = {
5414
+ operation: () => "prompt",
5415
+ label: () => "User Prompt",
5416
+ detail: () => "\u2500",
5417
+ summary: (event) => plainSummary(event.data.prompt),
5418
+ expansion: rawOrDataExpansion
5419
+ };
5420
+ var planUpdate = {
5421
+ operation: () => "plan.upd",
5422
+ label: () => "Plan Update",
5423
+ detail: () => "plan",
5424
+ summary: (event) => {
5425
+ if (event.data.explanation) return plainSummary(event.data.explanation);
5426
+ if (event.data.plan && event.data.plan.length > 0) {
5427
+ const completed = event.data.plan.filter(
5428
+ (step) => step.status === "completed"
5429
+ ).length;
5430
+ return plainSummary(`${completed}/${event.data.plan.length} steps`);
5431
+ }
5432
+ return plainSummary(event.data.delta || "plan updated");
5433
+ },
5434
+ expansion: dataExpansion
5435
+ };
5436
+ var reasoningSummary = {
5437
+ operation: () => "reason",
5438
+ label: () => "Reasoning",
5439
+ detail: () => "summary",
5440
+ summary: (event) => plainSummary(firstSentence(stripMarkdownInline(event.data.message))),
5441
+ expansion: dataExpansion
5442
+ };
5443
+ var usageUpdate = {
5444
+ operation: () => "usage.upd",
5445
+ label: () => "Usage Update",
5446
+ detail: () => "tokens",
5447
+ summary: (event) => {
5448
+ const total = event.data.usage?.total;
5449
+ const delta = event.data.delta?.total;
5450
+ if (typeof total === "number" && typeof delta === "number") {
5451
+ return plainSummary(
5452
+ `${total.toLocaleString()} total (+${delta.toLocaleString()})`
5879
5453
  );
5880
- case "subagent.stop":
5881
- case "run.end":
5882
- case "plan.update":
5883
- case "reasoning.summary":
5884
- case "usage.update":
5885
- case "runtime.error":
5886
- case "thread.status":
5887
- case "turn.diff":
5888
- case "server.request.resolved":
5889
- case "web.search":
5890
- case "review.status":
5891
- case "image.view":
5892
- case "context.compaction":
5893
- case "mcp.progress":
5894
- case "terminal.input":
5895
- case "skills.changed":
5896
- case "skills.loaded":
5897
- return JSON.stringify(event.data, null, 2);
5898
- case "setup":
5899
- case "session.start":
5900
- case "session.end":
5901
- case "run.start":
5902
- case "user.prompt":
5903
- case "permission.decision":
5904
- case "permission.denied":
5905
- case "stop.request":
5906
- case "stop.decision":
5907
- case "stop.failure":
5908
- case "notification":
5909
- case "subagent.start":
5910
- case "compact.pre":
5911
- case "compact.post":
5912
- case "unknown.hook":
5913
- case "todo.add":
5914
- case "todo.update":
5915
- case "todo.done":
5916
- case "agent.message":
5917
- case "teammate.idle":
5918
- case "task.created":
5919
- case "task.completed":
5920
- case "config.change":
5921
- case "cwd.changed":
5922
- case "file.changed":
5923
- case "elicitation.request":
5924
- case "elicitation.result":
5925
- case "channel.permission.relayed":
5926
- case "channel.permission.resolved":
5927
- case "channel.question.relayed":
5928
- case "channel.question.resolved":
5929
- case "channel.chat.inbound":
5930
- case "channel.chat.outbound":
5931
- case "gateway.function.invoked":
5932
- case "gateway.function.completed":
5933
- case "gateway.function.failed":
5934
- return JSON.stringify(event.raw ?? event.data, null, 2);
5935
- }
5454
+ }
5455
+ if (typeof total === "number") {
5456
+ return plainSummary(`${total.toLocaleString()} total`);
5457
+ }
5458
+ return plainSummary("usage updated");
5459
+ },
5460
+ expansion: dataExpansion
5461
+ };
5462
+ var toolDelta = {
5463
+ operation: () => "tool.call",
5464
+ label: () => "Tool Call",
5465
+ detail: (event) => resolveDisplayName(event.data.tool_name),
5466
+ summary: (event) => formatToolSummary(event.data.tool_name, event.data.tool_input),
5467
+ expansion: (event) => JSON.stringify(
5468
+ { tool: event.data.tool_name, args: event.data.tool_input },
5469
+ null,
5470
+ 2
5471
+ )
5472
+ };
5473
+ var toolPre = {
5474
+ operation: () => "tool.call",
5475
+ label: () => "Tool Call",
5476
+ detail: (event) => resolveDisplayName(event.data.tool_name),
5477
+ summary: (event) => formatToolSummary(event.data.tool_name, event.data.tool_input),
5478
+ expansion: (event) => JSON.stringify(
5479
+ { tool: event.data.tool_name, args: event.data.tool_input },
5480
+ null,
5481
+ 2
5482
+ )
5483
+ };
5484
+ var toolPost = {
5485
+ operation: () => "tool.ok",
5486
+ label: () => "Tool OK",
5487
+ detail: (event) => resolveDisplayName(event.data.tool_name),
5488
+ summary: (event) => formatToolSummary(event.data.tool_name, event.data.tool_input),
5489
+ expansion: (event) => JSON.stringify(
5490
+ {
5491
+ tool: event.data.tool_name,
5492
+ args: event.data.tool_input,
5493
+ result: event.data.tool_response
5494
+ },
5495
+ null,
5496
+ 2
5497
+ )
5498
+ };
5499
+ var toolFailure = {
5500
+ operation: () => "tool.fail",
5501
+ label: () => "Tool Fail",
5502
+ detail: (event) => resolveDisplayName(event.data.tool_name),
5503
+ summary: (event) => formatToolSummary(
5504
+ event.data.tool_name,
5505
+ event.data.tool_input,
5506
+ event.data.error
5507
+ ),
5508
+ expansion: (event) => JSON.stringify(
5509
+ {
5510
+ tool: event.data.tool_name,
5511
+ args: event.data.tool_input,
5512
+ error: event.data.error,
5513
+ interrupt: event.data.is_interrupt
5514
+ },
5515
+ null,
5516
+ 2
5517
+ ),
5518
+ isError: () => true
5519
+ };
5520
+ var permissionRequest = {
5521
+ operation: () => "perm.req",
5522
+ label: () => "Perm Request",
5523
+ detail: (event) => resolveDisplayName(event.data.tool_name),
5524
+ summary: (event) => formatPermissionSummary(event),
5525
+ expansion: (event) => JSON.stringify(
5526
+ {
5527
+ tool: event.data.tool_name,
5528
+ args: event.data.tool_input,
5529
+ suggestions: event.data.permission_suggestions
5530
+ },
5531
+ null,
5532
+ 2
5533
+ )
5534
+ };
5535
+ var permissionDecision = {
5536
+ operation: (event) => `perm.${event.data.decision_type}`,
5537
+ label: (event) => {
5538
+ switch (event.data.decision_type) {
5539
+ case "allow":
5540
+ return "Perm Allow";
5541
+ case "deny":
5542
+ return "Perm Deny";
5543
+ case "ask":
5544
+ return "Perm Ask";
5545
+ case "no_opinion":
5546
+ return "Perm Skip";
5547
+ default:
5548
+ return "Perm Decision";
5549
+ }
5550
+ },
5551
+ detail: () => "\u2500",
5552
+ summary: (event) => {
5553
+ const detail = event.data.decision_type === "deny" ? event.data.message || event.data.reason : event.data.reason;
5554
+ return plainSummary(detail || event.data.decision_type);
5555
+ },
5556
+ expansion: rawOrDataExpansion,
5557
+ isError: (event) => event.data.decision_type === "deny"
5558
+ };
5559
+ var stopRequest = {
5560
+ operation: () => "stop.req",
5561
+ label: () => "Stop Request",
5562
+ detail: () => "\u2500",
5563
+ summary: (event) => plainSummary(
5564
+ event.data.stop_hook_active ? "Stop hook active" : "Stop hook inactive"
5565
+ ),
5566
+ expansion: rawOrDataExpansion
5567
+ };
5568
+ var stopDecision = {
5569
+ operation: (event) => `stop.${event.data.decision_type}`,
5570
+ label: (event) => {
5571
+ switch (event.data.decision_type) {
5572
+ case "block":
5573
+ return "Stop Block";
5574
+ case "allow":
5575
+ return "Stop Allow";
5576
+ case "no_opinion":
5577
+ return "Stop Skip";
5578
+ default:
5579
+ return "Stop Decision";
5580
+ }
5581
+ },
5582
+ detail: () => "\u2500",
5583
+ summary: (event) => plainSummary(event.data.reason || event.data.decision_type),
5584
+ expansion: rawOrDataExpansion,
5585
+ isError: (event) => event.data.decision_type === "block"
5586
+ };
5587
+ var subagentStart = {
5588
+ operation: () => "sub.start",
5589
+ label: () => "Sub Start",
5590
+ detail: (event) => event.data.agent_type,
5591
+ summary: (event) => {
5592
+ const text = compactText(
5593
+ event.data.description?.trim() || `id:${event.data.agent_id}`,
5594
+ 200
5595
+ );
5596
+ return { text, segments: [{ text, role: "target" }] };
5597
+ },
5598
+ expansion: rawOrDataExpansion
5599
+ };
5600
+ var subagentStop = {
5601
+ operation: () => "sub.stop",
5602
+ label: () => "Sub Stop",
5603
+ detail: (event) => event.data.agent_type,
5604
+ summary: (event) => {
5605
+ const text = compactText(
5606
+ event.data.description?.trim() || `id:${event.data.agent_id}`,
5607
+ 200
5608
+ );
5609
+ return { text, segments: [{ text, role: "target" }] };
5610
+ },
5611
+ expansion: dataExpansion
5612
+ };
5613
+ var notification = {
5614
+ operation: () => "notify",
5615
+ label: () => "Notify",
5616
+ detail: () => "\u2500",
5617
+ summary: (event) => plainSummary(stripMarkdownInline(event.data.message)),
5618
+ expansion: rawOrDataExpansion
5619
+ };
5620
+ var runtimeError = {
5621
+ operation: () => "error",
5622
+ label: () => "Error",
5623
+ detail: () => "\u2500",
5624
+ summary: (event) => plainSummary(stripMarkdownInline(event.data.message)),
5625
+ expansion: dataExpansion,
5626
+ isError: () => true
5627
+ };
5628
+ var threadStatus = {
5629
+ operation: () => "thread",
5630
+ label: () => "Thread",
5631
+ detail: (event) => event.data.status_type ?? "status",
5632
+ summary: (event) => plainSummary(event.data.message),
5633
+ expansion: dataExpansion
5634
+ };
5635
+ var turnDiff = {
5636
+ operation: () => "diff",
5637
+ label: () => "Diff",
5638
+ detail: () => "\u2500",
5639
+ summary: (event) => plainSummary(event.data.message),
5640
+ expansion: dataExpansion
5641
+ };
5642
+ var serverRequestResolved = {
5643
+ operation: () => "req.done",
5644
+ label: () => "Request",
5645
+ detail: (event) => event.data.request_id ?? "request",
5646
+ summary: (event) => plainSummary(event.data.message),
5647
+ expansion: dataExpansion
5648
+ };
5649
+ var webSearch = {
5650
+ operation: () => "web.search",
5651
+ label: () => "Web Search",
5652
+ detail: (event) => event.data.action_type ?? event.data.phase,
5653
+ summary: (event) => plainSummary(event.data.message),
5654
+ expansion: dataExpansion
5655
+ };
5656
+ var reviewStatus = {
5657
+ operation: () => "review",
5658
+ label: () => "Review",
5659
+ detail: (event) => event.data.phase,
5660
+ summary: (event) => plainSummary(event.data.message),
5661
+ expansion: dataExpansion
5662
+ };
5663
+ var imageView = {
5664
+ operation: () => "image",
5665
+ label: () => "Image",
5666
+ detail: (event) => event.data.path ?? "image",
5667
+ summary: (event) => plainSummary(event.data.message),
5668
+ expansion: dataExpansion
5669
+ };
5670
+ var contextCompaction = {
5671
+ operation: () => "compact",
5672
+ label: () => "Compaction",
5673
+ detail: (event) => event.data.phase,
5674
+ summary: (event) => plainSummary(event.data.message),
5675
+ expansion: dataExpansion
5676
+ };
5677
+ var mcpProgress = {
5678
+ operation: () => "mcp.prog",
5679
+ label: () => "MCP Progress",
5680
+ detail: () => "\u2500",
5681
+ summary: (event) => plainSummary(event.data.message),
5682
+ expansion: dataExpansion
5683
+ };
5684
+ var terminalInput = {
5685
+ operation: () => "term.in",
5686
+ label: () => "Terminal In",
5687
+ detail: () => "\u2500",
5688
+ summary: (event) => plainSummary(event.data.message),
5689
+ expansion: dataExpansion
5690
+ };
5691
+ var skillsChanged = {
5692
+ operation: () => "skills",
5693
+ label: () => "Skills",
5694
+ detail: () => "\u2500",
5695
+ summary: (event) => plainSummary(event.data.message),
5696
+ expansion: dataExpansion
5697
+ };
5698
+ var skillsLoaded = {
5699
+ operation: () => "skills",
5700
+ label: () => "Skills",
5701
+ detail: () => "\u2500",
5702
+ summary: (event) => plainSummary(event.data.message),
5703
+ expansion: dataExpansion
5704
+ };
5705
+ var compactPre = {
5706
+ operation: () => "compact",
5707
+ label: () => "Compact",
5708
+ detail: () => "\u2500",
5709
+ summary: (event) => plainSummary(event.data.trigger),
5710
+ expansion: dataExpansion
5711
+ };
5712
+ var setup = {
5713
+ operation: () => "setup",
5714
+ label: () => "Setup",
5715
+ detail: () => "\u2500",
5716
+ summary: (event) => plainSummary(event.data.trigger),
5717
+ expansion: rawOrDataExpansion
5718
+ };
5719
+ var unknownHook = {
5720
+ operation: () => "unknown",
5721
+ label: () => "Unknown",
5722
+ detail: () => "\u2500",
5723
+ summary: (event) => plainSummary(event.data.hook_event_name),
5724
+ expansion: rawOrDataExpansion
5725
+ };
5726
+ var todoAdd = {
5727
+ operation: () => "todo.add",
5728
+ label: () => "Todo Add",
5729
+ detail: (event) => (event.data.priority ?? "p1").toUpperCase(),
5730
+ summary: (event) => plainSummary(
5731
+ `${event.data.priority?.toUpperCase() ?? "P1"} ${event.data.text}`
5732
+ ),
5733
+ expansion: rawOrDataExpansion
5734
+ };
5735
+ var todoUpdate = {
5736
+ operation: () => "todo.upd",
5737
+ label: () => "Todo Update",
5738
+ detail: (event) => event.data.todo_id,
5739
+ summary: (event) => {
5740
+ const patchFields = Object.keys(event.data.patch);
5741
+ return plainSummary(
5742
+ `${event.data.todo_id} ${patchFields.length > 0 ? patchFields.join(",") : "update"}`
5743
+ );
5744
+ },
5745
+ expansion: rawOrDataExpansion
5746
+ };
5747
+ var todoDone = {
5748
+ operation: () => "todo.done",
5749
+ label: () => "Todo Done",
5750
+ detail: (event) => event.data.todo_id,
5751
+ summary: (event) => plainSummary(`${event.data.todo_id} ${event.data.reason || "done"}`),
5752
+ expansion: rawOrDataExpansion
5753
+ };
5754
+ var agentMessage = {
5755
+ operation: () => "agent.msg",
5756
+ label: () => "Agent Msg",
5757
+ detail: () => "\u2500",
5758
+ summary: (event) => {
5759
+ const text = compactText(
5760
+ firstSentence(stripMarkdownInline(event.data.message)),
5761
+ 200
5762
+ );
5763
+ return { text, segments: [{ text, role: "plain" }] };
5764
+ },
5765
+ expansion: rawOrDataExpansion
5766
+ };
5767
+ var teammateIdle = {
5768
+ operation: () => "tm.idle",
5769
+ label: () => "Team Idle",
5770
+ detail: () => "\u2500",
5771
+ summary: (event) => plainSummary(`${event.data.teammate_name} idle in ${event.data.team_name}`),
5772
+ expansion: rawOrDataExpansion
5773
+ };
5774
+ var taskCompleted = {
5775
+ operation: () => "task.ok",
5776
+ label: () => "Task OK",
5777
+ detail: () => "\u2500",
5778
+ summary: (event) => plainSummary(event.data.task_subject),
5779
+ expansion: rawOrDataExpansion
5780
+ };
5781
+ var configChange = {
5782
+ operation: () => "cfg.chg",
5783
+ label: () => "Config Chg",
5784
+ detail: (event) => event.data.source,
5785
+ summary: (event) => plainSummary(
5786
+ `${event.data.source}${event.data.file_path ? ` ${event.data.file_path}` : ""}`
5787
+ ),
5788
+ expansion: rawOrDataExpansion
5789
+ };
5790
+ var compactPost = defaultRenderer(
5791
+ (event) => `compacted (${event.data.trigger})`
5792
+ );
5793
+ var taskCreated = defaultRenderer(
5794
+ (event) => event.data.task_subject
5795
+ );
5796
+ var cwdChanged = defaultRenderer(
5797
+ (event) => `cwd \u2192 ${event.data.cwd}`
5798
+ );
5799
+ var fileChanged = defaultRenderer(
5800
+ (event) => `changed ${event.data.file_path}`
5801
+ );
5802
+ var stopFailure = defaultRenderer(
5803
+ (event) => `${event.data.error_type}${event.data.error_message ? `: ${event.data.error_message}` : ""}`
5804
+ );
5805
+ var permissionDenied = defaultRenderer(
5806
+ (event) => `${event.data.tool_name}${event.data.reason ? `: ${event.data.reason}` : ""}`
5807
+ );
5808
+ var elicitationRequest = defaultRenderer((event) => `elicitation from ${event.data.mcp_server}`);
5809
+ var elicitationResult = defaultRenderer(
5810
+ (event) => `${event.data.mcp_server} \u2192 ${event.data.action}`
5811
+ );
5812
+ var channelPermissionRelayed = defaultRenderer(
5813
+ (event) => `${event.data.channel_name}: ${event.data.tool_name} (${event.data.channel_request_id})`
5814
+ );
5815
+ var channelPermissionResolved = defaultRenderer(
5816
+ (event) => `${event.data.channel_name} ${event.data.source} ${event.data.tool_name}`
5817
+ );
5818
+ var channelQuestionRelayed = defaultRenderer(
5819
+ (event) => `${event.data.channel_name}: ${event.data.title} (${event.data.channel_request_id})`
5820
+ );
5821
+ var channelQuestionResolved = defaultRenderer(
5822
+ (event) => `${event.data.channel_name || event.data.source} ${event.data.source} ${event.data.title}`
5823
+ );
5824
+ var channelChatInbound = defaultRenderer((event) => `${event.data.channel_name}: ${event.data.content}`);
5825
+ var channelChatOutbound = defaultRenderer(
5826
+ (event) => `${event.data.channel_name} \u2192 ${event.data.target_peer_id}: ${event.data.content}`
5827
+ );
5828
+ var gatewayFunctionInvoked = defaultRenderer(
5829
+ (event) => `fn invoked: ${event.data.function_name} (${event.data.caller_kind})`
5830
+ );
5831
+ var gatewayFunctionCompleted = defaultRenderer(
5832
+ (event) => `fn ok: ${event.data.function_name} ${event.data.duration_ms}ms`
5833
+ );
5834
+ var gatewayFunctionFailed = defaultRenderer(
5835
+ (event) => `fn ${event.data.reason}: ${event.data.function_name} \u2014 ${event.data.error_message}`
5836
+ );
5837
+ var RENDERERS = {
5838
+ "session.start": sessionStart,
5839
+ "session.end": sessionEnd,
5840
+ "run.start": runStart,
5841
+ "run.end": runEnd,
5842
+ "user.prompt": userPrompt,
5843
+ "plan.update": planUpdate,
5844
+ "reasoning.summary": reasoningSummary,
5845
+ "usage.update": usageUpdate,
5846
+ "tool.delta": toolDelta,
5847
+ "tool.pre": toolPre,
5848
+ "tool.post": toolPost,
5849
+ "tool.failure": toolFailure,
5850
+ "permission.request": permissionRequest,
5851
+ "permission.decision": permissionDecision,
5852
+ "stop.request": stopRequest,
5853
+ "stop.decision": stopDecision,
5854
+ "subagent.start": subagentStart,
5855
+ "subagent.stop": subagentStop,
5856
+ notification,
5857
+ "runtime.error": runtimeError,
5858
+ "thread.status": threadStatus,
5859
+ "turn.diff": turnDiff,
5860
+ "server.request.resolved": serverRequestResolved,
5861
+ "web.search": webSearch,
5862
+ "review.status": reviewStatus,
5863
+ "image.view": imageView,
5864
+ "context.compaction": contextCompaction,
5865
+ "mcp.progress": mcpProgress,
5866
+ "terminal.input": terminalInput,
5867
+ "skills.changed": skillsChanged,
5868
+ "skills.loaded": skillsLoaded,
5869
+ "compact.pre": compactPre,
5870
+ "compact.post": compactPost,
5871
+ setup,
5872
+ "unknown.hook": unknownHook,
5873
+ "todo.add": todoAdd,
5874
+ "todo.update": todoUpdate,
5875
+ "todo.done": todoDone,
5876
+ "agent.message": agentMessage,
5877
+ "teammate.idle": teammateIdle,
5878
+ "task.created": taskCreated,
5879
+ "task.completed": taskCompleted,
5880
+ "config.change": configChange,
5881
+ "cwd.changed": cwdChanged,
5882
+ "file.changed": fileChanged,
5883
+ "stop.failure": stopFailure,
5884
+ "permission.denied": permissionDenied,
5885
+ "elicitation.request": elicitationRequest,
5886
+ "elicitation.result": elicitationResult,
5887
+ "channel.permission.relayed": channelPermissionRelayed,
5888
+ "channel.permission.resolved": channelPermissionResolved,
5889
+ "channel.question.relayed": channelQuestionRelayed,
5890
+ "channel.question.resolved": channelQuestionResolved,
5891
+ "channel.chat.inbound": channelChatInbound,
5892
+ "channel.chat.outbound": channelChatOutbound,
5893
+ "gateway.function.invoked": gatewayFunctionInvoked,
5894
+ "gateway.function.completed": gatewayFunctionCompleted,
5895
+ "gateway.function.failed": gatewayFunctionFailed
5896
+ };
5897
+ function rendererFor(event) {
5898
+ return RENDERERS[event.kind];
5899
+ }
5900
+ function eventOperation(event) {
5901
+ return rendererFor(event).operation(event);
5902
+ }
5903
+ function eventLabel(event) {
5904
+ return rendererFor(event).label(event);
5905
+ }
5906
+ function eventSummary(event) {
5907
+ const harness = harnessSummary(event);
5908
+ if (harness) return harness;
5909
+ return rendererFor(event).summary(event);
5910
+ }
5911
+ function expansionForEvent(event) {
5912
+ return rendererFor(event).expansion(event);
5936
5913
  }
5937
5914
  function isEventError(event) {
5938
5915
  if (event.level === "error") return true;
5939
- if (event.kind === "tool.failure") return true;
5940
- if (event.kind === "runtime.error") return true;
5941
- if (event.kind === "run.end") return event.data.status !== "completed";
5942
- if (event.kind === "permission.decision" && event.data.decision_type === "deny") {
5943
- return true;
5944
- }
5945
- if (event.kind === "stop.decision" && event.data.decision_type === "block") {
5946
- return true;
5947
- }
5948
- return false;
5916
+ const renderer = rendererFor(event);
5917
+ return renderer.isError?.(event) ?? false;
5949
5918
  }
5950
5919
  function isEventExpandable(event) {
5951
5920
  void event;
5952
5921
  return true;
5953
5922
  }
5954
- var VERBOSE_ONLY_KINDS = /* @__PURE__ */ new Set([
5955
- "session.start",
5956
- "session.end",
5957
- "run.start",
5958
- "run.end",
5959
- "unknown.hook",
5960
- "compact.pre",
5961
- "config.change",
5962
- "turn.diff",
5963
- "usage.update",
5964
- "reasoning.summary"
5965
- ]);
5966
- function mergedEventOperation(event, postEvent) {
5967
- if (!postEvent) return eventOperation(event);
5968
- if (postEvent.kind === "tool.failure") return "tool.fail";
5969
- if (postEvent.kind === "tool.post") return "tool.ok";
5970
- return eventOperation(event);
5971
- }
5972
- function mergedEventLabel(event, postEvent) {
5973
- if (!postEvent) return eventLabel(event);
5974
- if (postEvent.kind === "tool.failure") return "Tool Fail";
5975
- if (postEvent.kind === "tool.post") return "Tool OK";
5976
- return eventLabel(event);
5977
- }
5978
- function mergedEventSummary(event, postEvent) {
5979
- if (!postEvent) return eventSummary(event);
5980
- if (event.kind !== "tool.pre" && event.kind !== "permission.request") {
5981
- return eventSummary(event);
5982
- }
5923
+ var toolPairOk = {
5924
+ operation: () => "tool.ok",
5925
+ label: () => "Tool OK",
5926
+ summary: (pre, post) => buildMergedToolSummary(pre, post)
5927
+ };
5928
+ var toolPairFail = {
5929
+ operation: () => "tool.fail",
5930
+ label: () => "Tool Fail",
5931
+ summary: (pre, post) => buildMergedToolSummary(pre, post)
5932
+ };
5933
+ var TOOL_PAIRS = {
5934
+ "tool.post": toolPairOk,
5935
+ "tool.failure": toolPairFail
5936
+ };
5937
+ function buildMergedToolSummary(event, postEvent) {
5983
5938
  const harness = harnessSummary(event) ?? harnessSummary(postEvent);
5984
5939
  if (harness) {
5985
5940
  return {
@@ -6006,279 +5961,74 @@ function mergedEventSummary(event, postEvent) {
6006
5961
  void 0,
6007
5962
  postEvent.data.error
6008
5963
  );
6009
- } else if (postEvent.kind === "tool.delta") {
6010
- return eventSummary(event);
6011
5964
  } else if (postEvent.kind === "tool.post") {
6012
5965
  resultText = summarizeToolResult(
6013
- toolName,
6014
- toolInput,
6015
- postEvent.data.tool_response
6016
- );
6017
- } else {
6018
- return eventSummary(event);
6019
- }
6020
- const prefix = primaryInput ? `${name} ${primaryInput}` : name;
6021
- const prefixText = compactText(prefix, 200);
6022
- const segments = primaryInput ? [
6023
- { text: name, role: "verb" },
6024
- { text: prefixText.slice(name.length), role: "target" }
6025
- ] : [{ text: prefixText, role: "verb" }];
6026
- if (!resultText) {
6027
- return { text: prefixText, segments };
6028
- }
6029
- return {
6030
- text: prefixText,
6031
- segments,
6032
- outcome: resultText,
6033
- outcomeZero: /^0\s/.test(resultText)
6034
- };
6035
- }
6036
- function harnessSummary(event) {
6037
- const title = event.display?.title?.trim();
6038
- if (!title) return void 0;
6039
- const text = compactText(title, 200);
6040
- return { text, segments: [{ text, role: "target" }] };
6041
- }
6042
- function postOutcome(postEvent) {
6043
- if (postEvent.kind === "tool.failure") {
6044
- return summarizeToolResult(
6045
- postEvent.data.tool_name,
6046
- postEvent.data.tool_input,
6047
- void 0,
6048
- postEvent.data.error
6049
- );
6050
- }
6051
- if (postEvent.kind === "tool.post") {
6052
- return summarizeToolResult(
6053
- postEvent.data.tool_name,
6054
- postEvent.data.tool_input,
6055
- postEvent.data.tool_response
6056
- );
6057
- }
6058
- return void 0;
6059
- }
6060
- function toRunStatus(event) {
6061
- switch (event.data.status) {
6062
- case "completed":
6063
- return "SUCCEEDED";
6064
- case "failed":
6065
- return "FAILED";
6066
- case "aborted":
6067
- return "CANCELLED";
6068
- }
6069
- }
6070
-
6071
- // src/core/feed/indexedTimeline.ts
6072
- var MAX_SEARCH_CACHE_SIZE = 8;
6073
- var IndexedTimeline = class {
6074
- // Underlying build cache (reuses existing logic from useTimeline.ts)
6075
- cache = null;
6076
- // Secondary indexes (maintained on every update)
6077
- runIndex = /* @__PURE__ */ new Map();
6078
- errorPositions = /* @__PURE__ */ new Set();
6079
- // Run summary tracking (incremental)
6080
- _runSummaryMap = /* @__PURE__ */ new Map();
6081
- _runSummariesDirty = true;
6082
- _runSummariesCache = [];
6083
- _lastFeedEventsLength = 0;
6084
- // Search cache
6085
- searchCache = /* @__PURE__ */ new Map();
6086
- lastFilteredRef = null;
6087
- // Instance-level caches (avoid cross-instance leaks in tests)
6088
- detailCache = /* @__PURE__ */ new WeakMap();
6089
- searchTextCache = /* @__PURE__ */ new WeakMap();
6090
- verbose = false;
6091
- constructor() {
6092
- }
6093
- /**
6094
- * Main update — determines if incremental append is possible,
6095
- * delegates to existing build/append logic, then updates indexes.
6096
- */
6097
- update(feedItems, feedEvents, postByToolUseId, verbose) {
6098
- this.verbose = verbose;
6099
- const incremental = canAppendIncrementally(
6100
- this.cache,
6101
- feedItems,
6102
- feedEvents,
6103
- this.verbose
6104
- );
6105
- if (incremental) {
6106
- this.updateRunSummaries(feedEvents);
6107
- this.cache = appendTimelineCache(
6108
- this.cache,
6109
- feedItems,
6110
- feedEvents,
6111
- postByToolUseId
6112
- );
6113
- } else {
6114
- this.rebuildRunSummaries(feedEvents);
6115
- this.cache = buildTimelineCache(
6116
- feedItems,
6117
- feedEvents,
6118
- postByToolUseId,
6119
- this.verbose
6120
- );
6121
- }
6122
- this.rebuildIndexes();
6123
- }
6124
- getEntries() {
6125
- return this.cache?.entries ?? [];
6126
- }
6127
- /**
6128
- * Index-based filtering — O(k) where k = matching entries.
6129
- * Replaces Array.filter() O(n) on every render.
6130
- */
6131
- getFilteredView(runFilter, errorsOnly) {
6132
- const entries = this.getEntries();
6133
- if ((!runFilter || runFilter === "all") && !errorsOnly) {
6134
- return entries;
6135
- }
6136
- let candidateIndices;
6137
- if (runFilter && runFilter !== "all") {
6138
- candidateIndices = this.runIndex.get(runFilter) ?? [];
6139
- } else {
6140
- candidateIndices = Array.from({ length: entries.length }, (_, i) => i);
6141
- }
6142
- if (errorsOnly) {
6143
- candidateIndices = candidateIndices.filter(
6144
- (i) => this.errorPositions.has(i)
6145
- );
6146
- }
6147
- return candidateIndices.map((i) => entries[i]);
6148
- }
6149
- /**
6150
- * Incremental search — only scans new entries since last call with same query.
6151
- * Returns indices into filteredEntries (not this.entries).
6152
- */
6153
- getSearchMatches(filteredEntries, query) {
6154
- const q = query.trim().toLowerCase();
6155
- if (!q) return [];
6156
- if (filteredEntries !== this.lastFilteredRef) {
6157
- this.searchCache.clear();
6158
- this.lastFilteredRef = filteredEntries;
6159
- }
6160
- const cached = this.searchCache.get(q);
6161
- if (cached && cached.lastScanned === filteredEntries.length) {
6162
- return cached.matches;
6163
- }
6164
- const startFrom = cached ? cached.lastScanned : 0;
6165
- const matches = cached ? [...cached.matches] : [];
6166
- for (let i = startFrom; i < filteredEntries.length; i++) {
6167
- const searchText = this.getEntrySearchText(filteredEntries[i]);
6168
- if (searchText.toLowerCase().includes(q)) {
6169
- matches.push(i);
6170
- }
6171
- }
6172
- this.searchCache.set(q, { matches, lastScanned: filteredEntries.length });
6173
- if (this.searchCache.size > MAX_SEARCH_CACHE_SIZE) {
6174
- const oldest = this.searchCache.keys().next().value;
6175
- if (oldest !== void 0) {
6176
- this.searchCache.delete(oldest);
6177
- }
6178
- }
6179
- return matches;
6180
- }
6181
- // ── Search text helpers ─────────────────────────────────
6182
- getEntrySearchText(entry) {
6183
- const cached = this.searchTextCache.get(entry);
6184
- if (cached !== void 0) return cached;
6185
- if (!entry.feedEvent) {
6186
- this.searchTextCache.set(entry, entry.searchText);
6187
- return entry.searchText;
6188
- }
6189
- const details = this.getEntryDetails(entry);
6190
- const searchText = details ? `${entry.summary}
6191
- ${details}` : entry.summary;
6192
- this.searchTextCache.set(entry, searchText);
6193
- return searchText;
6194
- }
6195
- getEntryDetails(entry) {
6196
- if (entry.details) return entry.details;
6197
- if (!entry.feedEvent) return entry.summary;
6198
- const cached = this.detailCache.get(entry);
6199
- if (cached !== void 0) return cached;
6200
- const details = isEventExpandable(entry.feedEvent) ? expansionForEvent(entry.feedEvent) : "";
6201
- this.detailCache.set(entry, details);
6202
- return details;
6203
- }
6204
- // ── Run summary tracking ─────────────────────────────
6205
- /**
6206
- * Returns sorted run summaries. Cached until a run.start/run.end
6207
- * event invalidates the sorted array.
6208
- */
6209
- getRunSummaries() {
6210
- if (this._runSummariesDirty) {
6211
- this._runSummariesCache = Array.from(this._runSummaryMap.values()).sort(
6212
- (a, b) => a.startedAt - b.startedAt
6213
- );
6214
- this._runSummariesDirty = false;
6215
- }
6216
- return this._runSummariesCache;
6217
- }
6218
- processRunEvent(event) {
6219
- if (event.kind === "run.start") {
6220
- this._runSummaryMap.set(event.run_id, {
6221
- runId: event.run_id,
6222
- title: compactText(
6223
- event.data.trigger.prompt_preview || "Untitled run",
6224
- 46
6225
- ),
6226
- status: "RUNNING",
6227
- startedAt: event.ts
6228
- });
6229
- this._runSummariesDirty = true;
6230
- } else if (event.kind === "run.end") {
6231
- const existing = this._runSummaryMap.get(event.run_id);
6232
- if (existing) {
6233
- existing.status = toRunStatus(event);
6234
- existing.endedAt = event.ts;
6235
- } else {
6236
- this._runSummaryMap.set(event.run_id, {
6237
- runId: event.run_id,
6238
- title: "Untitled run",
6239
- status: toRunStatus(event),
6240
- startedAt: event.ts,
6241
- endedAt: event.ts
6242
- });
6243
- }
6244
- this._runSummariesDirty = true;
6245
- }
6246
- }
6247
- rebuildRunSummaries(feedEvents) {
6248
- this._runSummaryMap.clear();
6249
- this._runSummariesDirty = true;
6250
- this._lastFeedEventsLength = 0;
6251
- this.updateRunSummaries(feedEvents);
5966
+ toolName,
5967
+ toolInput,
5968
+ postEvent.data.tool_response
5969
+ );
5970
+ } else {
5971
+ return eventSummary(event);
6252
5972
  }
6253
- updateRunSummaries(feedEvents) {
6254
- for (let i = this._lastFeedEventsLength; i < feedEvents.length; i++) {
6255
- this.processRunEvent(feedEvents[i]);
6256
- }
6257
- this._lastFeedEventsLength = feedEvents.length;
5973
+ const prefix = primaryInput ? `${name} ${primaryInput}` : name;
5974
+ const prefixText = compactText(prefix, 200);
5975
+ const segments = primaryInput ? [
5976
+ { text: name, role: "verb" },
5977
+ { text: prefixText.slice(name.length), role: "target" }
5978
+ ] : [{ text: prefixText, role: "verb" }];
5979
+ if (!resultText) {
5980
+ return { text: prefixText, segments };
6258
5981
  }
6259
- // ── Index maintenance ─────────────────────────────────
6260
- addToIndex(entry, index) {
6261
- const runId = entry.runId ?? "__none__";
6262
- let indices = this.runIndex.get(runId);
6263
- if (!indices) {
6264
- indices = [];
6265
- this.runIndex.set(runId, indices);
6266
- }
6267
- indices.push(index);
6268
- if (entry.error) {
6269
- this.errorPositions.add(index);
6270
- }
5982
+ return {
5983
+ text: prefixText,
5984
+ segments,
5985
+ outcome: resultText,
5986
+ outcomeZero: /^0\s/.test(resultText)
5987
+ };
5988
+ }
5989
+ function mergedEventOperation(event, postEvent) {
5990
+ if (!postEvent) return eventOperation(event);
5991
+ const pair = TOOL_PAIRS[postEvent.kind];
5992
+ if (!pair) return eventOperation(event);
5993
+ return pair.operation(event, postEvent);
5994
+ }
5995
+ function mergedEventLabel(event, postEvent) {
5996
+ if (!postEvent) return eventLabel(event);
5997
+ const pair = TOOL_PAIRS[postEvent.kind];
5998
+ if (!pair) return eventLabel(event);
5999
+ return pair.label(event, postEvent);
6000
+ }
6001
+ function mergedEventSummary(event, postEvent) {
6002
+ if (!postEvent) return eventSummary(event);
6003
+ if (event.kind !== "tool.pre" && event.kind !== "permission.request") {
6004
+ return eventSummary(event);
6271
6005
  }
6272
- rebuildIndexes() {
6273
- this.runIndex.clear();
6274
- this.errorPositions.clear();
6275
- this.searchCache.clear();
6276
- const entries = this.getEntries();
6277
- for (let i = 0; i < entries.length; i++) {
6278
- this.addToIndex(entries[i], i);
6279
- }
6006
+ const pair = TOOL_PAIRS[postEvent.kind];
6007
+ if (!pair) return eventSummary(event);
6008
+ return pair.summary(event, postEvent);
6009
+ }
6010
+ var VERBOSE_ONLY_KINDS = /* @__PURE__ */ new Set([
6011
+ "session.start",
6012
+ "session.end",
6013
+ "run.start",
6014
+ "run.end",
6015
+ "unknown.hook",
6016
+ "compact.pre",
6017
+ "config.change",
6018
+ "turn.diff",
6019
+ "usage.update",
6020
+ "reasoning.summary"
6021
+ ]);
6022
+ function toRunStatus(event) {
6023
+ switch (event.data.status) {
6024
+ case "completed":
6025
+ return "SUCCEEDED";
6026
+ case "failed":
6027
+ return "FAILED";
6028
+ case "aborted":
6029
+ return "CANCELLED";
6280
6030
  }
6281
- };
6031
+ }
6282
6032
 
6283
6033
  // src/core/feed/toolDisplay.ts
6284
6034
  function prop2(obj, key) {
@@ -6992,14 +6742,9 @@ function resolveEventToolColumn(event) {
6992
6742
  }
6993
6743
  }
6994
6744
 
6995
- // src/ui/hooks/useTimeline.ts
6996
- var detailCache = /* @__PURE__ */ new WeakMap();
6997
- var searchTextCache = /* @__PURE__ */ new WeakMap();
6998
- var EMPTY_MATCHES = Object.freeze([]);
6999
- var EMPTY_MATCH_SET = Object.freeze(/* @__PURE__ */ new Set());
7000
- function subagentActorLabel(agentType, agentId) {
7001
- void agentType;
7002
- void agentId;
6745
+ // src/core/feed/indexedTimeline.ts
6746
+ var MAX_SEARCH_CACHE_SIZE = 8;
6747
+ function subagentActorLabel(_agentType, _agentId) {
7003
6748
  return "SUB AGENT";
7004
6749
  }
7005
6750
  function buildSubagentTypeMap(feedEvents) {
@@ -7170,7 +6915,7 @@ function sameFeedEventPrefix(previous, next) {
7170
6915
  }
7171
6916
  function canAppendIncrementally(previous, feedItems, feedEvents, verbose) {
7172
6917
  if (!previous) return false;
7173
- if (previous.verbose !== !!verbose) return false;
6918
+ if (previous.verbose !== verbose) return false;
7174
6919
  return sameFeedItemPrefix(previous.feedItems, feedItems) && sameFeedEventPrefix(previous.feedEvents, feedEvents);
7175
6920
  }
7176
6921
  function buildTimelineCache(feedItems, feedEvents, postByToolUseId, verbose) {
@@ -7202,109 +6947,274 @@ function buildTimelineCache(feedItems, feedEvents, postByToolUseId, verbose) {
7202
6947
  activeRunId = void 0;
7203
6948
  }
7204
6949
  }
7205
- computeDuplicateActors(entries);
7206
- return {
7207
- feedItems,
7208
- feedEvents,
7209
- entries,
7210
- activeRunId,
7211
- messageCounter,
7212
- subagentTypes,
7213
- pendingEntryIndexByToolUseId,
7214
- verbose: !!verbose
7215
- };
7216
- }
7217
- function appendTimelineCache(previous, feedItems, feedEvents, postByToolUseId) {
7218
- const entries = previous.entries.slice();
7219
- const subagentTypes = new Map(previous.subagentTypes);
7220
- updateSubagentTypeMap(
7221
- subagentTypes,
7222
- feedEvents.slice(previous.feedEvents.length)
7223
- );
7224
- const pendingEntryIndexByToolUseId = new Map(
7225
- previous.pendingEntryIndexByToolUseId
7226
- );
7227
- let activeRunId = previous.activeRunId;
7228
- let messageCounter = previous.messageCounter;
7229
- for (const item of feedItems.slice(previous.feedItems.length)) {
7230
- if (item.type === "message") {
7231
- const index = entries.push(
7232
- buildMessageEntry(item.data, activeRunId, messageCounter++)
7233
- ) - 1;
7234
- recomputeDuplicateActorsAround(entries, index);
7235
- continue;
6950
+ computeDuplicateActors(entries);
6951
+ return {
6952
+ feedItems,
6953
+ feedEvents,
6954
+ entries,
6955
+ activeRunId,
6956
+ messageCounter,
6957
+ subagentTypes,
6958
+ pendingEntryIndexByToolUseId,
6959
+ verbose
6960
+ };
6961
+ }
6962
+ function appendTimelineCache(previous, feedItems, feedEvents, postByToolUseId) {
6963
+ const entries = previous.entries.slice();
6964
+ const subagentTypes = new Map(previous.subagentTypes);
6965
+ updateSubagentTypeMap(
6966
+ subagentTypes,
6967
+ feedEvents.slice(previous.feedEvents.length)
6968
+ );
6969
+ const pendingEntryIndexByToolUseId = new Map(
6970
+ previous.pendingEntryIndexByToolUseId
6971
+ );
6972
+ let activeRunId = previous.activeRunId;
6973
+ let messageCounter = previous.messageCounter;
6974
+ for (const item of feedItems.slice(previous.feedItems.length)) {
6975
+ if (item.type === "message") {
6976
+ const index = entries.push(
6977
+ buildMessageEntry(item.data, activeRunId, messageCounter++)
6978
+ ) - 1;
6979
+ recomputeDuplicateActorsAround(entries, index);
6980
+ continue;
6981
+ }
6982
+ const event = item.data;
6983
+ if (event.kind === "run.start") {
6984
+ activeRunId = event.run_id;
6985
+ }
6986
+ const resolvedToolUseId = pendingToolUpdateUseId(event);
6987
+ if (resolvedToolUseId) {
6988
+ const pendingIndex = pendingEntryIndexByToolUseId.get(resolvedToolUseId);
6989
+ if (pendingIndex !== void 0) {
6990
+ const pendingEntry = entries[pendingIndex];
6991
+ if (pendingEntry.feedEvent) {
6992
+ entries[pendingIndex] = buildEventEntry(
6993
+ pendingEntry.feedEvent,
6994
+ subagentTypes,
6995
+ event
6996
+ );
6997
+ if (event.kind === "tool.post" || event.kind === "tool.failure") {
6998
+ pendingEntryIndexByToolUseId.delete(resolvedToolUseId);
6999
+ }
7000
+ recomputeDuplicateActorsAround(entries, pendingIndex);
7001
+ }
7002
+ }
7003
+ continue;
7004
+ }
7005
+ const entry = maybeBuildEventEntry(
7006
+ event,
7007
+ subagentTypes,
7008
+ postByToolUseId,
7009
+ previous.verbose
7010
+ );
7011
+ if (entry) {
7012
+ const index = entries.push(entry) - 1;
7013
+ recomputeDuplicateActorsAround(entries, index);
7014
+ rememberPendingEntry(pendingEntryIndexByToolUseId, entry, index);
7015
+ }
7016
+ if (event.kind === "run.end") {
7017
+ activeRunId = void 0;
7018
+ }
7019
+ }
7020
+ return {
7021
+ feedItems,
7022
+ feedEvents,
7023
+ entries,
7024
+ activeRunId,
7025
+ messageCounter,
7026
+ subagentTypes,
7027
+ pendingEntryIndexByToolUseId,
7028
+ verbose: previous.verbose
7029
+ };
7030
+ }
7031
+ var IndexedTimeline = class {
7032
+ cache = null;
7033
+ runIndex = /* @__PURE__ */ new Map();
7034
+ errorPositions = /* @__PURE__ */ new Set();
7035
+ _runSummaryMap = /* @__PURE__ */ new Map();
7036
+ _runSummariesDirty = true;
7037
+ _runSummariesCache = [];
7038
+ _lastFeedEventsLength = 0;
7039
+ searchCache = /* @__PURE__ */ new Map();
7040
+ lastFilteredRef = null;
7041
+ detailCache = /* @__PURE__ */ new WeakMap();
7042
+ searchTextCache = /* @__PURE__ */ new WeakMap();
7043
+ verbose = false;
7044
+ update(feedItems, feedEvents, postByToolUseId, verbose) {
7045
+ this.verbose = verbose;
7046
+ const incremental = canAppendIncrementally(
7047
+ this.cache,
7048
+ feedItems,
7049
+ feedEvents,
7050
+ this.verbose
7051
+ );
7052
+ if (incremental) {
7053
+ this.updateRunSummaries(feedEvents);
7054
+ this.cache = appendTimelineCache(
7055
+ this.cache,
7056
+ feedItems,
7057
+ feedEvents,
7058
+ postByToolUseId
7059
+ );
7060
+ } else {
7061
+ this.rebuildRunSummaries(feedEvents);
7062
+ this.cache = buildTimelineCache(
7063
+ feedItems,
7064
+ feedEvents,
7065
+ postByToolUseId,
7066
+ this.verbose
7067
+ );
7068
+ }
7069
+ this.rebuildIndexes();
7070
+ }
7071
+ getEntries() {
7072
+ return this.cache?.entries ?? [];
7073
+ }
7074
+ getFilteredView(runFilter, errorsOnly) {
7075
+ const entries = this.getEntries();
7076
+ if ((!runFilter || runFilter === "all") && !errorsOnly) {
7077
+ return entries;
7078
+ }
7079
+ let candidateIndices;
7080
+ if (runFilter && runFilter !== "all") {
7081
+ candidateIndices = this.runIndex.get(runFilter) ?? [];
7082
+ } else {
7083
+ candidateIndices = Array.from({ length: entries.length }, (_, i) => i);
7084
+ }
7085
+ if (errorsOnly) {
7086
+ candidateIndices = candidateIndices.filter(
7087
+ (i) => this.errorPositions.has(i)
7088
+ );
7089
+ }
7090
+ return candidateIndices.map((i) => entries[i]);
7091
+ }
7092
+ getSearchMatches(filteredEntries, query) {
7093
+ const q = query.trim().toLowerCase();
7094
+ if (!q) return [];
7095
+ if (filteredEntries !== this.lastFilteredRef) {
7096
+ this.searchCache.clear();
7097
+ this.lastFilteredRef = filteredEntries;
7098
+ }
7099
+ const cached = this.searchCache.get(q);
7100
+ if (cached && cached.lastScanned === filteredEntries.length) {
7101
+ return cached.matches;
7102
+ }
7103
+ const startFrom = cached ? cached.lastScanned : 0;
7104
+ const matches = cached ? [...cached.matches] : [];
7105
+ for (let i = startFrom; i < filteredEntries.length; i++) {
7106
+ const searchText = this.getEntrySearchText(filteredEntries[i]);
7107
+ if (searchText.toLowerCase().includes(q)) {
7108
+ matches.push(i);
7109
+ }
7110
+ }
7111
+ this.searchCache.set(q, { matches, lastScanned: filteredEntries.length });
7112
+ if (this.searchCache.size > MAX_SEARCH_CACHE_SIZE) {
7113
+ const oldest = this.searchCache.keys().next().value;
7114
+ if (oldest !== void 0) {
7115
+ this.searchCache.delete(oldest);
7116
+ }
7117
+ }
7118
+ return matches;
7119
+ }
7120
+ getEntrySearchText(entry) {
7121
+ const cached = this.searchTextCache.get(entry);
7122
+ if (cached !== void 0) return cached;
7123
+ if (!entry.feedEvent) {
7124
+ this.searchTextCache.set(entry, entry.searchText);
7125
+ return entry.searchText;
7126
+ }
7127
+ const details = this.getEntryDetails(entry);
7128
+ const searchText = details ? `${entry.summary}
7129
+ ${details}` : entry.summary;
7130
+ this.searchTextCache.set(entry, searchText);
7131
+ return searchText;
7132
+ }
7133
+ getEntryDetails(entry) {
7134
+ if (entry.details) return entry.details;
7135
+ if (!entry.feedEvent) return entry.summary;
7136
+ const cached = this.detailCache.get(entry);
7137
+ if (cached !== void 0) return cached;
7138
+ const details = isEventExpandable(entry.feedEvent) ? expansionForEvent(entry.feedEvent) : "";
7139
+ this.detailCache.set(entry, details);
7140
+ return details;
7141
+ }
7142
+ getRunSummaries() {
7143
+ if (this._runSummariesDirty) {
7144
+ this._runSummariesCache = Array.from(this._runSummaryMap.values()).sort(
7145
+ (a, b) => a.startedAt - b.startedAt
7146
+ );
7147
+ this._runSummariesDirty = false;
7236
7148
  }
7237
- const event = item.data;
7149
+ return this._runSummariesCache;
7150
+ }
7151
+ processRunEvent(event) {
7238
7152
  if (event.kind === "run.start") {
7239
- activeRunId = event.run_id;
7240
- }
7241
- const resolvedToolUseId = pendingToolUpdateUseId(event);
7242
- if (resolvedToolUseId) {
7243
- const pendingIndex = pendingEntryIndexByToolUseId.get(resolvedToolUseId);
7244
- if (pendingIndex !== void 0) {
7245
- const pendingEntry = entries[pendingIndex];
7246
- if (pendingEntry.feedEvent) {
7247
- entries[pendingIndex] = buildEventEntry(
7248
- pendingEntry.feedEvent,
7249
- subagentTypes,
7250
- event
7251
- );
7252
- if (event.kind === "tool.post" || event.kind === "tool.failure") {
7253
- pendingEntryIndexByToolUseId.delete(resolvedToolUseId);
7254
- }
7255
- recomputeDuplicateActorsAround(entries, pendingIndex);
7256
- }
7153
+ this._runSummaryMap.set(event.run_id, {
7154
+ runId: event.run_id,
7155
+ title: compactText(
7156
+ event.data.trigger.prompt_preview || "Untitled run",
7157
+ 46
7158
+ ),
7159
+ status: "RUNNING",
7160
+ startedAt: event.ts
7161
+ });
7162
+ this._runSummariesDirty = true;
7163
+ } else if (event.kind === "run.end") {
7164
+ const existing = this._runSummaryMap.get(event.run_id);
7165
+ if (existing) {
7166
+ existing.status = toRunStatus(event);
7167
+ existing.endedAt = event.ts;
7168
+ } else {
7169
+ this._runSummaryMap.set(event.run_id, {
7170
+ runId: event.run_id,
7171
+ title: "Untitled run",
7172
+ status: toRunStatus(event),
7173
+ startedAt: event.ts,
7174
+ endedAt: event.ts
7175
+ });
7257
7176
  }
7258
- continue;
7177
+ this._runSummariesDirty = true;
7259
7178
  }
7260
- const entry = maybeBuildEventEntry(
7261
- event,
7262
- subagentTypes,
7263
- postByToolUseId,
7264
- previous.verbose
7265
- );
7266
- if (entry) {
7267
- const index = entries.push(entry) - 1;
7268
- recomputeDuplicateActorsAround(entries, index);
7269
- rememberPendingEntry(pendingEntryIndexByToolUseId, entry, index);
7179
+ }
7180
+ rebuildRunSummaries(feedEvents) {
7181
+ this._runSummaryMap.clear();
7182
+ this._runSummariesDirty = true;
7183
+ this._lastFeedEventsLength = 0;
7184
+ this.updateRunSummaries(feedEvents);
7185
+ }
7186
+ updateRunSummaries(feedEvents) {
7187
+ for (let i = this._lastFeedEventsLength; i < feedEvents.length; i++) {
7188
+ this.processRunEvent(feedEvents[i]);
7270
7189
  }
7271
- if (event.kind === "run.end") {
7272
- activeRunId = void 0;
7190
+ this._lastFeedEventsLength = feedEvents.length;
7191
+ }
7192
+ addToIndex(entry, index) {
7193
+ const runId = entry.runId ?? "__none__";
7194
+ let indices = this.runIndex.get(runId);
7195
+ if (!indices) {
7196
+ indices = [];
7197
+ this.runIndex.set(runId, indices);
7198
+ }
7199
+ indices.push(index);
7200
+ if (entry.error) {
7201
+ this.errorPositions.add(index);
7273
7202
  }
7274
7203
  }
7275
- return {
7276
- feedItems,
7277
- feedEvents,
7278
- entries,
7279
- activeRunId,
7280
- messageCounter,
7281
- subagentTypes,
7282
- pendingEntryIndexByToolUseId,
7283
- verbose: previous.verbose
7284
- };
7285
- }
7286
- function getTimelineEntryDetails(entry) {
7287
- if (entry.details) return entry.details;
7288
- if (!entry.feedEvent) return entry.summary;
7289
- const cached = detailCache.get(entry);
7290
- if (cached !== void 0) return cached;
7291
- const details = isEventExpandable(entry.feedEvent) ? expansionForEvent(entry.feedEvent) : "";
7292
- detailCache.set(entry, details);
7293
- return details;
7294
- }
7295
- function getTimelineEntrySearchText(entry) {
7296
- const cached = searchTextCache.get(entry);
7297
- if (cached !== void 0) return cached;
7298
- if (!entry.feedEvent) {
7299
- searchTextCache.set(entry, entry.searchText);
7300
- return entry.searchText;
7204
+ rebuildIndexes() {
7205
+ this.runIndex.clear();
7206
+ this.errorPositions.clear();
7207
+ this.searchCache.clear();
7208
+ const entries = this.getEntries();
7209
+ for (let i = 0; i < entries.length; i++) {
7210
+ this.addToIndex(entries[i], i);
7211
+ }
7301
7212
  }
7302
- const details = getTimelineEntryDetails(entry);
7303
- const searchText = details ? `${entry.summary}
7304
- ${details}` : entry.summary;
7305
- searchTextCache.set(entry, searchText);
7306
- return searchText;
7307
- }
7213
+ };
7214
+
7215
+ // src/ui/hooks/useTimeline.ts
7216
+ var EMPTY_MATCHES = Object.freeze([]);
7217
+ var EMPTY_MATCH_SET = Object.freeze(/* @__PURE__ */ new Set());
7308
7218
  function useTimeline({
7309
7219
  feedItems,
7310
7220
  feedEvents,
@@ -7362,12 +7272,17 @@ function useTimeline({
7362
7272
  () => searchMatches === EMPTY_MATCHES ? EMPTY_MATCH_SET : new Set(searchMatches),
7363
7273
  [searchMatches]
7364
7274
  );
7275
+ const getEntrySearchText = useCallback10(
7276
+ (entry) => indexedRef.current.getEntrySearchText(entry),
7277
+ []
7278
+ );
7365
7279
  return {
7366
7280
  timelineEntries,
7367
7281
  runSummaries,
7368
7282
  filteredEntries,
7369
7283
  searchMatches,
7370
- searchMatchSet
7284
+ searchMatchSet,
7285
+ getEntrySearchText
7371
7286
  };
7372
7287
  }
7373
7288
 
@@ -7448,7 +7363,7 @@ function useLayout({
7448
7363
 
7449
7364
  // src/ui/hooks/usePager.ts
7450
7365
  import process5 from "process";
7451
- import { useState as useState10, useCallback as useCallback10, useRef as useRef11, useEffect as useEffect9 } from "react";
7366
+ import { useState as useState10, useCallback as useCallback11, useRef as useRef11, useEffect as useEffect9 } from "react";
7452
7367
  import { useInput as useInput11 } from "ink";
7453
7368
 
7454
7369
  // src/shared/utils/clipboard.ts
@@ -7477,6 +7392,30 @@ function getClipboardCommand() {
7477
7392
  return null;
7478
7393
  }
7479
7394
 
7395
+ // src/core/feed/defaultRender.ts
7396
+ var DEFAULT_RENDER = /* @__PURE__ */ new Set([
7397
+ "compact.post",
7398
+ "task.created",
7399
+ "cwd.changed",
7400
+ "file.changed",
7401
+ "stop.failure",
7402
+ "permission.denied",
7403
+ "elicitation.request",
7404
+ "elicitation.result",
7405
+ "channel.permission.relayed",
7406
+ "channel.permission.resolved",
7407
+ "channel.question.relayed",
7408
+ "channel.question.resolved",
7409
+ "channel.chat.inbound",
7410
+ "channel.chat.outbound",
7411
+ "gateway.function.invoked",
7412
+ "gateway.function.completed",
7413
+ "gateway.function.failed"
7414
+ ]);
7415
+ function isDefaultRenderKind(k) {
7416
+ return DEFAULT_RENDER.has(k);
7417
+ }
7418
+
7480
7419
  // src/ui/tooling/toolExtractors.ts
7481
7420
  var EXT_TO_LANGUAGE = {
7482
7421
  ".ts": "typescript",
@@ -8571,13 +8510,13 @@ function usePager({
8571
8510
  const pagerActiveRef = useRef11(false);
8572
8511
  const pagerEntryIdRef = useRef11(null);
8573
8512
  const lastPairedPostRef = useRef11(void 0);
8574
- const clearCopyToastTimer = useCallback10(() => {
8513
+ const clearCopyToastTimer = useCallback11(() => {
8575
8514
  if (copyToastTimerRef.current) {
8576
8515
  clearTimeout(copyToastTimerRef.current);
8577
8516
  copyToastTimerRef.current = null;
8578
8517
  }
8579
8518
  }, []);
8580
- const paintPager = useCallback10(() => {
8519
+ const paintPager = useCallback11(() => {
8581
8520
  const lines = pagerLinesRef.current;
8582
8521
  const scroll = pagerScrollRef.current;
8583
8522
  const contentRows = pagerContentRows();
@@ -8600,7 +8539,7 @@ function usePager({
8600
8539
  margin + source_default.dim(`${pos} \u2191/\u2193 j/k scroll PgUp/PgDn page y copy q exit`)
8601
8540
  );
8602
8541
  }, []);
8603
- const scrollPager = useCallback10(
8542
+ const scrollPager = useCallback11(
8604
8543
  (delta) => {
8605
8544
  const contentRows = pagerContentRows();
8606
8545
  const maxScroll = Math.max(0, pagerLinesRef.current.length - contentRows);
@@ -8612,7 +8551,7 @@ function usePager({
8612
8551
  },
8613
8552
  [paintPager]
8614
8553
  );
8615
- const handleExpandForPager = useCallback10(() => {
8554
+ const handleExpandForPager = useCallback11(() => {
8616
8555
  const entry = displayedEntriesRef.current.find((e) => e.id === feedCursorId);
8617
8556
  if (!entry?.expandable) return;
8618
8557
  pendingPagerEntryRef.current = entry;
@@ -8755,7 +8694,7 @@ function usePager({
8755
8694
  }
8756
8695
 
8757
8696
  // src/ui/hooks/useFrameChrome.ts
8758
- import { useMemo as useMemo10, useCallback as useCallback11 } from "react";
8697
+ import { useMemo as useMemo10, useCallback as useCallback12 } from "react";
8759
8698
 
8760
8699
  // src/ui/layout/buildFrameLines.ts
8761
8700
  function buildHintPairs(pairs) {
@@ -8945,7 +8884,7 @@ function useFrameChrome({
8945
8884
  sectionBorder: `${glyphs.teeLeft}${spliceJunction(hFill, glyphs.cross)}${glyphs.teeRight}`
8946
8885
  };
8947
8886
  }, [glyphs, innerWidth, dividerColumn]);
8948
- const frameLine = useCallback11(
8887
+ const frameLine = useCallback12(
8949
8888
  (content) => `${glyphs.vertical}${fitAnsi(content, innerWidth)}${glyphs.vertical}`,
8950
8889
  [glyphs.vertical, innerWidth]
8951
8890
  );
@@ -11122,24 +11061,24 @@ function renderYankLines(entry, width, theme) {
11122
11061
  }
11123
11062
 
11124
11063
  // src/setup/SetupWizard.tsx
11125
- import { useState as useState14, useCallback as useCallback14, useEffect as useEffect10, useRef as useRef13 } from "react";
11064
+ import { useState as useState14, useCallback as useCallback15, useEffect as useEffect10, useRef as useRef13 } from "react";
11126
11065
  import { Box as Box16, Text as Text22, useInput as useInput13 } from "ink";
11127
11066
 
11128
11067
  // src/setup/useSetupState.ts
11129
- import { useState as useState12, useCallback as useCallback12 } from "react";
11068
+ import { useState as useState12, useCallback as useCallback13 } from "react";
11130
11069
  var TOTAL_STEPS = 2;
11131
11070
  function useSetupState() {
11132
11071
  const [stepIndex, setStepIndex] = useState12(0);
11133
11072
  const [stepState, setStepState] = useState12("selecting");
11134
- const startVerifying = useCallback12(() => setStepState("verifying"), []);
11135
- const markSuccess = useCallback12(() => setStepState("success"), []);
11136
- const markError = useCallback12(() => setStepState("error"), []);
11137
- const retry = useCallback12(() => setStepState("selecting"), []);
11138
- const advance = useCallback12(() => {
11073
+ const startVerifying = useCallback13(() => setStepState("verifying"), []);
11074
+ const markSuccess = useCallback13(() => setStepState("success"), []);
11075
+ const markError = useCallback13(() => setStepState("error"), []);
11076
+ const retry = useCallback13(() => setStepState("selecting"), []);
11077
+ const advance = useCallback13(() => {
11139
11078
  setStepIndex((prev) => prev + 1);
11140
11079
  setStepState("selecting");
11141
11080
  }, []);
11142
- const retreat = useCallback12(() => {
11081
+ const retreat = useCallback13(() => {
11143
11082
  setStepIndex((prev) => Math.max(0, prev - 1));
11144
11083
  setStepState("selecting");
11145
11084
  }, []);
@@ -11193,7 +11132,7 @@ function ThemeStep({ onComplete, onPreview }) {
11193
11132
  }
11194
11133
 
11195
11134
  // src/setup/steps/HarnessStep.tsx
11196
- import { useState as useState13, useCallback as useCallback13 } from "react";
11135
+ import { useState as useState13, useCallback as useCallback14 } from "react";
11197
11136
  import { Box as Box13, Text as Text19 } from "ink";
11198
11137
  import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
11199
11138
  function HarnessStep({ onComplete, onError }) {
@@ -11202,7 +11141,7 @@ function HarnessStep({ onComplete, onError }) {
11202
11141
  const [status, setStatus] = useState13("selecting");
11203
11142
  const [message, setMessage] = useState13("");
11204
11143
  const [checks, setChecks] = useState13([]);
11205
- const renderCheckLine = useCallback13(
11144
+ const renderCheckLine = useCallback14(
11206
11145
  (check) => {
11207
11146
  const glyph = check.status === "pass" ? "\u2713" : check.status === "fail" ? "\u2717" : "!";
11208
11147
  const color = check.status === "pass" ? theme.status.success : check.status === "fail" ? theme.status.error : theme.status.warning;
@@ -11210,7 +11149,7 @@ function HarnessStep({ onComplete, onError }) {
11210
11149
  },
11211
11150
  [theme.status.error, theme.status.success, theme.status.warning]
11212
11151
  );
11213
- const handleSelect = useCallback13(
11152
+ const handleSelect = useCallback14(
11214
11153
  (value) => {
11215
11154
  const capability = capabilities.find(
11216
11155
  (c2) => c2.id === value
@@ -11345,7 +11284,7 @@ function SetupWizard({ onComplete, onThemePreview }) {
11345
11284
  const [writeRetryCount, setWriteRetryCount] = useState14(0);
11346
11285
  const themePreviewRef = useRef13(result.theme);
11347
11286
  const completedRef = useRef13(false);
11348
- const handleThemeComplete = useCallback14(
11287
+ const handleThemeComplete = useCallback15(
11349
11288
  (theme2) => {
11350
11289
  themePreviewRef.current = theme2;
11351
11290
  setResult((prev) => ({ ...prev, theme: theme2 }));
@@ -11354,25 +11293,25 @@ function SetupWizard({ onComplete, onThemePreview }) {
11354
11293
  },
11355
11294
  [markSuccess, onThemePreview]
11356
11295
  );
11357
- const handleThemePreview = useCallback14(
11296
+ const handleThemePreview = useCallback15(
11358
11297
  (nextTheme) => {
11359
11298
  themePreviewRef.current = nextTheme;
11360
11299
  onThemePreview?.(nextTheme);
11361
11300
  },
11362
11301
  [onThemePreview]
11363
11302
  );
11364
- const handleHarnessComplete = useCallback14(
11303
+ const handleHarnessComplete = useCallback15(
11365
11304
  (harness) => {
11366
11305
  setResult((prev) => ({ ...prev, harness }));
11367
11306
  markSuccess();
11368
11307
  },
11369
11308
  [markSuccess]
11370
11309
  );
11371
- const handleHarnessSkip = useCallback14(() => {
11310
+ const handleHarnessSkip = useCallback15(() => {
11372
11311
  setResult((prev) => ({ ...prev, harness: void 0 }));
11373
11312
  markSuccess();
11374
11313
  }, [markSuccess]);
11375
- const handleSkipShortcut = useCallback14(() => {
11314
+ const handleSkipShortcut = useCallback15(() => {
11376
11315
  if (stepState !== "selecting" || isComplete) {
11377
11316
  return;
11378
11317
  }
@@ -11493,7 +11432,7 @@ function SetupWizard({ onComplete, onThemePreview }) {
11493
11432
  }
11494
11433
 
11495
11434
  // src/app/workflow/WorkflowPicker.tsx
11496
- import { useState as useState15, useCallback as useCallback15, useEffect as useEffect11 } from "react";
11435
+ import { useState as useState15, useCallback as useCallback16, useEffect as useEffect11 } from "react";
11497
11436
  import { Box as Box17, Text as Text23, useInput as useInput14, useStdout as useStdout7 } from "ink";
11498
11437
 
11499
11438
  // src/core/workflows/workflowOptions.ts
@@ -11593,7 +11532,7 @@ function WorkflowPicker({
11593
11532
  }
11594
11533
  }
11595
11534
  });
11596
- const handleSelect = useCallback15(
11535
+ const handleSelect = useCallback16(
11597
11536
  (value) => {
11598
11537
  if (value === "default") {
11599
11538
  writeProjectConfig(projectDir, { activeWorkflow: "default" });
@@ -11631,7 +11570,7 @@ function WorkflowPicker({
11631
11570
  },
11632
11571
  [onComplete, projectDir]
11633
11572
  );
11634
- const handleMcpComplete = useCallback15(
11573
+ const handleMcpComplete = useCallback16(
11635
11574
  (choices) => {
11636
11575
  if (phase.type !== "mcp-options") return;
11637
11576
  const { workflowName } = phase;
@@ -11694,7 +11633,7 @@ function WorkflowPicker({
11694
11633
  }
11695
11634
 
11696
11635
  // src/app/modelPreferences/ModelPicker.tsx
11697
- import { useState as useState16, useEffect as useEffect12, useCallback as useCallback16 } from "react";
11636
+ import { useState as useState16, useEffect as useEffect12, useCallback as useCallback17 } from "react";
11698
11637
  import { Box as Box18, Text as Text24, useInput as useInput15, useStdout as useStdout8 } from "ink";
11699
11638
 
11700
11639
  // src/app/modelPreferences/listAvailableModels.ts
@@ -11761,7 +11700,7 @@ function ModelPicker({
11761
11700
  const { stdout } = useStdout8();
11762
11701
  const frameWidth = Math.min(stdout.columns - 4, 72);
11763
11702
  const [phase, setPhase] = useState16({ type: "loading" });
11764
- const loadModels = useCallback16(() => {
11703
+ const loadModels = useCallback17(() => {
11765
11704
  setPhase({ type: "loading" });
11766
11705
  setTimeout(() => {
11767
11706
  void listAvailableModels({ harness, runtime }).then((options) => {
@@ -11793,7 +11732,7 @@ function ModelPicker({
11793
11732
  loadModels();
11794
11733
  }
11795
11734
  });
11796
- const handleSelect = useCallback16(
11735
+ const handleSelect = useCallback17(
11797
11736
  (value) => {
11798
11737
  setPhase({ type: "saving", model: value });
11799
11738
  setTimeout(() => {
@@ -11882,7 +11821,7 @@ function useRuntimeSelectors() {
11882
11821
  const questionQueueCount = useHookContextSelector((v) => v.questionQueueCount);
11883
11822
  const resolveQuestion = useHookContextSelector((v) => v.resolveQuestion);
11884
11823
  const isServerRunning = useHookContextSelector((v) => v.isServerRunning);
11885
- const runtimeError = useHookContextSelector((v) => v.runtimeError);
11824
+ const runtimeError2 = useHookContextSelector((v) => v.runtimeError);
11886
11825
  const postByToolUseId = useHookContextSelector((v) => v.postByToolUseId);
11887
11826
  const allocateSeq = useHookContextSelector((v) => v.allocateSeq);
11888
11827
  const clearEvents = useHookContextSelector((v) => v.clearEvents);
@@ -11907,7 +11846,7 @@ function useRuntimeSelectors() {
11907
11846
  questionQueueCount,
11908
11847
  resolveQuestion,
11909
11848
  isServerRunning,
11910
- runtimeError,
11849
+ runtimeError: runtimeError2,
11911
11850
  postByToolUseId,
11912
11851
  allocateSeq,
11913
11852
  clearEvents,
@@ -11958,16 +11897,16 @@ function useTimelineCurrentRun(currentRun) {
11958
11897
  }
11959
11898
 
11960
11899
  // src/app/shell/useShellInput.ts
11961
- import { useState as useState17, useCallback as useCallback17, useRef as useRef14 } from "react";
11900
+ import { useState as useState17, useCallback as useCallback18, useRef as useRef14 } from "react";
11962
11901
  function deriveInputMode(value) {
11963
11902
  if (value.startsWith("/")) return "command";
11964
11903
  if (value.startsWith(":")) return "search";
11965
11904
  return "normal";
11966
11905
  }
11967
- function findFirstSearchMatch(entries, query, startIndex) {
11906
+ function findFirstSearchMatch(entries, query, startIndex, getEntrySearchText) {
11968
11907
  const q = query.toLowerCase();
11969
11908
  for (let i = startIndex; i < entries.length; i++) {
11970
- if (getTimelineEntrySearchText(entries[i]).toLowerCase().includes(q)) {
11909
+ if (getEntrySearchText(entries[i]).toLowerCase().includes(q)) {
11971
11910
  return i;
11972
11911
  }
11973
11912
  }
@@ -11981,13 +11920,14 @@ function useShellInput({
11981
11920
  submitSearchQuery,
11982
11921
  submitPromptOrSlashCommand,
11983
11922
  displayedEntriesRef,
11923
+ getEntrySearchText,
11984
11924
  getSelectedCommand
11985
11925
  }) {
11986
11926
  const setInputValueRef = useRef14(() => {
11987
11927
  });
11988
11928
  const inputValueRef = useRef14("");
11989
11929
  const [inputRows, setInputRows] = useState17(1);
11990
- const syncInputModeFromValue = useCallback17(
11930
+ const syncInputModeFromValue = useCallback18(
11991
11931
  (value) => {
11992
11932
  const nextMode = deriveInputMode(value);
11993
11933
  setInputMode(nextMode);
@@ -11998,7 +11938,7 @@ function useShellInput({
11998
11938
  [setInputMode, setSearchQuery]
11999
11939
  );
12000
11940
  const inputContentWidthRef = useRef14(1);
12001
- const handleSetValueRef = useCallback17(
11941
+ const handleSetValueRef = useCallback18(
12002
11942
  (setValue) => {
12003
11943
  setInputValueRef.current = (value) => {
12004
11944
  inputValueRef.current = value;
@@ -12009,7 +11949,7 @@ function useShellInput({
12009
11949
  },
12010
11950
  [syncInputModeFromValue]
12011
11951
  );
12012
- const handleInputSubmit = useCallback17(
11952
+ const handleInputSubmit = useCallback18(
12013
11953
  (rawValue) => {
12014
11954
  const trimmed = rawValue.trim();
12015
11955
  if (trimmed) {
@@ -12023,7 +11963,12 @@ function useShellInput({
12023
11963
  }
12024
11964
  } else if (inputMode === "search") {
12025
11965
  const query = trimmed.replace(/^:/, "").trim();
12026
- const firstIdx = query.length > 0 ? findFirstSearchMatch(displayedEntriesRef.current, query, 0) : -1;
11966
+ const firstIdx = query.length > 0 ? findFirstSearchMatch(
11967
+ displayedEntriesRef.current,
11968
+ query,
11969
+ 0,
11970
+ getEntrySearchText
11971
+ ) : -1;
12027
11972
  submitSearchQuery(query, firstIdx >= 0 ? firstIdx : null);
12028
11973
  } else {
12029
11974
  submitPromptOrSlashCommand(trimmed);
@@ -12041,10 +11986,11 @@ function useShellInput({
12041
11986
  getSelectedCommand,
12042
11987
  closeInput,
12043
11988
  submitSearchQuery,
12044
- displayedEntriesRef
11989
+ displayedEntriesRef,
11990
+ getEntrySearchText
12045
11991
  ]
12046
11992
  );
12047
- const handleMainInputChange = useCallback17(
11993
+ const handleMainInputChange = useCallback18(
12048
11994
  (value) => {
12049
11995
  inputValueRef.current = value;
12050
11996
  syncInputModeFromValue(value);
@@ -12850,7 +12796,7 @@ function AppContent({
12850
12796
  const searchQuery = uiState.searchQuery;
12851
12797
  const perfEnabled = isPerfEnabled();
12852
12798
  usePerfRenderLog(perfEnabled, "app.main.content.render");
12853
- const handleSectionProfilerRender = useCallback18(
12799
+ const handleSectionProfilerRender = useCallback19(
12854
12800
  (id, phaseName, actualDuration, baseDuration, startTime, commitTime) => {
12855
12801
  logReactCommit(
12856
12802
  id,
@@ -12884,7 +12830,7 @@ function AppContent({
12884
12830
  isServerRunning,
12885
12831
  recordTokens,
12886
12832
  restoredTokens,
12887
- runtimeError,
12833
+ runtimeError: runtimeError2,
12888
12834
  hookCommandFeed
12889
12835
  } = useRuntimeSelectors();
12890
12836
  const currentSessionId = session?.session_id ?? null;
@@ -12892,7 +12838,7 @@ function AppContent({
12892
12838
  const timelineCurrentRun = useTimelineCurrentRun(currentRun);
12893
12839
  const harnessLabel = detectHarness(harness);
12894
12840
  const shouldTrackClaudeStartup = shouldTrackStartupDiagnostics(harness);
12895
- const onExitTokens = useCallback18(
12841
+ const onExitTokens = useCallback19(
12896
12842
  (tokens) => {
12897
12843
  if (session?.session_id) {
12898
12844
  recordTokens(session.session_id, tokens);
@@ -12900,7 +12846,7 @@ function AppContent({
12900
12846
  },
12901
12847
  [session?.session_id, recordTokens]
12902
12848
  );
12903
- const emitClaudeStartupDiagnostics = useCallback18(
12849
+ const emitClaudeStartupDiagnostics = useCallback19(
12904
12850
  (event) => {
12905
12851
  trackClaudeStartupFailed({
12906
12852
  harness,
@@ -12911,7 +12857,7 @@ function AppContent({
12911
12857
  },
12912
12858
  [harness]
12913
12859
  );
12914
- const onProcessLifecycleEvent = useCallback18(
12860
+ const onProcessLifecycleEvent = useCallback19(
12915
12861
  (event) => {
12916
12862
  const startupAttempt = startupAttemptRef.current;
12917
12863
  const isStartupFailure = shouldTrackClaudeStartup && startupAttempt !== null;
@@ -13029,7 +12975,7 @@ function AppContent({
13029
12975
  if (!current) {
13030
12976
  return current;
13031
12977
  }
13032
- const isActiveHookServerStartupFailure = current.failureStage === "startup_timeout" && !!runtimeError && !isServerRunning && current.message === runtimeError.message;
12978
+ const isActiveHookServerStartupFailure = current.failureStage === "startup_timeout" && !!runtimeError2 && !isServerRunning && current.message === runtimeError2.message;
13033
12979
  if (isActiveHookServerStartupFailure) {
13034
12980
  return current;
13035
12981
  }
@@ -13038,21 +12984,21 @@ function AppContent({
13038
12984
  }
13039
12985
  return null;
13040
12986
  });
13041
- }, [feedEvents.length, isServerRunning, runtimeError]);
12987
+ }, [feedEvents.length, isServerRunning, runtimeError2]);
13042
12988
  useEffect14(() => {
13043
12989
  if (!shouldTrackClaudeStartup || !isTelemetryEnabled()) return;
13044
- if (!runtimeError || isServerRunning) {
12990
+ if (!runtimeError2 || isServerRunning) {
13045
12991
  runtimeStartupDiagnosticsSignatureRef.current = null;
13046
12992
  return;
13047
12993
  }
13048
- const signature = `${runtimeError.code}:${runtimeError.message}`;
12994
+ const signature = `${runtimeError2.code}:${runtimeError2.message}`;
13049
12995
  if (signature === runtimeStartupDiagnosticsSignatureRef.current) {
13050
12996
  return;
13051
12997
  }
13052
12998
  runtimeStartupDiagnosticsSignatureRef.current = signature;
13053
12999
  const diagnosticsEvent = createPendingStartupDiagnosticsEvent({
13054
13000
  failureStage: "startup_timeout",
13055
- message: runtimeError.message,
13001
+ message: runtimeError2.message,
13056
13002
  feedEventCount: feedEvents.length
13057
13003
  });
13058
13004
  if (diagnosticsConsent === true) {
@@ -13065,7 +13011,7 @@ function AppContent({
13065
13011
  emitClaudeStartupDiagnostics,
13066
13012
  feedEvents.length,
13067
13013
  isServerRunning,
13068
- runtimeError,
13014
+ runtimeError2,
13069
13015
  shouldTrackClaudeStartup
13070
13016
  ]);
13071
13017
  useEffect14(() => {
@@ -13080,7 +13026,7 @@ function AppContent({
13080
13026
  return;
13081
13027
  }
13082
13028
  const derivedFailure = deriveStartupTimeoutFailure({
13083
- runtimeError,
13029
+ runtimeError: runtimeError2,
13084
13030
  isServerRunning,
13085
13031
  isHarnessRunning,
13086
13032
  harnessLabel
@@ -13117,10 +13063,10 @@ function AppContent({
13117
13063
  harnessLabel,
13118
13064
  isHarnessRunning,
13119
13065
  isServerRunning,
13120
- runtimeError,
13066
+ runtimeError2,
13121
13067
  shouldTrackClaudeStartup
13122
13068
  ]);
13123
- const addMessage = useCallback18(
13069
+ const addMessage = useCallback19(
13124
13070
  (role, content) => {
13125
13071
  const newMessage = {
13126
13072
  id: generateId(),
@@ -13134,7 +13080,7 @@ function AppContent({
13134
13080
  },
13135
13081
  [allocateSeq]
13136
13082
  );
13137
- const clearScreen = useCallback18(() => {
13083
+ const clearScreen = useCallback19(() => {
13138
13084
  onSessionTelemetrySnapshot(metrics);
13139
13085
  clearEvents();
13140
13086
  process6.stdout.write("\x1B[2J\x1B[3J\x1B[H");
@@ -13148,7 +13094,7 @@ function AppContent({
13148
13094
  postByToolUseId,
13149
13095
  verbose
13150
13096
  });
13151
- const { runSummaries, filteredEntries, searchMatches } = timeline;
13097
+ const { runSummaries, filteredEntries, searchMatches, getEntrySearchText } = timeline;
13152
13098
  const todoPanel = useTodoPanel({
13153
13099
  tasks,
13154
13100
  isWorking: appMode.type === "working",
@@ -13209,7 +13155,7 @@ function AppContent({
13209
13155
  messageEntryLineOffsets: [],
13210
13156
  messageContentRows: 0
13211
13157
  });
13212
- const dispatchUi = useCallback18((action) => {
13158
+ const dispatchUi = useCallback19((action) => {
13213
13159
  setUiState(
13214
13160
  (prev) => reduceSessionUiState(prev, action, uiContextRef.current)
13215
13161
  );
@@ -13221,7 +13167,7 @@ function AppContent({
13221
13167
  previousWorkflowPickerVisibleRef.current = workflowPickerVisible;
13222
13168
  previousModelPickerVisibleRef.current = modelPickerVisible;
13223
13169
  }, [dispatchUi, workflowPickerVisible, modelPickerVisible]);
13224
- const submitPromptOrSlashCommand = useCallback18(
13170
+ const submitPromptOrSlashCommand = useCallback19(
13225
13171
  (value) => {
13226
13172
  if (!value.trim()) return;
13227
13173
  inputHistory.push(value);
@@ -13230,13 +13176,13 @@ function AppContent({
13230
13176
  setPendingStartupDiagnostics(null);
13231
13177
  setStartupFailure(null);
13232
13178
  addMessage("user", result.text);
13233
- if (!isServerRunning && runtimeError) {
13179
+ if (!isServerRunning && runtimeError2) {
13234
13180
  setStartupFailure({
13235
- message: runtimeError.message,
13236
- failureCode: runtimeError.code === "socket_path_too_long" ? "socket_path_too_long" : "hook_server_unavailable"
13181
+ message: runtimeError2.message,
13182
+ failureCode: runtimeError2.code === "socket_path_too_long" ? "socket_path_too_long" : "hook_server_unavailable"
13237
13183
  });
13238
13184
  emitNotification(
13239
- `Athena failed to start ${harnessLabel}: ${runtimeError.message}`,
13185
+ `Athena failed to start ${harnessLabel}: ${runtimeError2.message}`,
13240
13186
  `${harnessLabel} Startup Error`
13241
13187
  );
13242
13188
  return;
@@ -13292,13 +13238,13 @@ function AppContent({
13292
13238
  spawn: (prompt, sessionId2, configOverride) => {
13293
13239
  setPendingStartupDiagnostics(null);
13294
13240
  setStartupFailure(null);
13295
- if (!isServerRunning && runtimeError) {
13241
+ if (!isServerRunning && runtimeError2) {
13296
13242
  setStartupFailure({
13297
- message: runtimeError.message,
13298
- failureCode: runtimeError.code === "socket_path_too_long" ? "socket_path_too_long" : "hook_server_unavailable"
13243
+ message: runtimeError2.message,
13244
+ failureCode: runtimeError2.code === "socket_path_too_long" ? "socket_path_too_long" : "hook_server_unavailable"
13299
13245
  });
13300
13246
  emitNotification(
13301
- `Athena failed to start ${harnessLabel}: ${runtimeError.message}`,
13247
+ `Athena failed to start ${harnessLabel}: ${runtimeError2.message}`,
13302
13248
  `${harnessLabel} Startup Error`
13303
13249
  );
13304
13250
  return Promise.resolve();
@@ -13326,7 +13272,7 @@ function AppContent({
13326
13272
  spawnHarness,
13327
13273
  currentSessionId,
13328
13274
  isServerRunning,
13329
- runtimeError,
13275
+ runtimeError2,
13330
13276
  exit,
13331
13277
  clearScreen,
13332
13278
  onShowSessions,
@@ -13345,7 +13291,7 @@ function AppContent({
13345
13291
  const isHarnessRunningRef = useRef16(isHarnessRunning);
13346
13292
  isHarnessRunningRef.current = isHarnessRunning;
13347
13293
  const submitDispatchAsTurnRef = useRef16(null);
13348
- const submitDispatchAsTurn = useCallback18(
13294
+ const submitDispatchAsTurn = useCallback19(
13349
13295
  (payload) => {
13350
13296
  const text = payload.inbound.text;
13351
13297
  if (text.trim().length === 0) return;
@@ -13438,17 +13384,18 @@ function AppContent({
13438
13384
  submitSearchQuery: (query, firstMatchIndex) => dispatchUi({ type: "submit_search_query", query, firstMatchIndex }),
13439
13385
  submitPromptOrSlashCommand,
13440
13386
  displayedEntriesRef: displayedFeedEntriesRef,
13387
+ getEntrySearchText,
13441
13388
  getSelectedCommand: () => getSelectedCommandRef.current()
13442
13389
  });
13443
13390
  const visualInputRows = Math.max(2, inputRows);
13444
13391
  const shellInputRef = useRef16(null);
13445
13392
  getSelectedCommandRef.current = () => shellInputRef.current?.getSelectedCommand();
13446
13393
  const { back: handleHistoryBack, forward: handleHistoryForward } = inputHistory;
13447
- const stableSetInputValue = useCallback18(
13394
+ const stableSetInputValue = useCallback19(
13448
13395
  (v) => setInputValueRef.current(v),
13449
13396
  [setInputValueRef]
13450
13397
  );
13451
- const stableGetInputValue = useCallback18(() => inputValueRef.current, []);
13398
+ const stableGetInputValue = useCallback19(() => inputValueRef.current, []);
13452
13399
  const provisionalFooterRows = 1;
13453
13400
  const hasMessages = useMemo17(
13454
13401
  () => filteredEntries.some((e) => classifyEntry(e) !== "feed"),
@@ -13631,29 +13578,29 @@ function AppContent({
13631
13578
  runSummaries,
13632
13579
  staticHighWaterMark
13633
13580
  });
13634
- const cycleFocus = useCallback18(
13581
+ const cycleFocus = useCallback19(
13635
13582
  () => dispatchUi({ type: "cycle_focus" }),
13636
13583
  [dispatchUi]
13637
13584
  );
13638
- const handlePermissionDecision = useCallback18(
13585
+ const handlePermissionDecision = useCallback19(
13639
13586
  (decision) => {
13640
13587
  if (!currentPermissionRequest) return;
13641
13588
  resolvePermission(currentPermissionRequest.request_id, decision);
13642
13589
  },
13643
13590
  [currentPermissionRequest, resolvePermission]
13644
13591
  );
13645
- const handleQuestionAnswer = useCallback18(
13592
+ const handleQuestionAnswer = useCallback19(
13646
13593
  (answers) => {
13647
13594
  if (!currentQuestionRequest?.cause?.hook_request_id) return;
13648
13595
  resolveQuestion(currentQuestionRequest.cause.hook_request_id, answers);
13649
13596
  },
13650
13597
  [currentQuestionRequest, resolveQuestion]
13651
13598
  );
13652
- const handleQuestionSkip = useCallback18(() => {
13599
+ const handleQuestionSkip = useCallback19(() => {
13653
13600
  if (!currentQuestionRequest?.cause?.hook_request_id) return;
13654
13601
  resolveQuestion(currentQuestionRequest.cause.hook_request_id, {});
13655
13602
  }, [currentQuestionRequest, resolveQuestion]);
13656
- const handleDiagnosticsDecision = useCallback18(
13603
+ const handleDiagnosticsDecision = useCallback19(
13657
13604
  (decision) => {
13658
13605
  const pending = pendingStartupDiagnostics;
13659
13606
  setPendingStartupDiagnostics(null);
@@ -13705,7 +13652,7 @@ function AppContent({
13705
13652
  }
13706
13653
  }
13707
13654
  });
13708
- const showToast = useCallback18((msg) => {
13655
+ const showToast = useCallback19((msg) => {
13709
13656
  if (toastTimerRef.current) clearTimeout(toastTimerRef.current);
13710
13657
  setToastMessage(msg);
13711
13658
  toastTimerRef.current = setTimeout(() => setToastMessage(null), 1500);
@@ -13715,7 +13662,7 @@ function AppContent({
13715
13662
  if (toastTimerRef.current) clearTimeout(toastTimerRef.current);
13716
13663
  };
13717
13664
  }, []);
13718
- const yankAtCursor = useCallback18(() => {
13665
+ const yankAtCursor = useCallback19(() => {
13719
13666
  const entry = displayedFeedEntriesRef.current.find(
13720
13667
  (e) => e.id === resolvedUiState.feedCursorId
13721
13668
  );
@@ -13724,7 +13671,7 @@ function AppContent({
13724
13671
  copyToClipboard(content);
13725
13672
  showToast("Copied to clipboard!");
13726
13673
  }, [resolvedUiState.feedCursorId, showToast, theme]);
13727
- const yankMessageAtCursor = useCallback18(() => {
13674
+ const yankMessageAtCursor = useCallback19(() => {
13728
13675
  const entry = messageEntries.at(resolvedUiState.messageCursorIndex);
13729
13676
  if (!entry) return;
13730
13677
  const text = messageText(entry);
@@ -13884,7 +13831,7 @@ function AppContent({
13884
13831
  () => source_default.hex(theme.inputPrompt).bold(inputPrefix),
13885
13832
  [inputPrefix, theme.inputPrompt]
13886
13833
  );
13887
- const withBorderEdges = useCallback18(
13834
+ const withBorderEdges = useCallback19(
13888
13835
  (line) => {
13889
13836
  if (line.length < 2) return line;
13890
13837
  const first = line.charAt(0);
@@ -13893,14 +13840,14 @@ function AppContent({
13893
13840
  },
13894
13841
  [border]
13895
13842
  );
13896
- const withSectionEdges = useCallback18(
13843
+ const withSectionEdges = useCallback19(
13897
13844
  (content) => {
13898
13845
  const glyphs = frameGlyphs(useAscii);
13899
13846
  return `${border(glyphs.teeLeft)}${content}${border(glyphs.teeRight)}`;
13900
13847
  },
13901
13848
  [border, useAscii]
13902
13849
  );
13903
- const wrapFrameLine = useCallback18(
13850
+ const wrapFrameLine = useCallback19(
13904
13851
  (line) => withBorderEdges(frameLine(line)),
13905
13852
  [withBorderEdges, frameLine]
13906
13853
  );
@@ -14495,7 +14442,7 @@ function App({
14495
14442
  runtimeState.modelName,
14496
14443
  runtimeState.workflowRef
14497
14444
  ]);
14498
- const handleProfilerRender = useCallback18(
14445
+ const handleProfilerRender = useCallback19(
14499
14446
  (id, phaseName, actualDuration, baseDuration, startTime, commitTime) => {
14500
14447
  logReactCommit(
14501
14448
  id,
@@ -14508,20 +14455,20 @@ function App({
14508
14455
  },
14509
14456
  []
14510
14457
  );
14511
- const handleSessionSelect = useCallback18((sessionId) => {
14458
+ const handleSessionSelect = useCallback19((sessionId) => {
14512
14459
  const meta = getSessionMeta(sessionId);
14513
14460
  const adapterIds = meta?.adapterSessionIds ?? [];
14514
14461
  const lastAdapterId = adapterIds[adapterIds.length - 1];
14515
14462
  setAthenaSessionId(sessionId);
14516
14463
  setPhase({ type: "main", initialSessionId: lastAdapterId });
14517
14464
  }, []);
14518
- const handleSessionCancel = useCallback18(() => {
14465
+ const handleSessionCancel = useCallback19(() => {
14519
14466
  setPhase({ type: "main" });
14520
14467
  }, []);
14521
- const handleShowSessions = useCallback18(() => {
14468
+ const handleShowSessions = useCallback19(() => {
14522
14469
  setPhase({ type: "session-select" });
14523
14470
  }, []);
14524
- const handleShowSetup = useCallback18(() => {
14471
+ const handleShowSetup = useCallback19(() => {
14525
14472
  setPhase({ type: "setup" });
14526
14473
  }, []);
14527
14474
  const [sessions, setSessions] = useState18([]);
@@ -14539,7 +14486,7 @@ function App({
14539
14486
  }, 0);
14540
14487
  return () => clearTimeout(timer);
14541
14488
  }, [projectDir, phase.type]);
14542
- const refreshRuntime = useCallback18(() => {
14489
+ const refreshRuntime = useCallback19(() => {
14543
14490
  try {
14544
14491
  const refreshed = bootstrapRuntimeConfig({
14545
14492
  projectDir,
@@ -14564,7 +14511,7 @@ function App({
14564
14511
  console.error(`Error: ${error.message}`);
14565
14512
  }
14566
14513
  }, [projectDir, pluginFlags, isolationPreset, verbose]);
14567
- const handleSetupComplete = useCallback18(
14514
+ const handleSetupComplete = useCallback19(
14568
14515
  (setupResult) => {
14569
14516
  setActiveTheme(resolveTheme(setupResult.theme));
14570
14517
  refreshRuntime();
@@ -14572,10 +14519,10 @@ function App({
14572
14519
  },
14573
14520
  [refreshRuntime]
14574
14521
  );
14575
- const handleWorkflowSelected = useCallback18(() => {
14522
+ const handleWorkflowSelected = useCallback19(() => {
14576
14523
  refreshRuntime();
14577
14524
  }, [refreshRuntime]);
14578
- const handleModelSelected = useCallback18(() => {
14525
+ const handleModelSelected = useCallback19(() => {
14579
14526
  refreshRuntime();
14580
14527
  }, [refreshRuntime]);
14581
14528
  if (phase.type === "setup") {
@@ -14801,7 +14748,7 @@ var tasksCommand = {
14801
14748
  };
14802
14749
 
14803
14750
  // src/app/commands/builtins/setup.ts
14804
- var setup = {
14751
+ var setup2 = {
14805
14752
  name: "setup",
14806
14753
  description: "Re-run the setup wizard",
14807
14754
  category: "ui",
@@ -14809,7 +14756,7 @@ var setup = {
14809
14756
  ctx.showSetup();
14810
14757
  }
14811
14758
  };
14812
- var setup_default = setup;
14759
+ var setup_default = setup2;
14813
14760
 
14814
14761
  // src/app/commands/builtins/telemetry.ts
14815
14762
  var telemetryCommand = {
@@ -15989,6 +15936,8 @@ Subcommands:
15989
15936
  so the daemon starts automatically on login.
15990
15937
  doctor Verify pairing health. With --runner <id>, also confirms the
15991
15938
  runner is bound to this instance.
15939
+ list Print the local attachment mirror (the runners the dashboard
15940
+ reported as bound to this instance at the last pair/refresh).
15992
15941
  console enable <runnerId>
15993
15942
  Configure the console channel for a runner (opinionated;
15994
15943
  writes the sidecar and reloads the gateway).
@@ -16015,7 +15964,7 @@ var cachedVersion = null;
16015
15964
  function readPackageVersion() {
16016
15965
  if (cachedVersion !== null) return cachedVersion;
16017
15966
  try {
16018
- const injected = "0.4.2";
15967
+ const injected = "0.4.5";
16019
15968
  if (typeof injected === "string" && injected.length > 0) {
16020
15969
  cachedVersion = injected;
16021
15970
  return cachedVersion;
@@ -16058,6 +16007,9 @@ async function runDashboardCommand(input, deps = {}) {
16058
16007
  const writeConfig = deps.writeConfig ?? ((c2) => writeDashboardClientConfig(c2));
16059
16008
  const removeConfig = deps.removeConfig ?? (() => removeDashboardClientConfig());
16060
16009
  const configPath = deps.configPath ?? (() => dashboardClientConfigPath());
16010
+ const readMirror = deps.readMirror ?? (() => readAttachmentMirror());
16011
+ const writeMirror = deps.writeMirror ?? ((m) => writeAttachmentMirror(m));
16012
+ const removeMirror = deps.removeMirror ?? (() => removeAttachmentMirror());
16061
16013
  const packageVersion = deps.packageVersion ?? readPackageVersion();
16062
16014
  const { subcommand, subcommandArgs, flags } = input;
16063
16015
  if (!subcommand || subcommand === "help" || subcommand === "--help") {
@@ -16137,7 +16089,7 @@ async function runDashboardCommand(input, deps = {}) {
16137
16089
  `dashboard pair: cli version ${packageVersion} is older than the dashboard's required >=${parsed.requiredCliVersion}.`
16138
16090
  );
16139
16091
  logError(
16140
- "dashboard pair: upgrade with `npm i -g @athenaflow/cli` then re-run pair."
16092
+ "dashboard pair: upgrade with `npm i -g @drisp/cli` then re-run pair."
16141
16093
  );
16142
16094
  return 1;
16143
16095
  }
@@ -16149,6 +16101,22 @@ async function runDashboardCommand(input, deps = {}) {
16149
16101
  pairedAt: now()
16150
16102
  };
16151
16103
  writeConfig(config);
16104
+ try {
16105
+ writeMirror({
16106
+ instanceId: parsed.instanceId,
16107
+ fetchedAt: now(),
16108
+ attachments: (parsed.runners ?? []).map((r) => ({
16109
+ runnerId: r.runnerId,
16110
+ ...r.name !== void 0 ? { name: r.name } : {},
16111
+ ...r.executionTarget !== void 0 ? { executionTarget: r.executionTarget } : {},
16112
+ ...r.remoteInstanceId !== void 0 ? { remoteInstanceId: r.remoteInstanceId } : {}
16113
+ }))
16114
+ });
16115
+ } catch (err) {
16116
+ logError(
16117
+ `dashboard pair: failed to write attachment mirror: ${err instanceof Error ? err.message : String(err)}`
16118
+ );
16119
+ }
16152
16120
  const daemonStart = await (deps.startRuntimeDaemon ?? defaultStartRuntimeDaemon)({
16153
16121
  log: (msg) => logOut(msg)
16154
16122
  });
@@ -16866,14 +16834,22 @@ async function runDashboardCommand(input, deps = {}) {
16866
16834
  return 1;
16867
16835
  }
16868
16836
  const dir = (deps.channelDir ?? channelSidecarDir)();
16837
+ const target = path7.join(dir, `console-${runnerId}.json`);
16838
+ const legacyTarget = path7.join(dir, "console.json");
16869
16839
  let previousBroker;
16870
- const target = path7.join(dir, "console.json");
16871
16840
  try {
16872
16841
  const existing = JSON.parse(fs7.readFileSync(target, "utf-8"));
16873
16842
  if (typeof existing.broker_url === "string") {
16874
16843
  previousBroker = existing.broker_url;
16875
16844
  }
16876
16845
  } catch {
16846
+ try {
16847
+ const legacy = JSON.parse(fs7.readFileSync(legacyTarget, "utf-8"));
16848
+ if (typeof legacy.broker_url === "string" && legacy.runner_id === runnerId) {
16849
+ previousBroker = legacy.broker_url;
16850
+ }
16851
+ } catch {
16852
+ }
16877
16853
  }
16878
16854
  try {
16879
16855
  fs7.mkdirSync(dir, { recursive: true, mode: 448 });
@@ -16884,6 +16860,8 @@ async function runDashboardCommand(input, deps = {}) {
16884
16860
  return 1;
16885
16861
  }
16886
16862
  const payload = {
16863
+ kind: "console",
16864
+ instance_id: `console:${runnerId}`,
16887
16865
  broker_url: brokerUrl,
16888
16866
  runner_id: runnerId,
16889
16867
  dashboard_config: true
@@ -16904,6 +16882,13 @@ async function runDashboardCommand(input, deps = {}) {
16904
16882
  );
16905
16883
  return 1;
16906
16884
  }
16885
+ try {
16886
+ const legacy = JSON.parse(fs7.readFileSync(legacyTarget, "utf-8"));
16887
+ if (legacy.runner_id === runnerId) {
16888
+ fs7.unlinkSync(legacyTarget);
16889
+ }
16890
+ } catch {
16891
+ }
16907
16892
  const reload = await (deps.reloadGatewayChannels ?? defaultReloadGatewayChannels)();
16908
16893
  if (flags.json) {
16909
16894
  logOut(
@@ -16938,6 +16923,72 @@ async function runDashboardCommand(input, deps = {}) {
16938
16923
  );
16939
16924
  return 2;
16940
16925
  }
16926
+ if (subcommand === "list") {
16927
+ if (subcommandArgs.length > 0) {
16928
+ logError(`dashboard list: unexpected argument ${subcommandArgs[0]}`);
16929
+ return 2;
16930
+ }
16931
+ const config = readConfig2();
16932
+ if (!config) {
16933
+ if (flags.json) {
16934
+ logOut(JSON.stringify({ ok: false, paired: false }));
16935
+ } else {
16936
+ logError(
16937
+ 'dashboard list: not paired. Run "drisp dashboard pair" first.'
16938
+ );
16939
+ }
16940
+ return 1;
16941
+ }
16942
+ const mirror = readMirror();
16943
+ if (!mirror) {
16944
+ if (flags.json) {
16945
+ logOut(
16946
+ JSON.stringify({
16947
+ ok: true,
16948
+ paired: true,
16949
+ instanceId: config.instanceId,
16950
+ attachments: [],
16951
+ mirror: null
16952
+ })
16953
+ );
16954
+ } else {
16955
+ logOut(
16956
+ `dashboard list: paired as ${config.instanceId}, no attachment mirror on disk.`
16957
+ );
16958
+ logOut(
16959
+ "dashboard list: re-run `drisp dashboard pair` to refresh the mirror."
16960
+ );
16961
+ }
16962
+ return 0;
16963
+ }
16964
+ if (flags.json) {
16965
+ logOut(
16966
+ JSON.stringify({
16967
+ ok: true,
16968
+ paired: true,
16969
+ instanceId: mirror.instanceId,
16970
+ fetchedAt: mirror.fetchedAt,
16971
+ attachments: mirror.attachments
16972
+ })
16973
+ );
16974
+ } else {
16975
+ logOut(`dashboard: instance ${mirror.instanceId}`);
16976
+ logOut(
16977
+ `dashboard: mirror fetched ${new Date(mirror.fetchedAt).toISOString()}`
16978
+ );
16979
+ if (mirror.attachments.length === 0) {
16980
+ logOut("dashboard: no runners attached.");
16981
+ } else {
16982
+ logOut(`dashboard: ${mirror.attachments.length} runner(s) attached:`);
16983
+ for (const a of mirror.attachments) {
16984
+ const label = a.name ? `${a.name} (${a.runnerId})` : a.runnerId;
16985
+ const target = a.executionTarget ? ` [${a.executionTarget}]` : "";
16986
+ logOut(` - ${label}${target}`);
16987
+ }
16988
+ }
16989
+ }
16990
+ return 0;
16991
+ }
16941
16992
  if (subcommand === "unpair") {
16942
16993
  if (subcommandArgs.length > 0) {
16943
16994
  logError(`dashboard unpair: unexpected argument ${subcommandArgs[0]}`);
@@ -17009,6 +17060,7 @@ async function runDashboardCommand(input, deps = {}) {
17009
17060
  }
17010
17061
  }
17011
17062
  removeConfig();
17063
+ removeMirror();
17012
17064
  if (flags.json) {
17013
17065
  logOut(
17014
17066
  JSON.stringify({
@@ -18473,7 +18525,7 @@ Available commands: ${[...KNOWN_COMMANDS].join(", ")}`
18473
18525
  await exitWith(1);
18474
18526
  return;
18475
18527
  }
18476
- const { default: WorkflowInstallWizard } = await import("./WorkflowInstallWizard-NDWLVIFI.js");
18528
+ const { default: WorkflowInstallWizard } = await import("./WorkflowInstallWizard-2MC5A7W4.js");
18477
18529
  const { waitUntilExit } = render(
18478
18530
  /* @__PURE__ */ jsx25(
18479
18531
  WorkflowInstallWizard,