cicy-desktop 2.1.306 → 2.1.308

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/.gitattributes ADDED
@@ -0,0 +1,4 @@
1
+ *.js text eol=lf
2
+ *.json text eol=lf
3
+ *.sh text eol=lf
4
+ *.yml text eol=lf
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cicy-desktop",
3
- "version": "2.1.306",
3
+ "version": "2.1.308",
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.575",
148
- "cicy-code-darwin-arm64": "2.3.575",
149
- "cicy-code-linux-x64": "2.3.575",
150
- "cicy-code-linux-arm64": "2.3.575",
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",
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",
@@ -159,6 +159,7 @@ function register({ sidecarLogPath } = {}) {
159
159
  } else if (result) {
160
160
  _lastBootstrapError = { reason: result.reason || result.error || "bootstrap_failed", message: result.message || "", ts: Date.now() };
161
161
  } else return;
162
+ _softRetryAt = Date.now() + 2 * 60 * 1000;
162
163
  if (_lastBootstrapError.reason === "wsl_reboot_required") scheduleReboot(90);
163
164
  if (HARD_BOOTSTRAP_REASONS.has(_lastBootstrapError.reason)) {
164
165
  _autoBootstrapPaused = _lastBootstrapError.reason;
@@ -171,6 +172,7 @@ function register({ sidecarLogPath } = {}) {
171
172
  let _rebootScheduled = false;
172
173
  let _relayMisses = 0, _relayResetDone = false; // WSL localhost 转发自愈(见 daemon 循环)
173
174
  let _unknownStreak = 0, _wslRepairDone = false; // WSL 卡死自愈(见 daemon 循环)
175
+ let _softRetryAt = 0; // 非硬失败(如 docker_install_failed)也退避 2 分钟,别每 35 秒重跑一遍
174
176
  // 防重启循环:WSL 始终起不来时不能每次开机都重启。计数存 db/wsl-reboots.json,最多自动重启 2 次
175
177
  // (成功后 :8008 起来时清零)。
176
178
  const REBOOT_COUNT_FILE = path.join(os.homedir(), "cicy-ai", "db", "wsl-reboots.json");
@@ -265,6 +267,8 @@ function register({ sidecarLogPath } = {}) {
265
267
  } else if (s.running) { _relayMisses = 0; }
266
268
  if (!s.running && !s.unknown && _autoBootstrapPaused && Date.now() < _autoBootstrapRetryAt) {
267
269
  // 硬失败后退避(见 recordBootstrapResult);卡片显示 lastError,到点自动再试,用户点「重试」也行。
270
+ } else if (!s.running && !s.unknown && Date.now() < _softRetryAt) {
271
+ // 上一轮刚失败,2 分钟内不重跑
268
272
  } else if (!s.running && !s.unknown) {
269
273
  if (_autoBootstrapPaused) log.info(`[docker-daemon] backoff elapsed after ${_autoBootstrapPaused} → auto-retrying bootstrap`);
270
274
  log.info(`[docker-daemon] :8008 down (${s.installed ? "installed" : "not installed"}) → auto-bootstrapping WSL cicy-code`);
@@ -95,7 +95,9 @@ async function ensureWslKernel({ emit } = {}) {
95
95
  // …连接尝试失败」。实测 `wsl --shutdown` 后恢复。据此标记,bootstrap 遇到就重置一次再重试。
96
96
  function isWslVmUnreachable(err) {
97
97
  if (!err) return false;
98
- const code = err.code === 4294967295 || err.code === -1 || err.code === 0xffffffff;
98
+ // bash 的退出码只会是 0-255;>255 / -1 / 4294967295 只可能来自 wsl.exe 自己(连不上 VM)。
99
+ const code = err.code === 4294967295 || err.code === -1 || err.code === 0xffffffff || (typeof err.code === "number" && err.code > 255);
100
+ if (code) return true;
99
101
  let text = "";
100
102
  try { const raw = err.stdout || ""; text = Buffer.isBuffer(raw) ? raw.toString("utf16le") : String(raw); } catch {}
101
103
  try { text += Buffer.from(String(err.stdout || ""), "binary").toString("utf16le"); } catch {}
@@ -139,7 +141,13 @@ function wslRunStream(cmd, { emit, phase = "install-docker", timeout = 900000, d
139
141
  child.stderr.on("data", pump);
140
142
  const timer = setTimeout(() => { try { child.kill("SIGKILL"); } catch {} reject(Object.assign(new Error("timeout"), { stdout: tail })); }, timeout);
141
143
  child.on("error", (e) => { clearTimeout(timer); reject(e); });
142
- child.on("close", (code) => { clearTimeout(timer); code === 0 ? resolve({ stdout: tail }) : reject(Object.assign(new Error(`exit ${code}`), { stdout: tail })); });
144
+ child.on("close", (code) => {
145
+ clearTimeout(timer);
146
+ if (code === 0) return resolve({ stdout: tail });
147
+ const err = Object.assign(new Error(`exit ${code}`), { stdout: tail, code });
148
+ err.wslVmUnreachable = isWslVmUnreachable(err);
149
+ reject(err);
150
+ });
143
151
  });
144
152
  }
145
153
 
@@ -1510,7 +1518,7 @@ async function update({ onProgress, container = "cicy-code-docker", port = 8008
1510
1518
  emit({ phase: "image", status: "running", message: latest ? t("docker.updating.toVersion", { v: latest }) : t("docker.updating.pulling") });
1511
1519
  // cp 结果出到 drawer(诊断:之前静默失败 → 回落镜像内旧脚本 → 又卡 2 分钟,看不出来)。
1512
1520
  try {
1513
- const b64 = fs.readFileSync(path.join(__dirname, "container-scripts", "cicy-code-update.sh")).toString("base64");
1521
+ const b64 = Buffer.from(fs.readFileSync(path.join(__dirname, "container-scripts", "cicy-code-update.sh"), "utf8").replace(/\r\n?/g, "\n"), "utf8").toString("base64"); // CI 的 Windows runner 会把 .sh 转成 CRLF → 容器里 shebang 变 /bin/bash\r 执行不了
1514
1522
  await wslRun(buildPushUpdateScriptCommand(b64, container), { timeout: 30000 });
1515
1523
  emit({ phase: "image", status: "running", message: t("docker.updating.scriptReady") });
1516
1524
  } catch (e) {
@@ -134,3 +134,15 @@ test("an unreachable WSL VM (socket timeout from wsl.exe) resets WSL and retries
134
134
  assert.match(w, /err\.wslVmUnreachable = isWslVmUnreachable\(err\)/);
135
135
  assert.match(w, /if \(e && e\.wslVmUnreachable\) \{[^]*await wslTerminate\(\)[^]*await wslShutdown\(\)[^]*reason: "wsl_vm_unreachable"/);
136
136
  });
137
+
138
+ test("the container update script is pushed with LF endings even from a CRLF checkout", () => {
139
+ assert.match(read("src/sidecar/wsl-docker.js"), /cicy-code-update\.sh"\), "utf8"\)\.replace\(\/\\r\\n\?\/g, "\\n"\)/);
140
+ assert.match(read(".gitattributes"), /\*\.sh text eol=lf/);
141
+ });
142
+
143
+ test("streamed wsl runs flag an unreachable VM too, and soft failures back off 2 min", () => {
144
+ const w = read("src/sidecar/wsl-docker.js");
145
+ assert.match(w, /const err = Object\.assign\(new Error\(`exit \$\{code\}`\), \{ stdout: tail, code \}\);\n\s+err\.wslVmUnreachable = isWslVmUnreachable\(err\);/);
146
+ assert.match(w, /err\.code > 255\)/);
147
+ assert.match(read("src/backends/sidecar-ipc.js"), /_softRetryAt = Date\.now\(\) \+ 2 \* 60 \* 1000;/);
148
+ });