@narumitw/pi-inspect 0.0.0-stage → 0.1.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.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +107 -2
  3. package/dist/app.css +1 -0
  4. package/dist/app.js +129 -0
  5. package/dist/index.html +1 -0
  6. package/docs/REVIEW.md +189 -0
  7. package/docs/VERIFICATION.md +186 -0
  8. package/docs/viewer.md +63 -0
  9. package/package.json +67 -4
  10. package/src/ancestry.ts +32 -0
  11. package/src/collector.ts +143 -0
  12. package/src/context.ts +115 -0
  13. package/src/correlation.ts +27 -0
  14. package/src/entry-index.ts +17 -0
  15. package/src/extension.ts +259 -0
  16. package/src/feed.ts +145 -0
  17. package/src/identity.ts +112 -0
  18. package/src/index.ts +1 -0
  19. package/src/model.ts +113 -0
  20. package/src/native-projection.ts +28 -0
  21. package/src/privacy.ts +136 -0
  22. package/src/projection.ts +361 -0
  23. package/src/server.ts +202 -0
  24. package/src/system-message.ts +117 -0
  25. package/src/web/api.ts +137 -0
  26. package/src/web/app.tsx +439 -0
  27. package/src/web/components.css +261 -0
  28. package/src/web/components.tsx +289 -0
  29. package/src/web/composition.css +554 -0
  30. package/src/web/context-composition.tsx +324 -0
  31. package/src/web/entry-calls.ts +14 -0
  32. package/src/web/format.ts +92 -0
  33. package/src/web/hierarchy.ts +117 -0
  34. package/src/web/inline-entry.tsx +124 -0
  35. package/src/web/inspector.tsx +337 -0
  36. package/src/web/json-tree.tsx +74 -0
  37. package/src/web/live-drawer.tsx +175 -0
  38. package/src/web/overview.tsx +67 -0
  39. package/src/web/panels.css +267 -0
  40. package/src/web/panes.tsx +123 -0
  41. package/src/web/search.ts +16 -0
  42. package/src/web/style.css +332 -0
  43. package/src/web/styles.d.ts +1 -0
  44. package/src/web/timeline.tsx +33 -0
  45. package/src/web/timing.ts +26 -0
  46. package/src/web/trace.css +410 -0
  47. package/src/web/trace.tsx +273 -0
  48. package/src/web/tree.tsx +281 -0
  49. package/src/web/virtual-context.ts +138 -0
