@aiyiran/myclaw 1.0.11 → 1.0.13
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/package.json +1 -1
- package/wsl2.js +87 -69
package/package.json
CHANGED
package/wsl2.js
CHANGED
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
*
|
|
8
8
|
* 使用方式: myclaw wsl2
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* 安装过程中会提示:
|
|
11
|
+
* - 有本地文件?拖拽到窗口 + 回车
|
|
12
|
+
* - 没有?直接回车,从 CDN 下载
|
|
13
13
|
*
|
|
14
|
-
*
|
|
14
|
+
* 自动检测安装状态,分两阶段完成:
|
|
15
|
+
* Phase 1: 启用底层 Windows 功能 + 安装 WSL → 需要重启
|
|
16
|
+
* Phase 2: 导入预制 Linux 环境 → 完成
|
|
15
17
|
* ============================================================================
|
|
16
18
|
*/
|
|
17
19
|
|
|
@@ -19,20 +21,17 @@ const { execSync } = require('child_process');
|
|
|
19
21
|
const os = require('os');
|
|
20
22
|
|
|
21
23
|
// ============================================================================
|
|
22
|
-
// 配置
|
|
24
|
+
// 配置
|
|
23
25
|
// ============================================================================
|
|
24
26
|
|
|
25
27
|
const WSL_CDN = {
|
|
26
|
-
// ★ 新版 WSL 完整安装包(243MB,含内核,替代老的 wsl_update_x64.msi 和 wsl --update)
|
|
27
28
|
wsl: 'https://cdn.yiranlaoshi.com/software/myclaw/wsl.2.7.1.0.x64.msi',
|
|
28
|
-
//
|
|
29
|
-
// TODO: 替换为你自己的 CDN 地址,制作方法见 README
|
|
29
|
+
// TODO: 替换为你自己的 CDN 地址
|
|
30
30
|
rootfs: 'https://openclaw.ai/wsl/openclaw-rootfs.tar',
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
const isWindows = os.platform() === 'win32';
|
|
34
34
|
|
|
35
|
-
// 颜色(Windows 下禁用避免乱码)
|
|
36
35
|
const C = isWindows
|
|
37
36
|
? { r: '', g: '', y: '', b: '', nc: '' }
|
|
38
37
|
: { r: '\x1b[31m', g: '\x1b[32m', y: '\x1b[33m', b: '\x1b[34m', nc: '\x1b[0m' };
|
|
@@ -41,10 +40,6 @@ const C = isWindows
|
|
|
41
40
|
// 工具函数
|
|
42
41
|
// ============================================================================
|
|
43
42
|
|
|
44
|
-
/**
|
|
45
|
-
* 以管理员权限启动 PowerShell 脚本
|
|
46
|
-
* 利用 UTF-16LE Base64 编码避免引号转义地狱
|
|
47
|
-
*/
|
|
48
43
|
function launchElevatedPS(script) {
|
|
49
44
|
const b64 = Buffer.from(script, 'utf16le').toString('base64');
|
|
50
45
|
try {
|
|
@@ -60,33 +55,76 @@ function launchElevatedPS(script) {
|
|
|
60
55
|
}
|
|
61
56
|
}
|
|
62
57
|
|
|
58
|
+
/**
|
|
59
|
+
* 生成「拖拽或回车」的 PowerShell 交互代码片段
|
|
60
|
+
* @param {string} prompt 提示文字
|
|
61
|
+
* @param {string} destVar 目标文件变量名(如 $msi, $tarPath)
|
|
62
|
+
* @param {string} cdnUrl CDN 下载地址
|
|
63
|
+
* @param {string} desc 文件描述(如 "WSL 安装包")
|
|
64
|
+
*/
|
|
65
|
+
function makeAskLocalOrCDN(prompt, destVar, cdnUrl, desc) {
|
|
66
|
+
return `
|
|
67
|
+
Write-Host ''
|
|
68
|
+
Write-Host ' ┌─────────────────────────────────────────┐'
|
|
69
|
+
Write-Host ' │ 如有 ${desc} 的本地文件: │'
|
|
70
|
+
Write-Host ' │ 请将文件拖拽到此窗口,然后按回车 │'
|
|
71
|
+
Write-Host ' │ │'
|
|
72
|
+
Write-Host ' │ 没有?直接按回车,自动从网络下载 │'
|
|
73
|
+
Write-Host ' └─────────────────────────────────────────┘'
|
|
74
|
+
Write-Host ''
|
|
75
|
+
$userInput = Read-Host ' 拖拽文件或直接回车'
|
|
76
|
+
$userInput = $userInput.Trim().Trim('"')
|
|
77
|
+
|
|
78
|
+
if ($userInput -and (Test-Path $userInput)) {
|
|
79
|
+
Write-Host " 使用本地文件: $userInput"
|
|
80
|
+
Copy-Item $userInput ${destVar} -Force
|
|
81
|
+
Write-Host ' [OK]'
|
|
82
|
+
} elseif ($userInput) {
|
|
83
|
+
Write-Host " [警告] 文件不存在: $userInput"
|
|
84
|
+
Write-Host ' 将改为从网络下载...'
|
|
85
|
+
$userInput = ''
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (-Not $userInput) {
|
|
89
|
+
if (-Not (Test-Path ${destVar})) {
|
|
90
|
+
Write-Host ' 正在从网络下载...'
|
|
91
|
+
try {
|
|
92
|
+
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
93
|
+
Invoke-WebRequest -Uri '${cdnUrl}' -OutFile ${destVar} -UseBasicParsing
|
|
94
|
+
Write-Host ' 下载完成!'
|
|
95
|
+
} catch {
|
|
96
|
+
Write-Host ' [失败] 下载失败,请检查网络后重试 myclaw wsl2'
|
|
97
|
+
Write-Host ''; Write-Host '按任意键关闭...'
|
|
98
|
+
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
|
|
99
|
+
exit 1
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
Write-Host ' 使用上次缓存的文件'
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
`;
|
|
106
|
+
}
|
|
107
|
+
|
|
63
108
|
// ============================================================================
|
|
64
109
|
// 状态检测
|
|
65
110
|
// ============================================================================
|
|
66
111
|
|
|
67
|
-
/**
|
|
68
|
-
* 自动检测当前 WSL2 安装状态
|
|
69
|
-
* @returns {'ready'|'needs-setup'|'needs-features'}
|
|
70
|
-
*/
|
|
71
112
|
function detectState() {
|
|
72
|
-
// 1. WSL 已完全可用(有发行版能跑命令)
|
|
73
113
|
try {
|
|
74
114
|
execSync('wsl echo ok', { stdio: 'pipe', timeout: 15000 });
|
|
75
115
|
return 'ready';
|
|
76
116
|
} catch {}
|
|
77
117
|
|
|
78
|
-
// 2. WSL 命令可用但没有发行版(功能已启用,重启后的状态)
|
|
79
118
|
try {
|
|
80
119
|
execSync('wsl --status', { stdio: 'pipe', timeout: 5000 });
|
|
81
120
|
return 'needs-setup';
|
|
82
121
|
} catch {}
|
|
83
122
|
|
|
84
|
-
// 3. WSL 功能未启用
|
|
85
123
|
return 'needs-features';
|
|
86
124
|
}
|
|
87
125
|
|
|
88
126
|
// ============================================================================
|
|
89
|
-
// Phase 1: 启用功能 + 安装 WSL
|
|
127
|
+
// Phase 1: 启用功能 + 安装 WSL
|
|
90
128
|
// ============================================================================
|
|
91
129
|
|
|
92
130
|
function runPhase1() {
|
|
@@ -95,20 +133,25 @@ function runPhase1() {
|
|
|
95
133
|
console.log(' WSL 组件 ' + C.r + '[未安装]' + C.nc);
|
|
96
134
|
console.log(' Linux ' + C.r + '[未安装]' + C.nc);
|
|
97
135
|
console.log('');
|
|
98
|
-
console.log('
|
|
136
|
+
console.log('阶段 1/2: 启用底层功能 + 安装 WSL');
|
|
99
137
|
console.log(' 完成后需要 ' + C.y + '重启电脑' + C.nc);
|
|
100
|
-
console.log(' 重启后再运行 ' + C.y + 'myclaw wsl2' + C.nc + ' 自动进入阶段 2');
|
|
101
138
|
console.log('');
|
|
102
139
|
console.log('[' + C.y + '注意' + C.nc + '] 请在 UAC 弹窗中点击【是】');
|
|
103
140
|
console.log('');
|
|
104
141
|
|
|
142
|
+
const askMsi = makeAskLocalOrCDN(
|
|
143
|
+
'拖拽 WSL 安装包或回车下载',
|
|
144
|
+
'$msi',
|
|
145
|
+
WSL_CDN.wsl,
|
|
146
|
+
'WSL 安装包 (wsl_full.msi)'
|
|
147
|
+
);
|
|
148
|
+
|
|
105
149
|
const ps = `
|
|
106
150
|
$ErrorActionPreference = 'Continue'
|
|
107
151
|
$Host.UI.RawUI.WindowTitle = 'MyClaw WSL2 Installer - Phase 1'
|
|
108
152
|
Write-Host ''
|
|
109
153
|
Write-Host '========================================'
|
|
110
154
|
Write-Host ' MyClaw WSL2 安装 - 阶段 1/2'
|
|
111
|
-
Write-Host ' 启用底层功能 + 安装 WSL 完整包'
|
|
112
155
|
Write-Host '========================================'
|
|
113
156
|
Write-Host ''
|
|
114
157
|
|
|
@@ -124,7 +167,7 @@ try {
|
|
|
124
167
|
}
|
|
125
168
|
Write-Host ''
|
|
126
169
|
|
|
127
|
-
Write-Host '[2/4]
|
|
170
|
+
Write-Host '[2/4] 启用虚拟机平台...'
|
|
128
171
|
try {
|
|
129
172
|
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart | Out-Null
|
|
130
173
|
Write-Host ' [OK]'
|
|
@@ -133,7 +176,8 @@ try {
|
|
|
133
176
|
}
|
|
134
177
|
Write-Host ''
|
|
135
178
|
|
|
136
|
-
Write-Host '[3/4]
|
|
179
|
+
Write-Host '[3/4] 获取 WSL 安装包...'
|
|
180
|
+
$msi = "$dir\\wsl_full.msi"
|
|
137
181
|
$wslInstalled = $false
|
|
138
182
|
try {
|
|
139
183
|
$ver = wsl --version 2>&1 | Out-String
|
|
@@ -141,33 +185,18 @@ try {
|
|
|
141
185
|
} catch {}
|
|
142
186
|
|
|
143
187
|
if ($wslInstalled) {
|
|
144
|
-
Write-Host ' WSL
|
|
188
|
+
Write-Host ' WSL 已安装,跳过'
|
|
145
189
|
Write-Host ' [OK]'
|
|
146
190
|
} else {
|
|
147
|
-
|
|
148
|
-
$msi = "$dir\\wsl_full.msi"
|
|
149
|
-
if (-Not (Test-Path $msi)) {
|
|
150
|
-
try {
|
|
151
|
-
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
152
|
-
Invoke-WebRequest -Uri '${WSL_CDN.wsl}' -OutFile $msi -UseBasicParsing
|
|
153
|
-
Write-Host ' 下载完成!'
|
|
154
|
-
} catch {
|
|
155
|
-
Write-Host ' [失败] 下载失败,请检查网络后重试 myclaw wsl2'
|
|
156
|
-
Write-Host ''; Write-Host '按任意键关闭...'
|
|
157
|
-
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
|
|
158
|
-
exit 1
|
|
159
|
-
}
|
|
160
|
-
} else {
|
|
161
|
-
Write-Host ' 使用上次缓存的文件'
|
|
162
|
-
}
|
|
191
|
+
${askMsi}
|
|
163
192
|
|
|
164
193
|
Write-Host ''
|
|
165
|
-
Write-Host '[4/4] 安装 WSL
|
|
194
|
+
Write-Host '[4/4] 安装 WSL...'
|
|
166
195
|
try {
|
|
167
196
|
Start-Process msiexec.exe -ArgumentList "/i \`"$msi\`" /quiet /norestart" -Wait -NoNewWindow
|
|
168
|
-
Write-Host ' [OK]
|
|
197
|
+
Write-Host ' [OK]'
|
|
169
198
|
} catch {
|
|
170
|
-
Write-Host ' [失败]
|
|
199
|
+
Write-Host ' [失败]'
|
|
171
200
|
Write-Host ''; Write-Host '按任意键关闭...'
|
|
172
201
|
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
|
|
173
202
|
exit 1
|
|
@@ -181,7 +210,6 @@ Write-Host ''
|
|
|
181
210
|
Write-Host ' >>> 请立即 [重启电脑] <<<'
|
|
182
211
|
Write-Host ''
|
|
183
212
|
Write-Host ' 重启后运行: myclaw wsl2'
|
|
184
|
-
Write-Host ' 将自动进入阶段 2 完成安装'
|
|
185
213
|
Write-Host '========================================'
|
|
186
214
|
Write-Host ''
|
|
187
215
|
Write-Host '按任意键关闭此窗口...'
|
|
@@ -206,10 +234,17 @@ function runPhase2() {
|
|
|
206
234
|
console.log(' WSL 组件 ' + C.g + '[OK]' + C.nc);
|
|
207
235
|
console.log(' Linux ' + C.y + '[待安装]' + C.nc);
|
|
208
236
|
console.log('');
|
|
209
|
-
console.log('即将导入预制 Linux
|
|
237
|
+
console.log('即将导入预制 Linux 环境...');
|
|
210
238
|
console.log('[' + C.y + '注意' + C.nc + '] 请在 UAC 弹窗中点击【是】');
|
|
211
239
|
console.log('');
|
|
212
240
|
|
|
241
|
+
const askTar = makeAskLocalOrCDN(
|
|
242
|
+
'拖拽 tar 包或回车下载',
|
|
243
|
+
'$tarPath',
|
|
244
|
+
WSL_CDN.rootfs,
|
|
245
|
+
'Linux 环境包 (openclaw-rootfs.tar)'
|
|
246
|
+
);
|
|
247
|
+
|
|
213
248
|
const ps = `
|
|
214
249
|
$ErrorActionPreference = 'Continue'
|
|
215
250
|
$Host.UI.RawUI.WindowTitle = 'MyClaw WSL2 Installer - Phase 2'
|
|
@@ -217,7 +252,7 @@ Write-Host ''
|
|
|
217
252
|
Write-Host '========================================'
|
|
218
253
|
Write-Host ' MyClaw WSL2 安装 - 阶段 2/2'
|
|
219
254
|
Write-Host ' 导入预制 Linux 环境'
|
|
220
|
-
Write-Host '========================================'
|
|
255
|
+
Write-Host '========================================'
|
|
221
256
|
Write-Host ''
|
|
222
257
|
|
|
223
258
|
$dir = "$env:LOCALAPPDATA\\myclaw"
|
|
@@ -228,27 +263,13 @@ try { wsl --set-default-version 2 2>$null } catch {}
|
|
|
228
263
|
Write-Host ' [OK]'
|
|
229
264
|
Write-Host ''
|
|
230
265
|
|
|
231
|
-
Write-Host '[2/3]
|
|
266
|
+
Write-Host '[2/3] 获取预制 Linux 环境...'
|
|
232
267
|
$tarPath = "$dir\\openclaw-rootfs.tar"
|
|
233
268
|
$distroName = 'OpenClaw'
|
|
234
269
|
$installDir = "$dir\\OpenClaw"
|
|
235
270
|
$installed = $false
|
|
236
271
|
|
|
237
|
-
|
|
238
|
-
Write-Host ' 正在下载预制环境包...'
|
|
239
|
-
try {
|
|
240
|
-
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
241
|
-
Invoke-WebRequest -Uri '${WSL_CDN.rootfs}' -OutFile $tarPath -UseBasicParsing
|
|
242
|
-
Write-Host ' 下载完成!'
|
|
243
|
-
} catch {
|
|
244
|
-
Write-Host ' [失败] 下载失败,请检查网络后重试 myclaw wsl2'
|
|
245
|
-
Write-Host ''; Write-Host '按任意键关闭...'
|
|
246
|
-
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
|
|
247
|
-
exit 1
|
|
248
|
-
}
|
|
249
|
-
} else {
|
|
250
|
-
Write-Host ' 使用上次缓存的文件'
|
|
251
|
-
}
|
|
272
|
+
${askTar}
|
|
252
273
|
|
|
253
274
|
Write-Host ' 正在导入 (可能需要几分钟)...'
|
|
254
275
|
try {
|
|
@@ -279,10 +300,8 @@ if ($installed) {
|
|
|
279
300
|
Write-Host ' [OK] WSL2 + OpenClaw Linux 安装完成!'
|
|
280
301
|
Write-Host ''
|
|
281
302
|
Write-Host ' 输入 wsl 即可进入 Linux 环境'
|
|
282
|
-
Write-Host ' OpenClaw 已预装就绪'
|
|
283
303
|
} else {
|
|
284
|
-
Write-Host ' [失败]
|
|
285
|
-
Write-Host ' 运行: myclaw wsl2'
|
|
304
|
+
Write-Host ' [失败] 请检查后重试: myclaw wsl2'
|
|
286
305
|
}
|
|
287
306
|
Write-Host '========================================'
|
|
288
307
|
Write-Host ''
|
|
@@ -294,7 +313,6 @@ $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
|
|
|
294
313
|
console.log('[' + C.g + '已启动' + C.nc + '] 请查看新弹出的蓝色窗口');
|
|
295
314
|
console.log('');
|
|
296
315
|
console.log('安装完成后,输入 ' + C.y + 'wsl' + C.nc + ' 即可进入 Linux');
|
|
297
|
-
console.log('可随时运行 ' + C.y + 'myclaw wsl2' + C.nc + ' 检查状态');
|
|
298
316
|
console.log('');
|
|
299
317
|
}
|
|
300
318
|
}
|