@tonyclaw/agent-inspector 2.1.17 → 2.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-B9sLBHw5.js → CompareDrawer-CHXN5HYU.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-TZJV7HhE.js +106 -0
  4. package/.output/public/assets/{ReplayDialog-D9I9W9n3.js → ReplayDialog-DQ7nS5Rr.js} +1 -1
  5. package/.output/public/assets/{RequestAnatomy-DGXK_Rii.js → RequestAnatomy-DXWweH_2.js} +1 -1
  6. package/.output/public/assets/{ResponseView-df_JzwsS.js → ResponseView-3PimPfiD.js} +2 -2
  7. package/.output/public/assets/{StreamingChunkSequence-i3DM5IKL.js → StreamingChunkSequence-4v52v-7a.js} +1 -1
  8. package/.output/public/assets/_sessionId-DfkBPvCC.js +1 -0
  9. package/.output/public/assets/{index-Dqc2r1ea.js → index-BuhFRImh.js} +1 -1
  10. package/.output/public/assets/index-ChgjUix0.css +1 -0
  11. package/.output/public/assets/index-Uf87L52J.js +1 -0
  12. package/.output/public/assets/{json-viewer-D3QWQlSB.js → json-viewer-d2gWBDLO.js} +1 -1
  13. package/.output/public/assets/{main-ZhxhOCmF.js → main-Do-E-46G.js} +2 -2
  14. package/.output/server/{_sessionId-YFrP0lZP.mjs → _sessionId-B82aMW2A.mjs} +2 -2
  15. package/.output/server/_ssr/{CompareDrawer-qC3adEeq.mjs → CompareDrawer-Bud_yIrM.mjs} +2 -2
  16. package/.output/server/_ssr/{ProxyViewerContainer-DCZIJC2b.mjs → ProxyViewerContainer-DqgVb0So.mjs} +1976 -1988
  17. package/.output/server/_ssr/{ReplayDialog-CvX4XYCi.mjs → ReplayDialog-DKbV5fnW.mjs} +3 -3
  18. package/.output/server/_ssr/{RequestAnatomy-HQfrxjO1.mjs → RequestAnatomy-MStxp1Wp.mjs} +2 -2
  19. package/.output/server/_ssr/{ResponseView-QSlSD11e.mjs → ResponseView-HLTCpJcF.mjs} +2 -2
  20. package/.output/server/_ssr/{StreamingChunkSequence-DTAiwlnI.mjs → StreamingChunkSequence-DEiyiUs_.mjs} +2 -2
  21. package/.output/server/_ssr/{index-D_EzfXaN.mjs → index-DamOPFDI.mjs} +2 -2
  22. package/.output/server/_ssr/index.mjs +2 -2
  23. package/.output/server/_ssr/{json-viewer-CrIX0e0Q.mjs → json-viewer-MmTWKxqh.mjs} +2 -2
  24. package/.output/server/_ssr/{router-__o2wrfO.mjs → router-50BIB6ED.mjs} +545 -22
  25. package/.output/server/{_tanstack-start-manifest_v-DbqyLpsI.mjs → _tanstack-start-manifest_v-TSwb1vFc.mjs} +1 -1
  26. package/.output/server/index.mjs +66 -66
  27. package/package.json +1 -1
  28. package/src/components/proxy-viewer/ConversationGroupList.tsx +11 -11
  29. package/src/components/proxy-viewer/ConversationHeader.tsx +7 -7
  30. package/src/components/proxy-viewer/LogEntry.tsx +15 -26
  31. package/src/components/proxy-viewer/LogEntryHeader.tsx +11 -14
  32. package/src/components/proxy-viewer/RequestToolsPanel.tsx +15 -15
  33. package/src/components/proxy-viewer/ThreadConnector.tsx +75 -91
  34. package/src/components/proxy-viewer/ToolTraceEvents.tsx +1 -1
  35. package/src/components/proxy-viewer/TurnGroup.tsx +11 -14
  36. package/src/mcp/server.ts +275 -0
  37. package/src/mcp/toolHandlers.ts +380 -3
  38. package/src/proxy/logSearch.ts +3 -0
  39. package/src/proxy/store.ts +40 -15
  40. package/src/routes/api/logs.ts +8 -2
  41. package/.output/public/assets/ProxyViewerContainer-DbWjc_BE.js +0 -106
  42. package/.output/public/assets/_sessionId-CTpCHdFh.js +0 -1
  43. package/.output/public/assets/index-Blqvndcn.js +0 -1
  44. package/.output/public/assets/index-Cs79WRQj.css +0 -1
