@narumitw/pi-inspect 0.1.0 → 0.2.0
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/README.md +4 -1
- package/dist/app.css +1 -1
- package/dist/app.js +25 -26
- package/docs/viewer.md +26 -15
- package/package.json +1 -1
- package/src/entry-summary.ts +34 -0
- package/src/model.ts +4 -0
- package/src/projection.ts +14 -1
- package/src/web/app.tsx +196 -65
- package/src/web/{live-drawer.tsx → captured-executions.tsx} +29 -27
- package/src/web/components.tsx +47 -95
- package/src/web/context-composition.tsx +8 -3
- package/src/web/context-inventory.tsx +65 -0
- package/src/web/format.ts +3 -1
- package/src/web/history.ts +56 -0
- package/src/web/inspector.tsx +102 -53
- package/src/web/recorded-content.tsx +49 -0
- package/src/web/session-filters.tsx +100 -0
- package/src/web/session.css +114 -0
- package/src/web/style.css +2 -2
- package/src/web/trace.css +1 -0
- package/src/web/trace.tsx +58 -18
- package/src/web/tree.tsx +0 -281
package/src/web/inspector.tsx
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as Collapsible from "@radix-ui/react-collapsible";
|
|
2
2
|
import { ChevronRightIcon, CubeIcon } from "@radix-ui/react-icons";
|
|
3
|
-
import {
|
|
3
|
+
import { Button, Heading, Tabs, Text } from "@radix-ui/themes";
|
|
4
4
|
import { useEffect, useMemo, useState } from "react";
|
|
5
5
|
import type { BranchView, Call, Capture, DetailView, EntrySummary, Json, Snapshot } from "../model.js";
|
|
6
|
-
import {
|
|
6
|
+
import { Copy, Data, Metadata, Status } from "./components.js";
|
|
7
7
|
import { entryCalls } from "./entry-calls.js";
|
|
8
8
|
import { count, duration, eventName, output, promptDiff, record, scripts } from "./format.js";
|
|
9
|
+
import { RecordedContent } from "./recorded-content.js";
|
|
9
10
|
|
|
10
11
|
export function Inspector({
|
|
11
12
|
selected,
|
|
@@ -22,6 +23,7 @@ export function Inspector({
|
|
|
22
23
|
changeTab,
|
|
23
24
|
select,
|
|
24
25
|
selectCall,
|
|
26
|
+
preview,
|
|
25
27
|
}: {
|
|
26
28
|
selected: string;
|
|
27
29
|
node?: EntrySummary;
|
|
@@ -37,6 +39,7 @@ export function Inspector({
|
|
|
37
39
|
changeTab(tab: string): void;
|
|
38
40
|
select(id: string): void;
|
|
39
41
|
selectCall(id: string): void;
|
|
42
|
+
preview(): void;
|
|
40
43
|
}) {
|
|
41
44
|
const [format, setFormat] = useState("formatted");
|
|
42
45
|
const raw = record(detail?.raw.value);
|
|
@@ -62,24 +65,22 @@ export function Inspector({
|
|
|
62
65
|
);
|
|
63
66
|
const enabled = useMemo(
|
|
64
67
|
() => [
|
|
68
|
+
"content",
|
|
65
69
|
"raw",
|
|
66
|
-
"prompt",
|
|
67
|
-
"tools",
|
|
68
|
-
...(isCall ? [] : ["context"]),
|
|
69
|
-
...(hasSkills ? ["skills"] : []),
|
|
70
|
+
...(isCall ? [] : ["prompt", "tools", "context", ...(hasSkills ? ["skills"] : [])]),
|
|
70
71
|
...(codemode ? ["codemode"] : []),
|
|
71
72
|
],
|
|
72
73
|
[isCall, hasSkills, codemode],
|
|
73
74
|
);
|
|
74
75
|
useEffect(() => {
|
|
75
|
-
if (!enabled.includes(tab)) changeTab("
|
|
76
|
+
if (!enabled.includes(tab)) changeTab("content");
|
|
76
77
|
}, [enabled, tab, changeTab]);
|
|
77
78
|
return (
|
|
78
79
|
<section className="panel inspector-panel">
|
|
79
80
|
<div className="panel-heading">
|
|
80
81
|
<Heading size="3">
|
|
81
82
|
<CubeIcon />
|
|
82
|
-
|
|
83
|
+
Details
|
|
83
84
|
</Heading>
|
|
84
85
|
{activeRaw && <Copy key={selected} value={output(activeRaw.value)} />}
|
|
85
86
|
</div>
|
|
@@ -90,7 +91,8 @@ export function Inspector({
|
|
|
90
91
|
</Text>
|
|
91
92
|
)}
|
|
92
93
|
<Heading size="4">
|
|
93
|
-
{call ? "Captured execution" : node ? eventName(node.kind) : "Entry"} ·
|
|
94
|
+
{call ? "Captured execution" : node ? eventName(node.kind) : "Entry"} ·{" "}
|
|
95
|
+
{selected.slice(0, 16) || "no selection"}
|
|
94
96
|
</Heading>
|
|
95
97
|
<Text size="2" color="gray">
|
|
96
98
|
{call?.name ?? node?.name ?? "Session log entry"}
|
|
@@ -119,12 +121,96 @@ export function Inspector({
|
|
|
119
121
|
)}
|
|
120
122
|
<Tabs.Root value={tab} onValueChange={changeTab} className="inspector-tabs">
|
|
121
123
|
<Tabs.List wrap="nowrap" aria-label="Event detail views">
|
|
122
|
-
{["raw", "prompt", "tools", "context", "skills", "codemode"].map((tab) => (
|
|
124
|
+
{["content", "raw", "prompt", "tools", "context", "skills", "codemode"].map((tab) => (
|
|
123
125
|
<Tabs.Trigger key={tab} value={tab} disabled={!enabled.includes(tab)}>
|
|
124
126
|
{tab}
|
|
125
127
|
</Tabs.Trigger>
|
|
126
128
|
))}
|
|
127
129
|
</Tabs.List>
|
|
130
|
+
<Tabs.Content value="content">
|
|
131
|
+
{call ? (
|
|
132
|
+
<>
|
|
133
|
+
<Status value={call.status} />
|
|
134
|
+
<Data label="Arguments · redacted display copy" data={call.args} scope={`${call.occurrenceId}-args`} />
|
|
135
|
+
<Data label="Result · observed tool event" data={call.result} scope={`${call.occurrenceId}-result`} />
|
|
136
|
+
<div className="inspector-metadata">
|
|
137
|
+
<Metadata
|
|
138
|
+
rows={[
|
|
139
|
+
["Source", "Observed tool execution"],
|
|
140
|
+
[
|
|
141
|
+
"Parent relationship",
|
|
142
|
+
call.parentUnavailable ??
|
|
143
|
+
call.parentOccurrenceId ??
|
|
144
|
+
(call.parentId ? "unavailable" : "none (root)"),
|
|
145
|
+
],
|
|
146
|
+
[
|
|
147
|
+
"Correlation",
|
|
148
|
+
call.correlationUnavailable || !call.branchAnchor
|
|
149
|
+
? "unavailable"
|
|
150
|
+
: "Recorded anchor only; not request association",
|
|
151
|
+
],
|
|
152
|
+
["Reported duration", duration(call.durationMs)],
|
|
153
|
+
["Occurrence", call.occurrenceId],
|
|
154
|
+
["Raw call ID", call.id],
|
|
155
|
+
["Anchor entry", call.branchAnchor ?? undefined],
|
|
156
|
+
[
|
|
157
|
+
"Start observed",
|
|
158
|
+
call.observedStartedAt === undefined ? undefined : new Date(call.observedStartedAt).toISOString(),
|
|
159
|
+
],
|
|
160
|
+
[
|
|
161
|
+
"End observed",
|
|
162
|
+
call.observedEndedAt === undefined ? undefined : new Date(call.observedEndedAt).toISOString(),
|
|
163
|
+
],
|
|
164
|
+
[
|
|
165
|
+
"Children",
|
|
166
|
+
String(
|
|
167
|
+
snapshot?.calls.filter((child) => child.parentOccurrenceId === call.occurrenceId).length ?? 0,
|
|
168
|
+
),
|
|
169
|
+
],
|
|
170
|
+
]}
|
|
171
|
+
/>
|
|
172
|
+
</div>
|
|
173
|
+
{call.parentId && !snapshot?.calls.some((parent) => parent.occurrenceId === call.parentOccurrenceId) && (
|
|
174
|
+
<Text size="1" color="gray">
|
|
175
|
+
Parent {call.parentId} (not captured)
|
|
176
|
+
</Text>
|
|
177
|
+
)}
|
|
178
|
+
{snapshot?.calls
|
|
179
|
+
.filter(
|
|
180
|
+
(item) =>
|
|
181
|
+
item.parentOccurrenceId === call.occurrenceId || item.occurrenceId === call.parentOccurrenceId,
|
|
182
|
+
)
|
|
183
|
+
.map((item) => (
|
|
184
|
+
<Button
|
|
185
|
+
key={item.occurrenceId}
|
|
186
|
+
size="1"
|
|
187
|
+
variant="ghost"
|
|
188
|
+
onClick={() => selectCall(item.occurrenceId)}
|
|
189
|
+
>
|
|
190
|
+
Related execution · {item.name} · {item.occurrenceId}
|
|
191
|
+
</Button>
|
|
192
|
+
))}
|
|
193
|
+
{call.branchAnchor && snapshot?.nodes.some((entry) => entry.id === call.branchAnchor) && (
|
|
194
|
+
<Button variant="ghost" size="1" onClick={() => select(call.branchAnchor ?? "")}>
|
|
195
|
+
Inspect recorded anchor →
|
|
196
|
+
</Button>
|
|
197
|
+
)}
|
|
198
|
+
</>
|
|
199
|
+
) : (
|
|
200
|
+
<>
|
|
201
|
+
<Text as="p" size="1" color="gray">
|
|
202
|
+
Session log entry · bounded recorded content
|
|
203
|
+
</Text>
|
|
204
|
+
{node?.status && <Status value={node.status} />}
|
|
205
|
+
<RecordedContent data={detail?.raw} scope={selected} />
|
|
206
|
+
</>
|
|
207
|
+
)}
|
|
208
|
+
{!detail && !call && !detailError && (
|
|
209
|
+
<Text size="1" color="gray">
|
|
210
|
+
Loading bounded entry details…
|
|
211
|
+
</Text>
|
|
212
|
+
)}
|
|
213
|
+
</Tabs.Content>
|
|
128
214
|
<Tabs.Content value="raw">
|
|
129
215
|
<div className="format-toolbar">
|
|
130
216
|
<div className="view-switch">
|
|
@@ -248,7 +334,6 @@ export function Inspector({
|
|
|
248
334
|
/>
|
|
249
335
|
<Data label="Historical sections" data={branch?.sections} scope={`${selected}-sections`} />
|
|
250
336
|
<Data label="Prompt updates on branch" data={branch?.promptUpdates} scope={`${selected}-promptUpdates`} />
|
|
251
|
-
<Data label="Current runtime effective prompt · may not yet be sent" data={snapshot?.currentPrompt} />
|
|
252
337
|
</Tabs.Content>
|
|
253
338
|
<Tabs.Content value="tools">
|
|
254
339
|
<Data
|
|
@@ -256,52 +341,11 @@ export function Inspector({
|
|
|
256
341
|
data={branch?.declaredTools}
|
|
257
342
|
scope={`${selected}-declaredTools`}
|
|
258
343
|
/>
|
|
259
|
-
<Text as="p" size="2" color="gray">
|
|
260
|
-
Current active ≠ provider-visible. MCP connection status is unavailable.
|
|
261
|
-
</Text>
|
|
262
|
-
{snapshot?.tools.map((tool) => (
|
|
263
|
-
<Card key={tool.name} className="inventory-card">
|
|
264
|
-
<Text weight="bold">{tool.name}</Text>
|
|
265
|
-
<Flex gap="1" wrap="wrap">
|
|
266
|
-
<Badge>{tool.namespace ?? "tool"}</Badge>
|
|
267
|
-
<Badge>{tool.exposure}</Badge>
|
|
268
|
-
<Badge>{tool.active ? "active" : "inactive"}</Badge>
|
|
269
|
-
<Badge>{tool.callable ? "callable" : "not callable"}</Badge>
|
|
270
|
-
</Flex>
|
|
271
|
-
<Text as="p" size="2" color="gray">
|
|
272
|
-
{tool.description}
|
|
273
|
-
</Text>
|
|
274
|
-
<Collapsible.Root>
|
|
275
|
-
<Collapsible.Trigger asChild>
|
|
276
|
-
<Button size="1" variant="ghost">
|
|
277
|
-
Schema · {tool.name}
|
|
278
|
-
</Button>
|
|
279
|
-
</Collapsible.Trigger>
|
|
280
|
-
<Collapsible.Content>
|
|
281
|
-
<Data label="Schema" data={tool.schema} />
|
|
282
|
-
</Collapsible.Content>
|
|
283
|
-
</Collapsible.Root>
|
|
284
|
-
</Card>
|
|
285
|
-
))}
|
|
286
344
|
</Tabs.Content>
|
|
287
345
|
<Tabs.Content value="skills">
|
|
288
346
|
<Text as="p" size="2" color="gray">
|
|
289
347
|
Advertised or read does not prove model compliance. Historical discovery may be unavailable.
|
|
290
348
|
</Text>
|
|
291
|
-
{snapshot?.skills.map((skill) => (
|
|
292
|
-
<Card key={skill.path} className="inventory-card">
|
|
293
|
-
<Flex gap="2">
|
|
294
|
-
<Text weight="bold">{skill.name}</Text>
|
|
295
|
-
<Badge>advertised</Badge>
|
|
296
|
-
</Flex>
|
|
297
|
-
<Text as="p" size="2">
|
|
298
|
-
{skill.description}
|
|
299
|
-
</Text>
|
|
300
|
-
<Text size="1" color="gray">
|
|
301
|
-
{skill.path}
|
|
302
|
-
</Text>
|
|
303
|
-
</Card>
|
|
304
|
-
))}
|
|
305
349
|
<Data label="Evidence on preview branch" data={branch?.skillEvidence} scope={`${selected}-skillEvidence`} />
|
|
306
350
|
</Tabs.Content>
|
|
307
351
|
<Tabs.Content value="context">
|
|
@@ -309,6 +353,9 @@ export function Inspector({
|
|
|
309
353
|
Pi projection applies compaction and context edits. Request-local hooks can still transform it; this is not
|
|
310
354
|
the final provider HTTP request.
|
|
311
355
|
</Text>
|
|
356
|
+
<Button size="1" onClick={preview} disabled={!branch}>
|
|
357
|
+
View branch context
|
|
358
|
+
</Button>
|
|
312
359
|
<Data label="Projected branch entries" data={branch?.projection} scope={`${selected}-projection`} />
|
|
313
360
|
<Data label="Selected entry contribution" data={detail?.projected} scope={`${selected}-projected`} />
|
|
314
361
|
</Tabs.Content>
|
|
@@ -328,7 +375,9 @@ export function Inspector({
|
|
|
328
375
|
/>
|
|
329
376
|
<Data label="Source / output / persisted nestedCalls" data={detail?.raw} />
|
|
330
377
|
{captured.map((call) => (
|
|
331
|
-
<
|
|
378
|
+
<Button key={call.occurrenceId} variant="ghost" onClick={() => selectCall(call.occurrenceId)}>
|
|
379
|
+
{call.name} · {call.occurrenceId} · inspect captured execution
|
|
380
|
+
</Button>
|
|
332
381
|
))}
|
|
333
382
|
</Tabs.Content>
|
|
334
383
|
</Tabs.Root>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Capture } from "../model.js";
|
|
2
|
+
import { Data } from "./components.js";
|
|
3
|
+
import { record } from "./format.js";
|
|
4
|
+
|
|
5
|
+
export function RecordedContent({ data, scope }: { data?: Capture; scope: string }) {
|
|
6
|
+
const raw = record(data?.value);
|
|
7
|
+
const message = record(raw?.message);
|
|
8
|
+
const content =
|
|
9
|
+
message && Object.hasOwn(message, "content")
|
|
10
|
+
? message.content
|
|
11
|
+
: raw && Object.hasOwn(raw, "data")
|
|
12
|
+
? raw.data
|
|
13
|
+
: (raw?.content ?? raw?.summary ?? raw);
|
|
14
|
+
const blocks = Array.isArray(content) ? content : [content];
|
|
15
|
+
return (
|
|
16
|
+
<div className="recorded-content">
|
|
17
|
+
{blocks.slice(0, 128).map((block, index) => {
|
|
18
|
+
const item = record(block);
|
|
19
|
+
const name = typeof item?.name === "string" ? item.name : "unknown";
|
|
20
|
+
const label =
|
|
21
|
+
item?.type === "thinking"
|
|
22
|
+
? "Thinking"
|
|
23
|
+
: item?.type === "toolCall"
|
|
24
|
+
? `Tool call · ${name}`
|
|
25
|
+
: "Recorded content";
|
|
26
|
+
return (
|
|
27
|
+
<Data
|
|
28
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: Historical content blocks are immutable and scoped by entry identity.
|
|
29
|
+
key={`${scope}-${index}`}
|
|
30
|
+
label={label}
|
|
31
|
+
data={
|
|
32
|
+
data && {
|
|
33
|
+
value: item?.text ?? item?.thinking ?? item?.arguments ?? block ?? null,
|
|
34
|
+
truncated: data.truncated || blocks.length > 128,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
scope={`${scope}-content-${index}`}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
})}
|
|
41
|
+
<Data
|
|
42
|
+
label="Metadata and Raw JSON · redacted display copy"
|
|
43
|
+
data={data}
|
|
44
|
+
scope={`${scope}-raw`}
|
|
45
|
+
defaultOpen={false}
|
|
46
|
+
/>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Checkbox, Heading, Select, TextField } from "@radix-ui/themes";
|
|
2
|
+
import { useId } from "react";
|
|
3
|
+
import type { Filters } from "./format.js";
|
|
4
|
+
|
|
5
|
+
/** Filters only: ancestry lives in the primary Branch view, never a duplicate sidebar. */
|
|
6
|
+
export function SessionFilters({ filters, change }: { filters: Filters; change(filters: Filters): void }) {
|
|
7
|
+
const id = useId();
|
|
8
|
+
return (
|
|
9
|
+
<aside className="sidebar panel session-filters">
|
|
10
|
+
<div className="panel-heading">
|
|
11
|
+
<Heading size="3">Session filters</Heading>
|
|
12
|
+
</div>
|
|
13
|
+
<TextField.Root
|
|
14
|
+
aria-label="Search session"
|
|
15
|
+
placeholder="Search entries or content…"
|
|
16
|
+
value={filters.query}
|
|
17
|
+
onChange={(event) => change({ ...filters, query: event.target.value })}
|
|
18
|
+
/>
|
|
19
|
+
<div className="filter-pills">
|
|
20
|
+
{["All", "Model", "Tool", "Custom"].map((group) => (
|
|
21
|
+
<button
|
|
22
|
+
type="button"
|
|
23
|
+
key={group}
|
|
24
|
+
aria-pressed={
|
|
25
|
+
group === "All" ? !filters.groups.length : filters.groups.length === 1 && filters.groups[0] === group
|
|
26
|
+
}
|
|
27
|
+
onClick={() => change({ ...filters, kind: "all", groups: group === "All" ? [] : [group] })}
|
|
28
|
+
>
|
|
29
|
+
{group}
|
|
30
|
+
</button>
|
|
31
|
+
))}
|
|
32
|
+
</div>
|
|
33
|
+
<details className="filter-panel">
|
|
34
|
+
<summary>Filters</summary>
|
|
35
|
+
<label className="filter-check" htmlFor={`${id}-errors`}>
|
|
36
|
+
<span>Errors only</span>
|
|
37
|
+
<Checkbox
|
|
38
|
+
id={`${id}-errors`}
|
|
39
|
+
checked={filters.errorsOnly}
|
|
40
|
+
onCheckedChange={(checked) => change({ ...filters, errorsOnly: checked === true })}
|
|
41
|
+
/>
|
|
42
|
+
</label>
|
|
43
|
+
<label className="filter-check" htmlFor={`${id}-slow`}>
|
|
44
|
+
<span>Slow tool calls (> 10s)</span>
|
|
45
|
+
<Checkbox
|
|
46
|
+
id={`${id}-slow`}
|
|
47
|
+
checked={filters.slowOnly}
|
|
48
|
+
onCheckedChange={(checked) => change({ ...filters, slowOnly: checked === true })}
|
|
49
|
+
/>
|
|
50
|
+
</label>
|
|
51
|
+
{["Tool", "Model", "Custom"].map((group) => (
|
|
52
|
+
<label className="filter-check" key={group} htmlFor={`${id}-${group}`}>
|
|
53
|
+
<span>{group} events</span>
|
|
54
|
+
<Checkbox
|
|
55
|
+
id={`${id}-${group}`}
|
|
56
|
+
checked={filters.groups.includes(group)}
|
|
57
|
+
onCheckedChange={() =>
|
|
58
|
+
change({
|
|
59
|
+
...filters,
|
|
60
|
+
groups: filters.groups.includes(group)
|
|
61
|
+
? filters.groups.filter((item) => item !== group)
|
|
62
|
+
: [...filters.groups, group],
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
/>
|
|
66
|
+
</label>
|
|
67
|
+
))}
|
|
68
|
+
<label className="filter-check" htmlFor={`${id}-kind`}>
|
|
69
|
+
<span>Entry type</span>
|
|
70
|
+
<Select.Root value={filters.kind} onValueChange={(kind) => change({ ...filters, kind })}>
|
|
71
|
+
<Select.Trigger id={`${id}-kind`} aria-label="Filter entry type" />
|
|
72
|
+
<Select.Content>
|
|
73
|
+
{[
|
|
74
|
+
"all",
|
|
75
|
+
"user",
|
|
76
|
+
"assistant",
|
|
77
|
+
"toolResult",
|
|
78
|
+
"system",
|
|
79
|
+
"custom",
|
|
80
|
+
"custom_message",
|
|
81
|
+
"compaction",
|
|
82
|
+
"branch_summary",
|
|
83
|
+
"model_change",
|
|
84
|
+
"thinking_level_change",
|
|
85
|
+
"context_edit",
|
|
86
|
+
"usage",
|
|
87
|
+
"label",
|
|
88
|
+
"session_info",
|
|
89
|
+
].map((kind) => (
|
|
90
|
+
<Select.Item key={kind} value={kind}>
|
|
91
|
+
{kind}
|
|
92
|
+
</Select.Item>
|
|
93
|
+
))}
|
|
94
|
+
</Select.Content>
|
|
95
|
+
</Select.Root>
|
|
96
|
+
</label>
|
|
97
|
+
</details>
|
|
98
|
+
</aside>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
.observed-context,
|
|
2
|
+
.preview-context,
|
|
3
|
+
.session-primary {
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
flex: 1;
|
|
7
|
+
min-height: 0;
|
|
8
|
+
min-width: 0;
|
|
9
|
+
}
|
|
10
|
+
.observed-context[hidden],
|
|
11
|
+
.session-primary[hidden],
|
|
12
|
+
.header-actions [hidden] {
|
|
13
|
+
display: none;
|
|
14
|
+
}
|
|
15
|
+
.context-inventory {
|
|
16
|
+
flex-shrink: 0;
|
|
17
|
+
border-top: 1px solid var(--panel-border);
|
|
18
|
+
padding: 6px 10px;
|
|
19
|
+
color: var(--secondary);
|
|
20
|
+
}
|
|
21
|
+
.context-inventory summary,
|
|
22
|
+
.session-filters summary {
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
}
|
|
25
|
+
.inventory-scroll {
|
|
26
|
+
overflow: auto;
|
|
27
|
+
max-height: 38dvh;
|
|
28
|
+
}
|
|
29
|
+
.preview-heading,
|
|
30
|
+
.session-toolbar {
|
|
31
|
+
display: flex;
|
|
32
|
+
align-items: center;
|
|
33
|
+
gap: 8px;
|
|
34
|
+
flex-wrap: wrap;
|
|
35
|
+
padding: 6px 0;
|
|
36
|
+
color: var(--secondary);
|
|
37
|
+
font-size: 12px;
|
|
38
|
+
}
|
|
39
|
+
.preview-heading strong {
|
|
40
|
+
overflow-wrap: anywhere;
|
|
41
|
+
}
|
|
42
|
+
.preview-heading button,
|
|
43
|
+
.session-toolbar > button {
|
|
44
|
+
background: var(--panel-raised);
|
|
45
|
+
color: var(--gray-12);
|
|
46
|
+
border: 1px solid var(--panel-border);
|
|
47
|
+
border-radius: 4px;
|
|
48
|
+
padding: 5px;
|
|
49
|
+
}
|
|
50
|
+
.session-toolbar fieldset {
|
|
51
|
+
margin: 0;
|
|
52
|
+
border: 0;
|
|
53
|
+
flex-wrap: wrap;
|
|
54
|
+
}
|
|
55
|
+
.session-toolbar label {
|
|
56
|
+
display: flex;
|
|
57
|
+
gap: 4px;
|
|
58
|
+
align-items: center;
|
|
59
|
+
}
|
|
60
|
+
.session-filters {
|
|
61
|
+
padding: 8px;
|
|
62
|
+
overflow: auto;
|
|
63
|
+
}
|
|
64
|
+
.trace-history .trace-item {
|
|
65
|
+
border-left: 0;
|
|
66
|
+
}
|
|
67
|
+
.trace-history .trace-item::before {
|
|
68
|
+
display: none;
|
|
69
|
+
}
|
|
70
|
+
.turn-heading {
|
|
71
|
+
padding: 10px 8px 5px;
|
|
72
|
+
color: var(--muted);
|
|
73
|
+
font-weight: 600;
|
|
74
|
+
}
|
|
75
|
+
.execution-primary .live-drawer {
|
|
76
|
+
flex: 1;
|
|
77
|
+
max-height: none;
|
|
78
|
+
min-height: 0;
|
|
79
|
+
display: flex;
|
|
80
|
+
flex-direction: column;
|
|
81
|
+
}
|
|
82
|
+
.execution-primary .live-drawer-body {
|
|
83
|
+
flex: 1;
|
|
84
|
+
min-height: 0;
|
|
85
|
+
max-height: none;
|
|
86
|
+
}
|
|
87
|
+
.execution-primary .live-drawer-toggle {
|
|
88
|
+
flex-wrap: wrap;
|
|
89
|
+
flex-shrink: 0;
|
|
90
|
+
}
|
|
91
|
+
.call-summary {
|
|
92
|
+
flex: 2;
|
|
93
|
+
min-width: 0;
|
|
94
|
+
white-space: nowrap;
|
|
95
|
+
overflow: hidden;
|
|
96
|
+
text-overflow: ellipsis;
|
|
97
|
+
color: var(--muted);
|
|
98
|
+
}
|
|
99
|
+
.live-controls {
|
|
100
|
+
flex-wrap: wrap;
|
|
101
|
+
}
|
|
102
|
+
.recorded-content .code-preview {
|
|
103
|
+
white-space: pre-wrap;
|
|
104
|
+
overflow-wrap: anywhere;
|
|
105
|
+
}
|
|
106
|
+
@media (max-width: 680px) {
|
|
107
|
+
.brand .rt-Heading {
|
|
108
|
+
display: none;
|
|
109
|
+
}
|
|
110
|
+
.session-toolbar {
|
|
111
|
+
font-size: 11px;
|
|
112
|
+
gap: 4px;
|
|
113
|
+
}
|
|
114
|
+
}
|
package/src/web/style.css
CHANGED
|
@@ -158,10 +158,10 @@ button:disabled {
|
|
|
158
158
|
touch-action: none;
|
|
159
159
|
grid-row: 1;
|
|
160
160
|
}
|
|
161
|
-
.pane-resizer[aria-label="Resize
|
|
161
|
+
.pane-resizer[aria-label="Resize filters"] {
|
|
162
162
|
grid-column: 2;
|
|
163
163
|
}
|
|
164
|
-
.pane-resizer[aria-label="Resize
|
|
164
|
+
.pane-resizer[aria-label="Resize details"] {
|
|
165
165
|
grid-column: 4;
|
|
166
166
|
}
|
|
167
167
|
.pane-resizer:hover,
|