@aiyiran/myclaw 1.0.163 → 1.0.165

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/index.js CHANGED
@@ -1131,7 +1131,7 @@ function showHelp() {
1131
1131
  console.log(' up 升级 + 刷新桌面快捷方式 (= update + bat)');
1132
1132
  console.log(' open 打开浏览器控制台(自动带 token)');
1133
1133
  console.log(' fix 兜底修复(自动补装 WSL + Chrome,仅限 Windows)');
1134
- console.log(' wsl2 WSL2 一键安装/修复 (仅限 Windows, 可选: --cli)');
1134
+ console.log(' wsl2 WSL2 一键安装/修复 (仅限 Windows, 可选: --cli, --remote)');
1135
1135
  console.log(' safe 开启虚拟机屏蔽 (禁止自动挂载 Windows 盘符)');
1136
1136
  console.log(' bat 在桌面生成一键启动脚本 (仅限 Windows)');
1137
1137
  console.log(' list 查看注入资源管理列表(智能体/技能/配置)');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiyiran/myclaw",
3
- "version": "1.0.163",
3
+ "version": "1.0.165",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
package/restrict.js CHANGED
@@ -11,7 +11,7 @@
11
11
  * 步骤 3: 在 Windows 桌面创建快捷方式,指向 \\wsl.localhost\OpenClaw\root\.openclaw\workspace
12
12
  *
13
13
  * 使用方法:
14
- * myclaw restrict
14
+ * myclaw safe
15
15
  *
16
16
  * 前提:OpenClaw WSL2 发行版已安装(myclaw wsl2 完成)
17
17
  * ============================================================================
@@ -33,8 +33,8 @@ const C = isWindows
33
33
  : { r: '\x1b[31m', g: '\x1b[32m', y: '\x1b[33m', b: '\x1b[34m', nc: '\x1b[0m' };
34
34
 
35
35
  const DISTRO_NAME = 'OpenClaw';
36
- const WORKSPACE_PATH = '/root/.openclaw/workspace/myclaw'; // 实际创建的目录
37
- const SHORTCUT_TARGET = '/root/.openclaw/workspace'; // 快捷方式导航到这里
36
+ const WORKSPACE_PATH = '/root/.openclaw/workspace/myclaw';
37
+ const SHORTCUT_TARGET = '/root/.openclaw/workspace';
38
38
 
39
39
  // ============================================================================
40
40
  // 工具函数
@@ -46,10 +46,10 @@ function printSuccess(msg) { console.log(C.g + '[成功]' + C.nc + ' ' + msg); }
46
46
  function printWarning(msg) { console.log(C.y + '[警告]' + C.nc + ' ' + msg); }
47
47
  function printError(msg) { console.error(C.r + '[错误]' + C.nc + ' ' + msg); }
48
48
 
49
- // 在 WSL 中执行命令,返回输出(stdout
49
+ // 在 WSL 中执行命令,返回 stdout
50
50
  function wslExec(cmd) {
51
51
  try {
52
- return execSync('wsl -d ' + DISTRO_NAME + ' -- bash -c "' + cmd + '"', {
52
+ return execSync('wsl -d ' + DISTRO_NAME + ' -- ' + cmd, {
53
53
  encoding: 'utf8',
54
54
  stdio: ['pipe', 'pipe', 'pipe'],
55
55
  }).trim();
@@ -58,10 +58,21 @@ function wslExec(cmd) {
58
58
  }
59
59
  }
60
60
 
61
- // WSL 中以 root 执行命令(不关心输出)
62
- function wslExecRoot(cmd) {
61
+ // 写临时 shell 脚本到 WSL 内,然后以 root 执行
62
+ // 这样避免 Windows cmd.exe 对管道/重定向的干扰
63
+ function wslRunScriptAsRoot(scriptContent) {
64
+ // 把脚本写到 WSL 的 /tmp 下
65
+ const tmpScript = '/tmp/myclaw_safe_setup.sh';
66
+ const b64 = Buffer.from(scriptContent).toString('base64');
67
+
63
68
  try {
64
- execSync('wsl -d ' + DISTRO_NAME + ' -u root -- bash -c "' + cmd + '"', {
69
+ // 写入脚本
70
+ execSync('wsl -d ' + DISTRO_NAME + ' -u root -- bash -c "echo ' + b64 + ' | base64 -d > ' + tmpScript + '"', {
71
+ encoding: 'utf8',
72
+ stdio: 'pipe',
73
+ });
74
+ // 执行脚本
75
+ execSync('wsl -d ' + DISTRO_NAME + ' -u root -- bash ' + tmpScript, {
65
76
  encoding: 'utf8',
66
77
  stdio: 'pipe',
67
78
  });
@@ -81,7 +92,6 @@ function checkPrerequisites() {
81
92
  process.exit(1);
82
93
  }
83
94
 
84
- // 检查 wsl 命令
85
95
  try {
86
96
  execSync('wsl --version', { stdio: 'pipe' });
87
97
  } catch {
@@ -89,7 +99,6 @@ function checkPrerequisites() {
89
99
  process.exit(1);
90
100
  }
91
101
 
92
- // 检查 OpenClaw 发行版
93
102
  try {
94
103
  const list = execSync('wsl -l -q', { encoding: 'utf16le' });
95
104
  if (!list.includes(DISTRO_NAME)) {
@@ -129,28 +138,30 @@ function step1_createWorkspace() {
129
138
  function step2_disableAutomount() {
130
139
  printStep('步骤 2/3: 禁用自动挂载 Windows 盘符');
131
140
 
132
- // 备份
133
- wslExecRoot('cp /etc/wsl.conf /etc/wsl.conf.bak 2>/dev/null || true');
134
-
135
141
  // 读取现有配置
136
142
  const existing = wslExec('cat /etc/wsl.conf 2>/dev/null') || '';
137
143
 
138
144
  let newContent;
139
145
  if (existing.includes('[automount]')) {
140
- // 替换已有 automount 段
141
146
  newContent = existing.replace(
142
147
  /\[automount\][^\[]*/,
143
148
  '[automount]\nenabled = false\n'
144
149
  );
145
150
  } else {
146
- // 追加
147
151
  newContent = existing + (existing.endsWith('\n') ? '' : '\n') + '[automount]\nenabled = false\n';
148
152
  }
149
153
 
150
- // heredoc 写入(通过 base64 传递内容,避免 shell 转义问题)
151
- const b64 = Buffer.from(newContent).toString('base64');
152
- const writeCmd = "echo '" + b64 + "' | base64 -d > /etc/wsl.conf";
153
- const ok = wslExecRoot(writeCmd);
154
+ // 构建一个完整的 shell 脚本,在 WSL 内执行
155
+ const script = [
156
+ '#!/bin/bash',
157
+ 'cp /etc/wsl.conf /etc/wsl.conf.bak 2>/dev/null || true',
158
+ 'cat > /etc/wsl.conf << \'MYCLAW_EOF\'',
159
+ newContent,
160
+ 'MYCLAW_EOF',
161
+ ].join('\n');
162
+
163
+ printInfo('正在写入 /etc/wsl.conf ...');
164
+ const ok = wslRunScriptAsRoot(script);
154
165
 
155
166
  if (!ok) {
156
167
  printError('写入 wsl.conf 失败');
@@ -161,10 +172,16 @@ function step2_disableAutomount() {
161
172
  const verify = wslExec('cat /etc/wsl.conf 2>/dev/null') || '';
162
173
  if (verify.includes('enabled = false') || verify.includes('enabled=false')) {
163
174
  printSuccess('automount 已禁用');
175
+ printInfo('/etc/wsl.conf 内容:');
176
+ console.log('---');
177
+ console.log(verify);
178
+ console.log('---');
164
179
  return true;
165
180
  }
166
181
 
167
- printError('配置验证失败');
182
+ printError('配置验证失败,写入可能不完整');
183
+ printInfo('实际内容:');
184
+ console.log(verify || '(空)');
168
185
  return false;
169
186
  }
170
187
 
@@ -175,10 +192,8 @@ function step2_disableAutomount() {
175
192
  function step3_createShortcut() {
176
193
  printStep('步骤 3/3: 创建桌面快捷方式');
177
194
 
178
- // \\wsl.localhost\OpenClaw\root\.openclaw\workspace
179
195
  const wslPath = '\\\\wsl.localhost\\' + DISTRO_NAME + '\\' + SHORTCUT_TARGET.replace(/\//g, '\\');
180
196
 
181
- // 找桌面路径(兼容中英文)
182
197
  const desktopPath = path.join(os.homedir(), 'Desktop');
183
198
  const desktopPathCN = path.join(os.homedir(), '桌面');
184
199
  const shortcutDir = fs.existsSync(desktopPath) ? desktopPath
@@ -189,9 +204,8 @@ function step3_createShortcut() {
189
204
  return false;
190
205
  }
191
206
 
192
- const shortcutPath = path.join(shortcutDir, 'myclaw.lnk');
207
+ const shortcutPath = path.join(shortcutDir, '我的私人龙虾.lnk');
193
208
 
194
- // 写临时 .ps1 文件来创建快捷方式(避免复杂的命令行转义)
195
209
  const tmpDir = path.join(process.env.LOCALAPPDATA || os.tmpdir(), 'myclaw');
196
210
  try { fs.mkdirSync(tmpDir, { recursive: true }); } catch {}
197
211
  const psFile = path.join(tmpDir, 'create-shortcut.ps1');
@@ -203,22 +217,12 @@ function step3_createShortcut() {
203
217
  '$sc.Arguments = "' + wslPath + '"',
204
218
  '$sc.WorkingDirectory = "' + wslPath + '"',
205
219
  '$sc.Description = "OpenClaw Workspace"',
220
+ '$sc.IconLocation = "C:\\Windows\\explorer.exe,0"',
206
221
  '$sc.Save()',
207
222
  '',
208
- '# 尝试下载图标',
209
- '$iconDir = "' + tmpDir + '"',
210
- '$iconPath = "$iconDir\\openclaw.ico"',
211
- 'try {',
212
- ' Invoke-WebRequest -Uri "https://cdn.yiranlaoshi.com/software/myclaw/openclaw.ico" -OutFile $iconPath -UseBasicParsing',
213
- ' $sc2 = $ws.CreateShortcut("' + shortcutPath + '")',
214
- ' $sc2.IconLocation = "$iconPath,0"',
215
- ' $sc2.Save()',
216
- '} catch {}',
217
- '',
218
223
  'Write-Host "OK"',
219
224
  ].join('\r\n');
220
225
 
221
- // UTF-8 BOM
222
226
  fs.writeFileSync(psFile, '\uFEFF' + psContent, 'utf8');
223
227
 
224
228
  try {
@@ -228,15 +232,14 @@ function step3_createShortcut() {
228
232
  ).trim();
229
233
 
230
234
  if (result.includes('OK')) {
231
- printSuccess('桌面快捷方式已创建: myclaw');
235
+ printSuccess('桌面快捷方式已创建: 我的私人龙虾');
232
236
  printInfo('双击即可打开工作目录');
233
237
  return true;
234
238
  }
235
239
  } catch {
236
- // 回退:创建 .url 文件
237
240
  try {
238
241
  const urlContent = '[InternetShortcut]\r\nURL=file:///' + wslPath.replace(/\\/g, '/') + '\r\n';
239
- fs.writeFileSync(path.join(shortcutDir, 'myclaw.url'), urlContent, 'utf8');
242
+ fs.writeFileSync(path.join(shortcutDir, '我的私人龙虾.url'), urlContent, 'utf8');
240
243
  printSuccess('桌面快捷方式已创建 (.url)');
241
244
  return true;
242
245
  } catch (err2) {
@@ -255,13 +258,13 @@ function step3_createShortcut() {
255
258
  function run() {
256
259
  console.log('');
257
260
  console.log('========================================');
258
- console.log(' MyClaw WSL2 权限封锁');
261
+ console.log(' MyClaw 虚拟机屏蔽');
259
262
  console.log('========================================');
260
263
  console.log('');
261
264
  console.log('此操作将:');
262
265
  console.log(' 1. 在 WSL 内创建工作目录');
263
266
  console.log(' 2. 禁用 WSL 自动挂载 Windows 盘符');
264
- console.log(' 3. 在桌面创建快捷方式 myclaw');
267
+ console.log(' 3. 在桌面创建快捷方式');
265
268
  console.log('');
266
269
  console.log('效果:Linux 看不到 Windows 文件,但 Windows');
267
270
  console.log(' 可以通过桌面快捷方式访问 WSL 工作目录。');
@@ -277,21 +280,37 @@ function run() {
277
280
  printWarning('快捷方式创建失败,但不影响权限封锁');
278
281
  }
279
282
 
280
- // 完成提示
281
283
  console.log('');
282
284
  console.log('========================================');
283
- printSuccess('权限封锁完成!');
285
+ printSuccess('虚拟机屏蔽配置完成!');
284
286
  console.log('========================================');
285
287
  console.log('');
286
- printWarning('需要重启 WSL2 才能使禁用挂载生效!');
288
+ printInfo('正在重启 WSL2 使配置生效...');
287
289
  console.log('');
288
- console.log(' 在 PowerShell 中运行:');
289
- console.log(' ' + C.y + 'wsl --shutdown' + C.nc);
290
- console.log(' 然后重新点击桌面图标启动。');
290
+
291
+ try {
292
+ execSync('wsl --shutdown', { stdio: 'pipe', timeout: 15000 });
293
+ printSuccess('WSL2 已重启');
294
+ } catch {
295
+ printWarning('自动重启失败,请手动运行: wsl --shutdown');
296
+ }
297
+
298
+ // 验证
299
+ console.log('');
300
+ console.log('验证中...');
301
+ try {
302
+ const check = wslExec('ls /mnt/c 2>&1');
303
+ if (!check || check.includes('cannot access') || check.includes('No such file')) {
304
+ printSuccess('验证通过: /mnt/c 不可访问,屏蔽生效!');
305
+ } else {
306
+ printWarning('/mnt/c 仍然可访问,可能需要再次 wsl --shutdown');
307
+ }
308
+ } catch {
309
+ printSuccess('验证通过: /mnt/c 不可访问');
310
+ }
311
+
291
312
  console.log('');
292
- console.log('验证:');
293
- console.log(' - WSL 内 ls /mnt/c → 应显示不存在');
294
- console.log(' - 双击桌面「myclaw」→ 打开工作文件夹');
313
+ printInfo('双击桌面「我的私人龙虾」可打开工作文件夹');
295
314
  console.log('');
296
315
  }
297
316
 
package/start.js CHANGED
@@ -66,6 +66,25 @@ function startWindows() {
66
66
  }
67
67
  console.log('');
68
68
 
69
+ // Step 2.5: 自动检测虚拟机屏蔽(safe)
70
+ console.log('[safe] 虚拟机屏蔽...');
71
+ try {
72
+ const conf = execSync('wsl -d OpenClaw -u root -- cat /etc/wsl.conf 2>/dev/null', {
73
+ encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
74
+ });
75
+ if (conf.includes('enabled = false') || conf.includes('enabled=false')) {
76
+ console.log(' ' + C.g + '[已开启]' + C.nc);
77
+ } else {
78
+ console.log(' ' + C.y + '[未开启,正在启用...]' + C.nc);
79
+ try { execSync('myclaw safe', { stdio: 'inherit', timeout: 30000 }); } catch {}
80
+ }
81
+ } catch {
82
+ // wsl.conf 不存在,说明还没开启
83
+ console.log(' ' + C.y + '[未开启,正在启用...]' + C.nc);
84
+ try { execSync('myclaw safe', { stdio: 'inherit', timeout: 30000 }); } catch {}
85
+ }
86
+ console.log('');
87
+
69
88
  // Step 3: 检查 Gateway
70
89
  console.log('[3/4] Gateway...');
71
90
  let gatewayRunning = false;
package/wsl2.js CHANGED
@@ -506,10 +506,11 @@ function runCliMode() {
506
506
  console.log(' 1. 重新安装 Phase 1 (启用功能 + 下载)');
507
507
  console.log(' 2. 重新安装 Phase 2 (导入 Linux 环境)');
508
508
  console.log(' 3. 重新设置安装包路径');
509
+ console.log(' 4. WSL2虚拟机重装 (强制远程 + 阶段1重启)');
509
510
  console.log(' 0. 退出');
510
511
  console.log('');
511
512
 
512
- const choice = await question('请输入选项 (0-3): ');
513
+ const choice = await question('请输入选项 (0-4): ');
513
514
 
514
515
  switch (choice.trim()) {
515
516
  case '1':
@@ -517,7 +518,7 @@ function runCliMode() {
517
518
  console.log('[' + C.y + '执行' + C.nc + '] 开始 Phase 1 安装...');
518
519
  setState('needs-features');
519
520
  rl.close();
520
- runPhase1();
521
+ runPhase1(false);
521
522
  break;
522
523
 
523
524
  case '2':
@@ -525,7 +526,7 @@ function runCliMode() {
525
526
  console.log('[' + C.y + '执行' + C.nc + '] 开始 Phase 2 安装...');
526
527
  setState('phase1-done');
527
528
  rl.close();
528
- runPhase2();
529
+ runPhase2(false);
529
530
  break;
530
531
 
531
532
  case '3':
@@ -543,6 +544,15 @@ function runCliMode() {
543
544
  rl.close();
544
545
  break;
545
546
 
547
+ case '4':
548
+ console.log('');
549
+ console.log('[' + C.y + '执行' + C.nc + '] WSL2虚拟机重装 (强制远程下载)...');
550
+ console.log('');
551
+ setState('needs-features');
552
+ rl.close();
553
+ runPhase1(true);
554
+ break;
555
+
546
556
  case '0':
547
557
  console.log('');
548
558
  console.log('已退出。');
@@ -626,9 +636,9 @@ function run() {
626
636
  }
627
637
 
628
638
  if (state === 'phase1-done') {
629
- runPhase2();
639
+ runPhase2(forceRemote);
630
640
  } else {
631
- runPhase1();
641
+ runPhase1(forceRemote);
632
642
  }
633
643
  }
634
644