diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 460b86d..554882c 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -2,8 +2,10 @@ name: 构建并发布 Docker 镜像 on: push: - tags: - - 'v*.*.*' # 匹配 v1.0.0, v2.1.3 等版本号格式 + branches: + - main + paths: + - 'VERSION' # 仅当 VERSION 文件变更时触发 env: REGISTRY: docker.io @@ -13,12 +15,42 @@ jobs: build-and-push: runs-on: ubuntu-latest permissions: - contents: read + contents: write # 需要写权限来创建 tag packages: write steps: - name: 检出代码 uses: actions/checkout@v4 + with: + fetch-depth: 0 # 获取完整历史以便创建 tag + + - name: 读取版本号 + id: version + run: | + VERSION=$(cat VERSION | tr -d '\n\r ') + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "tag=v$VERSION" >> $GITHUB_OUTPUT + echo "读取到版本号: $VERSION" + + - name: 检查 tag 是否已存在 + id: check_tag + run: | + if git rev-parse "v${{ steps.version.outputs.version }}" >/dev/null 2>&1; then + echo "exists=true" >> $GITHUB_OUTPUT + echo "Tag v${{ steps.version.outputs.version }} 已存在" + else + echo "exists=false" >> $GITHUB_OUTPUT + echo "Tag v${{ steps.version.outputs.version }} 不存在,将创建新 tag" + fi + + - name: 创建 Git Tag + if: steps.check_tag.outputs.exists == 'false' + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "v${{ steps.version.outputs.version }}" -m "Release v${{ steps.version.outputs.version }}" + git push origin "v${{ steps.version.outputs.version }}" + echo "已创建并推送 tag: v${{ steps.version.outputs.version }}" - name: 设置 Docker Buildx uses: docker/setup-buildx-action@v3 @@ -35,10 +67,8 @@ jobs: with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - type=raw,value=latest,enable={{is_default_branch}} + type=raw,value=${{ steps.version.outputs.version }} + type=raw,value=latest - name: 构建并推送 Docker 镜像 uses: docker/build-push-action@v5 @@ -56,7 +86,8 @@ jobs: run: | echo "## Docker 镜像构建成功 :rocket:" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "**版本标签:** ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY + echo "**版本号:** ${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "**Git Tag:** ${{ steps.version.outputs.tag }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**镜像标签:**" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..b539ade --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +2.2.7 \ No newline at end of file diff --git a/src/ui-manager.js b/src/ui-manager.js index 4ec0f1c..e2a675f 100644 --- a/src/ui-manager.js +++ b/src/ui-manager.js @@ -758,8 +758,21 @@ export async function handleUIApiRequests(method, pathParam, req, res, currentCo // Get system information if (method === 'GET' && pathParam === '/api/system') { const memUsage = process.memoryUsage(); + + // 读取版本号 + let appVersion = 'unknown'; + try { + const versionFilePath = path.join(process.cwd(), 'VERSION'); + if (existsSync(versionFilePath)) { + appVersion = readFileSync(versionFilePath, 'utf8').trim(); + } + } catch (error) { + console.warn('[UI API] Failed to read VERSION file:', error.message); + } + res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ + appVersion: appVersion, nodeVersion: process.version, serverTime: new Date().toLocaleString(), memoryUsage: `${Math.round(memUsage.heapUsed / 1024 / 1024)} MB / ${Math.round(memUsage.heapTotal / 1024 / 1024)} MB`, diff --git a/static/app/i18n.js b/static/app/i18n.js index 6afdd2b..90c73fc 100644 --- a/static/app/i18n.js +++ b/static/app/i18n.js @@ -22,6 +22,7 @@ const translations = { 'dashboard.title': '系统概览', 'dashboard.uptime': '运行时间', 'dashboard.systemInfo': '系统信息', + 'dashboard.version': '版本号', 'dashboard.nodeVersion': 'Node.js版本', 'dashboard.serverTime': '服务器时间', 'dashboard.memoryUsage': '内存使用', @@ -60,6 +61,8 @@ const translations = { // OAuth 'oauth.modal.title': 'OAuth 授权', 'oauth.modal.provider': '提供商:', + 'oauth.modal.requiredPort': '需要开放端口:', + 'oauth.modal.portNote': '请确保此端口可被外部访问,用于接收授权回调', 'oauth.modal.steps': '授权步骤:', 'oauth.modal.step1': '点击下方按钮在浏览器中打开授权页面', 'oauth.modal.step2.qwen': '完成授权后,系统会自动获取凭据文件', @@ -391,6 +394,7 @@ const translations = { 'dashboard.title': 'System Overview', 'dashboard.uptime': 'Uptime', 'dashboard.systemInfo': 'System Information', + 'dashboard.version': 'Version', 'dashboard.nodeVersion': 'Node.js Version', 'dashboard.serverTime': 'Server Time', 'dashboard.memoryUsage': 'Memory Usage', @@ -429,6 +433,8 @@ const translations = { // OAuth 'oauth.modal.title': 'OAuth Authorization', 'oauth.modal.provider': 'Provider:', + 'oauth.modal.requiredPort': 'Required Port:', + 'oauth.modal.portNote': 'Please ensure this port is accessible externally for receiving authorization callbacks', 'oauth.modal.steps': 'Authorization Steps:', 'oauth.modal.step1': 'Click the button below to open the authorization page in your browser', 'oauth.modal.step2.qwen': 'After authorization, the system will automatically fetch the credentials file', diff --git a/static/app/provider-manager.js b/static/app/provider-manager.js index be91a46..928d716 100644 --- a/static/app/provider-manager.js +++ b/static/app/provider-manager.js @@ -18,11 +18,13 @@ async function loadSystemInfo() { try { const data = await window.apiClient.get('/system'); + const appVersionEl = document.getElementById('appVersion'); const nodeVersionEl = document.getElementById('nodeVersion'); const serverTimeEl = document.getElementById('serverTime'); const memoryUsageEl = document.getElementById('memoryUsage'); const uptimeEl = document.getElementById('uptime'); + if (appVersionEl) appVersionEl.textContent = data.appVersion ? `v${data.appVersion}` : '--'; if (nodeVersionEl) nodeVersionEl.textContent = data.nodeVersion || '--'; if (memoryUsageEl) memoryUsageEl.textContent = data.memoryUsage || '--'; @@ -488,6 +490,9 @@ function showAuthModal(authUrl, authInfo) { // 获取授权文件路径 const authFilePath = getAuthFilePath(authInfo.provider); + // 获取需要开放的端口号(从 authInfo 或当前页面 URL) + const requiredPort = authInfo.callbackPort || authInfo.port || window.location.port || '3000'; + let instructionsHtml = ''; if (authInfo.provider === 'openai-qwen-oauth') { instructionsHtml = ` @@ -539,6 +544,14 @@ function showAuthModal(authUrl, authInfo) {
${t('oauth.modal.provider')} ${authInfo.provider}
+
+
+ ${t('oauth.modal.requiredPort')}
+ ${requiredPort}
+
${t('oauth.modal.portNote')}
+