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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cicy-desktop",
3
- "version": "2.1.152",
3
+ "version": "2.1.153",
4
4
  "description": "CiCy - AI-powered operating system browser",
5
5
  "main": "src/main.js",
6
6
  "bin": {
@@ -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
- /usr/bin/codesign --force --deep --sign - "$APP" 2>/dev/null || true
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 __snapOn = process.platform === "darwin"
1093
- ? process.env.CICY_DESKTOP_SNAPSHOT === "1"
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 = require("./utils/desktop-snapshot").startDesktopSnapshots();
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
- if (process.platform !== "win32") {
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 }] }; // win32: stale is better than nothing
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 };