@aiyiran/myclaw 1.0.246 → 1.0.248

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.
@@ -30,8 +30,7 @@
30
30
  var panelVisible = false;
31
31
  var cachedData = null;
32
32
  var pollTimer = null;
33
- var cachedConfig = null; // { claw, base_url }
34
- var envInfo = null; // { remote: bool, clawName: string|null }
33
+ var lastKnownClawName = null; // 本地环境下从 API 获取,remote 环境每次从 hostname 实时派生
35
34
  var MYCLAW_API_PORT = 18800;
36
35
  var MYCLAW_API_BASE = 'http://127.0.0.1:' + MYCLAW_API_PORT;
37
36
 
@@ -74,56 +73,35 @@
74
73
  return { remote: false, clawName: null };
75
74
  }
76
75
 
77
- // ═══ 初始化配置 ═══
78
- // 远程环境直接用 hostname 中的 clawName
79
- // 本地环境从 sync_workspace.py 的 HTTP API 获取
80
- function initConfig() {
81
- envInfo = detectEnvironment();
82
-
83
- // 解析 agentName 和 workspaceName(与环境无关,纯粹从 URL 参数获取)
84
- var agent = getAgentName() || 'main';
85
- var workspace = agent === 'main' ? 'workspace' : 'workspace-' + agent;
86
-
87
- if (envInfo.remote) {
88
- // 远程:直接拿到 clawName,不需要请求
89
- cachedConfig = {
90
- claw: envInfo.clawName,
91
- base_url: 'https://cdn.yiranlaoshi.com/' + envInfo.clawName,
92
- agentName: agent,
93
- workspaceName: workspace,
94
- };
95
- console.log('[myclaw-artifacts] ✅ 远程环境:', envInfo.clawName, '| agent:', agent, '| workspace:', workspace);
96
- return Promise.resolve(cachedConfig);
76
+ // ═══ 获取 clawName(本地环境从 API 实时获取) ═══
77
+ function resolveClawName() {
78
+ var env = detectEnvironment();
79
+ if (env.remote) {
80
+ return Promise.resolve(env.clawName);
97
81
  }
98
-
99
- // 本地:从 API 获取 claw 配置
100
82
  return fetch(MYCLAW_API_BASE + '/api/config')
101
83
  .then(function (res) {
102
84
  if (!res.ok) throw new Error('HTTP ' + res.status);
103
85
  return res.json();
104
86
  })
105
87
  .then(function (data) {
106
- data.agentName = agent;
107
- data.workspaceName = workspace;
108
- cachedConfig = data;
109
- console.log('[myclaw-artifacts] ✅ 本地环境 | claw:', data.claw, '| agent:', agent, '| workspace:', workspace);
110
- return data;
88
+ lastKnownClawName = data.claw;
89
+ return data.claw;
111
90
  })
112
91
  .catch(function (err) {
113
- // API 不可用时仍保留 agent/workspace 信息
114
- cachedConfig = { claw: null, base_url: null, agentName: agent, workspaceName: workspace };
115
92
  console.warn('[myclaw-artifacts] ⚠ 本地 API 不可用:', err.message);
116
- return cachedConfig;
93
+ return lastKnownClawName; // 降级用上次成功的值
117
94
  });
118
95
  }
119
96
 
120
97
  // ═══ 构建预览 URL ═══
121
- // 统一走 CDN,clawName workspaceName cachedConfig 提供
98
+ // 统一走 CDN,clawName 实时派生,wsPrefix 实时从当前 URL 计算
122
99
  function buildPreviewUrl(data, assetPath) {
123
- var clawName = cachedConfig ? cachedConfig.claw : null;
124
- var wsPrefix = cachedConfig ? cachedConfig.workspaceName : null;
100
+ var env = detectEnvironment();
101
+ var clawName = env.remote ? env.clawName : lastKnownClawName;
102
+ var wsPrefix = getWorkspaceId();
125
103
  if (!clawName || !wsPrefix) {
126
- console.error('[myclaw-artifacts] ❌ 配置未就绪,无法构建预览链接');
104
+ console.error('[myclaw-artifacts] ❌ clawName 未就绪,无法构建预览链接');
127
105
  return null;
128
106
  }
129
107
  return 'https://cdn.yiranlaoshi.com/' + clawName + '/' + wsPrefix + '/' + assetPath;
@@ -266,7 +244,8 @@
266
244
 
267
245
  // ═══ 请求数据 ═══
268
246
  function getWorkspaceId() {
269
- return cachedConfig ? cachedConfig.workspaceName : 'workspace';
247
+ var agent = getAgentName() || 'main';
248
+ return agent === 'main' ? 'workspace' : 'workspace-' + agent;
270
249
  }
271
250
 
272
251
  function fetchArtifactsFromLocalAPI(wsPrefix) {
@@ -277,8 +256,7 @@
277
256
  });
278
257
  }
279
258
 
280
- function fetchArtifactsFromCDN(wsPrefix) {
281
- var clawName = cachedConfig ? cachedConfig.claw : null;
259
+ function fetchArtifactsFromCDN(wsPrefix, clawName) {
282
260
  if (!clawName) return Promise.reject(new Error('no claw name'));
283
261
  var url = 'https://cdn.yiranlaoshi.com/' + clawName + '/' + wsPrefix + '/.myclaw/__MY_ARTIFACTS__.json?t=' + Date.now();
284
262
  return fetch(url).then(function (res) {
@@ -299,18 +277,18 @@
299
277
  }
300
278
 
301
279
  function fetchArtifacts(contentEl) {
302
- // cachedConfig 未就绪时跳过,等 initConfig 完成后的 startPolling 重试
303
- if (!cachedConfig) return;
304
-
280
+ var env = detectEnvironment();
305
281
  var wsPrefix = getWorkspaceId();
306
282
  var fetcher;
307
283
 
308
- if (envInfo && envInfo.remote) {
309
- // 远程服务器 → 走 /cmd/api(服务器直接提供 JSON)
284
+ if (env.remote) {
285
+ // 远程服务器 → 走 /cmd/api
310
286
  fetcher = fetchArtifactsFromServerAPI(wsPrefix);
311
287
  } else {
312
- // 本地环境 → 走 CDN
313
- fetcher = fetchArtifactsFromCDN(wsPrefix);
288
+ // 本地环境 → 实时拿 clawName → 走 CDN
289
+ fetcher = resolveClawName().then(function (clawName) {
290
+ return fetchArtifactsFromCDN(wsPrefix, clawName);
291
+ });
314
292
  }
315
293
 
316
294
  fetcher
@@ -722,10 +700,10 @@
722
700
  }
723
701
  var payload = {
724
702
  title: titleVal,
725
- workspace: cachedConfig ? cachedConfig.workspaceName : 'workspace',
703
+ workspace: getWorkspaceId(),
726
704
  cover_path: coverSelect.value || '',
727
705
  entry_path: entrySelect.value || '',
728
- claw: cachedConfig ? cachedConfig.claw : '',
706
+ claw: (function () { var e = detectEnvironment(); return e.remote ? e.clawName : (lastKnownClawName || ''); }()),
729
707
  };
730
708
  submitBtn.disabled = true;
731
709
  submitBtn.textContent = '\u53D1\u5E03\u4E2D...';
@@ -957,8 +935,8 @@
957
935
  footer.style.cssText = 'padding: 0 24px 20px;text-align:center;display:flex;gap:10px;justify-content:center;';
958
936
 
959
937
  var showcaseBtn = document.createElement('a');
960
- var cfgAgent = cachedConfig ? cachedConfig.agentName : 'main';
961
- var cfgWs = cachedConfig ? cachedConfig.workspaceName : 'workspace';
938
+ var cfgAgent = getAgentName() || 'main';
939
+ var cfgWs = getWorkspaceId();
962
940
  showcaseBtn.href = 'https://www.yiranlaoshi.com/showcase?workspace=' + cfgWs;
963
941
  showcaseBtn.target = '_blank';
964
942
  showcaseBtn.textContent = '\uD83D\uDC41 \u67E5\u770B' + cfgAgent + '\u9879\u76EE\u96C6';
@@ -1409,11 +1387,9 @@
1409
1387
  function init() {
1410
1388
  injectStyles();
1411
1389
  createArtifactsButton();
1412
- // 检测环境 → 获取配置 → 启动轮询
1413
- initConfig().then(function () {
1414
- startPolling();
1415
- console.log('[myclaw-artifacts] ✅ 初始化完成 (' + (envInfo.remote ? '远程: ' + envInfo.clawName : '本地') + ')');
1416
- });
1390
+ startPolling();
1391
+ var env = detectEnvironment();
1392
+ console.log('[myclaw-artifacts] ✅ 初始化完成 (' + (env.remote ? '远程: ' + env.clawName : '本地') + ')');
1417
1393
  }
1418
1394
 
1419
1395
  if (document.readyState === 'loading') {
@@ -341,10 +341,18 @@ btn.addEventListener("click", function () {
341
341
  if (!btn) return;
342
342
 
343
343
  if (recording) {
344
+ btn.classList.remove("myclaw-voice-stopping");
344
345
  btn.classList.add("agent-chat__input-btn--recording");
346
+ btn.disabled = false;
345
347
  btn.title = "\u505c\u6b62\u8bed\u97f3";
346
- } else {
348
+ } else if (stopping) {
347
349
  btn.classList.remove("agent-chat__input-btn--recording");
350
+ btn.classList.add("myclaw-voice-stopping");
351
+ btn.disabled = true;
352
+ btn.title = "\u5904\u7406\u4e2d\u2026";
353
+ } else {
354
+ btn.classList.remove("agent-chat__input-btn--recording", "myclaw-voice-stopping");
355
+ btn.disabled = false;
348
356
  btn.title = "\u8baf\u98de\u8bed\u97f3";
349
357
  }
350
358
 
@@ -465,6 +473,7 @@ btn.addEventListener("click", function () {
465
473
  voiceStopTimer = setTimeout(function () {
466
474
  voiceStopTimer = null;
467
475
  stopping = false;
476
+ updateButtonUI();
468
477
  console.log("[myclaw-voice] 2s timer fired, closing resources...");
469
478
 
470
479
  // 快照当前 textarea 值(2 秒内 onResult 可能已更新)
@@ -529,6 +538,11 @@ btn.addEventListener("click", function () {
529
538
  " animation: myclaw-ring 1.5s ease-out infinite;",
530
539
  " pointer-events: none;",
531
540
  "}",
541
+ /* 按钮处理中态:灰色半透明,禁止点击 */
542
+ ".myclaw-voice-stopping {",
543
+ " opacity: 0.4 !important;",
544
+ " cursor: not-allowed !important;",
545
+ "}",
532
546
  /* textarea 录音态:左侧红色竖线 + 微弱红色背景 */
533
547
  ".myclaw-voice-active {",
534
548
  " border-left: 3px solid #ff4444 !important;",
package/index.js CHANGED
@@ -835,12 +835,17 @@ function runPatch() {
835
835
  console.log('');
836
836
  const skillResult = patchSkills();
837
837
 
838
- // 3. 智能体上传(从 agent-list/ 复制到 ~/.openclaw/)
838
+ // 3. Python 依赖安装(读取 requirements.txt,pip install 缺失的包)
839
+ console.log('');
840
+ const { patchPythonDeps } = require('./patches/patch-python-deps');
841
+ patchPythonDeps();
842
+
843
+ // 4. 智能体上传(从 agent-list/ 复制到 ~/.openclaw/)
839
844
  console.log('');
840
845
  const { patchAgents } = require('./patches/patch-agent');
841
846
  const agentResult = patchAgents();
842
847
 
843
- // 4. Config 补丁(从 manifest 读取,修改 openclaw.json)
848
+ // 5. Config 补丁(从 manifest 读取,修改 openclaw.json)
844
849
  console.log('');
845
850
  try {
846
851
  const { loadManifest } = require('./patches/patch-agent');
@@ -888,7 +893,7 @@ function runPatch() {
888
893
  console.log('[myclaw-config] ⚠ 配置补丁失败: ' + err.message);
889
894
  }
890
895
 
891
- // 5. 自定义注入脚本执行引擎 (Manifest `run` 数组)
896
+ // 6. 自定义注入脚本执行引擎 (Manifest `run` 数组)
892
897
  // 此处读取 manifest.json 中的 "run" 数组,并按顺序 require 执行对应的模块。
893
898
  // 通过修改 manifest 即可控制额外脚本(如 inject-image, inject-search)是否跟随 patch 自动执行,
894
899
  // 从而避免硬编码具体要注入哪些模块。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiyiran/myclaw",
3
- "version": "1.0.246",
3
+ "version": "1.0.248",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -0,0 +1,79 @@
1
+ /**
2
+ * ============================================================================
3
+ * MyClaw Patch Python Deps
4
+ * ============================================================================
5
+ *
6
+ * 功能:
7
+ * 读取 myclaw 根目录下的 requirements.txt,检查并安装所有 Python 依赖。
8
+ * 幂等:已安装的包跳过,只安装缺失的。
9
+ * ============================================================================
10
+ */
11
+
12
+ const { execSync } = require('child_process');
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+
16
+ function patchPythonDeps() {
17
+ const reqPath = path.join(__dirname, '..', 'requirements.txt');
18
+
19
+ if (!fs.existsSync(reqPath)) {
20
+ console.log('[myclaw-python-deps] ⚠ 未找到 requirements.txt,跳过');
21
+ return { success: true, installed: [] };
22
+ }
23
+
24
+ const packages = fs.readFileSync(reqPath, 'utf8')
25
+ .split('\n')
26
+ .map(l => l.trim())
27
+ .filter(l => l && !l.startsWith('#'));
28
+
29
+ if (packages.length === 0) {
30
+ console.log('[myclaw-python-deps] ✅ requirements.txt 为空,无需安装');
31
+ return { success: true, installed: [] };
32
+ }
33
+
34
+ console.log('[myclaw-python-deps] 检查 Python 依赖...');
35
+
36
+ const missing = [];
37
+
38
+ for (const pkg of packages) {
39
+ // pip 包名转 import 名:把连字符换成下划线(volcengine → volcengine,boto3 → boto3)
40
+ const importName = pkg.split(/[>=<!]/)[0].trim().replace(/-/g, '_');
41
+ try {
42
+ execSync(`python3 -c "import ${importName}"`, { stdio: 'pipe' });
43
+ console.log('[myclaw-python-deps] ✅ 已安装: ' + pkg);
44
+ } catch {
45
+ console.log('[myclaw-python-deps] ⚠ 缺少: ' + pkg);
46
+ missing.push(pkg);
47
+ }
48
+ }
49
+
50
+ if (missing.length === 0) {
51
+ console.log('[myclaw-python-deps] ✅ 所有依赖已就绪');
52
+ return { success: true, installed: [] };
53
+ }
54
+
55
+ console.log('[myclaw-python-deps] → 安装缺失依赖: ' + missing.join(', '));
56
+
57
+ const installed = [];
58
+ const failed = [];
59
+
60
+ for (const pkg of missing) {
61
+ try {
62
+ execSync(`pip3 install -q ${pkg}`, { stdio: 'pipe' });
63
+ console.log('[myclaw-python-deps] ✅ 已安装: ' + pkg);
64
+ installed.push(pkg);
65
+ } catch (err) {
66
+ console.log('[myclaw-python-deps] ❌ 安装失败: ' + pkg + ' — ' + err.message);
67
+ failed.push(pkg);
68
+ }
69
+ }
70
+
71
+ if (failed.length > 0) {
72
+ console.log('[myclaw-python-deps] ⚠ 以下依赖安装失败,请手动运行:');
73
+ console.log(' pip3 install ' + failed.join(' '));
74
+ }
75
+
76
+ return { success: failed.length === 0, installed, failed };
77
+ }
78
+
79
+ module.exports = { patchPythonDeps };
@@ -0,0 +1,2 @@
1
+ volcengine
2
+ requests