@lobehub/lobehub 2.0.0-next.291 → 2.0.0-next.293

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 (85) hide show
  1. package/.conductor/setup.sh +107 -0
  2. package/.cursor/rules/linear.mdc +53 -0
  3. package/.github/actions/desktop-build-setup/action.yml +29 -0
  4. package/.github/actions/desktop-upload-artifacts/action.yml +46 -0
  5. package/.github/workflows/release-desktop-beta.yml +76 -115
  6. package/.github/workflows/release-desktop-stable.yml +472 -0
  7. package/CHANGELOG.md +58 -0
  8. package/CLAUDE.md +2 -48
  9. package/apps/desktop/dev-app-update.yml +10 -0
  10. package/apps/desktop/electron-builder.mjs +40 -10
  11. package/apps/desktop/electron.vite.config.ts +3 -2
  12. package/apps/desktop/package.json +2 -1
  13. package/apps/desktop/scripts/update-test/README.md +222 -0
  14. package/apps/desktop/scripts/update-test/dev-app-update.local.yml +18 -0
  15. package/apps/desktop/scripts/update-test/generate-manifest.sh +277 -0
  16. package/apps/desktop/scripts/update-test/run-test.sh +105 -0
  17. package/apps/desktop/scripts/update-test/setup.sh +111 -0
  18. package/apps/desktop/scripts/update-test/start-server.sh +70 -0
  19. package/apps/desktop/scripts/update-test/stop-server.sh +33 -0
  20. package/apps/desktop/src/main/core/infrastructure/UpdaterManager.ts +120 -9
  21. package/apps/desktop/src/main/core/infrastructure/__tests__/UpdaterManager.test.ts +17 -1
  22. package/apps/desktop/src/main/env.ts +19 -11
  23. package/apps/desktop/src/main/modules/updater/configs.ts +14 -1
  24. package/changelog/v1.json +14 -0
  25. package/conductor.json +5 -0
  26. package/locales/en-US/subscription.json +2 -2
  27. package/locales/zh-CN/subscription.json +2 -2
  28. package/package.json +1 -1
  29. package/packages/builtin-tool-notebook/src/client/Render/CreateDocument/DocumentCard.tsx +16 -14
  30. package/packages/const/src/cacheControl.ts +1 -0
  31. package/packages/electron-client-ipc/src/useWatchBroadcast.ts +10 -4
  32. package/packages/model-bank/src/aiModels/qiniu.ts +6 -6
  33. package/packages/observability-otel/src/node.ts +39 -37
  34. package/scripts/electronWorkflow/mergeMacReleaseFiles.js +22 -8
  35. package/src/app/(backend)/api/desktop/latest/route.ts +115 -0
  36. package/src/app/(backend)/api/version/route.ts +13 -0
  37. package/src/app/(backend)/middleware/validate/createValidator.test.ts +61 -0
  38. package/src/app/(backend)/middleware/validate/createValidator.ts +79 -0
  39. package/src/app/(backend)/middleware/validate/index.ts +3 -0
  40. package/src/app/[variants]/(desktop)/desktop-onboarding/_layout/index.tsx +2 -1
  41. package/src/app/[variants]/(main)/_layout/index.tsx +2 -1
  42. package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobScheduleConfig.tsx +0 -1
  43. package/src/app/[variants]/(main)/agent/cron/[cronId]/index.tsx +5 -5
  44. package/src/app/[variants]/(main)/agent/features/Conversation/ThreadHydration.tsx +3 -1
  45. package/src/app/[variants]/(main)/group/features/Conversation/ThreadHydration.tsx +3 -1
  46. package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/Checker.tsx +3 -3
  47. package/src/app/[variants]/(mobile)/router/mobileRouter.config.tsx +1 -4
  48. package/src/app/[variants]/router/desktopRouter.config.tsx +1 -4
  49. package/src/components/HtmlPreview/PreviewDrawer.tsx +1 -1
  50. package/src/features/Conversation/Messages/AssistantGroup/components/GroupItem.tsx +12 -2
  51. package/src/features/Conversation/Messages/Tool/Tool/index.tsx +10 -1
  52. package/src/features/{ElectronTitlebar/hooks → Electron/navigation}/useNavigationHistory.ts +1 -1
  53. package/src/features/{ElectronTitlebar/NavigationBar/index.tsx → Electron/titlebar/NavigationBar.tsx} +1 -1
  54. package/src/features/{ElectronTitlebar/NavigationBar → Electron/titlebar}/RecentlyViewed.tsx +1 -1
  55. package/src/features/{ElectronTitlebar/index.tsx → Electron/titlebar/TitleBar.tsx} +19 -9
  56. package/src/features/Electron/titlebar/WinControl.tsx +5 -0
  57. package/src/features/Electron/updater/UpdateModal.tsx +299 -0
  58. package/src/features/LibraryModal/AddFilesToKnowledgeBase/index.test.tsx +24 -0
  59. package/src/features/LibraryModal/AddFilesToKnowledgeBase/index.tsx +21 -24
  60. package/src/features/LibraryModal/CreateNew/index.tsx +18 -22
  61. package/src/features/PluginDevModal/index.tsx +1 -1
  62. package/src/layout/GlobalProvider/AppTheme.tsx +1 -1
  63. package/src/libs/swr/index.ts +26 -30
  64. package/src/server/services/desktopRelease/index.test.ts +65 -0
  65. package/src/server/services/desktopRelease/index.ts +208 -0
  66. package/src/store/aiInfra/slices/aiProvider/action.ts +16 -17
  67. package/src/store/chat/slices/portal/action.test.ts +0 -2
  68. package/src/store/chat/slices/portal/action.ts +17 -44
  69. package/src/store/chat/slices/thread/action.test.ts +4 -1
  70. package/src/store/chat/slices/thread/action.ts +6 -1
  71. package/src/components/FunctionModal/createModalHooks.ts +0 -48
  72. package/src/components/FunctionModal/index.ts +0 -1
  73. package/src/components/FunctionModal/style.tsx +0 -44
  74. package/src/features/ElectronTitlebar/UpdateModal.tsx +0 -274
  75. package/src/features/ElectronTitlebar/WinControl/index.tsx +0 -90
  76. /package/src/features/{ElectronTitlebar/Connection/index.tsx → Electron/connection/Connection.tsx} +0 -0
  77. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/ConnectionMode.tsx +0 -0
  78. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/Option.tsx +0 -0
  79. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/RemoteStatus.tsx +0 -0
  80. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/Waiting.tsx +0 -0
  81. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/WaitingAnim.tsx +0 -0
  82. /package/src/features/{ElectronTitlebar/helpers → Electron/navigation}/routeMetadata.ts +0 -0
  83. /package/src/features/{ElectronTitlebar/hooks → Electron/system}/useWatchThemeUpdate.ts +0 -0
  84. /package/src/features/{ElectronTitlebar → Electron/titlebar}/SimpleTitleBar.tsx +0 -0
  85. /package/src/features/{ElectronTitlebar → Electron/updater}/UpdateNotification.tsx +0 -0
