diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 08ca8c19e..ba05e9cfe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -57,7 +57,9 @@ jobs: run: pnpm run installRuntime:win:${{ matrix.arch }} - name: Build Windows - run: pnpm run build:win:${{ matrix.arch }} + run: | + pnpm run build + pnpm exec electron-builder --win --${{ matrix.arch }} --publish=never env: VITE_GITHUB_CLIENT_ID: ${{ secrets.DC_GITHUB_CLIENT_ID }} VITE_GITHUB_CLIENT_SECRET: ${{ secrets.DC_GITHUB_CLIENT_SECRET }} @@ -111,7 +113,9 @@ jobs: # run: pnpm run installRuntime:linux:${{ matrix.arch }} - name: Build Linux - run: pnpm run build:linux:${{ matrix.arch }} + run: | + pnpm run build + pnpm exec electron-builder --linux --${{ matrix.arch }} --publish=never env: VITE_GITHUB_CLIENT_ID: ${{ secrets.DC_GITHUB_CLIENT_ID }} VITE_GITHUB_CLIENT_SECRET: ${{ secrets.DC_GITHUB_CLIENT_SECRET }} @@ -166,7 +170,9 @@ jobs: run: pnpm run installRuntime:mac:${{ matrix.arch }} - name: Build Mac - run: pnpm run build:mac:${{ matrix.arch }} + run: | + pnpm run build + pnpm exec electron-builder --mac --${{ matrix.arch }} --publish=never env: CSC_LINK: ${{ secrets.DEEPCHAT_CSC_LINK }} CSC_KEY_PASSWORD: ${{ secrets.DEEPCHAT_CSC_KEY_PASS }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1209a9066..8065fdda9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,45 +1,341 @@ -name: Create Release +name: Release on: workflow_dispatch: inputs: - workflow_id: - description: 'Build workflow run ID to use for artifacts' + tag: + description: 'Release tag (e.g. v0.5.5 v0.5.6-beta.1)' required: true type: string - prerelease: - description: 'Is this a prerelease?' - required: true - type: boolean - default: false + push: + tags: + - v*.*.* + +permissions: + contents: write jobs: - create-release: + resolve-tag: runs-on: ubuntu-latest + outputs: + tag: ${{ steps.resolve.outputs.tag }} + sha: ${{ steps.resolve.outputs.sha }} steps: - - name: Download artifacts from workflow - uses: dawidd6/action-download-artifact@v6 + - name: Resolve tag + id: resolve + uses: actions/github-script@v7 with: - workflow_conclusion: success - run_id: ${{ github.event.inputs.workflow_id }} - path: artifacts + script: | + const isDispatch = context.eventName === 'workflow_dispatch' + const tag = isDispatch + ? context.payload.inputs?.tag + : context.ref.replace('refs/tags/', '') + if (!tag) { + core.setFailed('Tag is required') + return + } + + const owner = context.repo.owner + const repo = context.repo.repo + const refName = `tags/${tag}` + + const resolveTagSha = async (refData) => { + let sha = refData.object.sha + if (refData.object.type === 'tag') { + const tagObj = await github.rest.git.getTag({ + owner, + repo, + tag_sha: sha + }) + sha = tagObj.data.object.sha + } + return sha + } + + if (isDispatch) { + try { + const { data } = await github.rest.git.getRef({ + owner, + repo, + ref: refName + }) + const sha = await resolveTagSha(data) + core.setOutput('sha', sha) + } catch (error) { + const sha = context.sha + await github.rest.git.createRef({ + owner, + repo, + ref: `refs/${refName}`, + sha + }) + core.setOutput('sha', sha) + } + } else { + try { + const { data } = await github.rest.git.getRef({ + owner, + repo, + ref: refName + }) + const sha = await resolveTagSha(data) + core.setOutput('sha', sha) + } catch (error) { + core.setFailed(`Tag ${tag} not found`) + return + } + } + + core.setOutput('tag', tag) + + build-windows: + needs: resolve-tag + runs-on: windows-latest + strategy: + matrix: + arch: [x64] + include: + - arch: x64 + platform: win-x64 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.resolve-tag.outputs.sha }} + fetch-depth: 1 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.13.1' - - name: List downloaded artifacts - run: find artifacts -type f | sort + - name: Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: 10.12.1 + + - name: Install dependencies + run: pnpm install + + - name: Configure pnpm workspace for Windows ${{ matrix.arch }} + run: pnpm run install:sharp + env: + TARGET_OS: win32 + TARGET_ARCH: ${{ matrix.arch }} + + - name: Install dependencies + run: pnpm install + env: + npm_config_build_from_source: true + npm_config_platform: win32 + npm_config_arch: ${{ matrix.arch }} + + - name: Install Node Runtime + run: pnpm run installRuntime:win:${{ matrix.arch }} + + - name: Build Windows + run: | + pnpm run build + pnpm exec electron-builder --win --${{ matrix.arch }} --publish=never + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VITE_GITHUB_CLIENT_ID: ${{ secrets.DC_GITHUB_CLIENT_ID }} + VITE_GITHUB_CLIENT_SECRET: ${{ secrets.DC_GITHUB_CLIENT_SECRET }} + VITE_GITHUB_REDIRECT_URI: ${{ secrets.DC_GITHUB_REDIRECT_URI }} + VITE_PROVIDER_DB_URL: ${{ secrets.CDN_PROVIDER_DB_URL }} + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: deepchat-${{ matrix.platform }} + path: | + dist/* + !dist/win-unpacked + !dist/win-arm64-unpacked + + build-linux: + needs: resolve-tag + runs-on: ubuntu-22.04 + strategy: + matrix: + arch: [x64] + include: + - arch: x64 + platform: linux-x64 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.resolve-tag.outputs.sha }} + fetch-depth: 1 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.13.1' + + - name: Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: 10.12.1 + + - name: Install dependencies + run: pnpm install + + - name: Configure pnpm workspace for Linux ${{ matrix.arch }} + run: pnpm run install:sharp + env: + TARGET_OS: linux + TARGET_ARCH: ${{ matrix.arch }} + + - name: Install dependencies + run: pnpm install + + - name: Build Linux + run: | + pnpm run build + pnpm exec electron-builder --linux --${{ matrix.arch }} --publish=never + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VITE_GITHUB_CLIENT_ID: ${{ secrets.DC_GITHUB_CLIENT_ID }} + VITE_GITHUB_CLIENT_SECRET: ${{ secrets.DC_GITHUB_CLIENT_SECRET }} + VITE_GITHUB_REDIRECT_URI: ${{ secrets.DC_GITHUB_REDIRECT_URI }} + VITE_PROVIDER_DB_URL: ${{ secrets.CDN_PROVIDER_DB_URL }} + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: deepchat-${{ matrix.platform }} + path: | + dist/* + !dist/linux-unpacked + + build-mac: + needs: resolve-tag + runs-on: macos-15 + strategy: + matrix: + arch: [x64, arm64] + include: + - arch: x64 + platform: mac-x64 + - arch: arm64 + platform: mac-arm64 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.resolve-tag.outputs.sha }} + fetch-depth: 1 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.13.1' + + - name: Setup pnpm + uses: pnpm/action-setup@v2 + with: + version: 10.12.1 + + - name: Install dependencies + run: pnpm install + + - name: Configure pnpm workspace for macOS ${{ matrix.arch }} + run: pnpm run install:sharp + env: + TARGET_OS: darwin + TARGET_ARCH: ${{ matrix.arch }} + + - name: Install dependencies + run: pnpm install + + - name: Install Node Runtime + run: pnpm run installRuntime:mac:${{ matrix.arch }} + + - name: Build Mac + run: | + pnpm run build + pnpm exec electron-builder --mac --${{ matrix.arch }} --publish=never + env: + CSC_LINK: ${{ secrets.DEEPCHAT_CSC_LINK }} + CSC_KEY_PASSWORD: ${{ secrets.DEEPCHAT_CSC_KEY_PASS }} + DEEPCHAT_APPLE_NOTARY_USERNAME: ${{ secrets.DEEPCHAT_APPLE_NOTARY_USERNAME }} + DEEPCHAT_APPLE_NOTARY_TEAM_ID: ${{ secrets.DEEPCHAT_APPLE_NOTARY_TEAM_ID }} + DEEPCHAT_APPLE_NOTARY_PASSWORD: ${{ secrets.DEEPCHAT_APPLE_NOTARY_PASSWORD }} + build_for_release: '2' + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VITE_GITHUB_CLIENT_ID: ${{ secrets.DC_GITHUB_CLIENT_ID }} + VITE_GITHUB_CLIENT_SECRET: ${{ secrets.DC_GITHUB_CLIENT_SECRET }} + VITE_GITHUB_REDIRECT_URI: ${{ secrets.DC_GITHUB_REDIRECT_URI }} + NODE_OPTIONS: '--max-old-space-size=4096' + VITE_PROVIDER_DB_URL: ${{ secrets.CDN_PROVIDER_DB_URL }} + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: deepchat-${{ matrix.platform }} + path: | + dist/* + !dist/mac/* + !dist/mac-arm64/* + + release: + needs: + - resolve-tag + - build-windows + - build-linux + - build-mac + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.resolve-tag.outputs.sha }} + fetch-depth: 1 - name: Get version number id: get_version run: | - VERSION_FILE=$(find artifacts/deepchat-linux-x64 -name "DeepChat-*.tar.gz" | head -n 1) - if [ -n "$VERSION_FILE" ]; then - VERSION=$(echo $VERSION_FILE | grep -o 'DeepChat-[0-9]\+\.[0-9]\+\.[0-9]\+' | sed 's/DeepChat-//') - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Found version: $VERSION" + VERSION=$(node -p "require('./package.json').version") + TAG="${{ needs.resolve-tag.outputs.tag }}" + if [ "v$VERSION" != "$TAG" ]; then + echo "Error: tag $TAG does not match package.json version v$VERSION" + exit 1 + fi + if echo "$VERSION" | grep -qE '-(beta|alpha)\.[0-9]+$'; then + echo "prerelease=true" >> $GITHUB_OUTPUT else - echo "Error: DeepChat tar.gz file not found" + echo "prerelease=false" >> $GITHUB_OUTPUT + fi + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Build release notes from CHANGELOG + run: | + VERSION="${{ steps.get_version.outputs.version }}" + CHANGELOG="CHANGELOG.md" + if [ ! -f "$CHANGELOG" ]; then + echo "Error: CHANGELOG.md not found" + exit 1 + fi + NORMALIZED_CHANGELOG="$(mktemp)" + perl -pe 's/\x{FF08}/(/g; s/\x{FF09}/)/g; s/\r$//' "$CHANGELOG" > "$NORMALIZED_CHANGELOG" + HEADER_REGEX="^##[[:space:]]+v${VERSION}[[:space:]]*\\([0-9]{4}-[0-9]{2}-[0-9]{2}\\)[[:space:]]*$" + if ! grep -Eq "$HEADER_REGEX" "$NORMALIZED_CHANGELOG"; then + echo "Error: Changelog entry not found for v${VERSION}" + exit 1 + fi + awk -v ver="v${VERSION}" ' + $0 ~ "^##[[:space:]]+" ver "[[:space:]]*\\(" { in_section = 1 } + in_section && $0 ~ "^##[[:space:]]+" && $0 !~ "^##[[:space:]]+" ver "[[:space:]]*\\(" { exit } + in_section { print } + ' "$NORMALIZED_CHANGELOG" > release_notes.md + if [ ! -s release_notes.md ]; then + echo "Error: Release notes are empty for v${VERSION}" exit 1 fi + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + - name: Prepare release assets run: | mkdir -p release_assets @@ -49,33 +345,67 @@ jobs: cp artifacts/deepchat-win-x64/*.exe release_assets/ 2>/dev/null || true cp artifacts/deepchat-win-x64/*.msi release_assets/ 2>/dev/null || true cp artifacts/deepchat-win-x64/*.zip release_assets/ 2>/dev/null || true + cp artifacts/deepchat-win-x64/*.yml release_assets/ 2>/dev/null || true + cp artifacts/deepchat-win-x64/*.blockmap release_assets/ 2>/dev/null || true fi - # Process Windows arm64 artifacts - #if [ -d "artifacts/deepchat-win-arm64" ]; then - # cp artifacts/deepchat-win-arm64/*.exe release_assets/ 2>/dev/null || true - # cp artifacts/deepchat-win-arm64/*.msi release_assets/ 2>/dev/null || true - # cp artifacts/deepchat-win-arm64/*.zip release_assets/ 2>/dev/null || true - #fi - # Process Linux x64 artifacts if [ -d "artifacts/deepchat-linux-x64" ]; then cp artifacts/deepchat-linux-x64/*.AppImage release_assets/ 2>/dev/null || true cp artifacts/deepchat-linux-x64/*.deb release_assets/ 2>/dev/null || true cp artifacts/deepchat-linux-x64/*.rpm release_assets/ 2>/dev/null || true cp artifacts/deepchat-linux-x64/*.tar.gz release_assets/ 2>/dev/null || true + cp artifacts/deepchat-linux-x64/*.yml release_assets/ 2>/dev/null || true + cp artifacts/deepchat-linux-x64/*.blockmap release_assets/ 2>/dev/null || true fi # Process Mac x64 artifacts if [ -d "artifacts/deepchat-mac-x64" ]; then cp artifacts/deepchat-mac-x64/*.dmg release_assets/ 2>/dev/null || true cp artifacts/deepchat-mac-x64/*.zip release_assets/ 2>/dev/null || true + cp artifacts/deepchat-mac-x64/*.blockmap release_assets/ 2>/dev/null || true fi # Process Mac arm64 artifacts if [ -d "artifacts/deepchat-mac-arm64" ]; then cp artifacts/deepchat-mac-arm64/*.dmg release_assets/ 2>/dev/null || true cp artifacts/deepchat-mac-arm64/*.zip release_assets/ 2>/dev/null || true + cp artifacts/deepchat-mac-arm64/*.blockmap release_assets/ 2>/dev/null || true + fi + + merge_mac_yml() { + local name="$1" + local x64="artifacts/deepchat-mac-x64/$name" + local arm64="artifacts/deepchat-mac-arm64/$name" + if [ -f "$x64" ] && [ -f "$arm64" ]; then + ruby -ryaml -e ' + x64 = YAML.load_file(ARGV[0]) || {} + arm = YAML.load_file(ARGV[1]) || {} + merged = x64.dup + merged["version"] ||= arm["version"] + merged["releaseDate"] ||= arm["releaseDate"] + merged["releaseNotes"] ||= arm["releaseNotes"] + merged["path"] ||= arm["path"] + merged["sha512"] ||= arm["sha512"] + files = [] + files.concat(x64["files"]) if x64["files"].is_a?(Array) + files.concat(arm["files"]) if arm["files"].is_a?(Array) + merged["files"] = files.uniq { |f| f["url"] } + File.write(ARGV[2], merged.to_yaml) + ' "$x64" "$arm64" "release_assets/$name" + elif [ -f "$x64" ]; then + cp "$x64" "release_assets/$name" + elif [ -f "$arm64" ]; then + cp "$arm64" "release_assets/$name" + fi + } + + merge_mac_yml latest-mac.yml + merge_mac_yml beta-mac.yml + + if [ -z "$(ls -A release_assets)" ]; then + echo "Error: No release assets found" + exit 1 fi ls -la release_assets/ @@ -83,51 +413,12 @@ jobs: - name: Create Draft Release uses: softprops/action-gh-release@v1 with: - tag_name: v${{ steps.get_version.outputs.version }} + tag_name: ${{ needs.resolve-tag.outputs.tag }} name: DeepChat V${{ steps.get_version.outputs.version }} draft: true - prerelease: ${{ github.event.inputs.prerelease }} + prerelease: ${{ steps.get_version.outputs.prerelease == 'true' }} files: | release_assets/* - body: | - # 🚀 DeepChat ${{ steps.get_version.outputs.version }} 正式发布 | 重新定义你的 AI 对话体验! - —— 不再是简单的 ChatBot,而是你的自然语言 Agent 工具🌟 - - 🔥 为什么选择 DeepChat? - - ✅ **商业友好**:基于原版 [Apache License 2.0](https://github.com/ThinkInAIXYZ/deepchat/blob/main/LICENSE) 开源,无任何协议外的额外约束,面向开源。 - ✅ **开箱即用**:极简配置,即刻开启你的智能对话之旅。 - ✅ **极致灵活**:自由切换模型,自定义模型源,满足你多样化的对话和探索需求。 - ✅ **体验绝佳**:LaTeX 公式渲染、代码高亮、Markdown 支持,模型对话从未如此顺畅。 - ✅ **持续进化**:我们倾听用户反馈,不断迭代更新,为你带来更卓越的 AI 对话体验。 - - 📥 立即体验未来 - - 💬 反馈有礼:欢迎提交你的宝贵建议,加入 VIP 用户社群,与我们一同塑造 DeepChat 的未来! - - - 🎮 加入 Discord 社区:[https://discord.gg/6RBatENX](https://discord.gg/6RBatENX) - - --- - - # 🚀 DeepChat ${{ steps.get_version.outputs.version }} Official Release | Redefine Your AI Conversation Experience! - —— Not just a simple ChatBot, but your natural language Agent tool 🌟 - - 🔥 Why Choose DeepChat? - - ✅ **Business-Friendly**: Open source under [Apache License 2.0](https://github.com/ThinkInAIXYZ/deepchat/blob/main/LICENSE), with no additional constraints beyond the license, truly open source. - ✅ **Ready to Use**: Minimal configuration, start your intelligent conversation journey immediately. - ✅ **Ultra Flexible**: Freely switch models, customize model sources, meet your diverse conversation and exploration needs. - ✅ **Excellent Experience**: LaTeX formula rendering, code highlighting, Markdown support, model conversations have never been smoother. - ✅ **Continuous Evolution**: We listen to user feedback, continuously iterate and update, bringing you an even better AI conversation experience. - - 📥 Experience the Future Now - - 💬 Feedback Welcome: We welcome your valuable suggestions, join the user community, and shape the future of DeepChat together! - - - - 🎮 Join Discord Community: [https://discord.gg/6RBatENX](https://discord.gg/6RBatENX) - + body_path: release_notes.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..cc73e0d7c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,18 @@ +# Changelog + +## v0.5.6-beta.1 (2025-12-23) +- Markdown 优化,修复列表元素异常 +- 修复 Ollama 视觉模型图片格式 +- Improved Markdown rendering, fixed list element issues +- Fixed Ollama vision model image format + +## v0.5.5 (2025-12-19) +- 全新 Yo Browser 功能,让你的模型畅游网络 +- All-new Yo Browser lets your model roam the web + +## v0.5.3 (2025-12-13) +- 优化 ACP 体验,增加 ACP 调试能力 +- 增加了自定义软件字体能力 +- add acp process warmup and debug panel +- add font settings +- add Hebrew (he-IL) Translation diff --git a/docs/rebrand-guide.md b/docs/rebrand-guide.md index eb9f1bc2d..6ac09de52 100644 --- a/docs/rebrand-guide.md +++ b/docs/rebrand-guide.md @@ -86,7 +86,6 @@ This script will automatically replace brand information in the following files: - `package.json` - Package configuration - `electron-builder.yml` - Build configuration -- `electron-builder-macx64.yml` - macOS x64 build configuration - `src/main/index.ts` - Main process configuration - `src/main/presenter/upgradePresenter/index.ts` - Update service configuration - `src/renderer/src/i18n/*/about.json` - Internationalization files @@ -343,7 +342,6 @@ node scripts/rebrand.js - `package.json` - 包配置 - `electron-builder.yml` - 构建配置 -- `electron-builder-macx64.yml` - macOS x64 构建配置 - `src/main/index.ts` - 主进程配置 - `src/main/presenter/upgradePresenter/index.ts` - 更新服务配置 - `src/renderer/src/i18n/*/about.json` - 国际化文件 diff --git a/electron-builder-macx64.yml b/electron-builder-macx64.yml deleted file mode 100644 index beb6a7b84..000000000 --- a/electron-builder-macx64.yml +++ /dev/null @@ -1,83 +0,0 @@ -appId: com.wefonk.deepchat -productName: DeepChat -directories: - buildResources: build -files: - - '!**/.claude/*' - - '!**/.github/*' - - '!**/.cursor/*' - - '!**/.vscode/*' - - '!src/*' - - '!test/*' - - '!docs/*' - - '!electron.vite.config.{js,ts,mjs,cjs}' - - '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}' - - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}' - - '!{tsconfig.json,tsconfig.node.json,tsconfig.app.json}' - - '!keys/*' - - '!scripts/*' - - '!.github/*' - - '!electron-builder.yml' - - '!electron-builder-macx64.yml' - - '!test/*' - - '!*.config.ts' - - '!*.config.js' - - '!**/{LICENSE,LICENSE.txt,*.LICENSE.txt,NOTICE.txt,README.md,CHANGELOG.md,CONTRIBUTING.md,CONTRIBUTING.zh.md,README.zh.md,README.jp.md}' - - '!**/{.DS_Store,Thumbs.db}' - - '!*.md' -asarUnpack: - - '**/node_modules/sharp/**/*' - - '**/node_modules/@img/**/*' -extraResources: - - from: ./runtime/ - to: app.asar.unpacked/runtime - filter: ['**/*'] - - from: ./resources/cdn/ - to: app.asar.unpacked/resources/cdn - filter: ['**/*'] -afterSign: scripts/notarize.js -afterPack: scripts/afterPack.js -electronLanguages: - - zh-CN - - zh-TW - - zh-HK - - en-US - - ja-JP - - ko-KR - - fr-FR - - ru-RU - - ja - - ru - - zh_CN - - zh_TW - - zh_HK - - en - - ko - - fr - - fa-IR - - fa - - pt-BR - - pt - - da-DK - - da - - he-IL - - he -mac: - entitlementsInherit: build/entitlements.mac.plist - extendInfo: - - NSCameraUsageDescription: Application requests access to the device's camera. - - NSMicrophoneUsageDescription: Application requests access to the device's microphone. - - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder. - - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder. - gatekeeperAssess: false - category: public.app-category.utilities - target: - - target: dmg - arch: x64 - - target: zip - arch: x64 - artifactName: ${name}-${version}-mac-${arch}.${ext} -npmRebuild: true -publish: - provider: generic - url: https://cdn.deepchatai.cn/upgrade/ diff --git a/electron-builder.yml b/electron-builder.yml index 93c31acbb..3b2ace778 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -18,7 +18,6 @@ files: - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}' - '!{tsconfig.json,tsconfig.node.json,tsconfig.app.json}' - '!electron-builder.yml' - - '!electron-builder-macx64.yml' - '!test/*' - '!*.config.ts' - '!*.config.js' @@ -84,9 +83,7 @@ mac: category: public.app-category.utilities target: - target: dmg - arch: arm64 - target: zip - arch: arm64 artifactName: ${name}-${version}-mac-${arch}.${ext} linux: target: @@ -99,5 +96,6 @@ linux: - x-scheme-handler/deepchat npmRebuild: true publish: - provider: generic - url: https://cdn.deepchatai.cn/upgrade/ + provider: github + owner: ThinkInAIXYZ + repo: deepchat diff --git a/package.json b/package.json index e1bbee87f..dacadd5e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "DeepChat", - "version": "0.5.5", + "version": "0.5.6-beta.1", "description": "DeepChat,一个简单易用的AI客户端", "main": "./out/main/index.js", "author": "ThinkInAIXYZ", @@ -38,7 +38,7 @@ "install:sharp": "node scripts/install-sharp-for-platform.js", "build:mac": "pnpm run build && electron-builder --mac", "build:mac:arm64": "pnpm run build && electron-builder --mac --arm64", - "build:mac:x64": "pnpm run build && electron-builder -c electron-builder-macx64.yml --mac --x64 ", + "build:mac:x64": "pnpm run build && electron-builder --mac --x64", "build:linux": "pnpm run build && electron-builder --linux", "build:linux:x64": "pnpm run build && electron-builder --linux --x64", "build:linux:arm64": "pnpm run build && electron-builder --linux --arm64", diff --git a/scripts/rebrand.js b/scripts/rebrand.js index 797ce4984..1e1731c31 100644 --- a/scripts/rebrand.js +++ b/scripts/rebrand.js @@ -122,34 +122,6 @@ function updateElectronBuilder(config) { } } -// 更新 electron-builder-macx64.yml -function updateElectronBuilderMacX64(config) { - const builderPath = path.join(PROJECT_ROOT, 'electron-builder-macx64.yml') - - if (!fs.existsSync(builderPath)) { - return // 文件不存在则跳过 - } - - try { - let content = fs.readFileSync(builderPath, 'utf8') - - // 替换 appId - content = content.replace(/appId: .+/, `appId: ${config.app.appId}`) - - // 替换 productName - content = content.replace(/productName: .+/, `productName: ${config.app.productName}`) - - // 替换 publish URL - if (config.update && config.update.baseUrl) { - content = content.replace(/url: https:\/\/cdn\.deepchatai\.cn\/upgrade\//, `url: ${config.update.baseUrl}`) - } - - fs.writeFileSync(builderPath, content, 'utf8') - success('已更新 electron-builder-macx64.yml') - } catch (err) { - error(`更新 electron-builder-macx64.yml 失败: ${err.message}`) - } -} // 更新主进程中的 app user model ID function updateMainIndex(config) { @@ -480,7 +452,6 @@ function main() { // 执行替换 updatePackageJson(config) updateElectronBuilder(config) - updateElectronBuilderMacX64(config) updateMainIndex(config) updateUpgradePresenter(config) updateI18nFiles(config) diff --git a/src/main/presenter/configPresenter/index.ts b/src/main/presenter/configPresenter/index.ts index 86c03b1b6..25b329a98 100644 --- a/src/main/presenter/configPresenter/index.ts +++ b/src/main/presenter/configPresenter/index.ts @@ -73,7 +73,7 @@ interface IAppSettings { floatingButtonEnabled?: boolean // Whether floating button is enabled default_system_prompt?: string // Default system prompt webContentLengthLimit?: number // Web content truncation length limit, default 3000 characters - updateChannel?: string // Update channel: 'stable' | 'canary' + updateChannel?: string // Update channel: 'stable' | 'beta' fontFamily?: string // Custom UI font codeFontFamily?: string // Custom code font [key: string]: unknown // Allow arbitrary keys, using unknown type instead of any @@ -1475,7 +1475,12 @@ export class ConfigPresenter implements IConfigPresenter { // 获取更新渠道 getUpdateChannel(): string { - return this.getSetting('updateChannel') || 'stable' + const raw = this.getSetting('updateChannel') || 'stable' + const channel = raw === 'stable' || raw === 'beta' ? raw : 'beta' + if (channel !== raw) { + this.setSetting('updateChannel', channel) + } + return channel } // 设置更新渠道 diff --git a/src/main/presenter/upgradePresenter/index.ts b/src/main/presenter/upgradePresenter/index.ts index 9d9584eb1..737dc5a0e 100644 --- a/src/main/presenter/upgradePresenter/index.ts +++ b/src/main/presenter/upgradePresenter/index.ts @@ -8,13 +8,22 @@ import { import { eventBus, SendTarget } from '@/eventbus' import { UPDATE_EVENTS, WINDOW_EVENTS } from '@/events' import electronUpdater from 'electron-updater' -import axios from 'axios' -import { compare } from 'compare-versions' +import type { UpdateInfo } from 'electron-updater' import fs from 'fs' import path from 'path' const { autoUpdater } = electronUpdater +const GITHUB_OWNER = 'ThinkInAIXYZ' +const GITHUB_REPO = 'deepchat' +const UPDATE_CHANNEL_STABLE = 'stable' +const UPDATE_CHANNEL_BETA = 'beta' + +type ReleaseNoteItem = { + version?: string | null + note?: string | null +} + // 版本信息接口 interface VersionInfo { version: string @@ -24,26 +33,41 @@ interface VersionInfo { downloadUrl: string } -// 获取平台和架构信息 -const getPlatformInfo = () => { - const platform = process.platform - const arch = process.arch - let platformString = '' - - if (platform === 'win32') { - platformString = arch === 'arm64' ? 'winarm' : 'winx64' - } else if (platform === 'darwin') { - platformString = arch === 'arm64' ? 'macarm' : 'macx64' - } else if (platform === 'linux') { - platformString = arch === 'arm64' ? 'linuxarm' : 'linuxx64' - } +const normalizeUpdateChannel = (channel?: string): 'stable' | 'beta' => { + return channel === UPDATE_CHANNEL_BETA ? UPDATE_CHANNEL_BETA : UPDATE_CHANNEL_STABLE +} - return platformString +const formatTagVersion = (version: string): string => { + return version.startsWith('v') ? version : `v${version}` } -// 获取版本检查的基础URL -const getVersionCheckBaseUrl = () => { - return 'https://cdn.deepchatai.cn' +const buildReleaseUrl = (version: string): string => { + return `https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/releases/tag/${formatTagVersion(version)}` +} + +const formatReleaseNotes = (notes?: string | ReleaseNoteItem[] | null): string => { + if (!notes) return '' + if (typeof notes === 'string') return notes + if (!Array.isArray(notes)) return String(notes) + const blocks = notes + .map((note) => { + const title = note.version ? `## ${note.version}` : '' + const body = note.note ?? '' + return [title, body].filter(Boolean).join('\n') + }) + .filter((entry) => entry.length > 0) + return blocks.join('\n\n') +} + +const toVersionInfo = (info: UpdateInfo): VersionInfo => { + const releaseUrl = buildReleaseUrl(info.version) + return { + version: info.version, + releaseDate: info.releaseDate || '', + releaseNotes: formatReleaseNotes(info.releaseNotes), + githubUrl: releaseUrl, + downloadUrl: releaseUrl + } } // 获取自动更新状态文件路径 @@ -57,8 +81,8 @@ export class UpgradePresenter implements IUpgradePresenter { private _progress: UpdateProgress | null = null private _error: string | null = null private _versionInfo: VersionInfo | null = null - private _baseUrl: string private _lastCheckTime: number = 0 // 上次检查更新的时间戳 + private _lastCheckType?: string private _updateMarkerPath: string private _previousUpdateFailed: boolean = false // 标记上次更新是否失败 private _configPresenter: IConfigPresenter // 配置presenter @@ -66,7 +90,6 @@ export class UpgradePresenter implements IUpgradePresenter { constructor(configPresenter: IConfigPresenter) { this._configPresenter = configPresenter - this._baseUrl = getVersionCheckBaseUrl() this._updateMarkerPath = getUpdateMarkerFilePath() // 配置自动更新 @@ -98,18 +121,33 @@ export class UpgradePresenter implements IUpgradePresenter { this._lock = false this._status = 'not-available' eventBus.sendToRenderer(UPDATE_EVENTS.STATUS_CHANGED, SendTarget.ALL_WINDOWS, { - status: this._status + status: this._status, + type: this._lastCheckType }) }) // 有可用更新 autoUpdater.on('update-available', (info) => { console.log('检测到新版本', info) - this._status = 'available' + this._versionInfo = toVersionInfo(info) - // 重要:这里不再使用info中的信息更新this._versionInfo - // 而是确保使用之前从versionUrl获取的原始信息 - console.log('使用已保存的版本信息:', this._versionInfo) + if (this._previousUpdateFailed) { + console.log('上次更新失败,本次不进行自动更新,改为手动更新') + this._status = 'error' + this._error = '自动更新可能不稳定,请手动下载更新' + eventBus.sendToRenderer(UPDATE_EVENTS.STATUS_CHANGED, SendTarget.ALL_WINDOWS, { + status: this._status, + error: this._error, + info: this._versionInfo + }) + return + } + + this._status = 'available' + eventBus.sendToRenderer(UPDATE_EVENTS.STATUS_CHANGED, SendTarget.ALL_WINDOWS, { + status: this._status, + info: this._versionInfo + }) // 检测到更新后自动开始下载 this.startDownloadUpdate() }) @@ -137,6 +175,10 @@ export class UpgradePresenter implements IUpgradePresenter { this._lock = false this._status = 'downloaded' + if (!this._versionInfo) { + this._versionInfo = toVersionInfo(info) + } + // 写入更新标记文件 this.writeUpdateMarker(this._versionInfo?.version || info.version) @@ -250,83 +292,17 @@ export class UpgradePresenter implements IUpgradePresenter { try { this._status = 'checking' + this._lastCheckType = type eventBus.sendToRenderer(UPDATE_EVENTS.STATUS_CHANGED, SendTarget.ALL_WINDOWS, { status: this._status }) - // 首先获取版本信息文件 - const platformString = getPlatformInfo() - const rawChannel = this._configPresenter.getUpdateChannel() - const updateChannel = rawChannel === 'canary' ? 'canary' : 'upgrade' // Sanitize channel - const randomId = Math.floor(Date.now() / 3600000) // Timestamp truncated to hour - const versionPath = updateChannel - const versionUrl = `${this._baseUrl}/${versionPath}/${platformString}.json?noCache=${randomId}` - console.log('versionUrl', versionUrl) - const response = await axios.get(versionUrl, { timeout: 60000 }) // Add network timeout - const remoteVersion = response.data - const currentVersion = app.getVersion() - - // 保存完整的远程版本信息到内存中,作为唯一的标准信息源 - this._versionInfo = { - version: remoteVersion.version, - releaseDate: remoteVersion.releaseDate, - releaseNotes: remoteVersion.releaseNotes, - githubUrl: remoteVersion.githubUrl, - downloadUrl: remoteVersion.downloadUrl - } - - console.log('cache versionInfo:', this._versionInfo) + const updateChannel = normalizeUpdateChannel(this._configPresenter.getUpdateChannel()) + autoUpdater.allowPrerelease = updateChannel === UPDATE_CHANNEL_BETA + autoUpdater.channel = updateChannel === UPDATE_CHANNEL_BETA ? UPDATE_CHANNEL_BETA : 'latest' - // 更新上次检查时间 + await autoUpdater.checkForUpdates() this._lastCheckTime = Date.now() - - // 比较版本号 - if (compare(remoteVersion.version, currentVersion, '>')) { - // 有新版本 - - // 如果上次更新失败,这次不再尝试自动更新,直接进入错误状态让用户手动更新 - if (this._previousUpdateFailed) { - console.log('上次更新失败,本次不进行自动更新,改为手动更新') - this._status = 'error' - this._error = '自动更新可能不稳定,请手动下载更新' - - eventBus.sendToRenderer(UPDATE_EVENTS.STATUS_CHANGED, SendTarget.ALL_WINDOWS, { - status: this._status, - error: this._error, - info: this._versionInfo - }) - return - } - - // 设置自动更新的URL - const autoUpdateUrl = - updateChannel === 'canary' - ? `${this._baseUrl}/canary/${platformString}` - : `${this._baseUrl}/upgrade/v${remoteVersion.version}/${platformString}` - console.log('设置自动更新URL:', autoUpdateUrl) - autoUpdater.setFeedURL(autoUpdateUrl) - - try { - // 使用electron-updater检查更新,但不自动下载 - await autoUpdater.checkForUpdates() - } catch (err) { - console.error('自动更新检查失败,回退到手动更新', err) - // 如果自动更新失败,回退到手动更新 - this._status = 'available' - - eventBus.sendToRenderer(UPDATE_EVENTS.STATUS_CHANGED, SendTarget.ALL_WINDOWS, { - status: this._status, - info: this._versionInfo // 使用已保存的版本信息 - }) - } - } else { - // 没有新版本 - this._status = 'not-available' - eventBus.sendToRenderer(UPDATE_EVENTS.STATUS_CHANGED, SendTarget.ALL_WINDOWS, { - status: this._status, - type - }) - } } catch (error: Error | unknown) { this._status = 'error' this._error = error instanceof Error ? error.message : String(error) @@ -355,13 +331,14 @@ export class UpgradePresenter implements IUpgradePresenter { } async goDownloadUpgrade(type: 'github' | 'netdisk'): Promise { + const fallbackUrl = `https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/releases` if (type === 'github') { - const url = this._versionInfo?.githubUrl + const url = this._versionInfo?.githubUrl || fallbackUrl if (url) { shell.openExternal(url) } } else if (type === 'netdisk') { - const url = this._versionInfo?.downloadUrl + const url = this._versionInfo?.downloadUrl || fallbackUrl if (url) { shell.openExternal(url) } diff --git a/src/renderer/settings/components/AboutUsSettings.vue b/src/renderer/settings/components/AboutUsSettings.vue index 5d008ec8e..f88225443 100644 --- a/src/renderer/settings/components/AboutUsSettings.vue +++ b/src/renderer/settings/components/AboutUsSettings.vue @@ -57,8 +57,8 @@ {{ t('about.stableChannel') }} - - {{ t('about.canaryChannel') }} + + {{ t('about.betaChannel') }} diff --git a/src/renderer/src/i18n/da-DK/about.json b/src/renderer/src/i18n/da-DK/about.json index 3b15f1a33..b035590f7 100644 --- a/src/renderer/src/i18n/da-DK/about.json +++ b/src/renderer/src/i18n/da-DK/about.json @@ -1,5 +1,5 @@ { - "canaryChannel": "Intern testversion", + "betaChannel": "Beta", "checkUpdateButton": "Tjek for opdateringer", "description": "DeepChat er en tværplatform AI-klient, der har til formål at gøre det nemmere for flere mennesker at bruge AI.", "deviceInfo": { diff --git a/src/renderer/src/i18n/en-US/about.json b/src/renderer/src/i18n/en-US/about.json index c4a66a843..3a2ebc9aa 100644 --- a/src/renderer/src/i18n/en-US/about.json +++ b/src/renderer/src/i18n/en-US/about.json @@ -15,5 +15,5 @@ "checkUpdateButton": "Check for Updates", "updateChannel": "Update Channel", "stableChannel": "Stable", - "canaryChannel": "Canary" + "betaChannel": "Beta" } diff --git a/src/renderer/src/i18n/fa-IR/about.json b/src/renderer/src/i18n/fa-IR/about.json index 77b59e799..b3a7c107e 100644 --- a/src/renderer/src/i18n/fa-IR/about.json +++ b/src/renderer/src/i18n/fa-IR/about.json @@ -15,5 +15,5 @@ "checkUpdateButton": "بررسی به‌روزرسانی", "updateChannel": "کانال به‌روزرسانی", "stableChannel": "پایدار", - "canaryChannel": "کاناری" + "betaChannel": "Beta" } diff --git a/src/renderer/src/i18n/fr-FR/about.json b/src/renderer/src/i18n/fr-FR/about.json index c5d9af7d9..d77768bb0 100644 --- a/src/renderer/src/i18n/fr-FR/about.json +++ b/src/renderer/src/i18n/fr-FR/about.json @@ -15,5 +15,5 @@ "checkUpdateButton": "Vérifier les mises à jour", "updateChannel": "Canal de mise à jour", "stableChannel": "Stable", - "canaryChannel": "Canary" + "betaChannel": "Beta" } diff --git a/src/renderer/src/i18n/he-IL/about.json b/src/renderer/src/i18n/he-IL/about.json index 03e17c5bb..2626806ca 100644 --- a/src/renderer/src/i18n/he-IL/about.json +++ b/src/renderer/src/i18n/he-IL/about.json @@ -15,5 +15,5 @@ "checkUpdateButton": "בדוק עדכונים", "updateChannel": "ערוץ עדכון", "stableChannel": "יציב (Stable)", - "canaryChannel": "קנרית (Canary)" + "betaChannel": "Beta" } diff --git a/src/renderer/src/i18n/ja-JP/about.json b/src/renderer/src/i18n/ja-JP/about.json index e4ce28faa..da646cdc0 100644 --- a/src/renderer/src/i18n/ja-JP/about.json +++ b/src/renderer/src/i18n/ja-JP/about.json @@ -7,7 +7,7 @@ "checkUpdateButton": "アップデートを確認", "updateChannel": "アップデートチャンネル", "stableChannel": "安定版", - "canaryChannel": "テスト版", + "betaChannel": "Beta", "deviceInfo": { "title": "デバイス情報", "platform": "プラットフォーム", diff --git a/src/renderer/src/i18n/ko-KR/about.json b/src/renderer/src/i18n/ko-KR/about.json index 114506c81..ef1666753 100644 --- a/src/renderer/src/i18n/ko-KR/about.json +++ b/src/renderer/src/i18n/ko-KR/about.json @@ -7,7 +7,7 @@ "checkUpdateButton": "업데이트 확인", "updateChannel": "업데이트 채널", "stableChannel": "안정 버전", - "canaryChannel": "테스트 버전", + "betaChannel": "Beta", "deviceInfo": { "title": "장치 정보", "platform": "플랫폼", diff --git a/src/renderer/src/i18n/pt-BR/about.json b/src/renderer/src/i18n/pt-BR/about.json index e1e02d593..433bfc7a2 100644 --- a/src/renderer/src/i18n/pt-BR/about.json +++ b/src/renderer/src/i18n/pt-BR/about.json @@ -15,5 +15,5 @@ "checkUpdateButton": "Verificar Atualizações", "updateChannel": "Canal de Atualização", "stableChannel": "Estável", - "canaryChannel": "Canary" + "betaChannel": "Beta" } diff --git a/src/renderer/src/i18n/ru-RU/about.json b/src/renderer/src/i18n/ru-RU/about.json index 04db38aef..ac4af0d6d 100644 --- a/src/renderer/src/i18n/ru-RU/about.json +++ b/src/renderer/src/i18n/ru-RU/about.json @@ -7,7 +7,7 @@ "checkUpdateButton": "Проверить обновления", "updateChannel": "Канал обновлений", "stableChannel": "Стабильный", - "canaryChannel": "Канареечный", + "betaChannel": "Beta", "deviceInfo": { "title": "Сведения об устройстве", "platform": "Платформа", diff --git a/src/renderer/src/i18n/zh-CN/about.json b/src/renderer/src/i18n/zh-CN/about.json index 88f9bfc1d..092dc8273 100644 --- a/src/renderer/src/i18n/zh-CN/about.json +++ b/src/renderer/src/i18n/zh-CN/about.json @@ -7,7 +7,7 @@ "checkUpdateButton": "检查更新", "updateChannel": "更新渠道", "stableChannel": "正式版", - "canaryChannel": "内测版", + "betaChannel": "内测版", "deviceInfo": { "title": "设备信息", "platform": "平台", diff --git a/src/renderer/src/i18n/zh-HK/about.json b/src/renderer/src/i18n/zh-HK/about.json index 091bf17e5..317079238 100644 --- a/src/renderer/src/i18n/zh-HK/about.json +++ b/src/renderer/src/i18n/zh-HK/about.json @@ -7,7 +7,7 @@ "checkUpdateButton": "檢查更新", "updateChannel": "更新頻道", "stableChannel": "正式版", - "canaryChannel": "測試版", + "betaChannel": "内测版", "deviceInfo": { "title": "設備信息", "platform": "平台", diff --git a/src/renderer/src/i18n/zh-TW/about.json b/src/renderer/src/i18n/zh-TW/about.json index 80ccdb87e..515c09a40 100644 --- a/src/renderer/src/i18n/zh-TW/about.json +++ b/src/renderer/src/i18n/zh-TW/about.json @@ -7,7 +7,7 @@ "checkUpdateButton": "檢查更新", "updateChannel": "更新頻道", "stableChannel": "正式版", - "canaryChannel": "測試版", + "betaChannel": "内测版", "deviceInfo": { "title": "裝置資訊", "platform": "平台",