aipeek 0.2.4 → 0.2.6

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.
@@ -71,13 +71,54 @@ function check(raw) {
71
71
  function truncate(s, max) {
72
72
  return s.length > max ? `${s.slice(0, max)}\u2026` : s;
73
73
  }
74
+ function formatValue(v, seen = /* @__PURE__ */ new Set()) {
75
+ if (v === null || v === void 0)
76
+ return String(v);
77
+ const t = typeof v;
78
+ if (t === "string")
79
+ return v;
80
+ if (t === "number" || t === "boolean" || t === "bigint")
81
+ return String(v);
82
+ if (t === "symbol")
83
+ return v.toString();
84
+ if (t === "function")
85
+ return `[Function: ${v.name || "anonymous"}]`;
86
+ const obj = v;
87
+ if (seen.has(obj))
88
+ return "[Circular]";
89
+ if (v instanceof Error)
90
+ return v.stack || `${v.name}: ${v.message}`;
91
+ seen.add(obj);
92
+ if (v instanceof Map) {
93
+ const items = [...v.entries()].slice(0, 15).map(([k, val]) => `${formatValue(k, seen)} => ${formatValue(val, seen)}`);
94
+ return `Map(${v.size}) {${items.join(", ")}${v.size > 15 ? ", \u2026" : ""}}`;
95
+ }
96
+ if (v instanceof Set) {
97
+ const items = [...v.values()].slice(0, 15).map((val) => formatValue(val, seen));
98
+ return `Set(${v.size}) {${items.join(", ")}${v.size > 15 ? ", \u2026" : ""}}`;
99
+ }
100
+ if (Array.isArray(v)) {
101
+ const items = v.slice(0, 30).map((val) => formatValue(val, seen));
102
+ return `[${items.join(", ")}${v.length > 30 ? ", \u2026" : ""}]`;
103
+ }
104
+ try {
105
+ return JSON.stringify(v);
106
+ } catch (e2) {
107
+ const entries = Object.entries(v).slice(0, 15);
108
+ const parts = entries.map(([k, val]) => `${k}: ${formatValue(val, seen)}`);
109
+ return `{${parts.join(", ")}}`;
110
+ }
111
+ }
112
+ function appStackFrames(stack, max) {
113
+ return stack.split("\n").map((l) => l.trim()).filter((l) => l.startsWith("at ") && !l.includes("node_modules") && !l.includes("<anonymous>")).slice(0, max);
114
+ }
74
115
  function compactUrl(url, search) {
75
116
  try {
76
117
  const u = new URL(url);
77
118
  if (search && u.search)
78
119
  return `${u.pathname}?${truncate(u.search.slice(1), search)}`;
79
120
  return u.pathname;
80
- } catch (e2) {
121
+ } catch (e3) {
81
122
  return truncate(url, 80);
82
123
  }
83
124
  }
@@ -249,7 +290,7 @@ function isApiUrl(url) {
249
290
  try {
250
291
  const u = new URL(url);
251
292
  return u.pathname.startsWith("/api") || u.pathname.includes("/graphql");
252
- } catch (e3) {
293
+ } catch (e4) {
253
294
  return false;
254
295
  }
255
296
  }
@@ -287,17 +328,12 @@ function compactErrors(errors) {
287
328
  for (const err of seen.values()) {
288
329
  lines.push(err.message);
289
330
  if (err.stack) {
290
- const frames = filterStack(err.stack);
291
- for (const frame of frames) {
292
- lines.push(` at ${frame}`);
293
- }
331
+ for (const frame of appStackFrames(err.stack, 5))
332
+ lines.push(` ${frame}`);
294
333
  }
295
334
  }
296
335
  return lines.join("\n");
297
336
  }
298
- function filterStack(stack) {
299
- 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);
300
- }
301
337
  function compactState(state) {
302
338
  if (!state || !Object.keys(state).length)
303
339
  return "";
@@ -306,7 +342,7 @@ function compactState(state) {
306
342
  lines.push(`${name}:`);
307
343
  if (typeof value === "object" && value !== null) {
308
344
  for (const [k, v] of Object.entries(value)) {
309
- lines.push(` ${k}: ${formatValue(v)}`);
345
+ lines.push(` ${k}: ${truncate(formatValue(v), 120)}`);
310
346
  }
311
347
  } else {
312
348
  lines.push(` ${String(value)}`);
@@ -314,19 +350,6 @@ function compactState(state) {
314
350
  }
315
351
  return lines.join("\n");
316
352
  }
317
- function formatValue(v) {
318
- if (v === null || v === void 0)
319
- return String(v);
320
- if (typeof v === "string")
321
- return v;
322
- if (typeof v === "number" || typeof v === "boolean")
323
- return String(v);
324
- if (typeof v === "object") {
325
- const s = JSON.stringify(v);
326
- return s.length > 120 ? `${s.slice(0, 120)}\u2026` : s;
327
- }
328
- return String(v);
329
- }
330
353
  function compact(raw) {
331
354
  return {
332
355
  url: raw.url,
@@ -463,12 +486,10 @@ function detailError(errors, index, full) {
463
486
  }
464
487
  const lines = [err.message];
465
488
  if (err.stack) {
466
- const appFrames = err.stack.split("\n").map((l) => l.trim()).filter((l) => l.startsWith("at ") && !l.includes("node_modules")).slice(0, 3);
467
- if (appFrames.length)
468
- lines.push(...appFrames);
469
- const totalApp = err.stack.split("\n").filter((l) => l.trim().startsWith("at ") && !l.includes("node_modules")).length;
470
- if (totalApp > 3)
471
- lines.push(` ... ${totalApp - 3} more app frames`);
489
+ const all = appStackFrames(err.stack, Infinity);
490
+ lines.push(...all.slice(0, 3));
491
+ if (all.length > 3)
492
+ lines.push(` ... ${all.length - 3} more app frames`);
472
493
  }
473
494
  if (err.line != null)
474
495
  lines.push(`location: ${err.source || ""}:${err.line}:${_nullishCoalesce(err.column, () => ( 0))}`);
@@ -486,9 +507,9 @@ function detailState(state, name, full) {
486
507
  const value = state[name];
487
508
  if (full) {
488
509
  try {
489
- return JSON.stringify(value, null, 2);
490
- } catch (e4) {
491
- return String(value);
510
+ return _nullishCoalesce(JSON.stringify(value, null, 2), () => ( formatValue(value)));
511
+ } catch (e5) {
512
+ return formatValue(value);
492
513
  }
493
514
  }
494
515
  if (typeof value !== "object" || value === null)
@@ -506,25 +527,14 @@ function isArraySentinel(v) {
506
527
  return digits.length > 0 && [...digits].every((c) => c >= "0" && c <= "9");
507
528
  }
508
529
  function formatSummaryValue(v) {
509
- if (v === null || v === void 0)
510
- return String(v);
511
- if (typeof v === "string") {
512
- if (isArraySentinel(v))
513
- return v;
514
- return v.length > 80 ? `${v.slice(0, 80)}\u2026` : v;
515
- }
516
- if (typeof v === "number" || typeof v === "boolean")
517
- return String(v);
518
- if (typeof v === "object") {
519
- const s = JSON.stringify(v);
520
- return s.length > 80 ? `${s.slice(0, 80)}\u2026` : s;
521
- }
522
- return String(v);
530
+ if (typeof v === "string" && isArraySentinel(v))
531
+ return v;
532
+ return truncate(formatValue(v), 80);
523
533
  }
524
534
  function jsonSchema(sample) {
525
535
  try {
526
536
  return schemaOf(JSON.parse(sample), 0);
527
- } catch (e5) {
537
+ } catch (e6) {
528
538
  return null;
529
539
  }
530
540
  }
@@ -753,6 +763,10 @@ function readBody(req) {
753
763
  req.on("end", () => resolve2(s));
754
764
  });
755
765
  }
766
+ function send(res, status, body) {
767
+ res.writeHead(status, { "Content-Type": "text/plain; charset=utf-8" });
768
+ res.end(body);
769
+ }
756
770
  var __dirname = _path.dirname.call(void 0, _url.fileURLToPath.call(void 0, _chunkZ2Y65YOYcjs.importMetaUrl));
757
771
  var clientDir = _fs.existsSync.call(void 0, _path.resolve.call(void 0, __dirname, "../client")) ? _path.resolve.call(void 0, __dirname, "../client") : _path.resolve.call(void 0, __dirname, "../src/client");
758
772
  var clientPath = _path.resolve.call(void 0, clientDir, "client.ts");
@@ -830,62 +844,30 @@ JS in the page and returns the result \u2014 for anything the typed endpoints ca
830
844
  aipeek auto-detects errors after HMR and prints them to the terminal \u2014 watch for \`[aipeek]\` messages.
831
845
  `;
832
846
  }
833
- function norm(line) {
834
- const t = line.trim();
835
- const i = t.indexOf("localhost:");
836
- if (i === -1)
837
- return t;
838
- let j = i + "localhost:".length;
839
- while (j < t.length && t[j] >= "0" && t[j] <= "9") j++;
840
- return `${t.slice(0, i)}localhost:PORT${t.slice(j)}`;
841
- }
842
- function stripBlocks(content, snippet) {
843
- const known = new Set(snippet.split("\n").map(norm).filter((l) => l.length > 3));
844
- const lines = content.split("\n");
845
- const keep = [];
846
- let inside = false;
847
- let buf = [];
848
- let hits = 0;
849
- const flush = () => {
850
- if (buf.length && hits / buf.length <= 0.5)
851
- keep.push(...buf);
852
- buf = [];
853
- hits = 0;
854
- inside = false;
855
- };
856
- for (const line of lines) {
857
- const isKnown = known.has(norm(line));
858
- if (!inside) {
859
- if (isKnown) {
860
- inside = true;
861
- buf = [line];
862
- hits = 1;
863
- } else {
864
- keep.push(line);
865
- }
866
- continue;
867
- }
868
- buf.push(line);
869
- if (isKnown)
870
- hits++;
871
- else if (buf.slice(-3).every((l) => !known.has(norm(l))))
872
- flush();
873
- }
874
- flush();
875
- return keep.join("\n");
876
- }
847
+ var START_TAG = "<!-- AIPEEK:START -->";
848
+ var END_TAG = "<!-- AIPEEK:END -->";
877
849
  function injectClaudeMd(root, port) {
878
850
  const path = _path.resolve.call(void 0, root, "CLAUDE.md");
879
- const snippet = aipeekSnippet(port);
851
+ const block = `${START_TAG}
852
+ ${aipeekSnippet(port).trim()}
853
+ ${END_TAG}
854
+ `;
880
855
  try {
881
856
  if (!_fs.existsSync.call(void 0, path)) {
882
- _fs.writeFileSync.call(void 0, path, snippet.trimStart());
857
+ _fs.writeFileSync.call(void 0, path, block);
883
858
  return;
884
859
  }
885
- const stripped = stripBlocks(_fs.readFileSync.call(void 0, path, "utf-8"), snippet).trimEnd();
886
- _fs.writeFileSync.call(void 0, path, `${stripped}
887
- ${snippet}`);
888
- } catch (e6) {
860
+ const content = _fs.readFileSync.call(void 0, path, "utf-8");
861
+ const si = content.indexOf(START_TAG);
862
+ const ei = content.indexOf(END_TAG);
863
+ if (si !== -1 && ei !== -1) {
864
+ _fs.writeFileSync.call(void 0, path, content.slice(0, si) + block.trimEnd() + content.slice(ei + END_TAG.length));
865
+ return;
866
+ }
867
+ const sep = content.endsWith("\n") ? "" : "\n";
868
+ _fs.writeFileSync.call(void 0, path, `${content}${sep}
869
+ ${block}`);
870
+ } catch (e7) {
889
871
  }
890
872
  }
891
873
  function aipeekPlugin() {
@@ -1033,7 +1015,7 @@ function aipeekPlugin() {
1033
1015
  if (msg)
1034
1016
  server.config.logger.warn(msg);
1035
1017
  }
1036
- } catch (e7) {
1018
+ } catch (e8) {
1037
1019
  }
1038
1020
  }, 500);
