@aiyiran/myclaw 1.1.138 → 1.1.140
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 +164 -0
- package/assets/debug-collector.js +384 -0
- package/assets/debug-probe.js +306 -0
- package/assets/myclaw-artifacts.js +20 -1
- package/assets/myclaw-inject.js +36 -23
- package/index.js +4 -0
- package/package.json +1 -1
- package/patches/patch.js +12 -0
- package/server/debug_record.py +1241 -0
- package/server/sync_workspace.py +108 -3
- package/server//345/217/202/350/200/203/debug-record-render.node.js.ref +165 -0
- package/server//345/217/202/350/200/203/debug-record-save.express.js.ref +154 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw Debug Probe V1
|
|
3
|
+
*
|
|
4
|
+
* 职责:
|
|
5
|
+
* 1. 记录网页运行现场
|
|
6
|
+
* 2. 通过 postMessage 发给父页面
|
|
7
|
+
*
|
|
8
|
+
* 不负责:
|
|
9
|
+
* 1. traceId
|
|
10
|
+
* 2. workspaceId
|
|
11
|
+
* 3. 上传服务端
|
|
12
|
+
* 4. 判断 bug 原因
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
(function () {
|
|
16
|
+
if (window.__OPENCLAW_DEBUG_PROBE_INSTALLED__) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
window.__OPENCLAW_DEBUG_PROBE_INSTALLED__ = true;
|
|
21
|
+
|
|
22
|
+
const PROBE_VERSION = "probe_001";
|
|
23
|
+
const MAX_TEXT_LENGTH = 1000;
|
|
24
|
+
const MAX_STACK_LENGTH = 3000;
|
|
25
|
+
const MAX_ELEMENT_TEXT_LENGTH = 80;
|
|
26
|
+
|
|
27
|
+
function now() {
|
|
28
|
+
return new Date().toISOString();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function truncate(text, maxLength) {
|
|
32
|
+
if (text == null) return "";
|
|
33
|
+
const str = String(text);
|
|
34
|
+
if (str.length <= maxLength) return str;
|
|
35
|
+
return str.slice(0, maxLength) + "...[truncated]";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function getPageInfo() {
|
|
39
|
+
return {
|
|
40
|
+
pageUrl: location.href,
|
|
41
|
+
pagePath: location.pathname,
|
|
42
|
+
pageTitle: document.title || ""
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function safeStringify(value) {
|
|
47
|
+
try {
|
|
48
|
+
if (typeof value === "string") {
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (value instanceof Error) {
|
|
53
|
+
return value.stack || value.message || String(value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (typeof value === "function") {
|
|
57
|
+
return "[Function " + (value.name || "anonymous") + "]";
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (value instanceof Element) {
|
|
61
|
+
return getElementSummary(value);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return JSON.stringify(value);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
try {
|
|
67
|
+
return String(value);
|
|
68
|
+
} catch (e) {
|
|
69
|
+
return "[Unserializable Value]";
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function getElementText(element) {
|
|
75
|
+
if (!element) return "";
|
|
76
|
+
|
|
77
|
+
const text =
|
|
78
|
+
element.innerText ||
|
|
79
|
+
element.textContent ||
|
|
80
|
+
element.value ||
|
|
81
|
+
element.getAttribute("aria-label") ||
|
|
82
|
+
element.getAttribute("title") ||
|
|
83
|
+
"";
|
|
84
|
+
|
|
85
|
+
return truncate(String(text).replace(/\s+/g, " ").trim(), MAX_ELEMENT_TEXT_LENGTH);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function getElementUrl(element) {
|
|
89
|
+
if (!element) return "";
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
element.currentSrc ||
|
|
93
|
+
element.src ||
|
|
94
|
+
element.href ||
|
|
95
|
+
element.getAttribute("src") ||
|
|
96
|
+
element.getAttribute("href") ||
|
|
97
|
+
""
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getSimpleSelector(element) {
|
|
102
|
+
if (!element || !element.tagName) return "";
|
|
103
|
+
|
|
104
|
+
const tag = element.tagName.toLowerCase();
|
|
105
|
+
const id = element.id ? "#" + element.id : "";
|
|
106
|
+
|
|
107
|
+
let classPart = "";
|
|
108
|
+
try {
|
|
109
|
+
if (element.classList && element.classList.length > 0) {
|
|
110
|
+
classPart =
|
|
111
|
+
"." +
|
|
112
|
+
Array.from(element.classList)
|
|
113
|
+
.slice(0, 3)
|
|
114
|
+
.join(".");
|
|
115
|
+
}
|
|
116
|
+
} catch (error) {}
|
|
117
|
+
|
|
118
|
+
return tag + id + classPart;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function getElementSummary(element) {
|
|
122
|
+
if (!element || !element.tagName) {
|
|
123
|
+
return "";
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
tag: element.tagName,
|
|
128
|
+
id: element.id || "",
|
|
129
|
+
className:
|
|
130
|
+
typeof element.className === "string"
|
|
131
|
+
? element.className
|
|
132
|
+
: "",
|
|
133
|
+
text: getElementText(element),
|
|
134
|
+
selector: getSimpleSelector(element)
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function sendEvent(type, payload) {
|
|
139
|
+
const event = {
|
|
140
|
+
type,
|
|
141
|
+
time: now(),
|
|
142
|
+
probeVersion: PROBE_VERSION,
|
|
143
|
+
...getPageInfo(),
|
|
144
|
+
payload: payload || {}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
if (window.parent && window.parent !== window) {
|
|
149
|
+
window.parent.postMessage(
|
|
150
|
+
{
|
|
151
|
+
source: "OPENCLAW_DEBUG_PROBE",
|
|
152
|
+
type: "DEBUG_EVENT",
|
|
153
|
+
event
|
|
154
|
+
},
|
|
155
|
+
"*"
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
} catch (error) {
|
|
159
|
+
// 不让 probe 影响学生作品运行
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function sendPageEnter() {
|
|
164
|
+
sendEvent("page-enter", {
|
|
165
|
+
referrer: document.referrer || ""
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function setupClickListener() {
|
|
170
|
+
document.addEventListener(
|
|
171
|
+
"click",
|
|
172
|
+
function (event) {
|
|
173
|
+
const target = event.target;
|
|
174
|
+
|
|
175
|
+
sendEvent("click", {
|
|
176
|
+
...getElementSummary(target),
|
|
177
|
+
x: event.clientX,
|
|
178
|
+
y: event.clientY
|
|
179
|
+
});
|
|
180
|
+
},
|
|
181
|
+
true
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function setupKeydownListener() {
|
|
186
|
+
document.addEventListener(
|
|
187
|
+
"keydown",
|
|
188
|
+
function (event) {
|
|
189
|
+
sendEvent("keydown", {
|
|
190
|
+
key: event.key,
|
|
191
|
+
code: event.code,
|
|
192
|
+
altKey: event.altKey,
|
|
193
|
+
ctrlKey: event.ctrlKey,
|
|
194
|
+
shiftKey: event.shiftKey,
|
|
195
|
+
metaKey: event.metaKey
|
|
196
|
+
});
|
|
197
|
+
},
|
|
198
|
+
true
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function setupConsoleListener() {
|
|
203
|
+
["log", "warn", "error"].forEach(function (level) {
|
|
204
|
+
const original = console[level];
|
|
205
|
+
|
|
206
|
+
if (typeof original !== "function") {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
console[level] = function (...args) {
|
|
211
|
+
try {
|
|
212
|
+
original.apply(console, args);
|
|
213
|
+
} catch (error) {}
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
const stringArgs = args.map(function (arg) {
|
|
217
|
+
return truncate(safeStringify(arg), MAX_TEXT_LENGTH);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
sendEvent("console", {
|
|
221
|
+
level,
|
|
222
|
+
message: truncate(stringArgs.join(" "), MAX_TEXT_LENGTH),
|
|
223
|
+
args: stringArgs
|
|
224
|
+
});
|
|
225
|
+
} catch (error) {}
|
|
226
|
+
};
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function setupRuntimeErrorListener() {
|
|
231
|
+
window.addEventListener(
|
|
232
|
+
"error",
|
|
233
|
+
function (event) {
|
|
234
|
+
const target = event.target;
|
|
235
|
+
|
|
236
|
+
// 资源加载失败:img/script/link/audio/video 等
|
|
237
|
+
if (target && target !== window && target.tagName) {
|
|
238
|
+
sendEvent("resource-error", {
|
|
239
|
+
tag: target.tagName,
|
|
240
|
+
id: target.id || "",
|
|
241
|
+
className:
|
|
242
|
+
typeof target.className === "string"
|
|
243
|
+
? target.className
|
|
244
|
+
: "",
|
|
245
|
+
url: getElementUrl(target),
|
|
246
|
+
selector: getSimpleSelector(target)
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// JS 运行时报错
|
|
253
|
+
sendEvent("runtime-error", {
|
|
254
|
+
message: truncate(event.message || "Unknown runtime error", MAX_TEXT_LENGTH),
|
|
255
|
+
filename: event.filename || "",
|
|
256
|
+
lineno: event.lineno || null,
|
|
257
|
+
colno: event.colno || null,
|
|
258
|
+
stack: truncate(
|
|
259
|
+
event.error && event.error.stack
|
|
260
|
+
? event.error.stack
|
|
261
|
+
: "",
|
|
262
|
+
MAX_STACK_LENGTH
|
|
263
|
+
)
|
|
264
|
+
});
|
|
265
|
+
},
|
|
266
|
+
true
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function setupUnhandledRejectionListener() {
|
|
271
|
+
window.addEventListener("unhandledrejection", function (event) {
|
|
272
|
+
const reason = event.reason;
|
|
273
|
+
|
|
274
|
+
sendEvent("unhandledrejection", {
|
|
275
|
+
message: truncate(
|
|
276
|
+
reason && reason.message
|
|
277
|
+
? reason.message
|
|
278
|
+
: safeStringify(reason),
|
|
279
|
+
MAX_TEXT_LENGTH
|
|
280
|
+
),
|
|
281
|
+
stack: truncate(
|
|
282
|
+
reason && reason.stack
|
|
283
|
+
? reason.stack
|
|
284
|
+
: "",
|
|
285
|
+
MAX_STACK_LENGTH
|
|
286
|
+
)
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function init() {
|
|
292
|
+
setupConsoleListener();
|
|
293
|
+
setupRuntimeErrorListener();
|
|
294
|
+
setupUnhandledRejectionListener();
|
|
295
|
+
setupClickListener();
|
|
296
|
+
setupKeydownListener();
|
|
297
|
+
|
|
298
|
+
if (document.readyState === "loading") {
|
|
299
|
+
document.addEventListener("DOMContentLoaded", sendPageEnter);
|
|
300
|
+
} else {
|
|
301
|
+
sendPageEnter();
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
init();
|
|
306
|
+
})();
|
|
@@ -1187,8 +1187,10 @@
|
|
|
1187
1187
|
video.focus();
|
|
1188
1188
|
} else {
|
|
1189
1189
|
// HTML 走 CDN;其余类型走本地 API
|
|
1190
|
+
var htmlPreviewSrc = '';
|
|
1190
1191
|
if (isHtml) {
|
|
1191
|
-
|
|
1192
|
+
htmlPreviewSrc = previewUrl + '?t=' + Date.now();
|
|
1193
|
+
iframe.src = htmlPreviewSrc;
|
|
1192
1194
|
} else {
|
|
1193
1195
|
iframe.src = MYCLAW_API_BASE + '/api/file?path=' + encodeURIComponent(getWorkspaceId() + '/' + asset.path) + '&t=' + Date.now();
|
|
1194
1196
|
}
|
|
@@ -1196,6 +1198,18 @@
|
|
|
1196
1198
|
overlay.appendChild(box);
|
|
1197
1199
|
document.body.appendChild(overlay);
|
|
1198
1200
|
iframe.focus();
|
|
1201
|
+
// HTML 作品已由服务端注入 debug probe,挂上调试记录收集器开始录制。
|
|
1202
|
+
// 其余类型(图片/视频/PDF…)不录制。collector 不存在时静默跳过。
|
|
1203
|
+
if (isHtml && typeof window.startDebugRecord === 'function') {
|
|
1204
|
+
var _dbgEnv = detectEnvironment();
|
|
1205
|
+
var debugContext = {
|
|
1206
|
+
claw: _dbgEnv.remote ? _dbgEnv.clawName : lastKnownClawName,
|
|
1207
|
+
workspace: getWorkspaceId(),
|
|
1208
|
+
entryFile: asset.path,
|
|
1209
|
+
apiBase: MYCLAW_API_BASE
|
|
1210
|
+
};
|
|
1211
|
+
try { window.startDebugRecord(iframe, htmlPreviewSrc, debugContext); } catch (e) {}
|
|
1212
|
+
}
|
|
1199
1213
|
}
|
|
1200
1214
|
return;
|
|
1201
1215
|
}
|
|
@@ -1204,6 +1218,11 @@
|
|
|
1204
1218
|
}
|
|
1205
1219
|
|
|
1206
1220
|
function closePreviewModal() {
|
|
1221
|
+
// 通知调试记录收集器收尾并提交。仅在录制中(HTML 预览)时有实际动作,
|
|
1222
|
+
// 其余情况内部自带兜底直接返回;异步保存失败不阻塞弹框关闭。
|
|
1223
|
+
if (typeof window.closePreviewAndSaveDebugRecord === 'function') {
|
|
1224
|
+
try { window.closePreviewAndSaveDebugRecord(); } catch (e) {}
|
|
1225
|
+
}
|
|
1207
1226
|
var modal = document.querySelector('#myclaw-artifacts-preview');
|
|
1208
1227
|
if (modal) modal.remove();
|
|
1209
1228
|
}
|
package/assets/myclaw-inject.js
CHANGED
|
@@ -881,39 +881,52 @@ btn.addEventListener("click", function () {
|
|
|
881
881
|
});
|
|
882
882
|
}
|
|
883
883
|
|
|
884
|
+
function hideNativeNewSessionBtn(nativeBtn) {
|
|
885
|
+
nativeBtn.style.setProperty("display", "none", "important");
|
|
886
|
+
}
|
|
887
|
+
|
|
884
888
|
function createNewSessionButton() {
|
|
885
|
-
|
|
889
|
+
var nativeBtn = findNativeNewSessionBtn();
|
|
890
|
+
if (!nativeBtn) {
|
|
891
|
+
setTimeout(createNewSessionButton, 500);
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
886
894
|
|
|
887
|
-
|
|
895
|
+
// 已经替换过,不重复插入
|
|
896
|
+
if (nativeBtn.parentNode && nativeBtn.parentNode.querySelector("#myclaw-newsession-btn")) return;
|
|
897
|
+
|
|
898
|
+
// 隐藏原生按钮
|
|
899
|
+
hideNativeNewSessionBtn(nativeBtn);
|
|
900
|
+
|
|
901
|
+
// 复用原生按钮的 class + innerHTML,外观完全一致
|
|
902
|
+
var btn = document.createElement("button");
|
|
888
903
|
btn.id = "myclaw-newsession-btn";
|
|
889
|
-
btn.
|
|
890
|
-
|
|
891
|
-
"bottom: 8px",
|
|
892
|
-
"right: 335px",
|
|
893
|
-
"padding: 3px 10px",
|
|
894
|
-
"background: rgba(139, 92, 246, 0.85)",
|
|
895
|
-
"color: #fff",
|
|
896
|
-
"font-size: 11px",
|
|
897
|
-
"font-weight: bold",
|
|
898
|
-
"font-family: monospace",
|
|
899
|
-
"border-radius: 4px",
|
|
900
|
-
"z-index: 99999",
|
|
901
|
-
"user-select: none",
|
|
902
|
-
"cursor: pointer",
|
|
903
|
-
"transition: all 0.2s",
|
|
904
|
-
"letter-spacing: 0.5px",
|
|
905
|
-
].join(";");
|
|
906
|
-
btn.textContent = "🆕 新会话";
|
|
904
|
+
btn.className = nativeBtn.className;
|
|
905
|
+
btn.innerHTML = nativeBtn.innerHTML;
|
|
907
906
|
btn.title = "创建新会话(可中文命名)";
|
|
908
907
|
|
|
909
|
-
btn.onmouseenter = function () { btn.style.background = "rgba(124, 58, 237, 1)"; btn.style.transform = "scale(1.05)"; };
|
|
910
|
-
btn.onmouseleave = function () { btn.style.background = "rgba(139, 92, 246, 0.85)"; btn.style.transform = "scale(1)"; };
|
|
911
908
|
btn.onclick = function (e) {
|
|
912
909
|
e.stopPropagation();
|
|
910
|
+
e.preventDefault();
|
|
913
911
|
if (newSessionOpen) { closeNewSessionModal(); } else { openNewSessionModal(); }
|
|
914
912
|
};
|
|
915
913
|
|
|
916
|
-
|
|
914
|
+
nativeBtn.parentNode.insertBefore(btn, nativeBtn);
|
|
915
|
+
|
|
916
|
+
// 监听 shadow DOM 变化:防止 Lit 重渲染后原生按钮恢复显示或我们的按钮被移除
|
|
917
|
+
var shadowRoot = nativeBtn.getRootNode();
|
|
918
|
+
if (shadowRoot && shadowRoot !== document) {
|
|
919
|
+
new MutationObserver(function () {
|
|
920
|
+
var ourBtn = shadowRoot.querySelector("#myclaw-newsession-btn");
|
|
921
|
+
if (!ourBtn) {
|
|
922
|
+
// 被重渲染移除了,重新插入
|
|
923
|
+
createNewSessionButton();
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
var native = shadowRoot.querySelector(".sidebar-new-session:not(#myclaw-newsession-btn)");
|
|
927
|
+
if (native) hideNativeNewSessionBtn(native);
|
|
928
|
+
}).observe(shadowRoot, { childList: true, subtree: true });
|
|
929
|
+
}
|
|
917
930
|
}
|
|
918
931
|
|
|
919
932
|
function closeNewSessionModal() {
|
package/index.js
CHANGED
|
@@ -1990,6 +1990,7 @@ function runSync(workspaceName) {
|
|
|
1990
1990
|
const targetConfigPath = path.join(targetDir, 'config.json');
|
|
1991
1991
|
const sourcePyPath = path.join(__dirname, 'server', 'sync_workspace.py');
|
|
1992
1992
|
const sourceSchemaPath = path.join(__dirname, 'server', 'artifacts_schema.py');
|
|
1993
|
+
const sourceDebugRecordPath = path.join(__dirname, 'server', 'debug_record.py');
|
|
1993
1994
|
|
|
1994
1995
|
// 确保目标目录存在
|
|
1995
1996
|
if (!fs.existsSync(targetDir)) {
|
|
@@ -1999,6 +2000,9 @@ function runSync(workspaceName) {
|
|
|
1999
2000
|
// 同步 py 文件
|
|
2000
2001
|
fs.copyFileSync(sourcePyPath, targetPyPath);
|
|
2001
2002
|
fs.copyFileSync(sourceSchemaPath, path.join(targetDir, 'artifacts_schema.py'));
|
|
2003
|
+
if (fs.existsSync(sourceDebugRecordPath)) {
|
|
2004
|
+
fs.copyFileSync(sourceDebugRecordPath, path.join(targetDir, 'debug_record.py'));
|
|
2005
|
+
}
|
|
2002
2006
|
|
|
2003
2007
|
// 读取配置(如果不存在则创建)
|
|
2004
2008
|
let config;
|
package/package.json
CHANGED
package/patches/patch.js
CHANGED
|
@@ -28,6 +28,7 @@ const VOICE_OUTPUT_SDK_FILENAME = 'voice-output.js';
|
|
|
28
28
|
const TTS_INJECT_FILENAME = 'myclaw-tts.js';
|
|
29
29
|
const ARTIFACTS_INJECT_FILENAME = 'myclaw-artifacts.js';
|
|
30
30
|
const ITERATION_INJECT_FILENAME = 'myclaw-iteration.js';
|
|
31
|
+
const DEBUG_COLLECTOR_FILENAME = 'debug-collector.js';
|
|
31
32
|
const BACKUP_SUFFIX = '.myclaw-backup';
|
|
32
33
|
|
|
33
34
|
/**
|
|
@@ -151,6 +152,8 @@ function patch() {
|
|
|
151
152
|
const artifactsInjectDest = path.join(uiDir, ARTIFACTS_INJECT_FILENAME);
|
|
152
153
|
const iterationInjectSrc = path.join(__dirname, '..', 'assets', ITERATION_INJECT_FILENAME);
|
|
153
154
|
const iterationInjectDest = path.join(uiDir, ITERATION_INJECT_FILENAME);
|
|
155
|
+
const debugCollectorSrc = path.join(__dirname, '..', 'assets', DEBUG_COLLECTOR_FILENAME);
|
|
156
|
+
const debugCollectorDest = path.join(uiDir, DEBUG_COLLECTOR_FILENAME);
|
|
154
157
|
const version = getMyclawVersion();
|
|
155
158
|
|
|
156
159
|
console.log('[myclaw-patch] → control-ui: ' + uiDir);
|
|
@@ -218,6 +221,14 @@ function patch() {
|
|
|
218
221
|
console.error('[myclaw-patch] ⚠ Iteration 注入脚本复制失败 (非致命): ' + err.message);
|
|
219
222
|
}
|
|
220
223
|
|
|
224
|
+
// 5.7 复制 Debug Collector 注入脚本(父页面侧,接收 iframe 内 probe 的事件)
|
|
225
|
+
try {
|
|
226
|
+
fs.copyFileSync(debugCollectorSrc, debugCollectorDest);
|
|
227
|
+
console.log('[myclaw-patch] ✅ Debug Collector 注入脚本已复制');
|
|
228
|
+
} catch (err) {
|
|
229
|
+
console.error('[myclaw-patch] ⚠ Debug Collector 复制失败 (非致命): ' + err.message);
|
|
230
|
+
}
|
|
231
|
+
|
|
221
232
|
// 6. Patch index.html(幂等)
|
|
222
233
|
try {
|
|
223
234
|
let html = fs.readFileSync(indexPath, 'utf8');
|
|
@@ -235,6 +246,7 @@ function patch() {
|
|
|
235
246
|
'<script src="./' + VOICE_OUTPUT_SDK_FILENAME + '"></script>',
|
|
236
247
|
'<script src="./' + VOICE_SDK_FILENAME + '"></script>',
|
|
237
248
|
'<script src="./' + TTS_INJECT_FILENAME + '"></script>',
|
|
249
|
+
'<script src="./' + DEBUG_COLLECTOR_FILENAME + '"></script>',
|
|
238
250
|
'<script src="./' + ARTIFACTS_INJECT_FILENAME + '"></script>',
|
|
239
251
|
'<script src="./' + ITERATION_INJECT_FILENAME + '"></script>',
|
|
240
252
|
'<script src="./' + INJECT_FILENAME + '"></script>',
|