cicy-desktop 2.1.321 → 2.1.323
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/preinstall.sh +31 -31
- package/package.json +5 -5
- package/scripts/deploy-exe-fleet.sh +4 -3
- package/src/backends/hub-client.js +82 -13
- package/src/config.js +8 -8
- package/src/main-old.js +837 -837
- package/src/server/express-app.js +174 -174
- package/src/server/mcp-server.js +53 -53
- package/src/server/ui-routes.js +81 -81
- package/src/tabbrowser/telegram-matrix.html +101 -76
- package/src/tools/account-tools.js +389 -389
- package/src/tools/automation-tools.js +297 -297
- package/src/tools/cdp-tools.js +444 -444
- package/src/tools/clipboard-tools.js +180 -180
- package/src/tools/download-tools.js +57 -57
- package/src/tools/exec-js.js +257 -257
- package/src/tools/file-tools.js +212 -212
- package/src/tools/hook-chatgpt.js +489 -489
- package/src/tools/index.js +21 -21
- package/src/tools/screenshot-tools.js +28 -28
- package/src/tools/system-tools.js +531 -531
- package/src/utils/cdp-utils.js +8 -8
- package/src/utils/download-manager.js +41 -41
- package/src/utils/process-utils.js +185 -185
- package/src/utils/snapshot-utils.js +56 -56
- package/test/telegram-matrix.test.js +6 -6
package/bin/preinstall.sh
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
set -e
|
|
4
|
-
|
|
5
|
-
echo "Installing electron globally..."
|
|
6
|
-
|
|
7
|
-
if [ "$(uname)" = "Linux" ]; then
|
|
8
|
-
sudo npm install -g electron
|
|
9
|
-
else
|
|
10
|
-
npm install -g electron
|
|
11
|
-
fi
|
|
12
|
-
|
|
13
|
-
if [ "$(uname)" = "Linux" ]; then
|
|
14
|
-
echo "Fixing chrome-sandbox permissions on Linux..."
|
|
15
|
-
ELECTRON_PATH=$(which electron)
|
|
16
|
-
ELECTRON_DIR=$(dirname "$ELECTRON_PATH")
|
|
17
|
-
SANDBOX_PATH="$ELECTRON_DIR/../lib/node_modules/electron/dist/chrome-sandbox"
|
|
18
|
-
|
|
19
|
-
if [ -f "$SANDBOX_PATH" ]; then
|
|
20
|
-
if command -v sudo &> /dev/null; then
|
|
21
|
-
sudo chown root:root "$SANDBOX_PATH"
|
|
22
|
-
sudo chmod 4755 "$SANDBOX_PATH"
|
|
23
|
-
echo "chrome-sandbox permissions fixed"
|
|
24
|
-
else
|
|
25
|
-
echo "Warning: sudo not available, skipping chrome-sandbox permissions"
|
|
26
|
-
fi
|
|
27
|
-
else
|
|
28
|
-
echo "Warning: chrome-sandbox not found at $SANDBOX_PATH"
|
|
29
|
-
fi
|
|
30
|
-
fi
|
|
31
|
-
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
echo "Installing electron globally..."
|
|
6
|
+
|
|
7
|
+
if [ "$(uname)" = "Linux" ]; then
|
|
8
|
+
sudo npm install -g electron
|
|
9
|
+
else
|
|
10
|
+
npm install -g electron
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
if [ "$(uname)" = "Linux" ]; then
|
|
14
|
+
echo "Fixing chrome-sandbox permissions on Linux..."
|
|
15
|
+
ELECTRON_PATH=$(which electron)
|
|
16
|
+
ELECTRON_DIR=$(dirname "$ELECTRON_PATH")
|
|
17
|
+
SANDBOX_PATH="$ELECTRON_DIR/../lib/node_modules/electron/dist/chrome-sandbox"
|
|
18
|
+
|
|
19
|
+
if [ -f "$SANDBOX_PATH" ]; then
|
|
20
|
+
if command -v sudo &> /dev/null; then
|
|
21
|
+
sudo chown root:root "$SANDBOX_PATH"
|
|
22
|
+
sudo chmod 4755 "$SANDBOX_PATH"
|
|
23
|
+
echo "chrome-sandbox permissions fixed"
|
|
24
|
+
else
|
|
25
|
+
echo "Warning: sudo not available, skipping chrome-sandbox permissions"
|
|
26
|
+
fi
|
|
27
|
+
else
|
|
28
|
+
echo "Warning: chrome-sandbox not found at $SANDBOX_PATH"
|
|
29
|
+
fi
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
32
|
echo "Electron setup complete"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cicy-desktop",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.323",
|
|
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.
|
|
148
|
-
"cicy-code-darwin-arm64": "2.3.
|
|
149
|
-
"cicy-code-linux-x64": "2.3.
|
|
150
|
-
"cicy-code-linux-arm64": "2.3.
|
|
147
|
+
"cicy-code-darwin-x64": "2.3.592",
|
|
148
|
+
"cicy-code-darwin-arm64": "2.3.592",
|
|
149
|
+
"cicy-code-linux-x64": "2.3.592",
|
|
150
|
+
"cicy-code-linux-arm64": "2.3.592",
|
|
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",
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
+
# Superseded by the cicy-exe-deploy skill (cicy-skills/skills/cicy-exe-deploy) — kept as a plain-ssh fallback.
|
|
2
3
|
# Push a locally built CiCy Desktop installer to every Windows node and install
|
|
3
4
|
# it there — no CDN, no auto-update wait.
|
|
4
5
|
#
|
|
5
6
|
# scripts/deploy-exe-fleet.sh [path/to/CiCy Desktop Setup X.Y.Z.exe] [node...]
|
|
6
7
|
#
|
|
7
8
|
# Per node (ssh alias from ~/.ssh/config, e.g. xs-1001 — frp via ws-hub):
|
|
8
|
-
# 1. scp the exe into the node's ~/projects (= C:\ of its Windows host)
|
|
9
|
+
# 1. scp the exe into the node's ~/projects (= C:\projects of its Windows host)
|
|
9
10
|
# 2. ssh -L tunnel to the node's cicy-code :8008, ask it for connected
|
|
10
11
|
# cicy-desktop clients (agent-desktop clients)
|
|
11
12
|
# 3. agent-desktop exec-file a tiny .bat on each Windows client that runs the
|
|
@@ -24,12 +25,12 @@ fi
|
|
|
24
25
|
shift || true
|
|
25
26
|
VER=$(basename "$EXE" | sed -E 's/.*Setup ([0-9.]+)\.exe/\1/')
|
|
26
27
|
REMOTE_NAME="CiCy-Desktop-Setup-$VER.exe"
|
|
27
|
-
WIN_PATH="C
|
|
28
|
+
WIN_PATH="C:\\projects\\$REMOTE_NAME"
|
|
28
29
|
|
|
29
30
|
if [ $# -gt 0 ]; then NODES="$*"; fi
|
|
30
31
|
if [ -z "${NODES:-}" ]; then
|
|
31
32
|
# every xs-* alias in ~/.ssh/config (Windows hosts); mac-local etc. are not exe targets
|
|
32
|
-
NODES=$(awk '/^Host xs-/{print $2}' ~/.ssh/config | sort -V)
|
|
33
|
+
NODES=$(awk '/^Host xs-/ && $2 !~ /[*?]/{print $2}' ~/.ssh/config | sort -V)
|
|
33
34
|
fi
|
|
34
35
|
PORT=${LOCAL_PORT_BASE:-18100}
|
|
35
36
|
SCRATCH=$(mktemp -d)
|
|
@@ -62,20 +62,72 @@ function desktopInstanceId() {
|
|
|
62
62
|
return id;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
// Electron's net.fetch goes through Chromium's network stack — it honours the
|
|
66
|
+
// OS proxy settings (PAC / system proxy) like the renderer does. Node's global
|
|
67
|
+
// fetch ignores them, which showed up as "fetch failed" on PCs that can only
|
|
68
|
+
// reach the hub through a proxy. Falls back to global fetch outside Electron.
|
|
69
|
+
function pickFetch() {
|
|
70
|
+
try { const { net, app } = require("electron"); if (net && typeof net.fetch === "function" && app && app.isReady()) return net.fetch.bind(net); } catch {}
|
|
71
|
+
return fetch;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function hubFetch(route, { method = "GET", token = "", body = null, tries = 2 } = {}) {
|
|
75
|
+
let lastErr;
|
|
76
|
+
for (let attempt = 0; attempt < tries; attempt++) {
|
|
77
|
+
const ctrl = new AbortController();
|
|
78
|
+
const t = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
|
|
79
|
+
try {
|
|
80
|
+
const headers = { accept: "application/json" };
|
|
81
|
+
if (token) headers.authorization = "Bearer " + token;
|
|
82
|
+
if (body != null) headers["content-type"] = "application/json";
|
|
83
|
+
const r = await pickFetch()(hubOrigin() + route, { method, headers, body: body == null ? undefined : JSON.stringify(body), signal: ctrl.signal, cache: "no-store" });
|
|
84
|
+
const text = await r.text();
|
|
85
|
+
let json = null;
|
|
86
|
+
try { json = text ? JSON.parse(text) : null; } catch {}
|
|
87
|
+
return { status: r.status, ok: r.ok, json, text };
|
|
88
|
+
} catch (e) {
|
|
89
|
+
lastErr = e;
|
|
90
|
+
log.warn(`[hub] ${method} ${route} failed (${attempt + 1}/${tries}): ${e.message}`);
|
|
91
|
+
if (attempt + 1 < tries) await new Promise((r) => setTimeout(r, 1500));
|
|
92
|
+
} finally { clearTimeout(t); }
|
|
93
|
+
}
|
|
94
|
+
const msg = String((lastErr && lastErr.message) || lastErr || "fetch failed");
|
|
95
|
+
throw new Error(/fetch failed|ECONN|ENOTFOUND|abort/i.test(msg) ? `hub unreachable (${hubOrigin()}): ${msg}` : msg);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ── fallback: the local cicy-code sidecar ───────────────────────────────────
|
|
99
|
+
// Some PCs cannot reach the hub directly at all (no proxy on Windows) while the
|
|
100
|
+
// cicy-code container on the same PC can (it carries its own proxy) and is
|
|
101
|
+
// signed in to the same hub account. Its /api/im/cicy-cloud/* routes give us
|
|
102
|
+
// the same instance list and one-time open grants, so use them when the direct
|
|
103
|
+
// call dies with a network error.
|
|
104
|
+
const SIDECAR_PORT = Number(process.env.CICY_SIDECAR_PORT || 8008);
|
|
105
|
+
let _sidecarTok = { value: "", at: 0 };
|
|
106
|
+
async function sidecarToken() {
|
|
107
|
+
if (_sidecarTok.value && Date.now() - _sidecarTok.at < 5 * 60 * 1000) return _sidecarTok.value;
|
|
108
|
+
let tok = "";
|
|
109
|
+
try { tok = String(readGlobalConfig(GLOBAL_JSON)?.api_token || "").trim(); } catch {}
|
|
110
|
+
if (!tok && process.platform === "win32") {
|
|
111
|
+
try { tok = String(await require("../sidecar/wsl-docker").readContainerToken(SIDECAR_PORT) || "").trim(); } catch (e) { log.warn(`[hub] sidecar token: ${e.message}`); }
|
|
112
|
+
}
|
|
113
|
+
if (tok) _sidecarTok = { value: tok, at: Date.now() };
|
|
114
|
+
return tok;
|
|
115
|
+
}
|
|
116
|
+
async function sidecarFetch(route, { method = "GET", body = null } = {}) {
|
|
117
|
+
const tok = await sidecarToken();
|
|
118
|
+
if (!tok) throw new Error("local cicy-code token unavailable");
|
|
66
119
|
const ctrl = new AbortController();
|
|
67
120
|
const t = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
|
|
68
121
|
try {
|
|
69
|
-
const headers = { accept: "application/json" };
|
|
70
|
-
if (token) headers.authorization = "Bearer " + token;
|
|
122
|
+
const headers = { accept: "application/json", authorization: "Bearer " + tok };
|
|
71
123
|
if (body != null) headers["content-type"] = "application/json";
|
|
72
|
-
const r = await fetch(
|
|
124
|
+
const r = await fetch(`http://127.0.0.1:${SIDECAR_PORT}${route}`, { method, headers, body: body == null ? undefined : JSON.stringify(body), signal: ctrl.signal, cache: "no-store" });
|
|
73
125
|
const text = await r.text();
|
|
74
|
-
let json = null;
|
|
75
|
-
try { json = text ? JSON.parse(text) : null; } catch {}
|
|
126
|
+
let json = null; try { json = text ? JSON.parse(text) : null; } catch {}
|
|
76
127
|
return { status: r.status, ok: r.ok, json, text };
|
|
77
128
|
} finally { clearTimeout(t); }
|
|
78
129
|
}
|
|
130
|
+
const isNetErr = (e) => /unreachable|fetch failed|ECONN|ENOTFOUND|abort/i.test(String((e && e.message) || e));
|
|
79
131
|
|
|
80
132
|
function errorOf(res, fallback) {
|
|
81
133
|
return (res && res.json && (res.json.error || res.json.message)) || fallback || `HTTP ${res && res.status}`;
|
|
@@ -168,18 +220,27 @@ function clearAuth() {
|
|
|
168
220
|
async function instances() {
|
|
169
221
|
const a = readAuth();
|
|
170
222
|
if (!a) return { ok: false, error: "not_logged_in", instances: [] };
|
|
171
|
-
|
|
172
|
-
|
|
223
|
+
let res, viaSidecar = false;
|
|
224
|
+
try { res = await hubFetch("/api/instances", { token: a.token }); }
|
|
225
|
+
catch (e) {
|
|
226
|
+
if (!isNetErr(e)) return { ok: false, error: e.message, instances: [] };
|
|
227
|
+
log.warn(`[hub] direct instance list failed (${e.message}); trying the local cicy-code`);
|
|
228
|
+
try { res = await sidecarFetch("/api/im/cicy-cloud/instances"); viaSidecar = true; }
|
|
229
|
+
catch (e2) { return { ok: false, error: `${e.message}; sidecar: ${e2.message}`, instances: [] }; }
|
|
230
|
+
}
|
|
231
|
+
if (res.status === 401 && !viaSidecar) { clearAuth(); return { ok: false, error: "unauthorized", instances: [] }; }
|
|
173
232
|
if (!res.ok || !res.json) return { ok: false, error: errorOf(res, "instances_failed"), instances: [] };
|
|
174
233
|
const list = Array.isArray(res.json.instances) ? res.json.instances : [];
|
|
175
234
|
const out = list
|
|
176
|
-
|
|
235
|
+
// direct: `self` is this desktop's hidden pseudo-instance; via sidecar: `self` is the
|
|
236
|
+
// local node itself, which IS a real instance the user may want to open.
|
|
237
|
+
.filter((i) => (viaSidecar || !i.self) && !String(i.platform || "").startsWith("desktop"))
|
|
177
238
|
.map((i) => ({
|
|
178
239
|
id: i.instanceId,
|
|
179
|
-
name: i.name || i.proxyHost
|
|
240
|
+
name: i.name || (i.proxyHost ? String(i.proxyHost).split(".")[0] : i.instanceId),
|
|
180
241
|
host: i.proxyHost || "",
|
|
181
242
|
url: i.proxyHost ? "https://" + i.proxyHost : "",
|
|
182
|
-
online: !!i.online,
|
|
243
|
+
online: i.status ? i.status === "online" : !!i.online,
|
|
183
244
|
reachable: !!i.proxyAvailable,
|
|
184
245
|
version: i.version || "",
|
|
185
246
|
platform: i.platform || "",
|
|
@@ -192,14 +253,22 @@ async function instances() {
|
|
|
192
253
|
agents: Array.isArray(i.agents) ? i.agents.length : undefined,
|
|
193
254
|
}))
|
|
194
255
|
.sort((x, y) => Number(y.online) - Number(x.online) || x.name.localeCompare(y.name));
|
|
195
|
-
return { ok: true, owner: res.json.owner || a.owner, instances: out };
|
|
256
|
+
return { ok: true, owner: res.json.owner || a.owner, viaSidecar, instances: out };
|
|
196
257
|
}
|
|
197
258
|
|
|
198
259
|
// One-time hand-off URL for an instance (optionally one of its local ports).
|
|
199
260
|
async function grantUrl({ id, port = 0, next = "/" } = {}) {
|
|
200
261
|
const a = readAuth();
|
|
201
262
|
if (!a) throw new Error("not_logged_in");
|
|
202
|
-
|
|
263
|
+
let res;
|
|
264
|
+
try { res = await hubFetch("/api/gateway/grant", { method: "POST", token: a.token, body: { instanceId: String(id || ""), port: Number(port) || 0, next: String(next || "/") } }); }
|
|
265
|
+
catch (e) {
|
|
266
|
+
if (!isNetErr(e)) throw e;
|
|
267
|
+
log.warn(`[hub] direct grant failed (${e.message}); trying the local cicy-code`);
|
|
268
|
+
res = await sidecarFetch("/api/im/cicy-cloud/open", { method: "POST", body: { instance_id: String(id || ""), port: Number(port) || 0, next: String(next || "/") } });
|
|
269
|
+
if (!res.ok || !res.json || !res.json.url) throw new Error(errorOf(res, "grant_failed"));
|
|
270
|
+
return { url: res.json.url, host: res.json.host };
|
|
271
|
+
}
|
|
203
272
|
if (res.status === 401) { clearAuth(); throw new Error("unauthorized"); }
|
|
204
273
|
if (!res.ok || !res.json || !res.json.url) throw new Error(errorOf(res, "grant_failed"));
|
|
205
274
|
return { url: res.json.url, host: res.json.host };
|
package/src/config.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Copyright 2026 CiCy AI
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
module.exports = {
|
|
5
|
-
config: {
|
|
6
|
-
port: null,
|
|
7
|
-
logsDir: null,
|
|
8
|
-
logFilePath: null,
|
|
9
|
-
oneWindow: false,
|
|
10
|
-
},
|
|
11
|
-
};
|
|
4
|
+
module.exports = {
|
|
5
|
+
config: {
|
|
6
|
+
port: null,
|
|
7
|
+
logsDir: null,
|
|
8
|
+
logFilePath: null,
|
|
9
|
+
oneWindow: false,
|
|
10
|
+
},
|
|
11
|
+
};
|