cicy-desktop 2.1.322 → 2.1.324

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.
Files changed (48) hide show
  1. package/.github/workflows/build-wsl-package.yml +23 -14
  2. package/.github/workflows/linux-app-release.yml +12 -15
  3. package/.github/workflows/mac-app-release.yml +18 -22
  4. package/.github/workflows/seed-r2-release.yml +112 -0
  5. package/.github/workflows/windows-exe-release.yml +33 -29
  6. package/bin/cicy-desktop +7 -6
  7. package/bin/preinstall.sh +31 -31
  8. package/package.json +5 -5
  9. package/scripts/r2.mjs +125 -0
  10. package/src/app-updater.js +3 -3
  11. package/src/config.js +8 -8
  12. package/src/main-old.js +837 -837
  13. package/src/main.js +2 -0
  14. package/src/profiles/profile-store.js +35 -2
  15. package/src/server/express-app.js +174 -174
  16. package/src/server/mcp-server.js +53 -53
  17. package/src/server/ui-routes.js +81 -81
  18. package/src/sidecar/cicy-code.js +13 -6
  19. package/src/sidecar/colima-docker.js +8 -36
  20. package/src/sidecar/docker.js +9 -7
  21. package/src/sidecar/host-mihomo.js +3 -3
  22. package/src/sidecar/mirrors.js +10 -7
  23. package/src/sidecar/wsl-docker.js +2 -2
  24. package/src/tabbrowser/panel-cells.js +21 -0
  25. package/src/tabbrowser/panel-live-reload.js +86 -0
  26. package/src/tabbrowser/panel-preload.js +2 -0
  27. package/src/tabbrowser/telegram-matrix.html +126 -11
  28. package/src/tools/account-tools.js +389 -389
  29. package/src/tools/automation-tools.js +297 -297
  30. package/src/tools/cdp-tools.js +444 -444
  31. package/src/tools/clipboard-tools.js +180 -180
  32. package/src/tools/download-tools.js +57 -57
  33. package/src/tools/electron-inject-tools.js +2 -2
  34. package/src/tools/exec-js.js +257 -257
  35. package/src/tools/file-tools.js +212 -212
  36. package/src/tools/hook-chatgpt.js +489 -489
  37. package/src/tools/index.js +21 -21
  38. package/src/tools/screenshot-tools.js +28 -28
  39. package/src/tools/system-tools.js +531 -531
  40. package/src/utils/auth.js +2 -2
  41. package/src/utils/cdp-utils.js +8 -8
  42. package/src/utils/download-manager.js +41 -41
  43. package/src/utils/process-utils.js +185 -185
  44. package/src/utils/snapshot-utils.js +56 -56
  45. package/src/utils/window-state.js +1 -1
  46. package/src/utils/window-utils.js +1 -1
  47. package/test/panel-live-reload.test.js +44 -0
  48. package/test/telegram-matrix.test.js +15 -1
@@ -3,7 +3,7 @@ name: Build WSL Package
3
3
  # Bakes a single WSL2 rootfs that already contains Ubuntu 22.04 + Docker Engine
4
4
  # + the cicy-code image (pre-loaded into /var/lib/docker), so a Windows install
5
5
  # is just: wsl --import <this> → dockerd auto-starts → docker run. No apt, no
6
- # image pull/load on the customer machine. Uploaded to Aliyun OSS (CN-fast).
6
+ # image pull/load on the customer machine. Uploaded to our Cloudflare R2 bucket.
7
7
 
8
8
  on:
9
9
  workflow_dispatch:
@@ -11,14 +11,21 @@ on:
11
11
  image:
12
12
  description: cicy-code image to embed
13
13
  default: cicybot/cicy-code:latest
14
- oss_key:
15
- description: OSS object key
14
+ r2_key:
15
+ description: R2 object key
16
16
  default: rootfs/cicy-wsl-latest.tar.gz
17
17
 
18
18
  jobs:
19
19
  build:
20
20
  runs-on: ubuntu-latest
21
21
  steps:
22
+ # First — actions/checkout cleans the workspace, so it has to run before
23
+ # anything writes build artifacts into it. Needed for scripts/r2.mjs
24
+ # (this job used to fetch a standalone ossutil binary and never checked
25
+ # the repo out at all).
26
+ - name: Checkout
27
+ uses: actions/checkout@v4
28
+
22
29
  - name: Build base rootfs image (Ubuntu + Docker + autostart)
23
30
  run: |
24
31
  mkdir -p ctx
@@ -80,25 +87,27 @@ jobs:
80
87
  docker export "$cid" | gzip > cicy-wsl.tar.gz
81
88
  ls -lh cicy-wsl.tar.gz
82
89
 
83
- - name: Upload to Aliyun OSS (public-read)
90
+ - name: Upload to Cloudflare R2
91
+ env:
92
+ R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
93
+ R2_API_TOKEN: ${{ secrets.R2_API_TOKEN }}
84
94
  run: |
