From 337fe21d18594270e59010d065a187bd4d22a65e Mon Sep 17 00:00:00 2001 From: fatfathao Date: Mon, 6 Apr 2026 01:40:06 +0800 Subject: [PATCH 1/7] =?UTF-8?q?fix:=20node25=E4=BD=BF=E7=94=A8pnpm?= =?UTF-8?q?=E6=8B=89=E5=8F=96=E6=96=87=E4=BB=B6=E6=97=B6=EF=BC=8Cajv?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E6=8B=89=E5=8F=96=E5=A4=B1=E8=B4=A5=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 28736e3..5361a0e 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,9 @@ "lodash": ">=4.17.21", "brace-expansion": ">=1.1.11", "picomatch": ">=2.3.1", - "ajv": ">=8.18.0" + "ajv": ">=8.18.0", + "ajv-keywords@3>ajv": "^6.12.6", + "@develar/schema-utils>ajv": "^6.12.6" } }, "build": { From 867f85e8f2cf9684b926215e47ee355d4522d058 Mon Sep 17 00:00:00 2001 From: ethan Date: Sun, 5 Apr 2026 17:28:08 -0400 Subject: [PATCH 2/7] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=20#580=20=E5=BC=95?= =?UTF-8?q?=E7=94=A8=E6=B6=88=E6=81=AF=E6=94=AF=E6=8C=81=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=BC=95=E7=94=A8=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- electron/services/chatService.ts | 81 ++++++++++++++++++++++++++++-- electron/services/exportService.ts | 74 ++++++++++++++++++++++++++- src/pages/ChatPage.tsx | 30 +++++++++-- 3 files changed, 174 insertions(+), 11 deletions(-) diff --git a/electron/services/chatService.ts b/electron/services/chatService.ts index bfeaf4a..270b4dc 100644 --- a/electron/services/chatService.ts +++ b/electron/services/chatService.ts @@ -4486,15 +4486,16 @@ class ChatService { */ private parseQuoteMessage(content: string): { content?: string; sender?: string } { try { + const normalizedContent = this.decodeHtmlEntities(content || '') // 提取 refermsg 部分 - const referMsgStart = content.indexOf('') - const referMsgEnd = content.indexOf('') + const referMsgStart = normalizedContent.indexOf('') + const referMsgEnd = normalizedContent.indexOf('') if (referMsgStart === -1 || referMsgEnd === -1) { return {} } - const referMsgXml = content.substring(referMsgStart, referMsgEnd + 11) + const referMsgXml = normalizedContent.substring(referMsgStart, referMsgEnd + 11) // 提取发送者名称 let displayName = this.extractXmlValue(referMsgXml, 'displayname') @@ -4511,8 +4512,8 @@ class ChatService { let displayContent = referContent switch (referType) { case '1': - // 文本消息,清理可能的 wxid - displayContent = this.sanitizeQuotedContent(referContent) + // 文本消息优先取“部分引用”字段,缺失时再回退到完整 content + displayContent = this.extractPreferredQuotedText(referMsgXml) break case '3': displayContent = '[图片]' @@ -4552,6 +4553,76 @@ class ChatService { } } + private extractPreferredQuotedText(referMsgXml: string): string { + if (!referMsgXml) return '' + + const sources = [this.decodeHtmlEntities(referMsgXml)] + const rawMsgSource = this.extractXmlValue(referMsgXml, 'msgsource') + if (rawMsgSource) { + const decodedMsgSource = this.decodeHtmlEntities(rawMsgSource) + if (decodedMsgSource) { + sources.push(decodedMsgSource) + } + } + + const fullContent = this.sanitizeQuotedContent(this.extractXmlValue(sources[0] || referMsgXml, 'content')) + const partialText = this.extractPartialQuotedText(sources[0] || referMsgXml, fullContent) + if (partialText) return partialText + + const candidateTags = [ + 'selectedcontent', + 'selectedtext', + 'selectcontent', + 'selecttext', + 'quotecontent', + 'quotetext', + 'partcontent', + 'parttext', + 'excerpt', + 'summary', + 'preview' + ] + + for (const source of sources) { + for (const tag of candidateTags) { + const value = this.sanitizeQuotedContent(this.extractXmlValue(source, tag)) + if (value) return value + } + } + + return fullContent + } + + private extractPartialQuotedText(xml: string, fullContent: string): string { + if (!xml || !fullContent) return '' + + const startChar = this.extractXmlValue(xml, 'start') + const endChar = this.extractXmlValue(xml, 'end') + const startIndexRaw = this.extractXmlValue(xml, 'startindex') + const endIndexRaw = this.extractXmlValue(xml, 'endindex') + const startIndex = Number.parseInt(startIndexRaw, 10) + const endIndex = Number.parseInt(endIndexRaw, 10) + + if (startChar && endChar) { + const startPos = fullContent.indexOf(startChar) + if (startPos !== -1) { + const endPos = fullContent.indexOf(endChar, startPos + startChar.length - 1) + if (endPos !== -1 && endPos >= startPos) { + const sliced = fullContent.slice(startPos, endPos + endChar.length).trim() + if (sliced) return sliced + } + } + } + + if (Number.isFinite(startIndex) && Number.isFinite(endIndex) && endIndex >= startIndex) { + const chars = Array.from(fullContent) + const sliced = chars.slice(startIndex, endIndex + 1).join('').trim() + if (sliced) return sliced + } + + return '' + } + /** * 解析名片消息 * 格式: diff --git a/electron/services/exportService.ts b/electron/services/exportService.ts index 95800b6..d03af2b 100644 --- a/electron/services/exportService.ts +++ b/electron/services/exportService.ts @@ -2254,7 +2254,7 @@ class ExportService { const referMsgXml = normalized.substring(referMsgStart, referMsgEnd + 11) const quoteInfo = this.parseQuoteMessage(normalized) const replyText = this.stripSenderPrefix(this.extractXmlValue(normalized, 'title') || '') - const quotedPreview = this.formatQuotedReferencePreview( + const quotedPreview = quoteInfo.content || this.formatQuotedReferencePreview( this.extractXmlValue(referMsgXml, 'content'), this.extractXmlValue(referMsgXml, 'type') ) @@ -2960,7 +2960,7 @@ class ExportService { switch (referType) { case '1': - displayContent = this.sanitizeQuotedContent(referContent) + displayContent = this.extractPreferredQuotedText(referMsgXml) break case '3': displayContent = '[图片]' @@ -3001,6 +3001,76 @@ class ExportService { } } + private extractPreferredQuotedText(referMsgXml: string): string { + if (!referMsgXml) return '' + + const sources = [this.decodeHtmlEntities(referMsgXml)] + const rawMsgSource = this.extractXmlValue(referMsgXml, 'msgsource') + if (rawMsgSource) { + const decodedMsgSource = this.decodeHtmlEntities(rawMsgSource) + if (decodedMsgSource) { + sources.push(decodedMsgSource) + } + } + + const fullContent = this.sanitizeQuotedContent(this.extractXmlValue(sources[0] || referMsgXml, 'content')) + const partialText = this.extractPartialQuotedText(sources[0] || referMsgXml, fullContent) + if (partialText) return partialText + + const candidateTags = [ + 'selectedcontent', + 'selectedtext', + 'selectcontent', + 'selecttext', + 'quotecontent', + 'quotetext', + 'partcontent', + 'parttext', + 'excerpt', + 'summary', + 'preview' + ] + + for (const source of sources) { + for (const tag of candidateTags) { + const value = this.sanitizeQuotedContent(this.extractXmlValue(source, tag)) + if (value) return value + } + } + + return fullContent + } + + private extractPartialQuotedText(xml: string, fullContent: string): string { + if (!xml || !fullContent) return '' + + const startChar = this.extractXmlValue(xml, 'start') + const endChar = this.extractXmlValue(xml, 'end') + const startIndexRaw = this.extractXmlValue(xml, 'startindex') + const endIndexRaw = this.extractXmlValue(xml, 'endindex') + const startIndex = Number.parseInt(startIndexRaw, 10) + const endIndex = Number.parseInt(endIndexRaw, 10) + + if (startChar && endChar) { + const startPos = fullContent.indexOf(startChar) + if (startPos !== -1) { + const endPos = fullContent.indexOf(endChar, startPos + startChar.length - 1) + if (endPos !== -1 && endPos >= startPos) { + const sliced = fullContent.slice(startPos, endPos + endChar.length).trim() + if (sliced) return sliced + } + } + } + + if (Number.isFinite(startIndex) && Number.isFinite(endIndex) && endIndex >= startIndex) { + const chars = Array.from(fullContent) + const sliced = chars.slice(startIndex, endIndex + 1).join('').trim() + if (sliced) return sliced + } + + return '' + } + private extractChatLabReplyToMessageId(content: string): string | undefined { try { const normalized = this.normalizeAppMessageContent(content || '') diff --git a/src/pages/ChatPage.tsx b/src/pages/ChatPage.tsx index 36b7cc1..5e86cc5 100644 --- a/src/pages/ChatPage.tsx +++ b/src/pages/ChatPage.tsx @@ -8695,6 +8695,28 @@ function MessageBubble({ appMsgTextCache.set(selector, value) return value }, [appMsgDoc, appMsgTextCache]) + const queryPreferredQuotedContent = useCallback((): string => { + if (message.quotedContent) return message.quotedContent + const candidates = [ + 'refermsg > selectedcontent', + 'refermsg > selectedtext', + 'refermsg > selectcontent', + 'refermsg > selecttext', + 'refermsg > quotecontent', + 'refermsg > quotetext', + 'refermsg > partcontent', + 'refermsg > parttext', + 'refermsg > excerpt', + 'refermsg > summary', + 'refermsg > preview', + 'refermsg > content' + ] + for (const selector of candidates) { + const value = queryAppMsgText(selector) + if (value) return value + } + return '' + }, [message.quotedContent, queryAppMsgText]) const appMsgThumbRawCandidate = useMemo(() => ( message.linkThumb || message.appMsgThumbUrl || @@ -8712,7 +8734,7 @@ function MessageBubble({ queryAppMsgText('refermsg > fromusr'), queryAppMsgText('refermsg > chatusr') ) - const quotedContent = message.quotedContent || queryAppMsgText('refermsg > content') || '' + const quotedContent = queryPreferredQuotedContent() const quotedSenderFallbackName = useMemo( () => resolveQuotedSenderFallbackDisplayName( session.username, @@ -9262,7 +9284,7 @@ function MessageBubble({ // type 57: 引用回复消息,解析 refermsg 渲染为引用样式 if (xmlType === '57') { const replyText = q('title') || cleanedParsedContent || '' - const referContent = q('refermsg > content') || '' + const referContent = queryPreferredQuotedContent() const referType = q('refermsg > type') || '' // 根据被引用消息类型渲染对应内容 @@ -9385,7 +9407,7 @@ function MessageBubble({ if (kind === 'quote') { // 引用回复消息(appMsgKind='quote',xmlType=57) const replyText = message.linkTitle || q('title') || cleanedParsedContent || '' - const referContent = message.quotedContent || q('refermsg > content') || '' + const referContent = queryPreferredQuotedContent() return ( renderBubbleWithQuote( renderQuotedMessageBlock(renderTextWithEmoji(cleanMessageContent(referContent))), @@ -9576,7 +9598,7 @@ function MessageBubble({ // 引用回复消息 (type=57),防止被误判为链接 if (appMsgType === '57') { const replyText = parsedDoc?.querySelector('title')?.textContent?.trim() || cleanedParsedContent || '' - const referContent = parsedDoc?.querySelector('refermsg > content')?.textContent?.trim() || '' + const referContent = queryPreferredQuotedContent() const referType = parsedDoc?.querySelector('refermsg > type')?.textContent?.trim() || '' const renderReferContent2 = () => { From b8bf29277afb88c0b51bf93108ab411560548aab Mon Sep 17 00:00:00 2001 From: ethan Date: Sun, 5 Apr 2026 17:48:12 -0400 Subject: [PATCH 3/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=8E=E9=83=A8?= =?UTF-8?q?=E5=88=86=E5=BC=95=E7=94=A8=E5=8A=9F=E8=83=BD=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E8=81=94=E7=9A=84=E6=97=A0=E6=B3=95=E8=AF=BB=E5=8F=96=E8=A7=A3?= =?UTF-8?q?=E5=AF=86=E9=85=8D=E7=BD=AE=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- electron/exportWorker.ts | 8 ++++++++ electron/main.ts | 6 ++++++ electron/services/config.ts | 11 +++++++++-- electron/services/exportService.ts | 11 ++++++++--- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/electron/exportWorker.ts b/electron/exportWorker.ts index 1f98439..dfa4ba3 100644 --- a/electron/exportWorker.ts +++ b/electron/exportWorker.ts @@ -5,6 +5,9 @@ interface ExportWorkerConfig { sessionIds: string[] outputDir: string options: ExportOptions + dbPath?: string + decryptKey?: string + myWxid?: string resourcesPath?: string userDataPath?: string logEnabled?: boolean @@ -29,6 +32,11 @@ async function run() { wcdbService.setPaths(config.resourcesPath || '', config.userDataPath || '') wcdbService.setLogEnabled(config.logEnabled === true) + exportService.setRuntimeConfig({ + dbPath: config.dbPath, + decryptKey: config.decryptKey, + myWxid: config.myWxid + }) const result = await exportService.exportSessions( Array.isArray(config.sessionIds) ? config.sessionIds : [], diff --git a/electron/main.ts b/electron/main.ts index ce578dc..6b692b4 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -2362,6 +2362,9 @@ function registerIpcHandlers() { const cfg = configService || new ConfigService() configService = cfg const logEnabled = cfg.get('logEnabled') + const dbPath = String(cfg.get('dbPath') || '').trim() + const decryptKey = String(cfg.get('decryptKey') || '').trim() + const myWxid = String(cfg.get('myWxid') || '').trim() const resourcesPath = app.isPackaged ? join(process.resourcesPath, 'resources') : join(app.getAppPath(), 'resources') @@ -2375,6 +2378,9 @@ function registerIpcHandlers() { sessionIds, outputDir, options, + dbPath, + decryptKey, + myWxid, resourcesPath, userDataPath, logEnabled diff --git a/electron/services/config.ts b/electron/services/config.ts index d65d93b..6fa0af8 100644 --- a/electron/services/config.ts +++ b/electron/services/config.ts @@ -5,6 +5,13 @@ import Store from 'electron-store' // 加密前缀标记 const SAFE_PREFIX = 'safe:' // safeStorage 加密(普通模式) +const isSafeStorageAvailable = (): boolean => { + try { + return typeof safeStorage?.isEncryptionAvailable === 'function' && safeStorage.isEncryptionAvailable() + } catch { + return false + } +} const LOCK_PREFIX = 'lock:' // 密码派生密钥加密(锁定模式) interface ConfigSchema { @@ -257,7 +264,7 @@ export class ConfigService { private safeEncrypt(plaintext: string): string { if (!plaintext) return '' if (plaintext.startsWith(SAFE_PREFIX)) return plaintext - if (!safeStorage.isEncryptionAvailable()) return plaintext + if (!isSafeStorageAvailable()) return plaintext const encrypted = safeStorage.encryptString(plaintext) return SAFE_PREFIX + encrypted.toString('base64') } @@ -265,7 +272,7 @@ export class ConfigService { private safeDecrypt(stored: string): string { if (!stored) return '' if (!stored.startsWith(SAFE_PREFIX)) return stored - if (!safeStorage.isEncryptionAvailable()) return '' + if (!isSafeStorageAvailable()) return '' try { const buf = Buffer.from(stored.slice(SAFE_PREFIX.length), 'base64') return safeStorage.decryptString(buf) diff --git a/electron/services/exportService.ts b/electron/services/exportService.ts index 95800b6..1f0dd0e 100644 --- a/electron/services/exportService.ts +++ b/electron/services/exportService.ts @@ -254,6 +254,7 @@ async function parallelLimit( class ExportService { private configService: ConfigService + private runtimeConfig: { dbPath?: string; decryptKey?: string; myWxid?: string } | null = null private contactCache: LRUCache private inlineEmojiCache: LRUCache private htmlStyleCache: string | null = null @@ -295,6 +296,10 @@ class ExportService { return error } + setRuntimeConfig(config: { dbPath?: string; decryptKey?: string; myWxid?: string } | null): void { + this.runtimeConfig = config + } + private normalizeSessionIds(sessionIds: string[]): string[] { return Array.from( new Set((sessionIds || []).map((id) => String(id || '').trim()).filter(Boolean)) @@ -1316,9 +1321,9 @@ class ExportService { } private async ensureConnected(): Promise<{ success: boolean; cleanedWxid?: string; error?: string }> { - const wxid = this.configService.get('myWxid') - const dbPath = this.configService.get('dbPath') - const decryptKey = this.configService.get('decryptKey') + const wxid = String(this.runtimeConfig?.myWxid || this.configService.get('myWxid') || '').trim() + const dbPath = String(this.runtimeConfig?.dbPath || this.configService.get('dbPath') || '').trim() + const decryptKey = String(this.runtimeConfig?.decryptKey || this.configService.get('decryptKey') || '').trim() if (!wxid) return { success: false, error: '请先在设置页面配置微信ID' } if (!dbPath) return { success: false, error: '请先在设置页面配置数据库路径' } if (!decryptKey) return { success: false, error: '请先在设置页面配置解密密钥' } From 3b26e0c0140e972232d8330c9149dcc3e45b5af4 Mon Sep 17 00:00:00 2001 From: cc <98377878+hicccc77@users.noreply.github.com> Date: Mon, 6 Apr 2026 12:15:50 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/dev-daily-fixed.yml | 31 +++++++++++++++++++-- .github/workflows/preview-nightly-main.yml | 32 ++++++++++++++++++++-- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dev-daily-fixed.yml b/.github/workflows/dev-daily-fixed.yml index 03bdc42..35e2950 100644 --- a/.github/workflows/dev-daily-fixed.yml +++ b/.github/workflows/dev-daily-fixed.yml @@ -6,6 +6,10 @@ on: - cron: "0 16 * * *" workflow_dispatch: +concurrency: + group: dev-daily-fixed-release + cancel-in-progress: false + permissions: contents: write @@ -278,7 +282,16 @@ jobs: exit 0 fi - ASSETS_JSON="$(gh release view "$TAG" --repo "$REPO" --json assets)" + RELEASE_JSON="$(gh release view "$TAG" --repo "$REPO" --json id,tagName,isDraft,isPrerelease,url,assets)" + RELEASE_ID="$(echo "$RELEASE_JSON" | jq -r '.id')" + RELEASE_TAG="$(echo "$RELEASE_JSON" | jq -r '.tagName')" + RELEASE_DRAFT="$(echo "$RELEASE_JSON" | jq -r '.isDraft')" + RELEASE_PRERELEASE="$(echo "$RELEASE_JSON" | jq -r '.isPrerelease')" + RELEASE_URL="$(echo "$RELEASE_JSON" | jq -r '.url')" + ASSETS_JSON="$(echo "$RELEASE_JSON" | jq -c '{assets: .assets}')" + + echo "Resolved release id=$RELEASE_ID tag=$RELEASE_TAG draft=$RELEASE_DRAFT prerelease=$RELEASE_PRERELEASE" + echo "Resolved release url=$RELEASE_URL" pick_asset() { local pattern="$1" @@ -327,4 +340,18 @@ jobs: - 如某个平台资源暂未生成,请进入[发布页]($RELEASE_PAGE)查看最新状态 EOF - gh release edit "$TAG" --repo "$REPO" --title "Daily Dev Build" --notes-file dev_release_notes.md + # Use release id to avoid tag resolution ambiguity, and force status to prerelease (not draft). + jq -n \ + --arg name "Daily Dev Build" \ + --arg body "$(cat dev_release_notes.md)" \ + '{name: $name, body: $body, draft: false, prerelease: true, make_latest: "false"}' \ + > release_patch_payload.json + + gh api \ + --method PATCH \ + -H "Accept: application/vnd.github+json" \ + "repos/$REPO/releases/$RELEASE_ID" \ + --input release_patch_payload.json >/dev/null + + FINAL_STATUS="$(gh release view "$TAG" --repo "$REPO" --json isDraft,isPrerelease,url)" + echo "Final release status: $(echo "$FINAL_STATUS" | jq -c '.')" diff --git a/.github/workflows/preview-nightly-main.yml b/.github/workflows/preview-nightly-main.yml index 186c7c0..1081ea8 100644 --- a/.github/workflows/preview-nightly-main.yml +++ b/.github/workflows/preview-nightly-main.yml @@ -6,6 +6,10 @@ on: - cron: "0 16 * * *" workflow_dispatch: +concurrency: + group: preview-nightly-fixed-release + cancel-in-progress: false + permissions: contents: write @@ -305,6 +309,7 @@ jobs: - name: Update preview release notes env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + FIXED_PREVIEW_TAG: ${{ env.FIXED_PREVIEW_TAG }} shell: bash run: | set -euo pipefail @@ -319,7 +324,16 @@ jobs: exit 0 fi - ASSETS_JSON="$(gh release view "$TAG" --repo "$REPO" --json assets)" + RELEASE_JSON="$(gh release view "$TAG" --repo "$REPO" --json id,tagName,isDraft,isPrerelease,url,assets)" + RELEASE_ID="$(echo "$RELEASE_JSON" | jq -r '.id')" + RELEASE_TAG="$(echo "$RELEASE_JSON" | jq -r '.tagName')" + RELEASE_DRAFT="$(echo "$RELEASE_JSON" | jq -r '.isDraft')" + RELEASE_PRERELEASE="$(echo "$RELEASE_JSON" | jq -r '.isPrerelease')" + RELEASE_URL="$(echo "$RELEASE_JSON" | jq -r '.url')" + ASSETS_JSON="$(echo "$RELEASE_JSON" | jq -c '{assets: .assets}')" + + echo "Resolved release id=$RELEASE_ID tag=$RELEASE_TAG draft=$RELEASE_DRAFT prerelease=$RELEASE_PRERELEASE" + echo "Resolved release url=$RELEASE_URL" pick_asset() { local pattern="$1" @@ -369,4 +383,18 @@ jobs: > 如某个平台链接暂未生成,请前往[发布页]($RELEASE_PAGE)查看最新资源 EOF - gh release edit "$TAG" --repo "$REPO" --notes-file preview_release_notes.md + # Use release id to avoid tag resolution ambiguity, and force status to prerelease (not draft). + jq -n \ + --arg name "Preview Nightly Build" \ + --arg body "$(cat preview_release_notes.md)" \ + '{name: $name, body: $body, draft: false, prerelease: true, make_latest: "false"}' \ + > release_patch_payload.json + + gh api \ + --method PATCH \ + -H "Accept: application/vnd.github+json" \ + "repos/$REPO/releases/$RELEASE_ID" \ + --input release_patch_payload.json >/dev/null + + FINAL_STATUS="$(gh release view "$TAG" --repo "$REPO" --json isDraft,isPrerelease,url)" + echo "Final release status: $(echo "$FINAL_STATUS" | jq -c '.')" From 92abe73f0a91e69657b85717f3ea002171798672 Mon Sep 17 00:00:00 2001 From: cc <98377878+hicccc77@users.noreply.github.com> Date: Mon, 6 Apr 2026 12:48:53 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/dev-daily-fixed.yml | 31 ++------------------- .github/workflows/preview-nightly-main.yml | 32 ++-------------------- 2 files changed, 4 insertions(+), 59 deletions(-) diff --git a/.github/workflows/dev-daily-fixed.yml b/.github/workflows/dev-daily-fixed.yml index 35e2950..756a7c1 100644 --- a/.github/workflows/dev-daily-fixed.yml +++ b/.github/workflows/dev-daily-fixed.yml @@ -6,10 +6,6 @@ on: - cron: "0 16 * * *" workflow_dispatch: -concurrency: - group: dev-daily-fixed-release - cancel-in-progress: false - permissions: contents: write @@ -282,16 +278,7 @@ jobs: exit 0 fi - RELEASE_JSON="$(gh release view "$TAG" --repo "$REPO" --json id,tagName,isDraft,isPrerelease,url,assets)" - RELEASE_ID="$(echo "$RELEASE_JSON" | jq -r '.id')" - RELEASE_TAG="$(echo "$RELEASE_JSON" | jq -r '.tagName')" - RELEASE_DRAFT="$(echo "$RELEASE_JSON" | jq -r '.isDraft')" - RELEASE_PRERELEASE="$(echo "$RELEASE_JSON" | jq -r '.isPrerelease')" - RELEASE_URL="$(echo "$RELEASE_JSON" | jq -r '.url')" - ASSETS_JSON="$(echo "$RELEASE_JSON" | jq -c '{assets: .assets}')" - - echo "Resolved release id=$RELEASE_ID tag=$RELEASE_TAG draft=$RELEASE_DRAFT prerelease=$RELEASE_PRERELEASE" - echo "Resolved release url=$RELEASE_URL" + ASSETS_JSON="$(gh release view "$TAG" --repo "$REPO" --json assets)" pick_asset() { local pattern="$1" @@ -340,18 +327,4 @@ jobs: - 如某个平台资源暂未生成,请进入[发布页]($RELEASE_PAGE)查看最新状态 EOF - # Use release id to avoid tag resolution ambiguity, and force status to prerelease (not draft). - jq -n \ - --arg name "Daily Dev Build" \ - --arg body "$(cat dev_release_notes.md)" \ - '{name: $name, body: $body, draft: false, prerelease: true, make_latest: "false"}' \ - > release_patch_payload.json - - gh api \ - --method PATCH \ - -H "Accept: application/vnd.github+json" \ - "repos/$REPO/releases/$RELEASE_ID" \ - --input release_patch_payload.json >/dev/null - - FINAL_STATUS="$(gh release view "$TAG" --repo "$REPO" --json isDraft,isPrerelease,url)" - echo "Final release status: $(echo "$FINAL_STATUS" | jq -c '.')" + gh release edit "$TAG" --repo "$REPO" --title "Daily Dev Build" --notes-file dev_release_notes.md --prerelease diff --git a/.github/workflows/preview-nightly-main.yml b/.github/workflows/preview-nightly-main.yml index 1081ea8..bf09256 100644 --- a/.github/workflows/preview-nightly-main.yml +++ b/.github/workflows/preview-nightly-main.yml @@ -6,10 +6,6 @@ on: - cron: "0 16 * * *" workflow_dispatch: -concurrency: - group: preview-nightly-fixed-release - cancel-in-progress: false - permissions: contents: write @@ -309,7 +305,6 @@ jobs: - name: Update preview release notes env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - FIXED_PREVIEW_TAG: ${{ env.FIXED_PREVIEW_TAG }} shell: bash run: | set -euo pipefail @@ -324,16 +319,7 @@ jobs: exit 0 fi - RELEASE_JSON="$(gh release view "$TAG" --repo "$REPO" --json id,tagName,isDraft,isPrerelease,url,assets)" - RELEASE_ID="$(echo "$RELEASE_JSON" | jq -r '.id')" - RELEASE_TAG="$(echo "$RELEASE_JSON" | jq -r '.tagName')" - RELEASE_DRAFT="$(echo "$RELEASE_JSON" | jq -r '.isDraft')" - RELEASE_PRERELEASE="$(echo "$RELEASE_JSON" | jq -r '.isPrerelease')" - RELEASE_URL="$(echo "$RELEASE_JSON" | jq -r '.url')" - ASSETS_JSON="$(echo "$RELEASE_JSON" | jq -c '{assets: .assets}')" - - echo "Resolved release id=$RELEASE_ID tag=$RELEASE_TAG draft=$RELEASE_DRAFT prerelease=$RELEASE_PRERELEASE" - echo "Resolved release url=$RELEASE_URL" + ASSETS_JSON="$(gh release view "$TAG" --repo "$REPO" --json assets)" pick_asset() { local pattern="$1" @@ -383,18 +369,4 @@ jobs: > 如某个平台链接暂未生成,请前往[发布页]($RELEASE_PAGE)查看最新资源 EOF - # Use release id to avoid tag resolution ambiguity, and force status to prerelease (not draft). - jq -n \ - --arg name "Preview Nightly Build" \ - --arg body "$(cat preview_release_notes.md)" \ - '{name: $name, body: $body, draft: false, prerelease: true, make_latest: "false"}' \ - > release_patch_payload.json - - gh api \ - --method PATCH \ - -H "Accept: application/vnd.github+json" \ - "repos/$REPO/releases/$RELEASE_ID" \ - --input release_patch_payload.json >/dev/null - - FINAL_STATUS="$(gh release view "$TAG" --repo "$REPO" --json isDraft,isPrerelease,url)" - echo "Final release status: $(echo "$FINAL_STATUS" | jq -c '.')" + gh release edit "$TAG" --repo "$REPO" --title "Preview Nightly Build" --notes-file preview_release_notes.md --prerelease From 4335abe31bf8dd99ae86f13994387b26afcf8631 Mon Sep 17 00:00:00 2001 From: cc <98377878+hicccc77@users.noreply.github.com> Date: Mon, 6 Apr 2026 13:08:32 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/dev-daily-fixed.yml | 5 +++++ .github/workflows/preview-nightly-main.yml | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/.github/workflows/dev-daily-fixed.yml b/.github/workflows/dev-daily-fixed.yml index 756a7c1..70fa798 100644 --- a/.github/workflows/dev-daily-fixed.yml +++ b/.github/workflows/dev-daily-fixed.yml @@ -55,6 +55,8 @@ jobs: gh release delete "$FIXED_DEV_TAG" --repo "$GITHUB_REPOSITORY" --yes --cleanup-tag fi gh release create "$FIXED_DEV_TAG" --repo "$GITHUB_REPOSITORY" --title "Daily Dev Build" --notes "开发版发布页" --prerelease --target "$TARGET_BRANCH" + RELEASE_REST_ID="$(gh api "repos/$GITHUB_REPOSITORY/releases/tags/$FIXED_DEV_TAG" --jq '.id')" + gh api --method PATCH "repos/$GITHUB_REPOSITORY/releases/$RELEASE_REST_ID" -f draft=false -f prerelease=true >/dev/null dev-mac-arm64: needs: prepare @@ -328,3 +330,6 @@ jobs: EOF gh release edit "$TAG" --repo "$REPO" --title "Daily Dev Build" --notes-file dev_release_notes.md --prerelease + RELEASE_REST_ID="$(gh api "repos/$REPO/releases/tags/$TAG" --jq '.id')" + gh api --method PATCH "repos/$REPO/releases/$RELEASE_REST_ID" -f draft=false -f prerelease=true >/dev/null + gh release view "$TAG" --repo "$REPO" --json isDraft,isPrerelease,url diff --git a/.github/workflows/preview-nightly-main.yml b/.github/workflows/preview-nightly-main.yml index bf09256..00d23a4 100644 --- a/.github/workflows/preview-nightly-main.yml +++ b/.github/workflows/preview-nightly-main.yml @@ -81,6 +81,8 @@ jobs: gh release delete "$FIXED_PREVIEW_TAG" --repo "$GITHUB_REPOSITORY" --yes --cleanup-tag fi gh release create "$FIXED_PREVIEW_TAG" --repo "$GITHUB_REPOSITORY" --title "Preview Nightly Build" --notes "预览版发布页" --prerelease --target "$TARGET_BRANCH" + RELEASE_REST_ID="$(gh api "repos/$GITHUB_REPOSITORY/releases/tags/$FIXED_PREVIEW_TAG" --jq '.id')" + gh api --method PATCH "repos/$GITHUB_REPOSITORY/releases/$RELEASE_REST_ID" -f draft=false -f prerelease=true >/dev/null preview-mac-arm64: needs: prepare @@ -370,3 +372,6 @@ jobs: EOF gh release edit "$TAG" --repo "$REPO" --title "Preview Nightly Build" --notes-file preview_release_notes.md --prerelease + RELEASE_REST_ID="$(gh api "repos/$REPO/releases/tags/$TAG" --jq '.id')" + gh api --method PATCH "repos/$REPO/releases/$RELEASE_REST_ID" -f draft=false -f prerelease=true >/dev/null + gh release view "$TAG" --repo "$REPO" --json isDraft,isPrerelease,url From 20c5381211eb32b0b7d131baf2a4c3b76ffd5d92 Mon Sep 17 00:00:00 2001 From: cc <98377878+hicccc77@users.noreply.github.com> Date: Mon, 6 Apr 2026 13:23:16 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/dev-daily-fixed.yml | 6 ++++-- .github/workflows/preview-nightly-main.yml | 6 ++++-- .gitignore | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/dev-daily-fixed.yml b/.github/workflows/dev-daily-fixed.yml index 70fa798..fb63aff 100644 --- a/.github/workflows/dev-daily-fixed.yml +++ b/.github/workflows/dev-daily-fixed.yml @@ -329,7 +329,9 @@ jobs: - 如某个平台资源暂未生成,请进入[发布页]($RELEASE_PAGE)查看最新状态 EOF - gh release edit "$TAG" --repo "$REPO" --title "Daily Dev Build" --notes-file dev_release_notes.md --prerelease RELEASE_REST_ID="$(gh api "repos/$REPO/releases/tags/$TAG" --jq '.id')" - gh api --method PATCH "repos/$REPO/releases/$RELEASE_REST_ID" -f draft=false -f prerelease=true >/dev/null + jq -n --rawfile body dev_release_notes.md \ + '{name:"Daily Dev Build", body:$body, draft:false, prerelease:true}' \ + > release_update_payload.json + gh api --method PATCH "repos/$REPO/releases/$RELEASE_REST_ID" --input release_update_payload.json >/dev/null gh release view "$TAG" --repo "$REPO" --json isDraft,isPrerelease,url diff --git a/.github/workflows/preview-nightly-main.yml b/.github/workflows/preview-nightly-main.yml index 00d23a4..751d227 100644 --- a/.github/workflows/preview-nightly-main.yml +++ b/.github/workflows/preview-nightly-main.yml @@ -371,7 +371,9 @@ jobs: > 如某个平台链接暂未生成,请前往[发布页]($RELEASE_PAGE)查看最新资源 EOF - gh release edit "$TAG" --repo "$REPO" --title "Preview Nightly Build" --notes-file preview_release_notes.md --prerelease RELEASE_REST_ID="$(gh api "repos/$REPO/releases/tags/$TAG" --jq '.id')" - gh api --method PATCH "repos/$REPO/releases/$RELEASE_REST_ID" -f draft=false -f prerelease=true >/dev/null + jq -n --rawfile body preview_release_notes.md \ + '{name:"Preview Nightly Build", body:$body, draft:false, prerelease:true}' \ + > release_update_payload.json + gh api --method PATCH "repos/$REPO/releases/$RELEASE_REST_ID" --input release_update_payload.json >/dev/null gh release view "$TAG" --repo "$REPO" --json isDraft,isPrerelease,url diff --git a/.gitignore b/.gitignore index 99f4414..ae6f9bf 100644 --- a/.gitignore +++ b/.gitignore @@ -72,4 +72,5 @@ pnpm-lock.yaml /pnpm-workspace.yaml wechat-research-site .codex -weflow-web-offical \ No newline at end of file +weflow-web-offical +Insight \ No newline at end of file