1039
1021
  });
@@ -1047,13 +1029,11 @@ function aipeekPlugin() {
1047
1029
  if (!code && req.method === "POST")
1048
1030
  code = await readBody(req);
1049
1031
  if (!code) {
1050
- res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
1051
- res.end("eval needs ?code= or a POST body");
1032
+ send(res, 400, "eval needs ?code= or a POST body");
1052
1033
  return;
1053
1034
  }
1054
1035
  const r = await evalInClient(code);
1055
- res.writeHead(r.ok ? 200 : 422, { "Content-Type": "text/plain; charset=utf-8" });
1056
- res.end(r.ok ? _nullishCoalesce(r.value, () => ( "undefined")) : `error: ${r.error}`);
1036
+ send(res, r.ok ? 200 : 422, r.ok ? _nullishCoalesce(r.value, () => ( "undefined")) : `error: ${r.error}`);
1057
1037
  return;
1058
1038
  }
1059
1039
  if (parts[0] === "dom") {
@@ -1061,14 +1041,12 @@ function aipeekPlugin() {
1061
1041
  url.searchParams.get("scope") || void 0,
1062
1042
  url.searchParams.get("sel") || void 0
1063
1043
  );
1064
- res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
1065
- res.end(dom || "(empty)");
1044
+ send(res, 200, dom || "(empty)");
1066
1045
  return;
1067
1046
  }