85
- curl -sL https://gosspublic.alicdn.com/ossutil/1.7.18/ossutil64 -o ossutil && chmod +x ossutil
86
- test -s ossutil && head -c4 ossutil | grep -q ELF || { echo "ossutil download bad"; exit 1; }
87
- ./ossutil config -e oss-cn-shanghai.aliyuncs.com \
88
- -i "${{ secrets.OSS_ACCESS_KEY_ID }}" -k "${{ secrets.OSS_ACCESS_KEY_SECRET }}"
89
- ./ossutil cp cicy-wsl.tar.gz "oss://cicy-1372193042-cn/${{ inputs.oss_key }}" -f --acl public-read
90
- echo "Uploaded: https://cicy-1372193042-cn.oss-cn-shanghai.aliyuncs.com/${{ inputs.oss_key }}"
95
+ set -e
96
+ node scripts/r2.mjs put "${{ inputs.r2_key }}" cicy-wsl.tar.gz
91
97
 
92
98
  # macOS (colima) loads the cicy-code image tarball directly, NOT a WSL rootfs. So the
93
99
  # SAME run also republishes images/cicy-code-latest.tar.gz from the image already saved
94
100
  # at /tmp/cicy-image.tar — one workflow keeps BOTH platforms' docker images current
95
- # (this OSS key had no producer, which is why macOS was stuck on a stale image).
96
- - name: Publish cicy-code image tarball to OSS (macOS / colima)
101
+ # (this key had no producer, which is why macOS was stuck on a stale image).
102
+ - name: Publish cicy-code image tarball to R2 (macOS / colima)
103
+ env:
104
+ R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
105
+ R2_API_TOKEN: ${{ secrets.R2_API_TOKEN }}
97
106
  run: |
107
+ set -e
98
108
  gzip -c /tmp/cicy-image.tar > cicy-code-latest.tar.gz
99
109
  ls -lh cicy-code-latest.tar.gz
100
- ./ossutil cp cicy-code-latest.tar.gz "oss://cicy-1372193042-cn/images/cicy-code-latest.tar.gz" -f --acl public-read
101
- echo "Uploaded mac image: https://cicy-1372193042-cn.oss-cn-shanghai.aliyuncs.com/images/cicy-code-latest.tar.gz"
110
+ node scripts/r2.mjs put images/cicy-code-latest.tar.gz cicy-code-latest.tar.gz
102
111
 
103
112
  - name: Upload artifact (backup)
104
113
  uses: actions/upload-artifact@v4
@@ -82,30 +82,27 @@ jobs:
82
82
  fi
83
83
  npm run build:linux -- --x64 --config.linux.target=AppImage --config.publish.owner="$PUBLISH_OWNER" --config.publish.repo="$PUBLISH_REPO" --publish always
84
84
 
85
- # AppImage + 版本指针传到 OSS —— app-updater 现已全走 OSS(不碰 GitHub),linux 也要在
86
- # OSS 上有 versioned AppImage(CiCy-Desktop-<ver>.AppImage)和自己的指针 linux-latest-version.txt。
85
+ # AppImage + 版本指针传到 R2 —— app-updater 现已全走 R2(不碰 GitHub),linux 也要在
86
+ # R2 上有 versioned AppImage(CiCy-Desktop-<ver>.AppImage)和自己的指针 linux-latest-version.txt。
87
87
  # 和 mac/win 同一 bucket/凭证。electron-builder 默认产物名含空格,重命名成代码约定的连字符名。
88
- - name: Upload AppImage to OSS (versioned + latest pointer)
88
+ - name: Upload AppImage to R2 (versioned + latest pointer)
89
89
  if: startsWith(github.ref, 'refs/tags/v')
90
90
  shell: bash
91
91
  env:
92
- OSS_AK: ${{ secrets.OSS_ACCESS_KEY_ID }}
93
- OSS_SK: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
92
+ R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
93
+ R2_API_TOKEN: ${{ secrets.R2_API_TOKEN }}
94
94
  run: |
95
95
  set -e
96
- if [ -z "${OSS_AK:-}" ] || [ -z "${OSS_SK:-}" ]; then echo "::warning::OSS creds missing — skip"; exit 0; fi
96
+ if [ -z "${R2_ACCOUNT_ID:-}" ] || [ -z "${R2_API_TOKEN:-}" ]; then echo "::warning::R2 creds missing — skip"; exit 0; fi
97
97
  VER="${GITHUB_REF_NAME#v}"
