@aiyiran/myclaw 1.0.164 → 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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/restrict.js +68 -49
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiyiran/myclaw",
3
- "version": "1.0.164",
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