1068
1047
  if (parts[0] === "screen") {
1069
1048
  const screen = await collectScreenFromClient();
1070
- res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
1071
- res.end(screen || "(empty)");
1049
+ send(res, 200, screen || "(empty)");
1072
1050
  return;
1073
1051
  }
1074
1052
  if (parts[0] === "chain") {
@@ -1079,8 +1057,7 @@ function aipeekPlugin() {
1079
1057
  if (!Array.isArray(steps))
1080
1058
  throw new Error("body must be a JSON array");
1081
1059
  } catch (e) {
1082
- res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
1083
- res.end(`invalid chain body: ${e instanceof Error ? e.message : String(e)}`);
1060
+ send(res, 400, `invalid chain body: ${e instanceof Error ? e.message : String(e)}`);
1084
1061
  return;
1085
1062
  }
1086
1063
  lastRaw = null;
@@ -1106,8 +1083,7 @@ function aipeekPlugin() {
1106
1083
  break;
1107
1084
  }
1108
1085
  }
1109
- res.writeHead(allOk ? 200 : 422, { "Content-Type": "text/plain; charset=utf-8" });
1110
- res.end(lastUi ? `${lines.join("\n")}
1086
+ send(res, allOk ? 200 : 422, lastUi ? `${lines.join("\n")}
1111
1087
 
1112
1088
  --- ui after ---
1113
1089
  ${lastUi}` : lines.join("\n"));
@@ -1125,8 +1101,7 @@ ${lastUi}` : lines.join("\n"));
1125
1101
  };
