feat: 仓库导入、分支模型重构与审查历史摘要

仓库接入
- 新增「从 Gitea 导入」:用全局 Token 列出可见仓库,一键建配置
- 新增仓库只填 Git 地址,自动解析 owner/name,支持 https/ssh/scp 写法
- 新增「测试连接」按钮,保存前即可校验地址并拉取分支

分支模型
- 由单一 base_branch + glob 改为「一个管理分支 + 多个检查分支」
- 管理分支是唯一合并目标;检查分支全部纳入监控
- 支持从任意分支克隆创建管理分支
- 审查基准改为管理分支的 merge-base;仅目标为管理分支的 PR 才自动合并
- 旧库自动迁移:base_branch 播种 managed_branch,branch_patterns 展开为检查分支

审查历史
- 新增 review_records 表与「审查历史」页
- 记录触发来源、PR 链接、审查范围、阻断阈值、发布方式、自动合并设置、
  排除路径、LLM 模型、token 消耗、耗时、需求背景与全部审查意见
- 详情弹窗一览,支持按仓库过滤

AI 摘要
- 新增独立摘要模块(app/lib/summary.js),与代码审查提示词分离
- 专用提示词输出固定四节、500 字内的中文记录:结论/范围/问题/要点
- 与代码审查共用全局 LLM 设置;摘要失败不影响审查与合并,可单条重跑

修复
- 摘要改用内置 fetch:运行镜像没有 curl,原先 spawn curl 必然 ENOENT
- 去掉 blob:none 部分克隆并把凭据写入 .git/config:
  惰性取 blob 不会带上 per-command extraHeader,私有库会报 could not read Username

UI
- 审查背景改为多行文本域(可滚动)
- 分支改为可点选列表,管理分支高亮
- 仓库表格展示管理分支与检查分支
This commit is contained in:
2026-09-20 12:38:23 +08:00
parent ed172bf369
commit 6dc77ce907
12 changed files with 1374 additions and 153 deletions
+31
View File
@@ -96,6 +96,37 @@ export class GiteaClient {
return this.get(`/api/v1/repos/${owner}/${repo}`);
}
/** Repositories visible to the token, across pages. */
async listAccessibleRepos(limit = 50, maxPages = 40) {
const out = [];
const seen = new Set();
for (let page = 1; page <= maxPages; page += 1) {
let batch;
try {
batch = await this.get("/api/v1/user/repos", { query: { limit, page } });
} catch (err) {
if (page === 1) throw err;
break;
}
if (!Array.isArray(batch) || batch.length === 0) break;
for (const r of batch) {
if (r?.full_name && !seen.has(r.full_name)) {
seen.add(r.full_name);
out.push(r);
}
}
if (batch.length < limit) break;
}
return out;
}
/** Create a branch, optionally from another branch/tag/commit. */
async createBranch(owner, repo, { newBranch, fromBranch }) {
const payload = { new_branch_name: newBranch };
if (fromBranch) payload.old_ref_name = fromBranch;
return this.post(`/api/v1/repos/${owner}/${repo}/branches`, payload);
}
async listRepoBranches(owner, repo, limit = 100) {
const out = [];
for (let page = 1; page <= 20; page += 1) {