mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-02-09 14:30:26 +00:00
Compare commits
4 Commits
v4.10.3
...
test-pr-is
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20f6101f95 | ||
|
|
018e8aa4f0 | ||
|
|
1ad700b935 | ||
|
|
68c8b984ad |
31
.github/prompt/default.md
vendored
31
.github/prompt/default.md
vendored
@@ -1,27 +1,18 @@
|
||||
# V?.?.?
|
||||
# {VERSION}
|
||||
[使用文档](https://napneko.github.io/)
|
||||
|
||||
## Windows 一键包
|
||||
我们为提供了的轻量化一键部署方案
|
||||
相对于普通需要安装QQ的方案,下面已内置QQ和Napcat 阅读使用文档参考
|
||||
我们提供了轻量化一键部署方案,内置 QQ 和 NapCat,详见使用文档。
|
||||
|
||||
你可以下载
|
||||
可下载文件:
|
||||
- NapCat.Shell.Windows.Node.zip(无头模式)
|
||||
|
||||
NapCat.Shell.Windows.OneKey.zip (无头)
|
||||
## 注意事项
|
||||
**推荐 QQ 版本:9.9.23+,最低支持 9.9.22**
|
||||
**默认 WebUI 密钥为随机密码,请在控制台查看**
|
||||
|
||||
启动后可自动化部署一键包,教程参考使用文档安装部分
|
||||
## 运行库
|
||||
如果 Windows x64 缺少 xxx.dll,请安装 [VC++ 运行库](https://aka.ms/vs/17/release/vc_redist.x64.exe)
|
||||
|
||||
## 警告
|
||||
**注意QQ版本推荐使用 40768+ 版本 最低可以使用40768版本**
|
||||
**默认WebUi密钥为随机密码 控制台查看**
|
||||
|
||||
**[9.9.22-40990 X64 Win](https://dldir1v6.qq.com/qqfile/qq/QQNT/2c9d3f6c/QQ9.9.22.40990_x64.exe)**
|
||||
[LinuxX64 DEB 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_amd64.deb)
|
||||
[LinuxX64 RPM 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_x86_64.rpm)
|
||||
[LinuxArm64 DEB 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_arm64.deb)
|
||||
[LinuxArm64 RPM 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_aarch64.rpm)
|
||||
[MAC DMG 40990 ](https://dldir1v6.qq.com/qqfile/qq/QQNT/c6cb0f5d/QQ_v6.9.82.40990.dmg)
|
||||
## 如果WinX64缺少运行库或者xxx.dll?
|
||||
[安装运行库](https://aka.ms/vs/17/release/vc_redist.x64.exe)
|
||||
|
||||
## 更新
|
||||
## 更新内容
|
||||
详见 commit 历史。
|
||||
118
.github/prompt/release_note_prompt.txt
vendored
118
.github/prompt/release_note_prompt.txt
vendored
@@ -1,60 +1,94 @@
|
||||
注意:输出必须严格使用 NapCat 的发布说明格式,严格保证示例格式,并用简体中文。
|
||||
# NapCat Release Note Generator
|
||||
|
||||
格式规则:
|
||||
1. 第一行:# V{TAG}
|
||||
2. 第二行:[使用文档](https://napneko.github.io/)
|
||||
3. 空行后,按下面的节顺序输出(存在则输出,不存在则省略该节):
|
||||
你是 NapCat 项目的发布说明生成器。请根据提供的 commit 列表生成标准格式的发布说明。
|
||||
|
||||
## Windows 一键包
|
||||
- 简短一句话介绍一键包用途
|
||||
- 列出可下载的文件名(只列文件名,不写下载链接)
|
||||
## 核心规则
|
||||
|
||||
## 警告
|
||||
- 如果有需要特别提醒的兼容/运行库/版本要求,写成加粗警告句
|
||||
1. **版本号**:第一行必须是 `# {VERSION}`,使用用户提供的版本号(如 v4.10.2),不要添加额外的 V 前缀
|
||||
2. **语言**:全部使用简体中文
|
||||
3. **格式**:严格按照下方模板输出,不要添加额外的 markdown 格式
|
||||
|
||||
## 如果WinX64缺少运行库或者xxx.dll?
|
||||
- 常见运行库建议
|
||||
## Commit 分析规则
|
||||
|
||||
## 更新
|
||||
按数字序列列出主要变更项,每条尽量一句话
|
||||
- 前缀短 commit id,例如:1. 修复 get_essence_msg_list 崩溃 (a1b2c3d)
|
||||
- 保持 4-18 条要点
|
||||
将 commit 分类为以下类型:
|
||||
- 🐛 **修复**:bug fix、修复、fix 相关
|
||||
- ✨ **新增**:新功能、feat、add 相关
|
||||
- 🔧 **优化**:优化、重构、refactor、improve、perf 相关
|
||||
- 📦 **依赖**:deps、依赖更新(通常可以忽略或合并)
|
||||
- 🔨 **构建**:ci、build、workflow 相关(通常可以忽略)
|
||||
|
||||
## 开发者注意
|
||||
- 列出迁移/接口断裂/配置变更;若无则省略
|
||||
## 合并和筛选
|
||||
|
||||
额外约束:
|
||||
- 语言简体中文,面向最终用户
|
||||
- **合并相似项**:同一功能的多个 commit 合并为一条
|
||||
- **忽略琐碎项**:合并冲突、格式化、typo 等可忽略
|
||||
- **控制数量**:最终保持 5-15 条更新要点
|
||||
- **保留 commit hash**:每条末尾附上短 hash,格式 `(a1b2c3d)`
|
||||
|
||||
下面为真实示例,请完全参考(第一行版本号必须使用用户提供的版本号,例如 v4.9.5)
|
||||
## 输出模板
|
||||
|
||||
# V4.9.0
|
||||
```
|
||||
# {VERSION}
|
||||
[使用文档](https://napneko.github.io/)
|
||||
|
||||
## Windows 一键包
|
||||
我们为提供了的轻量化一键部署方案
|
||||
相对于普通需要安装QQ的方案,下面已内置QQ和Napcat 阅读使用文档参考
|
||||
我们提供了轻量化一键部署方案,内置 QQ 和 NapCat,详见使用文档。
|
||||
|
||||
你可以下载
|
||||
可下载文件:
|
||||
- NapCat.Shell.Windows.Node.zip(无头模式)
|
||||
|
||||
NapCat.Shell.Windows.OneKey.zip (无头)
|
||||
## 注意事项
|
||||
**推荐 QQ 版本:9.9.23+,最低支持 9.9.22**
|
||||
**默认 WebUI 密钥为随机密码,请在控制台查看**
|
||||
|
||||
启动后可自动化部署一键包,教程参考使用文档安装部分
|
||||
## 运行库
|
||||
如果 Windows x64 缺少 xxx.dll,请安装 [VC++ 运行库](https://aka.ms/vs/17/release/vc_redist.x64.exe)
|
||||
|
||||
## 警告
|
||||
**注意QQ版本推荐使用 40768+ 版本 最低可以使用40768版本**
|
||||
**默认WebUi密钥为随机密码 控制台查看**
|
||||
## 更新内容
|
||||
|
||||
**[9.9.22-40990 X64 Win](https://dldir1v6.qq.com/qqfile/qq/QQNT/2c9d3f6c/QQ9.9.22.40990_x64.exe)**
|
||||
[LinuxX64 DEB 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_amd64.deb)
|
||||
[LinuxX64 RPM 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_x86_64.rpm)
|
||||
[LinuxArm64 DEB 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_arm64.deb)
|
||||
[LinuxArm64 RPM 40990 ](https://dldir1.qq.com/qqfile/qq/QQNT/ec800879/linuxqq_3.2.20-40990_aarch64.rpm)
|
||||
[MAC DMG 40990 ](https://dldir1v6.qq.com/qqfile/qq/QQNT/c6cb0f5d/QQ_v6.9.82.40990.dmg)
|
||||
## 如果WinX64缺少运行库或者xxx.dll?
|
||||
[安装运行库](https://aka.ms/vs/17/release/vc_redist.x64.exe)
|
||||
### 🐛 修复
|
||||
1. 修复 xxx 问题 (a1b2c3d)
|
||||
2. 修复 yyy 崩溃 (b2c3d4e)
|
||||
|
||||
## 更新
|
||||
1. 修改了XXXXX
|
||||
2. 新增了XXXX
|
||||
3. 重构了XXXX
|
||||
### ✨ 新增
|
||||
1. 新增 xxx 功能 (c3d4e5f)
|
||||
2. 支持 yyy 特性 (d4e5f6g)
|
||||
|
||||
### 🔧 优化
|
||||
1. 优化 xxx 性能 (e5f6g7h)
|
||||
2. 重构 yyy 模块 (f6g7h8i)
|
||||
|
||||
---
|
||||
|
||||
**完整更新日志**: [{PREV_VERSION}...{VERSION}](https://github.com/NapNeko/NapCatQQ/compare/{PREV_VERSION}...{VERSION})
|
||||
```
|
||||
|
||||
## 重要约束
|
||||
|
||||
1. 如果某个分类没有内容,则完全省略该分类
|
||||
2. 不要编造不存在的更新
|
||||
3. 保持简洁,每条更新控制在一行内
|
||||
4. 使用用户友好的语言,避免过于技术化的描述
|
||||
5. 重大变更(Breaking Changes)需要在注意事项中加粗提示
|
||||
|
||||
## 文件变化分析
|
||||
|
||||
用户会提供文件变化统计和具体代码diff,帮助你理解变更内容:
|
||||
|
||||
### 目录含义
|
||||
- `packages/napcat-core/` → 核心功能、消息处理、QQ接口
|
||||
- `packages/napcat-onebot/` → OneBot 协议实现、API、事件
|
||||
- `packages/napcat-webui-backend/` → WebUI 后端接口
|
||||
- `packages/napcat-webui-frontend/` → WebUI 前端界面
|
||||
- `packages/napcat-shell/` → Shell 启动器
|
||||
|
||||
### 代码diff阅读指南
|
||||
- `+` 开头的行是新增代码
|
||||
- `-` 开头的行是删除代码
|
||||
- 关注函数名、类名的变化来理解功能变更
|
||||
- 关注 `fix`、`bug`、`error` 等关键词识别修复项
|
||||
- 关注 `add`、`new`、`feature` 等关键词识别新功能
|
||||
- 忽略纯重构(代码移动但功能不变)和格式化变更
|
||||
|
||||
### 截断说明
|
||||
- 如果看到 `[... 已截断 ...]`,表示内容过长被截断
|
||||
- 根据已有信息推断完整变更意图即可
|
||||
9
.github/workflows/pr-build.yml
vendored
9
.github/workflows/pr-build.yml
vendored
@@ -41,8 +41,14 @@ permissions:
|
||||
# 并发控制
|
||||
# =============================================================================
|
||||
# 同一 PR 的多次构建会取消之前未完成的构建,避免资源浪费
|
||||
# 注意:只有在 should_build=true 时才会进入实际构建流程,
|
||||
# issue_comment 事件如果不是 /build 命令,会在 check-build 阶段快速退出,
|
||||
# 不会取消正在进行的构建(因为 cancel-in-progress 只影响同 group 的后续任务)
|
||||
concurrency:
|
||||
group: pr-build-${{ github.event.pull_request.number || github.event.issue.number || github.run_id }}
|
||||
# 使用不同的 group 策略:
|
||||
# - pull_request_target: 使用 PR 号
|
||||
# - issue_comment: 只有确认是 /build 命令时才使用 PR 号,否则使用 run_id(不冲突)
|
||||
group: pr-build-${{ github.event_name == 'pull_request_target' && github.event.pull_request.number || github.event_name == 'issue_comment' && github.event.issue.pull_request && contains(github.event.comment.body, '/build') && github.event.issue.number || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
# =============================================================================
|
||||
@@ -199,7 +205,6 @@ jobs:
|
||||
status: ${{ steps.build.outcome }} # 构建结果:success/failure
|
||||
error: ${{ steps.build.outputs.error }} # 错误信息(如有)
|
||||
version: ${{ steps.version.outputs.version }} # 构建版本号
|
||||
version: ${{ steps.version.outputs.version }} # 构建版本号
|
||||
steps:
|
||||
# 【安全】先从 base 分支 checkout 构建脚本
|
||||
- name: Checkout scripts from base
|
||||
|
||||
182
.github/workflows/release.yml
vendored
182
.github/workflows/release.yml
vendored
@@ -4,10 +4,7 @@ on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- 'v[0-9]*.[0-9]*.[0-9]*'
|
||||
- 'v[0-9]*.[0-9]*.[0-9]*-*'
|
||||
- 'v[0-9]*.[0-9]*.[0-9]*+*'
|
||||
- 'v[0-9]*.[0-9]*.[0-9]*-*+*'
|
||||
- 'v*'
|
||||
|
||||
permissions: write-all
|
||||
|
||||
@@ -17,7 +14,38 @@ env:
|
||||
RELEASE_NAME: "NapCat"
|
||||
|
||||
jobs:
|
||||
# 验证版本号格式
|
||||
validate-version:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
valid: ${{ steps.check.outputs.valid }}
|
||||
version: ${{ steps.check.outputs.version }}
|
||||
steps:
|
||||
- name: Validate semantic version
|
||||
id: check
|
||||
run: |
|
||||
TAG="${GITHUB_REF#refs/tags/}"
|
||||
echo "Checking tag: $TAG"
|
||||
|
||||
# 语义化版本正则表达式
|
||||
# 支持: v1.0.0, v1.0.0-beta, v1.0.0-rc.1, v1.0.0-alpha.1+build.123
|
||||
SEMVER_REGEX="^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*))?$"
|
||||
|
||||
if [[ "$TAG" =~ $SEMVER_REGEX ]]; then
|
||||
echo "✅ Valid semantic version: $TAG"
|
||||
echo "valid=true" >> $GITHUB_OUTPUT
|
||||
echo "version=$TAG" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "❌ Invalid version format: $TAG"
|
||||
echo "Expected format: vX.Y.Z or vX.Y.Z-prerelease"
|
||||
echo "Examples: v1.0.0, v1.2.3-beta, v2.0.0-rc.1"
|
||||
echo "valid=false" >> $GITHUB_OUTPUT
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Build-Framework:
|
||||
needs: validate-version
|
||||
if: needs.validate-version.outputs.valid == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone Main Repository
|
||||
@@ -45,6 +73,8 @@ jobs:
|
||||
path: framework-dist
|
||||
|
||||
Build-Shell:
|
||||
needs: validate-version
|
||||
if: needs.validate-version.outputs.valid == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone Main Repository
|
||||
@@ -181,7 +211,7 @@ jobs:
|
||||
OPENAI_KEY: ${{ secrets.OPENAI_KEY }}
|
||||
OPENROUTER_API_URL: ${{ env.OPENROUTER_API_URL }}
|
||||
OPENROUTER_MODEL: ${{ env.OPENROUTER_MODEL }}
|
||||
GITHUB_OWNER: "NapNeKo" # 替换成你的 repo owner
|
||||
GITHUB_OWNER: "NapNeko" # 替换成你的 repo owner
|
||||
GITHUB_REPO: "NapCatQQ" # 替换成你的 repo 名
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -206,34 +236,145 @@ jobs:
|
||||
done
|
||||
|
||||
if [ -z "$PREV_TAG" ]; then
|
||||
echo "❌ Could not find previous tag for $CURRENT_TAG, aborting."
|
||||
exit 1
|
||||
echo "⚠️ Could not find previous tag for $CURRENT_TAG, using first commit"
|
||||
PREV_TAG=$(git rev-list --max-parents=0 HEAD | head -1)
|
||||
fi
|
||||
|
||||
echo "Previous tag: $PREV_TAG"
|
||||
|
||||
# 强制拉取上一个 tag 和当前 tag
|
||||
git fetch origin "refs/tags/$PREV_TAG:refs/tags/$PREV_TAG" --force
|
||||
git fetch origin "refs/tags/$CURRENT_TAG:refs/tags/$CURRENT_TAG" --force
|
||||
git fetch origin "refs/tags/$PREV_TAG:refs/tags/$PREV_TAG" --force || true
|
||||
git fetch origin "refs/tags/$CURRENT_TAG:refs/tags/$CURRENT_TAG" --force || true
|
||||
|
||||
# 获取 commit title + body + 作者,保留换行
|
||||
COMMITS=$(git log --pretty=format:'%h %B (%an)' "$PREV_TAG".."$CURRENT_TAG" | sed 's/$/\\n/')
|
||||
# 获取 commit,使用更清晰的格式
|
||||
# 格式: <type>: <subject> (<hash>)
|
||||
COMMITS=$(git log --pretty=format:'- %s (%h)' "$PREV_TAG".."$CURRENT_TAG" 2>/dev/null || git log --pretty=format:'- %s (%h)' -20)
|
||||
|
||||
echo "Commit list from $PREV_TAG to $CURRENT_TAG:"
|
||||
echo -e "$COMMITS"
|
||||
echo "$COMMITS"
|
||||
|
||||
# 获取文件变化统计
|
||||
echo "Getting file change statistics..."
|
||||
FILE_STATS=$(git diff --stat "$PREV_TAG".."$CURRENT_TAG" 2>/dev/null || echo "")
|
||||
|
||||
# 获取总体统计(最后一行)
|
||||
SUMMARY_LINE=$(echo "$FILE_STATS" | tail -1)
|
||||
echo "Summary: $SUMMARY_LINE"
|
||||
|
||||
# 获取每个文件的变化(去掉最后一行汇总)
|
||||
# 截断过长的输出(最多50个文件,每行最多80字符)
|
||||
FILE_CHANGES=$(echo "$FILE_STATS" | head -n -1 | head -50 | cut -c1-80)
|
||||
|
||||
# 如果文件变化太多,进一步精简:只保留主要目录的变化
|
||||
FILE_COUNT=$(echo "$FILE_STATS" | head -n -1 | wc -l)
|
||||
if [ "$FILE_COUNT" -gt 50 ]; then
|
||||
echo "Too many files ($FILE_COUNT), grouping by directory..."
|
||||
# 按目录分组统计
|
||||
DIR_STATS=$(git diff --stat "$PREV_TAG".."$CURRENT_TAG" 2>/dev/null | head -n -1 | \
|
||||
sed 's/|.*//g' | \
|
||||
awk -F'/' '{if(NF>1) print $1"/"$2; else print $1}' | \
|
||||
sort | uniq -c | sort -rn | head -20)
|
||||
FILE_CHANGES="[按目录分组统计 - 共 $FILE_COUNT 个文件变更]
|
||||
$DIR_STATS"
|
||||
fi
|
||||
|
||||
echo "File changes:"
|
||||
echo "$FILE_CHANGES"
|
||||
|
||||
# 获取具体代码变化(关键文件的diff)
|
||||
echo "Getting code diff for key files..."
|
||||
|
||||
# 定义关键目录(优先展示这些目录的变化)
|
||||
KEY_DIRS="packages/napcat-core packages/napcat-onebot packages/napcat-webui-backend"
|
||||
|
||||
# 获取变更的关键文件列表(排除测试、配置等)
|
||||
KEY_FILES=$(git diff --name-only "$PREV_TAG".."$CURRENT_TAG" 2>/dev/null | \
|
||||
grep -E "^packages/napcat-(core|onebot|webui-backend|shell)/" | \
|
||||
grep -E "\.(ts|js)$" | \
|
||||
grep -v -E "(test|spec|\.d\.ts|config)" | \
|
||||
head -15)
|
||||
|
||||
CODE_DIFF=""
|
||||
DIFF_CHAR_LIMIT=6000 # 总diff字符限制
|
||||
CURRENT_CHARS=0
|
||||
|
||||
for file in $KEY_FILES; do
|
||||
if [ "$CURRENT_CHARS" -ge "$DIFF_CHAR_LIMIT" ]; then
|
||||
CODE_DIFF="$CODE_DIFF
|
||||
[... 更多文件变化已截断 ...]"
|
||||
break
|
||||
fi
|
||||
|
||||
# 获取单个文件的diff,限制每个文件最多50行
|
||||
FILE_DIFF=$(git diff "$PREV_TAG".."$CURRENT_TAG" -- "$file" 2>/dev/null | head -50)
|
||||
FILE_DIFF_LEN=${#FILE_DIFF}
|
||||
|
||||
# 如果单个文件diff超过1500字符,截断
|
||||
if [ "$FILE_DIFF_LEN" -gt 1500 ]; then
|
||||
FILE_DIFF=$(echo "$FILE_DIFF" | head -c 1500)
|
||||
FILE_DIFF="$FILE_DIFF
|
||||
[... 文件 $file 变化已截断 ...]"
|
||||
fi
|
||||
|
||||
if [ -n "$FILE_DIFF" ]; then
|
||||
CODE_DIFF="$CODE_DIFF
|
||||
|
||||
### $file
|
||||
\`\`\`diff
|
||||
$FILE_DIFF
|
||||
\`\`\`"
|
||||
CURRENT_CHARS=$((CURRENT_CHARS + FILE_DIFF_LEN))
|
||||
fi
|
||||
done
|
||||
|
||||
# 如果没有关键文件变化,获取前5个变更文件的diff
|
||||
if [ -z "$CODE_DIFF" ]; then
|
||||
echo "No key files changed, getting top changed files..."
|
||||
TOP_FILES=$(git diff --name-only "$PREV_TAG".."$CURRENT_TAG" 2>/dev/null | \
|
||||
grep -E "\.(ts|js)$" | head -5)
|
||||
|
||||
for file in $TOP_FILES; do
|
||||
FILE_DIFF=$(git diff "$PREV_TAG".."$CURRENT_TAG" -- "$file" 2>/dev/null | head -30)
|
||||
if [ -n "$FILE_DIFF" ] && [ ${#FILE_DIFF} -lt 1000 ]; then
|
||||
CODE_DIFF="$CODE_DIFF
|
||||
|
||||
### $file
|
||||
\`\`\`diff
|
||||
$FILE_DIFF
|
||||
\`\`\`"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "Code diff preview:"
|
||||
echo "$CODE_DIFF" | head -50
|
||||
|
||||
# 读取 prompt
|
||||
PROMPT_FILE=".github/prompt/release_note_prompt.txt"
|
||||
SYSTEM_PROMPT=$(<"$PROMPT_FILE")
|
||||
|
||||
# 构建用户内容
|
||||
USER_CONTENT="当前真正的版本: $CURRENT_TAG\n提交列表:\n$COMMITS"
|
||||
# 构建用户内容,传递更多上下文(包含文件变化和代码diff)
|
||||
USER_CONTENT="当前版本: $CURRENT_TAG
|
||||
上一版本: $PREV_TAG
|
||||
|
||||
## 提交列表
|
||||
$COMMITS
|
||||
|
||||
## 文件变化统计
|
||||
$SUMMARY_LINE
|
||||
|
||||
## 变更文件列表
|
||||
$FILE_CHANGES
|
||||
|
||||
## 关键代码变化
|
||||
$CODE_DIFF"
|
||||
|
||||
# 构建请求 JSON
|
||||
# 构建请求 JSON,增加 max_tokens 以获取更完整的输出
|
||||
BODY=$(jq -n \
|
||||
--arg system "$SYSTEM_PROMPT" \
|
||||
--arg user "$USER_CONTENT" \
|
||||
'{model: env.OPENROUTER_MODEL, messages:[{role:"system", content:$system},{role:"user", content:$user}], temperature:0.3, max_tokens:800}')
|
||||
--arg model "$OPENROUTER_MODEL" \
|
||||
'{model: $model, messages:[{role:"system", content:$system},{role:"user", content:$user}], temperature:0.2, max_tokens:1500}')
|
||||
|
||||
echo "=== OpenRouter request body ==="
|
||||
echo "$BODY" | jq .
|
||||
@@ -257,13 +398,18 @@ jobs:
|
||||
|
||||
if [ -z "$RELEASE_BODY" ]; then
|
||||
echo "❌ OpenRouter failed to generate release note, using default.md"
|
||||
cp .github/prompt/default.md CHANGELOG.md
|
||||
# 替换默认模板中的版本占位符
|
||||
sed "s/{VERSION}/$CURRENT_TAG/g" .github/prompt/default.md > CHANGELOG.md
|
||||
else
|
||||
# 后处理:确保版本号正确,并添加比较链接
|
||||
echo -e "$RELEASE_BODY" > CHANGELOG.md
|
||||
# 替换可能的占位符
|
||||
sed -i "s/{VERSION}/$CURRENT_TAG/g" CHANGELOG.md
|
||||
sed -i "s/{PREV_VERSION}/$PREV_TAG/g" CHANGELOG.md
|
||||
fi
|
||||
else
|
||||
echo "❌ Curl failed, using default.md"
|
||||
cp .github/prompt/default.md CHANGELOG.md
|
||||
sed "s/{VERSION}/$CURRENT_TAG/g" .github/prompt/default.md > CHANGELOG.md
|
||||
fi
|
||||
echo "=== generated release note ==="
|
||||
cat CHANGELOG.md
|
||||
|
||||
@@ -34,8 +34,9 @@ export async function NCoreInitFramework (
|
||||
});
|
||||
|
||||
const pathWrapper = new NapCatPathWrapper();
|
||||
await applyPendingUpdates(pathWrapper);
|
||||
|
||||
const logger = new LogWrapper(pathWrapper.logsPath);
|
||||
await applyPendingUpdates(pathWrapper, logger);
|
||||
const basicInfoWrapper = new QQBasicInfoWrapper({ logger });
|
||||
const wrapper = loadQQWrapper(basicInfoWrapper.getFullQQVersion());
|
||||
const nativePacketHandler = new NativePacketHandler({ logger }); // 初始化 NativePacketHandler 用于后续使用
|
||||
|
||||
@@ -2,14 +2,8 @@
|
||||
const path = require('path');
|
||||
|
||||
async function initializeNapCat (session, loginService, registerCallback) {
|
||||
// const logFile = path.join(currentPath, 'napcat.log');
|
||||
|
||||
console.log('[NapCat] [Info] 开始初始化NapCat');
|
||||
|
||||
// fs.writeFileSync(logFile, '', { flag: 'w' });
|
||||
|
||||
// fs.writeFileSync(logFile, '[NapCat] [Info] NapCat 初始化成功\n', { flag: 'a' });
|
||||
|
||||
try {
|
||||
const currentPath = path.dirname(__filename);
|
||||
const { NCoreInitFramework } = await import('file://' + path.join(currentPath, './napcat.mjs'));
|
||||
|
||||
@@ -319,7 +319,7 @@ export async function NCoreInitShell () {
|
||||
const pathWrapper = new NapCatPathWrapper();
|
||||
const logger = new LogWrapper(pathWrapper.logsPath);
|
||||
handleUncaughtExceptions(logger);
|
||||
await applyPendingUpdates(pathWrapper);
|
||||
await applyPendingUpdates(pathWrapper, logger);
|
||||
|
||||
// 初始化 FFmpeg 服务
|
||||
await FFmpegService.init(pathWrapper.binaryPath, logger);
|
||||
|
||||
@@ -42,6 +42,7 @@ export let WebUiConfig: WebUiConfigWrapper;
|
||||
export let webUiPathWrapper: NapCatPathWrapper;
|
||||
export let logSubscription: ISubscription;
|
||||
export let statusHelperSubscription: IStatusHelperSubscription;
|
||||
export let webUiLogger: ILogWrapper | null = null;
|
||||
const MAX_PORT_TRY = 100;
|
||||
|
||||
export let webUiRuntimePort = 6099;
|
||||
@@ -100,6 +101,7 @@ export async function InitWebUi (logger: ILogWrapper, pathWrapper: NapCatPathWra
|
||||
webUiPathWrapper = pathWrapper;
|
||||
logSubscription = Subscription;
|
||||
statusHelperSubscription = statusSubscription;
|
||||
webUiLogger = logger;
|
||||
WebUiConfig = new WebUiConfigWrapper();
|
||||
let config = await WebUiConfig.GetWebUIConfig();
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as https from 'https';
|
||||
import compressing from 'compressing';
|
||||
import { webUiPathWrapper } from '../../index';
|
||||
import { webUiPathWrapper, webUiLogger } from '../../index';
|
||||
import { NapCatPathWrapper } from '@/napcat-common/src/path';
|
||||
import { WebUiDataRuntime } from '@/napcat-webui-backend/src/helper/Data';
|
||||
import { NapCatCoreWorkingEnv } from '@/napcat-webui-backend/src/types';
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
getGitHubRelease,
|
||||
findAvailableDownloadUrl
|
||||
} from '@/napcat-common/src/mirror';
|
||||
import { ILogWrapper } from '@/napcat-common/src/log-interface';
|
||||
|
||||
// 更新请求体接口
|
||||
interface UpdateRequestBody {
|
||||
@@ -78,18 +79,18 @@ function scanFilesRecursively (dirPath: string, basePath: string = dirPath): Arr
|
||||
* 下载文件(带进度和重试)
|
||||
*/
|
||||
async function downloadFile (url: string, dest: string): Promise<void> {
|
||||
console.log('Starting download from:', url);
|
||||
webUiLogger?.log('[NapCat Update] Starting download from:', url);
|
||||
const file = fs.createWriteStream(dest);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = https.get(url, {
|
||||
headers: { 'User-Agent': 'NapCat-WebUI' }
|
||||
}, (res) => {
|
||||
console.log('Response status:', res.statusCode);
|
||||
console.log('Content-Type:', res.headers['content-type']);
|
||||
webUiLogger?.log('[NapCat Update] Response status:', res.statusCode);
|
||||
webUiLogger?.log('[NapCat Update] Content-Type:', res.headers['content-type']);
|
||||
|
||||
if (res.statusCode === 302 || res.statusCode === 301) {
|
||||
console.log('Following redirect to:', res.headers.location);
|
||||
webUiLogger?.log('[NapCat Update] Following redirect to:', res.headers.location);
|
||||
file.close();
|
||||
fs.unlinkSync(dest);
|
||||
downloadFile(res.headers.location!, dest).then(resolve).catch(reject);
|
||||
@@ -106,13 +107,13 @@ async function downloadFile (url: string, dest: string): Promise<void> {
|
||||
res.pipe(file);
|
||||
file.on('finish', () => {
|
||||
file.close();
|
||||
console.log('Download completed');
|
||||
webUiLogger?.log('[NapCat Update] Download completed');
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
request.on('error', (err) => {
|
||||
console.error('Download error:', err);
|
||||
webUiLogger?.logError('[NapCat Update] Download error:', err);
|
||||
file.close();
|
||||
fs.unlink(dest, () => { });
|
||||
reject(err);
|
||||
@@ -131,7 +132,7 @@ export const UpdateNapCatHandler: RequestHandler = async (req, res) => {
|
||||
// 确定目标版本 tag
|
||||
// 如果指定了版本,使用指定版本;否则使用 'latest'
|
||||
const targetTag = targetVersion || 'latest';
|
||||
console.log(`[NapCat Update] Target version: ${targetTag}`);
|
||||
webUiLogger?.log(`[NapCat Update] Target version: ${targetTag}`);
|
||||
|
||||
// 使用 mirror 模块获取 release 信息(不依赖 API)
|
||||
// 通过 assetNames 参数直接构建下载 URL,避免调用 GitHub API
|
||||
@@ -147,7 +148,7 @@ export const UpdateNapCatHandler: RequestHandler = async (req, res) => {
|
||||
|
||||
// 检查是否需要强制更新(降级警告)
|
||||
const currentVersion = WebUiDataRuntime.GetNapCatVersion();
|
||||
console.log(`[NapCat Update] Current version: ${currentVersion}, Target version: ${release.tag_name}`);
|
||||
webUiLogger?.log(`[NapCat Update] Current version: ${currentVersion}, Target version: ${release.tag_name}`);
|
||||
|
||||
if (!force && currentVersion) {
|
||||
// 简单的版本比较(可选的降级保护)
|
||||
@@ -165,12 +166,12 @@ export const UpdateNapCatHandler: RequestHandler = async (req, res) => {
|
||||
(targetMajor === currMajor && targetMinor === currMinor && targetPatch < currPatch);
|
||||
|
||||
if (isDowngrade) {
|
||||
console.log(`[NapCat Update] Downgrade from ${currentVersion} to ${release.tag_name}, force=${force}`);
|
||||
webUiLogger?.log(`[NapCat Update] Downgrade from ${currentVersion} to ${release.tag_name}, force=${force}`);
|
||||
// 不阻止降级,只是记录日志
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[NapCat Update] Updating to version: ${release.tag_name}`);
|
||||
webUiLogger?.log(`[NapCat Update] Updating to version: ${release.tag_name}`);
|
||||
|
||||
// 创建临时目录
|
||||
const tempDir = path.join(webUiPathWrapper.binaryPath, './temp');
|
||||
@@ -186,20 +187,20 @@ export const UpdateNapCatHandler: RequestHandler = async (req, res) => {
|
||||
timeout: 10000, // 10秒超时
|
||||
});
|
||||
|
||||
console.log(`[NapCat Update] Using download URL: ${downloadUrl}`);
|
||||
webUiLogger?.log(`[NapCat Update] Using download URL: ${downloadUrl}`);
|
||||
|
||||
// 下载zip
|
||||
const zipPath = path.join(tempDir, 'napcat-latest.zip');
|
||||
console.log('[NapCat Update] Saving to:', zipPath);
|
||||
webUiLogger?.log('[NapCat Update] Saving to:', zipPath);
|
||||
await downloadFile(downloadUrl, zipPath);
|
||||
|
||||
// 检查文件大小
|
||||
const stats = fs.statSync(zipPath);
|
||||
console.log('[NapCat Update] Downloaded file size:', stats.size, 'bytes');
|
||||
webUiLogger?.log('[NapCat Update] Downloaded file size:', stats.size, 'bytes');
|
||||
|
||||
// 解压到临时目录
|
||||
const extractPath = path.join(tempDir, 'napcat-extract');
|
||||
console.log('[NapCat Update] Extracting to:', extractPath);
|
||||
webUiLogger?.log('[NapCat Update] Extracting to:', extractPath);
|
||||
await compressing.zip.uncompress(zipPath, extractPath);
|
||||
|
||||
// 获取解压后的实际内容目录(NapCat.Shell.zip直接包含文件,无额外根目录)
|
||||
@@ -220,7 +221,7 @@ export const UpdateNapCatHandler: RequestHandler = async (req, res) => {
|
||||
|
||||
// 跳过指定的文件
|
||||
if (SKIP_UPDATE_FILES.includes(path.basename(fileInfo.relativePath))) {
|
||||
console.log(`[NapCat Update] Skipping update for ${fileInfo.relativePath}`);
|
||||
webUiLogger?.log(`[NapCat Update] Skipping update for ${fileInfo.relativePath}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -238,7 +239,7 @@ export const UpdateNapCatHandler: RequestHandler = async (req, res) => {
|
||||
fs.copyFileSync(fileInfo.sourcePath, targetFilePath);
|
||||
} catch (error) {
|
||||
// 如果替换失败,添加到失败列表
|
||||
console.log(`[NapCat Update] Failed to update ${targetFilePath}, will retry on next startup:`, error);
|
||||
webUiLogger?.logError(`[NapCat Update] Failed to update ${targetFilePath}, will retry on next startup:`, error);
|
||||
failedFiles.push({
|
||||
sourcePath: fileInfo.sourcePath,
|
||||
targetPath: targetFilePath
|
||||
@@ -258,7 +259,7 @@ export const UpdateNapCatHandler: RequestHandler = async (req, res) => {
|
||||
// 保存更新配置文件
|
||||
const configPath = path.join(webUiPathWrapper.configPath, 'napcat-update.json');
|
||||
fs.writeFileSync(configPath, JSON.stringify(updateConfig, null, 2));
|
||||
console.log(`[NapCat Update] Update config saved for ${failedFiles.length} failed files: ${configPath}`);
|
||||
webUiLogger?.log(`[NapCat Update] Update config saved for ${failedFiles.length} failed files: ${configPath}`);
|
||||
}
|
||||
|
||||
// 发送成功响应
|
||||
@@ -273,12 +274,12 @@ export const UpdateNapCatHandler: RequestHandler = async (req, res) => {
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('更新失败:', error);
|
||||
webUiLogger?.logError('[NapCat Update] 更新失败:', error);
|
||||
sendError(res, '更新失败: ' + (error instanceof Error ? error.message : '未知错误'));
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('更新失败:', error);
|
||||
webUiLogger?.logError('[NapCat Update] 更新失败:', error);
|
||||
sendError(res, '更新失败: ' + error.message);
|
||||
}
|
||||
};
|
||||
@@ -288,16 +289,16 @@ export const UpdateNapCatHandler: RequestHandler = async (req, res) => {
|
||||
/**
|
||||
* 应用待处理的更新(在应用启动时调用)
|
||||
*/
|
||||
export async function applyPendingUpdates (webUiPathWrapper: NapCatPathWrapper): Promise<void> {
|
||||
export async function applyPendingUpdates (webUiPathWrapper: NapCatPathWrapper, logger: ILogWrapper): Promise<void> {
|
||||
const configPath = path.join(webUiPathWrapper.configPath, 'napcat-update.json');
|
||||
|
||||
if (!fs.existsSync(configPath)) {
|
||||
console.log('No pending updates found');
|
||||
logger.log('[NapCat Update] No pending updates found');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('[NapCat Update] Applying pending updates...');
|
||||
logger.log('[NapCat Update] Applying pending updates...');
|
||||
const updateConfig: UpdateConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
|
||||
const remainingFiles: Array<{
|
||||
@@ -309,7 +310,7 @@ export async function applyPendingUpdates (webUiPathWrapper: NapCatPathWrapper):
|
||||
try {
|
||||
// 检查源文件是否存在
|
||||
if (!fs.existsSync(file.sourcePath)) {
|
||||
console.warn(`[NapCat Update] Source file not found: ${file.sourcePath}`);
|
||||
logger.logWarn(`[NapCat Update] Source file not found: ${file.sourcePath}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -324,10 +325,10 @@ export async function applyPendingUpdates (webUiPathWrapper: NapCatPathWrapper):
|
||||
fs.unlinkSync(file.targetPath); // 删除旧文件
|
||||
}
|
||||
fs.copyFileSync(file.sourcePath, file.targetPath);
|
||||
console.log(`[NapCat Update] Updated ${path.basename(file.targetPath)} on startup`);
|
||||
logger.log(`[NapCat Update] Updated ${path.basename(file.targetPath)} on startup`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`[NapCat Update] Failed to update ${file.targetPath} on startup:`, error);
|
||||
logger.logError(`[NapCat Update] Failed to update ${file.targetPath} on startup:`, error);
|
||||
// 如果仍然失败,保留在列表中
|
||||
remainingFiles.push(file);
|
||||
}
|
||||
@@ -340,13 +341,13 @@ export async function applyPendingUpdates (webUiPathWrapper: NapCatPathWrapper):
|
||||
files: remainingFiles
|
||||
};
|
||||
fs.writeFileSync(configPath, JSON.stringify(updatedConfig, null, 2));
|
||||
console.log(`${remainingFiles.length} files still pending update`);
|
||||
logger.log(`[NapCat Update] ${remainingFiles.length} files still pending update`);
|
||||
} else {
|
||||
// 所有文件都成功更新,删除配置文件
|
||||
fs.unlinkSync(configPath);
|
||||
console.log('[NapCat Update] All pending updates applied successfully');
|
||||
logger.log('[NapCat Update] All pending updates applied successfully');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[NapCat Update] Failed to apply pending updates:', error);
|
||||
logger.logError('[NapCat Update] Failed to apply pending updates:', error);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user