@@ -0,0 +1 @@
1
+ declare module "*.css";
@@ -0,0 +1,33 @@
1
+ import type { Call } from "../model.js";
2
+ import { type Axis, interval, position, timestamp } from "./timing.js";
3
+
4
+ export function TimelineMark({ range, logTime, call }: { range?: Axis; logTime?: string; call?: Call }) {
5
+ if (!range) return <span className="timing-unavailable">—</span>;
6
+ const span = call ? interval(call) : undefined;
7
+ const point = logTime === undefined ? (call?.observedStartedAt ?? call?.observedEndedAt) : timestamp(logTime);
8
+ if (span && span.end > span.start)
9
+ return (
10
+ <span
11
+ className="timeline-track"
12
+ title={`Observed callback interval: ${new Date(span.start).toISOString()} → ${new Date(span.end).toISOString()} (${span.end - span.start}ms). Not provider transport timing.`}
13
+ >
14
+ <span
15
+ className="timeline-span"
16
+ style={{
17
+ left: `${position(span.start, range)}%`,
18
+ width: `${position(span.end, range) - position(span.start, range)}%`,
19
+ }}
20
+ />
21
+ </span>
22
+ );
23
+ return point === undefined ? (
24
+ <span className="timing-unavailable">—</span>
25
+ ) : (
26
+ <span
27
+ className="timeline-track"
28
+ title={`${logTime === undefined ? "Observed lifecycle point" : "Session log timestamp"}: ${new Date(point).toISOString()}`}
29
+ >
30
+ <span className="timeline-point" style={{ left: `${position(point, range)}%` }} />
31
+ </span>
32
+ );
33
+ }
@@ -0,0 +1,26 @@
1
+ import type { Call, EntrySummary } from "../model.js";
2
+ export interface Axis {
3
+ start: number;
4
+ end: number;
5
+ }
6
+ export function timestamp(value: string): number | undefined {
7
+ const parsed = Date.parse(value);
8
+ return Number.isFinite(parsed) ? parsed : undefined;
9
+ }
10
+ export function axis(entries: EntrySummary[], calls: Call[]): Axis | undefined {
11
+ const values = [
12
+ ...entries.map((entry) => timestamp(entry.timestamp)),
13
+ ...calls.flatMap((call) => [call.observedStartedAt, call.observedEndedAt]),
14
+ ].filter((value): value is number => value !== undefined && Number.isFinite(value));
15
+ return values.length ? { start: Math.min(...values), end: Math.max(...values) } : undefined;
16
+ }
17
+ export function position(value: number, range: Axis): number {
18
+ return range.end === range.start ? 50 : ((value - range.start) / (range.end - range.start)) * 100;
19
+ }
20
+ export function interval(call: Call): { start: number; end: number } | undefined {
21
+ const start = call.observedStartedAt;
22
+ const end = call.observedEndedAt;
23
+ return start !== undefined && end !== undefined && Number.isFinite(start) && Number.isFinite(end) && end >= start
24
+ ? { start, end }
25
+ : undefined;
26
+ }
@@ -0,0 +1,410 @@
1
+ .overview {
2
+ flex-shrink: 0;
3
+ padding: 0 6px 5px;
4
+ }
5
+ .overview-metrics {
6
+ display: flex;
7
+ justify-content: space-between;
8
+ gap: 12px;
9
+ flex-wrap: wrap;
10
+ }
11
+ .metric {
12
+ display: flex;
13
+ align-items: baseline;
14
+ gap: 6px;
15
+ font-size: 10px;
16
+ color: var(--muted);
17
+ white-space: nowrap;
18
+ }
19
+ .metric strong {
20
+ font-size: 12px;
21
+ color: var(--secondary);
22
+ font-variant-numeric: tabular-nums;
23
+ font-weight: 600;
24
+ }
25
+ .trace-panel {
26
+ flex: 1;
27
+ display: flex;
28
+ flex-direction: column;
29
+ }
30
+ .trace-toolbar {
31
+ display: flex;
32
+ align-items: center;
33
+ padding: 7px 9px 4px;
34
+ gap: 10px;
35
+ flex-wrap: wrap;
36
+ }
37
+ .trace-toolbar .rt-Heading {
38
+ font-size: 14px;
39
+ }
40
+ .trace-toolbar > .rt-Text {
41
+ font-size: 10px;
42
+ color: var(--muted);
43
+ }
44
+ .trace-actions {
45
+ display: flex;
46
+ align-items: center;
47
+ gap: 6px;
48
+ margin-left: auto;
49
+ }
50
+ .trace-actions .rt-Button {
51
+ font-size: 10px;
52
+ color: var(--secondary);
53
+ }
54
+ .trace-hint {
55
+ padding: 0 10px 6px;
56
+ color: var(--muted);
57
+ font-size: 10px;
58
+ border-bottom: 1px solid var(--panel-border);
59
+ }
60
+ .time-axis {
61
+ display: flex;
62
+ justify-content: space-between;
63
+ gap: 6px;
64
+ padding: 4px 10px;
65
+ font:
66
+ 9px / 1.4 Consolas,
67
+ monospace;
68
+ color: var(--muted);
69
+ border-bottom: 1px solid var(--panel-border);
70
+ }
71
+ .trace-scroll {
72
+ overflow: auto;
73
+ flex: 1;
74
+ min-height: 0;
75
+ padding: 5px 8px;
76
+ }
77
+ .trace-tree {
78
+ min-width: 0;
79
+ }
80
+ .trace-item {
81
+ position: relative;
82
+ border-left: 1px solid var(--panel-border);
83
+ }
84
+ .trace-item::before {
85
+ content: "";
86
+ position: absolute;
87
+ left: -1px;
88
+ width: 8px;
89
+ top: 16px;
90
+ border-top: 1px solid var(--panel-border);
91
+ }
92
+ .trace-row {
93
+ display: flex;
94
+ position: relative;
95
+ align-items: center;
96
+ min-height: 34px;
97
+ gap: 7px;
98
+ padding: 3px 7px 3px 4px;
99
+ color: var(--gray-12);
100
+ font-size: 11px;
101
+ border-bottom: 1px solid color-mix(in srgb, var(--panel-border), transparent 55%);
102
+ border-radius: 3px;
103
+ cursor: pointer;
104
+ outline: none;
105
+ }
106
+ .trace-row:hover {
107
+ background: var(--surface-hover);
108
+ }
109
+ .trace-row.expanded {
110
+ background: color-mix(in srgb, var(--panel-raised), transparent 50%);
111
+ }
112
+ .trace-row.selected {
113
+ background: var(--selected-bg);
114
+ box-shadow: inset 2px 0 var(--blue-9);
115
+ }
116
+ .expand-button {
117
+ display: grid;
118
+ place-items: center;
119
+ width: 20px;
120
+ height: 20px;
121
+ border: 0;
122
+ background: transparent;
123
+ color: var(--muted);
124
+ border-radius: 3px;
125
+ flex-shrink: 0;
126
+ padding: 0;
127
+ }
128
+ .expand-button:hover {
129
+ color: var(--gray-12);
130
+ background: var(--surface-hover);
131
+ }
132
+ .trace-event {
133
+ display: flex;
134
+ align-items: center;
135
+ gap: 6px;
136
+ min-width: 0;
137
+ flex: 1;
138
+ }
139
+ .row-title {
140
+ display: flex;
141
+ gap: 7px;
142
+ min-width: 0;
143
+ align-items: baseline;
144
+ white-space: nowrap;
145
+ }
146
+ .row-title strong {
147
+ font-weight: 500;
148
+ flex-shrink: 0;
149
+ }
150
+ .row-title > span {
151
+ color: var(--secondary);
152
+ text-overflow: ellipsis;
153
+ overflow: hidden;
154
+ min-width: 0;
155
+ }
156
+ .trace-event > code,
157
+ .row-metrics time,
158
+ .call-trigger code {
159
+ font:
160
+ 10px / 1.4 Consolas,
161
+ monospace;
162
+ color: var(--muted);
163
+ white-space: nowrap;
164
+ }
165
+ .ancestor-badge {
166
+ color: var(--muted);
167
+ font-size: 9px;
168
+ }
169
+ .row-metrics {
170
+ display: flex;
171
+ gap: 8px;
172
+ align-items: center;
173
+ flex-shrink: 0;
174
+ font-size: 10px;
175
+ font-variant-numeric: tabular-nums;
176
+ color: var(--secondary);
177
+ }
178
+ .entry-expanded {
179
+ padding: 6px 10px 8px 29px;
180
+ background: color-mix(in srgb, var(--code-bg), transparent 15%);
181
+ border-bottom: 1px solid var(--panel-border);
182
+ }
183
+ .inline-tabs .rt-TabsList {
184
+ flex-wrap: nowrap;
185
+ overflow-x: auto;
186
+ }
187
+ .inline-tabs .rt-TabsTrigger {
188
+ padding: 0 7px;
189
+ font-size: 11px;
190
+ height: 27px;
191
+ white-space: nowrap;
192
+ flex-shrink: 0;
193
+ }
194
+ .inline-tabs .rt-TabsTriggerInner,
195
+ .inline-tabs .rt-TabsTriggerInnerHidden {
196
+ padding: 0;
197
+ }
198
+ .inline-tabs .rt-TabsContent {
199
+ padding-top: 5px;
200
+ }
201
+ .inline-summary {
202
+ display: flex;
203
+ align-items: start;
204
+ gap: 16px;
205
+ }
206
+ .inline-summary .metadata {
207
+ flex: 1;
208
+ }
209
+ .usage-breakdown {
210
+ min-width: 160px;
211
+ width: 35%;
212
+ font-size: 10px;
213
+ color: var(--secondary);
214
+ padding-top: 7px;
215
+ }
216
+ .usage-bar {
217
+ display: flex;
218
+ height: 5px;
219
+ border-radius: 3px;
220
+ overflow: hidden;
221
+ background: var(--panel-raised);
222
+ margin-bottom: 6px;
223
+ }
224
+ .usage-bar span:first-child {
225
+ background: #4b91f7;
226
+ }
227
+ .usage-bar span:last-child {
228
+ background: #a38adc;
229
+ }
230
+ .children-label {
231
+ display: block;
232
+ font-size: 10px;
233
+ color: var(--muted);
234
+ padding-top: 5px;
235
+ }
236
+ .trace-pagination {
237
+ flex-shrink: 0;
238
+ display: flex;
239
+ gap: 8px;
240
+ justify-content: space-between;
241
+ align-items: center;
242
+ padding: 4px 8px;
243
+ border-top: 1px solid var(--panel-border);
244
+ font-size: 9px;
245
+ color: var(--muted);
246
+ flex-wrap: wrap;
247
+ }
248
+ .trace-pagination .rt-Button {
249
+ font-size: 10px;
250
+ }
251
+ .empty-state {
252
+ padding: 12px;
253
+ text-align: center;
254
+ font-size: 11px;
255
+ color: var(--muted);
256
+ }
257
+ .timeline-track {
258
+ position: relative;
259
+ display: block;
260
+ width: 24%;
261
+ min-width: 90px;
262
+ height: 16px;
263
+ border-bottom: 1px solid var(--panel-border);
264
+ flex-shrink: 0;
265
+ }
266
+ .timeline-point {
267
+ position: absolute;
268
+ width: 5px;
269
+ height: 5px;
270
+ margin-left: -2px;
271
+ top: 5px;
272
+ border-radius: 50%;
273
+ background: var(--blue-10);
274
+ }
275
+ .timeline-span {
276
+ position: absolute;
277
+ height: 5px;
278
+ top: 5px;
279
+ background: #72b4c2;
280
+ border-radius: 2px;
281
+ }
282
+ .timing-unavailable {
283
+ color: var(--muted);
284
+ }
285
+ .live-drawer {
286
+ flex-shrink: 0;
287
+ border: 1px solid var(--panel-border);
288
+ border-radius: 4px;
289
+ background: var(--panel-bg);
290
+ min-width: 0;
291
+ overflow: hidden;
292
+ }
293
+ .live-drawer-toggle {
294
+ display: flex;
295
+ align-items: center;
296
+ gap: 8px;
297
+ width: 100%;
298
+ padding: 7px 8px;
299
+ color: var(--secondary);
300
+ border: 0;
301
+ background: transparent;
302
+ text-align: left;
303
+ font-size: 10px;
304
+ }
305
+ .live-drawer-toggle strong {
306
+ font-size: 11px;
307
+ font-weight: 500;
308
+ }
309
+ .drawer-scope {
310
+ margin-left: auto;
311
+ color: var(--muted);
312
+ }
313
+ .live-drawer-body {
314
+ height: min(30vh, 260px);
315
+ min-height: 110px;
316
+ overflow: auto;
317
+ padding: 4px 8px;
318
+ }
319
+ .live-controls {
320
+ display: flex;
321
+ align-items: center;
322
+ gap: 6px;
323
+ margin-bottom: 6px;
324
+ }
325
+ .live-controls > .rt-Text {
326
+ flex: 1;
327
+ font-size: 10px;
328
+ line-height: 14px;
329
+ }
330
+ .live-controls .rt-Button {
331
+ font-size: 10px;
332
+ }
333
+ .live-call-row {
334
+ display: flex;
335
+ align-items: center;
336
+ gap: 5px;
337
+ min-height: 31px;
338
+ border-bottom: 1px solid var(--panel-border);
339
+ }
340
+ .live-call-row.selected {
341
+ background: var(--selected-bg);
342
+ }
343
+ .call-trigger {
344
+ display: flex;
345
+ align-items: center;
346
+ gap: 8px;
347
+ flex: 1;
348
+ min-width: 0;
349
+ color: var(--secondary);
350
+ background: none;
351
+ border: 0;
352
+ padding: 5px 0;
353
+ text-align: left;
354
+ font-size: 11px;
355
+ }
356
+ .call-trigger > strong {
357
+ font-weight: 500;
358
+ overflow: hidden;
359
+ text-overflow: ellipsis;
360
+ white-space: nowrap;
361
+ flex: 1;
362
+ }
363
+ .call-trigger > span:last-child {
364
+ font-variant-numeric: tabular-nums;
365
+ font-size: 10px;
366
+ }
367
+ @media (max-width: 680px) {
368
+ .trace-toolbar > .rt-Text {
369
+ display: none;
370
+ }
371
+ .trace-actions {
372
+ gap: 4px;
373
+ }
374
+ .trace-actions .rt-Button {
375
+ font-size: 9px;
376
+ }
377
+ .trace-hint {
378
+ font-size: 9px;
379
+ }
380
+ .trace-event > code,
381
+ .ancestor-badge {
382
+ display: none;
383
+ }
384
+ .row-title {
385
+ flex-direction: column;
386
+ gap: 0;
387
+ line-height: 14px;
388
+ }
389
+ .row-metrics > span {
390
+ display: none;
391
+ }
392
+ .inline-summary {
393
+ display: block;
394
+ }
395
+ .usage-breakdown {
396
+ width: 100%;
397
+ }
398
+ .drawer-scope {
399
+ display: none;
400
+ }
401
+ .live-controls > .rt-Text {
402
+ display: none;
403
+ }
404
+ .timeline-track {
405
+ min-width: 60px;
406
+ }
407
+ .time-axis span:nth-child(2) {
408
+ display: none;
409
+ }
410
+ }