cicy-desktop 2.1.152 → 2.1.153
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/.github/workflows/mac-app-release.yml +32 -0
- package/.github/workflows/windows-exe-release.yml +5 -0
- package/package.json +1 -1
- package/scripts/mac-allinone/postinstall +41 -1
- package/src/main.js +3 -5
- package/src/tools/desktop-snapshot-tools.js +8 -2
- package/src/utils/desktop-snapshot.js +11 -1
|
@@ -228,3 +228,35 @@ jobs:
|
|
|
228
228
|
echo "::warning::pkgbuild failed for $ARCH (other arch unaffected)"
|
|
229
229
|
fi
|
|
230
230
|
done
|
|
231
|
+
|
|
232
|
+
# Publish the .pkg installers to OSS (CN-fast). GitHub release downloads stall from
|
|
233
|
+
# mainland China, so users in CN pull from OSS instead. Each arch gets a versioned key
|
|
234
|
+
# plus a stable cicy-desktop-mac-<arch>-latest.pkg alias a download page can hard-link.
|
|
235
|
+
# Same bucket/creds as the Windows latest.exe step.
|
|
236
|
+
- name: Upload .pkg to OSS (versioned + per-arch latest alias)
|
|
237
|
+
continue-on-error: true # OSS is a convenience mirror — never fail the release
|
|
238
|
+
shell: bash
|
|
239
|
+
env:
|
|
240
|
+
OSS_AK: ${{ secrets.OSS_ACCESS_KEY_ID }}
|
|
241
|
+
OSS_SK: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
|
|
242
|
+
run: |
|
|
243
|
+
set -uo pipefail
|
|
244
|
+
VER="${{ steps.meta.outputs.version }}"
|
|
245
|
+
if [ -z "${OSS_AK:-}" ] || [ -z "${OSS_SK:-}" ]; then
|
|
246
|
+
echo "::warning::OSS creds missing — skipping OSS mirror"; exit 0
|
|
247
|
+
fi
|
|
248
|
+
curl -fsSL -o ossutil.zip "https://gosspublic.alicdn.com/ossutil/1.7.18/ossutil-v1.7.18-mac-arm64.zip"
|
|
249
|
+
unzip -oq ossutil.zip
|
|
250
|
+
OSS="./ossutil-v1.7.18-mac-arm64/ossutil"; chmod +x "$OSS"
|
|
251
|
+
"$OSS" config -e oss-cn-shanghai.aliyuncs.com -i "$OSS_AK" -k "$OSS_SK"
|
|
252
|
+
BASE="oss://cicy-1372193042-cn/releases"
|
|
253
|
+
HOST="https://cicy-1372193042-cn.oss-cn-shanghai.aliyuncs.com/releases"
|
|
254
|
+
for ARCH in x64 arm64; do
|
|
255
|
+
PKG="cicy-desktop-$VER-$ARCH.pkg"
|
|
256
|
+
[ -f "$PKG" ] || { echo "::warning::$PKG not built — skipping OSS for $ARCH"; continue; }
|
|
257
|
+
"$OSS" cp "$PKG" "$BASE/$PKG" -f --acl public-read || { echo "::warning::OSS versioned upload failed $ARCH"; continue; }
|
|
258
|
+
"$OSS" cp "$PKG" "$BASE/cicy-desktop-mac-$ARCH-latest.pkg" -f --acl public-read || echo "::warning::OSS latest upload failed $ARCH"
|
|
259
|
+
echo "OSS $ARCH: $HOST/cicy-desktop-mac-$ARCH-latest.pkg"
|
|
260
|
+
done
|
|
261
|
+
printf '%s' "$VER" > mac-latest-version.txt
|
|
262
|
+
"$OSS" cp mac-latest-version.txt "$BASE/mac-latest-version.txt" -f --acl public-read || true
|
|
@@ -138,6 +138,11 @@ jobs:
|
|
|
138
138
|
Set-Content -NoNewline -Path "current-latest.txt" -Value $version
|
|
139
139
|
& $oss cp "current-latest.txt" "$base/latest-version.txt" -f --acl public-read
|
|
140
140
|
if ($LASTEXITCODE -ne 0) { Write-Error "latest-version.txt upload failed"; exit 1 }
|
|
141
|
+
# Unified per-platform naming: cicy-desktop-<platform>-latest.<ext> so every OS
|
|
142
|
+
# shares one URL shape (win + mac-x64 + mac-arm64). The bare cicy-desktop-latest.exe
|
|
143
|
+
# / latest-version.txt above are kept as backward-compat aliases for old links.
|
|
144
|
+
& $oss cp "$($exe.FullName)" "$base/cicy-desktop-win-latest.exe" -f --acl public-read
|
|
145
|
+
& $oss cp "current-latest.txt" "$base/win-latest-version.txt" -f --acl public-read
|
|
141
146
|
} else {
|
|
142
147
|
Write-Host "Skip latest: building $version < published $cur (older build — not clobbering newer latest)"
|
|
143
148
|
}
|
package/package.json
CHANGED
|
@@ -7,7 +7,47 @@ APP="/Applications/CiCy Desktop.app"
|
|
|
7
7
|
[ -d "$APP" ] || exit 0
|
|
8
8
|
/usr/bin/xattr -dr com.apple.quarantine "$APP" 2>/dev/null || true
|
|
9
9
|
/usr/bin/xattr -cr "$APP" 2>/dev/null || true
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
# ── Stable LOCAL code-signing identity (主人令: 用自签证书) ────────────────────
|
|
12
|
+
# ad-hoc has no stable identity, so macOS never persists the Screen-Recording TCC
|
|
13
|
+
# grant → it re-prompts forever. A self-signed cert gives the app a STABLE designated
|
|
14
|
+
# requirement, so the grant sticks after the user allows it once. We run as root here,
|
|
15
|
+
# so we can write the System keychain + trust the cert with NO password prompt.
|
|
16
|
+
SIGN_CN="CiCy Desktop Local Signing"
|
|
17
|
+
SYS_KC="/Library/Keychains/System.keychain"
|
|
18
|
+
if ! /usr/bin/security find-identity -p codesigning "$SYS_KC" 2>/dev/null | grep -qF "$SIGN_CN"; then
|
|
19
|
+
TMPD="$(/usr/bin/mktemp -d)"
|
|
20
|
+
# Config file (portable across the LibreSSL that ships in /usr/bin/openssl, which
|
|
21
|
+
# lacks `-addext`). codeSigning EKU is what makes it a valid signing identity.
|
|
22
|
+
cat > "$TMPD/c.cnf" <<CNF
|
|
23
|
+
[req]
|
|
24
|
+
distinguished_name = dn
|
|
25
|
+
x509_extensions = v3
|
|
26
|
+
prompt = no
|
|
27
|
+
[dn]
|
|
28
|
+
CN = $SIGN_CN
|
|
29
|
+
[v3]
|
|
30
|
+
basicConstraints = critical,CA:false
|
|
31
|
+
keyUsage = critical,digitalSignature
|
|
32
|
+
extendedKeyUsage = critical,codeSigning
|
|
33
|
+
CNF
|
|
34
|
+
/usr/bin/openssl req -x509 -newkey rsa:2048 -keyout "$TMPD/k.pem" -out "$TMPD/c.pem" \
|
|
35
|
+
-days 3650 -nodes -config "$TMPD/c.cnf" >/dev/null 2>&1
|
|
36
|
+
/usr/bin/openssl pkcs12 -export -inkey "$TMPD/k.pem" -in "$TMPD/c.pem" \
|
|
37
|
+
-out "$TMPD/id.p12" -passout pass:cicy -name "$SIGN_CN" >/dev/null 2>&1
|
|
38
|
+
# -A = no ACL on the key → codesign can use it without a partition-list/password dance.
|
|
39
|
+
/usr/bin/security import "$TMPD/id.p12" -k "$SYS_KC" -P cicy -A >/dev/null 2>&1 || true
|
|
40
|
+
/usr/bin/security add-trusted-cert -d -r trustRoot -p codeSign -k "$SYS_KC" "$TMPD/c.pem" >/dev/null 2>&1 || true
|
|
41
|
+
/bin/rm -rf "$TMPD"
|
|
42
|
+
fi
|
|
43
|
+
if /usr/bin/security find-identity -p codesigning "$SYS_KC" 2>/dev/null | grep -qF "$SIGN_CN"; then
|
|
44
|
+
/usr/bin/codesign --force --deep --sign "$SIGN_CN" --keychain "$SYS_KC" "$APP" 2>/dev/null \
|
|
45
|
+
&& echo "signed with local identity: $SIGN_CN" \
|
|
46
|
+
|| /usr/bin/codesign --force --deep --sign - "$APP" 2>/dev/null || true
|
|
47
|
+
else
|
|
48
|
+
echo "local identity unavailable — falling back to ad-hoc"
|
|
49
|
+
/usr/bin/codesign --force --deep --sign - "$APP" 2>/dev/null || true
|
|
50
|
+
fi
|
|
11
51
|
|
|
12
52
|
# Desktop shortcut for the logged-in user (postinstall runs as root, so resolve the
|
|
13
53
|
# console user + their home and chown the symlink to them). Launchpad/Spotlight pick
|
package/src/main.js
CHANGED
|
@@ -1089,13 +1089,11 @@ electronApp.whenReady().then(async () => {
|
|
|
1089
1089
|
// the prompt fires over and over. So it's OFF by default on macOS (most users —
|
|
1090
1090
|
// docker/team management — don't need the agent to watch their screen). Opt in with
|
|
1091
1091
|
// CICY_DESKTOP_SNAPSHOT=1. Other platforms stay on (opt out with =0).
|
|
1092
|
-
const
|
|
1093
|
-
|
|
1094
|
-
: process.env.CICY_DESKTOP_SNAPSHOT !== "0";
|
|
1095
|
-
if (!global.__cicyDesktopSnapStarted && __snapOn) {
|
|
1092
|
+
const __snap = require("./utils/desktop-snapshot");
|
|
1093
|
+
if (!global.__cicyDesktopSnapStarted && __snap.snapshotEnabled()) {
|
|
1096
1094
|
global.__cicyDesktopSnapStarted = true;
|
|
1097
1095
|
try {
|
|
1098
|
-
const info =
|
|
1096
|
+
const info = __snap.startDesktopSnapshots();
|
|
1099
1097
|
log.info(`[desktop-snap] desktop snapshots → ${info.dir} (every ${info.intervalMs}ms, maxW ${info.maxWidth}, mode ${info.mode})`);
|
|
1100
1098
|
} catch (e) { log.warn(`[desktop-snap] start failed: ${e.message}`); }
|
|
1101
1099
|
}
|
|
@@ -51,7 +51,10 @@ module.exports = (registerTool) => {
|
|
|
51
51
|
|
|
52
52
|
// Stale/missing. mac/linux can capture live in-process; win32 cannot (needs
|
|
53
53
|
// the --disable-gpu daemon), so there we fall back to whatever file exists.
|
|
54
|
-
|
|
54
|
+
// BUT honor snapshotEnabled(): on macOS capture is off by default, and a live
|
|
55
|
+
// `screencapture` here is exactly what pops the Screen-Recording prompt (just
|
|
56
|
+
// less often than the daemon did) — so when disabled we must NOT live-capture.
|
|
57
|
+
if (process.platform !== "win32" && snap.snapshotEnabled()) {
|
|
55
58
|
try {
|
|
56
59
|
const r = await snap.captureB64(maxWidth);
|
|
57
60
|
return { content: [{ type: "text", text: r.b64 }] };
|
|
@@ -61,7 +64,10 @@ module.exports = (registerTool) => {
|
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
|
|
64
|
-
if (fresh) return { content: [{ type: "text", text: fresh.b64 }] }; //
|
|
67
|
+
if (fresh) return { content: [{ type: "text", text: fresh.b64 }] }; // stale is better than nothing
|
|
68
|
+
if (process.platform === "darwin" && !snap.snapshotEnabled()) {
|
|
69
|
+
throw new Error("桌面截图在 macOS 默认关闭(避免反复弹屏幕录制授权)。需要 agent 看屏幕时,启动 app 前设 CICY_DESKTOP_SNAPSHOT=1。");
|
|
70
|
+
}
|
|
65
71
|
throw new Error("no desktop snapshot yet (daemon warming up?)");
|
|
66
72
|
} catch (error) {
|
|
67
73
|
return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
|
|
@@ -33,6 +33,16 @@ function snapDir() {
|
|
|
33
33
|
return fromEnv || path.join(os.homedir(), "cicy-files", "desktop-snapshot");
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
// Is desktop screen capture allowed here? Single source of truth shared by the
|
|
37
|
+
// periodic daemon (main.js) AND the on-demand `desktop_snapshot` tool's live fallback.
|
|
38
|
+
// ON by default on every platform (主人令: 不能关周期截图 — the agent needs to watch the
|
|
39
|
+
// screen). The macOS repeated Screen-Recording prompt is NOT fixed by disabling capture
|
|
40
|
+
// but by giving the app a STABLE signing identity (see scripts/mac-allinone codesign), so
|
|
41
|
+
// the TCC grant sticks. Opt out entirely with CICY_DESKTOP_SNAPSHOT=0.
|
|
42
|
+
function snapshotEnabled() {
|
|
43
|
+
return process.env.CICY_DESKTOP_SNAPSHOT !== "0";
|
|
44
|
+
}
|
|
45
|
+
|
|
36
46
|
function intervalMs(opt) {
|
|
37
47
|
const fromEnv = parseInt(process.env.CICY_DESKTOP_SNAP_INTERVAL_MS || "", 10);
|
|
38
48
|
return (opt && opt.intervalMs) || (fromEnv > 0 ? fromEnv : DEFAULT_INTERVAL_MS);
|
|
@@ -187,4 +197,4 @@ if (process.env.CICY_SNAP_DAEMON === "1") {
|
|
|
187
197
|
app.on("render-process-gone", () => app.quit());
|
|
188
198
|
}
|
|
189
199
|
|
|
190
|
-
module.exports = { startDesktopSnapshots, stopDesktopSnapshots, snapDir, captureOnce, captureB64, MAX_W };
|
|
200
|
+
module.exports = { startDesktopSnapshots, stopDesktopSnapshots, snapDir, captureOnce, captureB64, snapshotEnabled, MAX_W };
|