1126
1102
  const check2 = resolveAction(parts[0], args);
1127
1103
  if (!check2.valid) {
1128
- res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
1129
- res.end(check2.error);
1104
+ send(res, 400, _nullishCoalesce(check2.error, () => ( "invalid action")));
1130
1105
  return;
1131
1106
  }
1132
1107
  const result = await sendAction(parts[0], args);
@@ -1137,15 +1112,13 @@ ${lastUi}` : lines.join("\n"));
1137
1112
  const name = q.get("out") || `shot-${result.dataUrl.length}.png`;
1138
1113
  const file = _path.resolve.call(void 0, dir, name);
1139
1114
  _fs.writeFileSync.call(void 0, file, _buffer.Buffer.from(result.dataUrl.split(",")[1], "base64"));
1140
- res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
1141
- res.end(`saved: ${file}`);
1115
+ send(res, 200, `saved: ${file}`);
1142
1116
  return;
1143
1117
  }
1144
- res.writeHead(result.ok ? 200 : 422, { "Content-Type": "text/plain; charset=utf-8" });
1145
1118
  const head = result.ok ? result.detail || "ok" : `${result.error}${result.detail ? `
1146
1119
 
1147
1120
  clickable: ${result.detail}` : ""}`;
1148
- res.end(result.ui ? `${head}
1121
+ send(res, result.ok ? 200 : 422, result.ui ? `${head}
1149
1122
 
1150
1123
  --- ui after ---
1151
1124
  ${result.ui}` : head);
