@aiyiran/myclaw 1.1.142 → 1.1.144
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/myclaw-artifacts.js +13 -42
- package/assets/myclaw-inject.js +179 -70
- package/package.json +1 -1
- package/server/debug_record.py +4 -34
|
@@ -60,33 +60,13 @@
|
|
|
60
60
|
|
|
61
61
|
// ═══ 环境检测 ═══
|
|
62
62
|
// 判断当前是远程服务器还是本地环境
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
function detectEnvironment() {
|
|
67
|
-
var hostname = window.location.hostname;
|
|
68
|
-
|
|
69
|
-
// claw.yiranlaoshi.com → 特殊映射:clawdev
|
|
70
|
-
if (hostname === 'claw.yiranlaoshi.com') {
|
|
71
|
-
return { remote: true, clawName: 'clawdev' };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// *.kekouen.cn → 子域名即 clawName
|
|
75
|
-
if (hostname.endsWith('.kekouen.cn')) {
|
|
76
|
-
var clawName = hostname.split('.')[0];
|
|
77
|
-
return { remote: true, clawName: clawName };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// 本地或无法判定
|
|
81
|
-
return { remote: false, clawName: null };
|
|
63
|
+
function isRemote() {
|
|
64
|
+
var h = window.location.hostname;
|
|
65
|
+
return h.endsWith('.yiranlaoshi.com') || h.endsWith('.kekouen.cn');
|
|
82
66
|
}
|
|
83
67
|
|
|
84
|
-
// ═══ 获取 clawName
|
|
68
|
+
// ═══ 获取 clawName(统一从 API 读取) ═══
|
|
85
69
|
function resolveClawName() {
|
|
86
|
-
var env = detectEnvironment();
|
|
87
|
-
if (env.remote) {
|
|
88
|
-
return Promise.resolve(env.clawName);
|
|
89
|
-
}
|
|
90
70
|
return fetch(MYCLAW_API_BASE + '/api/config')
|
|
91
71
|
.then(function (res) {
|
|
92
72
|
if (!res.ok) throw new Error('HTTP ' + res.status);
|
|
@@ -97,19 +77,15 @@
|
|
|
97
77
|
return data.claw;
|
|
98
78
|
})
|
|
99
79
|
.catch(function (err) {
|
|
100
|
-
console.warn('[myclaw-artifacts] ⚠
|
|
101
|
-
return lastKnownClawName;
|
|
80
|
+
console.warn('[myclaw-artifacts] ⚠ API 不可用:', err.message);
|
|
81
|
+
return lastKnownClawName;
|
|
102
82
|
});
|
|
103
83
|
}
|
|
104
84
|
|
|
105
85
|
// ═══ 构建预览 URL ═══
|
|
106
|
-
// 统一走 CDN,clawName 只从两个可信来源取:
|
|
107
|
-
// 远程 → hostname 派生(detectEnvironment)
|
|
108
|
-
// 本地 → resolveClawName() 缓存的 lastKnownClawName
|
|
109
86
|
function buildPreviewUrl(data, assetPath) {
|
|
110
|
-
var env = detectEnvironment();
|
|
111
87
|
var wsPrefix = getWorkspaceId();
|
|
112
|
-
var clawName =
|
|
88
|
+
var clawName = lastKnownClawName;
|
|
113
89
|
|
|
114
90
|
if (!clawName) {
|
|
115
91
|
console.error('[myclaw-artifacts] ❌ clawName 未就绪,无法构建预览链接');
|
|
@@ -270,8 +246,7 @@
|
|
|
270
246
|
|
|
271
247
|
// 展示间跳转(发布按钮左边)
|
|
272
248
|
var showcaseLink = document.createElement('a');
|
|
273
|
-
var
|
|
274
|
-
var _scClaw = _scEnv.remote ? _scEnv.clawName : (lastKnownClawName || '');
|
|
249
|
+
var _scClaw = lastKnownClawName || '';
|
|
275
250
|
var _scWs = getWorkspaceId();
|
|
276
251
|
showcaseLink.href = 'https://www.yiranlaoshi.com/showcase?claw=' + _scClaw + '&workspace=' + _scWs + '&clawName=' + _scClaw;
|
|
277
252
|
showcaseLink.target = '_blank';
|
|
@@ -812,8 +787,7 @@
|
|
|
812
787
|
// 本地环境:走本地 API(文件尚未同步到 CDN)
|
|
813
788
|
// CSP img-src 限制后续在服务端统一放行,此处不做 blob 绕行
|
|
814
789
|
var img = document.createElement('img');
|
|
815
|
-
|
|
816
|
-
img.src = _imgEnv.remote
|
|
790
|
+
img.src = isRemote()
|
|
817
791
|
? previewUrl + '?t=' + Date.now()
|
|
818
792
|
: MYCLAW_API_BASE + '/api/file?path=' + encodeURIComponent(getWorkspaceId() + '/' + asset.path) + '&t=' + Date.now();
|
|
819
793
|
img.alt = asset.name || asset.path;
|
|
@@ -1177,8 +1151,7 @@
|
|
|
1177
1151
|
var video = document.createElement('video');
|
|
1178
1152
|
video.controls = true;
|
|
1179
1153
|
video.style.cssText = 'flex:1;width:100%;max-height:100%;background:#000;outline:none;';
|
|
1180
|
-
|
|
1181
|
-
video.src = _videoEnv.remote
|
|
1154
|
+
video.src = isRemote()
|
|
1182
1155
|
? previewUrl + '?t=' + Date.now()
|
|
1183
1156
|
: MYCLAW_API_BASE + '/api/file?path=' + encodeURIComponent(getWorkspaceId() + '/' + asset.path);
|
|
1184
1157
|
box.appendChild(video);
|
|
@@ -1201,9 +1174,8 @@
|
|
|
1201
1174
|
// HTML 作品已由服务端注入 debug probe,挂上调试记录收集器开始录制。
|
|
1202
1175
|
// 其余类型(图片/视频/PDF…)不录制。collector 不存在时静默跳过。
|
|
1203
1176
|
if (isHtml && typeof window.startDebugRecord === 'function') {
|
|
1204
|
-
var _dbgEnv = detectEnvironment();
|
|
1205
1177
|
var debugContext = {
|
|
1206
|
-
claw:
|
|
1178
|
+
claw: lastKnownClawName,
|
|
1207
1179
|
workspace: getWorkspaceId(),
|
|
1208
1180
|
entryFile: asset.path,
|
|
1209
1181
|
apiBase: MYCLAW_API_BASE
|
|
@@ -2051,7 +2023,7 @@
|
|
|
2051
2023
|
workspace: getWorkspaceId(),
|
|
2052
2024
|
cover_path: coverSelect.value || '',
|
|
2053
2025
|
entry_path: entrySelect.value || '',
|
|
2054
|
-
claw: (
|
|
2026
|
+
claw: (lastKnownClawName || ''),
|
|
2055
2027
|
};
|
|
2056
2028
|
submitBtn.disabled = true;
|
|
2057
2029
|
submitBtn.textContent = '\u53D1\u5E03\u4E2D...';
|
|
@@ -3084,8 +3056,7 @@
|
|
|
3084
3056
|
// 本地环境:启动时获取一次 clawName 并缓存,轮询期间复用
|
|
3085
3057
|
resolveClawName();
|
|
3086
3058
|
startPolling();
|
|
3087
|
-
|
|
3088
|
-
console.log('[myclaw-artifacts] ✅ 初始化完成 (' + (env.remote ? '远程: ' + env.clawName : '本地') + ')');
|
|
3059
|
+
console.log('[myclaw-artifacts] ✅ 初始化完成 (clawName=' + (lastKnownClawName || 'pending') + ')');
|
|
3089
3060
|
}
|
|
3090
3061
|
|
|
3091
3062
|
if (document.readyState === 'loading') {
|
package/assets/myclaw-inject.js
CHANGED
|
@@ -345,7 +345,35 @@
|
|
|
345
345
|
return btn;
|
|
346
346
|
}
|
|
347
347
|
|
|
348
|
+
function createLogButton() {
|
|
349
|
+
var btn = document.createElement("button");
|
|
350
|
+
btn.id = "myclaw-log-btn";
|
|
351
|
+
btn.className = "agent-chat__input-btn";
|
|
352
|
+
btn.title = "让 AI 帮你加运行提示";
|
|
353
|
+
btn.setAttribute("aria-label", "让 AI 帮你加运行提示");
|
|
354
|
+
btn.innerHTML = [
|
|
355
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18"',
|
|
356
|
+
' viewBox="0 0 24 24" fill="none" stroke="currentColor"',
|
|
357
|
+
' stroke-width="2" stroke-linecap="round" stroke-linejoin="round">',
|
|
358
|
+
' <path d="M8 6h13"/>',
|
|
359
|
+
' <path d="M8 12h13"/>',
|
|
360
|
+
' <path d="M8 18h13"/>',
|
|
361
|
+
' <path d="M3 6h.01"/>',
|
|
362
|
+
' <path d="M3 12h.01"/>',
|
|
363
|
+
' <path d="M3 18h.01"/>',
|
|
364
|
+
'</svg>',
|
|
365
|
+
].join("");
|
|
366
|
+
|
|
367
|
+
btn.addEventListener("click", function (e) {
|
|
368
|
+
e.stopPropagation();
|
|
369
|
+
showLogModal();
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
return btn;
|
|
373
|
+
}
|
|
374
|
+
|
|
348
375
|
var debugVoiceDestroyers = [];
|
|
376
|
+
var logVoiceDestroyers = [];
|
|
349
377
|
|
|
350
378
|
function closeDebugModal() {
|
|
351
379
|
debugVoiceDestroyers.forEach(function (destroy) {
|
|
@@ -356,6 +384,15 @@
|
|
|
356
384
|
if (modal) modal.remove();
|
|
357
385
|
}
|
|
358
386
|
|
|
387
|
+
function closeLogModal() {
|
|
388
|
+
logVoiceDestroyers.forEach(function (destroy) {
|
|
389
|
+
try { destroy(); } catch (e) {}
|
|
390
|
+
});
|
|
391
|
+
logVoiceDestroyers = [];
|
|
392
|
+
var modal = document.getElementById("myclaw-log-modal");
|
|
393
|
+
if (modal) modal.remove();
|
|
394
|
+
}
|
|
395
|
+
|
|
359
396
|
function makeDebugLabel(text) {
|
|
360
397
|
var label = document.createElement("div");
|
|
361
398
|
label.textContent = text;
|
|
@@ -371,7 +408,7 @@
|
|
|
371
408
|
].join(";");
|
|
372
409
|
|
|
373
410
|
var input = document.createElement("textarea");
|
|
374
|
-
input.rows =
|
|
411
|
+
input.rows = 4;
|
|
375
412
|
input.maxLength = maxLength || 180;
|
|
376
413
|
input.placeholder = placeholder || "";
|
|
377
414
|
input.spellcheck = false;
|
|
@@ -554,58 +591,38 @@
|
|
|
554
591
|
scroll.className = "myclaw-debug-scroll";
|
|
555
592
|
|
|
556
593
|
var guide = document.createElement("div");
|
|
557
|
-
guide.className = "myclaw-debug-
|
|
558
|
-
["我做了什么", "发生了什么", "我的预期是什么"].forEach(function (text) {
|
|
559
|
-
var item = document.createElement("
|
|
560
|
-
item.
|
|
594
|
+
guide.className = "myclaw-debug-steps";
|
|
595
|
+
["我做了什么", "发生了什么", "我的预期是什么"].forEach(function (text, index) {
|
|
596
|
+
var item = document.createElement("div");
|
|
597
|
+
item.className = "myclaw-debug-step";
|
|
598
|
+
var num = document.createElement("span");
|
|
599
|
+
num.className = "myclaw-debug-step-num";
|
|
600
|
+
num.textContent = String(index + 1) + ".";
|
|
601
|
+
var label = document.createElement("span");
|
|
602
|
+
label.textContent = text;
|
|
603
|
+
item.appendChild(num);
|
|
604
|
+
item.appendChild(label);
|
|
561
605
|
guide.appendChild(item);
|
|
562
606
|
});
|
|
563
607
|
|
|
564
608
|
var inputSection = document.createElement("div");
|
|
565
|
-
inputSection.appendChild(makeDebugLabel("
|
|
566
|
-
var descriptionField = makeDebugVoiceInputField("
|
|
609
|
+
inputSection.appendChild(makeDebugLabel("按 1、2、3 的顺序说"));
|
|
610
|
+
var descriptionField = makeDebugVoiceInputField("1. 我点了开始按钮\n2. 页面没有反应\n3. 我希望角色开始移动", 220, function (val) {
|
|
567
611
|
state.description = val;
|
|
568
612
|
refresh();
|
|
569
613
|
});
|
|
570
614
|
inputSection.appendChild(descriptionField.el);
|
|
571
615
|
debugVoiceDestroyers.push(descriptionField.destroy);
|
|
572
616
|
|
|
573
|
-
var previewWrap = document.createElement("div");
|
|
574
|
-
previewWrap.className = "myclaw-debug-preview";
|
|
575
|
-
var previewLabel = document.createElement("div");
|
|
576
|
-
previewLabel.className = "myclaw-debug-preview-label";
|
|
577
|
-
previewLabel.textContent = "将要发给 AI 的内容:";
|
|
578
|
-
var previewEl = document.createElement("div");
|
|
579
|
-
previewEl.className = "myclaw-debug-preview-text";
|
|
580
|
-
previewWrap.appendChild(previewLabel);
|
|
581
|
-
previewWrap.appendChild(previewEl);
|
|
582
|
-
|
|
583
617
|
scroll.appendChild(guide);
|
|
584
618
|
scroll.appendChild(inputSection);
|
|
585
|
-
scroll.appendChild(previewWrap);
|
|
586
619
|
|
|
587
620
|
var footer = document.createElement("div");
|
|
588
621
|
footer.className = "myclaw-debug-footer";
|
|
589
622
|
|
|
590
|
-
var cancelBtn = document.createElement("button");
|
|
591
|
-
cancelBtn.className = "myclaw-debug-cancel";
|
|
592
|
-
cancelBtn.textContent = "取消";
|
|
593
|
-
cancelBtn.addEventListener("click", function () {
|
|
594
|
-
closeDebugModal();
|
|
595
|
-
});
|
|
596
|
-
|
|
597
|
-
var insertBtn = document.createElement("button");
|
|
598
|
-
insertBtn.className = "myclaw-debug-insert";
|
|
599
|
-
insertBtn.textContent = "⬇ 先放到聊天框";
|
|
600
|
-
insertBtn.addEventListener("click", function () {
|
|
601
|
-
if (!hasDebugInput()) return;
|
|
602
|
-
setTextareaValue(buildDebugPrompt());
|
|
603
|
-
closeDebugModal();
|
|
604
|
-
});
|
|
605
|
-
|
|
606
623
|
var submitBtn = document.createElement("button");
|
|
607
624
|
submitBtn.className = "myclaw-debug-submit";
|
|
608
|
-
submitBtn.textContent = "➤
|
|
625
|
+
submitBtn.textContent = "➤ 发给 AI 帮我查";
|
|
609
626
|
submitBtn.addEventListener("click", function () {
|
|
610
627
|
if (!hasDebugInput()) return;
|
|
611
628
|
setTextareaValue(buildDebugPrompt());
|
|
@@ -619,18 +636,11 @@
|
|
|
619
636
|
|
|
620
637
|
function refresh() {
|
|
621
638
|
var ready = hasDebugInput();
|
|
622
|
-
previewEl.textContent = ready ? buildDebugPrompt() : "先写一项,这里会自动整理成要发给 AI 的内容。";
|
|
623
|
-
previewEl.style.color = ready ? "#cdd6f4" : "#555";
|
|
624
639
|
submitBtn.disabled = !ready;
|
|
625
|
-
insertBtn.disabled = !ready;
|
|
626
640
|
submitBtn.style.opacity = ready ? "1" : "0.4";
|
|
627
|
-
insertBtn.style.opacity = ready ? "1" : "0.4";
|
|
628
641
|
submitBtn.style.cursor = ready ? "pointer" : "not-allowed";
|
|
629
|
-
insertBtn.style.cursor = ready ? "pointer" : "not-allowed";
|
|
630
642
|
}
|
|
631
643
|
|
|
632
|
-
footer.appendChild(cancelBtn);
|
|
633
|
-
footer.appendChild(insertBtn);
|
|
634
644
|
footer.appendChild(submitBtn);
|
|
635
645
|
box.appendChild(header);
|
|
636
646
|
box.appendChild(scroll);
|
|
@@ -638,12 +648,112 @@
|
|
|
638
648
|
overlay.appendChild(box);
|
|
639
649
|
document.body.appendChild(overlay);
|
|
640
650
|
|
|
641
|
-
|
|
642
|
-
|
|
651
|
+
refresh();
|
|
652
|
+
descriptionField.focus();
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
function showLogModal() {
|
|
656
|
+
if (document.getElementById("myclaw-log-modal")) return;
|
|
657
|
+
|
|
658
|
+
var state = { problem: "" };
|
|
659
|
+
|
|
660
|
+
function buildLogPrompt() {
|
|
661
|
+
var lines = [];
|
|
662
|
+
lines.push("我需要你帮我添加一些调试信息,我希望调试信息非常清晰、全面。");
|
|
663
|
+
lines.push("我正在解决的问题是关于:" + state.problem);
|
|
664
|
+
lines.push("");
|
|
665
|
+
lines.push("这些调试信息后续会给到你,用来帮我继续解决问题。");
|
|
666
|
+
lines.push("");
|
|
667
|
+
lines.push("请只添加调试信息,不要顺手修改功能逻辑。");
|
|
668
|
+
lines.push("请优先添加 console.log,文字要清楚,适合小学生看懂。");
|
|
669
|
+
lines.push("请在关键步骤都加上信息,比如:有没有点到、进入了哪一步、重要变量现在是多少、为什么没有继续。");
|
|
670
|
+
lines.push("改完后告诉我:你在哪些地方加了提示、每条提示能帮我看出什么。");
|
|
671
|
+
return lines.join("\n");
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
var overlay = document.createElement("div");
|
|
675
|
+
overlay.id = "myclaw-log-modal";
|
|
676
|
+
overlay.className = "myclaw-debug-modal";
|
|
677
|
+
|
|
678
|
+
var box = document.createElement("div");
|
|
679
|
+
box.className = "myclaw-debug-box";
|
|
680
|
+
|
|
681
|
+
var header = document.createElement("div");
|
|
682
|
+
header.className = "myclaw-debug-header myclaw-log-header";
|
|
683
|
+
header.innerHTML = "<span>🧭 让 AI 加运行提示</span>";
|
|
684
|
+
var closeX = document.createElement("span");
|
|
685
|
+
closeX.textContent = "✕";
|
|
686
|
+
closeX.className = "myclaw-debug-close";
|
|
687
|
+
closeX.onclick = function () { closeLogModal(); };
|
|
688
|
+
header.appendChild(closeX);
|
|
689
|
+
|
|
690
|
+
var scroll = document.createElement("div");
|
|
691
|
+
scroll.className = "myclaw-debug-scroll";
|
|
692
|
+
|
|
693
|
+
var guide = document.createElement("div");
|
|
694
|
+
guide.className = "myclaw-debug-steps";
|
|
695
|
+
["我想查什么问题", "哪一步最不确定", "想看到哪些变化"].forEach(function (text, index) {
|
|
696
|
+
var item = document.createElement("div");
|
|
697
|
+
item.className = "myclaw-debug-step";
|
|
698
|
+
var num = document.createElement("span");
|
|
699
|
+
num.className = "myclaw-debug-step-num";
|
|
700
|
+
num.textContent = String(index + 1) + ".";
|
|
701
|
+
var label = document.createElement("span");
|
|
702
|
+
label.textContent = text;
|
|
703
|
+
item.appendChild(num);
|
|
704
|
+
item.appendChild(label);
|
|
705
|
+
guide.appendChild(item);
|
|
643
706
|
});
|
|
644
707
|
|
|
708
|
+
var inputSection = document.createElement("div");
|
|
709
|
+
inputSection.appendChild(makeDebugLabel("按 1、2、3 的顺序说"));
|
|
710
|
+
var problemField = makeDebugVoiceInputField(
|
|
711
|
+
"1. 我想查为什么按钮点了没反应\n2. 我不确定点击后有没有进入判断\n3. 我想看到按钮有没有被点到、分数有没有变化",
|
|
712
|
+
240,
|
|
713
|
+
function (val) {
|
|
714
|
+
state.problem = val;
|
|
715
|
+
refresh();
|
|
716
|
+
}
|
|
717
|
+
);
|
|
718
|
+
inputSection.appendChild(problemField.el);
|
|
719
|
+
logVoiceDestroyers.push(problemField.destroy);
|
|
720
|
+
|
|
721
|
+
scroll.appendChild(guide);
|
|
722
|
+
scroll.appendChild(inputSection);
|
|
723
|
+
|
|
724
|
+
var footer = document.createElement("div");
|
|
725
|
+
footer.className = "myclaw-debug-footer";
|
|
726
|
+
|
|
727
|
+
var submitBtn = document.createElement("button");
|
|
728
|
+
submitBtn.className = "myclaw-debug-submit myclaw-log-submit";
|
|
729
|
+
submitBtn.textContent = "➤ 发给 AI 加提示";
|
|
730
|
+
submitBtn.addEventListener("click", function () {
|
|
731
|
+
if (!hasLogInput()) return;
|
|
732
|
+
setTextareaValue(buildLogPrompt());
|
|
733
|
+
closeLogModal();
|
|
734
|
+
trySend();
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
function hasLogInput() {
|
|
738
|
+
return !!state.problem.trim();
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
function refresh() {
|
|
742
|
+
var ready = hasLogInput();
|
|
743
|
+
submitBtn.disabled = !ready;
|
|
744
|
+
submitBtn.style.opacity = ready ? "1" : "0.4";
|
|
745
|
+
submitBtn.style.cursor = ready ? "pointer" : "not-allowed";
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
footer.appendChild(submitBtn);
|
|
749
|
+
box.appendChild(header);
|
|
750
|
+
box.appendChild(scroll);
|
|
751
|
+
box.appendChild(footer);
|
|
752
|
+
overlay.appendChild(box);
|
|
753
|
+
document.body.appendChild(overlay);
|
|
754
|
+
|
|
645
755
|
refresh();
|
|
646
|
-
|
|
756
|
+
problemField.focus();
|
|
647
757
|
}
|
|
648
758
|
|
|
649
759
|
// ═══ 3.1 Prompt 小助手按钮(实现见 myclaw-iteration.js) ═══
|
|
@@ -850,6 +960,7 @@ btn.addEventListener("click", function () {
|
|
|
850
960
|
if (!toolbar) return;
|
|
851
961
|
if (
|
|
852
962
|
toolbar.querySelector("#myclaw-debug-btn") &&
|
|
963
|
+
toolbar.querySelector("#myclaw-log-btn") &&
|
|
853
964
|
toolbar.querySelector("#myclaw-prompt-btn") &&
|
|
854
965
|
toolbar.querySelector("#myclaw-voice-btn")
|
|
855
966
|
) {
|
|
@@ -862,16 +973,18 @@ btn.addEventListener("click", function () {
|
|
|
862
973
|
}
|
|
863
974
|
|
|
864
975
|
var debugBtn = document.querySelector("#myclaw-debug-btn") || createDebugButton();
|
|
976
|
+
var logBtn = document.querySelector("#myclaw-log-btn") || createLogButton();
|
|
865
977
|
var promptBtn = document.querySelector("#myclaw-prompt-btn") || createPromptButton();
|
|
866
978
|
var voiceBtn = document.querySelector("#myclaw-voice-btn") || createVoiceButton();
|
|
867
979
|
|
|
868
|
-
// 插入到工具栏最前面:debug
|
|
980
|
+
// 插入到工具栏最前面:debug、log、prompt 和语音按钮依次靠右
|
|
869
981
|
toolbar.insertBefore(voiceBtn, toolbar.firstChild);
|
|
870
982
|
toolbar.insertBefore(promptBtn, voiceBtn);
|
|
871
|
-
toolbar.insertBefore(
|
|
983
|
+
toolbar.insertBefore(logBtn, promptBtn);
|
|
984
|
+
toolbar.insertBefore(debugBtn, logBtn);
|
|
872
985
|
|
|
873
986
|
injected = true;
|
|
874
|
-
console.log("[myclaw-inject] \u2705 debug
|
|
987
|
+
console.log("[myclaw-inject] \u2705 debug/log/prompt/\u8bed\u97f3\u6309\u94ae\u5df2\u6ce8\u5165");
|
|
875
988
|
}
|
|
876
989
|
|
|
877
990
|
// ═══ 注入录音态样式 ═══
|
|
@@ -941,7 +1054,7 @@ btn.addEventListener("click", function () {
|
|
|
941
1054
|
" to { opacity: 1; }",
|
|
942
1055
|
"}",
|
|
943
1056
|
/* Debug 提交弹框 */
|
|
944
|
-
"#myclaw-debug-modal {",
|
|
1057
|
+
"#myclaw-debug-modal, #myclaw-log-modal {",
|
|
945
1058
|
" position: fixed; inset: 0; z-index: 99999;",
|
|
946
1059
|
" background: rgba(0,0,0,0.45);",
|
|
947
1060
|
" display: flex; align-items: center; justify-content: center;",
|
|
@@ -960,6 +1073,9 @@ btn.addEventListener("click", function () {
|
|
|
960
1073
|
" color: #fff; font-size: 15px; font-weight: bold;",
|
|
961
1074
|
" font-family: -apple-system,sans-serif; user-select: none; flex-shrink: 0;",
|
|
962
1075
|
"}",
|
|
1076
|
+
".myclaw-log-header {",
|
|
1077
|
+
" background: linear-gradient(135deg,#0ea5e9,#6366f1);",
|
|
1078
|
+
"}",
|
|
963
1079
|
".myclaw-debug-close {",
|
|
964
1080
|
" cursor: pointer; padding: 2px 8px; border-radius: 4px; font-size: 15px;",
|
|
965
1081
|
"}",
|
|
@@ -972,42 +1088,34 @@ btn.addEventListener("click", function () {
|
|
|
972
1088
|
" font-size: 12px; color: #f59e0b; font-weight: bold;",
|
|
973
1089
|
" margin-bottom: 8px; font-family: -apple-system,sans-serif;",
|
|
974
1090
|
"}",
|
|
975
|
-
".myclaw-debug-
|
|
976
|
-
" display: flex;
|
|
977
|
-
"}",
|
|
978
|
-
".myclaw-debug-guide span {",
|
|
979
|
-
" padding: 7px 10px; border-radius: 999px;",
|
|
980
|
-
" background: rgba(245,158,11,0.12); border: 1px solid rgba(245,158,11,0.35);",
|
|
981
|
-
" color: #fbbf24; font-size: 12px; font-family: -apple-system,sans-serif;",
|
|
982
|
-
"}",
|
|
983
|
-
".myclaw-debug-preview {",
|
|
1091
|
+
".myclaw-debug-steps {",
|
|
1092
|
+
" display: flex; flex-direction: column; gap: 8px;",
|
|
984
1093
|
" padding: 12px 14px; background: #252536; border-radius: 8px;",
|
|
985
1094
|
" border-left: 3px solid #f59e0b;",
|
|
986
1095
|
"}",
|
|
987
|
-
".myclaw-debug-
|
|
988
|
-
"
|
|
989
|
-
"
|
|
1096
|
+
".myclaw-debug-step {",
|
|
1097
|
+
" display: flex; align-items: center; gap: 9px;",
|
|
1098
|
+
" color: #cdd6f4; font-size: 13px; font-family: -apple-system,sans-serif;",
|
|
990
1099
|
"}",
|
|
991
|
-
".myclaw-debug-
|
|
992
|
-
"
|
|
993
|
-
"
|
|
1100
|
+
".myclaw-debug-step-num {",
|
|
1101
|
+
" width: 24px; height: 20px; border-radius: 999px; flex-shrink: 0;",
|
|
1102
|
+
" display: inline-flex; align-items: center; justify-content: center;",
|
|
1103
|
+
" background: #f59e0b; color: #1e1e2e; font-weight: bold; font-size: 12px;",
|
|
994
1104
|
"}",
|
|
995
1105
|
".myclaw-debug-footer {",
|
|
996
1106
|
" display: flex; gap: 10px; padding: 14px 20px;",
|
|
997
1107
|
" border-top: 1px solid #2d2d3f; flex-shrink: 0; background: #1e1e2e;",
|
|
998
1108
|
"}",
|
|
999
|
-
".myclaw-debug-
|
|
1109
|
+
".myclaw-debug-submit {",
|
|
1000
1110
|
" flex: 1; padding: 11px 0; border: none; border-radius: 8px;",
|
|
1001
1111
|
" color: #fff; font-size: 14px; font-weight: bold;",
|
|
1002
1112
|
" font-family: -apple-system,sans-serif; cursor: pointer; transition: all 0.15s;",
|
|
1003
1113
|
"}",
|
|
1004
|
-
".myclaw-debug-cancel { background: #3d3d5c; color: #cdd6f4; }",
|
|
1005
|
-
".myclaw-debug-insert { background: #6366f1; }",
|
|
1006
1114
|
".myclaw-debug-submit { background: #10b981; }",
|
|
1007
|
-
".myclaw-
|
|
1115
|
+
".myclaw-log-submit { background: #0ea5e9; }",
|
|
1008
1116
|
".myclaw-debug-submit:hover:not(:disabled) { background: #059669; }",
|
|
1009
|
-
".myclaw-
|
|
1010
|
-
".myclaw-debug-
|
|
1117
|
+
".myclaw-log-submit:hover:not(:disabled) { background: #0284c7; }",
|
|
1118
|
+
".myclaw-debug-submit:disabled {",
|
|
1011
1119
|
" cursor: not-allowed;",
|
|
1012
1120
|
"}",
|
|
1013
1121
|
].join("\n");
|
|
@@ -2205,6 +2313,7 @@ btn.addEventListener("click", function () {
|
|
|
2205
2313
|
new MutationObserver(function () {
|
|
2206
2314
|
if (
|
|
2207
2315
|
!document.querySelector("#myclaw-debug-btn") ||
|
|
2316
|
+
!document.querySelector("#myclaw-log-btn") ||
|
|
2208
2317
|
!document.querySelector("#myclaw-prompt-btn") ||
|
|
2209
2318
|
!document.querySelector("#myclaw-voice-btn")
|
|
2210
2319
|
) {
|
package/package.json
CHANGED
package/server/debug_record.py
CHANGED
|
@@ -128,48 +128,18 @@ def render_debug_record_html(input_record: Dict[str, Any]) -> str:
|
|
|
128
128
|
|
|
129
129
|
|
|
130
130
|
# =============================================================================
|
|
131
|
-
# 3. 保存层:写入 debug-record.html
|
|
131
|
+
# 3. 保存层:写入 debug-record.html
|
|
132
132
|
# =============================================================================
|
|
133
133
|
|
|
134
134
|
|
|
135
135
|
def save_debug_record(record: Dict[str, Any], debug_dir: Path) -> Dict[str, str]:
|
|
136
|
-
"""
|
|
137
|
-
保存调试记录。
|
|
138
|
-
|
|
139
|
-
会保存两个文件:
|
|
140
|
-
1. debug-record.json:完整结构化数据,方便 AI / 后续系统读取
|
|
141
|
-
2. debug-record.html:学生、老师、AI 都可以打开看的运行回放页面
|
|
142
|
-
|
|
143
|
-
参数:
|
|
144
|
-
record:
|
|
145
|
-
前端提交的调试记录。
|
|
146
|
-
debug_dir:
|
|
147
|
-
服务端已经计算好的 debug 目录。
|
|
148
|
-
不要直接使用前端传来的路径。
|
|
149
|
-
|
|
150
|
-
返回:
|
|
151
|
-
{
|
|
152
|
-
"json_path": "...",
|
|
153
|
-
"html_path": "..."
|
|
154
|
-
}
|
|
155
|
-
"""
|
|
156
136
|
debug_dir.mkdir(parents=True, exist_ok=True)
|
|
157
137
|
|
|
158
138
|
normalized_record = normalize_record(record)
|
|
159
|
-
|
|
160
|
-
json_path = debug_dir / "debug-record.json"
|
|
161
139
|
html_path = debug_dir / "debug-record.html"
|
|
140
|
+
write_text_atomic(html_path, render_debug_record_html(normalized_record))
|
|
162
141
|
|
|
163
|
-
|
|
164
|
-
html_content = render_debug_record_html(normalized_record)
|
|
165
|
-
|
|
166
|
-
write_text_atomic(json_path, json_content)
|
|
167
|
-
write_text_atomic(html_path, html_content)
|
|
168
|
-
|
|
169
|
-
return {
|
|
170
|
-
"json_path": str(json_path),
|
|
171
|
-
"html_path": str(html_path),
|
|
172
|
-
}
|
|
142
|
+
return {"html_path": str(html_path)}
|
|
173
143
|
|
|
174
144
|
|
|
175
145
|
def write_text_atomic(file_path: Path, content: str) -> None:
|
|
@@ -279,7 +249,7 @@ def handle_save_request(body: Dict[str, Any], openclaw_root: str, server_claw: s
|
|
|
279
249
|
"ok": True,
|
|
280
250
|
"traceId": record["traceId"],
|
|
281
251
|
"debugRecordPath": paths["html_path"],
|
|
282
|
-
|
|
252
|
+
|
|
283
253
|
"debugRecordUrl": debug_record_url,
|
|
284
254
|
}
|
|
285
255
|
|