cicy-desktop 2.1.142 → 2.1.144
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 +1 -1
- package/src/backends/homepage-react/assets/index-LZDX5apT.js +377 -0
- package/src/backends/homepage-react/index.html +1 -1
- package/src/sidecar/docker.js +1 -1
- package/src/sidecar/wsl-docker.js +43 -7
- package/workers/render/src/App.jsx +3 -12
- package/src/backends/homepage-react/assets/index-DVdvubOy.js +0 -377
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="./favicon.svg" />
|
|
7
7
|
<link rel="icon" type="image/png" sizes="256x256" href="./favicon-256.png" />
|
|
8
8
|
<title>CiCy Desktop</title>
|
|
9
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
+
<script type="module" crossorigin src="./assets/index-LZDX5apT.js"></script>
|
|
10
10
|
<link rel="stylesheet" crossorigin href="./assets/index-CKhSx1lp.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
package/src/sidecar/docker.js
CHANGED
|
@@ -722,5 +722,5 @@ module.exports = {
|
|
|
722
722
|
bootstrap, probeHealth, readContainerToken, dockerDesktopExe, desktopDir, downloadsDir, imageTarballPath,
|
|
723
723
|
launchElevated, wslMissing, ensureWsl,
|
|
724
724
|
// platform-agnostic download/retry primitives, reused by native.js
|
|
725
|
-
ensureDownloaded, curlDownload, withRetry, waitUntil, run,
|
|
725
|
+
ensureDownloaded, curlDownload, withRetry, waitUntil, run, headSize,
|
|
726
726
|
};
|
|
@@ -155,10 +155,24 @@ async function installDistro({ emit } = {}) {
|
|
|
155
155
|
// 1) Download the PRE-BAKED rootfs (Ubuntu+Docker+image baked in, ~444MB) with
|
|
156
156
|
// a real progress bar. curl is ~10× faster than node's downloader on OSS.
|
|
157
157
|
const dest = rootfsPath();
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
158
|
+
// REUSE a complete rootfs already on disk (pre-staged into ~/Downloads, or left by
|
|
159
|
+
// a prior run) BEFORE curlDownload touches it. The bug: curlDownload doesn't skip a
|
|
160
|
+
// complete file (and on a failed curl it truncated the staged 447MB), so a staged
|
|
161
|
+
// rootfs got re-downloaded. headSize uses node http (works even when curl can't
|
|
162
|
+
// resolve the host — the `curl exit 6` we saw), so this skip is reliable.
|
|
163
|
+
let haveComplete = false;
|
|
164
|
+
try {
|
|
165
|
+
const expected = await docker.headSize(ROOTFS_URL);
|
|
166
|
+
const have = fs.statSync(dest).size;
|
|
167
|
+
haveComplete = expected > 0 && have === expected;
|
|
168
|
+
if (haveComplete) emit && emit({ phase: "image", status: "skip", message: "下载运行环境:已有完整包,跳过下载", progress: 100, received: have, total: expected });
|
|
169
|
+
} catch {}
|
|
170
|
+
if (!haveComplete) {
|
|
171
|
+
try { await docker.curlDownload(ROOTFS_URL, dest, { emit, phase: "image", label: "下载运行环境" }); }
|
|
172
|
+
catch (e) {
|
|
173
|
+
emit && emit({ phase: "image", status: "running", message: `下载器异常(${e.message}),改用备用下载…` });
|
|
174
|
+
await docker.ensureDownloaded(ROOTFS_URL, dest, null, { emit, phase: "image", label: "下载运行环境" });
|
|
175
|
+
}
|
|
162
176
|
}
|
|
163
177
|
// 2) Import as an ISOLATED WSL2 distro: its OWN VHDX under a dedicated dir, so
|
|
164
178
|
// it never touches the user's existing distros. `--version 2` sets just THIS
|
|
@@ -252,6 +266,25 @@ const BOOT_SCRIPT_B64 = Buffer.from(
|
|
|
252
266
|
"pgrep dockerd >/dev/null 2>&1 || setsid sh -c 'exec dockerd >/var/log/dockerd.log 2>&1 </dev/null' &\n"
|
|
253
267
|
).toString("base64");
|
|
254
268
|
|
|
269
|
+
// Hold the distro OPEN. The flip side of detaching dockerd: once the launching
|
|
270
|
+
// wsl.exe exits, WSL tears the distro down if no session holds it — killing the
|
|
271
|
+
// just-launched dockerd (the "启动引擎 转圈但 dockerd=none" we saw). A detached,
|
|
272
|
+
// long-lived `wsl … sleep infinity` keeps the distro alive so dockerd (and the
|
|
273
|
+
// container) survive. unref'd so it never blocks the app; survives app exit too.
|
|
274
|
+
let _keepalive = null;
|
|
275
|
+
function ensureKeepalive() {
|
|
276
|
+
if (process.platform !== "win32") return;
|
|
277
|
+
if (_keepalive && _keepalive.exitCode == null && !_keepalive.killed) return;
|
|
278
|
+
try {
|
|
279
|
+
_keepalive = spawn("wsl", ["-d", DISTRO, "-u", "root", "--", "sh", "-c", "exec sleep infinity"],
|
|
280
|
+
{ detached: true, stdio: "ignore", windowsHide: true });
|
|
281
|
+
_keepalive.on("error", (e) => { log.warn(`[keepalive] ${e.message}`); _keepalive = null; });
|
|
282
|
+
_keepalive.on("exit", () => { _keepalive = null; });
|
|
283
|
+
_keepalive.unref();
|
|
284
|
+
log.info("[keepalive] holding distro open (sleep infinity)");
|
|
285
|
+
} catch (e) { log.warn(`[keepalive] spawn failed: ${e.message}`); }
|
|
286
|
+
}
|
|
287
|
+
|
|
255
288
|
async function launchDockerd() {
|
|
256
289
|
await wslRun(
|
|
257
290
|
`echo ${BOOT_SCRIPT_B64} | base64 -d > /usr/local/sbin/start-dockerd.sh 2>/dev/null; chmod +x /usr/local/sbin/start-dockerd.sh 2>/dev/null; ` +
|
|
@@ -260,8 +293,10 @@ async function launchDockerd() {
|
|
|
260
293
|
// Stale /var/run/docker.{pid,sock} from the pre-baked rootfs make a fresh dockerd
|
|
261
294
|
// refuse to start; clear them when dockerd isn't already running.
|
|
262
295
|
"if ! pgrep dockerd >/dev/null 2>&1; then rm -f /var/run/docker.pid /run/docker.pid /var/run/docker.sock /run/docker.sock; fi; " +
|
|
263
|
-
|
|
264
|
-
|
|
296
|
+
// setsid --fork: fork dockerd into a NEW session and have setsid EXIT immediately,
|
|
297
|
+
// so this wsl call returns at once and dockerd is fully orphaned (no `& true`
|
|
298
|
+
// backgrounding race). It only survives because ensureKeepalive() holds the distro.
|
|
299
|
+
"pgrep dockerd >/dev/null 2>&1 || setsid --fork bash -c 'exec dockerd >/var/log/cicy-dockerd.log 2>&1 </dev/null'",
|
|
265
300
|
{ timeout: 20000 });
|
|
266
301
|
}
|
|
267
302
|
|
|
@@ -273,7 +308,8 @@ async function startEngine() {
|
|
|
273
308
|
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
274
309
|
const at0 = Date.now();
|
|
275
310
|
let stuck = false;
|
|
276
|
-
log.info(`[startEngine] attempt ${attempt}/3 — launch dockerd (detached) + poll socket`);
|
|
311
|
+
log.info(`[startEngine] attempt ${attempt}/3 — keepalive + launch dockerd (detached) + poll socket`);
|
|
312
|
+
ensureKeepalive(); // hold the distro open BEFORE launching, or the teardown kills dockerd
|
|
277
313
|
try { await launchDockerd(); }
|
|
278
314
|
catch (e) { stuck = true; log.warn(`[startEngine] attempt ${attempt} launch errored — WSL stuck? ${e.message}`); }
|
|
279
315
|
if (!stuck) {
|
|
@@ -1709,7 +1709,6 @@ function DockerInstallDrawerHost() {
|
|
|
1709
1709
|
function DockerCard({ dockerTeam, cloudTitle, onOpen, onRename, onRefresh }) {
|
|
1710
1710
|
const [status, setStatus] = useState(null);
|
|
1711
1711
|
const [busy, setBusy] = useState(""); // "" | bootstrap | restart | stop | upgrade | probe
|
|
1712
|
-
const [probeNote, setProbeNote] = useState(""); // 「重试检测」后给用户的明确反馈(WSL 仍卡 → 提示重启)
|
|
1713
1712
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
1714
1713
|
const [confirmRecreate, setConfirmRecreate] = useState(false); // 重建容器 in-app 确认弹窗(不用 native confirm)
|
|
1715
1714
|
// Inline rename (mirrors LocalTeamCard): double-click the title to edit.
|
|
@@ -1733,9 +1732,7 @@ function DockerCard({ dockerTeam, cloudTitle, onOpen, onRename, onRefresh }) {
|
|
|
1733
1732
|
|
|
1734
1733
|
const checkStatus = useCallback(async () => {
|
|
1735
1734
|
try {
|
|
1736
|
-
|
|
1737
|
-
setStatus(s);
|
|
1738
|
-
if (s && !s.unknown) setProbeNote(""); // WSL came back → clear the stuck note
|
|
1735
|
+
setStatus(await window.cicy?.docker?.appStatus?.());
|
|
1739
1736
|
} catch (e) { console.warn("[DockerCard]", e); }
|
|
1740
1737
|
}, []);
|
|
1741
1738
|
|
|
@@ -1914,9 +1911,8 @@ function DockerCard({ dockerTeam, cloudTitle, onOpen, onRename, onRefresh }) {
|
|
|
1914
1911
|
try {
|
|
1915
1912
|
const s = await (window.cicy?.docker?.appRedetect?.() ?? window.cicy?.docker?.appStatus?.());
|
|
1916
1913
|
if (s) setStatus(s);
|
|
1917
|
-
if (s?.unknown)
|
|
1918
|
-
|
|
1919
|
-
} catch (e) { setProbeNote(tr("docker.probeFailed", "检测失败,请重试")); }
|
|
1914
|
+
if (s?.unknown) toast.show({ id: "docker-probe", status: "error", message: tr("docker.wslStillStuck", "WSL 仍无响应 —— 多半要重启 Windows 后再试"), ttl: 6000 });
|
|
1915
|
+
} catch (e) { toast.show({ id: "docker-probe", status: "error", message: tr("docker.probeFailed", "检测失败,请重试"), ttl: 5000 }); }
|
|
1920
1916
|
finally { setBusy(""); }
|
|
1921
1917
|
return;
|
|
1922
1918
|
}
|
|
@@ -2019,11 +2015,6 @@ function DockerCard({ dockerTeam, cloudTitle, onOpen, onRename, onRefresh }) {
|
|
|
2019
2015
|
)}
|
|
2020
2016
|
</div>
|
|
2021
2017
|
<div className="bcard__meta"><span className="bcard__chip">Docker</span></div>
|
|
2022
|
-
{(probeNote || (!running && stateText)) && (
|
|
2023
|
-
<div data-id="DockerCard-statusline" style={{ marginTop: 4, fontSize: 11, lineHeight: 1.4, color: probeNote ? "#f0a020" : "rgba(255,255,255,0.55)" }}>
|
|
2024
|
-
{probeNote || stateText}
|
|
2025
|
-
</div>
|
|
2026
|
-
)}
|
|
2027
2018
|
</div>
|
|
2028
2019
|
<button
|
|
2029
2020
|
type="button"
|