cicy-desktop 2.1.304 → 2.1.306

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.304",
3
+ "version": "2.1.306",
4
4
  "description": "CiCy - AI-powered operating system browser",
5
5
  "main": "src/main.js",
6
6
  "bin": {
@@ -90,12 +90,24 @@ async function ensureWslKernel({ emit } = {}) {
90
90
  // Run a bash command as root inside the distro. execFile (no host shell) → the
91
91
  // command string is passed verbatim to `bash -lc`, so only bash-level quoting
92
92
  // matters inside `cmd`.
93
+ // wsl.exe 连不上发行版的 VM(注册了、显示 Running,但 init 不可达):任何 `wsl -d` 立刻以
94
+ // 4294967295(-1)退出,stdout 是 UTF-16 的 Windows 套接字错误「由于连接方在一段时间后没有正确答复
95
+ // …连接尝试失败」。实测 `wsl --shutdown` 后恢复。据此标记,bootstrap 遇到就重置一次再重试。
96
+ function isWslVmUnreachable(err) {
97
+ if (!err) return false;
98
+ const code = err.code === 4294967295 || err.code === -1 || err.code === 0xffffffff;
99
+ let text = "";
100
+ try { const raw = err.stdout || ""; text = Buffer.isBuffer(raw) ? raw.toString("utf16le") : String(raw); } catch {}
101
+ try { text += Buffer.from(String(err.stdout || ""), "binary").toString("utf16le"); } catch {}
102
+ const msg = /连接尝试失败|connection attempt failed|没有正确答复|did not properly respond|0x80072746|0x8007274c/i.test(text + " " + (err.message || ""));
103
+ return code && msg || (code && /^Command failed: [^\n]*wsl[^\n]*\n?\s*$/.test(err.message || "") && !err.stderr);
104
+ }
93
105
  function wslRun(cmd, { timeout = 60000, distro = DISTRO } = {}) {
94
106
  return new Promise((resolve, reject) => {
95
107
  execFile(docker.wslExe(), ["-d", distro, "-u", "root", "--", "bash", "-lc", cmd],
96
108
  { timeout, windowsHide: true, maxBuffer: 1 << 26 },
97
109
  (err, stdout, stderr) => {
98
- if (err) { err.stdout = String(stdout || ""); err.stderr = String(stderr || ""); return reject(err); }
110
+ if (err) { err.stdout = String(stdout || ""); err.stderr = String(stderr || ""); err.wslVmUnreachable = isWslVmUnreachable(err); return reject(err); }
99
111
  resolve({ stdout: String(stdout), stderr: String(stderr) });
100
112
  });
101
113
  });
@@ -844,11 +856,20 @@ async function runContainer({ port = 8008, container = "cicy-code-docker", volum
844
856
  // must then NOT open with a wrong/host token — that strands the user at login).
845
857
  // 原则:执行什么命令、输出什么、报什么错,全都要可见(onLog),且每一步可重试。
846
858
  // onLog({ status, message }) —— 上层把它接进 drawer。不传也安全(默认静默 + 写 log 文件)。
859
+ // 失败节流:WSL 卡死时每次 readContainerToken 都会起 wsl.exe 挂 8s+,多个调用方(标签恢复 /
860
+ // openTeam / 守护循环)每 10 秒来一次 → 僵死的 wsl.exe 越积越多。读不到就记一下,60 秒内直接返回 ""。
861
+ let _tokenFailAt = 0;
847
862
  async function readContainerToken(port = 8008, container = "cicy-code-docker", volume = "cicy-team-8008", { onLog } = {}) {
848
863
  const say = (status, message) => {
849
864
  try { (status === "error" ? log.warn : log.info)(`[readContainerToken] ${message}`); } catch (e) {}
850
865
  try { onLog && onLog({ status, message }); } catch (e) {}
851
866
  };
867
+ if (Date.now() - _tokenFailAt < 60000) return "";
868
+ const _r = await _readContainerTokenOnce(port, container, volume, say);
869
+ if (!_r) _tokenFailAt = Date.now();
870
+ return _r;
871
+ }
872
+ async function _readContainerTokenOnce(port, container, volume, say) {
852
873
  const volCmd = `cat /var/lib/docker/volumes/${volume}/_data/cicy-ai/global.json`;
853
874
  const execCmd = `docker exec ${container} cat /home/cicy/cicy-ai/global.json`;
854
875
  for (let attempt = 1; attempt <= 5; attempt++) {
@@ -1288,7 +1309,16 @@ async function _bootstrap({ onProgress, port = 8008, container = "cicy-code-dock
1288
1309
  // 3) Docker Engine inside Ubuntu
1289
1310
  begin("install-docker-engine");
1290
1311
  if (!(await dockerInstalled())) {
1291
- try { await installDockerEngine({ emit }); } catch (e) { fail("docker_install_failed", e.message); emit({ phase: "install-docker", status: "error", message: `Docker 安装失败:${e.message}(点重试)${errTail(e)}` }); finish(false, "docker_install_failed"); return { ok: false, reason: "docker_install_failed" }; }
1312
+ try { await installDockerEngine({ emit }); } catch (e) {
1313
+ if (e && e.wslVmUnreachable) {
1314
+ // VM 半死:wsl.exe 连不上 init。重置 WSL(terminate + shutdown)后由下一轮自动重试。
1315
+ fail("wsl_vm_unreachable", e.message);
1316
+ emit({ phase: "install-docker", status: "running", message: "wsl.exe 连不上 WSL 虚拟机(半死状态),正在重置 WSL 后自动重试…" });
1317
+ try { await wslTerminate(); } catch {}
1318
+ try { await wslShutdown(); } catch {}
1319
+ finish(false, "wsl_vm_unreachable"); return { ok: false, reason: "wsl_vm_unreachable", message: "WSL 虚拟机无响应,已重置,稍后自动重试" };
1320
+ }
1321
+ fail("docker_install_failed", e.message); emit({ phase: "install-docker", status: "error", message: `Docker 安装失败:${e.message}(点重试)${errTail(e)}` }); finish(false, "docker_install_failed"); return { ok: false, reason: "docker_install_failed" }; }
1292
1322
  done();
1293
1323
  } else done(true);
1294
1324
 
@@ -122,3 +122,15 @@ test("a wedged WSL (status unknown) is auto-repaired, then auto-rebooted if stil
122
122
  const w = read("src/sidecar/wsl-docker.js");
123
123
  assert.match(w, /const stillHung = async \(\) => \(await lxssWedged\(\)\) \|\| \(await distroInstalled\(\)\) === null;/);
124
124
  });
125
+
126
+ test("readContainerToken throttles after a failure so a wedged WSL is not hammered", () => {
127
+ const w = read("src/sidecar/wsl-docker.js");
128
+ assert.match(w, /if \(Date\.now\(\) - _tokenFailAt < 60000\) return "";/);
129
+ });
130
+
131
+ test("an unreachable WSL VM (socket timeout from wsl.exe) resets WSL and retries instead of failing docker install", () => {
132
+ const w = read("src/sidecar/wsl-docker.js");
133
+ assert.match(w, /function isWslVmUnreachable\(err\)/);
134
+ assert.match(w, /err\.wslVmUnreachable = isWslVmUnreachable\(err\)/);
135
+ assert.match(w, /if \(e && e\.wslVmUnreachable\) \{[^]*await wslTerminate\(\)[^]*await wslShutdown\(\)[^]*reason: "wsl_vm_unreachable"/);
136
+ });