aipeek 0.1.1 → 0.1.3
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/{chunk-5SM5A2YR.js → chunk-FI6MF54L.js} +161 -103
- package/dist/{chunk-QXCVA2LU.cjs → chunk-KW232XW7.cjs} +160 -102
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/plugin.cjs +2 -2
- package/dist/plugin.js +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/plugin.ts
|
|
2
|
-
import { readFileSync, writeFileSync
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
3
3
|
import { dirname, resolve } from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
|
|
@@ -43,19 +43,23 @@ var UI_PRIMITIVES = /* @__PURE__ */ new Set([
|
|
|
43
43
|
"Panel"
|
|
44
44
|
]);
|
|
45
45
|
function compactUI(tree) {
|
|
46
|
-
if (!tree)
|
|
46
|
+
if (!tree)
|
|
47
|
+
return "";
|
|
47
48
|
const lines = tree.split("\n");
|
|
48
49
|
const result = [];
|
|
49
50
|
const repeatTracker = /* @__PURE__ */ new Map();
|
|
50
51
|
for (let i = 0; i < lines.length; i++) {
|
|
51
52
|
const line = lines[i];
|
|
52
53
|
const trimmed = line.trimStart();
|
|
53
|
-
if (!trimmed)
|
|
54
|
+
if (!trimmed)
|
|
55
|
+
continue;
|
|
54
56
|
const indent = line.length - trimmed.length;
|
|
55
57
|
const depth = Math.floor(indent / 2);
|
|
56
|
-
if (depth > MAX_UI_DEPTH)
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
if (depth > MAX_UI_DEPTH)
|
|
59
|
+
continue;
|
|
60
|
+
const componentName = trimmed.split(/[\s[—]/)[0];
|
|
61
|
+
if (UI_PRIMITIVES.has(componentName))
|
|
62
|
+
continue;
|
|
59
63
|
const key = `${depth}:${componentName}`;
|
|
60
64
|
const tracker = repeatTracker.get(key);
|
|
61
65
|
if (tracker && i - tracker.lastIndex <= 2) {
|
|
@@ -65,7 +69,7 @@ function compactUI(tree) {
|
|
|
65
69
|
}
|
|
66
70
|
for (const [k, t] of repeatTracker) {
|
|
67
71
|
if (t.count > 1) {
|
|
68
|
-
const d = parseInt(k.split(":")[0]);
|
|
72
|
+
const d = Number.parseInt(k.split(":")[0]);
|
|
69
73
|
const name = k.split(":").slice(1).join(":");
|
|
70
74
|
result.push(`${" ".repeat(d)}${name} \xD7${t.count}`);
|
|
71
75
|
}
|
|
@@ -78,7 +82,7 @@ function compactUI(tree) {
|
|
|
78
82
|
}
|
|
79
83
|
for (const [k, t] of repeatTracker) {
|
|
80
84
|
if (t.count > 1) {
|
|
81
|
-
const d = parseInt(k.split(":")[0]);
|
|
85
|
+
const d = Number.parseInt(k.split(":")[0]);
|
|
82
86
|
const name = k.split(":").slice(1).join(":");
|
|
83
87
|
result.push(`${" ".repeat(d)}${name} \xD7${t.count}`);
|
|
84
88
|
}
|
|
@@ -98,9 +102,11 @@ var NOISE_PATTERNS = [
|
|
|
98
102
|
/\[webpack\]/i
|
|
99
103
|
];
|
|
100
104
|
function compactConsole(logs) {
|
|
101
|
-
if (!logs.length)
|
|
105
|
+
if (!logs.length)
|
|
106
|
+
return "";
|
|
102
107
|
const filtered = logs.filter((l) => !NOISE_PATTERNS.some((p) => p.test(l.text)));
|
|
103
|
-
if (!filtered.length)
|
|
108
|
+
if (!filtered.length)
|
|
109
|
+
return "";
|
|
104
110
|
const deduped = [];
|
|
105
111
|
for (const log of filtered) {
|
|
106
112
|
const last = deduped[deduped.length - 1];
|
|
@@ -125,11 +131,13 @@ function compactConsole(logs) {
|
|
|
125
131
|
return lines.join("\n");
|
|
126
132
|
}
|
|
127
133
|
function compactNetwork(requests) {
|
|
128
|
-
if (!requests.length)
|
|
134
|
+
if (!requests.length)
|
|
135
|
+
return "";
|
|
129
136
|
const relevant = requests.filter(
|
|
130
137
|
(r) => r.resourceType === "fetch" || r.resourceType === "xhr" || r.resourceType === "websocket" || isApiUrl(r.url)
|
|
131
138
|
);
|
|
132
|
-
if (!relevant.length)
|
|
139
|
+
if (!relevant.length)
|
|
140
|
+
return "";
|
|
133
141
|
const lines = [];
|
|
134
142
|
for (const req of relevant) {
|
|
135
143
|
const duration = req.duration > 0 ? ` ${formatDuration(req.duration)}` : "";
|
|
@@ -156,7 +164,7 @@ function isApiUrl(url) {
|
|
|
156
164
|
function compactUrl(url) {
|
|
157
165
|
try {
|
|
158
166
|
const u = new URL(url);
|
|
159
|
-
const path = u.pathname + (u.search ?
|
|
167
|
+
const path = u.pathname + (u.search ? `?${truncate(u.search.slice(1), 50)}` : "");
|
|
160
168
|
return path;
|
|
161
169
|
} catch {
|
|
162
170
|
return truncate(url, 80);
|
|
@@ -166,7 +174,8 @@ function formatDuration(ms) {
|
|
|
166
174
|
return ms >= 1e3 ? `${(ms / 1e3).toFixed(1)}s` : `${Math.round(ms)}ms`;
|
|
167
175
|
}
|
|
168
176
|
function compactErrors(errors) {
|
|
169
|
-
if (!errors.length)
|
|
177
|
+
if (!errors.length)
|
|
178
|
+
return "";
|
|
170
179
|
const seen = /* @__PURE__ */ new Map();
|
|
171
180
|
for (const err of errors) {
|
|
172
181
|
if (!seen.has(err.message)) {
|
|
@@ -189,7 +198,8 @@ function filterStack(stack) {
|
|
|
189
198
|
return stack.split("\n").map((l) => l.trim()).filter((l) => l.startsWith("at ")).map((l) => l.slice(3)).filter((l) => !l.includes("node_modules") && !l.includes("<anonymous>")).slice(0, 5);
|
|
190
199
|
}
|
|
191
200
|
function compactState(state) {
|
|
192
|
-
if (!state || !Object.keys(state).length)
|
|
201
|
+
if (!state || !Object.keys(state).length)
|
|
202
|
+
return "";
|
|
193
203
|
const lines = [];
|
|
194
204
|
for (const [name, value] of Object.entries(state)) {
|
|
195
205
|
lines.push(`${name}:`);
|
|
@@ -204,12 +214,15 @@ function compactState(state) {
|
|
|
204
214
|
return lines.join("\n");
|
|
205
215
|
}
|
|
206
216
|
function formatValue(v) {
|
|
207
|
-
if (v === null || v === void 0)
|
|
208
|
-
|
|
209
|
-
if (typeof v === "
|
|
217
|
+
if (v === null || v === void 0)
|
|
218
|
+
return String(v);
|
|
219
|
+
if (typeof v === "string")
|
|
220
|
+
return v;
|
|
221
|
+
if (typeof v === "number" || typeof v === "boolean")
|
|
222
|
+
return String(v);
|
|
210
223
|
if (typeof v === "object") {
|
|
211
224
|
const s = JSON.stringify(v);
|
|
212
|
-
return s.length > 120 ? s.slice(0, 120)
|
|
225
|
+
return s.length > 120 ? `${s.slice(0, 120)}\u2026` : s;
|
|
213
226
|
}
|
|
214
227
|
return String(v);
|
|
215
228
|
}
|
|
@@ -231,39 +244,7 @@ function compact(raw) {
|
|
|
231
244
|
};
|
|
232
245
|
}
|
|
233
246
|
function truncate(s, max) {
|
|
234
|
-
return s.length > max ? s.slice(0, max)
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// src/emit.ts
|
|
238
|
-
var SECTIONS = ["ui", "console", "network", "errors", "state"];
|
|
239
|
-
var COUNTED_SECTIONS = {
|
|
240
|
-
console: "console",
|
|
241
|
-
network: "network",
|
|
242
|
-
errors: "errors",
|
|
243
|
-
state: "state"
|
|
244
|
-
};
|
|
245
|
-
function emit(state) {
|
|
246
|
-
const sections = [];
|
|
247
|
-
for (const key of SECTIONS) {
|
|
248
|
-
if (state[key]) {
|
|
249
|
-
const countKey = COUNTED_SECTIONS[key];
|
|
250
|
-
const count = countKey ? state.counts?.[countKey] ?? 0 : 0;
|
|
251
|
-
const attr = count ? ` count="${count}"` : "";
|
|
252
|
-
sections.push(`<${key}${attr}>
|
|
253
|
-
${state[key]}
|
|
254
|
-
</${key}>`);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
if (!sections.length) {
|
|
258
|
-
sections.push("<empty/>");
|
|
259
|
-
}
|
|
260
|
-
return `<aipeek url="${state.url}">
|
|
261
|
-
|
|
262
|
-
${sections.join("\n\n")}
|
|
263
|
-
|
|
264
|
-
</aipeek>
|
|
265
|
-
|
|
266
|
-
detail: GET /__aipeek/{ui|console|network|errors|state}/{index}`;
|
|
247
|
+
return s.length > max ? `${s.slice(0, max)}\u2026` : s;
|
|
267
248
|
}
|
|
268
249
|
|
|
269
250
|
// src/detail.ts
|
|
@@ -284,20 +265,24 @@ async function detail(raw, section, index, full) {
|
|
|
284
265
|
}
|
|
285
266
|
}
|
|
286
267
|
function detailConsole(logs, index, full) {
|
|
287
|
-
const i = parseInt(index ?? "");
|
|
288
|
-
if (isNaN(i) || i < 0 || i >= logs.length)
|
|
268
|
+
const i = Number.parseInt(index ?? "");
|
|
269
|
+
if (isNaN(i) || i < 0 || i >= logs.length)
|
|
270
|
+
return null;
|
|
289
271
|
const log = logs[i];
|
|
290
272
|
if (full) {
|
|
291
273
|
const parts = [`[${log.level}] ${log.text}`];
|
|
292
|
-
if (log.timestamp)
|
|
293
|
-
|
|
274
|
+
if (log.timestamp)
|
|
275
|
+
parts.push(`timestamp: ${new Date(log.timestamp).toISOString()}`);
|
|
276
|
+
if (log.source)
|
|
277
|
+
parts.push(`source: ${log.source}`);
|
|
294
278
|
return parts.join("\n");
|
|
295
279
|
}
|
|
296
280
|
return `[${log.level}] ${truncate2(log.text, 200)}`;
|
|
297
281
|
}
|
|
298
282
|
async function detailNetwork(requests, index, full) {
|
|
299
|
-
const i = parseInt(index ?? "");
|
|
300
|
-
if (isNaN(i) || i < 0 || i >= requests.length)
|
|
283
|
+
const i = Number.parseInt(index ?? "");
|
|
284
|
+
if (isNaN(i) || i < 0 || i >= requests.length)
|
|
285
|
+
return null;
|
|
301
286
|
const req = requests[i];
|
|
302
287
|
const lines = [
|
|
303
288
|
`${req.method} ${req.url}`,
|
|
@@ -305,26 +290,30 @@ async function detailNetwork(requests, index, full) {
|
|
|
305
290
|
`duration: ${req.duration}ms`,
|
|
306
291
|
`type: ${req.resourceType}`
|
|
307
292
|
];
|
|
308
|
-
if (req.failed)
|
|
293
|
+
if (req.failed)
|
|
294
|
+
lines.push(`failed: ${req.failureText || "true"}`);
|
|
309
295
|
if (full) {
|
|
310
296
|
if (req.requestHeaders && Object.keys(req.requestHeaders).length) {
|
|
311
297
|
lines.push("request-headers:");
|
|
312
298
|
for (const [k, v] of Object.entries(req.requestHeaders)) lines.push(` ${k}: ${v}`);
|
|
313
299
|
}
|
|
314
|
-
if (req.requestBody)
|
|
300
|
+
if (req.requestBody)
|
|
301
|
+
lines.push(`request-body:
|
|
315
302
|
${req.requestBody}`);
|
|
316
303
|
if (req.responseHeaders && Object.keys(req.responseHeaders).length) {
|
|
317
304
|
lines.push("response-headers:");
|
|
318
305
|
for (const [k, v] of Object.entries(req.responseHeaders)) lines.push(` ${k}: ${v}`);
|
|
319
306
|
}
|
|
320
|
-
if (req.responseBody)
|
|
307
|
+
if (req.responseBody)
|
|
308
|
+
lines.push(`response-body:
|
|
321
309
|
${req.responseBody}`);
|
|
322
310
|
} else {
|
|
323
311
|
if (req.requestBody) {
|
|
324
312
|
lines.push(`request-body: ${byteSize(req.requestBody)}`);
|
|
325
313
|
if (req.requestSample) {
|
|
326
314
|
const ts = await quickTypeOrFallback(req.requestSample, "RequestBody");
|
|
327
|
-
if (ts)
|
|
315
|
+
if (ts)
|
|
316
|
+
lines.push(ts);
|
|
328
317
|
}
|
|
329
318
|
}
|
|
330
319
|
if (req.responseBody) {
|
|
@@ -334,7 +323,8 @@ ${req.responseBody}`);
|
|
|
334
323
|
if (req.responseSample) {
|
|
335
324
|
const ts = await quickTypeOrFallback(req.responseSample, "ResponseBody");
|
|
336
325
|
lines.push(`response-body: ${byteSize(req.responseBody)}`);
|
|
337
|
-
if (ts)
|
|
326
|
+
if (ts)
|
|
327
|
+
lines.push(ts);
|
|
338
328
|
} else {
|
|
339
329
|
lines.push(`response-body: ${byteSize(req.responseBody)} ${truncate2(req.responseBody, 100)}`);
|
|
340
330
|
}
|
|
@@ -361,28 +351,36 @@ async function quickTypeOrFallback(sample, typeName) {
|
|
|
361
351
|
}
|
|
362
352
|
}
|
|
363
353
|
function detailError(errors, index, full) {
|
|
364
|
-
const i = parseInt(index ?? "");
|
|
365
|
-
if (isNaN(i) || i < 0 || i >= errors.length)
|
|
354
|
+
const i = Number.parseInt(index ?? "");
|
|
355
|
+
if (isNaN(i) || i < 0 || i >= errors.length)
|
|
356
|
+
return null;
|
|
366
357
|
const err = errors[i];
|
|
367
358
|
if (full) {
|
|
368
359
|
const lines2 = [err.message];
|
|
369
|
-
if (err.stack)
|
|
370
|
-
|
|
371
|
-
if (err.
|
|
360
|
+
if (err.stack)
|
|
361
|
+
lines2.push(err.stack);
|
|
362
|
+
if (err.source)
|
|
363
|
+
lines2.push(`source: ${err.source}`);
|
|
364
|
+
if (err.line != null)
|
|
365
|
+
lines2.push(`location: ${err.source || ""}:${err.line}:${err.column ?? 0}`);
|
|
372
366
|
return lines2.join("\n");
|
|
373
367
|
}
|
|
374
368
|
const lines = [err.message];
|
|
375
369
|
if (err.stack) {
|
|
376
370
|
const appFrames = err.stack.split("\n").map((l) => l.trim()).filter((l) => l.startsWith("at ") && !l.includes("node_modules")).slice(0, 3);
|
|
377
|
-
if (appFrames.length)
|
|
371
|
+
if (appFrames.length)
|
|
372
|
+
lines.push(...appFrames);
|
|
378
373
|
const totalApp = err.stack.split("\n").filter((l) => l.trim().startsWith("at ") && !l.includes("node_modules")).length;
|
|
379
|
-
if (totalApp > 3)
|
|
374
|
+
if (totalApp > 3)
|
|
375
|
+
lines.push(` ... ${totalApp - 3} more app frames`);
|
|
380
376
|
}
|
|
381
|
-
if (err.line != null)
|
|
377
|
+
if (err.line != null)
|
|
378
|
+
lines.push(`location: ${err.source || ""}:${err.line}:${err.column ?? 0}`);
|
|
382
379
|
return lines.join("\n");
|
|
383
380
|
}
|
|
384
381
|
function detailState(state, name, full) {
|
|
385
|
-
if (!name || !(name in state))
|
|
382
|
+
if (!name || !(name in state))
|
|
383
|
+
return null;
|
|
386
384
|
const value = state[name];
|
|
387
385
|
if (full) {
|
|
388
386
|
try {
|
|
@@ -391,7 +389,8 @@ function detailState(state, name, full) {
|
|
|
391
389
|
return String(value);
|
|
392
390
|
}
|
|
393
391
|
}
|
|
394
|
-
if (typeof value !== "object" || value === null)
|
|
392
|
+
if (typeof value !== "object" || value === null)
|
|
393
|
+
return `${name}: ${typeof value}`;
|
|
395
394
|
const lines = [];
|
|
396
395
|
for (const [k, v] of Object.entries(value)) {
|
|
397
396
|
lines.push(`${k}: ${formatSummaryValue(v)}`);
|
|
@@ -399,15 +398,18 @@ function detailState(state, name, full) {
|
|
|
399
398
|
return lines.join("\n");
|
|
400
399
|
}
|
|
401
400
|
function formatSummaryValue(v) {
|
|
402
|
-
if (v === null || v === void 0)
|
|
401
|
+
if (v === null || v === void 0)
|
|
402
|
+
return String(v);
|
|
403
403
|
if (typeof v === "string") {
|
|
404
|
-
if (/^Array\(\d+\)$/.test(v))
|
|
405
|
-
|
|
404
|
+
if (/^Array\(\d+\)$/.test(v))
|
|
405
|
+
return v;
|
|
406
|
+
return v.length > 80 ? `${v.slice(0, 80)}\u2026` : v;
|
|
406
407
|
}
|
|
407
|
-
if (typeof v === "number" || typeof v === "boolean")
|
|
408
|
+
if (typeof v === "number" || typeof v === "boolean")
|
|
409
|
+
return String(v);
|
|
408
410
|
if (typeof v === "object") {
|
|
409
411
|
const s = JSON.stringify(v);
|
|
410
|
-
return s.length > 80 ? s.slice(0, 80)
|
|
412
|
+
return s.length > 80 ? `${s.slice(0, 80)}\u2026` : s;
|
|
411
413
|
}
|
|
412
414
|
return String(v);
|
|
413
415
|
}
|
|
@@ -419,58 +421,113 @@ function jsonSchema(sample) {
|
|
|
419
421
|
}
|
|
420
422
|
}
|
|
421
423
|
function schemaOf(v, d) {
|
|
422
|
-
if (v === null)
|
|
423
|
-
|
|
424
|
-
if (typeof v === "
|
|
425
|
-
|
|
424
|
+
if (v === null)
|
|
425
|
+
return "null";
|
|
426
|
+
if (typeof v === "string")
|
|
427
|
+
return "string";
|
|
428
|
+
if (typeof v === "number")
|
|
429
|
+
return "number";
|
|
430
|
+
if (typeof v === "boolean")
|
|
431
|
+
return "boolean";
|
|
426
432
|
if (Array.isArray(v)) {
|
|
427
|
-
if (!v.length)
|
|
428
|
-
|
|
433
|
+
if (!v.length)
|
|
434
|
+
return "[]";
|
|
435
|
+
if (d >= 3)
|
|
436
|
+
return "[\u2026]";
|
|
429
437
|
return `${schemaOf(v[0], d + 1)}[]`;
|
|
430
438
|
}
|
|
431
439
|
if (typeof v === "object") {
|
|
432
|
-
if (d >= 3)
|
|
440
|
+
if (d >= 3)
|
|
441
|
+
return "{\u2026}";
|
|
433
442
|
const entries = Object.entries(v);
|
|
434
|
-
if (!entries.length)
|
|
443
|
+
if (!entries.length)
|
|
444
|
+
return "{}";
|
|
435
445
|
const max = d === 0 ? 12 : 6;
|
|
436
446
|
const fields = entries.slice(0, max).map(([k, val]) => `${k}: ${schemaOf(val, d + 1)}`);
|
|
437
|
-
if (entries.length > max)
|
|
447
|
+
if (entries.length > max)
|
|
448
|
+
fields.push(`\u2026 ${entries.length - max} more`);
|
|
438
449
|
return `{ ${fields.join(", ")} }`;
|
|
439
450
|
}
|
|
440
451
|
return typeof v;
|
|
441
452
|
}
|
|
442
453
|
function truncate2(s, max) {
|
|
443
|
-
return s.length > max ? s.slice(0, max)
|
|
454
|
+
return s.length > max ? `${s.slice(0, max)}\u2026` : s;
|
|
444
455
|
}
|
|
445
456
|
function byteSize(s) {
|
|
446
457
|
const bytes = new TextEncoder().encode(s).length;
|
|
447
|
-
if (bytes < 1024)
|
|
448
|
-
|
|
458
|
+
if (bytes < 1024)
|
|
459
|
+
return `${bytes}B`;
|
|
460
|
+
if (bytes < 1024 * 1024)
|
|
461
|
+
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
449
462
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
450
463
|
}
|
|
451
464
|
|
|
465
|
+
// src/emit.ts
|
|
466
|
+
var SECTIONS = ["ui", "console", "network", "errors", "state"];
|
|
467
|
+
var COUNTED_SECTIONS = {
|
|
468
|
+
console: "console",
|
|
469
|
+
network: "network",
|
|
470
|
+
errors: "errors",
|
|
471
|
+
state: "state"
|
|
472
|
+
};
|
|
473
|
+
function emit(state) {
|
|
474
|
+
const sections = [];
|
|
475
|
+
for (const key of SECTIONS) {
|
|
476
|
+
if (state[key]) {
|
|
477
|
+
const countKey = COUNTED_SECTIONS[key];
|
|
478
|
+
const count = countKey ? state.counts?.[countKey] ?? 0 : 0;
|
|
479
|
+
const attr = count ? ` count="${count}"` : "";
|
|
480
|
+
sections.push(`<${key}${attr}>
|
|
481
|
+
${state[key]}
|
|
482
|
+
</${key}>`);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
if (!sections.length) {
|
|
486
|
+
sections.push("<empty/>");
|
|
487
|
+
}
|
|
488
|
+
return `<aipeek url="${state.url}">
|
|
489
|
+
|
|
490
|
+
${sections.join("\n\n")}
|
|
491
|
+
|
|
492
|
+
</aipeek>
|
|
493
|
+
|
|
494
|
+
detail: GET /__aipeek/{ui|console|network|errors|state}/{index}`;
|
|
495
|
+
}
|
|
496
|
+
|
|
452
497
|
// src/plugin.ts
|
|
453
498
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
454
499
|
var clientPath = resolve(__dirname, "client.ts");
|
|
455
|
-
|
|
500
|
+
function aipeekSnippet(port) {
|
|
501
|
+
const base = `http://localhost:${port}/__aipeek`;
|
|
502
|
+
return `
|
|
456
503
|
# aipeek \u2014 Runtime Browser Inspector
|
|
457
504
|
|
|
458
|
-
|
|
505
|
+
IMPORTANT: Before debugging any UI issue, visual bug, or runtime error, ALWAYS fetch the live app state first. Do NOT guess \u2014 look at the actual browser state.
|
|
459
506
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
507
|
+
\`\`\`bash
|
|
508
|
+
curl ${base} # full summary: UI tree + console + network + errors + state
|
|
509
|
+
curl ${base}/ui # React component tree with props and DOM semantics
|
|
510
|
+
curl ${base}/console # console logs (errors, warnings, info)
|
|
511
|
+
curl ${base}/network # fetch/XHR requests with status and timing
|
|
512
|
+
curl ${base}/errors # uncaught errors and unhandled rejections
|
|
513
|
+
curl ${base}/state # registered store snapshots
|
|
514
|
+
\`\`\`
|
|
515
|
+
|
|
516
|
+
Append \`?full\` for untruncated output. Append \`/{index}\` for a specific item's detail.
|
|
464
517
|
`;
|
|
465
|
-
|
|
518
|
+
}
|
|
519
|
+
function injectClaudeMd(root, port) {
|
|
466
520
|
const path = resolve(root, "CLAUDE.md");
|
|
521
|
+
const snippet = aipeekSnippet(port);
|
|
467
522
|
try {
|
|
468
523
|
if (existsSync(path)) {
|
|
469
524
|
const content = readFileSync(path, "utf-8");
|
|
470
|
-
if (content.includes("__aipeek"))
|
|
471
|
-
|
|
525
|
+
if (content.includes("__aipeek"))
|
|
526
|
+
return;
|
|
527
|
+
writeFileSync(path, `${content.trimEnd()}
|
|
528
|
+
${snippet}`);
|
|
472
529
|
} else {
|
|
473
|
-
writeFileSync(path,
|
|
530
|
+
writeFileSync(path, snippet.trimStart());
|
|
474
531
|
}
|
|
475
532
|
} catch {
|
|
476
533
|
}
|
|
@@ -502,7 +559,7 @@ function aipeekPlugin() {
|
|
|
502
559
|
},
|
|
503
560
|
configureServer(_server) {
|
|
504
561
|
server = _server;
|
|
505
|
-
injectClaudeMd(server.config.root);
|
|
562
|
+
injectClaudeMd(server.config.root, server.config.server.port || 5173);
|
|
506
563
|
server.hot.on("aipeek:state", (data) => {
|
|
507
564
|
if (pendingResolve) {
|
|
508
565
|
pendingResolve(data);
|
|
@@ -515,7 +572,8 @@ function aipeekPlugin() {
|
|
|
515
572
|
const full = url.searchParams.has("full");
|
|
516
573
|
try {
|
|
517
574
|
if (parts.length >= 1) {
|
|
518
|
-
if (!lastRaw)
|
|
575
|
+
if (!lastRaw)
|
|
576
|
+
lastRaw = await collectFromClient();
|
|
519
577
|
const result = await detail(lastRaw, parts[0], parts[1], full);
|
|
520
578
|
if (result !== null) {
|
|
521
579
|
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
|
|
@@ -548,7 +606,7 @@ export {
|
|
|
548
606
|
compactErrors,
|
|
549
607
|
compactState,
|
|
550
608
|
compact,
|
|
551
|
-
emit,
|
|
552
609
|
detail,
|
|
610
|
+
emit,
|
|
553
611
|
aipeekPlugin
|
|
554
612
|
};
|
|
@@ -43,19 +43,23 @@ var UI_PRIMITIVES = /* @__PURE__ */ new Set([
|
|
|
43
43
|
"Panel"
|
|
44
44
|
]);
|
|
45
45
|
function compactUI(tree) {
|
|
46
|
-
if (!tree)
|
|
46
|
+
if (!tree)
|
|
47
|
+
return "";
|
|
47
48
|
const lines = tree.split("\n");
|
|
48
49
|
const result = [];
|
|
49
50
|
const repeatTracker = /* @__PURE__ */ new Map();
|
|
50
51
|
for (let i = 0; i < lines.length; i++) {
|
|
51
52
|
const line = lines[i];
|
|
52
53
|
const trimmed = line.trimStart();
|
|
53
|
-
if (!trimmed)
|
|
54
|
+
if (!trimmed)
|
|
55
|
+
continue;
|
|
54
56
|
const indent = line.length - trimmed.length;
|
|
55
57
|
const depth = Math.floor(indent / 2);
|
|
56
|
-
if (depth > MAX_UI_DEPTH)
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
if (depth > MAX_UI_DEPTH)
|
|
59
|
+
continue;
|
|
60
|
+
const componentName = trimmed.split(/[\s[—]/)[0];
|
|
61
|
+
if (UI_PRIMITIVES.has(componentName))
|
|
62
|
+
continue;
|
|
59
63
|
const key = `${depth}:${componentName}`;
|
|
60
64
|
const tracker = repeatTracker.get(key);
|
|
61
65
|
if (tracker && i - tracker.lastIndex <= 2) {
|
|
@@ -65,7 +69,7 @@ function compactUI(tree) {
|
|
|
65
69
|
}
|
|
66
70
|
for (const [k, t] of repeatTracker) {
|
|
67
71
|
if (t.count > 1) {
|
|
68
|
-
const d = parseInt(k.split(":")[0]);
|
|
72
|
+
const d = Number.parseInt(k.split(":")[0]);
|
|
69
73
|
const name = k.split(":").slice(1).join(":");
|
|
70
74
|
result.push(`${" ".repeat(d)}${name} \xD7${t.count}`);
|
|
71
75
|
}
|
|
@@ -78,7 +82,7 @@ function compactUI(tree) {
|
|
|
78
82
|
}
|
|
79
83
|
for (const [k, t] of repeatTracker) {
|
|
80
84
|
if (t.count > 1) {
|
|
81
|
-
const d = parseInt(k.split(":")[0]);
|
|
85
|
+
const d = Number.parseInt(k.split(":")[0]);
|
|
82
86
|
const name = k.split(":").slice(1).join(":");
|
|
83
87
|
result.push(`${" ".repeat(d)}${name} \xD7${t.count}`);
|
|
84
88
|
}
|
|
@@ -98,9 +102,11 @@ var NOISE_PATTERNS = [
|
|
|
98
102
|
/\[webpack\]/i
|
|
99
103
|
];
|
|
100
104
|
function compactConsole(logs) {
|
|
101
|
-
if (!logs.length)
|
|
105
|
+
if (!logs.length)
|
|
106
|
+
return "";
|
|
102
107
|
const filtered = logs.filter((l) => !NOISE_PATTERNS.some((p) => p.test(l.text)));
|
|
103
|
-
if (!filtered.length)
|
|
108
|
+
if (!filtered.length)
|
|
109
|
+
return "";
|
|
104
110
|
const deduped = [];
|
|
105
111
|
for (const log of filtered) {
|
|
106
112
|
const last = deduped[deduped.length - 1];
|
|
@@ -125,11 +131,13 @@ function compactConsole(logs) {
|
|
|
125
131
|
return lines.join("\n");
|
|
126
132
|
}
|
|
127
133
|
function compactNetwork(requests) {
|
|
128
|
-
if (!requests.length)
|
|
134
|
+
if (!requests.length)
|
|
135
|
+
return "";
|
|
129
136
|
const relevant = requests.filter(
|
|
130
137
|
(r) => r.resourceType === "fetch" || r.resourceType === "xhr" || r.resourceType === "websocket" || isApiUrl(r.url)
|
|
131
138
|
);
|
|
132
|
-
if (!relevant.length)
|
|
139
|
+
if (!relevant.length)
|
|
140
|
+
return "";
|
|
133
141
|
const lines = [];
|
|
134
142
|
for (const req of relevant) {
|
|
135
143
|
const duration = req.duration > 0 ? ` ${formatDuration(req.duration)}` : "";
|
|
@@ -156,7 +164,7 @@ function isApiUrl(url) {
|
|
|
156
164
|
function compactUrl(url) {
|
|
157
165
|
try {
|
|
158
166
|
const u = new URL(url);
|
|
159
|
-
const path = u.pathname + (u.search ?
|
|
167
|
+
const path = u.pathname + (u.search ? `?${truncate(u.search.slice(1), 50)}` : "");
|
|
160
168
|
return path;
|
|
161
169
|
} catch (e2) {
|
|
162
170
|
return truncate(url, 80);
|
|
@@ -166,7 +174,8 @@ function formatDuration(ms) {
|
|
|
166
174
|
return ms >= 1e3 ? `${(ms / 1e3).toFixed(1)}s` : `${Math.round(ms)}ms`;
|
|
167
175
|
}
|
|
168
176
|
function compactErrors(errors) {
|
|
169
|
-
if (!errors.length)
|
|
177
|
+
if (!errors.length)
|
|
178
|
+
return "";
|
|
170
179
|
const seen = /* @__PURE__ */ new Map();
|
|
171
180
|
for (const err of errors) {
|
|
172
181
|
if (!seen.has(err.message)) {
|
|
@@ -189,7 +198,8 @@ function filterStack(stack) {
|
|
|
189
198
|
return stack.split("\n").map((l) => l.trim()).filter((l) => l.startsWith("at ")).map((l) => l.slice(3)).filter((l) => !l.includes("node_modules") && !l.includes("<anonymous>")).slice(0, 5);
|
|
190
199
|
}
|
|
191
200
|
function compactState(state) {
|
|
192
|
-
if (!state || !Object.keys(state).length)
|
|
201
|
+
if (!state || !Object.keys(state).length)
|
|
202
|
+
return "";
|
|
193
203
|
const lines = [];
|
|
194
204
|
for (const [name, value] of Object.entries(state)) {
|
|
195
205
|
lines.push(`${name}:`);
|
|
@@ -204,12 +214,15 @@ function compactState(state) {
|
|
|
204
214
|
return lines.join("\n");
|
|
205
215
|
}
|
|
206
216
|
function formatValue(v) {
|
|
207
|
-
if (v === null || v === void 0)
|
|
208
|
-
|
|
209
|
-
if (typeof v === "
|
|
217
|
+
if (v === null || v === void 0)
|
|
218
|
+
return String(v);
|
|
219
|
+
if (typeof v === "string")
|
|
220
|
+
return v;
|
|
221
|
+
if (typeof v === "number" || typeof v === "boolean")
|
|
222
|
+
return String(v);
|
|
210
223
|
if (typeof v === "object") {
|
|
211
224
|
const s = JSON.stringify(v);
|
|
212
|
-
return s.length > 120 ? s.slice(0, 120)
|
|
225
|
+
return s.length > 120 ? `${s.slice(0, 120)}\u2026` : s;
|
|
213
226
|
}
|
|
214
227
|
return String(v);
|
|
215
228
|
}
|
|
@@ -231,39 +244,7 @@ function compact(raw) {
|
|
|
231
244
|
};
|
|
232
245
|
}
|
|
233
246
|
function truncate(s, max) {
|
|
234
|
-
return s.length > max ? s.slice(0, max)
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// src/emit.ts
|
|
238
|
-
var SECTIONS = ["ui", "console", "network", "errors", "state"];
|
|
239
|
-
var COUNTED_SECTIONS = {
|
|
240
|
-
console: "console",
|
|
241
|
-
network: "network",
|
|
242
|
-
errors: "errors",
|
|
243
|
-
state: "state"
|
|
244
|
-
};
|
|
245
|
-
function emit(state) {
|
|
246
|
-
const sections = [];
|
|
247
|
-
for (const key of SECTIONS) {
|
|
248
|
-
if (state[key]) {
|
|
249
|
-
const countKey = COUNTED_SECTIONS[key];
|
|
250
|
-
const count = countKey ? _nullishCoalesce(_optionalChain([state, 'access', _ => _.counts, 'optionalAccess', _2 => _2[countKey]]), () => ( 0)) : 0;
|
|
251
|
-
const attr = count ? ` count="${count}"` : "";
|
|
252
|
-
sections.push(`<${key}${attr}>
|
|
253
|
-
${state[key]}
|
|
254
|
-
</${key}>`);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
if (!sections.length) {
|
|
258
|
-
sections.push("<empty/>");
|
|
259
|
-
}
|
|
260
|
-
return `<aipeek url="${state.url}">
|
|
261
|
-
|
|
262
|
-
${sections.join("\n\n")}
|
|
263
|
-
|
|
264
|
-
</aipeek>
|
|
265
|
-
|
|
266
|
-
detail: GET /__aipeek/{ui|console|network|errors|state}/{index}`;
|
|
247
|
+
return s.length > max ? `${s.slice(0, max)}\u2026` : s;
|
|
267
248
|
}
|
|
268
249
|
|
|
269
250
|
// src/detail.ts
|
|
@@ -284,20 +265,24 @@ async function detail(raw, section, index, full) {
|
|
|
284
265
|
}
|
|
285
266
|
}
|
|
286
267
|
function detailConsole(logs, index, full) {
|
|
287
|
-
const i = parseInt(_nullishCoalesce(index, () => ( "")));
|
|
288
|
-
if (isNaN(i) || i < 0 || i >= logs.length)
|
|
268
|
+
const i = Number.parseInt(_nullishCoalesce(index, () => ( "")));
|
|
269
|
+
if (isNaN(i) || i < 0 || i >= logs.length)
|
|
270
|
+
return null;
|
|
289
271
|
const log = logs[i];
|
|
290
272
|
if (full) {
|
|
291
273
|
const parts = [`[${log.level}] ${log.text}`];
|
|
292
|
-
if (log.timestamp)
|
|
293
|
-
|
|
274
|
+
if (log.timestamp)
|
|
275
|
+
parts.push(`timestamp: ${new Date(log.timestamp).toISOString()}`);
|
|
276
|
+
if (log.source)
|
|
277
|
+
parts.push(`source: ${log.source}`);
|
|
294
278
|
return parts.join("\n");
|
|
295
279
|
}
|
|
296
280
|
return `[${log.level}] ${truncate2(log.text, 200)}`;
|
|
297
281
|
}
|
|
298
282
|
async function detailNetwork(requests, index, full) {
|
|
299
|
-
const i = parseInt(_nullishCoalesce(index, () => ( "")));
|
|
300
|
-
if (isNaN(i) || i < 0 || i >= requests.length)
|
|
283
|
+
const i = Number.parseInt(_nullishCoalesce(index, () => ( "")));
|
|
284
|
+
if (isNaN(i) || i < 0 || i >= requests.length)
|
|
285
|
+
return null;
|
|
301
286
|
const req = requests[i];
|
|
302
287
|
const lines = [
|
|
303
288
|
`${req.method} ${req.url}`,
|
|
@@ -305,26 +290,30 @@ async function detailNetwork(requests, index, full) {
|
|
|
305
290
|
`duration: ${req.duration}ms`,
|
|
306
291
|
`type: ${req.resourceType}`
|
|
307
292
|
];
|
|
308
|
-
if (req.failed)
|
|
293
|
+
if (req.failed)
|
|
294
|
+
lines.push(`failed: ${req.failureText || "true"}`);
|
|
309
295
|
if (full) {
|
|
310
296
|
if (req.requestHeaders && Object.keys(req.requestHeaders).length) {
|
|
311
297
|
lines.push("request-headers:");
|
|
312
298
|
for (const [k, v] of Object.entries(req.requestHeaders)) lines.push(` ${k}: ${v}`);
|
|
313
299
|
}
|
|
314
|
-
if (req.requestBody)
|
|
300
|
+
if (req.requestBody)
|
|
301
|
+
lines.push(`request-body:
|
|
315
302
|
${req.requestBody}`);
|
|
316
303
|
if (req.responseHeaders && Object.keys(req.responseHeaders).length) {
|
|
317
304
|
lines.push("response-headers:");
|
|
318
305
|
for (const [k, v] of Object.entries(req.responseHeaders)) lines.push(` ${k}: ${v}`);
|
|
319
306
|
}
|
|
320
|
-
if (req.responseBody)
|
|
307
|
+
if (req.responseBody)
|
|
308
|
+
lines.push(`response-body:
|
|
321
309
|
${req.responseBody}`);
|
|
322
310
|
} else {
|
|
323
311
|
if (req.requestBody) {
|
|
324
312
|
lines.push(`request-body: ${byteSize(req.requestBody)}`);
|
|
325
313
|
if (req.requestSample) {
|
|
326
314
|
const ts = await quickTypeOrFallback(req.requestSample, "RequestBody");
|
|
327
|
-
if (ts)
|
|
315
|
+
if (ts)
|
|
316
|
+
lines.push(ts);
|
|
328
317
|
}
|
|
329
318
|
}
|
|
330
319
|
if (req.responseBody) {
|
|
@@ -334,7 +323,8 @@ ${req.responseBody}`);
|
|
|
334
323
|
if (req.responseSample) {
|
|
335
324
|
const ts = await quickTypeOrFallback(req.responseSample, "ResponseBody");
|
|
336
325
|
lines.push(`response-body: ${byteSize(req.responseBody)}`);
|
|
337
|
-
if (ts)
|
|
326
|
+
if (ts)
|
|
327
|
+
lines.push(ts);
|
|
338
328
|
} else {
|
|
339
329
|
lines.push(`response-body: ${byteSize(req.responseBody)} ${truncate2(req.responseBody, 100)}`);
|
|
340
330
|
}
|
|
@@ -361,28 +351,36 @@ async function quickTypeOrFallback(sample, typeName) {
|
|
|
361
351
|
}
|
|
362
352
|
}
|
|
363
353
|
function detailError(errors, index, full) {
|
|
364
|
-
const i = parseInt(_nullishCoalesce(index, () => ( "")));
|
|
365
|
-
if (isNaN(i) || i < 0 || i >= errors.length)
|
|
354
|
+
const i = Number.parseInt(_nullishCoalesce(index, () => ( "")));
|
|
355
|
+
if (isNaN(i) || i < 0 || i >= errors.length)
|
|
356
|
+
return null;
|
|
366
357
|
const err = errors[i];
|
|
367
358
|
if (full) {
|
|
368
359
|
const lines2 = [err.message];
|
|
369
|
-
if (err.stack)
|
|
370
|
-
|
|
371
|
-
if (err.
|
|
360
|
+
if (err.stack)
|
|
361
|
+
lines2.push(err.stack);
|
|
362
|
+
if (err.source)
|
|
363
|
+
lines2.push(`source: ${err.source}`);
|
|
364
|
+
if (err.line != null)
|
|
365
|
+
lines2.push(`location: ${err.source || ""}:${err.line}:${_nullishCoalesce(err.column, () => ( 0))}`);
|
|
372
366
|
return lines2.join("\n");
|
|
373
367
|
}
|
|
374
368
|
const lines = [err.message];
|
|
375
369
|
if (err.stack) {
|
|
376
370
|
const appFrames = err.stack.split("\n").map((l) => l.trim()).filter((l) => l.startsWith("at ") && !l.includes("node_modules")).slice(0, 3);
|
|
377
|
-
if (appFrames.length)
|
|
371
|
+
if (appFrames.length)
|
|
372
|
+
lines.push(...appFrames);
|
|
378
373
|
const totalApp = err.stack.split("\n").filter((l) => l.trim().startsWith("at ") && !l.includes("node_modules")).length;
|
|
379
|
-
if (totalApp > 3)
|
|
374
|
+
if (totalApp > 3)
|
|
375
|
+
lines.push(` ... ${totalApp - 3} more app frames`);
|
|
380
376
|
}
|
|
381
|
-
if (err.line != null)
|
|
377
|
+
if (err.line != null)
|
|
378
|
+
lines.push(`location: ${err.source || ""}:${err.line}:${_nullishCoalesce(err.column, () => ( 0))}`);
|
|
382
379
|
return lines.join("\n");
|
|
383
380
|
}
|
|
384
381
|
function detailState(state, name, full) {
|
|
385
|
-
if (!name || !(name in state))
|
|
382
|
+
if (!name || !(name in state))
|
|
383
|
+
return null;
|
|
386
384
|
const value = state[name];
|
|
387
385
|
if (full) {
|
|
388
386
|
try {
|
|
@@ -391,7 +389,8 @@ function detailState(state, name, full) {
|
|
|
391
389
|
return String(value);
|
|
392
390
|
}
|
|
393
391
|
}
|
|
394
|
-
if (typeof value !== "object" || value === null)
|
|
392
|
+
if (typeof value !== "object" || value === null)
|
|
393
|
+
return `${name}: ${typeof value}`;
|
|
395
394
|
const lines = [];
|
|
396
395
|
for (const [k, v] of Object.entries(value)) {
|
|
397
396
|
lines.push(`${k}: ${formatSummaryValue(v)}`);
|
|
@@ -399,15 +398,18 @@ function detailState(state, name, full) {
|
|
|
399
398
|
return lines.join("\n");
|
|
400
399
|
}
|
|
401
400
|
function formatSummaryValue(v) {
|
|
402
|
-
if (v === null || v === void 0)
|
|
401
|
+
if (v === null || v === void 0)
|
|
402
|
+
return String(v);
|
|
403
403
|
if (typeof v === "string") {
|
|
404
|
-
if (/^Array\(\d+\)$/.test(v))
|
|
405
|
-
|
|
404
|
+
if (/^Array\(\d+\)$/.test(v))
|
|
405
|
+
return v;
|
|
406
|
+
return v.length > 80 ? `${v.slice(0, 80)}\u2026` : v;
|
|
406
407
|
}
|
|
407
|
-
if (typeof v === "number" || typeof v === "boolean")
|
|
408
|
+
if (typeof v === "number" || typeof v === "boolean")
|
|
409
|
+
return String(v);
|
|
408
410
|
if (typeof v === "object") {
|
|
409
411
|
const s = JSON.stringify(v);
|
|
410
|
-
return s.length > 80 ? s.slice(0, 80)
|
|
412
|
+
return s.length > 80 ? `${s.slice(0, 80)}\u2026` : s;
|
|
411
413
|
}
|
|
412
414
|
return String(v);
|
|
413
415
|
}
|
|
@@ -419,58 +421,113 @@ function jsonSchema(sample) {
|
|
|
419
421
|
}
|
|
420
422
|
}
|
|
421
423
|
function schemaOf(v, d) {
|
|
422
|
-
if (v === null)
|
|
423
|
-
|
|
424
|
-
if (typeof v === "
|
|
425
|
-
|
|
424
|
+
if (v === null)
|
|
425
|
+
return "null";
|
|
426
|
+
if (typeof v === "string")
|
|
427
|
+
return "string";
|
|
428
|
+
if (typeof v === "number")
|
|
429
|
+
return "number";
|
|
430
|
+
if (typeof v === "boolean")
|
|
431
|
+
return "boolean";
|
|
426
432
|
if (Array.isArray(v)) {
|
|
427
|
-
if (!v.length)
|
|
428
|
-
|
|
433
|
+
if (!v.length)
|
|
434
|
+
return "[]";
|
|
435
|
+
if (d >= 3)
|
|
436
|
+
return "[\u2026]";
|
|
429
437
|
return `${schemaOf(v[0], d + 1)}[]`;
|
|
430
438
|
}
|
|
431
439
|
if (typeof v === "object") {
|
|
432
|
-
if (d >= 3)
|
|
440
|
+
if (d >= 3)
|
|
441
|
+
return "{\u2026}";
|
|
433
442
|
const entries = Object.entries(v);
|
|
434
|
-
if (!entries.length)
|
|
443
|
+
if (!entries.length)
|
|
444
|
+
return "{}";
|
|
435
445
|
const max = d === 0 ? 12 : 6;
|
|
436
446
|
const fields = entries.slice(0, max).map(([k, val]) => `${k}: ${schemaOf(val, d + 1)}`);
|
|
437
|
-
if (entries.length > max)
|
|
447
|
+
if (entries.length > max)
|
|
448
|
+
fields.push(`\u2026 ${entries.length - max} more`);
|
|
438
449
|
return `{ ${fields.join(", ")} }`;
|
|
439
450
|
}
|
|
440
451
|
return typeof v;
|
|
441
452
|
}
|
|
442
453
|
function truncate2(s, max) {
|
|
443
|
-
return s.length > max ? s.slice(0, max)
|
|
454
|
+
return s.length > max ? `${s.slice(0, max)}\u2026` : s;
|
|
444
455
|
}
|
|
445
456
|
function byteSize(s) {
|
|
446
457
|
const bytes = new TextEncoder().encode(s).length;
|
|
447
|
-
if (bytes < 1024)
|
|
448
|
-
|
|
458
|
+
if (bytes < 1024)
|
|
459
|
+
return `${bytes}B`;
|
|
460
|
+
if (bytes < 1024 * 1024)
|
|
461
|
+
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
449
462
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
450
463
|
}
|
|
451
464
|
|
|
465
|
+
// src/emit.ts
|
|
466
|
+
var SECTIONS = ["ui", "console", "network", "errors", "state"];
|
|
467
|
+
var COUNTED_SECTIONS = {
|
|
468
|
+
console: "console",
|
|
469
|
+
network: "network",
|
|
470
|
+
errors: "errors",
|
|
471
|
+
state: "state"
|
|
472
|
+
};
|
|
473
|
+
function emit(state) {
|
|
474
|
+
const sections = [];
|
|
475
|
+
for (const key of SECTIONS) {
|
|
476
|
+
if (state[key]) {
|
|
477
|
+
const countKey = COUNTED_SECTIONS[key];
|
|
478
|
+
const count = countKey ? _nullishCoalesce(_optionalChain([state, 'access', _ => _.counts, 'optionalAccess', _2 => _2[countKey]]), () => ( 0)) : 0;
|
|
479
|
+
const attr = count ? ` count="${count}"` : "";
|
|
480
|
+
sections.push(`<${key}${attr}>
|
|
481
|
+
${state[key]}
|
|
482
|
+
</${key}>`);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
if (!sections.length) {
|
|
486
|
+
sections.push("<empty/>");
|
|
487
|
+
}
|
|
488
|
+
return `<aipeek url="${state.url}">
|
|
489
|
+
|
|
490
|
+
${sections.join("\n\n")}
|
|
491
|
+
|
|
492
|
+
</aipeek>
|
|
493
|
+
|
|
494
|
+
detail: GET /__aipeek/{ui|console|network|errors|state}/{index}`;
|
|
495
|
+
}
|
|
496
|
+
|
|
452
497
|
// src/plugin.ts
|
|
453
498
|
var __dirname = _path.dirname.call(void 0, _url.fileURLToPath.call(void 0, import.meta.url));
|
|
454
499
|
var clientPath = _path.resolve.call(void 0, __dirname, "client.ts");
|
|
455
|
-
|
|
500
|
+
function aipeekSnippet(port) {
|
|
501
|
+
const base = `http://localhost:${port}/__aipeek`;
|
|
502
|
+
return `
|
|
456
503
|
# aipeek \u2014 Runtime Browser Inspector
|
|
457
504
|
|
|
458
|
-
|
|
505
|
+
IMPORTANT: Before debugging any UI issue, visual bug, or runtime error, ALWAYS fetch the live app state first. Do NOT guess \u2014 look at the actual browser state.
|
|
459
506
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
507
|
+
\`\`\`bash
|
|
508
|
+
curl ${base} # full summary: UI tree + console + network + errors + state
|
|
509
|
+
curl ${base}/ui # React component tree with props and DOM semantics
|
|
510
|
+
curl ${base}/console # console logs (errors, warnings, info)
|
|
511
|
+
curl ${base}/network # fetch/XHR requests with status and timing
|
|
512
|
+
curl ${base}/errors # uncaught errors and unhandled rejections
|
|
513
|
+
curl ${base}/state # registered store snapshots
|
|
514
|
+
\`\`\`
|
|
515
|
+
|
|
516
|
+
Append \`?full\` for untruncated output. Append \`/{index}\` for a specific item's detail.
|
|
464
517
|
`;
|
|
465
|
-
|
|
518
|
+
}
|
|
519
|
+
function injectClaudeMd(root, port) {
|
|
466
520
|
const path = _path.resolve.call(void 0, root, "CLAUDE.md");
|
|
521
|
+
const snippet = aipeekSnippet(port);
|
|
467
522
|
try {
|
|
468
523
|
if (_fs.existsSync.call(void 0, path)) {
|
|
469
524
|
const content = _fs.readFileSync.call(void 0, path, "utf-8");
|
|
470
|
-
if (content.includes("__aipeek"))
|
|
471
|
-
|
|
525
|
+
if (content.includes("__aipeek"))
|
|
526
|
+
return;
|
|
527
|
+
_fs.writeFileSync.call(void 0, path, `${content.trimEnd()}
|
|
528
|
+
${snippet}`);
|
|
472
529
|
} else {
|
|
473
|
-
_fs.writeFileSync.call(void 0, path,
|
|
530
|
+
_fs.writeFileSync.call(void 0, path, snippet.trimStart());
|
|
474
531
|
}
|
|
475
532
|
} catch (e6) {
|
|
476
533
|
}
|
|
@@ -502,7 +559,7 @@ function aipeekPlugin() {
|
|
|
502
559
|
},
|
|
503
560
|
configureServer(_server) {
|
|
504
561
|
server = _server;
|
|
505
|
-
injectClaudeMd(server.config.root);
|
|
562
|
+
injectClaudeMd(server.config.root, server.config.server.port || 5173);
|
|
506
563
|
server.hot.on("aipeek:state", (data) => {
|
|
507
564
|
if (pendingResolve) {
|
|
508
565
|
pendingResolve(data);
|
|
@@ -515,7 +572,8 @@ function aipeekPlugin() {
|
|
|
515
572
|
const full = url.searchParams.has("full");
|
|
516
573
|
try {
|
|
517
574
|
if (parts.length >= 1) {
|
|
518
|
-
if (!lastRaw)
|
|
575
|
+
if (!lastRaw)
|
|
576
|
+
lastRaw = await collectFromClient();
|
|
519
577
|
const result = await detail(lastRaw, parts[0], parts[1], full);
|
|
520
578
|
if (result !== null) {
|
|
521
579
|
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
|
|
@@ -551,4 +609,4 @@ function aipeekPlugin() {
|
|
|
551
609
|
|
|
552
610
|
|
|
553
611
|
|
|
554
|
-
exports.compactUI = compactUI; exports.compactConsole = compactConsole; exports.compactNetwork = compactNetwork; exports.compactErrors = compactErrors; exports.compactState = compactState; exports.compact = compact; exports.
|
|
612
|
+
exports.compactUI = compactUI; exports.compactConsole = compactConsole; exports.compactNetwork = compactNetwork; exports.compactErrors = compactErrors; exports.compactState = compactState; exports.compact = compact; exports.detail = detail; exports.emit = emit; exports.aipeekPlugin = aipeekPlugin;
|
package/dist/index.cjs
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
var
|
|
11
|
+
var _chunkKW232XW7cjs = require('./chunk-KW232XW7.cjs');
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
|
|
@@ -19,4 +19,4 @@ var _chunkQXCVA2LUcjs = require('./chunk-QXCVA2LU.cjs');
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
exports.aipeekPlugin =
|
|
22
|
+
exports.aipeekPlugin = _chunkKW232XW7cjs.aipeekPlugin; exports.compact = _chunkKW232XW7cjs.compact; exports.compactConsole = _chunkKW232XW7cjs.compactConsole; exports.compactErrors = _chunkKW232XW7cjs.compactErrors; exports.compactNetwork = _chunkKW232XW7cjs.compactNetwork; exports.compactState = _chunkKW232XW7cjs.compactState; exports.compactUI = _chunkKW232XW7cjs.compactUI; exports.detail = _chunkKW232XW7cjs.detail; exports.emit = _chunkKW232XW7cjs.emit;
|
package/dist/index.d.cts
CHANGED
|
@@ -60,10 +60,10 @@ declare function compactErrors(errors: ErrorEntry[]): string;
|
|
|
60
60
|
declare function compactState(state: Record<string, unknown>): string;
|
|
61
61
|
declare function compact(raw: RawState): CompactState;
|
|
62
62
|
|
|
63
|
-
declare function emit(state: CompactState): string;
|
|
64
|
-
|
|
65
63
|
declare function detail(raw: RawState, section: string, index: string | undefined, full: boolean): Promise<string | null>;
|
|
66
64
|
|
|
65
|
+
declare function emit(state: CompactState): string;
|
|
66
|
+
|
|
67
67
|
declare function aipeekPlugin(): Plugin;
|
|
68
68
|
|
|
69
69
|
export { type CompactState, type ErrorEntry, type LogEntry, type NetworkRequest, type RawState, aipeekPlugin, compact, compactConsole, compactErrors, compactNetwork, compactState, compactUI, detail, emit };
|
package/dist/index.d.ts
CHANGED
|
@@ -60,10 +60,10 @@ declare function compactErrors(errors: ErrorEntry[]): string;
|
|
|
60
60
|
declare function compactState(state: Record<string, unknown>): string;
|
|
61
61
|
declare function compact(raw: RawState): CompactState;
|
|
62
62
|
|
|
63
|
-
declare function emit(state: CompactState): string;
|
|
64
|
-
|
|
65
63
|
declare function detail(raw: RawState, section: string, index: string | undefined, full: boolean): Promise<string | null>;
|
|
66
64
|
|
|
65
|
+
declare function emit(state: CompactState): string;
|
|
66
|
+
|
|
67
67
|
declare function aipeekPlugin(): Plugin;
|
|
68
68
|
|
|
69
69
|
export { type CompactState, type ErrorEntry, type LogEntry, type NetworkRequest, type RawState, aipeekPlugin, compact, compactConsole, compactErrors, compactNetwork, compactState, compactUI, detail, emit };
|
package/dist/index.js
CHANGED
package/dist/plugin.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkKW232XW7cjs = require('./chunk-KW232XW7.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
exports.aipeekPlugin =
|
|
6
|
+
exports.aipeekPlugin = _chunkKW232XW7cjs.aipeekPlugin;
|
package/dist/plugin.js
CHANGED