@@ -44,13 +44,13 @@ const CATEGORY_LABELS: Record<RequestToolCategory, string> = {
44
44
  };
45
45
 
46
46
  const CATEGORY_CLASSES: Record<RequestToolCategory, string> = {
47
- file: "border-blue-400/20 bg-blue-400/5 text-blue-300",
48
- shell: "border-teal-400/20 bg-teal-400/5 text-teal-300",
49
- browser: "border-cyan-400/20 bg-cyan-400/5 text-cyan-300",
50
- web: "border-sky-400/20 bg-sky-400/5 text-sky-300",
51
- mcp: "border-violet-400/20 bg-violet-400/5 text-violet-300",
52
- code: "border-emerald-400/20 bg-emerald-400/5 text-emerald-300",
53
- other: "border-muted-foreground/20 bg-muted/30 text-muted-foreground",
47
+ file: "border-transparent bg-blue-400/5 text-blue-300",
48
+ shell: "border-transparent bg-teal-400/5 text-teal-300",
49
+ browser: "border-transparent bg-cyan-400/5 text-cyan-300",
50
+ web: "border-transparent bg-sky-400/5 text-sky-300",
51
+ mcp: "border-transparent bg-violet-400/5 text-violet-300",
52
+ code: "border-transparent bg-emerald-400/5 text-emerald-300",
53
+ other: "border-transparent bg-muted/30 text-muted-foreground",
54
54
  };
55
55
 
