cicy-desktop 2.1.299 → 2.1.300
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
|
@@ -169,6 +169,7 @@ function register({ sidecarLogPath } = {}) {
|
|
|
169
169
|
// WSL 功能启用后必须重启 Windows 才能继续。不等人:自动安排 90 秒后重启(桌面上会有
|
|
170
170
|
// 系统倒计时提示),UI 可「取消」或「立即重启」。每次开机只安排一次。
|
|
171
171
|
let _rebootScheduled = false;
|
|
172
|
+
let _relayMisses = 0, _relayResetDone = false; // WSL localhost 转发自愈(见 daemon 循环)
|
|
172
173
|
// 防重启循环:WSL 始终起不来时不能每次开机都重启。计数存 db/wsl-reboots.json,最多自动重启 2 次
|
|
173
174
|
// (成功后 :8008 起来时清零)。
|
|
174
175
|
const REBOOT_COUNT_FILE = path.join(os.homedir(), "cicy-ai", "db", "wsl-reboots.json");
|
|
@@ -227,6 +228,25 @@ function register({ sidecarLogPath } = {}) {
|
|
|
227
228
|
// bootstrap 幂等且可续跑;首次启用 WSL 若要求重启 Windows,下次登录 Desktop
|
|
228
229
|
// 会再次进入这里并从已完成的步骤继续。unknown 表示 WSL 正卡住/未响应,
|
|
229
230
|
// 此时不并发安装,留给下一轮检测或显式「修复 WSL」。
|
|
231
|
+
// 容器在里面健康、Windows 侧却连不通 = WSL localhost 转发坏了(实测 wsl --shutdown 后恢复)。
|
|
232
|
+
// 连续 2 轮(≈2 分钟)如此 → 每次开机最多自动重置一次 WSL。数据在 volume 里,容器由
|
|
233
|
+
// unless-stopped 策略自动拉起;不算「销毁」——对用户来说它本来就已经不可用了。
|
|
234
|
+
if (!s.running && !s.unknown && s.installed && appDocker.insideHealthy && appDocker.wslShutdown) {
|
|
235
|
+
let inside = false;
|
|
236
|
+
try { inside = await appDocker.insideHealthy(APP_CONTAINER, APP_PORT); } catch {}
|
|
237
|
+
if (inside) {
|
|
238
|
+
_relayMisses += 1;
|
|
239
|
+
if (_relayMisses >= 2 && !_relayResetDone) {
|
|
240
|
+
_relayResetDone = true;
|
|
241
|
+
auditDestructiveIpc(log, "docker:self-heal-localhost-relay", null, { container: APP_CONTAINER, misses: _relayMisses });
|
|
242
|
+
log.warn("[docker-daemon] container healthy inside WSL but 127.0.0.1:8008 unreachable from Windows → wsl --shutdown once to rebuild the localhost relay");
|
|
243
|
+
try { await appDocker.wslShutdown(); } catch (e) { log.warn(`[docker-daemon] wsl --shutdown failed: ${e.message}`); }
|
|
244
|
+
await refreshDockerStatus();
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (_relayMisses < 2) { log.warn(`[docker-daemon] :${APP_PORT} unreachable from Windows but healthy inside (${_relayMisses}/2)`); return; }
|
|
248
|
+
} else { _relayMisses = 0; }
|
|
249
|
+
} else if (s.running) { _relayMisses = 0; }
|
|
230
250
|
if (!s.running && !s.unknown && _autoBootstrapPaused && Date.now() < _autoBootstrapRetryAt) {
|
|
231
251
|
// 硬失败后退避(见 recordBootstrapResult);卡片显示 lastError,到点自动再试,用户点「重试」也行。
|
|
232
252
|
} else if (!s.running && !s.unknown) {
|
|
@@ -620,6 +620,16 @@ async function ensureFreshImage({ emit } = {}) {
|
|
|
620
620
|
return true;
|
|
621
621
|
}
|
|
622
622
|
|
|
623
|
+
// 容器内部视角的健康:docker exec 进容器用 node 探 127.0.0.1:8008。用来区分「容器真挂了」和
|
|
624
|
+
// 「容器好好的、只是 WSL 的 localhost 转发坏了」(后者 Windows 侧 :8008 打不通,实测
|
|
625
|
+
// `wsl --shutdown` 后 75 秒恢复)。
|
|
626
|
+
async function insideHealthy(container = "cicy-code-docker-8008", port = 8008) {
|
|
627
|
+
try {
|
|
628
|
+
await wslRun(`docker exec ${container} node -e "fetch('http://127.0.0.1:${port}/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"`, { timeout: 20000 });
|
|
629
|
+
return true;
|
|
630
|
+
} catch { return false; }
|
|
631
|
+
}
|
|
632
|
+
|
|
623
633
|
// HTTP /health probe on 127.0.0.1:port from Windows — WSL2 forwards localhost,
|
|
624
634
|
// so a container published on :port is reachable here. Reuse docker.js's probe.
|
|
625
635
|
const probeHealth = docker.probeHealth;
|
|
@@ -1602,6 +1612,7 @@ async function readMihomoSelections(container = "cicy-code-docker-8008") {
|
|
|
1602
1612
|
}
|
|
1603
1613
|
|
|
1604
1614
|
module.exports = {
|
|
1615
|
+
insideHealthy, wslShutdown,
|
|
1605
1616
|
bootstrap, status, restart, stop, dockerRestart, recreate, update, upgrade, runContainer, readContainerToken,
|
|
1606
1617
|
distroInstalled, dockerInstalled, dockerEngineUp, imagePresent, probeHealth, wslRun, hasGatewayKey,
|
|
1607
1618
|
readMihomoConfig, readMihomoSelections, parseMihomoSelections,
|
|
@@ -100,3 +100,10 @@ test("a broken component store is reported once and backed off for hours, not re
|
|
|
100
100
|
assert.match(d, /reason: storeBroken \? "windows_component_store_broken" : "wsl_enable_failed"/);
|
|
101
101
|
assert.match(read("src/backends/sidecar-ipc.js"), /windows_component_store_broken: 6 \* 60 \* 60 \* 1000/);
|
|
102
102
|
});
|
|
103
|
+
|
|
104
|
+
test("broken WSL localhost relay (healthy inside, unreachable from Windows) is reset once per boot", () => {
|
|
105
|
+
assert.match(read("src/sidecar/wsl-docker.js"), /async function insideHealthy\(/);
|
|
106
|
+
const ipc = read("src/backends/sidecar-ipc.js");
|
|
107
|
+
assert.match(ipc, /_relayMisses >= 2 && !_relayResetDone/);
|
|
108
|
+
assert.match(ipc, /docker:self-heal-localhost-relay/);
|
|
109
|
+
});
|