98
- curl -sL https://gosspublic.alicdn.com/ossutil/1.7.18/ossutil64 -o ossutil && chmod +x ossutil
99
- test -s ossutil && head -c4 ossutil | grep -q ELF || { echo "ossutil download bad"; exit 1; }
100
- ./ossutil config -e oss-cn-shanghai.aliyuncs.com -i "$OSS_AK" -k "$OSS_SK"
101
- BASE="oss://cicy-1372193042-cn/releases"
102
- HOST="https://cicy-1372193042-cn.oss-cn-shanghai.aliyuncs.com/releases"
98
+ BASE="releases"
99
+ HOST="https://r2.deepfetch.de5.net/releases"
103
100
  APP=$(ls dist/*.AppImage 2>/dev/null | head -1)
104
101
  [ -n "$APP" ] && [ -f "$APP" ] || { echo "::error::no AppImage built"; exit 1; }
105
102
  DEST="CiCy-Desktop-$VER.AppImage"
106
- ./ossutil cp "$APP" "$BASE/$DEST" -f --acl public-read
107
- ./ossutil cp "$APP" "$BASE/CiCy-Desktop-latest.AppImage" -f --acl public-read || true
103
+ node scripts/r2.mjs put "$BASE/$DEST" "$APP"
104
+ node scripts/r2.mjs put "$BASE/CiCy-Desktop-latest.AppImage" "$APP" || true
108
105
  # 版本指针最后写(包传完再更新),避免版本号涨了但包还没就位。
109
106
  printf '%s' "$VER" > linux-latest-version.txt
110
- ./ossutil cp linux-latest-version.txt "$BASE/linux-latest-version.txt" -f --acl public-read
111
- echo "OSS linux: $HOST/$DEST"
107
+ node scripts/r2.mjs put "$BASE/linux-latest-version.txt" linux-latest-version.txt
108
+ echo "R2 linux: $HOST/$DEST"
@@ -191,46 +191,42 @@ jobs:
191
191
  echo "uploaded $PKG ($(du -h "$PKG" | cut -f1))"
192
192
  done
193
193
 
194
- # Publish the .pkg installers to OSS (CN-fast). GitHub release downloads stall from
195
- # mainland China, so users in CN pull from OSS instead. Each arch gets a versioned key
194
+ # Publish the .pkg installers to our R2 bucket. GitHub release downloads stall from
195
+ # mainland China, so users in CN pull from the CDN instead. Each arch gets a versioned key
196
196
  # plus a stable cicy-desktop-mac-<arch>-latest.pkg alias a download page can hard-link.
197
197
  # Same bucket/creds as the Windows latest.exe step.
198
- - name: Upload .pkg to OSS (versioned + per-arch latest alias)
199
- continue-on-error: true # OSS is a convenience mirror — never fail the release
198
+ - name: Upload .pkg to R2 (versioned + per-arch latest alias)
199
+ continue-on-error: true # the CDN mirror is a convenience — never fail the release
200
200
  shell: bash
201
201
  env:
202
- OSS_AK: ${{ secrets.OSS_ACCESS_KEY_ID }}
203
- OSS_SK: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
202
+ R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
203
+ R2_API_TOKEN: ${{ secrets.R2_API_TOKEN }}
204
204
  run: |
205
205
  set -uo pipefail
206
206
  VER="${{ steps.meta.outputs.version }}"
207
- if [ -z "${OSS_AK:-}" ] || [ -z "${OSS_SK:-}" ]; then
208
- echo "::warning::OSS creds missing — skipping OSS mirror"; exit 0
207
+ if [ -z "${R2_ACCOUNT_ID:-}" ] || [ -z "${R2_API_TOKEN:-}" ]; then
208
+ echo "::warning::R2 creds missing — skipping CDN mirror"; exit 0
209
209
  fi
210
- curl -fsSL -o ossutil.zip "https://gosspublic.alicdn.com/ossutil/1.7.18/ossutil-v1.7.18-mac-arm64.zip"
211
- unzip -oq ossutil.zip
212
- OSS="./ossutil-v1.7.18-mac-arm64/ossutil"; chmod +x "$OSS"
213
- "$OSS" config -e oss-cn-shanghai.aliyuncs.com -i "$OSS_AK" -k "$OSS_SK"
214
- BASE="oss://cicy-1372193042-cn/releases"
215
- HOST="https://cicy-1372193042-cn.oss-cn-shanghai.aliyuncs.com/releases"
210
+ BASE="releases"
211
+ HOST="https://r2.deepfetch.de5.net/releases"
216
212
  for ARCH in x64 arm64; do
217
213
  PKG="cicy-desktop-$VER-$ARCH.pkg"
218
- [ -f "$PKG" ] || { echo "::warning::$PKG not built — skipping OSS for $ARCH"; continue; }
219
- "$OSS" cp "$PKG" "$BASE/$PKG" -f --acl public-read || { echo "::warning::OSS versioned upload failed $ARCH"; continue; }
220
- "$OSS" cp "$PKG" "$BASE/cicy-desktop-mac-$ARCH-latest.pkg" -f --acl public-read || echo "::warning::OSS latest upload failed $ARCH"
221
- echo "OSS $ARCH: $HOST/cicy-desktop-mac-$ARCH-latest.pkg"
214
+ [ -f "$PKG" ] || { echo "::warning::$PKG not built — skipping R2 for $ARCH"; continue; }
215
+ node scripts/r2.mjs put "$BASE/$PKG" "$PKG" || { echo "::warning::R2 versioned upload failed $ARCH"; continue; }
216
+ node scripts/r2.mjs put "$BASE/cicy-desktop-mac-$ARCH-latest.pkg" "$PKG" || echo "::warning::R2 latest upload failed $ARCH"
217
+ echo "R2 $ARCH: $HOST/cicy-desktop-mac-$ARCH-latest.pkg"
222
218
  done
223
219
  printf '%s' "$VER" > mac-latest-version.txt
224
- "$OSS" cp mac-latest-version.txt "$BASE/mac-latest-version.txt" -f --acl public-read || true
220
+ node scripts/r2.mjs put "$BASE/mac-latest-version.txt" mac-latest-version.txt || true
225
221
 
226
- # Prune —— 版本化 pkg 只保留最新 2 个版本(每版含 x64+arm64),更旧的删掉(省 OSS)。
222
+ # Prune —— 版本化 pkg 只保留最新 2 个版本(每版含 x64+arm64),更旧的删掉(省存储)。
227
223
  # 只匹配 cicy-desktop-<semver>-<arch>.pkg;mac-<arch>-latest.pkg 指针不含 semver、永远保留。非致命。
228
- allvers=$("$OSS" ls "$BASE/cicy-desktop-" -s 2>/dev/null | grep -oE 'cicy-desktop-[0-9]+\.[0-9]+\.[0-9]+-(x64|arm64)\.pkg' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | sort -uV || true)
224
+ allvers=$(node scripts/r2.mjs list "$BASE/cicy-desktop-" 2>/dev/null | grep -oE 'cicy-desktop-[0-9]+\.[0-9]+\.[0-9]+-(x64|arm64)\.pkg' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | sort -uV || true)
229
225
  keep=$(echo "$allvers" | tail -2)
230
226
  for v in $allvers; do
231
227
  echo "$keep" | grep -qx "$v" && continue
232
228
  for ARCH in x64 arm64; do
233
- "$OSS" rm "$BASE/cicy-desktop-$v-$ARCH.pkg" -f 2>/dev/null || true
229
+ node scripts/r2.mjs delete "$BASE/cicy-desktop-$v-$ARCH.pkg" 2>/dev/null || true
234
230
  done
235
231
  echo "Pruned old mac pkg version: $v"
236
232
  done
@@ -0,0 +1,112 @@
1
+ name: Seed R2 from a GitHub release
2
+
3
+ # Republish one version's installers from its GitHub release into the R2
4
+ # bucket, under the same keys the release workflows write.
5
+ #
6
+ # This exists because R2 can fall behind the GitHub release: a release
7
+ # workflow can fail after uploading to GitHub but before uploading to R2 (that
8
+ # is exactly what the dead Aliyun OSS bucket caused for 2.1.323), and because
9
+ # the R2 side had to be rebuilt from scratch when that bucket was disabled.
10
+ #
11
+ # Run it on a runner rather than from a workstation: the runner pulls GitHub's
12
+ # own release assets at LAN speed and reaches R2 directly, with none of the
13
+ # local proxy hops that make a 180MB transfer a coin flip.
14
+
15
+ on:
16
+ workflow_dispatch:
17
+ inputs:
18
+ version:
19
+ description: Version to publish, without the leading v (e.g. 2.1.323)
20
+ required: true
21
+ advance_latest:
22
+ description: Also move the latest/* aliases and version pointers to this version
23
+ type: boolean
24
+ default: true
25
+
26
+ concurrency:
27
+ group: cicy-desktop-seed-r2
28
+ cancel-in-progress: false
29
+
30
+ jobs:
31
+ seed:
32
+ runs-on: ubuntu-latest
33
+ steps:
34
+ - name: Checkout
35
+ uses: actions/checkout@v4
36
+
37
+ - uses: actions/setup-node@v4
38
+ with:
39
+ node-version: '22'
40
+
41
+ - name: Download release assets
42
+ env:
43
+ GH_TOKEN: ${{ github.token }}
44
+ run: |
45
+ set -e
46
+ mkdir -p assets
47
+ gh release download "v${{ inputs.version }}" --repo "$GITHUB_REPOSITORY" --dir assets --clobber
48
+ ls -lh assets
49
+
50
+ - name: Publish to R2
51
+ env:
52
+ R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
53
+ R2_API_TOKEN: ${{ secrets.R2_API_TOKEN }}
54
+ run: |
55
+ set -uo pipefail
56
+ VER="${{ inputs.version }}"
57
+ ADVANCE="${{ inputs.advance_latest }}"
58
+ BASE=releases
59
+ fail=0
60
+
61
+ put() { # put <key> <file>
62
+ [ -f "$2" ] || { echo "::warning::missing $2 — skipping $1"; return 0; }
63
+ node scripts/r2.mjs put "$1" "$2" || { echo "::error::upload failed $1"; fail=1; }
64
+ }
65
+
66
+ EXE="assets/CiCy-Desktop-Setup-$VER.exe"
67
+ put "$BASE/cicy-desktop-$VER.exe" "$EXE"
68
+ put "$BASE/CiCy-Desktop-Setup-$VER.exe.blockmap" "assets/CiCy-Desktop-Setup-$VER.exe.blockmap"
69
+
70
+ for ARCH in x64 arm64; do
71
+ put "$BASE/cicy-desktop-$VER-$ARCH.pkg" "assets/cicy-desktop-$VER-$ARCH.pkg"
72
+ done
73
+
74
+ APP="assets/CiCy-Desktop-$VER.AppImage"
75
+ put "$BASE/CiCy-Desktop-$VER.AppImage" "$APP"
76
+
77
+ # electron-updater feeds — resolveFeedUrl() probes latest.yml to decide
78
+ # whether R2 is usable as the CN update feed at all, so these matter.
79
+ put "$BASE/latest.yml" "assets/latest.yml"
80
+ put "$BASE/latest-linux.yml" "assets/latest-linux.yml"
81
+
82
+ if [ "$ADVANCE" = "true" ]; then
83
+ put "$BASE/cicy-desktop-latest.exe" "$EXE"
84
+ put "$BASE/cicy-desktop-win-latest.exe" "$EXE"
85
+ for ARCH in x64 arm64; do
86
+ put "$BASE/cicy-desktop-mac-$ARCH-latest.pkg" "assets/cicy-desktop-$VER-$ARCH.pkg"
87
+ done
88
+ put "$BASE/CiCy-Desktop-latest.AppImage" "$APP"
89
+
90
+ # Version pointers go LAST: a client that reads a new version number
91
+ # must find every installer already in place.
92
+ printf '%s' "$VER" > version.txt
93
+ for k in latest-version win-latest-version mac-latest-version linux-latest-version; do
94
+ put "$BASE/$k.txt" version.txt
95
+ done
96
+ fi
97
+
98
+ exit $fail
99
+
100
+ - name: Verify what is live
101
+ run: |
102
+ BASE=https://r2.deepfetch.de5.net/releases
103
+ VER="${{ inputs.version }}"
104
+ for k in \
105
+ "cicy-desktop-$VER.exe" "cicy-desktop-latest.exe" "cicy-desktop-win-latest.exe" \
106
+ "cicy-desktop-$VER-x64.pkg" "cicy-desktop-$VER-arm64.pkg" \
107
+ "cicy-desktop-mac-x64-latest.pkg" "cicy-desktop-mac-arm64-latest.pkg" \
108
+ "CiCy-Desktop-$VER.AppImage" "CiCy-Desktop-latest.AppImage" \
109
+ "latest.yml" "latest-linux.yml" "latest-version.txt"; do
110
+ code=$(curl -sI -o /dev/null -w '%{http_code}' "$BASE/$k")
111
+ printf '%-45s %s\n' "$k" "$code"
112
+ done
@@ -98,64 +98,68 @@ jobs:
98
98
  npm run build:win -- --config.publish.owner="$env:PUBLISH_OWNER" --config.publish.repo="$env:PUBLISH_REPO" --publish always
99
99
  }
100
100
 
101
- # 推 exe 到 OSS。三件事(不再是"永远一个版本"):
101
+ # 推 exe 到 R2。三件事(不再是"永远一个版本"):
102
102
  # 1) 带版本号的永久副本 releases/cicy-desktop-<version>.exe — 历史 / 指定版本 / 回滚
103
103
  # 2) latest 指针 releases/cicy-desktop-latest.exe — 只前进:本次版本 < 已发布版本(更旧的
104
104
  # 构建后完成)则不覆盖,避免并发构建竞态把 latest 退回旧版
105
105
  # 3) releases/latest-version.txt — 记录 latest 当前是哪个版本,curl 一下即可核对,无需猜 exe
106
- - name: Upload EXE to OSS (versioned + forward-only latest pointer)
106
+ #
107
+ # 原先发到 Aliyun OSS,该账号已停用(整桶 403 UserDisable),统一改走 scripts/r2.mjs。
108
+ - name: Upload EXE to R2 (versioned + forward-only latest pointer)
107
109
  shell: pwsh
108
110
  env:
109
- OSS_AK: ${{ secrets.OSS_ACCESS_KEY_ID }}
110
- OSS_SK: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
111
+ R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
112
+ R2_API_TOKEN: ${{ secrets.R2_API_TOKEN }}
111
113
  run: |
114
+ $ErrorActionPreference = "Continue"
112
115
  $version = "${{ steps.meta.outputs.version }}"
113
- Invoke-WebRequest -Uri "https://gosspublic.alicdn.com/ossutil/1.7.18/ossutil-v1.7.18-windows-amd64.zip" -OutFile ossutil.zip
114
- Expand-Archive -LiteralPath ossutil.zip -DestinationPath ossutil-dir -Force
115
- $oss = "ossutil-dir\ossutil-v1.7.18-windows-amd64\ossutil.exe"
116
- & $oss config -e oss-cn-shanghai.aliyuncs.com -i "$env:OSS_AK" -k "$env:OSS_SK"
116
+ if (-not $env:R2_ACCOUNT_ID -or -not $env:R2_API_TOKEN) {
117
+ Write-Host "::warning::R2 creds missing skip"; exit 0
118
+ }
119
+ $r2 = "scripts/r2.mjs"
120
+ $base = "releases"
121
+ $host_ = "https://r2.deepfetch.de5.net/releases"
117
122
  $exe = Get-ChildItem dist\*.exe | Where-Object { $_.Name -match 'Setup' } | Select-Object -First 1
118
123
  if (-not $exe) { $exe = Get-ChildItem dist\*.exe | Select-Object -First 1 }
119
124
  if (-not $exe) { Write-Error "no exe found in dist"; exit 1 }
120
- $base = "oss://cicy-1372193042-cn/releases"
121
125
 
122
126
  # 0) WSL2 内核裸文件(一次性,已存在就跳过):精简版 Windows 没有 msiexec 装不了
123
127
  # wsl_update_x64.msi,桌面端改为直接下这个文件放到 System32\lxss\tools\kernel。
124
128
  $kernelKey = "$base/wsl-kernel/kernel"
125
- & $oss stat "$kernelKey" 2>$null | Out-Null
129
+ node $r2 exists $kernelKey
126
130
  if ($LASTEXITCODE -ne 0) {
127
131
  Write-Host "Publishing raw WSL2 kernel -> $kernelKey"
128
132
  Invoke-WebRequest -Uri "https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi" -OutFile wsl_update_x64.msi
129
133
  $kdir = Join-Path $PWD "wsl-kernel-extract"
130
134
  Start-Process msiexec.exe -ArgumentList "/a","`"$PWD\wsl_update_x64.msi`"","/qn","TARGETDIR=$kdir" -Wait
131
135
  $kfile = Get-ChildItem $kdir -Recurse -File | Where-Object { $_.Name -eq "kernel" } | Select-Object -First 1
132
- if ($kfile) { & $oss cp "$($kfile.FullName)" "$kernelKey" -f --acl public-read } else { Write-Warning "kernel not found in msi extract" }
133
- } else { Write-Host "WSL2 kernel already on OSS, skip" }
136
+ if ($kfile) { node $r2 put $kernelKey "$($kfile.FullName)" } else { Write-Warning "kernel not found in msi extract" }
137
+ } else { Write-Host "WSL2 kernel already on R2, skip" }
134
138
 
135
139
  # 0b) 新版 WSL 的 MSI(一次性,已存在就跳过):老 Win10 自带旧版 WSL 反复死锁,桌面端改为装新版。
136
140
  $wslKey = "$base/wsl/wsl.x64.msi"
137
- & $oss stat "$wslKey" 2>$null | Out-Null
141
+ node $r2 exists $wslKey
138
142
  if ($LASTEXITCODE -ne 0) {
139
143
  $rel = Invoke-RestMethod -Uri "https://api.github.com/repos/microsoft/WSL/releases/latest" -Headers @{ "User-Agent" = "cicy-desktop-ci" }
140
144
  $asset = $rel.assets | Where-Object { $_.name -match 'x64\.msi$' } | Select-Object -First 1
141
145
  if ($asset) {
142
146
  Write-Host "Publishing modern WSL $($rel.tag_name) -> $wslKey"
143
147
  Invoke-WebRequest -Uri $asset.browser_download_url -OutFile wsl.x64.msi
144
- & $oss cp "wsl.x64.msi" "$wslKey" -f --acl public-read
148
+ node $r2 put $wslKey "wsl.x64.msi"
145
149
  Set-Content -Path wsl-version.txt -Value $rel.tag_name
146
- & $oss cp "wsl-version.txt" "$base/wsl/version.txt" -f --acl public-read
150
+ node $r2 put "$base/wsl/version.txt" "wsl-version.txt"
147
151
  } else { Write-Warning "no x64 msi asset in microsoft/WSL latest" }
148
- } else { Write-Host "modern WSL msi already on OSS, skip" }
152
+ } else { Write-Host "modern WSL msi already on R2, skip" }
149
153
 
150
154
  # 1) 永久版本化副本(unique key — 不会被后续发版覆盖)
151
155
  $verKey = "$base/cicy-desktop-$version.exe"
152
156
  Write-Host "Uploading versioned -> $verKey"
153
- & $oss cp "$($exe.FullName)" "$verKey" -f --acl public-read
157
+ node $r2 put $verKey "$($exe.FullName)"
154
158
  if ($LASTEXITCODE -ne 0) { Write-Error "versioned upload failed"; exit 1 }
155
159
 
156
160
  # 2) latest 指针 — 只在本次版本 >= 已发布版本时前进
157
- & $oss cp "$base/latest-version.txt" "current-latest.txt" -f 2>$null
158
- $cur = if (Test-Path "current-latest.txt") { (Get-Content "current-latest.txt" -Raw).Trim() } else { "0.0.0" }
161
+ $cur = "0.0.0"
162
+ try { $cur = (Invoke-WebRequest -Uri "$host_/latest-version.txt" -UseBasicParsing).Content.Trim() } catch { $cur = "0.0.0" }
159
163
  $advance = $true
160
164
  try { $advance = ([version]$version -ge [version]$cur) } catch { $advance = $true }
161
165
  if ($advance) {
@@ -163,43 +167,43 @@ jobs:
163
167
  # 关键:版本指针(latest-version.txt)必须在所有安装包传完之后才写 —— 否则
164
168
  # updater 先读到新版本号、用户点下载,但 exe 还没传完 → 404。所以先把所有 exe
165
169
  # 传齐(versioned 已在上面传过 + latest + win-latest),最后才更新版本指针。
166
- & $oss cp "$($exe.FullName)" "$base/cicy-desktop-latest.exe" -f --acl public-read
170
+ node $r2 put "$base/cicy-desktop-latest.exe" "$($exe.FullName)"
167
171
  if ($LASTEXITCODE -ne 0) { Write-Error "latest upload failed"; exit 1 }
168
172
  # Unified per-platform naming: cicy-desktop-<platform>-latest.<ext> so every OS
169
173
  # shares one URL shape (win + mac-x64 + mac-arm64). The bare cicy-desktop-latest.exe
170
174
  # / latest-version.txt are kept as backward-compat aliases for old links.
171
- & $oss cp "$($exe.FullName)" "$base/cicy-desktop-win-latest.exe" -f --acl public-read
175
+ node $r2 put "$base/cicy-desktop-win-latest.exe" "$($exe.FullName)"
172
176
  if ($LASTEXITCODE -ne 0) { Write-Error "win-latest upload failed"; exit 1 }
173
177
  # —— 安装包全部就位,最后写版本指针(version file 永远最后)——
174
178
  Set-Content -NoNewline -Path "current-latest.txt" -Value $version
175
- & $oss cp "current-latest.txt" "$base/latest-version.txt" -f --acl public-read
179
+ node $r2 put "$base/latest-version.txt" "current-latest.txt"
176
180
  if ($LASTEXITCODE -ne 0) { Write-Error "latest-version.txt upload failed"; exit 1 }
177
- & $oss cp "current-latest.txt" "$base/win-latest-version.txt" -f --acl public-read
181
+ node $r2 put "$base/win-latest-version.txt" "current-latest.txt"
178
182
  if ($LASTEXITCODE -ne 0) { Write-Error "win-latest-version.txt upload failed"; exit 1 }
179
183
  } else {
180
184
  Write-Host "Skip latest: building $version < published $cur (older build — not clobbering newer latest)"
181
185
  }
182
186
 
183
- # 3) 保留策略 — 只留最近 $KEEP 个版本化 exe(~130MB/个),旧的删掉,避免 OSS 无限膨胀。
187
+ # 3) 保留策略 — 只留最近 $KEEP 个版本化 exe(~130MB/个),旧的删掉,避免 bucket 无限膨胀。
184
188
  # latest.exe / latest-version.txt 不在此列(名字不匹配 X.Y.Z),永远保留。
185
189
  $KEEP = 2
186
190
  $versions = @()
187
- foreach ($l in (& $oss ls "$base/" 2>$null)) {
191
+ foreach ($l in (node $r2 list "$base/cicy-desktop-")) {
188
192
  if ($l -match 'releases/cicy-desktop-(\d+\.\d+\.\d+)\.exe\s*$') { $versions += $matches[1] }
189
193
  }
190
194
  $sorted = @($versions | Sort-Object { [version]$_ } -Descending)
191
195
  if ($sorted.Count -gt $KEEP) {
192
196
  foreach ($v in ($sorted | Select-Object -Skip $KEEP)) {
193
197
  Write-Host "Pruning old versioned exe: cicy-desktop-$v.exe"
194
- & $oss rm "$base/cicy-desktop-$v.exe" -f 2>$null
198
+ node $r2 delete "$base/cicy-desktop-$v.exe"
195
199
  }
196
200
  } else {
197
201
  Write-Host "Retention: $($sorted.Count) versioned exe(s) <= keep $KEEP, nothing to prune"
198
202
  }
199
203
 
200
- Write-Host "Versioned : https://cicy-1372193042-cn.oss-cn-shanghai.aliyuncs.com/releases/cicy-desktop-$version.exe"
201
- Write-Host "Latest : https://cicy-1372193042-cn.oss-cn-shanghai.aliyuncs.com/releases/cicy-desktop-latest.exe"
202
- Write-Host "Version-of: https://cicy-1372193042-cn.oss-cn-shanghai.aliyuncs.com/releases/latest-version.txt"
204
+ Write-Host "Versioned : $host_/cicy-desktop-$version.exe"
205
+ Write-Host "Latest : $host_/cicy-desktop-latest.exe"
206
+ Write-Host "Version-of: $host_/latest-version.txt"
203
207
 
204
208
  - name: Publish release (drop draft, mark latest)
205
209
  # Only promote AFTER all assets uploaded successfully. autoUpdater on
package/bin/cicy-desktop CHANGED
@@ -22,11 +22,12 @@ const STATE_FILE = path.join(HOME, ".cicy-cluster.json");
22
22
  const LOGS_DIR = path.join(HOME, "logs");
23
23
  const PACKAGE_ROOT = path.join(__dirname, "..");
24
24
  // Electron 二进制来源:**不用用户设任何变量**,自动判断网络。
25
- // CN(或探测不通,兜底)→ 我们的 Aliyun OSS 镜像(CN-fast,三平台 zip 镜像在
26
- // <OSS>electron/v<version>/electron-v<version>-<platform>.zip,正是 @electron/get 的布局)。
25
+ // CN(或探测不通,兜底)→ 我们的 Cloudflare R2 镜像(三平台 zip 镜像在
26
+ // <R2>electron/v<version>/electron-v<version>-<platform>.zip,正是 @electron/get 的布局)。
27
+ // 原 Aliyun OSS 镜像已下线(账号停用,整桶 403 UserDisable)。
27
28
  // 海外 → electron 官方 GitHub release(不压我们 OSS,海外更快)。
28
29
  // 仍可用 ELECTRON_MIRROR 显式覆盖(power user / CI)。下载只在首次(无缓存)发生。
29
- const OSS_ELECTRON_MIRROR = "https://cicy-1372193042-cn.oss-cn-shanghai.aliyuncs.com/electron/";
30
+ const R2_ELECTRON_MIRROR = "https://r2.deepfetch.de5.net/electron/";
30
31
  const GH_ELECTRON_BASE = "https://github.com/electron/electron/releases/download/";
31
32
  const NPM_REGISTRY = process.env.CICY_NPM_REGISTRY || process.env.npm_config_registry || "https://registry.npmmirror.com";
32
33
  const MASTER_ENTRY = path.join(PACKAGE_ROOT, "src", "master", "master-main.js");
@@ -111,11 +112,11 @@ function isCNNetwork() {
111
112
  } catch { return true; } // google 不可达 → CN/兜底,走 OSS
112
113
  }
113
114
 
114
- // 决定 electron zip 的下载地址(不用用户设变量):ELECTRON_MIRROR 显式覆盖 > CN→OSS > 海外→官方 GitHub。
115
+ // 决定 electron zip 的下载地址(不用用户设变量):ELECTRON_MIRROR 显式覆盖 > CN→R2 > 海外→官方 GitHub。
115
116
  function electronZipUrl() {
116
117
  const { zip } = electronArtifact();
117
118
  if (process.env.ELECTRON_MIRROR) return { url: `${process.env.ELECTRON_MIRROR}v${ELECTRON_VERSION}/${zip}`, src: "ELECTRON_MIRROR" };
118
- if (isCNNetwork()) return { url: `${OSS_ELECTRON_MIRROR}v${ELECTRON_VERSION}/${zip}`, src: "OSS(CN)" };
119
+ if (isCNNetwork()) return { url: `${R2_ELECTRON_MIRROR}v${ELECTRON_VERSION}/${zip}`, src: "R2(CN)" };
119
120
  return { url: `${GH_ELECTRON_BASE}v${ELECTRON_VERSION}/${zip}`, src: "GitHub(海外)" };
120
121
  }
121
122
 
@@ -615,7 +616,7 @@ function ensureMacDesktopApp() {
615
616
  : "cicy-desktop";
616
617
  // do shell script needs node + the global bin on PATH (GUI launch has a
617
618
  // minimal PATH); trailing & + nohup + </dev/null lets the shell return so the
618
- // applet quits. 不再 export ELECTRON_MIRROR —— bin 自己按网络自动选(CN→OSS / 海外→GitHub)。
619
+ // applet quits. 不再 export ELECTRON_MIRROR —— bin 自己按网络自动选(CN→R2 / 海外→GitHub)。
619
620
  // npm_config_registry(npmmirror)留着给 cicy-code 子包下载用。
620
621
  const ascript =
621
622
  `do shell script "export PATH=\\"${nodeDir}:${gbin}:/usr/local/bin:/opt/homebrew/bin:$PATH\\" ; ` +
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.322",
3
+ "version": "2.1.324",
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.591",
148
- "cicy-code-darwin-arm64": "2.3.591",
149
- "cicy-code-linux-x64": "2.3.591",
150
- "cicy-code-linux-arm64": "2.3.591",
147
+ "cicy-code-darwin-x64": "2.3.593",
148
+ "cicy-code-darwin-arm64": "2.3.593",
149
+ "cicy-code-linux-x64": "2.3.593",
150
+ "cicy-code-linux-arm64": "2.3.593",
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",