cicy-desktop 2.1.308 → 2.1.310

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.
@@ -132,6 +132,21 @@ jobs:
132
132
  if ($kfile) { & $oss cp "$($kfile.FullName)" "$kernelKey" -f --acl public-read } else { Write-Warning "kernel not found in msi extract" }
133
133
  } else { Write-Host "WSL2 kernel already on OSS, skip" }
134
134
 
135
+ # 0b) 新版 WSL 的 MSI(一次性,已存在就跳过):老 Win10 自带旧版 WSL 反复死锁,桌面端改为装新版。
136
+ $wslKey = "$base/wsl/wsl.x64.msi"
137
+ & $oss stat "$wslKey" 2>$null | Out-Null
138
+ if ($LASTEXITCODE -ne 0) {
139
+ $rel = Invoke-RestMethod -Uri "https://api.github.com/repos/microsoft/WSL/releases/latest" -Headers @{ "User-Agent" = "cicy-desktop-ci" }
140
+ $asset = $rel.assets | Where-Object { $_.name -match 'x64\.msi$' } | Select-Object -First 1
141
+ if ($asset) {
142
+ Write-Host "Publishing modern WSL $($rel.tag_name) -> $wslKey"
143
+ Invoke-WebRequest -Uri $asset.browser_download_url -OutFile wsl.x64.msi
144
+ & $oss cp "wsl.x64.msi" "$wslKey" -f --acl public-read
145
+ Set-Content -Path wsl-version.txt -Value $rel.tag_name
146
+ & $oss cp "wsl-version.txt" "$base/wsl/version.txt" -f --acl public-read
147
+ } else { Write-Warning "no x64 msi asset in microsoft/WSL latest" }
148
+ } else { Write-Host "modern WSL msi already on OSS, skip" }
149
+
135
150
  # 1) 永久版本化副本(unique key — 不会被后续发版覆盖)
136
151
  $verKey = "$base/cicy-desktop-$version.exe"
137
152
  Write-Host "Uploading versioned -> $verKey"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cicy-desktop",
3
- "version": "2.1.308",
3
+ "version": "2.1.310",
4
4
  "description": "CiCy - AI-powered operating system browser",
5
5
  "main": "src/main.js",
