@lobehub/lobehub 2.0.0-next.290 → 2.0.0-next.292

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 (89) 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 +461 -0
  7. package/CHANGELOG.md +68 -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 +21 -0
  25. package/conductor.json +5 -0
  26. package/locales/en-US/chat.json +2 -0
  27. package/locales/en-US/subscription.json +2 -2
  28. package/locales/zh-CN/chat.json +2 -0
  29. package/locales/zh-CN/subscription.json +2 -2
  30. package/package.json +1 -1
  31. package/packages/builtin-tool-notebook/src/client/Render/CreateDocument/DocumentCard.tsx +16 -14
  32. package/packages/electron-client-ipc/src/useWatchBroadcast.ts +10 -4
  33. package/packages/model-bank/src/aiModels/qiniu.ts +6 -6
  34. package/packages/observability-otel/src/node.ts +39 -37
  35. package/scripts/electronWorkflow/mergeMacReleaseFiles.js +22 -8
  36. package/src/app/(backend)/api/version/route.ts +13 -0
  37. package/src/app/[variants]/(desktop)/desktop-onboarding/_layout/index.tsx +2 -1
  38. package/src/app/[variants]/(main)/_layout/index.tsx +2 -1
  39. package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobScheduleConfig.tsx +0 -1
  40. package/src/app/[variants]/(main)/agent/cron/[cronId]/index.tsx +5 -5
  41. package/src/app/[variants]/(main)/agent/features/Conversation/ThreadHydration.tsx +3 -1
  42. package/src/app/[variants]/(main)/group/features/Conversation/ThreadHydration.tsx +3 -1
  43. package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/Checker.tsx +15 -6
  44. package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/index.tsx +68 -23
  45. package/src/app/[variants]/(mobile)/router/mobileRouter.config.tsx +1 -4
  46. package/src/app/[variants]/router/desktopRouter.config.tsx +1 -4
  47. package/src/components/HtmlPreview/PreviewDrawer.tsx +1 -1
  48. package/src/features/ChatInput/ChatInputProvider.tsx +1 -1
  49. package/src/features/Conversation/Messages/Assistant/components/MessageContent.tsx +9 -16
  50. package/src/features/Conversation/Messages/AssistantGroup/components/GroupItem.tsx +12 -2
  51. package/src/features/Conversation/Messages/Task/components/MessageContent.tsx +1 -0
  52. package/src/features/Conversation/Messages/Tool/Tool/index.tsx +10 -1
  53. package/src/features/Conversation/Messages/components/ContentLoading.tsx +64 -0
  54. package/src/features/Conversation/Messages/components/DisplayContent.tsx +4 -2
  55. package/src/features/{ElectronTitlebar/hooks → Electron/navigation}/useNavigationHistory.ts +1 -1
  56. package/src/features/{ElectronTitlebar/NavigationBar/index.tsx → Electron/titlebar/NavigationBar.tsx} +1 -1
  57. package/src/features/{ElectronTitlebar/NavigationBar → Electron/titlebar}/RecentlyViewed.tsx +1 -1
  58. package/src/features/{ElectronTitlebar/index.tsx → Electron/titlebar/TitleBar.tsx} +19 -9
  59. package/src/features/Electron/titlebar/WinControl.tsx +5 -0
  60. package/src/features/Electron/updater/UpdateModal.tsx +299 -0
  61. package/src/features/LibraryModal/AddFilesToKnowledgeBase/index.test.tsx +24 -0
  62. package/src/features/LibraryModal/AddFilesToKnowledgeBase/index.tsx +21 -24
  63. package/src/features/LibraryModal/CreateNew/index.tsx +18 -22
  64. package/src/features/OllamaModelDownloader/index.tsx +3 -3
  65. package/src/features/PluginDevModal/index.tsx +1 -1
  66. package/src/layout/GlobalProvider/AppTheme.tsx +1 -1
  67. package/src/libs/swr/index.ts +17 -23
  68. package/src/locales/default/chat.ts +2 -0
  69. package/src/store/aiInfra/slices/aiProvider/action.ts +68 -1
  70. package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +2 -1
  71. package/src/store/chat/slices/portal/action.test.ts +0 -2
  72. package/src/store/chat/slices/portal/action.ts +17 -44
  73. package/src/store/chat/slices/thread/action.test.ts +4 -1
  74. package/src/store/chat/slices/thread/action.ts +6 -1
  75. package/src/components/FunctionModal/createModalHooks.ts +0 -48
  76. package/src/components/FunctionModal/index.ts +0 -1
  77. package/src/components/FunctionModal/style.tsx +0 -44
  78. package/src/features/ElectronTitlebar/UpdateModal.tsx +0 -274
  79. package/src/features/ElectronTitlebar/WinControl/index.tsx +0 -90
  80. /package/src/features/{ElectronTitlebar/Connection/index.tsx → Electron/connection/Connection.tsx} +0 -0
  81. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/ConnectionMode.tsx +0 -0
  82. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/Option.tsx +0 -0
  83. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/RemoteStatus.tsx +0 -0
  84. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/Waiting.tsx +0 -0
  85. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/WaitingAnim.tsx +0 -0
  86. /package/src/features/{ElectronTitlebar/helpers → Electron/navigation}/routeMetadata.ts +0 -0
  87. /package/src/features/{ElectronTitlebar/hooks → Electron/system}/useWatchThemeUpdate.ts +0 -0
  88. /package/src/features/{ElectronTitlebar → Electron/titlebar}/SimpleTitleBar.tsx +0 -0
  89. /package/src/features/{ElectronTitlebar → Electron/updater}/UpdateNotification.tsx +0 -0