56
56
  function CategoryIcon({ category }: { category: RequestToolCategory }): JSX.Element {
@@ -101,7 +101,7 @@ function ToolRow({ tool, called }: { tool: RequestToolDefinition; called: boolea
101
101
 
102
102
  return (
103
103
  <Collapsible open={open} onOpenChange={setOpen}>
104
- <div className="border border-border bg-card shadow-sm rounded-[8px]">
104
+ <div className="bg-white/[0.035] rounded-[8px]">
105
105
  <div className="flex min-w-0 items-center gap-2 px-2.5 py-2">
106
106
  <button
107
107
  type="button"
@@ -140,7 +140,7 @@ function ToolRow({ tool, called }: { tool: RequestToolDefinition; called: boolea
140
140
  </button>
141
141
  <button
142
142
  type="button"
143
- className="border border-input bg-background hover:bg-accent hover:text-accent-foreground inline-flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
143
+ className="bg-white/[0.045] hover:bg-white/[0.075] inline-flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
144
144
  onClick={nameCopy.copy}
145
145
  aria-label={nameCopy.copied ? "Copied tool name" : "Copy tool name"}
146
146
  >
@@ -153,13 +153,13 @@ function ToolRow({ tool, called }: { tool: RequestToolDefinition; called: boolea
153
153
  </div>
154
154
  <CollapsibleContent>
155
155
  {open && (
156
- <div className="space-y-2 border-t border-white/10 bg-white/[0.025] px-2.5 py-2">
156
+ <div className="space-y-2 bg-white/[0.025] px-2.5 py-2">
157
157
  {tool.description !== null && (
158
158
  <p className="text-xs leading-relaxed text-muted-foreground">{tool.description}</p>
159
159
  )}
160
160
  <RequiredParameters names={tool.requiredParameters} />
161
161
  {tool.schema !== null && (
162
- <ScrollArea className="border border-border bg-card shadow-sm max-h-64 rounded-[8px] p-2">
162
+ <ScrollArea className="bg-black/[0.16] max-h-64 rounded-[8px] p-2">
163
163
  <Suspense
164
164
  fallback={<div className="text-xs text-muted-foreground">Loading JSON...</div>}
165
165
  >
@@ -203,7 +203,7 @@ export const RequestTools = memo(function RequestTools({
203
203
  const hiddenPreviewCount = summary.tools.length - previewTools.length;
204
204
 
205
205
  return (
206
- <section className="border border-border bg-card shadow-sm mb-3 overflow-hidden rounded-[8px]">
206
+ <section className="bg-black/[0.10] mb-3 overflow-hidden rounded-[8px]">
207
207
  <div className="flex min-w-0 flex-wrap items-center gap-2 px-3 py-2">
208
208
  <div className="flex min-w-0 flex-1 items-center gap-2">
209
209
  <Wrench className="size-4 shrink-0 text-sky-300/80" />
@@ -251,7 +251,7 @@ export const RequestTools = memo(function RequestTools({
251
251
  </Button>
252
252
  </div>
253
253
 
254
- <div className="flex min-w-0 flex-wrap gap-1.5 border-t border-white/10 bg-white/[0.025] px-3 py-2">
254
+ <div className="flex min-w-0 flex-wrap gap-1.5 bg-white/[0.025] px-3 py-2">
255
255
  {previewTools.map((tool) => (
256
256
  <Badge
257
257
  key={tool.name}
@@ -272,8 +272,8 @@ export const RequestTools = memo(function RequestTools({
272
272
  </div>
273
273
 
274
274
  {expanded && (
275
- <div className="space-y-2 border-t border-white/10 bg-black/10 px-3 py-3">
276
- <label className="border border-input bg-background hover:bg-accent hover:text-accent-foreground flex h-8 items-center gap-2 rounded-md px-2 text-xs">
275
+ <div className="space-y-2 bg-black/10 px-3 py-3">
276
+ <label className="bg-white/[0.045] hover:bg-white/[0.075] flex h-8 items-center gap-2 rounded-md px-2 text-xs">
277
277
  <Search className="size-3.5 shrink-0 text-muted-foreground" />
278
278
  <input
279
279
  value={query}
@@ -1,6 +1,7 @@
1
- import type { JSX, KeyboardEvent, MouseEvent } from "react";
1
+ import { type JSX, type KeyboardEvent, type MouseEvent, useMemo } from "react";
2
2
  import { isTurnBoundary, type StopReason } from "../../lib/stopReason";
3
3
  import { cn } from "../../lib/utils";
4
+ import { getCrabVariant, getInteriorCrabVariant } from "../ui/crab-variants";
4
5
 
5
6
  export type ThreadConnectorProps = {
6
7
  stopReason: StopReason;
@@ -10,13 +11,13 @@ export type ThreadConnectorProps = {
10
11
  isTurnStart: boolean;
11
12
  /** True when this entry is the turn's only request. */
12
13
  isOnlyEntry?: boolean;
13
- /** When true the timeline marker is clickable (collapse / expand a turn). */
14
+ /** Seed for crab variant selection (0-11). */
15
+ crabIndex?: number;
16
+ /** When true the crab is clickable (collapse / expand a turn). */
14
17
  collapsible?: boolean;
15
18
  onToggle?: () => void;
16
19
  };
17
20
 
18
- type MarkerTone = "start" | "end" | "fused" | "running" | "idle";
19
-
20
21
  function boundaryTitle(stopReason: StopReason): string {
21
22
  switch (stopReason) {
22
23
  case "end_turn":
@@ -31,77 +32,8 @@ function boundaryTitle(stopReason: StopReason): string {
31
32
  }
32
33
  }
33
34
 
34
- function markerTone({
35
- isFusedBoundary,
36
- isBoundary,
37
- isTurnStart,
38
- isRunning,
39
- }: {
40
- isFusedBoundary: boolean;
41
- isBoundary: boolean;
42
- isTurnStart: boolean;
43
- isRunning: boolean;
44
- }): MarkerTone {
45
- if (isFusedBoundary) return "fused";
46
- if (isBoundary) return "end";
47
- if (isTurnStart) return "start";
48
- if (isRunning) return "running";
49
- return "idle";
50
- }
51
-
52
- function markerClass(tone: MarkerTone, interactive: boolean): string {
53
- const base =
54
- "inline-flex size-3.5 items-center justify-center rounded-full border transition-colors";
55
- const cursor = interactive ? "cursor-pointer hover:border-cyan-200/70 hover:bg-cyan-300/20" : "";
56
-
57
- switch (tone) {
58
- case "start":
59
- return cn(base, cursor, "border-cyan-300/50 bg-cyan-300/12 text-cyan-200");
60
- case "end":
61
- return cn(base, cursor, "border-amber-300/55 bg-amber-300/12 text-amber-200");
62
- case "fused":
63
- return cn(
64
- base,
65
- cursor,
66
- "border-slate-200/50 bg-slate-200/10 text-slate-100 ring-2 ring-cyan-300/15",
67
- );
68
- case "running":
69
- return cn(
70
- base,
71
- cursor,
72
- "border-amber-300/45 bg-amber-300/10 text-amber-200 ring-2 ring-amber-300/10",
73
- );
74
- case "idle":
75
- return cn(base, cursor, "border-muted-foreground/25 bg-muted/30 text-muted-foreground/60");
76
- }
77
- }
78
-
79
- function markerInnerClass(tone: MarkerTone): string {
80
- switch (tone) {
81
- case "running":
82
- return "size-1.5 rounded-full bg-current animate-pulse";
83
- case "idle":
84
- return "size-1 rounded-full bg-current opacity-55";
85
- case "start":
86
- case "end":
87
- case "fused":
88
- return "size-1.5 rounded-full bg-current";
89
- }
90
- }
91
-
92
- function markerTitle(tone: MarkerTone, stopReason: StopReason): string {
93
- switch (tone) {
94
- case "start":
95
- return "Start of turn";
96
- case "end":
97
- return boundaryTitle(stopReason);
98
- case "fused":
99
- return "Single-request turn";
100
- case "running":
101
- return "Processing";
102
- case "idle":
103
- return "Request in turn";
104
- }
35
+ function crabShellClass(interactive: boolean): string {
36
+ return interactive ? "cursor-pointer transition-transform hover:scale-110" : "";
105
37
  }
106
38
 
107
39
  export function ThreadConnector({
@@ -110,22 +42,24 @@ export function ThreadConnector({
110
42
  isFirst,
111
43
  isTurnStart,
112
44
  isOnlyEntry = false,
45
+ crabIndex = 0,
113
46
  collapsible = false,
114
47
  onToggle,
115
48
  }: ThreadConnectorProps): JSX.Element {
116
49
  const isBoundary = isTurnBoundary(stopReason);
117
50
  const isFusedBoundary = isOnlyEntry && isTurnStart && isBoundary;
118
51
  const isRunning = isPending && !isBoundary;
119
- const tone = markerTone({ isFusedBoundary, isBoundary, isTurnStart, isRunning });
120
52
  const interactive = collapsible && onToggle !== undefined;
53
+ const Crab = useMemo(() => getCrabVariant(crabIndex), [crabIndex]);
54
+ const FusedCrab = useMemo(() => getInteriorCrabVariant(crabIndex), [crabIndex]);
121
55
 
122
- const handleMarkerClick = (event: MouseEvent<HTMLSpanElement>): void => {
56
+ const handleCrabClick = (event: MouseEvent<HTMLSpanElement>): void => {
123
57
  if (!interactive || onToggle === undefined) return;
124
58
  event.stopPropagation();
125
59
  onToggle();
126
60
  };
127
61
 
128
- const handleMarkerKeyDown = (event: KeyboardEvent<HTMLSpanElement>): void => {
62
+ const handleCrabKeyDown = (event: KeyboardEvent<HTMLSpanElement>): void => {
129
63
  if (!interactive || onToggle === undefined) return;
130
64
  if (event.key !== "Enter" && event.key !== " ") return;
131
65
  event.preventDefault();
@@ -135,19 +69,69 @@ export function ThreadConnector({
135
69
  return (
136
70
  <div className="flex flex-col items-center w-6 shrink-0 pt-0.5 pb-0.5">
137
71
  <div className="flex justify-center h-[calc(0.75rem-8px)]">
138
- {!isFirst && <div className="w-0.5 bg-muted-foreground/30 h-full" />}
72
+ {!isFirst && <div className="w-px bg-muted-foreground/18 h-full" />}
139
73
  </div>
140
74
 
141
- <span
142
- role={interactive ? "button" : undefined}
143
- tabIndex={interactive ? 0 : undefined}
144
- title={markerTitle(tone, stopReason)}
145
- className={markerClass(tone, interactive)}
146
- onClick={handleMarkerClick}
147
- onKeyDown={handleMarkerKeyDown}
148
- >
149
- <span className={markerInnerClass(tone)} />
150
- </span>
75
+ {isFusedBoundary ? (
76
+ <span
77
+ role={interactive ? "button" : undefined}
78
+ tabIndex={interactive ? 0 : undefined}
79
+ title="Single-request turn"
80
+ className={crabShellClass(interactive)}
81
+ onClick={handleCrabClick}
82
+ onKeyDown={handleCrabKeyDown}
83
+ >
84
+ <FusedCrab
85
+ className={cn(
86
+ "size-3.5 text-[#80FF00]",
87
+ "animate-crab-settle",
88
+ "drop-shadow-[0_0_4px_rgba(128,255,0,0.5)]",
89
+ )}
90
+ />
91
+ </span>
92
+ ) : isBoundary ? (
93
+ <span
94
+ role={interactive ? "button" : undefined}
95
+ tabIndex={interactive ? 0 : undefined}
96
+ title={boundaryTitle(stopReason)}
97
+ className={crabShellClass(interactive)}
98
+ onClick={handleCrabClick}
99
+ onKeyDown={handleCrabKeyDown}
100
+ >
101
+ <Crab
102
+ className={cn(
103
+ "size-3.5 text-amber-400",
104
+ "animate-crab-settle",
105
+ "drop-shadow-[0_0_4px_rgba(251,191,36,0.5)]",
106
+ )}
107
+ />
108
+ </span>
109
+ ) : isTurnStart ? (
110
+ <span
111
+ role={interactive ? "button" : undefined}
112
+ tabIndex={interactive ? 0 : undefined}
113
+ title="Start of turn"
114
+ className={crabShellClass(interactive)}
115
+ onClick={handleCrabClick}
116
+ onKeyDown={handleCrabKeyDown}
117
+ >
118
+ <Crab
119
+ className={cn(
120
+ "size-3.5 text-emerald-400",
121
+ "animate-crab-appear",
122
+ "drop-shadow-[0_0_4px_rgba(52,211,153,0.5)]",
123
+ )}
124
+ />
125
+ </span>
126
+ ) : isRunning ? (
127
+ <span title="Processing">
128
+ <Crab className={cn("size-3.5 text-amber-300/80", "animate-crab-crawl")} />
129
+ </span>
130
+ ) : (
131
+ <span title="Request in turn">
132
+ <Crab className="size-3.5 text-muted-foreground/40" />
133
+ </span>
134
+ )}
151
135
 
152
136
  <div className="flex-1 flex justify-center min-h-0">
153
137
  {!isBoundary && (
@@ -155,8 +139,8 @@ export function ThreadConnector({
155
139
  className={cn(
156
140
  "w-0.5 h-full",
157
141
  isPending
158
- ? "border-dashed bg-transparent border-l-2 border-muted-foreground/20"
159
- : "bg-muted-foreground/30",
142
+ ? "border-dashed bg-transparent border-l border-muted-foreground/14"
143
+ : "bg-muted-foreground/18",
160
144
  )}
161
145
  />
162
146
  )}
@@ -14,7 +14,7 @@ function ToolTraceEventRow({ event }: { event: ToolTraceEvent }): JSX.Element {
14
14
  return (
15
15
  <div
16
16
  key={event.id}
17
- className="group/tool-trace flex min-w-0 items-center gap-2 rounded-md border border-border/70 bg-muted/20 px-2.5 py-1.5 text-xs"
17
+ className="group/tool-trace flex min-w-0 items-center gap-2 rounded-md bg-white/[0.035] px-2.5 py-1.5 text-xs"
18
18
  >
19
19
  <Wrench className="size-3.5 shrink-0 text-sky-400/70" />
20
20
  <span className="font-mono font-semibold text-foreground/80">{event.name}</span>
@@ -143,7 +143,7 @@ export const TurnGroup = memo(function TurnGroup({
143
143
  };
144
144
  }, [entries, lastIdx]);
145
145
 
146
- const bgClass = turnIndex % 2 === 0 ? "bg-white/[0.012]" : "bg-cyan-300/[0.012]";
146
+ const bgClass = turnIndex % 2 === 0 ? "bg-white/[0.008]" : "bg-cyan-300/[0.008]";
147
147
  const aggregateIsSlow =
148
148
  aggregate.maxElapsed !== null &&
149
149
  slowResponseThresholdSeconds > 0 &&
@@ -194,10 +194,8 @@ export const TurnGroup = memo(function TurnGroup({
194
194
  aria-label={collapsed ? undefined : turnLabel}
195
195
  data-nav-id={collapsed ? undefined : `turn-${String(firstLogId)}`}
196
196
  className={cn(
197
- "rounded-[8px] border transition-[border-color,box-shadow]",
198
- isPending
199
- ? "border-amber-300/15 shadow-[0_0_0_1px_rgba(252,211,77,0.04)]"
200
- : "border-transparent",
197
+ "rounded-[8px] transition-[background-color,box-shadow]",
198
+ isPending ? "bg-amber-300/[0.018] shadow-[0_0_0_1px_rgba(252,211,77,0.035)]" : "",
201
199
  !collapsed &&
202
200
  "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none",
203
201
  )}
@@ -226,16 +224,14 @@ export const TurnGroup = memo(function TurnGroup({
226
224
 
227
225
  <div className="w-6 shrink-0 flex flex-col items-center pt-1.5 pb-1.5">
228
226
  <div className="flex justify-center h-[calc(0.75rem-8px)]" />
229
- <span className="size-2 rounded-full border border-cyan-300/45 bg-cyan-300/20" />
227
+ <span className="size-2 rounded-full bg-cyan-300/45" />
230
228
  <div className="flex-1 flex justify-center min-h-0">
231
- <div className="w-px bg-muted-foreground/25 h-full" />
229
+ <div className="w-px bg-muted-foreground/14 h-full" />
232
230
  </div>
233
231
  <span
234
232
  className={cn(
235
- "size-2 rounded-full border",
236
- isComplete
237
- ? "border-amber-300/45 bg-amber-300/20"
238
- : "border-muted-foreground/30 bg-muted/30",
233
+ "size-2 rounded-full",
234
+ isComplete ? "bg-amber-300/45" : "bg-muted-foreground/25",
239
235
  )}
240
236
  />
241
237
  </div>
@@ -244,8 +240,8 @@ export const TurnGroup = memo(function TurnGroup({
244
240
  {entries.length > 1 && (
245
241
  <div
246
242
  className={cn(
247
- "flex-1 min-w-0 mb-0.5 rounded-[8px] py-1.5 px-3 flex items-center gap-3 text-xs shadow-[inset_0_1px_0_rgba(255,255,255,0.04)]",
248
- "border border-border bg-card shadow-sm transition-colors hover:border-cyan-200/20",
243
+ "flex-1 min-w-0 mb-0.5 rounded-[8px] py-1.5 px-3 flex items-center gap-3 text-xs",
244
+ "bg-card/80 transition-colors hover:bg-card",
249
245
  bgClass,
250
246
  )}
251
247
  >
@@ -318,7 +314,7 @@ export const TurnGroup = memo(function TurnGroup({
318
314
  <span className="flex-1 min-w-0" />
319
315
 
320
316
  <span
321
- className="border border-input bg-background inline-flex size-7 shrink-0 items-center justify-center rounded-md text-slate-200"
317
+ className="bg-white/[0.045] inline-flex size-7 shrink-0 items-center justify-center rounded-md text-slate-200"
322
318
  aria-hidden="true"
323
319
  >
324
320
  <ChevronRight className="size-4 shrink-0" />
@@ -349,6 +345,7 @@ export const TurnGroup = memo(function TurnGroup({
349
345
  isFirst={visibleIdx === 0}
350
346
  isTurnStart={isTurnStart}
351
347
  isOnlyEntry={isSingleLog}
348
+ crabIndex={log.id % 12}
352
349
  collapsible={collapsible && isTurnStart}
353
350
  onToggle={toggleCollapse}
354
351
  />