diff --git a/src/api/server.ts b/src/api/server.ts index fa6ccad..269dd20 100644 --- a/src/api/server.ts +++ b/src/api/server.ts @@ -9,7 +9,7 @@ import { syncProject, hasTodoJson } from '../sync/todo-sync.js'; import { resolvedExecutorModels } from '../executor/models.js'; import { classifyComplexity, type ClassifierFn } from '../executor/classify.js'; import { acceptAndMerge } from '../executor/exec-merge.js'; -import { createWorktree } from '../executor/worktree.js'; +import { createWorktree, git } from '../executor/worktree.js'; import { resolveLogo, LOGO_MIME } from './logo.js'; import { readTranscript, TranscriptError } from '../executor/transcript.js'; import { createReadStream, createWriteStream, mkdirSync, readFileSync, statSync } from 'node:fs'; @@ -342,6 +342,24 @@ export function buildServer(opts: ApiOptions): FastifyInstance { return store.listRuns(id); }); + // 任务改动 diff(结果评审用):git diff defaultBranch...branch,按文件切分返回,供点击文件看具体改动 + app.get('/api/tasks/:id/diff', async (req) => { + const { id } = req.params as { id: string }; + const task = store.getTask(id); + if (!task) throw new StoreError(`任务不存在: ${id}`); + const project = store.getProject(task.projectId); + const branch = task.result?.branch; + if (!project || !branch) return { files: [] }; + let raw = ''; + try { raw = await git(project.repoPath, ['diff', `${project.defaultBranch}...${branch}`]); } catch { return { files: [] }; } + const files = raw.split(/^diff --git /m).filter(Boolean).map((p) => { + const m = p.match(/^a\/(\S+)\s+b\/(\S+)/); + const path = m ? m[2] : (p.split('\n')[0] || '').trim(); + return { path, diff: 'diff --git ' + p }; + }); + return { files }; + }); + // 实时流(SSE):跟随任务「最近一条 run」的 transcript 文件,把新写入的 agent 消息逐行推送。 // 活跃 run(status=started)= 真实时;已结束 run = 一次性回放后 end。客户端 EventSource 消费。 app.get('/api/tasks/:id/stream', (req, reply) => {