6
6
  "bin": {
@@ -144,10 +144,10 @@
144
144
  "//optionalDependencies": "(2026-06 回调): mac/linux 改回 native cicy-code(:8008,colima 在 16G mac 上压垮内存)→ 重新内置 cicy-code-<plat> / cicy-mihomo-<plat>,localbin.fromBundle 零网络 seed(npm 仅作更新通道,带 npmmirror→npmjs 回退)。这些由 scripts/sync-runtime-deps.cjs 在 tag-push 时同步到最新版。npm 的 os/cpu 字段保证每个平台只装自己那份。Windows 仍走 docker(WSL :8009),它那份 cicy-code-windows 用不到但 bundle 着无害。",
145
145
  "optionalDependencies": {
146
146
  "electron": "41.0.3",
147
- "cicy-code-darwin-x64": "2.3.578",
148
- "cicy-code-darwin-arm64": "2.3.578",
149
- "cicy-code-linux-x64": "2.3.578",
150
- "cicy-code-linux-arm64": "2.3.578",
147
+ "cicy-code-darwin-x64": "2.3.580",
148
+ "cicy-code-darwin-arm64": "2.3.580",
149
+ "cicy-code-linux-x64": "2.3.580",
150
+ "cicy-code-linux-arm64": "2.3.580",
151
151
  "cicy-code-windows-x64": "2.3.193",
152
152
  "cicy-mihomo-darwin-x64": "1.10.4",
153
153
  "cicy-mihomo-darwin-arm64": "1.10.4",
@@ -240,7 +240,21 @@ function register({ sidecarLogPath } = {}) {
240
240
  _wslRepairDone = true;
241
241
  auditDestructiveIpc(log, "docker:self-heal-wsl-wedged", null, { streak: _unknownStreak });
242
242
  log.warn("[docker-daemon] WSL unresponsive for 3 checks → auto repair (kill wsl.exe, restart LxssManager)");
243
- try { const r = await appDocker.repairWsl({ emit: () => {} }); if (r && r.needsReboot) { _lastBootstrapError = { reason: "wsl_wedged", message: "WSL 卡死且服务重启无效,将自动重启 Windows 修复", ts: Date.now() }; scheduleReboot(90); } } catch (e) { log.warn(`[docker-daemon] auto repairWsl failed: ${e.message}`); }
243
+ try {
244
+ const r = await appDocker.repairWsl({ emit: () => {} });
245
+ if (r && r.needsReboot) {
246
+ // 旧版 WSL 死锁且服务重启无效:在重启前先装微软新版 WSL(一次 UAC),重启后就不再走
247
+ // 旧的 LxssManager 路径 —— 否则重启回来还会死锁。装成功时重置重启计数,给新版一次机会。
248
+ const dk = require("../sidecar/docker");
249
+ if (dk.modernWslInstalled && !dk.modernWslInstalled() && dk.elevatedWslSetup) {
250
+ log.warn("[docker-daemon] legacy WSL deadlocked → installing modern WSL before the reboot");
251
+ try { await dk.elevatedWslSetup({ emit: () => {}, need: {} }); } catch (e) { log.warn(`[docker-daemon] modern WSL install failed: ${e.message}`); }
252
+ if (dk.modernWslInstalled()) { try { rebootCount(-99); } catch {} }
253
+ }
254
+ _lastBootstrapError = { reason: "wsl_wedged", message: dk.modernWslInstalled && dk.modernWslInstalled() ? "已安装新版 WSL,将自动重启 Windows 生效" : "WSL 卡死且服务重启无效,将自动重启 Windows 修复", ts: Date.now() };
255
+ scheduleReboot(90);
256
+ }
257
+ } catch (e) { log.warn(`[docker-daemon] auto repairWsl failed: ${e.message}`); }
244
258
  await refreshDockerStatus(); return;
245
259
  }
246
260
  if (_unknownStreak >= 6 && !_rebootScheduled) { _lastBootstrapError = { reason: "wsl_wedged", message: "WSL 持续无响应,将自动重启 Windows 修复", ts: Date.now() }; scheduleReboot(90); }
@@ -612,6 +612,7 @@ function wslExe() {
612
612
  if (process.platform !== "win32") return "wsl";
613
613
  const sysroot = process.env.SystemRoot || process.env.windir || "C:\\Windows";
614
614
  const cands = [
615
+ path.join(process.env.ProgramFiles || "C:\\Program Files", "WSL", "wsl.exe"), // 新版 WSL(MSI),优先
615
616
  path.join(sysroot, "System32", "wsl.exe"),
616
617
  path.join(process.env.LOCALAPPDATA || "", "Microsoft", "WindowsApps", "wsl.exe"),
617
618
  ];
@@ -670,6 +671,18 @@ function featureEnabled(feature) {
670
671
  });
671
672
  }
672
673
 
674
+ // 新版 WSL(微软独立发布的 MSI,Store 版同源):不走旧的 LxssManager、内核内置、`--status` 等命令
675
+ // 齐全、localhost 转发稳定。老 Win10 自带的旧版 WSL 反复死锁/半死/缺内核,全部由它一次解决。
676
+ // MSI 由发布工作流从 GitHub 镜像到 OSS(国内可下)。
677
+ const WSL_MODERN_MSI_URL = process.env.CICY_WSL_MSI_URL || (require("./mirrors").OSS_RELEASES_BASE + "/wsl/wsl.x64.msi");
678
+ function modernWslInstalled() {
679
+ if (process.platform !== "win32") return true;
680
+ try { return fs.existsSync(path.join(process.env.ProgramFiles || "C:\\Program Files", "WSL", "wsl.exe")); } catch { return false; }
681
+ }
682
+ // 这台机器的旧版 WSL 出过死锁/被自动重启过(db/wsl-reboots.json 有计数)→ 下次提权时顺手换新版。
683
+ function legacyWslTroubleSeen() {
684
+ try { const j = JSON.parse(fs.readFileSync(path.join(os.homedir(), "cicy-ai", "db", "wsl-reboots.json"), "utf8")); return (Number(j.count) || 0) > 0; } catch { return false; }
685
+ }
673
686
  const WSL_KERNEL_MSI_URL = process.env.CICY_WSL_KERNEL_URL || "https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi";
674
687
  // 裸内核文件(由发布工作流从 MSI 解出后放到 OSS):精简版 Windows 没有 msiexec 时直接放到位。
675
688
  const WSL_KERNEL_RAW_URL = process.env.CICY_WSL_KERNEL_RAW_URL || (require("./mirrors").OSS_RELEASES_BASE + "/wsl-kernel/kernel");
@@ -750,6 +763,12 @@ function elevatedWslSetup({ emit, need = {} } = {}) {
750
763
  ' & $SFC /scannow | Out-Null; Say ("sfc exit=" + $LASTEXITCODE)',
751
764
  ' foreach ($f in $bad) { $c = En $f }',
752
765
  '}',
766
+ `$MODERN = Join-Path $env:ProgramFiles "WSL\\wsl.exe"`,
767
+ `if (-not (Test-Path $MODERN) -and (Test-Path $MSIEXEC)) {`,
768
+ ` $wm = Join-Path $env:USERPROFILE "Downloads\\wsl.x64.msi"`,
769
+ ` Say "installing modern WSL (replaces the legacy inbox WSL: no LxssManager deadlocks, kernel built in) — download ~250MB"`,
770
+ ` try { if (-not (Test-Path $wm) -or (Get-Item $wm).Length -lt 100000000) { Invoke-WebRequest -UseBasicParsing -Uri "${WSL_MODERN_MSI_URL}" -OutFile $wm }; $p = Start-Process $MSIEXEC -ArgumentList "/i","\`"$wm\`"","/qn","/norestart" -Wait -PassThru; Say ("modern wsl msi exit=" + $p.ExitCode) } catch { Say ("modern wsl install failed: " + $_.Exception.Message) }`,
771
+ `}`,
753
772
  `$KDIR = Join-Path $S32 "lxss\\tools"; $KFILE = Join-Path $KDIR "kernel"`,
754
773
  `if (-not (Test-Path $KFILE)) {`,
755
774
  ` if ((Test-Path $MSIEXEC) -and (Test-Path "${msi.replace(/"/g, '""')}")) { $p = Start-Process $MSIEXEC -ArgumentList "/i","\`"${msi.replace(/"/g, '""')}\`"","/qn","/norestart" -Wait -PassThru; Say ("kernel msi exit=" + $p.ExitCode) }`,
@@ -849,10 +868,20 @@ async function ensureWsl({ emit } = {}) {
849
868
  // 功能都已启用、wsl.exe 也在,但 WSL 本身还不能用(`wsl -l -v` 只打印帮助)= 启用后还没
850
869
  // 重启。别去 --import(必失败),直接进自动重启流程。
851
870
  if (!(await wslFunctional())) {
871
+ if (!modernWslInstalled() && legacyWslTroubleSeen()) {
872
+ // 旧版 WSL 已经死锁/重启过 → 别再等它,换新版 WSL(一次 UAC),装完重启。
873
+ emit && emit({ phase: "install-docker", status: "running", message: "旧版 WSL 反复无响应,改为安装微软新版 WSL(会弹一次 UAC,请点「是」,下载约 250MB)…" });
874
+ await elevatedWslSetup({ emit, need: {} });
875
+ }
852
876
  log.warn("[bootstrap] ensure-wsl: features enabled but WSL not functional yet (pending reboot)");
853
877
  emit && emit({ phase: "install-docker", status: "running", message: "WSL 功能已启用但尚未生效,需要重启 Windows…" });
854
878
  return { ok: false, needsReboot: true };
855
879
  }
880
+ if (!modernWslInstalled() && legacyWslTroubleSeen()) {
881
+ emit && emit({ phase: "install-docker", status: "running", message: "这台机器的旧版 WSL 出过死锁,升级为微软新版 WSL(会弹一次 UAC,下载约 250MB)…" });
882
+ await elevatedWslSetup({ emit, need: {} });
883
+ if (modernWslInstalled()) { emit && emit({ phase: "install-docker", status: "running", message: "新版 WSL 已安装,需要重启 Windows 生效…" }); return { ok: false, needsReboot: true }; }
884
+ }
856
885
  // WSL2 内核(lxss\tools\kernel)缺失时 --import 也必失败。先把 MSI 下到 Downloads,再用
857
886
  // 同一个提权脚本装(功能已启用的话脚本只做装内核这一件事)。
858
887
  if (!wslKernelPresent()) {
@@ -988,7 +1017,7 @@ module.exports = {
988
1017
  start, stop, stopContainer, restart, checkStatus, loadImage, loadImageFromTarball,
989
1018
  downloadImageTarball, imagePresent, dockerOk, installDocker,
990
1019
  bootstrap, probeHealth, readContainerToken, dockerDesktopExe, desktopDir, downloadsDir, imageTarballPath,
991
- launchElevated, elevatedWslSetup, spawnProbe, wslFunctional, wslKernelPresent, wslExe, wslMissing, ensureWsl, virtualizationStatus,
1020
+ launchElevated, elevatedWslSetup, modernWslInstalled, spawnProbe, wslFunctional, wslKernelPresent, wslExe, wslMissing, ensureWsl, virtualizationStatus,
992
1021
  // platform-agnostic download/retry primitives, reused by native.js
993
1022
  ensureDownloaded, curlDownload, withRetry, waitUntil, run, headSize,
994
1023
  // image freshness (修「重建仍用旧镜像」—— 校验 OSS ETag 变了才重下重载)
@@ -146,3 +146,17 @@ test("streamed wsl runs flag an unreachable VM too, and soft failures back off 2
146
146
  assert.match(w, /err\.code > 255\)/);
147
147
  assert.match(read("src/backends/sidecar-ipc.js"), /_softRetryAt = Date\.now\(\) \+ 2 \* 60 \* 1000;/);
148
148
  });
149
+
150
+ test("legacy WSL trouble → install modern WSL (MSI mirrored to OSS) in the single elevation; wslExe prefers it", () => {
151
+ const d = read("src/sidecar/docker.js");
152
+ assert.match(d, /function modernWslInstalled\(\)/);
153
+ assert.match(d, /function legacyWslTroubleSeen\(\)/);
154
+ assert.match(d, /"WSL", "wsl\.exe"\), \/\/ 新版 WSL/);
155
+ assert.match(d, /installing modern WSL/);
156
+ assert.match(d, /if \(!modernWslInstalled\(\) && legacyWslTroubleSeen\(\)\) \{/);
157
+ assert.match(read(".github/workflows/windows-exe-release.yml"), /wsl\/wsl\.x64\.msi/);
158
+ });
159
+
160
+ test("a deadlocked legacy WSL gets modern WSL installed before the automatic reboot", () => {
161
+ assert.match(read("src/backends/sidecar-ipc.js"), /legacy WSL deadlocked → installing modern WSL before the reboot/);
162
+ });