@aiyiran/myclaw 1.1.152 → 1.1.156
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/assets/debug-collector.js +32 -7
- package/assets/debug-probe.js +38 -3
- package/package.json +1 -1
- package/server/sync_workspace.py +23 -13
|
@@ -121,25 +121,40 @@ function appendDebugEvent(probeEvent) {
|
|
|
121
121
|
|
|
122
122
|
/**
|
|
123
123
|
* 控制日志长度,避免无限膨胀。
|
|
124
|
+
*
|
|
125
|
+
* 关键约束:作品可能在循环里疯狂打 console.log(每帧几十条),若简单地"保留
|
|
126
|
+
* 最近 N 条",会让 console 噪音把 page-enter / 点击 / 按键 / 报错等关键事件
|
|
127
|
+
* 全部挤掉。所以这里分两档:
|
|
128
|
+
* - 关键事件(导航 / 交互 / 各类报错)优先全量保留;
|
|
129
|
+
* - console 只保留最近一批,给它单独的配额。
|
|
124
130
|
*/
|
|
125
131
|
function trimDebugEvents(events) {
|
|
126
132
|
if (events.length <= MAX_EVENTS) {
|
|
127
133
|
return;
|
|
128
134
|
}
|
|
129
135
|
|
|
130
|
-
const
|
|
136
|
+
const KEY_TYPES = new Set([
|
|
137
|
+
"probe-ready",
|
|
138
|
+
"page-enter",
|
|
139
|
+
"click",
|
|
140
|
+
"keydown",
|
|
131
141
|
"runtime-error",
|
|
132
142
|
"unhandledrejection",
|
|
133
|
-
"resource-error"
|
|
143
|
+
"resource-error",
|
|
144
|
+
"console-truncated"
|
|
134
145
|
]);
|
|
135
146
|
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
);
|
|
147
|
+
const keyEvents = events.filter((event) => KEY_TYPES.has(event.type));
|
|
148
|
+
const consoleEvents = events.filter((event) => !KEY_TYPES.has(event.type));
|
|
139
149
|
|
|
140
|
-
|
|
150
|
+
// console 配额 = 总上限减去关键事件占用,至少留一部分给 console。
|
|
151
|
+
const consoleQuota = Math.max(0, MAX_EVENTS - keyEvents.length);
|
|
152
|
+
const keptConsole = consoleEvents.slice(-consoleQuota);
|
|
141
153
|
|
|
142
|
-
|
|
154
|
+
// 合并后按 seq 还原时间顺序,再做去重。
|
|
155
|
+
const merged = [...keyEvents, ...keptConsole].sort(
|
|
156
|
+
(a, b) => (a.seq || 0) - (b.seq || 0)
|
|
157
|
+
);
|
|
143
158
|
|
|
144
159
|
const seen = new Set();
|
|
145
160
|
const deduped = [];
|
|
@@ -317,6 +332,16 @@ function renderDebugRecordPreview(record) {
|
|
|
317
332
|
function formatEventForStudent(event) {
|
|
318
333
|
const time = event.time ? event.time.slice(11, 19) : "";
|
|
319
334
|
|
|
335
|
+
if (event.type === "probe-ready") {
|
|
336
|
+
const version = event.payload && event.payload.probeVersion;
|
|
337
|
+
return `${time} 调试探针启动${version ? "(" + version + ")" : ""}`;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (event.type === "console-truncated") {
|
|
341
|
+
const limit = event.payload && event.payload.limit;
|
|
342
|
+
return `${time} 程序输出过多,已截断${limit ? "(上限 " + limit + " 条)" : ""}`;
|
|
343
|
+
}
|
|
344
|
+
|
|
320
345
|
if (event.type === "page-enter") {
|
|
321
346
|
return `${time} 进入页面:${event.pageTitle || event.pagePath || event.pageUrl}`;
|
|
322
347
|
}
|
package/assets/debug-probe.js
CHANGED
|
@@ -19,11 +19,18 @@
|
|
|
19
19
|
|
|
20
20
|
window.__OPENCLAW_DEBUG_PROBE_INSTALLED__ = true;
|
|
21
21
|
|
|
22
|
-
const PROBE_VERSION = "
|
|
22
|
+
const PROBE_VERSION = "probe_004";
|
|
23
23
|
const MAX_TEXT_LENGTH = 1000;
|
|
24
24
|
const MAX_STACK_LENGTH = 3000;
|
|
25
25
|
const MAX_ELEMENT_TEXT_LENGTH = 80;
|
|
26
26
|
|
|
27
|
+
// console 上报限流:作品可能在循环里疯狂打 log,无节制上报会刷爆父页面
|
|
28
|
+
// 的事件缓冲、把 page-enter / error 等关键事件挤掉。超过上限后停止上报
|
|
29
|
+
// console(其它类型不受影响),并补一条截断提示。
|
|
30
|
+
const MAX_CONSOLE_EVENTS = 100;
|
|
31
|
+
let _consoleEventCount = 0;
|
|
32
|
+
let _consoleTruncatedNotified = false;
|
|
33
|
+
|
|
27
34
|
function now() {
|
|
28
35
|
return new Date().toISOString();
|
|
29
36
|
}
|
|
@@ -222,11 +229,22 @@
|
|
|
222
229
|
original.apply(console, args);
|
|
223
230
|
} catch (error) {}
|
|
224
231
|
|
|
232
|
+
// error 级别始终上报(数量少且关键);log/warn 受限流约束。
|
|
233
|
+
if (level !== "error" && _consoleEventCount >= MAX_CONSOLE_EVENTS) {
|
|
234
|
+
if (!_consoleTruncatedNotified) {
|
|
235
|
+
_consoleTruncatedNotified = true;
|
|
236
|
+
sendEvent("console-truncated", { limit: MAX_CONSOLE_EVENTS });
|
|
237
|
+
}
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
225
241
|
try {
|
|
226
242
|
const stringArgs = args.map(function (arg) {
|
|
227
243
|
return truncate(safeStringify(arg), MAX_TEXT_LENGTH);
|
|
228
244
|
});
|
|
229
245
|
|
|
246
|
+
if (level !== "error") _consoleEventCount++;
|
|
247
|
+
|
|
230
248
|
sendEvent("console", {
|
|
231
249
|
level,
|
|
232
250
|
message: truncate(stringArgs.join(" "), MAX_TEXT_LENGTH),
|
|
@@ -237,11 +255,21 @@
|
|
|
237
255
|
});
|
|
238
256
|
}
|
|
239
257
|
|
|
240
|
-
// 去重:避免 setTimeout 拦截 和 window.error 事件
|
|
258
|
+
// 去重:避免 setTimeout 拦截 和 window.error 事件 重复上报同一个错误。
|
|
259
|
+
// 两条路径拿到的 message 不一致:setTimeout 拦截器拿到原始 error.message
|
|
260
|
+
// (如 "Cannot read..."),window error 事件则带 "Uncaught TypeError: " 前缀。
|
|
261
|
+
// 归一化时剥掉这个前缀,确保同一个错误只上报一次。
|
|
241
262
|
const _reportedErrorKeys = new Set();
|
|
242
263
|
|
|
264
|
+
function normalizeErrorKey(message) {
|
|
265
|
+
return truncate(
|
|
266
|
+
String(message || "").replace(/^Uncaught\s+(\w*Error)?:?\s*/i, ""),
|
|
267
|
+
200
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
243
271
|
function reportRuntimeError(message, filename, lineno, colno, stack) {
|
|
244
|
-
const key =
|
|
272
|
+
const key = normalizeErrorKey(message);
|
|
245
273
|
if (_reportedErrorKeys.has(key)) return;
|
|
246
274
|
_reportedErrorKeys.add(key);
|
|
247
275
|
sendEvent("runtime-error", {
|
|
@@ -361,6 +389,13 @@
|
|
|
361
389
|
setupClickListener();
|
|
362
390
|
setupKeydownListener();
|
|
363
391
|
|
|
392
|
+
// 启动标记:版本号 + 时间。
|
|
393
|
+
// - 独立页面:直接打到控制台,方便人工确认 probe 已就位、是哪个版本。
|
|
394
|
+
// - iframe 模式:作为本轮记录的明确起点事件,便于排查"是否新一轮"。
|
|
395
|
+
const startedAt = now();
|
|
396
|
+
_nativeLog("[PROBE] " + PROBE_VERSION + " 已启动 @ " + startedAt);
|
|
397
|
+
sendEvent("probe-ready", { probeVersion: PROBE_VERSION, startedAt });
|
|
398
|
+
|
|
364
399
|
if (document.readyState === "loading") {
|
|
365
400
|
document.addEventListener("DOMContentLoaded", sendPageEnter);
|
|
366
401
|
} else {
|
package/package.json
CHANGED
package/server/sync_workspace.py
CHANGED
|
@@ -423,12 +423,31 @@ def _get_probe():
|
|
|
423
423
|
return _probe_cache
|
|
424
424
|
|
|
425
425
|
|
|
426
|
+
def _find_probe_insert_pos(html):
|
|
427
|
+
"""决定 probe 注入位置:越早越好,确保 probe 在所有作品脚本之前运行,
|
|
428
|
+
从而 window error listener 能捕获 head/body 任何同步阶段的报错。
|
|
429
|
+
逐级降级:<head> 开始标签后 → <html> 开始标签后 → <body> 开始标签后 → 文档开头。
|
|
430
|
+
返回插入下标(在该下标处插入 tag)。"""
|
|
431
|
+
lower = html.lower()
|
|
432
|
+
for open_tag in ("<head", "<html", "<body"):
|
|
433
|
+
idx = lower.find(open_tag)
|
|
434
|
+
if idx != -1:
|
|
435
|
+
tag_end = html.find(">", idx)
|
|
436
|
+
if tag_end != -1:
|
|
437
|
+
return tag_end + 1
|
|
438
|
+
return 0 # 三个标签都没有:插到最前面
|
|
439
|
+
|
|
440
|
+
|
|
426
441
|
def inject_probe_into_html(html_bytes):
|
|
427
442
|
"""对 HTML 字节注入/更新 probe,返回处理后的 bytes。
|
|
428
443
|
- 已含当前版本 → 原样返回(②)
|
|
429
444
|
- 含旧版本 → 移除旧 probe 再注入新版(③)
|
|
430
|
-
- 不含 →
|
|
431
|
-
probe 不可用、或内容非 UTF-8 文本时,原样返回。
|
|
445
|
+
- 不含 → 注入到尽可能靠前的位置(见 _find_probe_insert_pos)(③)
|
|
446
|
+
probe 不可用、或内容非 UTF-8 文本时,原样返回。
|
|
447
|
+
|
|
448
|
+
⚠️ probe 必须在作品脚本之前加载,否则 init() 等同步阶段的报错会在
|
|
449
|
+
window error listener 安装之前发生,无法被捕获。所以注入到 <head>/<html>
|
|
450
|
+
开始标签之后,而非 </body> 之前。"""
|
|
432
451
|
version, src = _get_probe()
|
|
433
452
|
if not version or not src:
|
|
434
453
|
return html_bytes
|
|
@@ -449,17 +468,8 @@ def inject_probe_into_html(html_bytes):
|
|
|
449
468
|
)
|
|
450
469
|
|
|
451
470
|
tag = f'<script {PROBE_MARKER_ATTR}="{version}">\n{src}\n</script>'
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
body_open = html.lower().find("<body")
|
|
455
|
-
if body_open != -1:
|
|
456
|
-
body_tag_end = html.find(">", body_open)
|
|
457
|
-
if body_tag_end != -1:
|
|
458
|
-
html = html[:body_tag_end + 1] + "\n" + tag + html[body_tag_end + 1:]
|
|
459
|
-
else:
|
|
460
|
-
html = html + "\n" + tag
|
|
461
|
-
else:
|
|
462
|
-
html = html + "\n" + tag
|
|
471
|
+
pos = _find_probe_insert_pos(html)
|
|
472
|
+
html = html[:pos] + "\n" + tag + html[pos:]
|
|
463
473
|
return html.encode("utf-8")
|
|
464
474
|
|
|
465
475
|
|