cicy-desktop 2.1.240 → 2.1.242
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 +5 -5
- package/src/backends/local-teams.js +27 -3
- package/src/main.js +26 -0
- package/src/sidecar/native.js +9 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cicy-desktop",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.242",
|
|
4
4
|
"description": "CiCy - AI-powered operating system browser",
|
|
5
5
|
"main": "src/main.js",
|
|
6
6
|
"bin": {
|
|
@@ -139,10 +139,10 @@
|
|
|
139
139
|
"//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 着无害。",
|
|
140
140
|
"optionalDependencies": {
|
|
141
141
|
"electron": "41.0.3",
|
|
142
|
-
"cicy-code-darwin-x64": "2.3.
|
|
143
|
-
"cicy-code-darwin-arm64": "2.3.
|
|
144
|
-
"cicy-code-linux-x64": "2.3.
|
|
145
|
-
"cicy-code-linux-arm64": "2.3.
|
|
142
|
+
"cicy-code-darwin-x64": "2.3.203",
|
|
143
|
+
"cicy-code-darwin-arm64": "2.3.203",
|
|
144
|
+
"cicy-code-linux-x64": "2.3.203",
|
|
145
|
+
"cicy-code-linux-arm64": "2.3.203",
|
|
146
146
|
"cicy-code-windows-x64": "2.3.193",
|
|
147
147
|
"cicy-mihomo-darwin-x64": "1.10.4",
|
|
148
148
|
"cicy-mihomo-darwin-arm64": "1.10.4",
|
|
@@ -572,8 +572,10 @@ async function pullCustomTeams() {
|
|
|
572
572
|
for (const [k, v] of Object.entries(nodes)) { if (v?.cloud_team_id != null) byCloudId[String(v.cloud_team_id)] = k; }
|
|
573
573
|
let added = 0, updated = 0;
|
|
574
574
|
for (const t of list.teams) {
|
|
575
|
-
|
|
576
|
-
|
|
575
|
+
// custom teams (remote URL) OR any team with a zero-trust gateway address:
|
|
576
|
+
// gateway teams are reached at <slug>.gw.cicy-ai.com (preferred over host_url).
|
|
577
|
+
if (t.kind !== "custom" && !t.gateway_url) continue;
|
|
578
|
+
const host = String(t.gateway_url || t.host_url || t.hostUrl || "").trim();
|
|
577
579
|
if (!host) continue;
|
|
578
580
|
const tid = t.teamId || t.id || null;
|
|
579
581
|
const localId = tid != null ? byCloudId[String(tid)] : null;
|
|
@@ -1099,4 +1101,26 @@ function avatarForUrl(url) {
|
|
|
1099
1101
|
return "";
|
|
1100
1102
|
}
|
|
1101
1103
|
|
|
1102
|
-
|
|
1104
|
+
// Remove teams tied to a cloud ACCOUNT (remote base_url — pulled from the cloud
|
|
1105
|
+
// via pullCustomTeams, or user-added remote nodes) so switching/leaving an account
|
|
1106
|
+
// doesn't leak them onto the next user. LOCAL machine teams on THIS device
|
|
1107
|
+
// (localhost base_url) are kept — they belong to the box, not the account. The
|
|
1108
|
+
// next login re-pulls the new account's own teams fresh.
|
|
1109
|
+
async function purgeAccountTeams() {
|
|
1110
|
+
let removed = 0;
|
|
1111
|
+
try {
|
|
1112
|
+
await writeNodes((nodes) => {
|
|
1113
|
+
for (const id of Object.keys(nodes)) {
|
|
1114
|
+
let host = "";
|
|
1115
|
+
try { host = new URL(String(nodes[id]?.base_url || "")).hostname.toLowerCase(); } catch {}
|
|
1116
|
+
const isLocal = host === "" || host === "127.0.0.1" || host === "localhost" || host === "::1";
|
|
1117
|
+
if (!isLocal) { delete nodes[id]; removed++; }
|
|
1118
|
+
}
|
|
1119
|
+
return nodes;
|
|
1120
|
+
});
|
|
1121
|
+
} catch (e) { log.warn(`[local-teams] purgeAccountTeams failed: ${e.message}`); }
|
|
1122
|
+
if (removed) { _cache = null; _cacheUntil = 0; log.info(`[local-teams] purged ${removed} account team(s) (login/logout)`); }
|
|
1123
|
+
return removed;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
module.exports = { list, openTeam, reloadTeam, closeLocalWindows, addTeam, removeTeam, updateTeam, upgradeTeam, syncAllLocalTeams, purgeAccountTeams, setAvatar, getAvatars, avatarForUrl };
|
package/src/main.js
CHANGED
|
@@ -998,6 +998,17 @@ electronApp.whenReady().then(async () => {
|
|
|
998
998
|
// renderer. A completed email login is thus indistinguishable downstream.
|
|
999
999
|
const onAuthResult = (payload) => {
|
|
1000
1000
|
if (payload && payload.token) {
|
|
1001
|
+
// Account isolation: if a DIFFERENT user is signing in, drop the previous
|
|
1002
|
+
// account's cloud/remote teams so they don't leak onto this account. The
|
|
1003
|
+
// login below re-pulls this account's own teams fresh. Local machine
|
|
1004
|
+
// teams (localhost) are kept — they belong to the device.
|
|
1005
|
+
try {
|
|
1006
|
+
const prevUid = String((readGlobalConfig(GLOBAL_JSON)?.desktopAuth?.userId) || "");
|
|
1007
|
+
const nextUid = payload.userId != null ? String(payload.userId) : "";
|
|
1008
|
+
if (prevUid && nextUid && prevUid !== nextUid) {
|
|
1009
|
+
require("./backends/local-teams").purgeAccountTeams().catch(() => {});
|
|
1010
|
+
}
|
|
1011
|
+
} catch {}
|
|
1001
1012
|
saveDesktopAuth(payload);
|
|
1002
1013
|
// Now that we have a real owner-bound login token, report this
|
|
1003
1014
|
// machine to the cloud (best-effort; safe to call repeatedly —
|
|
@@ -1067,6 +1078,8 @@ electronApp.whenReady().then(async () => {
|
|
|
1067
1078
|
__ipcMainAuth.handle("auth:logout", () => {
|
|
1068
1079
|
try {
|
|
1069
1080
|
updateGlobalConfig(GLOBAL_JSON, (c) => { delete c.desktopAuth; return c; });
|
|
1081
|
+
// Drop this account's cloud/remote teams on logout (local machines stay).
|
|
1082
|
+
require("./backends/local-teams").purgeAccountTeams().catch(() => {});
|
|
1070
1083
|
log.info("[auth] desktop login cleared (explicit logout)");
|
|
1071
1084
|
} catch (e) { log.warn(`[auth] logout clear failed: ${e.message}`); }
|
|
1072
1085
|
return { ok: true };
|
|
@@ -1123,6 +1136,19 @@ electronApp.whenReady().then(async () => {
|
|
|
1123
1136
|
.catch((e) => log.warn(`[cloud] device-info/register (on launch) failed: ${e.message}`));
|
|
1124
1137
|
} catch (e) { log.warn(`[cloud] device-info launch hook failed: ${e.message}`); }
|
|
1125
1138
|
|
|
1139
|
+
// Periodic device heartbeat → lets the ops backend show per-device liveness.
|
|
1140
|
+
// Re-POST /api/device/register every 60s (idempotent upsert by owner+deviceId;
|
|
1141
|
+
// cloud records last_seen on each call → "active if now - last_seen < N min").
|
|
1142
|
+
// Runs in MAIN, not the renderer, so it keeps beating even when the homepage
|
|
1143
|
+
// window is hidden/minimized. Best-effort, no-op when not logged in;
|
|
1144
|
+
// registerDevice reads cached deviceInfo (no network detection per beat).
|
|
1145
|
+
try {
|
|
1146
|
+
const cc = require("./cloud/cloud-client");
|
|
1147
|
+
const HEARTBEAT_MS = Math.max(15000, Number(process.env.CICY_DEVICE_HEARTBEAT_MS || 60000));
|
|
1148
|
+
const beat = setInterval(() => { try { cc.registerDevice().catch(() => {}); } catch (_) {} }, HEARTBEAT_MS);
|
|
1149
|
+
if (beat && typeof beat.unref === "function") beat.unref();
|
|
1150
|
+
} catch (e) { log.warn(`[cloud] device heartbeat setup failed: ${e.message}`); }
|
|
1151
|
+
|
|
1126
1152
|
// Cloud↔desktop title reconcile. The homepage drives the FAST cadence by window
|
|
1127
1153
|
// visibility (聚焦 ~3s / 切回立即,见 App.jsx + localTeams:syncCloud IPC). This
|
|
1128
1154
|
// 30s timer is just the SLOW fallback for when no homepage window is open / it's
|
package/src/sidecar/native.js
CHANGED
|
@@ -143,7 +143,15 @@ async function start({ port = 8008, logPath = null, emit, version = null } = {})
|
|
|
143
143
|
};
|
|
144
144
|
// --helper removed : boot cicy-code in normal mode (full tmux-based
|
|
145
145
|
// multi-agent), not the single headless 团队助手.
|
|
146
|
-
const
|
|
146
|
+
const args = ["--desktop"];
|
|
147
|
+
// Host role: if a zero-trust gateway is provisioned (~/cicy-ai/db/gateway.json
|
|
148
|
+
// with url+token), boot with --gateway so this machine dials OUT and becomes
|
|
149
|
+
// reachable through the gateway (no inbound port). Absent → plain local boot.
|
|
150
|
+
try {
|
|
151
|
+
const gwPath = require("path").join(require("os").homedir(), "cicy-ai", "db", "gateway.json");
|
|
152
|
+
if (require("fs").existsSync(gwPath)) args.push("--gateway");
|
|
153
|
+
} catch { /* best-effort */ }
|
|
154
|
+
const child = spawn(exe, args, { stdio, detached: true, windowsHide: true, env });
|
|
147
155
|
child.unref();
|
|
148
156
|
try { fs.writeFileSync(PID_FILE, String(child.pid)); } catch {}
|
|
149
157
|
console.log(`[native-sidecar] spawned ${exe} --desktop pid=${child.pid} port=${port} log=${logPath || "(none)"}`);
|