cicy-desktop 2.1.101 → 2.1.102

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cicy-desktop",
3
- "version": "2.1.101",
3
+ "version": "2.1.102",
4
4
  "description": "CiCy - AI-powered operating system browser",
5
5
  "main": "src/main.js",
6
6
  "bin": {
@@ -8,7 +8,7 @@
8
8
  // https://r2.deepfetch.de5.net/docker/cicy-code-latest.tar.gz
9
9
  //
10
10
  // The container maps :8008 and persists ~/cicy-ai in a named volume.
11
- const { execFile, spawn } = require("child_process");
11
+ const { execFile, execFileSync, spawn } = require("child_process");
12
12
  const https = require("https");
13
13
  const http = require("http");
14
14
  const fs = require("fs");
@@ -449,6 +449,35 @@ function launchElevated(exe, args, { emit } = {}) {
449
449
  });
450
450
  }
451
451
 
452
+ // Docker Desktop on Windows needs a WSL2 (or Hyper-V) backend — without it the
453
+ // engine never starts and `docker version` can't reach the daemon, so the card
454
+ // hangs on "正在启动 Docker Desktop". Detect a missing WSL. `wsl` prints UTF-16
455
+ // and a fresh Windows without the feature says "未安装 / not installed / can be
456
+ // installed by running wsl.exe --install".
457
+ function wslMissing() {
458
+ if (process.platform !== "win32") return false;
459
+ try {
460
+ const out = execFileSync("wsl", ["--status"], { timeout: 8000, windowsHide: true, encoding: "utf16le", stdio: ["ignore", "pipe", "pipe"] });
461
+ return /未安装|not installed|--install/i.test(String(out));
462
+ } catch (e) {
463
+ const s = String((e.stdout || "") + (e.stderr || ""));
464
+ if (/未安装|not installed|--install/i.test(s)) return true;
465
+ return false; // wsl present but errored for another reason — assume OK
466
+ }
467
+ }
468
+
469
+ // Ensure the WSL2 backend exists; install it (elevated) if missing. Returns
470
+ // { ok } when present, or { needsReboot } after kicking off `wsl --install`
471
+ // (which requires admin + a Windows reboot before Docker can use it).
472
+ async function ensureWsl({ emit } = {}) {
473
+ if (!wslMissing()) return { ok: true };
474
+ emit && emit({ phase: "install-docker", status: "running", message: "Docker 需要 WSL2 后端,正在安装 WSL(请在管理员授权框点「是」,装完需重启 Windows)…" });
475
+ // --no-distribution: just the WSL2 platform (Docker brings its own distro);
476
+ // falls back to plain `wsl --install` on older builds that reject the flag.
477
+ await launchElevated("wsl", ["--install", "--no-distribution"], { emit });
478
+ return { ok: false, needsReboot: true };
479
+ }
480
+
452
481
  // One-shot, idempotent, resumable bootstrap of the whole local-team stack on
453
482
  // Windows: install Docker (if missing) → load the base image (if missing) →
454
483
  // start the container → wait for :8008. Every step CHECKS first and SKIPS if
@@ -470,10 +499,14 @@ async function bootstrap({ onProgress, port = 8008, container = CONTAINER, volum
470
499
  // re-download/re-run the installer (主人: 装了就别再下 Docker Desktop 了).
471
500
  emit({ phase: "install-docker", status: "running", message: "Docker 已安装,正在启动 Docker Desktop…" });
472
501
  if (needImage) imgDl = downloadImageTarball({ emit }).catch((e) => { emit({ phase: "image", status: "error", message: `镜像下载失败:${e.message}` }); return null; });
502
+ // Docker Desktop installed but the engine needs the WSL2 backend — install
503
+ // it (elevated) if missing; it requires a reboot before the daemon can run.
504
+ const wsl1 = await ensureWsl({ emit });
505
+ if (wsl1.needsReboot) { emit({ phase: "install-docker", status: "error", message: "WSL2 正在安装——装好后请【重启 Windows】,重启后回来点「重试」即可继续。" }); return { ok: false, reason: "wsl_reboot_required" }; }
473
506
  startDockerDesktop();
474
507
  const up = await waitUntil(dockerOk, { totalMs: 300000, everyMs: 5000 });
475
508
  if (!up) {
476
- emit({ phase: "install-docker", status: "error", message: "Docker Desktop 启动超时——手动打开它等图标变绿,再点「重试」" });
509
+ emit({ phase: "install-docker", status: "error", message: "Docker Desktop 启动超时——确认 Docker 图标变绿(首次可能要重启 Windows),再点「重试」" });
477
510
  return { ok: false, reason: "docker_not_ready" };
478
511
  }
479
512
  emit({ phase: "install-docker", status: "done", message: "Docker 就绪" });
@@ -482,6 +515,9 @@ async function bootstrap({ onProgress, port = 8008, container = CONTAINER, volum
482
515
  // running + the daemon coming up (主人: 装 Docker 的同时下载 R2 镜像).
483
516
  if (needImage) imgDl = downloadImageTarball({ emit }).catch((e) => { emit({ phase: "image", status: "error", message: `镜像下载失败:${e.message}` }); return null; });
484
517
  await installDocker({ emit, dest: installDest });
518
+ // Docker Desktop needs WSL2 — install it (elevated) if missing; reboot first.
519
+ const wsl2 = await ensureWsl({ emit });
520
+ if (wsl2.needsReboot) { emit({ phase: "install-docker", status: "error", message: "Docker 和 WSL2 已装好——请【重启 Windows】,重启后回来点「重试」即可继续。" }); return { ok: false, reason: "wsl_reboot_required" }; }
485
521
  // A silent install doesn't auto-launch the daemon — explicitly start Docker
486
522
  // Desktop once its exe lands so the user doesn't have to (主人: 安装启动有问题).
487
523
  emit({ phase: "install-docker", status: "running", message: "启动 Docker Desktop…" });