cicy-desktop 2.1.338 → 2.1.340
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/app-updater.js +54 -7
- package/src/backends/homepage-react/assets/index-B72KF7tw.js +388 -0
- package/src/backends/homepage-react/index.html +33 -2
- package/src/backends/homepage-window.js +40 -3
- package/src/main.js +76 -0
- package/src/tools/tab-browser-tools.js +5 -1
- package/test/app-updater-install-relaunch.test.js +20 -7
- package/test/app-updater-loop-guard.test.js +55 -0
- package/tools/wsd +166 -0
- package/workers/render/index.html +32 -1
- package/workers/render/src/App.jsx +620 -3
- package/workers/render/vite.config.js +13 -0
- package/workers/render/worker.js +311 -0
- package/workers/render/wrangler.toml +12 -0
- package/src/backends/homepage-react/assets/index-CppodgBn.js +0 -377
package/package.json
CHANGED
package/src/app-updater.js
CHANGED
|
@@ -229,6 +229,41 @@ async function download(url, dest, onProgress) {
|
|
|
229
229
|
throw lastErr || new Error("download failed");
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
+
// ── 自动安装的循环闸 ─────────────────────────────────────────────────────────
|
|
233
|
+
// Auto-install kills the app by design (an installer cannot replace a running
|
|
234
|
+
// exe). So if an install does NOT land, the app comes back on the old version,
|
|
235
|
+
// the next check() tries the same thing, and the machine is stuck in a restart
|
|
236
|
+
// loop that closes the user's window every time. That is not hypothetical — it
|
|
237
|
+
// took the whole fleet down. The attempt is therefore remembered ACROSS
|
|
238
|
+
// restarts, and a version that has already failed twice is not auto-installed
|
|
239
|
+
// again until the cooldown passes; the update is still offered, just not forced.
|
|
240
|
+
const AUTO_TRY_MAX = 2;
|
|
241
|
+
const AUTO_TRY_COOLDOWN_MS = 6 * 60 * 60 * 1000;
|
|
242
|
+
|
|
243
|
+
function readAutoTry() {
|
|
244
|
+
try { return readGlobalConfig(GLOBAL_JSON)?.desktopAutoInstall || {}; } catch { return {}; }
|
|
245
|
+
}
|
|
246
|
+
function noteAutoTry(version) {
|
|
247
|
+
const cur = readAutoTry();
|
|
248
|
+
const count = cur.version === version ? (cur.count || 0) + 1 : 1;
|
|
249
|
+
try {
|
|
250
|
+
updateGlobalConfig(GLOBAL_JSON, (c) => ({
|
|
251
|
+
...(c || {}),
|
|
252
|
+
desktopAutoInstall: { version, count, at: Date.now() },
|
|
253
|
+
}));
|
|
254
|
+
} catch {}
|
|
255
|
+
return count;
|
|
256
|
+
}
|
|
257
|
+
function clearAutoTry() {
|
|
258
|
+
try { updateGlobalConfig(GLOBAL_JSON, (c) => { const n = { ...(c || {}) }; delete n.desktopAutoInstall; return n; }); } catch {}
|
|
259
|
+
}
|
|
260
|
+
function autoInstallAllowed(version) {
|
|
261
|
+
const t = readAutoTry();
|
|
262
|
+
if (t.version !== version) return true;
|
|
263
|
+
if ((t.count || 0) < AUTO_TRY_MAX) return true;
|
|
264
|
+
return Date.now() - (t.at || 0) > AUTO_TRY_COOLDOWN_MS;
|
|
265
|
+
}
|
|
266
|
+
|
|
232
267
|
// ── 状态机 + 广播 ─────────────────────────────────────────────────────────────
|
|
233
268
|
let _win = null;
|
|
234
269
|
let _state = { status: "idle", version: null, current: null, progress: null, filePath: null, error: null, autoUpdate: false, auto: false };
|
|
@@ -260,6 +295,9 @@ function init(mainWin) {
|
|
|
260
295
|
_win = mainWin;
|
|
261
296
|
_state.current = app.getVersion();
|
|
262
297
|
_state.autoUpdate = getAutoUpdate();
|
|
298
|
+
// Running the version we last tried to install = that attempt worked; forget
|
|
299
|
+
// it so a future update to the same number is never wrongly blocked.
|
|
300
|
+
try { if (readAutoTry().version === _state.current) clearAutoTry(); } catch {}
|
|
263
301
|
setTimeout(() => check().catch(() => {}), 15_000); // 启动后探一次
|
|
264
302
|
setInterval(() => check().catch(() => {}), 30 * 60 * 1000); // 每 30 分钟
|
|
265
303
|
}
|
|
@@ -279,10 +317,15 @@ async function check() {
|
|
|
279
317
|
log.info(`[app-updater] ${latest} 安装包就绪:${ready}`);
|
|
280
318
|
broadcast({ status: "available", version: latest, current, progress: null, filePath: null, autoUpdate: getAutoUpdate(), auto: false });
|
|
281
319
|
if (getAutoUpdate()) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
320
|
+
if (!autoInstallAllowed(latest)) {
|
|
321
|
+
log.warn(`[app-updater] ${latest} 已自动安装失败 ${AUTO_TRY_MAX} 次,冷却中 — 只提示不再自动装(避免反复关闭 app)`);
|
|
322
|
+
} else {
|
|
323
|
+
const n = noteAutoTry(latest);
|
|
324
|
+
log.info(`[app-updater] auto-update on → downloading ${latest} and installing without asking (attempt ${n}/${AUTO_TRY_MAX})`);
|
|
325
|
+
broadcast({ auto: true });
|
|
326
|
+
await downloadUpdate();
|
|
327
|
+
if (_state.status === "ready") installNow();
|
|
328
|
+
}
|
|
286
329
|
}
|
|
287
330
|
} else { log.info(`[app-updater] ${latest} 版本号已更新但所有来源都拿不到安装包(HEAD 非 200):${urls.join(" , ")} — 暂不提示更新`); broadcast({ status: "up-to-date", version: current, current }); }
|
|
288
331
|
} else {
|
|
@@ -364,8 +407,12 @@ function installWindows(installer) {
|
|
|
364
407
|
// VBS escapes a double quote by doubling it. cmd waits for the installer (no
|
|
365
408
|
// `start` on that leg), then the pause lets Windows release the replaced
|
|
366
409
|
// files before the new exe runs hidden.
|
|
410
|
+
// Wait for THIS process to exit before the installer starts: it cannot replace
|
|
411
|
+
// a running exe, and previously the chain and app.quit() raced — the installer
|
|
412
|
+
// could begin while the app was still up, fail, and leave the version
|
|
413
|
+
// unchanged, which is what fed the restart loop.
|
|
367
414
|
const cmd =
|
|
368
|
-
`cmd /c ""${installer}" /S & timeout /t 20 /nobreak >nul & start "" "${exe}" --hidden"`;
|
|
415
|
+
`cmd /c "timeout /t 8 /nobreak >nul & "${installer}" /S & timeout /t 20 /nobreak >nul & start "" "${exe}" --hidden"`;
|
|
369
416
|
const line = `sh.Run "${cmd.replace(/"/g, '""')}", 0, False`;
|
|
370
417
|
fs.writeFileSync(vbs, ['Set sh = CreateObject("WScript.Shell")', line, ""].join("\r\n"));
|
|
371
418
|
const ch = spawn("wscript.exe", ["//B", "//Nologo", vbs], {
|
|
@@ -375,8 +422,8 @@ function installWindows(installer) {
|
|
|
375
422
|
});
|
|
376
423
|
ch.unref();
|
|
377
424
|
log.info(`[app-updater] hidden install + relaunch chain started (pid ${ch.pid})`);
|
|
378
|
-
// Quit
|
|
379
|
-
setTimeout(() => { try { app.quit(); } catch {} },
|
|
425
|
+
// Quit promptly — the chain waits 8s for us before touching anything.
|
|
426
|
+
setTimeout(() => { try { app.quit(); } catch {} }, 500);
|
|
380
427
|
}
|
|
381
428
|
|
|
382
429
|
function installNow() {
|