@@ -0,0 +1,461 @@
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_windows:
38
+ description: 'Build Windows'
39
+ required: false
40
+ type: boolean
41
+ default: true
42
+ build_linux:
43
+ description: 'Build Linux'
44
+ required: false
45
+ type: boolean
46
+ default: true
47
+ skip_s3_upload:
48
+ description: 'Skip S3 upload (for testing)'
49
+ required: false
50
+ type: boolean
51
+ default: true
52
+ skip_github_release:
53
+ description: 'Skip GitHub release upload (for testing)'
54
+ required: false
55
+ type: boolean
56
+ default: true
57
+
58
+ concurrency:
59
+ group: ${{ github.ref }}-${{ github.workflow }}
60
+ cancel-in-progress: true
61
+
62
+ permissions: read-all
63
+
64
+ env:
65
+ NODE_VERSION: '24.11.1'
66
+
67
+ jobs:
68
+ # ============================================
69
+ # 检查版本信息
70
+ # ============================================
71
+ check-stable:
72
+ name: Check Release Version
73
+ runs-on: ubuntu-latest
74
+ outputs:
75
+ is_stable: ${{ steps.check.outputs.is_stable }}
76
+ version: ${{ steps.check.outputs.version }}
77
+ is_manual: ${{ steps.check.outputs.is_manual }}
78
+ release_notes: ${{ steps.check.outputs.release_notes }}
79
+ steps:
80
+ - name: Check release info
81
+ id: check
82
+ run: |
83
+ # 判断触发方式
84
+ if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
85
+ # 手动触发: 使用输入的版本号
86
+ version="${{ inputs.version }}"
87
+ echo "is_manual=true" >> $GITHUB_OUTPUT
88
+ echo "is_stable=true" >> $GITHUB_OUTPUT
89
+ echo "version=${version}" >> $GITHUB_OUTPUT
90
+ echo "release_notes=" >> $GITHUB_OUTPUT
91
+ echo "🔧 Manual trigger: version=${version}"
92
+ else
93
+ # Release 触发: 从 tag 提取版本号
94
+ version="${{ github.event.release.tag_name }}"
95
+ version="${version#v}"
96
+ echo "is_manual=false" >> $GITHUB_OUTPUT
97
+ echo "version=${version}" >> $GITHUB_OUTPUT
98
+ release_body="${{ github.event.release.body }}"
99
+ {
100
+ echo "release_notes<<EOF"
101
+ printf '%s\n' "$release_body"
102
+ echo "EOF"
103
+ } >> $GITHUB_OUTPUT
104
+
105
+ # 检查是否为 stable 版本 (不含 beta/alpha/rc/nightly)
106
+ if [[ "$version" == *"beta"* ]] || [[ "$version" == *"alpha"* ]] || [[ "$version" == *"rc"* ]] || [[ "$version" == *"nightly"* ]]; then
107
+ echo "is_stable=false" >> $GITHUB_OUTPUT
108
+ echo "⏭️ Skipping: $version is not a stable release"
109
+ else
110
+ echo "is_stable=true" >> $GITHUB_OUTPUT
111
+ echo "✅ Stable release detected: $version"
112
+ fi
113
+ fi
114
+
115
+ # ============================================
116
+ # 配置构建矩阵 (检查自托管 Runner)
117
+ # ============================================
118
+ configure-build:
119
+ needs: [check-stable]
120
+ if: needs.check-stable.outputs.is_stable == 'true'
121
+ name: Configure Build Matrix
122
+ runs-on: ubuntu-latest
123
+ outputs:
124
+ matrix: ${{ steps.set-matrix.outputs.matrix }}
125
+ steps:
126
+ - name: Generate Matrix
127
+ id: set-matrix
128
+ run: |
129
+ # 基础矩阵
130
+ static_matrix='[]'
131
+
132
+ # Windows
133
+ if [[ "${{ github.event_name }}" != "workflow_dispatch" ]] || [[ "${{ inputs.build_windows }}" == "true" ]]; then
134
+ static_matrix=$(echo "$static_matrix" | jq -c '. + [{"os": "windows-2025", "name": "windows-2025"}]')
135
+ fi
136
+
137
+ # Linux
138
+ if [[ "${{ github.event_name }}" != "workflow_dispatch" ]] || [[ "${{ inputs.build_linux }}" == "true" ]]; then
139
+ static_matrix=$(echo "$static_matrix" | jq -c '. + [{"os": "ubuntu-latest", "name": "ubuntu-latest"}]')
140
+ fi
141
+
142
+ # macOS (ARM64)
143
+ # 使用 GitHub Hosted Runner
144
+ if [[ "${{ github.event_name }}" != "workflow_dispatch" ]] || [[ "${{ inputs.build_mac }}" == "true" ]]; then
145
+ echo "Using GitHub-Hosted Runner for macOS ARM64"
146
+ arm_entry='{"os": "macos-14", "name": "macos-arm64"}'
147
+ static_matrix=$(echo "$static_matrix" | jq -c --argjson entry "$arm_entry" '. + [$entry]')
148
+ fi
149
+
150
+ # 输出
151
+ echo "matrix={\"include\":$static_matrix}" >> $GITHUB_OUTPUT
152
+
153
+ # ============================================
154
+ # 多平台构建
155
+ # ============================================
156
+ build:
157
+ needs: [check-stable, configure-build]
158
+ if: needs.check-stable.outputs.is_stable == 'true'
159
+ name: Build Desktop App
160
+ runs-on: ${{ matrix.os }}
161
+ strategy:
162
+ fail-fast: false
163
+ matrix: ${{ fromJson(needs.configure-build.outputs.matrix) }}
164
+ steps:
165
+ - uses: actions/checkout@v6
166
+ with:
167
+ fetch-depth: 0
168
+
169
+ - name: Setup build environment
170
+ uses: ./.github/actions/desktop-build-setup
171
+ with:
172
+ node-version: ${{ env.NODE_VERSION }}
173
+
174
+ - name: Set package version
175
+ run: npm run workflow:set-desktop-version ${{ needs.check-stable.outputs.version }} stable
176
+
177
+ # macOS 构建
178
+ - name: Build artifact on macOS
179
+ if: runner.os == 'macOS'
180
+ run: npm run desktop:build
181
+ env:
182
+ UPDATE_CHANNEL: stable
183
+ UPDATE_SERVER_URL: ${{ secrets.UPDATE_SERVER_URL }}
184
+ RELEASE_NOTES: ${{ needs.check-stable.outputs.release_notes }}
185
+ APP_URL: http://localhost:3015
186
+ DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
187
+ KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
188
+ CSC_LINK: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
189
+ CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
190
+ CSC_FOR_PULL_REQUEST: true
191
+ APPLE_ID: ${{ secrets.APPLE_ID }}
192
+ APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
193
+ APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
194
+ NEXT_PUBLIC_DESKTOP_PROJECT_ID: ${{ secrets.UMAMI_STABLE_DESKTOP_PROJECT_ID }}
195
+ NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL: ${{ secrets.UMAMI_STABLE_DESKTOP_BASE_URL }}
196
+
197
+ # Windows 构建
198
+ - name: Build artifact on Windows
199
+ if: runner.os == 'Windows'
200
+ run: npm run desktop:build
201
+ env:
202
+ UPDATE_CHANNEL: stable
203
+ UPDATE_SERVER_URL: ${{ secrets.UPDATE_SERVER_URL }}
204
+ RELEASE_NOTES: ${{ needs.check-stable.outputs.release_notes }}
205
+ APP_URL: http://localhost:3015
206
+ DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
207
+ KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
208
+ NEXT_PUBLIC_DESKTOP_PROJECT_ID: ${{ secrets.UMAMI_STABLE_DESKTOP_PROJECT_ID }}
209
+ NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL: ${{ secrets.UMAMI_STABLE_DESKTOP_BASE_URL }}
210
+ TEMP: C:\temp
211
+ TMP: C:\temp
212
+
213
+ # Linux 构建
214
+ - name: Build artifact on Linux
215
+ if: runner.os == 'Linux'
216
+ run: |
217
+ npm run desktop:build
218
+ tar -czf apps/desktop/release/lobehub-renderer.tar.gz -C out .
219
+ env:
220
+ UPDATE_CHANNEL: stable
221
+ UPDATE_SERVER_URL: ${{ secrets.UPDATE_SERVER_URL }}
222
+ RELEASE_NOTES: ${{ needs.check-stable.outputs.release_notes }}
223
+ APP_URL: http://localhost:3015
224
+ DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
225
+ KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
226
+ NEXT_PUBLIC_DESKTOP_PROJECT_ID: ${{ secrets.UMAMI_STABLE_DESKTOP_PROJECT_ID }}
227
+ NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL: ${{ secrets.UMAMI_STABLE_DESKTOP_BASE_URL }}
228
+
229
+ - name: Upload artifacts
230
+ uses: ./.github/actions/desktop-upload-artifacts
231
+ with:
232
+ artifact-name: release-${{ matrix.name }}
233
+
234
+ # ============================================
235
+ # 合并 macOS 多架构文件
236
+ # ============================================
237
+ merge-mac-files:
238
+ needs: [build, check-stable]
239
+ name: Merge macOS Release Files
240
+ runs-on: ubuntu-latest
241
+ permissions:
242
+ contents: write
243
+ steps:
244
+ - name: Checkout repository
245
+ uses: actions/checkout@v6
246
+
247
+ - name: Setup Node.js
248
+ uses: actions/setup-node@v6
249
+ with:
250
+ node-version: ${{ env.NODE_VERSION }}
251
+ package-manager-cache: false
252
+
253
+ - name: Install bun
254
+ uses: oven-sh/setup-bun@v2
255
+ with:
256
+ bun-version: latest
257
+
258
+ - name: Download artifacts
259
+ uses: actions/download-artifact@v7
260
+ with:
261
+ path: release
262
+ pattern: release-*
263
+ merge-multiple: true
264
+
265
+ - name: List downloaded artifacts
266
+ run: ls -R release
267
+
268
+ - name: Install yaml only for merge step
269
+ run: |
270
+ cd scripts/electronWorkflow
271
+ if [ ! -f package.json ]; then
272
+ echo '{"name":"merge-mac-release","private":true}' > package.json
273
+ fi
274
+ bun add --no-save yaml@2.8.1
275
+
276
+ - name: Merge latest-mac.yml files
277
+ run: bun run scripts/electronWorkflow/mergeMacReleaseFiles.js
278
+
279
+ - name: Upload artifacts with merged macOS files
280
+ uses: actions/upload-artifact@v6
281
+ with:
282
+ name: merged-release
283
+ path: release/
284
+ retention-days: 1
285
+
286
+ # ============================================
287
+ # 发布到 GitHub Releases
288
+ # ============================================
289
+ publish-github:
290
+ needs: [merge-mac-files, check-stable]
291
+ name: Publish to GitHub Release
292
+ runs-on: ubuntu-latest
293
+ # 手动触发时可选择跳过
294
+ if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.skip_github_release) }}
295
+ permissions:
296
+ contents: write
297
+ steps:
298
+ - name: Download merged artifacts
299
+ uses: actions/download-artifact@v7
300
+ with:
301
+ name: merged-release
302
+ path: release
303
+
304
+ - name: List final artifacts
305
+ run: ls -R release
306
+
307
+ - name: Upload to Release
308
+ uses: softprops/action-gh-release@v1
309
+ with:
310
+ # 手动触发时使用输入的版本号创建 tag
311
+ tag_name: ${{ github.event_name == 'workflow_dispatch' && format('v{0}', needs.check-stable.outputs.version) || github.event.release.tag_name }}
312
+ # 手动触发时创建为 draft
313
+ draft: ${{ github.event_name == 'workflow_dispatch' }}
314
+ files: |
315
+ release/stable*
316
+ release/latest*
317
+ release/*.dmg*
318
+ release/*.zip*
319
+ release/*.exe*
320
+ release/*.AppImage
321
+ release/*.deb*
322
+ release/*.snap*
323
+ release/*.rpm*
324
+ release/*.tar.gz*
325
+ env:
326
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
327
+
328
+ # ============================================
329
+ # 发布到 S3 更新服务器
330
+ # ============================================
331
+ # S3 目录结构:
332
+ # s3://bucket/
333
+ # stable/
334
+ # stable-mac.yml ← electron-updater 检查更新 (stable channel)
335
+ # stable.yml ← Windows (stable channel)
336
+ # stable-linux.yml ← Linux (stable channel)
337
+ # latest-mac.yml ← fallback for GitHub provider
338
+ # {version}/ ← 版本目录
339
+ # *.dmg, *.zip, *.exe, ...
340
+ # ============================================
341
+ publish-s3:
342
+ needs: [merge-mac-files, check-stable]
343
+ name: Publish to S3
344
+ runs-on: ubuntu-latest
345
+ # 手动触发时可选择跳过
346
+ if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.skip_s3_upload) }}
347
+ steps:
348
+ - name: Download merged artifacts
349
+ uses: actions/download-artifact@v7
350
+ with:
351
+ name: merged-release
352
+ path: release
353
+
354
+ - name: List artifacts to upload
355
+ run: |
356
+ echo "📦 Artifacts to upload to S3:"
357
+ ls -lah release/
358
+ echo ""
359
+ echo "📋 Version: ${{ needs.check-stable.outputs.version }}"
360
+
361
+ - name: Upload to S3
362
+ env:
363
+ AWS_ACCESS_KEY_ID: ${{ secrets.UPDATE_AWS_ACCESS_KEY_ID }}
364
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.UPDATE_AWS_SECRET_ACCESS_KEY }}
365
+ AWS_REGION: ${{ secrets.UPDATE_S3_REGION || 'us-east-1' }}
366
+ S3_BUCKET: ${{ secrets.UPDATE_S3_BUCKET }}
367
+ S3_ENDPOINT: ${{ secrets.UPDATE_S3_ENDPOINT }}
368
+ VERSION: ${{ needs.check-stable.outputs.version }}
369
+ run: |
370
+ if [ -z "$S3_BUCKET" ]; then
371
+ echo "⚠️ UPDATE_S3_BUCKET is not configured, skipping S3 upload"
372
+ echo ""
373
+ echo "To enable S3 upload, configure the following secrets:"
374
+ echo " - UPDATE_AWS_ACCESS_KEY_ID"
375
+ echo " - UPDATE_AWS_SECRET_ACCESS_KEY"
376
+ echo " - UPDATE_S3_BUCKET"
377
+ echo " - UPDATE_S3_REGION (optional, defaults to us-east-1)"
378
+ echo " - UPDATE_S3_ENDPOINT (optional, for S3-compatible services)"
379
+ exit 0
380
+ fi
381
+
382
+ # 构建端点参数
383
+ ENDPOINT_ARG=""
384
+ if [ -n "$S3_ENDPOINT" ]; then
385
+ ENDPOINT_ARG="--endpoint-url $S3_ENDPOINT"
386
+ echo "📡 Using custom S3 endpoint: $S3_ENDPOINT"
387
+ fi
388
+
389
+ echo "🚀 Uploading to S3 bucket: $S3_BUCKET"
390
+ echo "📁 Target path: s3://$S3_BUCKET/stable/"
391
+ echo ""
392
+
393
+ # 1. 上传安装包到版本目录
394
+ echo "📦 Uploading release files to s3://$S3_BUCKET/stable/$VERSION/"
395
+ for file in release/*.dmg release/*.zip release/*.exe release/*.AppImage release/*.deb release/*.rpm release/*.snap release/*.tar.gz; do
396
+ if [ -f "$file" ]; then
397
+ filename=$(basename "$file")
398
+ echo " ↗️ $filename"
399
+ aws s3 cp "$file" "s3://$S3_BUCKET/stable/$VERSION/$filename" $ENDPOINT_ARG
400
+ fi
401
+ done
402
+
403
+ # 2. 创建 stable*.yml (从 latest*.yml 复制,并修改 URL 加上版本目录前缀)
404
+ # electron-updater 在 channel=stable 时会找 stable-mac.yml
405
+ # S3 目录结构: stable/{version}/xxx.dmg,所以 URL 需要加上 {version}/ 前缀
406
+ echo ""
407
+ echo "📋 Creating stable*.yml files from latest*.yml..."
408
+ for yml in release/latest*.yml; do
409
+ if [ -f "$yml" ]; then
410
+ stable_name=$(basename "$yml" | sed 's/latest/stable/')
411
+ # 复制并修改 URL: 给所有 url 字段加上版本目录前缀
412
+ # url: xxx.dmg -> url: {VERSION}/xxx.dmg
413
+ sed "s|url: |url: $VERSION/|g" "$yml" > "release/$stable_name"
414
+ echo " 📄 Created $stable_name from $(basename $yml) with URL prefix: $VERSION/"
415
+ fi
416
+ done
417
+
418
+ # 3. 创建 renderer manifest (用于验证 renderer tar 完整性)
419
+ echo ""
420
+ echo "📋 Creating renderer manifest..."
421
+ RENDERER_TAR="release/lobehub-renderer.tar.gz"
422
+ if [ -f "$RENDERER_TAR" ]; then
423
+ RENDERER_SHA512=$(shasum -a 512 "$RENDERER_TAR" | awk '{print $1}' | xxd -r -p | base64)
424
+ RENDERER_SIZE=$(stat -f%z "$RENDERER_TAR" 2>/dev/null || stat -c%s "$RENDERER_TAR")
425
+ RELEASE_DATE=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
426
+ echo "version: $VERSION" > "release/stable-renderer.yml"
427
+ echo "files:" >> "release/stable-renderer.yml"
428
+ echo " - url: $VERSION/lobehub-renderer.tar.gz" >> "release/stable-renderer.yml"
429
+ echo " sha512: $RENDERER_SHA512" >> "release/stable-renderer.yml"
430
+ echo " size: $RENDERER_SIZE" >> "release/stable-renderer.yml"
431
+ echo "path: $VERSION/lobehub-renderer.tar.gz" >> "release/stable-renderer.yml"
432
+ echo "sha512: $RENDERER_SHA512" >> "release/stable-renderer.yml"
433
+ echo "releaseDate: '$RELEASE_DATE'" >> "release/stable-renderer.yml"
434
+ echo " 📄 Created stable-renderer.yml with SHA512 checksum"
435
+ else
436
+ echo " ⚠️ Renderer tar not found, skipping manifest creation"
437
+ fi
438
+
439
+ # 4. 上传 manifest 到根目录和版本目录
440
+ # 根目录: electron-updater 需要,会被每次发版覆盖
441
+ # 版本目录: 作为存档保留
442
+ echo ""
443
+ echo "📋 Uploading manifest files..."
444
+ for yml in release/stable*.yml release/latest*.yml; do
445
+ if [ -f "$yml" ]; then
446
+ filename=$(basename "$yml")
447
+ echo " ↗️ $filename -> s3://$S3_BUCKET/stable/$filename"
448
+ aws s3 cp "$yml" "s3://$S3_BUCKET/stable/$filename" $ENDPOINT_ARG
449
+ echo " ↗️ $filename -> s3://$S3_BUCKET/stable/$VERSION/$filename (archive)"
450
+ aws s3 cp "$yml" "s3://$S3_BUCKET/stable/$VERSION/$filename" $ENDPOINT_ARG
451
+ fi
452
+ done
453
+
454
+ echo ""
455
+ echo "✅ S3 upload completed!"
456
+ echo ""
457
+ echo "📋 Files in s3://$S3_BUCKET/stable/:"
458
+ aws s3 ls "s3://$S3_BUCKET/stable/" $ENDPOINT_ARG || true
459
+ echo ""
460
+ echo "📋 Files in s3://$S3_BUCKET/stable/$VERSION/:"
461
+ aws s3 ls "s3://$S3_BUCKET/stable/$VERSION/" $ENDPOINT_ARG || true
package/CHANGELOG.md CHANGED
@@ -2,6 +2,74 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 2.0.0-next.292](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.291...v2.0.0-next.292)
6
+
7
+ <sup>Released on **2026-01-15**</sup>
8
+
9
+ #### ♻ Code Refactoring
10
+
11
+ - **misc**: Use fallbackData to prevent useActionSWR auto-fetch.
12
+
13
+ #### ✨ Features
14
+
15
+ - **desktop**: Add local update testing scripts and stable channel API version check.
16
+
17
+ <br/>
18
+
19
+ <details>
20
+ <summary><kbd>Improvements and Fixes</kbd></summary>
21
+
22
+ #### Code refactoring
23
+
24
+ - **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))
25
+
26
+ #### What's improved
27
+
28
+ - **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))
29
+
30
+ </details>
31
+
32
+ <div align="right">
33
+
34
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
35
+
36
+ </div>
37
+
38
+ ## [Version 2.0.0-next.291](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.290...v2.0.0-next.291)
39
+
40
+ <sup>Released on **2026-01-15**</sup>
41
+
42
+ #### 🐛 Bug Fixes
43
+
44
+ - **settings**: Add instant UI feedback for provider config switches.
45
+ - **misc**: Click lobe ai topic trigger create new agent.
46
+
47
+ #### 💄 Styles
48
+
49
+ - **misc**: Improve agent loading state.
50
+
51
+ <br/>
52
+
53
+ <details>
54
+ <summary><kbd>Improvements and Fixes</kbd></summary>
55
+
56
+ #### What's fixed
57
+
58
+ - **settings**: Add instant UI feedback for provider config switches, closes [#11362](https://github.com/lobehub/lobe-chat/issues/11362) ([a758d01](https://github.com/lobehub/lobe-chat/commit/a758d01))
59
+ - **misc**: Click lobe ai topic trigger create new agent, closes [#11508](https://github.com/lobehub/lobe-chat/issues/11508) ([2443189](https://github.com/lobehub/lobe-chat/commit/2443189))
60
+
61
+ #### Styles
62
+
63
+ - **misc**: Improve agent loading state, closes [#11511](https://github.com/lobehub/lobe-chat/issues/11511) ([3bb7f33](https://github.com/lobehub/lobe-chat/commit/3bb7f33))
64
+
65
+ </details>
66
+
67
+ <div align="right">
68
+
69
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
70
+
71
+ </div>
72
+
5
73
  ## [Version 2.0.0-next.290](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.289...v2.0.0-next.290)
6
74
 
7
75
  <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
  },