@@ -1156,8 +1129,7 @@ ${result.ui}` : head);
1156
1129
  lastRaw = raw2;
1157
1130
  const result = check(raw2);
1158
1131
  const output = emitCheck(result);
1159
- res.writeHead(result.pass ? 200 : 417, { "Content-Type": "text/plain; charset=utf-8" });
1160
- res.end(output);
1132
+ send(res, result.pass ? 200 : 417, output);
1161
1133
  return;
1162
1134
  }
1163
1135
  if (parts.length >= 1) {
@@ -1165,29 +1137,22 @@ ${result.ui}` : head);
1165
1137
  lastRaw = await collectFromClient();
1166
1138
  const result = detail(lastRaw, parts[0], parts[1], full);
1167
1139
  if (result !== null) {
1168
- res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
1169
- res.end(result);
1140
+ send(res, 200, result);
1170
1141
  return;
1171
1142
  }
1172
- res.writeHead(404, { "Content-Type": "text/plain" });
1173
- res.end(`not found: ${parts.join("/")}`);
1143
+ send(res, 404, `not found: ${parts.join("/")}`);
1174
1144
  return;
1175
1145
  }
1176
1146
  const raw = await collectFromClient();
1177
1147
  lastRaw = raw;
1178
1148
  if (full) {
1179
1149
  const compacted = compact(raw);
1180
- const output = emit(compacted);
1181
- res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
1182
- res.end(output);
1150
+ send(res, 200, emit(compacted));
1183
1151
  } else {
1184
- const output = emitSummary(raw);
1185
- res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
1186
- res.end(output);
1152
+ send(res, 200, emitSummary(raw));
1187
1153
  }
1188
1154
  } catch (err) {
1189
- res.writeHead(504, { "Content-Type": "text/plain" });
1190
- res.end(err instanceof Error ? err.message : "unknown error");
1155
+ send(res, 504, err instanceof Error ? err.message : "unknown error");
1191
1156
  }
1192
1157
  });
1193
1158
  }
@@ -1201,4 +1166,7 @@ ${result.ui}` : head);
1201
1166
 
1202
1167
 
1203
1168
 
1204
- exports.check = check; exports.diffState = diffState; exports.emitSummary = emitSummary; exports.emitCheck = emitCheck; exports.emitDiff = emitDiff; exports.aipeekPlugin = aipeekPlugin;
1169
+
1170
+
1171
+
1172
+ exports.check = check; exports.diffState = diffState; exports.emitSummary = emitSummary; exports.emitCheck = emitCheck; exports.emitDiff = emitDiff; exports.START_TAG = START_TAG; exports.END_TAG = END_TAG; exports.injectClaudeMd = injectClaudeMd; exports.aipeekPlugin = aipeekPlugin;