@aiyiran/myclaw 1.0.170 → 1.0.172
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 +22 -1
- package/package.json +1 -1
- package/restrict.js +38 -200
package/index.js
CHANGED
|
@@ -461,12 +461,25 @@ if (-not (Test-Path '${iconPath.replace(/\\/g, '\\\\')}')) {
|
|
|
461
461
|
}
|
|
462
462
|
$ws = New-Object -ComObject WScript.Shell
|
|
463
463
|
$sc = $ws.CreateShortcut('${lnkPath.replace(/\\/g, '\\\\')}')
|
|
464
|
-
$sc.TargetPath = '${batPath.replace(/\\/g, '\\\\')}'
|
|
464
|
+
$sc.TargetPath = '${batPath.replace(/\\/g, '\\\\')}'
|
|
465
465
|
$sc.WorkingDirectory = '${myClawDir.replace(/\\/g, '\\\\')}'
|
|
466
466
|
$sc.WindowStyle = 1
|
|
467
467
|
$sc.IconLocation = '${iconPath.replace(/\\/g, '\\\\')}'
|
|
468
468
|
$sc.Description = 'OpenClaw'
|
|
469
469
|
$sc.Save()
|
|
470
|
+
|
|
471
|
+
# 创建「我的私人龙虾」工作目录快捷方式(如不存在)
|
|
472
|
+
$workspaceLnk = '${desktopPath}\\我的私人龙虾.lnk'
|
|
473
|
+
if (-not (Test-Path $workspaceLnk)) {
|
|
474
|
+
$ws2 = New-Object -ComObject WScript.Shell
|
|
475
|
+
$sc2 = $ws2.CreateShortcut($workspaceLnk)
|
|
476
|
+
$sc2.TargetPath = '\\\\wsl.localhost\\OpenClaw\\root\\.openclaw\\workspace'
|
|
477
|
+
$sc2.WorkingDirectory = '\\\\wsl.localhost\\OpenClaw\\root\\.openclaw\\workspace'
|
|
478
|
+
$sc2.Description = 'OpenClaw Workspace'
|
|
479
|
+
$sc2.IconLocation = 'C:\\Windows\\System32\\SHELL32.dll,4'
|
|
480
|
+
$sc2.Save()
|
|
481
|
+
}
|
|
482
|
+
|
|
470
483
|
Add-Type -TypeDefinition 'using System; using System.Runtime.InteropServices; public class Shell { [DllImport("shell32.dll")] public static extern void SHChangeNotify(int e, int f, IntPtr i1, IntPtr i2); }' -ErrorAction SilentlyContinue
|
|
471
484
|
[Shell]::SHChangeNotify(0x08000000, 0, [IntPtr]::Zero, [IntPtr]::Zero)
|
|
472
485
|
`;
|
|
@@ -1002,6 +1015,14 @@ const MENU_ITEMS = [
|
|
|
1002
1015
|
{ key: 'patch', label: '修复', cmd: 'mc patch', desc: '给 AI 助手装上新技能和好看的外衣', action: runPatch },
|
|
1003
1016
|
{ key: 'reinstall', label: '重装', cmd: 'mc longxia', desc: '出了大问题?把 AI 助手删了重新安装', action: runReinstall },
|
|
1004
1017
|
{ key: 'uninstall', label: '卸载', cmd: 'mc uninstall', desc: '卸载 MyClaw,恢复 npm 源地址', action: runUninstall },
|
|
1018
|
+
{ key: 'wsl2reinstall', label: 'WSL2虚拟机重装', cmd: 'mc wsl2 --remote', desc: '强制从网络重新下载并重装 WSL2 虚拟机(仅限 Windows)', action: () => {
|
|
1019
|
+
const wsl2 = require('./wsl2');
|
|
1020
|
+
wsl2.run();
|
|
1021
|
+
}},
|
|
1022
|
+
{ key: 'safe', label: '虚拟机屏蔽', cmd: 'mc safe', desc: '禁止 WSL2 访问 Windows 盘符(仅限 Windows)', action: () => {
|
|
1023
|
+
const restrict = require('./restrict');
|
|
1024
|
+
restrict.run();
|
|
1025
|
+
}},
|
|
1005
1026
|
{ key: 'quit', label: '退出', cmd: 'Ctrl+C', desc: '不玩了,下次见', action: () => { console.log(' 👋 再见!\n'); process.exit(0); } },
|
|
1006
1027
|
];
|
|
1007
1028
|
|
package/package.json
CHANGED
package/restrict.js
CHANGED
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* ============================================================================
|
|
5
|
-
* MyClaw
|
|
5
|
+
* MyClaw 虚拟机屏蔽(Windows 侧)
|
|
6
6
|
* ============================================================================
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* 步骤 2: 编辑 /etc/wsl.conf 禁用 automount(Linux 看不到 Windows 盘符)
|
|
11
|
-
* 步骤 3: 在 Windows 桌面创建快捷方式,指向 \\wsl.localhost\OpenClaw\root\.openclaw\workspace
|
|
8
|
+
* 只做一件事:禁用 WSL2 自动挂载 Windows 盘符
|
|
9
|
+
* 如果已经开启,直接跳过。
|
|
12
10
|
*
|
|
13
11
|
* 使用方法:
|
|
14
12
|
* myclaw safe
|
|
@@ -22,10 +20,6 @@ const os = require('os');
|
|
|
22
20
|
const fs = require('fs');
|
|
23
21
|
const path = require('path');
|
|
24
22
|
|
|
25
|
-
// ============================================================================
|
|
26
|
-
// 配置
|
|
27
|
-
// ============================================================================
|
|
28
|
-
|
|
29
23
|
const isWindows = os.platform() === 'win32';
|
|
30
24
|
|
|
31
25
|
const C = isWindows
|
|
@@ -33,46 +27,33 @@ const C = isWindows
|
|
|
33
27
|
: { r: '\x1b[31m', g: '\x1b[32m', y: '\x1b[33m', b: '\x1b[34m', nc: '\x1b[0m' };
|
|
34
28
|
|
|
35
29
|
const DISTRO_NAME = 'OpenClaw';
|
|
36
|
-
const WORKSPACE_PATH = '/root/.openclaw/workspace/myclaw';
|
|
37
|
-
const SHORTCUT_TARGET = '/root/.openclaw/workspace';
|
|
38
|
-
|
|
39
|
-
// ============================================================================
|
|
40
|
-
// 工具函数
|
|
41
|
-
// ============================================================================
|
|
42
30
|
|
|
43
|
-
function printStep(msg) { console.log(C.g + '==>' + C.nc + ' ' + msg); }
|
|
44
31
|
function printInfo(msg) { console.log(C.b + '[信息]' + C.nc + ' ' + msg); }
|
|
45
32
|
function printSuccess(msg) { console.log(C.g + '[成功]' + C.nc + ' ' + msg); }
|
|
46
33
|
function printWarning(msg) { console.log(C.y + '[警告]' + C.nc + ' ' + msg); }
|
|
47
34
|
function printError(msg) { console.error(C.r + '[错误]' + C.nc + ' ' + msg); }
|
|
48
35
|
|
|
49
|
-
// 在 WSL
|
|
36
|
+
// 在 WSL 中执行命令
|
|
50
37
|
function wslExec(cmd) {
|
|
51
38
|
try {
|
|
52
39
|
return execSync('wsl -d ' + DISTRO_NAME + ' -- bash -c "' + cmd + '"', {
|
|
53
|
-
encoding: 'utf8',
|
|
54
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
40
|
+
encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
|
|
55
41
|
}).trim();
|
|
56
42
|
} catch {
|
|
57
43
|
return null;
|
|
58
44
|
}
|
|
59
45
|
}
|
|
60
46
|
|
|
61
|
-
//
|
|
62
|
-
// 避免 cmd.exe 转义问题:脚本内容通过文件传递,不走命令行
|
|
47
|
+
// 通过临时脚本文件以 root 执行(只在 automount 未禁用时可用)
|
|
63
48
|
function wslRunScriptAsRoot(scriptContent) {
|
|
64
49
|
const tmpDir = path.join(process.env.LOCALAPPDATA || os.tmpdir(), 'myclaw');
|
|
65
50
|
try { fs.mkdirSync(tmpDir, { recursive: true }); } catch {}
|
|
66
51
|
const scriptFile = path.join(tmpDir, 'safe-setup.sh');
|
|
67
52
|
fs.writeFileSync(scriptFile, scriptContent, 'utf8');
|
|
68
|
-
|
|
69
|
-
// Windows 路径转 WSL 路径: C:\Users\... → /mnt/c/Users/...
|
|
70
53
|
const wslPath = '/mnt/' + scriptFile.charAt(0).toLowerCase() + scriptFile.slice(2).replace(/\\/g, '/');
|
|
71
|
-
|
|
72
54
|
try {
|
|
73
55
|
execSync('wsl -d ' + DISTRO_NAME + ' -u root -- bash ' + wslPath, {
|
|
74
|
-
encoding: 'utf8',
|
|
75
|
-
stdio: 'pipe',
|
|
56
|
+
encoding: 'utf8', stdio: 'pipe',
|
|
76
57
|
});
|
|
77
58
|
return true;
|
|
78
59
|
} catch {
|
|
@@ -80,76 +61,59 @@ function wslRunScriptAsRoot(scriptContent) {
|
|
|
80
61
|
}
|
|
81
62
|
}
|
|
82
63
|
|
|
64
|
+
// 检测是否已开启
|
|
65
|
+
function isAlreadySafe() {
|
|
66
|
+
const conf = wslExec('cat /etc/wsl.conf 2>/dev/null') || '';
|
|
67
|
+
return conf.includes('enabled = false') || conf.includes('enabled=false');
|
|
68
|
+
}
|
|
69
|
+
|
|
83
70
|
// ============================================================================
|
|
84
|
-
//
|
|
71
|
+
// 主函数
|
|
85
72
|
// ============================================================================
|
|
86
73
|
|
|
87
|
-
function
|
|
74
|
+
function run() {
|
|
88
75
|
if (!isWindows) {
|
|
89
76
|
printError('此命令只能在 Windows 上运行');
|
|
90
77
|
process.exit(1);
|
|
91
78
|
}
|
|
92
79
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
} catch {
|
|
80
|
+
// 检查 WSL + OpenClaw
|
|
81
|
+
try { execSync('wsl --version', { stdio: 'pipe' }); } catch {
|
|
96
82
|
printError('未检测到 WSL。请先运行: myclaw wsl2');
|
|
97
83
|
process.exit(1);
|
|
98
84
|
}
|
|
99
|
-
|
|
100
85
|
try {
|
|
101
86
|
const list = execSync('wsl -l -q', { encoding: 'utf16le' });
|
|
102
87
|
if (!list.includes(DISTRO_NAME)) {
|
|
103
|
-
printError('未找到 ' + DISTRO_NAME + '
|
|
88
|
+
printError('未找到 ' + DISTRO_NAME + ' 发行版');
|
|
104
89
|
process.exit(1);
|
|
105
90
|
}
|
|
106
91
|
} catch {
|
|
107
|
-
printError('无法读取 WSL
|
|
92
|
+
printError('无法读取 WSL 发行版列表');
|
|
108
93
|
process.exit(1);
|
|
109
94
|
}
|
|
110
95
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
// 步骤 1: 在 WSL 内创建工作目录
|
|
116
|
-
// ============================================================================
|
|
117
|
-
|
|
118
|
-
function step1_createWorkspace() {
|
|
119
|
-
printStep('步骤 1/3: 在 WSL 内创建工作目录');
|
|
120
|
-
|
|
121
|
-
const ok = wslExec('mkdir -p ' + WORKSPACE_PATH + ' && echo ok');
|
|
122
|
-
|
|
123
|
-
if (!ok || !ok.includes('ok')) {
|
|
124
|
-
printError('创建工作目录失败');
|
|
125
|
-
return false;
|
|
96
|
+
// 已开启则跳过
|
|
97
|
+
if (isAlreadySafe()) {
|
|
98
|
+
printSuccess('虚拟机屏蔽已开启,无需重复执行');
|
|
99
|
+
return true;
|
|
126
100
|
}
|
|
127
101
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
// ============================================================================
|
|
133
|
-
// 步骤 2: 禁用 automount — 写 /etc/wsl.conf
|
|
134
|
-
// ============================================================================
|
|
102
|
+
// 创建工作目录
|
|
103
|
+
printInfo('创建工作目录...');
|
|
104
|
+
wslExec('mkdir -p /root/.openclaw/workspace/myclaw');
|
|
135
105
|
|
|
136
|
-
|
|
137
|
-
|
|
106
|
+
// 写入 /etc/wsl.conf
|
|
107
|
+
printInfo('正在禁用自动挂载...');
|
|
138
108
|
|
|
139
|
-
// 读取现有配置
|
|
140
109
|
const existing = wslExec('cat /etc/wsl.conf 2>/dev/null') || '';
|
|
141
|
-
|
|
142
110
|
let newContent;
|
|
143
111
|
if (existing.includes('[automount]')) {
|
|
144
|
-
newContent = existing.replace(
|
|
145
|
-
/\[automount\][^\[]*/,
|
|
146
|
-
'[automount]\nenabled = false\n'
|
|
147
|
-
);
|
|
112
|
+
newContent = existing.replace(/\[automount\][^\[]*/, '[automount]\nenabled = false\n');
|
|
148
113
|
} else {
|
|
149
114
|
newContent = existing + (existing.endsWith('\n') ? '' : '\n') + '[automount]\nenabled = false\n';
|
|
150
115
|
}
|
|
151
116
|
|
|
152
|
-
// 构建一个完整的 shell 脚本,在 WSL 内执行
|
|
153
117
|
const script = [
|
|
154
118
|
'#!/bin/bash',
|
|
155
119
|
'cp /etc/wsl.conf /etc/wsl.conf.bak 2>/dev/null || true',
|
|
@@ -158,157 +122,31 @@ function step2_disableAutomount() {
|
|
|
158
122
|
'MYCLAW_EOF',
|
|
159
123
|
].join('\n');
|
|
160
124
|
|
|
161
|
-
printInfo('正在写入 /etc/wsl.conf ...');
|
|
162
125
|
const ok = wslRunScriptAsRoot(script);
|
|
163
|
-
|
|
164
126
|
if (!ok) {
|
|
165
127
|
printError('写入 wsl.conf 失败');
|
|
166
128
|
return false;
|
|
167
129
|
}
|
|
168
130
|
|
|
169
131
|
// 验证
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
printSuccess('automount 已禁用');
|
|
173
|
-
printInfo('/etc/wsl.conf 内容:');
|
|
174
|
-
console.log('---');
|
|
175
|
-
console.log(verify);
|
|
176
|
-
console.log('---');
|
|
177
|
-
return true;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
printError('配置验证失败,写入可能不完整');
|
|
181
|
-
printInfo('实际内容:');
|
|
182
|
-
console.log(verify || '(空)');
|
|
183
|
-
return false;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// ============================================================================
|
|
187
|
-
// 步骤 3: 在桌面创建快捷方式
|
|
188
|
-
// ============================================================================
|
|
189
|
-
|
|
190
|
-
function step3_createShortcut() {
|
|
191
|
-
printStep('步骤 3/3: 创建桌面快捷方式');
|
|
192
|
-
|
|
193
|
-
const wslPath = '\\\\wsl.localhost\\' + DISTRO_NAME + '\\' + SHORTCUT_TARGET.replace(/\//g, '\\');
|
|
194
|
-
|
|
195
|
-
const desktopPath = path.join(os.homedir(), 'Desktop');
|
|
196
|
-
const desktopPathCN = path.join(os.homedir(), '桌面');
|
|
197
|
-
const shortcutDir = fs.existsSync(desktopPath) ? desktopPath
|
|
198
|
-
: fs.existsSync(desktopPathCN) ? desktopPathCN : null;
|
|
199
|
-
|
|
200
|
-
if (!shortcutDir) {
|
|
201
|
-
printError('找不到桌面目录');
|
|
132
|
+
if (!isAlreadySafe()) {
|
|
133
|
+
printError('配置验证失败');
|
|
202
134
|
return false;
|
|
203
135
|
}
|
|
204
136
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const tmpDir = path.join(process.env.LOCALAPPDATA || os.tmpdir(), 'myclaw');
|
|
208
|
-
try { fs.mkdirSync(tmpDir, { recursive: true }); } catch {}
|
|
209
|
-
const psFile = path.join(tmpDir, 'create-shortcut.ps1');
|
|
210
|
-
|
|
211
|
-
const psContent = [
|
|
212
|
-
'$ws = New-Object -ComObject WScript.Shell',
|
|
213
|
-
'$sc = $ws.CreateShortcut("' + shortcutPath + '")',
|
|
214
|
-
'$sc.TargetPath = "' + wslPath + '"',
|
|
215
|
-
'$sc.WorkingDirectory = "' + wslPath + '"',
|
|
216
|
-
'$sc.Description = "OpenClaw Workspace"',
|
|
217
|
-
'$sc.IconLocation = "C:\\Windows\\System32\\SHELL32.dll,4"',
|
|
218
|
-
'$sc.Save()',
|
|
219
|
-
'',
|
|
220
|
-
'Write-Host "OK"',
|
|
221
|
-
].join('\r\n');
|
|
222
|
-
|
|
223
|
-
fs.writeFileSync(psFile, '\uFEFF' + psContent, 'utf8');
|
|
224
|
-
|
|
225
|
-
try {
|
|
226
|
-
const result = execSync(
|
|
227
|
-
'powershell -NoProfile -ExecutionPolicy Bypass -File "' + psFile + '"',
|
|
228
|
-
{ encoding: 'utf8', stdio: 'pipe' }
|
|
229
|
-
).trim();
|
|
230
|
-
|
|
231
|
-
if (result.includes('OK')) {
|
|
232
|
-
printSuccess('桌面快捷方式已创建: 我的私人龙虾');
|
|
233
|
-
printInfo('双击即可打开工作目录');
|
|
234
|
-
return true;
|
|
235
|
-
}
|
|
236
|
-
} catch {
|
|
237
|
-
try {
|
|
238
|
-
const urlContent = '[InternetShortcut]\r\nURL=file:///' + wslPath.replace(/\\/g, '/') + '\r\n';
|
|
239
|
-
fs.writeFileSync(path.join(shortcutDir, '我的私人龙虾.url'), urlContent, 'utf8');
|
|
240
|
-
printSuccess('桌面快捷方式已创建 (.url)');
|
|
241
|
-
return true;
|
|
242
|
-
} catch (err2) {
|
|
243
|
-
printError('创建快捷方式失败: ' + err2.message);
|
|
244
|
-
return false;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return false;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// ============================================================================
|
|
252
|
-
// 主函数
|
|
253
|
-
// ============================================================================
|
|
254
|
-
|
|
255
|
-
function run() {
|
|
256
|
-
console.log('');
|
|
257
|
-
console.log('========================================');
|
|
258
|
-
console.log(' MyClaw 虚拟机屏蔽');
|
|
259
|
-
console.log('========================================');
|
|
260
|
-
console.log('');
|
|
261
|
-
console.log('此操作将:');
|
|
262
|
-
console.log(' 1. 在 WSL 内创建工作目录');
|
|
263
|
-
console.log(' 2. 禁用 WSL 自动挂载 Windows 盘符');
|
|
264
|
-
console.log(' 3. 在桌面创建快捷方式');
|
|
265
|
-
console.log('');
|
|
266
|
-
console.log('效果:Linux 看不到 Windows 文件,但 Windows');
|
|
267
|
-
console.log(' 可以通过桌面快捷方式访问 WSL 工作目录。');
|
|
268
|
-
console.log('');
|
|
269
|
-
|
|
270
|
-
checkPrerequisites();
|
|
271
|
-
|
|
272
|
-
if (!step1_createWorkspace()) { printError('步骤 1 失败'); process.exit(1); }
|
|
273
|
-
|
|
274
|
-
if (!step2_disableAutomount()) { printError('步骤 2 失败'); process.exit(1); }
|
|
275
|
-
|
|
276
|
-
if (!step3_createShortcut()) {
|
|
277
|
-
printWarning('快捷方式创建失败,但不影响权限封锁');
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
console.log('');
|
|
281
|
-
console.log('========================================');
|
|
282
|
-
printSuccess('虚拟机屏蔽配置完成!');
|
|
283
|
-
console.log('========================================');
|
|
284
|
-
console.log('');
|
|
285
|
-
printInfo('正在重启 WSL2 使配置生效...');
|
|
286
|
-
console.log('');
|
|
137
|
+
printSuccess('automount 已禁用');
|
|
287
138
|
|
|
139
|
+
// 重启 WSL 使配置生效
|
|
140
|
+
printInfo('正在重启 WSL2...');
|
|
288
141
|
try {
|
|
289
142
|
execSync('wsl --shutdown', { stdio: 'pipe', timeout: 15000 });
|
|
290
143
|
printSuccess('WSL2 已重启');
|
|
291
144
|
} catch {
|
|
292
|
-
printWarning('
|
|
145
|
+
printWarning('请手动运行: wsl --shutdown');
|
|
293
146
|
}
|
|
294
147
|
|
|
295
|
-
|
|
296
|
-
console.log('');
|
|
297
|
-
console.log('验证中...');
|
|
298
|
-
try {
|
|
299
|
-
const check = wslExec('ls /mnt/c 2>&1');
|
|
300
|
-
if (!check || check.includes('cannot access') || check.includes('No such file')) {
|
|
301
|
-
printSuccess('验证通过: /mnt/c 不可访问,屏蔽生效!');
|
|
302
|
-
} else {
|
|
303
|
-
printWarning('/mnt/c 仍然可访问,可能需要再次 wsl --shutdown');
|
|
304
|
-
}
|
|
305
|
-
} catch {
|
|
306
|
-
printSuccess('验证通过: /mnt/c 不可访问');
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
console.log('');
|
|
310
|
-
printInfo('双击桌面「我的私人龙虾」可打开工作文件夹');
|
|
311
|
-
console.log('');
|
|
148
|
+
return true;
|
|
312
149
|
}
|
|
313
150
|
|
|
314
|
-
|
|
151
|
+
// 导出检测函数供 start.js 使用
|
|
152
|
+
module.exports = { run, isAlreadySafe };
|