@narumitw/pi-inspect 0.1.0 → 0.2.1
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 +31 -29
- 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 +104 -58
- 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 +3 -2
- package/src/web/tool-inspector.css +175 -0
- package/src/web/tool-inspector.tsx +210 -0
- package/src/web/tool-schema.ts +217 -0
- 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,13 @@
|
|
|
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";
|
|
10
|
+
import { ToolInspector } from "./tool-inspector.js";
|
|
9
11
|
|
|
10
12
|
export function Inspector({
|
|
11
13
|
selected,
|
|
@@ -22,6 +24,7 @@ export function Inspector({
|
|
|
22
24
|
changeTab,
|
|
23
25
|
select,
|
|
24
26
|
selectCall,
|
|
27
|
+
preview,
|
|
25
28
|
}: {
|
|
26
29
|
selected: string;
|
|
27
30
|
node?: EntrySummary;
|
|
@@ -37,6 +40,7 @@ export function Inspector({
|
|
|
37
40
|
changeTab(tab: string): void;
|
|
38
41
|
select(id: string): void;
|
|
39
42
|
selectCall(id: string): void;
|
|
43
|
+
preview(): void;
|
|
40
44
|
}) {
|
|
41
45
|
const [format, setFormat] = useState("formatted");
|
|
42
46
|
const raw = record(detail?.raw.value);
|
|
@@ -62,24 +66,22 @@ export function Inspector({
|
|
|
62
66
|
);
|
|
63
67
|
const enabled = useMemo(
|
|
64
68
|
() => [
|
|
69
|
+
"content",
|
|
65
70
|
"raw",
|
|
66
|
-
"prompt",
|
|
67
|
-
"tools",
|
|
68
|
-
...(isCall ? [] : ["context"]),
|
|
69
|
-
...(hasSkills ? ["skills"] : []),
|
|
71
|
+
...(isCall ? [] : ["prompt", "tools", "context", ...(hasSkills ? ["skills"] : [])]),
|
|
70
72
|
...(codemode ? ["codemode"] : []),
|
|
71
73
|
],
|
|
72
74
|
[isCall, hasSkills, codemode],
|
|
73
75
|
);
|
|
74
76
|
useEffect(() => {
|
|
75
|
-
if (!enabled.includes(tab)) changeTab("
|
|
77
|
+
if (!enabled.includes(tab)) changeTab("content");
|
|
76
78
|
}, [enabled, tab, changeTab]);
|
|
77
79
|
return (
|
|
78
80
|
<section className="panel inspector-panel">
|
|
79
81
|
<div className="panel-heading">
|
|
80
82
|
<Heading size="3">
|
|
81
83
|
<CubeIcon />
|
|
82
|
-
|
|
84
|
+
Details
|
|
83
85
|
</Heading>
|
|
84
86
|
{activeRaw && <Copy key={selected} value={output(activeRaw.value)} />}
|
|
85
87
|
</div>
|
|
@@ -90,7 +92,8 @@ export function Inspector({
|
|
|
90
92
|
</Text>
|
|
91
93
|
)}
|
|
92
94
|
<Heading size="4">
|
|
93
|
-
{call ? "Captured execution" : node ? eventName(node.kind) : "Entry"} ·
|
|
95
|
+
{call ? "Captured execution" : node ? eventName(node.kind) : "Entry"} ·{" "}
|
|
96
|
+
{selected.slice(0, 16) || "no selection"}
|
|
94
97
|
</Heading>
|
|
95
98
|
<Text size="2" color="gray">
|
|
96
99
|
{call?.name ?? node?.name ?? "Session log entry"}
|
|
@@ -119,12 +122,96 @@ export function Inspector({
|
|
|
119
122
|
)}
|
|
120
123
|
<Tabs.Root value={tab} onValueChange={changeTab} className="inspector-tabs">
|
|
121
124
|
<Tabs.List wrap="nowrap" aria-label="Event detail views">
|
|
122
|
-
{["raw", "prompt", "tools", "context", "skills", "codemode"].map((tab) => (
|
|
125
|
+
{["content", "raw", "prompt", "tools", "context", "skills", "codemode"].map((tab) => (
|
|
123
126
|
<Tabs.Trigger key={tab} value={tab} disabled={!enabled.includes(tab)}>
|
|
124
127
|
{tab}
|
|
125
128
|
</Tabs.Trigger>
|
|
126
129
|
))}
|
|
127
130
|
</Tabs.List>
|
|
131
|
+
<Tabs.Content value="content">
|
|
132
|
+
{call ? (
|
|
133
|
+
<>
|
|
134
|
+
<Status value={call.status} />
|
|
135
|
+
<Data label="Arguments · redacted display copy" data={call.args} scope={`${call.occurrenceId}-args`} />
|
|
136
|
+
<Data label="Result · observed tool event" data={call.result} scope={`${call.occurrenceId}-result`} />
|
|
137
|
+
<div className="inspector-metadata">
|
|
138
|
+
<Metadata
|
|
139
|
+
rows={[
|
|
140
|
+
["Source", "Observed tool execution"],
|
|
141
|
+
[
|
|
142
|
+
"Parent relationship",
|
|
143
|
+
call.parentUnavailable ??
|
|
144
|
+
call.parentOccurrenceId ??
|
|
145
|
+
(call.parentId ? "unavailable" : "none (root)"),
|
|
146
|
+
],
|
|
147
|
+
[
|
|
148
|
+
"Correlation",
|
|
149
|
+
call.correlationUnavailable || !call.branchAnchor
|
|
150
|
+
? "unavailable"
|
|
151
|
+
: "Recorded anchor only; not request association",
|
|
152
|
+
],
|
|
153
|
+
["Reported duration", duration(call.durationMs)],
|
|
154
|
+
["Occurrence", call.occurrenceId],
|
|
155
|
+
["Raw call ID", call.id],
|
|
156
|
+
["Anchor entry", call.branchAnchor ?? undefined],
|
|
157
|
+
[
|
|
158
|
+
"Start observed",
|
|
159
|
+
call.observedStartedAt === undefined ? undefined : new Date(call.observedStartedAt).toISOString(),
|
|
160
|
+
],
|
|
161
|
+
[
|
|
162
|
+
"End observed",
|
|
163
|
+
call.observedEndedAt === undefined ? undefined : new Date(call.observedEndedAt).toISOString(),
|
|
164
|
+
],
|
|
165
|
+
[
|
|
166
|
+
"Children",
|
|
167
|
+
String(
|
|
168
|
+
snapshot?.calls.filter((child) => child.parentOccurrenceId === call.occurrenceId).length ?? 0,
|
|
169
|
+
),
|
|
170
|
+
],
|
|
171
|
+
]}
|
|
172
|
+
/>
|
|
173
|
+
</div>
|
|
174
|
+
{call.parentId && !snapshot?.calls.some((parent) => parent.occurrenceId === call.parentOccurrenceId) && (
|
|
175
|
+
<Text size="1" color="gray">
|
|
176
|
+
Parent {call.parentId} (not captured)
|
|
177
|
+
</Text>
|
|
178
|
+
)}
|
|
179
|
+
{snapshot?.calls
|
|
180
|
+
.filter(
|
|
181
|
+
(item) =>
|
|
182
|
+
item.parentOccurrenceId === call.occurrenceId || item.occurrenceId === call.parentOccurrenceId,
|
|
183
|
+
)
|
|
184
|
+
.map((item) => (
|
|
185
|
+
<Button
|
|
186
|
+
key={item.occurrenceId}
|
|
187
|
+
size="1"
|
|
188
|
+
variant="ghost"
|
|
189
|
+
onClick={() => selectCall(item.occurrenceId)}
|
|
190
|
+
>
|
|
191
|
+
Related execution · {item.name} · {item.occurrenceId}
|
|
192
|
+
</Button>
|
|
193
|
+
))}
|
|
194
|
+
{call.branchAnchor && snapshot?.nodes.some((entry) => entry.id === call.branchAnchor) && (
|
|
195
|
+
<Button variant="ghost" size="1" onClick={() => select(call.branchAnchor ?? "")}>
|
|
196
|
+
Inspect recorded anchor →
|
|
197
|
+
</Button>
|
|
198
|
+
)}
|
|
199
|
+
</>
|
|
200
|
+
) : (
|
|
201
|
+
<>
|
|
202
|
+
<Text as="p" size="1" color="gray">
|
|
203
|
+
Session log entry · bounded recorded content
|
|
204
|
+
</Text>
|
|
205
|
+
{node?.status && <Status value={node.status} />}
|
|
206
|
+
<RecordedContent data={detail?.raw} scope={selected} />
|
|
207
|
+
</>
|
|
208
|
+
)}
|
|
209
|
+
{!detail && !call && !detailError && (
|
|
210
|
+
<Text size="1" color="gray">
|
|
211
|
+
Loading bounded entry details…
|
|
212
|
+
</Text>
|
|
213
|
+
)}
|
|
214
|
+
</Tabs.Content>
|
|
128
215
|
<Tabs.Content value="raw">
|
|
129
216
|
<div className="format-toolbar">
|
|
130
217
|
<div className="view-switch">
|
|
@@ -248,60 +335,14 @@ export function Inspector({
|
|
|
248
335
|
/>
|
|
249
336
|
<Data label="Historical sections" data={branch?.sections} scope={`${selected}-sections`} />
|
|
250
337
|
<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
338
|
</Tabs.Content>
|
|
253
339
|
<Tabs.Content value="tools">
|
|
254
|
-
<
|
|
255
|
-
label="Historical declared tools · preview branch"
|
|
256
|
-
data={branch?.declaredTools}
|
|
257
|
-
scope={`${selected}-declaredTools`}
|
|
258
|
-
/>
|
|
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
|
-
))}
|
|
340
|
+
<ToolInspector key={selected} data={branch?.declaredTools} scope={`${selected}-declaredTools`} />
|
|
286
341
|
</Tabs.Content>
|
|
287
342
|
<Tabs.Content value="skills">
|
|
288
343
|
<Text as="p" size="2" color="gray">
|
|
289
344
|
Advertised or read does not prove model compliance. Historical discovery may be unavailable.
|
|
290
345
|
</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
346
|
<Data label="Evidence on preview branch" data={branch?.skillEvidence} scope={`${selected}-skillEvidence`} />
|
|
306
347
|
</Tabs.Content>
|
|
307
348
|
<Tabs.Content value="context">
|
|
@@ -309,6 +350,9 @@ export function Inspector({
|
|
|
309
350
|
Pi projection applies compaction and context edits. Request-local hooks can still transform it; this is not
|
|
310
351
|
the final provider HTTP request.
|
|
311
352
|
</Text>
|
|
353
|
+
<Button size="1" onClick={preview} disabled={!branch}>
|
|
354
|
+
View branch context
|
|
355
|
+
</Button>
|
|
312
356
|
<Data label="Projected branch entries" data={branch?.projection} scope={`${selected}-projection`} />
|
|
313
357
|
<Data label="Selected entry contribution" data={detail?.projected} scope={`${selected}-projected`} />
|
|
314
358
|
</Tabs.Content>
|
|
@@ -328,7 +372,9 @@ export function Inspector({
|
|
|
328
372
|
/>
|
|
329
373
|
<Data label="Source / output / persisted nestedCalls" data={detail?.raw} />
|
|
330
374
|
{captured.map((call) => (
|
|
331
|
-
<
|
|
375
|
+
<Button key={call.occurrenceId} variant="ghost" onClick={() => selectCall(call.occurrenceId)}>
|
|
376
|
+
{call.name} · {call.occurrenceId} · inspect captured execution
|
|
377
|
+
</Button>
|
|
332
378
|
))}
|
|
333
379
|
</Tabs.Content>
|
|
334
380
|
</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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
@import "./components.css";
|
|
2
2
|
@import "./panels.css";
|
|
3
3
|
@import "./trace.css";
|
|
4
|
+
@import "./tool-inspector.css";
|
|
4
5
|
|
|
5
6
|
:root,
|
|
6
7
|
.radix-themes {
|
|
@@ -158,10 +159,10 @@ button:disabled {
|
|
|
158
159
|
touch-action: none;
|
|
159
160
|
grid-row: 1;
|
|
160
161
|
}
|
|
161
|
-
.pane-resizer[aria-label="Resize
|
|
162
|
+
.pane-resizer[aria-label="Resize filters"] {
|
|
162
163
|
grid-column: 2;
|
|
163
164
|
}
|
|
164
|
-
.pane-resizer[aria-label="Resize
|
|
165
|
+
.pane-resizer[aria-label="Resize details"] {
|
|
165
166
|
grid-column: 4;
|
|
166
167
|
}
|
|
167
168
|
.pane-resizer:hover,
|