@@ -0,0 +1,472 @@
1
+ name: Release Desktop Stable
2
+
3
+ # ============================================
4
+ # Stable 频道发版工作流
5
+ # ============================================
6
+ # 触发条件: 发布不含 pre-release 标识的 release (如 v2.0.0)
7
+ #
8
+ # 与 Beta 的区别:
9
+ # 1. 仅响应 stable 版本 tag (不含 beta/alpha/rc/nightly)
10
+ # 2. 使用 STABLE 专用的 Umami 配置
11
+ # 3. 额外上传到 S3 更新服务器
12
+ # 4. 构建时注入 UPDATE_SERVER_URL 让客户端从 S3 检查更新
13
+ #
14
+ # 需要配置的 Secrets (S3 相关, 统一 UPDATE_ 前缀):
15
+ # - UPDATE_AWS_ACCESS_KEY_ID
16
+ # - UPDATE_AWS_SECRET_ACCESS_KEY
17
+ # - UPDATE_S3_BUCKET (S3 存储桶名称)
18
+ # - UPDATE_S3_REGION (可选, 默认 us-east-1)
19
+ # - UPDATE_S3_ENDPOINT (可选, 用于 R2/MinIO 等 S3 兼容服务)
20
+ # - UPDATE_SERVER_URL (客户端检查更新的 URL)
21
+ # ============================================
22
+
23
+ on:
24
+ release:
25
+ types: [published]
26
+ workflow_dispatch:
27
+ inputs:
28
+ version:
29
+ description: 'Version to build (e.g., 2.0.0)'
30
+ required: true
31
+ type: string
32
+ build_mac:
33
+ description: 'Build macOS (ARM64)'
34
+ required: false
35
+ type: boolean
36
+ default: true
37
+ build_mac_intel:
38
+ description: 'Build macOS (Intel x64)'
39
+ required: false
40
+ type: boolean
41
+ default: true
42
+ build_windows:
43
+ description: 'Build Windows'
44
+ required: false
45
+ type: boolean
46
+ default: true
47
+ build_linux:
48
+ description: 'Build Linux'
49
+ required: false
50
+ type: boolean
51
+ default: true
52
+ skip_s3_upload:
53
+ description: 'Skip S3 upload (for testing)'
54
+ required: false
55
+ type: boolean
56
+ default: true
57
+ skip_github_release:
58
+ description: 'Skip GitHub release upload (for testing)'
59
+ required: false
60
+ type: boolean
61
+ default: true
62
+
63
+ concurrency:
64
+ group: ${{ github.ref }}-${{ github.workflow }}
65
+ cancel-in-progress: true
66
+
67
+ permissions: read-all
68
+
69
+ env:
70
+ NODE_VERSION: '24.11.1'
71
+
72
+ jobs:
73
+ # ============================================
74
+ # 检查版本信息
75
+ # ============================================
76
+ check-stable:
77
+ name: Check Release Version
78
+ runs-on: ubuntu-latest
79
+ outputs:
80
+ is_stable: ${{ steps.check.outputs.is_stable }}
81
+ version: ${{ steps.check.outputs.version }}
82
+ is_manual: ${{ steps.check.outputs.is_manual }}
83
+ release_notes: ${{ steps.check.outputs.release_notes }}
84
+ steps:
85
+ - name: Check release info
86
+ id: check
87
+ run: |
88
+ # 判断触发方式
89
+ if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
90
+ # 手动触发: 使用输入的版本号
91
+ version="${{ inputs.version }}"
92
+ echo "is_manual=true" >> $GITHUB_OUTPUT
93
+ echo "is_stable=true" >> $GITHUB_OUTPUT
94
+ echo "version=${version}" >> $GITHUB_OUTPUT
95
+ echo "release_notes=" >> $GITHUB_OUTPUT
96
+ echo "🔧 Manual trigger: version=${version}"
97
+ else
98
+ # Release 触发: 从 tag 提取版本号
99
+ version="${{ github.event.release.tag_name }}"
100
+ version="${version#v}"
101
+ echo "is_manual=false" >> $GITHUB_OUTPUT
102
+ echo "version=${version}" >> $GITHUB_OUTPUT
103
+ release_body="${{ github.event.release.body }}"
104
+ {
105
+ echo "release_notes<<EOF"
106
+ printf '%s\n' "$release_body"
107
+ echo "EOF"
108
+ } >> $GITHUB_OUTPUT
109
+
110
+ # 检查是否为 stable 版本 (不含 beta/alpha/rc/nightly)
111
+ if [[ "$version" == *"beta"* ]] || [[ "$version" == *"alpha"* ]] || [[ "$version" == *"rc"* ]] || [[ "$version" == *"nightly"* ]]; then
112
+ echo "is_stable=false" >> $GITHUB_OUTPUT
113
+ echo "⏭️ Skipping: $version is not a stable release"
114
+ else
115
+ echo "is_stable=true" >> $GITHUB_OUTPUT
116
+ echo "✅ Stable release detected: $version"
117
+ fi
118
+ fi
119
+
120
+ # ============================================
121
+ # 配置构建矩阵 (检查自托管 Runner)
122
+ # ============================================
123
+ configure-build:
124
+ needs: [check-stable]
125
+ if: needs.check-stable.outputs.is_stable == 'true'
126
+ name: Configure Build Matrix
127
+ runs-on: ubuntu-latest
128
+ outputs:
129
+ matrix: ${{ steps.set-matrix.outputs.matrix }}
130
+ steps:
131
+ - name: Generate Matrix
132
+ id: set-matrix
133
+ run: |
134
+ # 基础矩阵
135
+ static_matrix='[]'
136
+
137
+ # Windows
138
+ if [[ "${{ github.event_name }}" != "workflow_dispatch" ]] || [[ "${{ inputs.build_windows }}" == "true" ]]; then
139
+ static_matrix=$(echo "$static_matrix" | jq -c '. + [{"os": "windows-2025", "name": "windows-2025"}]')
140
+ fi
141
+
142
+ # Linux
143
+ if [[ "${{ github.event_name }}" != "workflow_dispatch" ]] || [[ "${{ inputs.build_linux }}" == "true" ]]; then
144
+ static_matrix=$(echo "$static_matrix" | jq -c '. + [{"os": "ubuntu-latest", "name": "ubuntu-latest"}]')
145
+ fi
146
+
147
+ # macOS (ARM64)
148
+ # 使用 GitHub Hosted Runner
149
+ if [[ "${{ github.event_name }}" != "workflow_dispatch" ]] || [[ "${{ inputs.build_mac }}" == "true" ]]; then
150
+ echo "Using GitHub-Hosted Runner for macOS ARM64"
151
+ arm_entry='{"os": "macos-14", "name": "macos-arm64"}'
152
+ static_matrix=$(echo "$static_matrix" | jq -c --argjson entry "$arm_entry" '. + [$entry]')
153
+ fi
154
+
155
+ if [[ "${{ github.event_name }}" != "workflow_dispatch" ]] || [[ "${{ inputs.build_mac_intel }}" == "true" ]]; then
156
+ echo "Using GitHub-Hosted Runner for macOS Intel x64"
157
+ intel_entry='{"os": "macos-15-intel", "name": "macos-intel"}'
158
+ static_matrix=$(echo "$static_matrix" | jq -c --argjson entry "$intel_entry" '. + [$entry]')
159
+ fi
160
+
161
+ # 输出
162
+ echo "matrix={\"include\":$static_matrix}" >> $GITHUB_OUTPUT
163
+
164
+ # ============================================
165
+ # 多平台构建
166
+ # ============================================
167
+ build:
168
+ needs: [check-stable, configure-build]
169
+ if: needs.check-stable.outputs.is_stable == 'true'
170
+ name: Build Desktop App
171
+ runs-on: ${{ matrix.os }}
172
+ strategy:
173
+ fail-fast: false
174
+ matrix: ${{ fromJson(needs.configure-build.outputs.matrix) }}
175
+ steps:
176
+ - uses: actions/checkout@v6
177
+ with:
178
+ fetch-depth: 0
179
+
180
+ - name: Setup build environment
181
+ uses: ./.github/actions/desktop-build-setup
182
+ with:
183
+ node-version: ${{ env.NODE_VERSION }}
184
+
185
+ - name: Set package version
186
+ run: npm run workflow:set-desktop-version ${{ needs.check-stable.outputs.version }} stable
187
+
188
+ # macOS 构建
189
+ - name: Build artifact on macOS
190
+ if: runner.os == 'macOS'
191
+ run: npm run desktop:build
192
+ env:
193
+ UPDATE_CHANNEL: stable
194
+ UPDATE_SERVER_URL: ${{ secrets.UPDATE_SERVER_URL }}
195
+ RELEASE_NOTES: ${{ needs.check-stable.outputs.release_notes }}
196
+ APP_URL: http://localhost:3015
197
+ DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
198
+ KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
199
+ CSC_LINK: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
200
+ CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
201
+ CSC_FOR_PULL_REQUEST: true
202
+ APPLE_ID: ${{ secrets.APPLE_ID }}
203
+ APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
204
+ APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
205
+ NEXT_PUBLIC_DESKTOP_PROJECT_ID: ${{ secrets.UMAMI_STABLE_DESKTOP_PROJECT_ID }}
206
+ NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL: ${{ secrets.UMAMI_STABLE_DESKTOP_BASE_URL }}
207
+
208
+ # Windows 构建
209
+ - name: Build artifact on Windows
210
+ if: runner.os == 'Windows'
211
+ run: npm run desktop:build
212
+ env:
213
+ UPDATE_CHANNEL: stable
214
+ UPDATE_SERVER_URL: ${{ secrets.UPDATE_SERVER_URL }}
215
+ RELEASE_NOTES: ${{ needs.check-stable.outputs.release_notes }}
216
+ APP_URL: http://localhost:3015
217
+ DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
218
+ KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
219
+ NEXT_PUBLIC_DESKTOP_PROJECT_ID: ${{ secrets.UMAMI_STABLE_DESKTOP_PROJECT_ID }}
220
+ NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL: ${{ secrets.UMAMI_STABLE_DESKTOP_BASE_URL }}
221
+ TEMP: C:\temp
222
+ TMP: C:\temp
223
+
224
+ # Linux 构建
225
+ - name: Build artifact on Linux
226
+ if: runner.os == 'Linux'
227
+ run: |
228
+ npm run desktop:build
229
+ tar -czf apps/desktop/release/lobehub-renderer.tar.gz -C out .
230
+ env:
231
+ UPDATE_CHANNEL: stable
232
+ UPDATE_SERVER_URL: ${{ secrets.UPDATE_SERVER_URL }}
233
+ RELEASE_NOTES: ${{ needs.check-stable.outputs.release_notes }}
234
+ APP_URL: http://localhost:3015
235
+ DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
236
+ KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
237
+ NEXT_PUBLIC_DESKTOP_PROJECT_ID: ${{ secrets.UMAMI_STABLE_DESKTOP_PROJECT_ID }}
238
+ NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL: ${{ secrets.UMAMI_STABLE_DESKTOP_BASE_URL }}
239
+
240
+ - name: Upload artifacts
241
+ uses: ./.github/actions/desktop-upload-artifacts
242
+ with:
243
+ artifact-name: release-${{ matrix.name }}
244
+
245
+ # ============================================
246
+ # 合并 macOS 多架构文件
247
+ # ============================================
248
+ merge-mac-files:
249
+ needs: [build, check-stable]
250
+ name: Merge macOS Release Files
251
+ runs-on: ubuntu-latest
252
+ permissions:
253
+ contents: write
254
+ steps:
255
+ - name: Checkout repository
256
+ uses: actions/checkout@v6
257
+
258
+ - name: Setup Node.js
259
+ uses: actions/setup-node@v6
260
+ with:
261
+ node-version: ${{ env.NODE_VERSION }}
262
+ package-manager-cache: false
263
+
264
+ - name: Install bun
265
+ uses: oven-sh/setup-bun@v2
266
+ with:
267
+ bun-version: latest
268
+
269
+ - name: Download artifacts
270
+ uses: actions/download-artifact@v7
271
+ with:
272
+ path: release
273
+ pattern: release-*
274
+ merge-multiple: true
275
+
276
+ - name: List downloaded artifacts
277
+ run: ls -R release
278
+
279
+ - name: Install yaml only for merge step
280
+ run: |
281
+ cd scripts/electronWorkflow
282
+ if [ ! -f package.json ]; then
283
+ echo '{"name":"merge-mac-release","private":true}' > package.json
284
+ fi
285
+ bun add --no-save yaml@2.8.1
286
+
287
+ - name: Merge latest-mac.yml files
288
+ run: bun run scripts/electronWorkflow/mergeMacReleaseFiles.js
289
+
290
+ - name: Upload artifacts with merged macOS files
291
+ uses: actions/upload-artifact@v6
292
+ with:
293
+ name: merged-release
294
+ path: release/
295
+ retention-days: 1
296
+
297
+ # ============================================
298
+ # 发布到 GitHub Releases
299
+ # ============================================
300
+ publish-github:
301
+ needs: [merge-mac-files, check-stable]
302
+ name: Publish to GitHub Release
303
+ runs-on: ubuntu-latest
304
+ # 手动触发时可选择跳过
305
+ if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.skip_github_release) }}
306
+ permissions:
307
+ contents: write
308
+ steps:
309
+ - name: Download merged artifacts
310
+ uses: actions/download-artifact@v7
311
+ with:
312
+ name: merged-release
313
+ path: release
314
+
315
+ - name: List final artifacts
316
+ run: ls -R release
317
+
318
+ - name: Upload to Release
319
+ uses: softprops/action-gh-release@v1
320
+ with:
321
+ # 手动触发时使用输入的版本号创建 tag
322
+ tag_name: ${{ github.event_name == 'workflow_dispatch' && format('v{0}', needs.check-stable.outputs.version) || github.event.release.tag_name }}
323
+ # 手动触发时创建为 draft
324
+ draft: ${{ github.event_name == 'workflow_dispatch' }}
325
+ files: |
326
+ release/stable*
327
+ release/latest*
328
+ release/*.dmg*
329
+ release/*.zip*
330
+ release/*.exe*
331
+ release/*.AppImage
332
+ release/*.deb*
333
+ release/*.snap*
334
+ release/*.rpm*
335
+ release/*.tar.gz*
336
+ env:
337
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
338
+
339
+ # ============================================
340
+ # 发布到 S3 更新服务器
341
+ # ============================================
342
+ # S3 目录结构:
343
+ # s3://bucket/
344
+ # stable/
345
+ # stable-mac.yml ← electron-updater 检查更新 (stable channel)
346
+ # stable.yml ← Windows (stable channel)
347
+ # stable-linux.yml ← Linux (stable channel)
348
+ # latest-mac.yml ← fallback for GitHub provider
349
+ # {version}/ ← 版本目录
350
+ # *.dmg, *.zip, *.exe, ...
351
+ # ============================================
352
+ publish-s3:
353
+ needs: [merge-mac-files, check-stable]
354
+ name: Publish to S3
355
+ runs-on: ubuntu-latest
356
+ # 手动触发时可选择跳过
357
+ if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.skip_s3_upload) }}
358
+ steps:
359
+ - name: Download merged artifacts
360
+ uses: actions/download-artifact@v7
361
+ with:
362
+ name: merged-release
363
+ path: release
364
+
365
+ - name: List artifacts to upload
366
+ run: |
367
+ echo "📦 Artifacts to upload to S3:"
368
+ ls -lah release/
369
+ echo ""
370
+ echo "📋 Version: ${{ needs.check-stable.outputs.version }}"
371
+
372
+ - name: Upload to S3
373
+ env:
374
+ AWS_ACCESS_KEY_ID: ${{ secrets.UPDATE_AWS_ACCESS_KEY_ID }}
375
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.UPDATE_AWS_SECRET_ACCESS_KEY }}
376
+ AWS_REGION: ${{ secrets.UPDATE_S3_REGION || 'us-east-1' }}
377
+ S3_BUCKET: ${{ secrets.UPDATE_S3_BUCKET }}
378
+ S3_ENDPOINT: ${{ secrets.UPDATE_S3_ENDPOINT }}
379
+ VERSION: ${{ needs.check-stable.outputs.version }}
380
+ run: |
381
+ if [ -z "$S3_BUCKET" ]; then
382
+ echo "⚠️ UPDATE_S3_BUCKET is not configured, skipping S3 upload"
383
+ echo ""
384
+ echo "To enable S3 upload, configure the following secrets:"
385
+ echo " - UPDATE_AWS_ACCESS_KEY_ID"
386
+ echo " - UPDATE_AWS_SECRET_ACCESS_KEY"
387
+ echo " - UPDATE_S3_BUCKET"
388
+ echo " - UPDATE_S3_REGION (optional, defaults to us-east-1)"
389
+ echo " - UPDATE_S3_ENDPOINT (optional, for S3-compatible services)"
390
+ exit 0
391
+ fi
392
+
393
+ # 构建端点参数
394
+ ENDPOINT_ARG=""
395
+ if [ -n "$S3_ENDPOINT" ]; then
396
+ ENDPOINT_ARG="--endpoint-url $S3_ENDPOINT"
397
+ echo "📡 Using custom S3 endpoint: $S3_ENDPOINT"
398
+ fi
399
+
400
+ echo "🚀 Uploading to S3 bucket: $S3_BUCKET"
401
+ echo "📁 Target path: s3://$S3_BUCKET/stable/"
402
+ echo ""
403
+
404
+ # 1. 上传安装包到版本目录
405
+ echo "📦 Uploading release files to s3://$S3_BUCKET/stable/$VERSION/"
406
+ for file in release/*.dmg release/*.zip release/*.exe release/*.AppImage release/*.deb release/*.rpm release/*.snap release/*.tar.gz; do
407
+ if [ -f "$file" ]; then
408
+ filename=$(basename "$file")
409
+ echo " ↗️ $filename"
410
+ aws s3 cp "$file" "s3://$S3_BUCKET/stable/$VERSION/$filename" $ENDPOINT_ARG
411
+ fi
412
+ done
413
+
414
+ # 2. 创建 stable*.yml (从 latest*.yml 复制,并修改 URL 加上版本目录前缀)
415
+ # electron-updater 在 channel=stable 时会找 stable-mac.yml
416
+ # S3 目录结构: stable/{version}/xxx.dmg,所以 URL 需要加上 {version}/ 前缀
417
+ echo ""
418
+ echo "📋 Creating stable*.yml files from latest*.yml..."
419
+ for yml in release/latest*.yml; do
420
+ if [ -f "$yml" ]; then
421
+ stable_name=$(basename "$yml" | sed 's/latest/stable/')
422
+ # 复制并修改 URL: 给所有 url 字段加上版本目录前缀
423
+ # url: xxx.dmg -> url: {VERSION}/xxx.dmg
424
+ sed "s|url: |url: $VERSION/|g" "$yml" > "release/$stable_name"
425
+ echo " 📄 Created $stable_name from $(basename $yml) with URL prefix: $VERSION/"
426
+ fi
427
+ done
428
+
429
+ # 3. 创建 renderer manifest (用于验证 renderer tar 完整性)
430
+ echo ""
431
+ echo "📋 Creating renderer manifest..."
432
+ RENDERER_TAR="release/lobehub-renderer.tar.gz"
433
+ if [ -f "$RENDERER_TAR" ]; then
434
+ RENDERER_SHA512=$(shasum -a 512 "$RENDERER_TAR" | awk '{print $1}' | xxd -r -p | base64)
435
+ RENDERER_SIZE=$(stat -f%z "$RENDERER_TAR" 2>/dev/null || stat -c%s "$RENDERER_TAR")
436
+ RELEASE_DATE=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
437
+ echo "version: $VERSION" > "release/stable-renderer.yml"
438
+ echo "files:" >> "release/stable-renderer.yml"
439
+ echo " - url: $VERSION/lobehub-renderer.tar.gz" >> "release/stable-renderer.yml"
440
+ echo " sha512: $RENDERER_SHA512" >> "release/stable-renderer.yml"
441
+ echo " size: $RENDERER_SIZE" >> "release/stable-renderer.yml"
442
+ echo "path: $VERSION/lobehub-renderer.tar.gz" >> "release/stable-renderer.yml"
443
+ echo "sha512: $RENDERER_SHA512" >> "release/stable-renderer.yml"
444
+ echo "releaseDate: '$RELEASE_DATE'" >> "release/stable-renderer.yml"
445
+ echo " 📄 Created stable-renderer.yml with SHA512 checksum"
446
+ else
447
+ echo " ⚠️ Renderer tar not found, skipping manifest creation"
448
+ fi
449
+
450
+ # 4. 上传 manifest 到根目录和版本目录
451
+ # 根目录: electron-updater 需要,会被每次发版覆盖
452
+ # 版本目录: 作为存档保留
453
+ echo ""
454
+ echo "📋 Uploading manifest files..."
455
+ for yml in release/stable*.yml release/latest*.yml; do
456
+ if [ -f "$yml" ]; then
457
+ filename=$(basename "$yml")
458
+ echo " ↗️ $filename -> s3://$S3_BUCKET/stable/$filename"
459
+ aws s3 cp "$yml" "s3://$S3_BUCKET/stable/$filename" $ENDPOINT_ARG
460
+ echo " ↗️ $filename -> s3://$S3_BUCKET/stable/$VERSION/$filename (archive)"
461
+ aws s3 cp "$yml" "s3://$S3_BUCKET/stable/$VERSION/$filename" $ENDPOINT_ARG
462
+ fi
463
+ done
464
+
465
+ echo ""
466
+ echo "✅ S3 upload completed!"
467
+ echo ""
468
+ echo "📋 Files in s3://$S3_BUCKET/stable/:"
469
+ aws s3 ls "s3://$S3_BUCKET/stable/" $ENDPOINT_ARG || true
470
+ echo ""
471
+ echo "📋 Files in s3://$S3_BUCKET/stable/$VERSION/:"
472
+ aws s3 ls "s3://$S3_BUCKET/stable/$VERSION/" $ENDPOINT_ARG || true
package/CHANGELOG.md CHANGED
@@ -2,6 +2,64 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 2.0.0-next.293](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.292...v2.0.0-next.293)
6
+
7
+ <sup>Released on **2026-01-15**</sup>
8
+
9
+ #### ✨ Features
10
+
11
+ - **desktop**: Add desktop release service and API endpoint.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's improved
19
+
20
+ - **desktop**: Add desktop release service and API endpoint, closes [#11520](https://github.com/lobehub/lobe-chat/issues/11520) ([e3dc5be](https://github.com/lobehub/lobe-chat/commit/e3dc5be))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ## [Version 2.0.0-next.292](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.291...v2.0.0-next.292)
31
+
32
+ <sup>Released on **2026-01-15**</sup>
33
+
34
+ #### ♻ Code Refactoring
35
+
36
+ - **misc**: Use fallbackData to prevent useActionSWR auto-fetch.
37
+
38
+ #### ✨ Features
39
+
40
+ - **desktop**: Add local update testing scripts and stable channel API version check.
41
+
42
+ <br/>
43
+
44
+ <details>
45
+ <summary><kbd>Improvements and Fixes</kbd></summary>
46
+
47
+ #### Code refactoring
48
+
49
+ - **misc**: Use fallbackData to prevent useActionSWR auto-fetch, closes [#11514](https://github.com/lobehub/lobe-chat/issues/11514) ([d446163](https://github.com/lobehub/lobe-chat/commit/d446163))
50
+
51
+ #### What's improved
52
+
53
+ - **desktop**: Add local update testing scripts and stable channel API version check, closes [#11474](https://github.com/lobehub/lobe-chat/issues/11474) [#11513](https://github.com/lobehub/lobe-chat/issues/11513) ([959c210](https://github.com/lobehub/lobe-chat/commit/959c210))
54
+
55
+ </details>
56
+
57
+ <div align="right">
58
+
59
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
60
+
61
+ </div>
62
+
5
63
  ## [Version 2.0.0-next.291](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.290...v2.0.0-next.291)
6
64
 
7
65
  <sup>Released on **2026-01-15**</sup>
package/CLAUDE.md CHANGED
@@ -57,55 +57,9 @@ see @.cursor/rules/typescript.mdc
57
57
  - **Dev**: Translate `locales/zh-CN/namespace.json` and `locales/en-US/namespace.json` locales file only for dev preview
58
58
  - DON'T run `pnpm i18n`, let CI auto handle it
59
59
 
60
- ## Linear Issue Management (ignore if not installed linear mcp)
60
+ ## Linear Issue Management(ignore if not installed linear mcp)
61
61
 
62
- When working with Linear issues:
63
-
64
- 1. **Retrieve issue details** before starting work using `mcp__linear-server__get_issue`
65
- 2. **Check for sub-issues**: If the issue has sub-issues, retrieve and review ALL sub-issues using `mcp__linear-server__list_issues` with `parentId` filter before starting work
66
- 3. **Update issue status** when completing tasks using `mcp__linear-server__update_issue`
67
- 4. **MUST add completion comment** using `mcp__linear-server__create_comment`
68
-
69
- ### Creating Issues
70
-
71
- When creating new Linear issues using `mcp__linear-server__create_issue`, **MUST add the `claude code` label** to indicate the issue was created by Claude Code.
72
-
73
- ### Completion Comment (REQUIRED)
74
-
75
- **Every time you complete an issue, you MUST add a comment summarizing the work done.** This is critical for:
76
-
77
- - Team visibility and knowledge sharing
78
- - Code review context
79
- - Future reference and debugging
80
-
81
- ### PR Linear Issue Association (REQUIRED)
82
-
83
- **When creating PRs for Linear issues, MUST include magic keywords in PR body:** `Fixes LOBE-123`, `Closes LOBE-123`, or `Resolves LOBE-123`, and summarize the work done in the linear issue comment and update the issue status to "In Review".
84
-
85
- ### IMPORTANT: Per-Issue Completion Rule
86
-
87
- **When working on multiple issues (e.g., parent issue with sub-issues), you MUST update status and add comment for EACH issue IMMEDIATELY after completing it.** Do NOT wait until all issues are done to update them in batch.
88
-
89
- **Workflow for EACH individual issue:**
90
-
91
- 1. Complete the implementation for this specific issue
92
- 2. Run type check: `bun run type-check`
93
- 3. Run related tests if applicable
94
- 4. Create PR if needed
95
- 5. **IMMEDIATELY** update issue status to **"In Review"** (NOT "Done"): `mcp__linear-server__update_issue`
96
- 6. **IMMEDIATELY** add completion comment: `mcp__linear-server__create_comment`
97
- 7. Only then move on to the next issue
98
-
99
- **Note:** Issue status should be set to **"In Review"** when PR is created. The status will be updated to **"Done"** only after the PR is merged (usually handled by Linear-GitHub integration or manually).
100
-
101
- **❌ Wrong approach:**
102
-
103
- - Complete Issue A → Complete Issue B → Complete Issue C → Update all statuses → Add all comments
104
- - Mark issue as "Done" immediately after creating PR
105
-
106
- **✅ Correct approach:**
107
-
108
- - Complete Issue A → Create PR → Update A status to "In Review" → Add A comment → Complete Issue B → ...
62
+ Read @.cursor/rules/linear.mdc when working with Linear issues.
109
63
 
110
64
  ## Rules Index
111
65
 
@@ -1,6 +1,16 @@
1
+ # 开发环境更新配置
2
+ # 可选择 GitHub 或 Generic provider 进行测试
3
+
4
+ # 方式1: GitHub Provider (默认)
1
5
  provider: github
2
6
  owner: lobehub
3
7
  repo: lobe-chat
4
8
  updaterCacheDirName: electron-app-updater
5
9
  allowPrerelease: true
6
10
  channel: nightly
11
+
12
+ # 方式2: Generic Provider (测试自定义服务器)
13
+ # 取消下面的注释,注释掉上面的 GitHub 配置
14
+ # provider: generic
15
+ # url: http://localhost:8080
16
+ # updaterCacheDirName: electron-app-updater
@@ -10,19 +10,47 @@ dotenv.config();
10
10
 
11
11
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
12
 
13
- const packageJSON = JSON.parse(
14
- await fs.readFile(path.join(__dirname, 'package.json'), 'utf8')
15
- );
13
+ const packageJSON = JSON.parse(await fs.readFile(path.join(__dirname, 'package.json'), 'utf8'));
16
14
 
17
15
  const channel = process.env.UPDATE_CHANNEL;
18
16
  const arch = os.arch();
19
17
  const hasAppleCertificate = Boolean(process.env.CSC_LINK);
20
18
 
19
+ // 自定义更新服务器 URL (用于 stable 频道)
20
+ const updateServerUrl = process.env.UPDATE_SERVER_URL;
21
+
21
22
  console.log(`🚄 Build Version ${packageJSON.version}, Channel: ${channel}`);
22
23
  console.log(`🏗️ Building for architecture: ${arch}`);
23
24
 
24
25
  const isNightly = channel === 'nightly';
25
26
  const isBeta = packageJSON.name.includes('beta');
27
+ const isStable = !isNightly && !isBeta;
28
+
29
+ // 根据 channel 配置不同的 publish provider
30
+ // - Stable + UPDATE_SERVER_URL: 使用 generic (自定义 HTTP 服务器)
31
+ // - Beta/Nightly: 仅使用 GitHub
32
+ const getPublishConfig = () => {
33
+ const githubProvider = {
34
+ owner: 'lobehub',
35
+ provider: 'github',
36
+ repo: 'lobe-chat',
37
+ };
38
+
39
+ // Stable channel: 使用自定义服务器 (generic provider)
40
+ if (isStable && updateServerUrl) {
41
+ console.log(`📦 Stable channel: Using generic provider (${updateServerUrl})`);
42
+ const genericProvider = {
43
+ provider: 'generic',
44
+ url: updateServerUrl,
45
+ };
46
+ // 同时发布到自定义服务器和 GitHub (GitHub 作为备用/镜像)
47
+ return [genericProvider, githubProvider];
48
+ }
49
+
50
+ // Beta/Nightly channel: 仅使用 GitHub
51
+ console.log(`📦 ${channel || 'default'} channel: Using GitHub provider`);
52
+ return [githubProvider];
53
+ };
26
54
 
27
55
  // Keep only these Electron Framework localization folders (*.lproj)
28
56
  // (aligned with previous Electron Forge build config)
@@ -221,13 +249,15 @@ const config = {
221
249
  schemes: [protocolScheme],
222
250
  },
223
251
  ],
224
- publish: [
225
- {
226
- owner: 'lobehub',
227
- provider: 'github',
228
- repo: 'lobe-chat',
229
- },
230
- ],
252
+ publish: getPublishConfig(),
253
+
254
+ // Release notes 配置
255
+ // 可以通过环境变量 RELEASE_NOTES 传入,或从文件读取
256
+ // 这会被写入 latest-mac.yml / latest.yml 中,供 generic provider 使用
257
+ releaseInfo: {
258
+ releaseNotes: process.env.RELEASE_NOTES || undefined,
259
+ },
260
+
231
261
  win: {
232
262
  executableName: 'LobeHub',
233
263
  },