cicy-desktop 2.1.91 → 2.1.93
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/bin/cicy-desktop +62 -21
- package/package.json +9 -8
- package/src/backends/homepage-preload.js +19 -5
- package/src/main.js +12 -0
package/bin/cicy-desktop
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const { spawn, execSync } = require("child_process");
|
|
2
|
+
const { spawn, execSync, execFileSync } = require("child_process");
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const os = require("os");
|
|
@@ -13,10 +13,13 @@ const GLOBAL_CONFIG_FILE = path.join(HOME, "global.json");
|
|
|
13
13
|
const STATE_FILE = path.join(HOME, ".cicy-cluster.json");
|
|
14
14
|
const LOGS_DIR = path.join(HOME, "logs");
|
|
15
15
|
const PACKAGE_ROOT = path.join(__dirname, "..");
|
|
16
|
-
// CN defaults: a fresh machine has no cached electron binary, so
|
|
17
|
-
// postinstall
|
|
18
|
-
//
|
|
19
|
-
|
|
16
|
+
// CN/global defaults: a fresh machine has no cached electron binary, so the
|
|
17
|
+
// electron postinstall (and our own self-provisioning below) would otherwise
|
|
18
|
+
// hit GitHub releases, which is slow/blocked on many networks. Default to our
|
|
19
|
+
// own Cloudflare R2 mirror — the three platform zips we ship are mirrored at
|
|
20
|
+
// <ELECTRON_MIRROR>v<version>/electron-v<version>-<platform>.zip (+ SHASUMS256.txt),
|
|
21
|
+
// the exact layout @electron/get expects. Overridable via the env var.
|
|
22
|
+
const ELECTRON_MIRROR = process.env.ELECTRON_MIRROR || "https://r2.deepfetch.de5.net/electron/";
|
|
20
23
|
const NPM_REGISTRY = process.env.CICY_NPM_REGISTRY || process.env.npm_config_registry || "https://registry.npmmirror.com";
|
|
21
24
|
const MASTER_ENTRY = path.join(PACKAGE_ROOT, "src", "master", "master-main.js");
|
|
22
25
|
|
|
@@ -73,32 +76,70 @@ function globalElectronDir() {
|
|
|
73
76
|
} catch { return null; }
|
|
74
77
|
}
|
|
75
78
|
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
// The per-platform Electron artifact (mirror zip name + the in-dist executable
|
|
80
|
+
// that path.txt must point at).
|
|
81
|
+
function electronArtifact() {
|
|
82
|
+
const plat = process.platform === "win32" ? "win32" : process.platform === "darwin" ? "darwin" : "linux";
|
|
83
|
+
const arch = process.arch === "arm64" ? "arm64" : "x64";
|
|
84
|
+
return {
|
|
85
|
+
zip: `electron-v${ELECTRON_VERSION}-${plat}-${arch}.zip`,
|
|
86
|
+
exe: process.platform === "win32" ? "electron.exe"
|
|
87
|
+
: process.platform === "darwin" ? "Electron.app/Contents/MacOS/Electron"
|
|
88
|
+
: "electron",
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Provision the Electron binary INTO the bundled npx copy ourselves: download the
|
|
93
|
+
// platform zip from the mirror (R2) with curl, extract with the OS's own unzip,
|
|
94
|
+
// then write path.txt. We deliberately do NOT use electron's install.js /
|
|
95
|
+
// @electron/get: on Windows its bundled extract-zip only PARTIALLY unpacks
|
|
96
|
+
// electron 41 (leaves no path.txt → "Electron failed to install correctly") even
|
|
97
|
+
// though the downloaded zip is valid. curl + Expand-Archive/unzip is reliable,
|
|
98
|
+
// mirror-only (no GitHub), and writes a complete dist/.
|
|
99
|
+
function provisionElectronFromMirror(bundledDir) {
|
|
100
|
+
const { zip, exe } = electronArtifact();
|
|
101
|
+
const url = `${ELECTRON_MIRROR}v${ELECTRON_VERSION}/${zip}`;
|
|
102
|
+
const tmpZip = path.join(os.tmpdir(), `cicy-${zip}`);
|
|
103
|
+
const curl = isWindows ? "curl.exe" : "curl";
|
|
104
|
+
execFileSync(curl, ["-fL", "--retry", "5", "--retry-delay", "2", "--connect-timeout", "20", "-o", tmpZip, url], { stdio: "inherit" });
|
|
105
|
+
const distDir = path.join(bundledDir, "dist");
|
|
106
|
+
fs.rmSync(distDir, { recursive: true, force: true });
|
|
107
|
+
fs.mkdirSync(distDir, { recursive: true });
|
|
108
|
+
if (isWindows) {
|
|
109
|
+
execFileSync("powershell", ["-NoProfile", "-Command", `Expand-Archive -LiteralPath "${tmpZip}" -DestinationPath "${distDir}" -Force`], { stdio: "inherit" });
|
|
110
|
+
} else {
|
|
111
|
+
execFileSync("unzip", ["-o", "-q", tmpZip, "-d", distDir], { stdio: "inherit" });
|
|
112
|
+
try { fs.chmodSync(path.join(distDir, exe), 0o755); } catch {}
|
|
113
|
+
}
|
|
114
|
+
fs.writeFileSync(path.join(bundledDir, "path.txt"), exe);
|
|
115
|
+
try { fs.rmSync(tmpZip, { force: true }); } catch {}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Make sure a USABLE electron exists before spawning the worker. A pre-existing
|
|
119
|
+
// GLOBAL electron is reused if present. Otherwise we provision the binary LOCALLY
|
|
120
|
+
// into the bundled npx copy straight from the R2 mirror — NO `npm i -g`, NO
|
|
121
|
+
// GitHub, NO @electron/get. This is what lets a single `npx cicy-desktop`
|
|
122
|
+
// self-provision electron and start first-try. Runs once per process.
|
|
82
123
|
let _electronEnsured = false;
|
|
83
124
|
function ensureElectron() {
|
|
84
125
|
if (_electronEnsured) return;
|
|
85
126
|
_electronEnsured = true;
|
|
86
|
-
// Already usable (global, or the resolvable bundled/npx copy)?
|
|
127
|
+
// Already usable (a shared global, or the resolvable bundled/npx copy)? done.
|
|
87
128
|
if (electronBinaryHealthy(globalElectronDir())) return;
|
|
88
129
|
let bundledDir = null;
|
|
89
130
|
try { bundledDir = path.dirname(require.resolve("electron/package.json", { paths: [PACKAGE_ROOT] })); } catch {}
|
|
90
131
|
if (electronBinaryHealthy(bundledDir)) return;
|
|
91
|
-
|
|
92
|
-
|
|
132
|
+
if (!bundledDir) {
|
|
133
|
+
console.warn(`⚠️ electron package not resolvable under ${PACKAGE_ROOT}; cannot self-provision.`);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
console.log(`⚙️ Fetching Electron ${ELECTRON_VERSION} from mirror (one-time)…`);
|
|
93
137
|
try {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
});
|
|
98
|
-
_globalElectronBin = undefined; // bust the memo so resolveElectronSpawn re-finds the new global bin
|
|
138
|
+
provisionElectronFromMirror(bundledDir);
|
|
139
|
+
if (electronBinaryHealthy(bundledDir)) return;
|
|
140
|
+
console.warn(`⚠️ Electron provisioned but health check still failing.`);
|
|
99
141
|
} catch (e) {
|
|
100
|
-
console.warn(`⚠️
|
|
101
|
-
console.warn(` Fix manually: set ELECTRON_MIRROR=${ELECTRON_MIRROR} && npm i -g electron@${ELECTRON_VERSION}`);
|
|
142
|
+
console.warn(`⚠️ Electron provision from mirror failed: ${e.message}`);
|
|
102
143
|
}
|
|
103
144
|
}
|
|
104
145
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cicy-desktop",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.93",
|
|
4
4
|
"description": "CiCy - AI-powered operating system browser",
|
|
5
5
|
"main": "src/main.js",
|
|
6
6
|
"bin": {
|
|
@@ -128,16 +128,16 @@
|
|
|
128
128
|
"swagger-jsdoc": "^6.2.8",
|
|
129
129
|
"swagger-ui-express": "^5.0.1",
|
|
130
130
|
"zod": "3.25",
|
|
131
|
-
"electron-updater": "6.6.2"
|
|
132
|
-
"electron": "41.0.3"
|
|
131
|
+
"electron-updater": "6.6.2"
|
|
133
132
|
},
|
|
134
133
|
"//optionalDependencies": "Runtime Bundle v1 (主人指令): platform binaries delivered by `npm i -g cicy-desktop` itself — npm installs only the current-platform subpackage (os/cpu pinned in each), so first start seeds the runtime store with ZERO network, ZERO npx. Windows packages are named *-windows-* (npm spam filter 403s new names containing win32). cicy-msys2 added once published.",
|
|
135
134
|
"optionalDependencies": {
|
|
136
|
-
"
|
|
137
|
-
"cicy-code-darwin-
|
|
138
|
-
"cicy-code-
|
|
139
|
-
"cicy-code-linux-
|
|
140
|
-
"cicy-code-
|
|
135
|
+
"electron": "41.0.3",
|
|
136
|
+
"cicy-code-darwin-x64": "2.3.12",
|
|
137
|
+
"cicy-code-darwin-arm64": "2.3.12",
|
|
138
|
+
"cicy-code-linux-x64": "2.3.12",
|
|
139
|
+
"cicy-code-linux-arm64": "2.3.12",
|
|
140
|
+
"cicy-code-windows-x64": "2.3.12",
|
|
141
141
|
"cicy-mihomo-darwin-x64": "1.10.4",
|
|
142
142
|
"cicy-mihomo-darwin-arm64": "1.10.4",
|
|
143
143
|
"cicy-mihomo-linux-x64": "1.10.4",
|
|
@@ -149,6 +149,7 @@
|
|
|
149
149
|
"@babel/core": "^7.29.0",
|
|
150
150
|
"@babel/preset-env": "^7.29.0",
|
|
151
151
|
"axios": "^1.13.5",
|
|
152
|
+
"electron": "41.0.3",
|
|
152
153
|
"electron-builder": "^26.7.0",
|
|
153
154
|
"jest": "^29.7.0",
|
|
154
155
|
"prettier": "^3.8.1",
|
|
@@ -64,12 +64,26 @@ async function execShell(command, opts = {}) {
|
|
|
64
64
|
|
|
65
65
|
contextBridge.exposeInMainWorld("electronRPC", (tool, args) => rpc(tool, args));
|
|
66
66
|
|
|
67
|
-
// i18n: expose t(key, opts) and current locale to render.
|
|
68
|
-
//
|
|
69
|
-
// preload runs in the
|
|
70
|
-
//
|
|
67
|
+
// i18n: expose t(key, opts) and current locale to render.
|
|
68
|
+
//
|
|
69
|
+
// IMPORTANT: this preload runs in the RENDERER process, so `require("../i18n")`
|
|
70
|
+
// gives a SEPARATE i18n instance from the main process — it has no idea what
|
|
71
|
+
// locale the app resolved. Left to its own lazy init() it would fall back to
|
|
72
|
+
// English (pickLocale(undefined) → FALLBACK), which is exactly why the homepage
|
|
73
|
+
// (e.g. the first-run terms gate) showed English even on zh-CN systems. So we
|
|
74
|
+
// pull the resolved locale from main over a synchronous IPC and init THIS
|
|
75
|
+
// instance with it. i18next.init() with inline resources is synchronous, so the
|
|
76
|
+
// language is set immediately and `locale` below reads the correct value.
|
|
71
77
|
let __i18n;
|
|
72
|
-
try {
|
|
78
|
+
try {
|
|
79
|
+
__i18n = require("../i18n");
|
|
80
|
+
let mainLng = "";
|
|
81
|
+
try { mainLng = ipcRenderer.sendSync("i18n:locale"); } catch (_) {}
|
|
82
|
+
__i18n.init(mainLng || undefined);
|
|
83
|
+
if (mainLng && __i18n.i18next.language !== __i18n.pickLocale(mainLng)) {
|
|
84
|
+
__i18n.i18next.changeLanguage(__i18n.pickLocale(mainLng));
|
|
85
|
+
}
|
|
86
|
+
} catch (e) { __i18n = null; }
|
|
73
87
|
contextBridge.exposeInMainWorld("cicyI18n", {
|
|
74
88
|
t: (key, opts) => {
|
|
75
89
|
if (!__i18n) return key;
|
package/src/main.js
CHANGED
|
@@ -81,6 +81,18 @@ const __initialLocale = (() => {
|
|
|
81
81
|
})();
|
|
82
82
|
i18n.init(__initialLocale);
|
|
83
83
|
|
|
84
|
+
// Synchronous bridge so the homepage preload — which runs in the RENDERER
|
|
85
|
+
// process and therefore holds its OWN separate i18n module instance — can
|
|
86
|
+
// resolve the same locale the main process picked. Without this the preload's
|
|
87
|
+
// lazy init() falls back to English regardless of OS language, so
|
|
88
|
+
// window.cicyI18n.t() returned English even on zh-CN systems. Read live at call
|
|
89
|
+
// time, so it reflects the ready-time changeLanguage() below.
|
|
90
|
+
try {
|
|
91
|
+
require("electron").ipcMain.on("i18n:locale", (e) => {
|
|
92
|
+
e.returnValue = (i18n.i18next && i18n.i18next.language) || i18n.FALLBACK || "en";
|
|
93
|
+
});
|
|
94
|
+
} catch {}
|
|
95
|
+
|
|
84
96
|
// Single-instance lock: only one cicy-desktop process can hold the primary
|
|
85
97
|
// instance. A second launch sends `second-instance` with argv to the primary
|
|
86
98
|
// and exits itself. The primary focuses its homepage so the user sees the
|