mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-28 15:07:55 +00:00
Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d537d81f1c | ||
|
|
26c6700152 | ||
|
|
49fb96d7a3 | ||
|
|
d256ee5696 | ||
|
|
bd70a7bfa8 | ||
|
|
3fb09bad0d | ||
|
|
06079659af | ||
|
|
22d8049c2c | ||
|
|
5f6b0e8960 | ||
|
|
9b8da7774d | ||
|
|
eabed55a7a | ||
|
|
32cc74f99c | ||
|
|
ffc4cc3d96 | ||
|
|
007cf57efd | ||
|
|
c6dba71197 | ||
|
|
8aa162e294 | ||
|
|
51d6dec7ff | ||
|
|
f1b2762769 | ||
|
|
d126be2aa5 | ||
|
|
ea034ee76a | ||
|
|
39634a690c | ||
|
|
a7001eb6da | ||
|
|
71e3540f18 | ||
|
|
78cadfd352 | ||
|
|
da15f829d3 | ||
|
|
bb60694013 | ||
|
|
b3758d2baf | ||
|
|
bc794e9a44 | ||
|
|
c80115d0f7 | ||
|
|
6277576249 | ||
|
|
2201d369fa | ||
|
|
9f4e4790f5 | ||
|
|
501e373e38 | ||
|
|
b2cf7c92d5 | ||
|
|
e92e13c045 | ||
|
|
f3dec958b0 | ||
|
|
0cf8ea8166 | ||
|
|
74b830dd79 | ||
|
|
8668c168a7 | ||
|
|
8b8c5f33ce | ||
|
|
2fcbb026df | ||
|
|
66ee72380d | ||
|
|
4f16345351 | ||
|
|
5110618996 | ||
|
|
bf51368cf4 | ||
|
|
d6054745d6 | ||
|
|
a4731f25f8 | ||
|
|
6c4507e495 | ||
|
|
cfa335564a | ||
|
|
61ef10de9b | ||
|
|
73f36d6b29 | ||
|
|
666a1a3296 | ||
|
|
b5a371da87 |
139
.github/workflows/release.yml
vendored
139
.github/workflows/release.yml
vendored
@@ -12,27 +12,8 @@ env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
|
||||
jobs:
|
||||
prepare-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Mark release as pre-release (building)
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
TAG="$GITHUB_REF_NAME"
|
||||
REPO="$GITHUB_REPOSITORY"
|
||||
# Create or update the release as a pre-release with a placeholder note
|
||||
if gh release view "$TAG" --repo "$REPO" > /dev/null 2>&1; then
|
||||
gh release edit "$TAG" --repo "$REPO" --prerelease --notes $'## ⚠️ 正在自动构建中,请勿下载\n\n各平台安装包正在构建,完成后将自动更新本页面并正式发布。\n\n**请勿在此期间下载任何文件。**'
|
||||
else
|
||||
gh release create "$TAG" --repo "$REPO" --prerelease --title "$TAG" --notes $'## ⚠️ 正在自动构建中,请勿下载\n\n各平台安装包正在构建,完成后将自动更新本页面并正式发布。\n\n**请勿在此期间下载任何文件。**'
|
||||
fi
|
||||
|
||||
release-mac-arm64:
|
||||
runs-on: macos-14
|
||||
needs: prepare-release
|
||||
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
@@ -68,9 +49,24 @@ jobs:
|
||||
run: |
|
||||
npx electron-builder --mac dmg --arm64 --publish always
|
||||
|
||||
- name: Inject minimumVersion into latest yml
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
TAG=${GITHUB_REF_NAME}
|
||||
REPO=${{ github.repository }}
|
||||
MINIMUM_VERSION="4.1.7"
|
||||
for YML_FILE in latest-mac.yml latest-arm64-mac.yml; do
|
||||
gh release download "$TAG" --repo "$REPO" --pattern "$YML_FILE" --output "/tmp/$YML_FILE" 2>/dev/null || continue
|
||||
if ! grep -q 'minimumVersion' "/tmp/$YML_FILE"; then
|
||||
echo "minimumVersion: $MINIMUM_VERSION" >> "/tmp/$YML_FILE"
|
||||
fi
|
||||
gh release upload "$TAG" --repo "$REPO" "/tmp/$YML_FILE" --clobber
|
||||
done
|
||||
|
||||
release-linux:
|
||||
runs-on: ubuntu-latest
|
||||
needs: prepare-release
|
||||
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
@@ -105,9 +101,22 @@ jobs:
|
||||
run: |
|
||||
npx electron-builder --linux --publish always
|
||||
|
||||
- name: Inject minimumVersion into latest yml
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
TAG=${GITHUB_REF_NAME}
|
||||
REPO=${{ github.repository }}
|
||||
MINIMUM_VERSION="4.1.7"
|
||||
gh release download "$TAG" --repo "$REPO" --pattern "latest-linux.yml" --output "/tmp/latest-linux.yml" 2>/dev/null
|
||||
if [ -f /tmp/latest-linux.yml ] && ! grep -q 'minimumVersion' /tmp/latest-linux.yml; then
|
||||
echo "minimumVersion: $MINIMUM_VERSION" >> /tmp/latest-linux.yml
|
||||
gh release upload "$TAG" --repo "$REPO" /tmp/latest-linux.yml --clobber
|
||||
fi
|
||||
|
||||
release:
|
||||
runs-on: windows-latest
|
||||
needs: prepare-release
|
||||
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
@@ -137,15 +146,27 @@ jobs:
|
||||
npx vite build
|
||||
|
||||
- name: Package and Publish
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
npx electron-builder --win nsis --x64 --publish always '--config.artifactName=${productName}-${version}-x64-Setup.${ext}'
|
||||
|
||||
- name: Inject minimumVersion into latest yml
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
npx electron-builder --win nsis --x64 --publish always "-c.artifactName=\${productName}-\${version}-x64-Setup.\${ext}"
|
||||
TAG=${GITHUB_REF_NAME}
|
||||
REPO=${{ github.repository }}
|
||||
MINIMUM_VERSION="4.1.7"
|
||||
gh release download "$TAG" --repo "$REPO" --pattern "latest.yml" --output "/tmp/latest.yml" 2>/dev/null
|
||||
if [ -f /tmp/latest.yml ] && ! grep -q 'minimumVersion' /tmp/latest.yml; then
|
||||
echo "minimumVersion: $MINIMUM_VERSION" >> /tmp/latest.yml
|
||||
gh release upload "$TAG" --repo "$REPO" /tmp/latest.yml --clobber
|
||||
fi
|
||||
|
||||
release-windows-arm64:
|
||||
runs-on: windows-latest
|
||||
needs: prepare-release
|
||||
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
@@ -175,11 +196,24 @@ jobs:
|
||||
npx vite build
|
||||
|
||||
- name: Package and Publish Windows arm64
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
npx electron-builder --win nsis --arm64 --publish always '--config.publish.channel=latest-arm64' '--config.artifactName=${productName}-${version}-arm64-Setup.${ext}'
|
||||
|
||||
- name: Inject minimumVersion into latest yml
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
npx electron-builder --win nsis --arm64 --publish always -c.publish.channel=latest-arm64 "-c.artifactName=\${productName}-\${version}-arm64-Setup.\${ext}"
|
||||
TAG=${GITHUB_REF_NAME}
|
||||
REPO=${{ github.repository }}
|
||||
MINIMUM_VERSION="4.1.7"
|
||||
gh release download "$TAG" --repo "$REPO" --pattern "latest-arm64.yml" --output "/tmp/latest-arm64.yml" 2>/dev/null
|
||||
if [ -f /tmp/latest-arm64.yml ] && ! grep -q 'minimumVersion' /tmp/latest-arm64.yml; then
|
||||
echo "minimumVersion: $MINIMUM_VERSION" >> /tmp/latest-arm64.yml
|
||||
gh release upload "$TAG" --repo "$REPO" /tmp/latest-arm64.yml --clobber
|
||||
fi
|
||||
|
||||
update-release-notes:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -190,53 +224,6 @@ jobs:
|
||||
- release-windows-arm64
|
||||
|
||||
steps:
|
||||
- name: Fix latest.yml to point to x64 installer
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
TAG="$GITHUB_REF_NAME"
|
||||
VERSION="${TAG#v}"
|
||||
REPO="$GITHUB_REPOSITORY"
|
||||
|
||||
# Find the x64 exe asset name
|
||||
ASSETS_JSON="$(gh release view "$TAG" --repo "$REPO" --json assets)"
|
||||
X64_ASSET="$(echo "$ASSETS_JSON" | jq -r '[.assets[].name | select(test("x64.*\\.exe$"))][0] // ""')"
|
||||
if [ -z "$X64_ASSET" ]; then
|
||||
X64_ASSET="$(echo "$ASSETS_JSON" | jq -r '[.assets[].name | select(test("\\.exe$")) | select(test("arm64") | not)][0] // ""')"
|
||||
fi
|
||||
|
||||
if [ -z "$X64_ASSET" ]; then
|
||||
echo "ERROR: Could not find x64 exe asset"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Downloading x64 installer: $X64_ASSET"
|
||||
gh release download "$TAG" --repo "$REPO" --pattern "$X64_ASSET" --dir /tmp/weflow-x64
|
||||
|
||||
SHA512_B64="$(sha512sum "/tmp/weflow-x64/$X64_ASSET" | awk '{print $1}' | xxd -r -p | base64 -w 0)"
|
||||
SIZE="$(stat -c%s "/tmp/weflow-x64/$X64_ASSET")"
|
||||
RELEASE_DATE="$(gh release view "$TAG" --repo "$REPO" --json publishedAt -q .publishedAt)"
|
||||
|
||||
cat > /tmp/latest.yml <<YMLEOF
|
||||
version: $VERSION
|
||||
files:
|
||||
- url: $X64_ASSET
|
||||
sha512: $SHA512_B64
|
||||
size: $SIZE
|
||||
path: $X64_ASSET
|
||||
sha512: $SHA512_B64
|
||||
releaseDate: '$RELEASE_DATE'
|
||||
YMLEOF
|
||||
|
||||
# Strip leading spaces (heredoc indentation)
|
||||
sed -i 's/^ //' /tmp/latest.yml
|
||||
cat /tmp/latest.yml
|
||||
|
||||
gh release upload "$TAG" --repo "$REPO" /tmp/latest.yml --clobber
|
||||
echo "latest.yml updated successfully to point to $X64_ASSET"
|
||||
|
||||
- name: Generate release notes with platform download links
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -294,18 +281,10 @@ jobs:
|
||||
## macOS 安装提示(未知来源)
|
||||
- 若打开时提示“来自未知开发者”或“无法验证开发者”,请到「系统设置 -> 隐私与安全性」中允许打开该应用。
|
||||
- 如果仍被系统拦截,请在终端执行以下命令去除隔离标记:
|
||||
- xattr -rd com.apple.quarantine /Applications/WeFlow.app
|
||||
- \`xattr -dr com.apple.quarantine "/Applications/WeFlow.app"\`
|
||||
- 执行后重新打开 WeFlow。
|
||||
|
||||
> 如果某个平台链接暂时未生成,可进入完整发布页查看全部资源:$RELEASE_PAGE
|
||||
EOF
|
||||
|
||||
gh release edit "$TAG" --repo "$REPO" --notes-file release_notes.md
|
||||
|
||||
- name: Mark release as published (no longer pre-release)
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
gh release edit "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --latest --no-fail-on-no-release --draft=false --prerelease=false
|
||||
|
||||
95
.github/workflows/security-scan.yml
vendored
Normal file
95
.github/workflows/security-scan.yml
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
name: Security Scan
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # 每天 UTC 02:00(北京时间 10:00)
|
||||
workflow_dispatch: # 支持手动触发
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
actions: read
|
||||
|
||||
jobs:
|
||||
security-scan:
|
||||
name: Security Scan (${{ matrix.branch }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch:
|
||||
- main
|
||||
|
||||
steps:
|
||||
- name: Checkout ${{ matrix.branch }}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ matrix.branch }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --no-frozen-lockfile
|
||||
|
||||
# 1. npm audit - 检查依赖漏洞
|
||||
- name: Dependency vulnerability audit
|
||||
run: pnpm audit --audit-level=moderate
|
||||
continue-on-error: true
|
||||
|
||||
# 2. CodeQL 静态分析
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: javascript, typescript
|
||||
queries: security-and-quality
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: '/language:javascript-typescript/branch:${{ matrix.branch }}'
|
||||
|
||||
# 3. 密钥/敏感信息扫描
|
||||
- name: Secret scanning with Gitleaks
|
||||
uses: gitleaks/gitleaks-action@v2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
continue-on-error: true
|
||||
|
||||
# 动态获取所有分支并扫描(排除已在 matrix 中的)
|
||||
scan-all-branches:
|
||||
name: Scan additional branches
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: List all branches
|
||||
id: branches
|
||||
run: |
|
||||
git branch -r | grep -v HEAD | sed 's|origin/||' | tr -d ' ' | while read branch; do
|
||||
echo "Branch: $branch"
|
||||
done
|
||||
|
||||
- name: Run pnpm audit on all branches
|
||||
run: |
|
||||
git branch -r | grep -v HEAD | sed 's|origin/||' | tr -d ' ' | while read branch; do
|
||||
echo "===== Auditing branch: $branch ====="
|
||||
git checkout "$branch" 2>/dev/null || continue
|
||||
pnpm install --frozen-lockfile --silent 2>/dev/null || npm install --silent 2>/dev/null || true
|
||||
pnpm audit --audit-level=moderate 2>/dev/null || true
|
||||
done
|
||||
continue-on-error: true
|
||||
23
.gitleaks.toml
Normal file
23
.gitleaks.toml
Normal file
@@ -0,0 +1,23 @@
|
||||
title = "Gitleaks Config"
|
||||
|
||||
[extend]
|
||||
# 继承默认规则
|
||||
useDefault = true
|
||||
|
||||
# 排除误报路径
|
||||
[[rules]]
|
||||
id = "curl-auth-header"
|
||||
[rules.allowlist]
|
||||
paths = [
|
||||
'''docs/HTTP-API\.md'''
|
||||
]
|
||||
regexes = [
|
||||
'''YOUR_TOKEN'''
|
||||
]
|
||||
|
||||
[[rules]]
|
||||
id = "generic-api-key"
|
||||
[rules.allowlist]
|
||||
paths = [
|
||||
'''src/pages/ChatPage\.tsx'''
|
||||
]
|
||||
@@ -19,7 +19,9 @@ WeFlow 是一个**完全本地**的微信**实时**聊天记录查看、分析
|
||||
</a>
|
||||
<a href="https://github.com/hicccc77/WeFlow/issues">
|
||||
<img src="https://img.shields.io/github/issues/hicccc77/WeFlow?style=flat-square" alt="Issues">
|
||||
<img src="https://gh-down-badges.linkof.link/hicccc77/WeFlow/" alt="Downloads" />
|
||||
</a>
|
||||
<a href="https://github.com/hicccc77/WeFlow/releases">
|
||||
<img src="https://img.shields.io/github/downloads/hicccc77/WeFlow/total?style=flat-square" alt="Downloads" />
|
||||
</a>
|
||||
<a href="https://t.me/weflow_cc">
|
||||
<img src="https://img.shields.io/badge/Telegram%20频道-0088cc?style=flat-square&logo=telegram&logoColor=0088cc&labelColor=white" alt="Telegram">
|
||||
|
||||
@@ -1242,7 +1242,8 @@ function registerIpcHandlers() {
|
||||
return {
|
||||
hasUpdate: true,
|
||||
version: latestVersion,
|
||||
releaseNotes: normalizeReleaseNotes(result.updateInfo.releaseNotes)
|
||||
releaseNotes: normalizeReleaseNotes(result.updateInfo.releaseNotes),
|
||||
minimumVersion: (result.updateInfo as any).minimumVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1300,7 +1301,7 @@ function registerIpcHandlers() {
|
||||
try {
|
||||
console.log('[Update] 开始下载更新...')
|
||||
await autoUpdater.downloadUpdate()
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('[Update] 下载更新失败:', error)
|
||||
// 失败时清理状态和监听器
|
||||
isDownloadInProgress = false
|
||||
@@ -1312,7 +1313,10 @@ function registerIpcHandlers() {
|
||||
autoUpdater.removeListener('update-downloaded', downloadedHandler)
|
||||
downloadedHandler = null
|
||||
}
|
||||
throw error
|
||||
|
||||
// 统一错误提示格式,避免出现 [object Object] 的 JSON 字符串
|
||||
const errorMessage = error.message || (typeof error === 'string' ? error : JSON.stringify(error))
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2636,19 +2640,19 @@ function registerIpcHandlers() {
|
||||
|
||||
// 密钥获取
|
||||
ipcMain.handle('key:autoGetDbKey', async (event) => {
|
||||
return keyService.autoGetDbKey(180_000, (message, level) => {
|
||||
return keyService.autoGetDbKey(180_000, (message: string, level: number) => {
|
||||
event.sender.send('key:dbKeyStatus', { message, level })
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.handle('key:autoGetImageKey', async (event, manualDir?: string, wxid?: string) => {
|
||||
return keyService.autoGetImageKey(manualDir, (message) => {
|
||||
return keyService.autoGetImageKey(manualDir, (message: string) => {
|
||||
event.sender.send('key:imageKeyStatus', { message })
|
||||
}, wxid)
|
||||
})
|
||||
|
||||
ipcMain.handle('key:scanImageKeyFromMemory', async (event, userDir: string) => {
|
||||
return keyService.autoGetImageKeyByMemoryScan(userDir, (message) => {
|
||||
return keyService.autoGetImageKeyByMemoryScan(userDir, (message: string) => {
|
||||
event.sender.send('key:imageKeyStatus', { message })
|
||||
})
|
||||
})
|
||||
@@ -2703,7 +2707,8 @@ function checkForUpdatesOnStartup() {
|
||||
// 通知渲染进程有新版本
|
||||
mainWindow.webContents.send('app:updateAvailable', {
|
||||
version: latestVersion,
|
||||
releaseNotes: normalizeReleaseNotes(result.updateInfo.releaseNotes)
|
||||
releaseNotes: normalizeReleaseNotes(result.updateInfo.releaseNotes),
|
||||
minimumVersion: (result.updateInfo as any).minimumVersion
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1135,7 +1135,7 @@ class AnnualReportService {
|
||||
|
||||
const now = Date.now()
|
||||
if (now - lastProgressAt > 200) {
|
||||
let progress = 30
|
||||
let progress: number
|
||||
if (totalMessagesForProgress > 0) {
|
||||
const ratio = Math.min(1, processedMessages / totalMessagesForProgress)
|
||||
progress = 30 + Math.floor(ratio * 50)
|
||||
|
||||
@@ -2009,7 +2009,7 @@ class ChatService {
|
||||
selectableColumns = resolvedColumns
|
||||
}
|
||||
|
||||
if (!selectableColumns || selectableColumns.length === 0) return rows
|
||||
if (selectableColumns.length === 0) return rows
|
||||
|
||||
const selectColumns = ['username', ...selectableColumns]
|
||||
const sql = `SELECT ${selectColumns.map((column) => this.quoteSqlIdentifier(column)).join(', ')} FROM contact WHERE username IS NOT NULL AND username != ''`
|
||||
|
||||
@@ -562,14 +562,14 @@ export class ImageDecryptService {
|
||||
if (allowThumbnail || !isThumb) {
|
||||
this.logInfo('[ImageDecrypt] hardlink hit (datName)', { imageMd5: imageDatName, path: preferredPath })
|
||||
this.cacheDatPath(accountDir, imageDatName, preferredPath)
|
||||
if (imageMd5) this.cacheDatPath(accountDir, imageMd5, preferredPath)
|
||||
this.cacheDatPath(accountDir, imageMd5, preferredPath)
|
||||
return preferredPath
|
||||
}
|
||||
// 找到缩略图但要求高清图,尝试同目录查找高清图变体
|
||||
const hdPath = this.findHdVariantInSameDir(preferredPath)
|
||||
if (hdPath) {
|
||||
this.cacheDatPath(accountDir, imageDatName, hdPath)
|
||||
if (imageMd5) this.cacheDatPath(accountDir, imageMd5, hdPath)
|
||||
this.cacheDatPath(accountDir, imageMd5, hdPath)
|
||||
return hdPath
|
||||
}
|
||||
return null
|
||||
|
||||
@@ -389,7 +389,7 @@ export class KeyServiceMac {
|
||||
`set timeoutSec to ${timeoutSec}`,
|
||||
'try',
|
||||
'with timeout of timeoutSec seconds',
|
||||
'set outText to do shell script cmd with administrator privileges',
|
||||
'set outText to do shell script (cmd & " 2>&1") with administrator privileges',
|
||||
'end timeout',
|
||||
'return "WF_OK::" & outText',
|
||||
'on error errMsg number errNum partial result pr',
|
||||
|
||||
1965
package-lock.json
generated
1965
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
24
package.json
24
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "weflow",
|
||||
"version": "2.1.0",
|
||||
"version": "4.3.0",
|
||||
"description": "WeFlow",
|
||||
"main": "dist-electron/main.js",
|
||||
"author": {
|
||||
@@ -38,7 +38,7 @@
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-router-dom": "^7.1.1",
|
||||
"react-router-dom": "^7.13.2",
|
||||
"react-virtuoso": "^4.18.1",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"sherpa-onnx-node": "^1.10.38",
|
||||
@@ -53,7 +53,7 @@
|
||||
"@types/react-dom": "^19.1.0",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"electron": "^39.2.7",
|
||||
"electron-builder": "^25.1.8",
|
||||
"electron-builder": "^26.8.1",
|
||||
"sass": "^1.83.0",
|
||||
"sharp": "^0.34.5",
|
||||
"typescript": "^5.6.3",
|
||||
@@ -61,6 +61,18 @@
|
||||
"vite-plugin-electron": "^0.28.8",
|
||||
"vite-plugin-electron-renderer": "^0.14.6"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"tar": ">=6.2.1",
|
||||
"minimatch": ">=3.1.2",
|
||||
"rollup": ">=4.0.0",
|
||||
"immutable": ">=4.0.0",
|
||||
"lodash": ">=4.17.21",
|
||||
"brace-expansion": ">=1.1.11",
|
||||
"picomatch": ">=2.3.1",
|
||||
"ajv": ">=8.18.0"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"appId": "com.WeFlow.app",
|
||||
"publish": {
|
||||
@@ -177,5 +189,11 @@
|
||||
}
|
||||
],
|
||||
"icon": "resources/icon.icns"
|
||||
},
|
||||
"overrides": {
|
||||
"picomatch": "^4.0.4",
|
||||
"tar": "^7.5.13",
|
||||
"immutable": "^5.1.5",
|
||||
"ajv": ">=6.14.0"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
public/icon.ico
BIN
public/icon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 212 KiB After Width: | Height: | Size: 364 KiB |
BIN
public/icon.png
BIN
public/icon.png
Binary file not shown.
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 570 KiB |
BIN
public/logo.png
BIN
public/logo.png
Binary file not shown.
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 570 KiB |
Binary file not shown.
Binary file not shown.
BIN
resources/libwcdb_api.so
Executable file
BIN
resources/libwcdb_api.so
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
resources/wcdb_api_arm64.dll
Normal file
BIN
resources/wcdb_api_arm64.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
resources/xkey_helper_macos
Normal file
BIN
resources/xkey_helper_macos
Normal file
Binary file not shown.
15
src/App.tsx
15
src/App.tsx
@@ -312,10 +312,14 @@ function App() {
|
||||
const removeUpdateListener = window.electronAPI?.app?.onUpdateAvailable?.((info: any) => {
|
||||
// 发现新版本时保存更新信息,锁定状态下不弹窗,解锁后再显示
|
||||
if (info) {
|
||||
setUpdateInfo({ ...info, hasUpdate: true })
|
||||
if (!useAppStore.getState().isLocked) {
|
||||
setShowUpdateDialog(true)
|
||||
}
|
||||
window.electronAPI.app.getVersion().then((currentVersion: string) => {
|
||||
const isMandatory = !!(info.minimumVersion && currentVersion &&
|
||||
currentVersion.localeCompare(info.minimumVersion, undefined, { numeric: true, sensitivity: 'base' }) <= 0)
|
||||
setUpdateInfo({ ...info, hasUpdate: true, isMandatory })
|
||||
if (!useAppStore.getState().isLocked) {
|
||||
setShowUpdateDialog(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
const removeProgressListener = window.electronAPI?.app?.onDownloadProgress?.((progress: any) => {
|
||||
@@ -685,10 +689,11 @@ function App() {
|
||||
<UpdateDialog
|
||||
open={showUpdateDialog}
|
||||
updateInfo={updateInfo}
|
||||
onClose={() => setShowUpdateDialog(false)}
|
||||
onClose={() => { if (!(updateInfo as any)?.isMandatory) setShowUpdateDialog(false) }}
|
||||
onUpdate={handleUpdateNow}
|
||||
onIgnore={handleIgnoreUpdate}
|
||||
isDownloading={isDownloading}
|
||||
isMandatory={!!(updateInfo as any)?.isMandatory}
|
||||
progress={downloadProgress}
|
||||
/>
|
||||
|
||||
|
||||
@@ -282,4 +282,13 @@
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.mandatory-tip {
|
||||
color: #e53e3e;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
margin: 0 0 8px;
|
||||
padding: 6px 12px;
|
||||
background: rgba(229, 62, 62, 0.08);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ interface UpdateDialogProps {
|
||||
onUpdate: () => void
|
||||
onIgnore?: () => void
|
||||
isDownloading: boolean
|
||||
isMandatory?: boolean
|
||||
progress: number | {
|
||||
percent: number
|
||||
bytesPerSecond?: number
|
||||
@@ -30,6 +31,7 @@ const UpdateDialog: React.FC<UpdateDialogProps> = ({
|
||||
onUpdate,
|
||||
onIgnore,
|
||||
isDownloading,
|
||||
isMandatory,
|
||||
progress
|
||||
}) => {
|
||||
if (!open || !updateInfo) return null
|
||||
@@ -69,7 +71,7 @@ const UpdateDialog: React.FC<UpdateDialogProps> = ({
|
||||
return (
|
||||
<div className="update-dialog-overlay">
|
||||
<div className="update-dialog">
|
||||
{!isDownloading && (
|
||||
{!isDownloading && !isMandatory && (
|
||||
<button className="close-btn" onClick={onClose}>
|
||||
<X size={20} />
|
||||
</button>
|
||||
@@ -119,11 +121,14 @@ const UpdateDialog: React.FC<UpdateDialogProps> = ({
|
||||
</div>
|
||||
) : (
|
||||
<div className="actions">
|
||||
{onIgnore && (
|
||||
{onIgnore && !isMandatory && (
|
||||
<button className="btn-ignore" onClick={onIgnore}>
|
||||
忽略本次更新
|
||||
</button>
|
||||
)}
|
||||
{isMandatory && (
|
||||
<p className="mandatory-tip">此版本存在安全风险,必须更新后才能继续使用</p>
|
||||
)}
|
||||
<button className="btn-update" onClick={onUpdate}>
|
||||
开启新旅程
|
||||
</button>
|
||||
|
||||
@@ -3227,7 +3227,7 @@ function ChatPage(props: ChatPageProps) {
|
||||
const session = sessionMapRef.current.get(sessionId)
|
||||
const unreadCount = session?.unreadCount ?? 0
|
||||
|
||||
let messageLimit = currentBatchSizeRef.current
|
||||
let messageLimit: number
|
||||
|
||||
if (offset === 0) {
|
||||
const preferredLimit = Number.isFinite(options.forceInitialLimit)
|
||||
@@ -7901,7 +7901,7 @@ function MessageBubble({
|
||||
useEffect(() => {
|
||||
if (emojiLocalPath) return
|
||||
// 后端已从本地缓存找到文件(转发表情包无 CDN URL 的情况)
|
||||
if (isEmoji && message.emojiLocalPath && !emojiLocalPath) {
|
||||
if (isEmoji && message.emojiLocalPath) {
|
||||
captureEmojiResizeBaseline()
|
||||
setEmojiLocalPath(message.emojiLocalPath)
|
||||
return
|
||||
|
||||
BIN
temp_assets.json
Normal file
BIN
temp_assets.json
Normal file
Binary file not shown.
Reference in New Issue
Block a user