@aiyiran/myclaw 1.1.175 → 1.1.176
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/CLAUDE.md +6 -6
- package/assets/myclaw-artifacts.js +14 -8
- package/assets/myclaw-inject.js +4 -4
- package/package.json +1 -1
- package/server/debug_record.py +11 -11
package/CLAUDE.md
CHANGED
|
@@ -132,8 +132,8 @@ voice-output.js → voice-input.js → myclaw-tts.js
|
|
|
132
132
|
▼ ▼
|
|
133
133
|
服务端(sync_workspace.py,本机 18800 / 远程经 nginx /sync)
|
|
134
134
|
├─ 按 workspace 自行算目录,写两个文件:
|
|
135
|
-
│
|
|
136
|
-
│ 调试日志.html ← 恒定壳,含 CSS + 前端渲染器,运行时加载
|
|
135
|
+
│ --debug-data--.js ← 每次覆盖,window.__DEBUG_DATA__ = {规范化记录}(数据,喂渲染也给 AI 读)
|
|
136
|
+
│ 调试日志.html ← 恒定壳,含 CSS + 前端渲染器,运行时加载 --debug-data--.js 渲染
|
|
137
137
|
▼
|
|
138
138
|
同步循环 → 上传 CDN → 可展示给学生
|
|
139
139
|
```
|
|
@@ -144,7 +144,7 @@ voice-output.js → voice-input.js → myclaw-tts.js
|
|
|
144
144
|
|------|------|------|--------|
|
|
145
145
|
| **probe**(采集侧) | `assets/debug-probe.js` | 在 iframe 内采集现场,`postMessage` 上报 | traceId、workspace、上传、判因 |
|
|
146
146
|
| **collector**(接收侧) | `assets/debug-collector.js` | 父页面收事件、攒记录、关闭时提交 | probe 注入、AI 修复、HTML 模板 |
|
|
147
|
-
| **server**(落库侧) | `server/debug_record.py` | 算目录、校验、normalize、写
|
|
147
|
+
| **server**(落库侧) | `server/debug_record.py` | 算目录、校验、normalize、写 --debug-data--.js + 恒定 HTML 壳 | 采集、CDN 上传(交给同步循环) |
|
|
148
148
|
| **renderer**(渲染侧) | HTML 壳内联 JS(`render_shell_html()` 里) | 读 `window.__DEBUG_DATA__`,渲染小结/线索/回放 | 数据清洗(服务端做) |
|
|
149
149
|
|
|
150
150
|
### 关键设计约束(改之前先读)
|
|
@@ -161,9 +161,9 @@ voice-output.js → voice-input.js → myclaw-tts.js
|
|
|
161
161
|
5. **前端不传文件路径**。前端只传逻辑字段(claw / workspace / entryFile),**服务端自己算目录**。`claw` 不是路径层级,只用于跟本机 `CLAW_NAME` 校验防串写;真实路径是 `{openclaw_root}/{workspace}/debug/`。
|
|
162
162
|
|
|
163
163
|
6. **数据/渲染分离,落盘两个文件**(固定文件名,每次覆盖):
|
|
164
|
-
-
|
|
165
|
-
- `调试日志.html`:**恒定壳**,内容不随数据变(哈希不变 → 同步不会反复当成更新)。壳内联 CSS + 渲染器 JS,运行时用
|
|
166
|
-
- ⚠️ 渲染逻辑(事件转写 / 错误解释 / 线索提取)现在在**前端 JS**(`render_shell_html()` 里),不在 Python。改文案/样式改这里,且因为壳恒定,AI 修 bug 应读
|
|
164
|
+
- `--debug-data--.js`:`window.__DEBUG_DATA__ = {...}`,唯一数据源(喂前端渲染 + 给 AI 直接读)。
|
|
165
|
+
- `调试日志.html`:**恒定壳**,内容不随数据变(哈希不变 → 同步不会反复当成更新)。壳内联 CSS + 渲染器 JS,运行时用 `--debug-data--.js?t=<时间戳>` 动态加载绕 CDN 缓存。
|
|
166
|
+
- ⚠️ 渲染逻辑(事件转写 / 错误解释 / 线索提取)现在在**前端 JS**(`render_shell_html()` 里),不在 Python。改文案/样式改这里,且因为壳恒定,AI 修 bug 应读 `--debug-data--.js` 而非 HTML。
|
|
167
167
|
|
|
168
168
|
### 接口
|
|
169
169
|
|
|
@@ -424,7 +424,7 @@
|
|
|
424
424
|
'__teacher__.json',
|
|
425
425
|
'__teacher-view__.html',
|
|
426
426
|
'__任务__.html',
|
|
427
|
-
'
|
|
427
|
+
'--debug-data--.js',
|
|
428
428
|
'USER.md',
|
|
429
429
|
'TOOLS.md',
|
|
430
430
|
'SOUL.md',
|
|
@@ -757,11 +757,21 @@
|
|
|
757
757
|
var OFFICE_EXTS = ['ppt', 'pptx', 'doc', 'docx', 'xls', 'xlsx'];
|
|
758
758
|
var isOffice = OFFICE_EXTS.indexOf(assetExt) !== -1;
|
|
759
759
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
var
|
|
760
|
+
var VIDEO_EXTS = ['mp4', 'webm', 'mov', 'avi', 'mkv'];
|
|
761
|
+
var isVideo = VIDEO_EXTS.indexOf(assetExt) !== -1;
|
|
762
|
+
var isHtml = assetExt === 'html' || assetExt === 'htm';
|
|
763
|
+
|
|
764
|
+
// 下载分流:只有「塞进 iframe 也打不开、过去会被浏览器下成无名 file」的
|
|
765
|
+
// 二进制 / 压缩包类型才走常规下载(带真实文件名)。能在 iframe 里渲染的
|
|
766
|
+
//(文本 / json / 代码 / 图片 / PDF / 视频 / HTML…)一律保持预览。
|
|
767
|
+
var DOWNLOAD_EXTS = [
|
|
768
|
+
'zip', 'rar', '7z', 'tar', 'gz', 'tgz', 'bz2', 'xz', 'zst',
|
|
769
|
+
'exe', 'msi', 'dmg', 'pkg', 'deb', 'rpm', 'apk',
|
|
770
|
+
'bin', 'iso', 'ttf', 'otf', 'woff', 'woff2'
|
|
771
|
+
];
|
|
763
772
|
if (DOWNLOAD_EXTS.indexOf(assetExt) !== -1) {
|
|
764
773
|
var fileName = asset.name || (asset.path || '').split('/').pop() || 'download';
|
|
774
|
+
// 本地走同源 /api/file,靠 a[download] 强制文件名;远程走 CDN,URL 末段已是真实文件名。
|
|
765
775
|
var dlUrl = isRemote()
|
|
766
776
|
? previewUrl
|
|
767
777
|
: MYCLAW_API_BASE + '/api/file?path=' + encodeURIComponent(getWorkspaceId() + '/' + asset.path) + '&t=' + Date.now();
|
|
@@ -1158,10 +1168,6 @@
|
|
|
1158
1168
|
'background: #fff',
|
|
1159
1169
|
].join(';');
|
|
1160
1170
|
|
|
1161
|
-
var VIDEO_EXTS = ['mp4', 'webm', 'mov', 'avi', 'mkv'];
|
|
1162
|
-
var isHtml = assetExt === 'html' || assetExt === 'htm';
|
|
1163
|
-
var isVideo = VIDEO_EXTS.indexOf(assetExt) !== -1;
|
|
1164
|
-
|
|
1165
1171
|
if (isVideo) {
|
|
1166
1172
|
// <video> 元素支持 range 请求,流式加载,可拖拽进度条,不用 iframe
|
|
1167
1173
|
// 远程环境:走 CDN(带宽快,不受本机出口限制)
|
package/assets/myclaw-inject.js
CHANGED
|
@@ -328,7 +328,7 @@
|
|
|
328
328
|
function buildTestDonePrompt(keepLogs) {
|
|
329
329
|
var lines = ["我刚才已经完成了测试。"];
|
|
330
330
|
|
|
331
|
-
lines.push("请你读取调试数据文件 debug
|
|
331
|
+
lines.push("请你读取调试数据文件 debug/--debug-data--.js,它是一行 `window.__DEBUG_DATA__ = {...}` 的赋值,里面的 events 数组就是完整运行现场。");
|
|
332
332
|
|
|
333
333
|
lines.push("");
|
|
334
334
|
lines.push("请帮我判断:我们之前的问题是否已经修复。");
|
|
@@ -562,14 +562,14 @@
|
|
|
562
562
|
function buildDebugPrompt() {
|
|
563
563
|
var lines = [];
|
|
564
564
|
|
|
565
|
-
lines.push("调试数据文件:debug
|
|
565
|
+
lines.push("调试数据文件:debug/--debug-data--.js");
|
|
566
566
|
lines.push("");
|
|
567
567
|
lines.push("学生描述:" + (state.description || "(未填写)"));
|
|
568
568
|
lines.push("");
|
|
569
569
|
lines.push("请从学生描述里提取:我做了什么、发生了什么、我的预期是什么。");
|
|
570
570
|
lines.push("");
|
|
571
571
|
lines.push("如何阅读调试数据(按下面抓重点,别东翻西找):");
|
|
572
|
-
lines.push("1. 读调试数据文件 debug
|
|
572
|
+
lines.push("1. 读调试数据文件 debug/--debug-data--.js,它是一行 `window.__DEBUG_DATA__ = {...}` 的赋值,里面的 events 数组就是完整运行现场。");
|
|
573
573
|
lines.push("2. 先在 events 里找 runtime-error / unhandledrejection / 以及 payload.level 为 error 的 console 事件,它们是问题的起点。");
|
|
574
574
|
lines.push("3. 抓住报错事件的 message、stack、filename、lineno——直接定位到源码里出错的那个函数/那几行,只看相关代码段,不要通读整个作品文件。");
|
|
575
575
|
lines.push("4. 再倒着看报错之前的 page-enter / click / keydown / console,还原“做了什么 → 触发了什么”的因果链,确认重现路径。");
|
|
@@ -666,7 +666,7 @@
|
|
|
666
666
|
|
|
667
667
|
function buildLogPrompt() {
|
|
668
668
|
var lines = [];
|
|
669
|
-
lines.push("目前的信息如下:debug
|
|
669
|
+
lines.push("目前的信息如下:debug/--debug-data--.js");
|
|
670
670
|
lines.push("我要解决一个问题:" + state.problem);
|
|
671
671
|
lines.push("");
|
|
672
672
|
lines.push("请优先添加 console.log,文字要清楚,适合小学生看懂。");
|
package/package.json
CHANGED
package/server/debug_record.py
CHANGED
|
@@ -5,20 +5,20 @@ debug_record.py
|
|
|
5
5
|
把前端收集到的 currentDebugRecord 落盘成两个文件,供学生/老师/AI 查看。
|
|
6
6
|
|
|
7
7
|
【架构:数据与渲染分离】
|
|
8
|
-
-
|
|
8
|
+
- --debug-data--.js —— 每次覆盖写。内容是 `window.__DEBUG_DATA__ = {规范化后的记录}`。
|
|
9
9
|
这是**唯一数据源**:既喂前端渲染,也给 AI 直接读。
|
|
10
10
|
- 调试日志.html —— 恒定的“壳”。包含 CSS + 前端渲染器 JS,运行时动态加载
|
|
11
|
-
|
|
11
|
+
--debug-data--.js 并渲染。内容不随数据变化,因此同步循环不会
|
|
12
12
|
反复把它当成“更新”重传。
|
|
13
13
|
|
|
14
14
|
为什么这么拆:
|
|
15
15
|
1. HTML 壳恒定 → 哈希不变 → 不再被同步误判为更新(根除循环上传问题)。
|
|
16
|
-
2. AI 读的是纯数据
|
|
16
|
+
2. AI 读的是纯数据 --debug-data--.js,信噪比高,不掺样式。
|
|
17
17
|
3. 渲染逻辑在前端,改样式不用动 Python、不用重启同步进程。
|
|
18
18
|
|
|
19
19
|
服务端职责(本文件):
|
|
20
20
|
- 接收 / 校验 / normalize 记录
|
|
21
|
-
- 写出
|
|
21
|
+
- 写出 --debug-data--.js 和 调试日志.html
|
|
22
22
|
渲染职责(前端,在 HTML 壳的内联 JS 里):
|
|
23
23
|
- 读 window.__DEBUG_DATA__,渲染小结 / 线索 / 运行回放 / 原始数据
|
|
24
24
|
|
|
@@ -65,7 +65,7 @@ ERROR_EVENT_TYPES = {
|
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
# =============================================================================
|
|
68
|
-
# 2. 保存层:写
|
|
68
|
+
# 2. 保存层:写 --debug-data--.js + 恒定的 调试日志.html 壳
|
|
69
69
|
# =============================================================================
|
|
70
70
|
|
|
71
71
|
|
|
@@ -74,7 +74,7 @@ def save_debug_record(record: Dict[str, Any], debug_dir: Path) -> Dict[str, str]
|
|
|
74
74
|
落盘调试记录。
|
|
75
75
|
|
|
76
76
|
写两个文件:
|
|
77
|
-
-
|
|
77
|
+
- --debug-data--.js 每次覆盖,内容 = window.__DEBUG_DATA__ = {normalized record}
|
|
78
78
|
- 调试日志.html 恒定壳(内容不变),负责加载并渲染上面的数据
|
|
79
79
|
"""
|
|
80
80
|
debug_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -83,7 +83,7 @@ def save_debug_record(record: Dict[str, Any], debug_dir: Path) -> Dict[str, str]
|
|
|
83
83
|
|
|
84
84
|
# 数据文件:每次覆盖
|
|
85
85
|
data_js = "window.__DEBUG_DATA__ = " + safe_json_for_js(normalized_record) + ";\n"
|
|
86
|
-
data_path = debug_dir / "
|
|
86
|
+
data_path = debug_dir / "--debug-data--.js"
|
|
87
87
|
write_text_atomic(data_path, data_js)
|
|
88
88
|
|
|
89
89
|
# HTML 壳:内容恒定(不含数据)。每次都写没关系——内容一致,
|
|
@@ -206,7 +206,7 @@ def assert_safe_id(value: str, field_name: str) -> None:
|
|
|
206
206
|
|
|
207
207
|
|
|
208
208
|
# =============================================================================
|
|
209
|
-
# 4. record / event 规范化(数据清洗留在服务端,输出进
|
|
209
|
+
# 4. record / event 规范化(数据清洗留在服务端,输出进 --debug-data--.js)
|
|
210
210
|
# =============================================================================
|
|
211
211
|
|
|
212
212
|
|
|
@@ -391,7 +391,7 @@ def safe_json_for_js(value: Any) -> str:
|
|
|
391
391
|
# 这个函数返回的内容**不随数据变化**,是纯静态的“壳”:
|
|
392
392
|
# - <style> 页面样式
|
|
393
393
|
# - 前端渲染器 JS(事件转写 / 错误解释 / 线索提取 / DOM 渲染)
|
|
394
|
-
# - 运行时动态加载
|
|
394
|
+
# - 运行时动态加载 --debug-data--.js?t=<时间戳> 绕开 CDN 缓存
|
|
395
395
|
# 渲染逻辑是从原 Python 函数(format_replay_event / simplify_error_message /
|
|
396
396
|
# extract_clues / render_*)逐一移植过来的 JS 版本。
|
|
397
397
|
#
|
|
@@ -719,13 +719,13 @@ def render_shell_html() -> str:
|
|
|
719
719
|
|
|
720
720
|
// 动态加载数据,带时间戳绕开 CDN 缓存(壳恒定,数据每次新)
|
|
721
721
|
var s = document.createElement("script");
|
|
722
|
-
s.src = "
|
|
722
|
+
s.src = "--debug-data--.js?t=" + Date.now();
|
|
723
723
|
s.onload = function () {
|
|
724
724
|
try { render(window.__DEBUG_DATA__); }
|
|
725
725
|
catch (e) { document.getElementById("dynamic").textContent = "渲染失败:" + (e && e.message); }
|
|
726
726
|
};
|
|
727
727
|
s.onerror = function () {
|
|
728
|
-
document.getElementById("dynamic").textContent = "
|
|
728
|
+
document.getElementById("dynamic").textContent = "调试数据加载失败(--debug-data--.js)";
|
|
729
729
|
};
|
|
730
730
|
document.head.appendChild(s);
|
|
731
731
|
})();
|