@aiyiran/myclaw 1.1.136 → 1.1.138
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 +17 -20
- package/assets/myclaw-inject.js +206 -0
- package/package.json +1 -1
- package/patches/patch.js +33 -1
|
@@ -808,8 +808,14 @@
|
|
|
808
808
|
'background: #252536',
|
|
809
809
|
].join(';');
|
|
810
810
|
|
|
811
|
-
//
|
|
811
|
+
// 远程环境:走 CDN(边缘缓存,速度快,不受本机出口带宽限制)
|
|
812
|
+
// 本地环境:走本地 API(文件尚未同步到 CDN)
|
|
813
|
+
// CSP img-src 限制后续在服务端统一放行,此处不做 blob 绕行
|
|
812
814
|
var img = document.createElement('img');
|
|
815
|
+
var _imgEnv = detectEnvironment();
|
|
816
|
+
img.src = _imgEnv.remote
|
|
817
|
+
? previewUrl + '?t=' + Date.now()
|
|
818
|
+
: MYCLAW_API_BASE + '/api/file?path=' + encodeURIComponent(getWorkspaceId() + '/' + asset.path) + '&t=' + Date.now();
|
|
813
819
|
img.alt = asset.name || asset.path;
|
|
814
820
|
img.style.cssText = [
|
|
815
821
|
'max-width: 100%',
|
|
@@ -820,28 +826,13 @@
|
|
|
820
826
|
'position: relative',
|
|
821
827
|
'z-index: 1',
|
|
822
828
|
].join(';');
|
|
823
|
-
|
|
824
|
-
function showImgError() {
|
|
829
|
+
img.onerror = function () {
|
|
825
830
|
img.style.display = 'none';
|
|
826
831
|
var errMsg = document.createElement('div');
|
|
827
832
|
errMsg.textContent = '加载失败';
|
|
828
833
|
errMsg.style.cssText = 'color:#666;font-size:13px;font-family:monospace;';
|
|
829
834
|
imgArea.appendChild(errMsg);
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
var localImgUrl = MYCLAW_API_BASE + '/api/file?path=' + encodeURIComponent(getWorkspaceId() + '/' + asset.path) + '&t=' + Date.now();
|
|
833
|
-
fetch(localImgUrl)
|
|
834
|
-
.then(function (r) {
|
|
835
|
-
if (!r.ok) throw new Error('HTTP ' + r.status);
|
|
836
|
-
return r.blob();
|
|
837
|
-
})
|
|
838
|
-
.then(function (blob) {
|
|
839
|
-
var blobUrl = URL.createObjectURL(blob);
|
|
840
|
-
img.onload = function () { URL.revokeObjectURL(blobUrl); };
|
|
841
|
-
img.onerror = showImgError;
|
|
842
|
-
img.src = blobUrl;
|
|
843
|
-
})
|
|
844
|
-
.catch(showImgError);
|
|
835
|
+
};
|
|
845
836
|
|
|
846
837
|
imgArea.appendChild(img);
|
|
847
838
|
imgBox.appendChild(imgArea);
|
|
@@ -1179,11 +1170,17 @@
|
|
|
1179
1170
|
var isVideo = VIDEO_EXTS.indexOf(assetExt) !== -1;
|
|
1180
1171
|
|
|
1181
1172
|
if (isVideo) {
|
|
1182
|
-
//
|
|
1173
|
+
// <video> 元素支持 range 请求,流式加载,可拖拽进度条,不用 iframe
|
|
1174
|
+
// 远程环境:走 CDN(带宽快,不受本机出口限制)
|
|
1175
|
+
// 本地环境:走本地 API(文件尚未同步到 CDN)
|
|
1176
|
+
// CSP media-src 限制后续在服务端统一放行
|
|
1183
1177
|
var video = document.createElement('video');
|
|
1184
1178
|
video.controls = true;
|
|
1185
1179
|
video.style.cssText = 'flex:1;width:100%;max-height:100%;background:#000;outline:none;';
|
|
1186
|
-
|
|
1180
|
+
var _videoEnv = detectEnvironment();
|
|
1181
|
+
video.src = _videoEnv.remote
|
|
1182
|
+
? previewUrl + '?t=' + Date.now()
|
|
1183
|
+
: MYCLAW_API_BASE + '/api/file?path=' + encodeURIComponent(getWorkspaceId() + '/' + asset.path);
|
|
1187
1184
|
box.appendChild(video);
|
|
1188
1185
|
overlay.appendChild(box);
|
|
1189
1186
|
document.body.appendChild(overlay);
|
package/assets/myclaw-inject.js
CHANGED
|
@@ -784,6 +784,211 @@ btn.addEventListener("click", function () {
|
|
|
784
784
|
});
|
|
785
785
|
}
|
|
786
786
|
|
|
787
|
+
// ═══ 7.5 右下角"新会话"按钮(支持中文命名) ═══
|
|
788
|
+
//
|
|
789
|
+
// 实现思路(复用原生机制,避免重写会话切换逻辑):
|
|
790
|
+
// 1. 点击我们的按钮 → 弹框输入中文名
|
|
791
|
+
// 2. 程序点击 openclaw 原生"新会话"按钮(藏在 openclaw-app 的 shadow DOM 里),
|
|
792
|
+
// 由它负责"创建 + 无刷新切换"——这套逻辑(zH/BH)是模块私有的,外部无法直接调用
|
|
793
|
+
// 3. 轮询 openclaw-app.sessionKey,等它从旧值变为新会话的 key
|
|
794
|
+
// 4. 通过 openclaw-app.client(WebSocket RPC)发 sessions.patch 把 label 改成中文名
|
|
795
|
+
// 服务端 patch 后会广播 sessions.changed,前端订阅会自动刷新侧栏显示,无需手动刷新
|
|
796
|
+
|
|
797
|
+
var newSessionOpen = false;
|
|
798
|
+
|
|
799
|
+
// 获取 openclaw 根组件(上面挂着 WebSocket client 和 sessionKey)
|
|
800
|
+
function getOpenclawApp() {
|
|
801
|
+
return document.querySelector("openclaw-app");
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// 在 shadow DOM(含嵌套)里深度查找元素
|
|
805
|
+
function deepQuerySelector(root, selector) {
|
|
806
|
+
if (!root) return null;
|
|
807
|
+
var direct = root.querySelector ? root.querySelector(selector) : null;
|
|
808
|
+
if (direct) return direct;
|
|
809
|
+
var all = root.querySelectorAll ? root.querySelectorAll("*") : [];
|
|
810
|
+
for (var i = 0; i < all.length; i++) {
|
|
811
|
+
if (all[i].shadowRoot) {
|
|
812
|
+
var found = deepQuerySelector(all[i].shadowRoot, selector);
|
|
813
|
+
if (found) return found;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
return null;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// 找到原生"新会话"按钮(先 light DOM,再 app 的 shadow DOM 深搜)
|
|
820
|
+
function findNativeNewSessionBtn() {
|
|
821
|
+
var sel = ".sidebar-new-session";
|
|
822
|
+
var el = document.querySelector(sel);
|
|
823
|
+
if (el) return el;
|
|
824
|
+
var app = getOpenclawApp();
|
|
825
|
+
if (app && app.shadowRoot) {
|
|
826
|
+
return deepQuerySelector(app.shadowRoot, sel);
|
|
827
|
+
}
|
|
828
|
+
return null;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// 从 sessionKey 解析 agentId(格式 agent:NAME:...),非 agent 会话返回 null
|
|
832
|
+
function deriveAgentId(sessionKey) {
|
|
833
|
+
if (typeof sessionKey === "string" && sessionKey.indexOf("agent:") === 0) {
|
|
834
|
+
var parts = sessionKey.split(":");
|
|
835
|
+
if (parts.length >= 2 && parts[1]) return parts[1];
|
|
836
|
+
}
|
|
837
|
+
return null;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// 轮询等待 sessionKey 变化(原生按钮创建+切换后,key 会变成新会话)
|
|
841
|
+
function waitForSessionChange(app, prevKey, timeoutMs) {
|
|
842
|
+
return new Promise(function (resolve) {
|
|
843
|
+
var start = Date.now();
|
|
844
|
+
(function poll() {
|
|
845
|
+
if (app.sessionKey && app.sessionKey !== prevKey) { resolve(app.sessionKey); return; }
|
|
846
|
+
if (Date.now() - start > timeoutMs) { resolve(null); return; }
|
|
847
|
+
setTimeout(poll, 80);
|
|
848
|
+
})();
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// 创建一个带中文名的新会话
|
|
853
|
+
function createNamedSession(label) {
|
|
854
|
+
var app = getOpenclawApp();
|
|
855
|
+
if (!app) { showToast("未找到 openclaw 应用", "error"); return; }
|
|
856
|
+
if (!app.client) { showToast("网关未连接", "error"); return; }
|
|
857
|
+
|
|
858
|
+
var nativeBtn = findNativeNewSessionBtn();
|
|
859
|
+
if (!nativeBtn) { showToast("未找到原生新会话按钮", "error"); return; }
|
|
860
|
+
if (nativeBtn.disabled) { showToast("当前无法新建(有进行中的任务?)", "error"); return; }
|
|
861
|
+
|
|
862
|
+
var prevKey = app.sessionKey;
|
|
863
|
+
showToast("正在创建:" + label);
|
|
864
|
+
|
|
865
|
+
// 由原生按钮负责创建 + 切换
|
|
866
|
+
nativeBtn.click();
|
|
867
|
+
|
|
868
|
+
waitForSessionChange(app, prevKey, 8000).then(function (newKey) {
|
|
869
|
+
if (!newKey) { showToast("新会话创建超时", "error"); return; }
|
|
870
|
+
// 改名
|
|
871
|
+
var params = { key: newKey, label: label };
|
|
872
|
+
var agentId = deriveAgentId(newKey);
|
|
873
|
+
if (agentId) params.agentId = agentId;
|
|
874
|
+
app.client.request("sessions.patch", params).then(function () {
|
|
875
|
+
showToast("已创建:" + label, "success");
|
|
876
|
+
console.log("[myclaw-newsession] 创建并命名成功:", newKey, label);
|
|
877
|
+
}).catch(function (err) {
|
|
878
|
+
showToast("改名失败:" + (err && err.message ? err.message : err), "error");
|
|
879
|
+
console.error("[myclaw-newsession] sessions.patch 失败:", err);
|
|
880
|
+
});
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
function createNewSessionButton() {
|
|
885
|
+
if (document.querySelector("#myclaw-newsession-btn")) return;
|
|
886
|
+
|
|
887
|
+
var btn = document.createElement("div");
|
|
888
|
+
btn.id = "myclaw-newsession-btn";
|
|
889
|
+
btn.style.cssText = [
|
|
890
|
+
"position: fixed",
|
|
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 = "🆕 新会话";
|
|
907
|
+
btn.title = "创建新会话(可中文命名)";
|
|
908
|
+
|
|
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
|
+
btn.onclick = function (e) {
|
|
912
|
+
e.stopPropagation();
|
|
913
|
+
if (newSessionOpen) { closeNewSessionModal(); } else { openNewSessionModal(); }
|
|
914
|
+
};
|
|
915
|
+
|
|
916
|
+
document.body.appendChild(btn);
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
function closeNewSessionModal() {
|
|
920
|
+
newSessionOpen = false;
|
|
921
|
+
var m = document.querySelector("#myclaw-newsession-modal");
|
|
922
|
+
if (m) m.remove();
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
function openNewSessionModal() {
|
|
926
|
+
if (document.querySelector("#myclaw-newsession-modal")) return;
|
|
927
|
+
newSessionOpen = true;
|
|
928
|
+
|
|
929
|
+
var overlay = document.createElement("div");
|
|
930
|
+
overlay.id = "myclaw-newsession-modal";
|
|
931
|
+
overlay.style.cssText = [
|
|
932
|
+
"position: fixed", "top: 0", "left: 0", "width: 100vw", "height: 100vh",
|
|
933
|
+
"background: rgba(0,0,0,0.4)", "z-index: 99998",
|
|
934
|
+
"display: flex", "align-items: center", "justify-content: center",
|
|
935
|
+
"animation: myclaw-fade-in 0.15s ease",
|
|
936
|
+
].join(";");
|
|
937
|
+
overlay.onclick = function (e) { if (e.target === overlay) closeNewSessionModal(); };
|
|
938
|
+
|
|
939
|
+
var box = document.createElement("div");
|
|
940
|
+
box.style.cssText = "width:360px;background:#1e1e2e;border-radius:8px;overflow:hidden;box-shadow:0 8px 32px rgba(0,0,0,0.5);";
|
|
941
|
+
|
|
942
|
+
var header = document.createElement("div");
|
|
943
|
+
header.style.cssText = "display:flex;align-items:center;justify-content:space-between;padding:10px 14px;background:#2d2d3f;color:#cdd6f4;font-size:13px;font-family:monospace;user-select:none;";
|
|
944
|
+
header.innerHTML = "<span>🆕 新会话</span>";
|
|
945
|
+
var closeBtn = document.createElement("span");
|
|
946
|
+
closeBtn.textContent = "✕";
|
|
947
|
+
closeBtn.style.cssText = "cursor:pointer;padding:2px 6px;border-radius:3px;font-size:14px;transition:background 0.15s;";
|
|
948
|
+
closeBtn.onmouseenter = function () { closeBtn.style.background = "rgba(255,255,255,0.1)"; };
|
|
949
|
+
closeBtn.onmouseleave = function () { closeBtn.style.background = "none"; };
|
|
950
|
+
closeBtn.onclick = function () { closeNewSessionModal(); };
|
|
951
|
+
header.appendChild(closeBtn);
|
|
952
|
+
|
|
953
|
+
var body = document.createElement("div");
|
|
954
|
+
body.style.cssText = "padding:16px;display:flex;flex-direction:column;gap:10px;";
|
|
955
|
+
|
|
956
|
+
var desc = document.createElement("div");
|
|
957
|
+
desc.textContent = "给新会话起个名字(支持中文),点击后自动创建并切换";
|
|
958
|
+
desc.style.cssText = "font-size:11px;color:#888;font-family:monospace;";
|
|
959
|
+
body.appendChild(desc);
|
|
960
|
+
|
|
961
|
+
var input = document.createElement("input");
|
|
962
|
+
input.type = "text";
|
|
963
|
+
input.placeholder = "如:期末复习计划";
|
|
964
|
+
input.style.cssText = "padding:8px 10px;background:#252536;border:1px solid #3d3d5c;border-radius:4px;color:#cdd6f4;font-size:13px;font-family:monospace;outline:none;";
|
|
965
|
+
input.onfocus = function () { input.style.borderColor = "#8b5cf6"; };
|
|
966
|
+
input.onblur = function () { input.style.borderColor = "#3d3d5c"; };
|
|
967
|
+
body.appendChild(input);
|
|
968
|
+
|
|
969
|
+
var submitBtn = document.createElement("button");
|
|
970
|
+
submitBtn.textContent = "创建";
|
|
971
|
+
submitBtn.style.cssText = "padding:8px 16px;background:#8b5cf6;border:none;border-radius:4px;color:#fff;font-size:12px;font-family:monospace;cursor:pointer;transition:opacity 0.15s;";
|
|
972
|
+
submitBtn.onmouseenter = function () { submitBtn.style.opacity = "0.8"; };
|
|
973
|
+
submitBtn.onmouseleave = function () { submitBtn.style.opacity = "1"; };
|
|
974
|
+
|
|
975
|
+
function doSubmit() {
|
|
976
|
+
var val = input.value.trim();
|
|
977
|
+
if (!val) { input.style.borderColor = "#ff4444"; input.focus(); return; }
|
|
978
|
+
closeNewSessionModal();
|
|
979
|
+
createNamedSession(val);
|
|
980
|
+
}
|
|
981
|
+
submitBtn.onclick = doSubmit;
|
|
982
|
+
input.onkeydown = function (e) { if (e.key === "Enter") doSubmit(); };
|
|
983
|
+
body.appendChild(submitBtn);
|
|
984
|
+
|
|
985
|
+
box.appendChild(header);
|
|
986
|
+
box.appendChild(body);
|
|
987
|
+
overlay.appendChild(box);
|
|
988
|
+
document.body.appendChild(overlay);
|
|
989
|
+
setTimeout(function () { input.focus(); }, 100);
|
|
990
|
+
}
|
|
991
|
+
|
|
787
992
|
// ═══ 8. 右下角"命令"按钮 ═══
|
|
788
993
|
|
|
789
994
|
var commandOpen = false;
|
|
@@ -1566,6 +1771,7 @@ btn.addEventListener("click", function () {
|
|
|
1566
1771
|
createDocButton();
|
|
1567
1772
|
createCmdButton();
|
|
1568
1773
|
createCommandButton();
|
|
1774
|
+
createNewSessionButton();
|
|
1569
1775
|
injectStyles();
|
|
1570
1776
|
|
|
1571
1777
|
// 初始化 VoiceInput SDK
|
package/package.json
CHANGED
package/patches/patch.js
CHANGED
|
@@ -113,6 +113,19 @@ function getMyclawVersion() {
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
/**
|
|
117
|
+
* 获取已安装的 OpenClaw 版本号
|
|
118
|
+
* uiDir 形如 <pkg>/dist/control-ui,包根目录为 uiDir/../..
|
|
119
|
+
*/
|
|
120
|
+
function getOpenclawVersion(uiDir) {
|
|
121
|
+
try {
|
|
122
|
+
const pkgRoot = path.resolve(uiDir, '..', '..');
|
|
123
|
+
return require(path.join(pkgRoot, 'package.json')).version;
|
|
124
|
+
} catch {
|
|
125
|
+
return 'unknown';
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
116
129
|
/**
|
|
117
130
|
* 执行注入
|
|
118
131
|
*/
|
|
@@ -250,6 +263,13 @@ function patch() {
|
|
|
250
263
|
let patched = false;
|
|
251
264
|
let foundTarget = false;
|
|
252
265
|
|
|
266
|
+
// img-src / media-src 放宽仅针对特定 OpenClaw 版本(2026.6.9)。
|
|
267
|
+
// 该版本 CSP 中 img-src/media-src 为 'self' data: blob:,会拦截 CDN 图片/视频;
|
|
268
|
+
// 限定版本可避免误改其它版本(CSP 结构可能不同,盲目放宽有风险)。
|
|
269
|
+
const ocVersion = getOpenclawVersion(uiDir);
|
|
270
|
+
const needsMediaCspFix = ocVersion === '2026.6.9';
|
|
271
|
+
console.log('[myclaw-patch] → OpenClaw 版本: ' + ocVersion + (needsMediaCspFix ? ' (将额外放宽 img-src/media-src)' : ''));
|
|
272
|
+
|
|
253
273
|
for (const f of distFiles) {
|
|
254
274
|
// 兼容多版本:gateway-cli-*.js(旧)、server-*.js(中)、control-ui-*.js(新)
|
|
255
275
|
const isTarget = (f.startsWith('gateway-cli-') || f.startsWith('server-') || f.startsWith('control-ui-')) && f.endsWith('.js');
|
|
@@ -264,7 +284,9 @@ function patch() {
|
|
|
264
284
|
const needsFrameSrc = !content.includes('"frame-src *');
|
|
265
285
|
const needsConnectSrc = !content.includes("connect-src *");
|
|
266
286
|
const needsFrameAncestors = !content.includes("frame-ancestors *");
|
|
267
|
-
const
|
|
287
|
+
const needsImgSrc = needsMediaCspFix && !content.includes('"img-src *');
|
|
288
|
+
const needsMediaSrc = needsMediaCspFix && !content.includes('"media-src *');
|
|
289
|
+
const needsAnyCspPatch = needsFrameSrc || needsConnectSrc || needsFrameAncestors || needsImgSrc || needsMediaSrc;
|
|
268
290
|
|
|
269
291
|
if (needsMicrophonePatch || needsAnyCspPatch) {
|
|
270
292
|
// 备份
|
|
@@ -306,6 +328,16 @@ function patch() {
|
|
|
306
328
|
content = content.replace(/\"frame-ancestors[^"]*\"/g, '"frame-ancestors *"');
|
|
307
329
|
cspPatches.push('frame-ancestors *');
|
|
308
330
|
}
|
|
331
|
+
// img-src → 允许所有(仅 2026.6.9,放行 CDN 图片)
|
|
332
|
+
if (needsImgSrc) {
|
|
333
|
+
content = content.replace(/\"img-src[^"]*\"/g, '"img-src *"');
|
|
334
|
+
cspPatches.push('img-src *');
|
|
335
|
+
}
|
|
336
|
+
// media-src → 允许所有(仅 2026.6.9,放行 CDN 视频)
|
|
337
|
+
if (needsMediaSrc) {
|
|
338
|
+
content = content.replace(/\"media-src[^"]*\"/g, '"media-src *"');
|
|
339
|
+
cspPatches.push('media-src *');
|
|
340
|
+
}
|
|
309
341
|
if (cspPatches.length > 0) {
|
|
310
342
|
console.log('[myclaw-patch] ✅ 已修复 CSP (' + cspPatches.join(', ') + '): ' + f);
|
|
311
343
|
}
|