feat(vscode): webhook 副作用按 assignee 门禁,适配多人协作

This commit is contained in:
2026-08-18 23:57:21 +08:00
parent c20bd86370
commit c370214d12
11 changed files with 450 additions and 22 deletions
+44 -6
View File
@@ -7,20 +7,22 @@ import { promises as fsp } from 'node:fs'
import * as os from 'node:os'
import * as path from 'node:path'
import { window, workspace } from 'vscode'
import { loginForToken } from '../../auth/identity'
import { getToken } from '../../auth/secrets'
import { buildCcCommand } from '../../cc/ccCommand'
import { buildCodexCommandString } from '../../cc/codexCommand'
import { watchForNewCodexSession } from '../../cc/codexSessionWatcher'
import { resolveProfilePath } from '../../cc/profiles'
import { getBrainstormContinuePrompt, getImplementPlanPrompt } from '../../cc/prompts'
import { projectsDirFor, watchForNewSession } from '../../cc/sessionWatcher'
import { detectRepo } from '../../git/remote'
import { createWorktree, resolveWorktreePath } from '../../git/worktree'
import { updateIssueAssignees } from '../../gitea/api'
import { logger } from '../../logging/logger'
import { getSettings } from '../../settings/store'
import { webhookCoordinator } from '../../webhook/coordinator'
import { resolveProfilePath } from '../../cc/profiles'
import { makeNonce } from '../KanbanPanel'
import { decideAutoReviewPath } from '../autoReviewDecision'
import { makeNonce } from '../KanbanPanel'
export async function handleResumeSession(panel: KanbanWebviewPanel, sessionId: string, profilePath?: string, relCwd?: string, issueNumber?: number): Promise<void> {
// kind 跟着 sessionRole 提前判定(原来散落在方法中部,提到入口是为了构造
@@ -647,9 +649,12 @@ function deriveSlug(planFile: string): string {
*/
function resolveWorktreeDir(template: string, workspaceRoot: string, slug: string): string {
let p = template
.split('$project_name').join(path.basename(workspaceRoot))
.split('$project_root').join(workspaceRoot)
.split('$feature_name').join(slug)
.split('$project_name')
.join(path.basename(workspaceRoot))
.split('$project_root')
.join(workspaceRoot)
.split('$feature_name')
.join(slug)
if (p.startsWith('~')) {
p = path.join(os.homedir(), p.slice(1))
}
@@ -832,6 +837,39 @@ export async function handleImplement(
return
}
// 实施即认领:assignee 是 webhook 副作用门禁的路由依据(谁实施,谁的
// 机器负责审查/写状态)。覆盖式单人指派,重新实施会转移责任。失败不阻塞
// 实施——门禁侧会退回本地终端兜底。
void (async () => {
try {
const me = await loginForToken(remote.host, token)
if (!me)
return
await updateIssueAssignees({
host: remote.host,
token,
owner: remote.owner,
repo: remote.repo,
index: issueNumber,
assignees: [me],
})
logger.add({
level: 'info',
source: 'implement',
message: `#${issueNumber} assignee → ${me}`,
})
}
catch (err) {
const message = err instanceof Error ? err.message : String(err)
logger.add({
level: 'warn',
source: 'implement',
message: `设置 #${issueNumber} assignee 失败(不阻塞实施)`,
details: message,
})
}
})()
// Run the post-create lifecycle hook. Fire-and-await so subsequent
// steps (mkdir projects dir, terminal spawn, cc launch) see whatever
// setup the user script performed (e.g. .env copy). Failures are
@@ -1223,7 +1261,7 @@ export async function handleStartTestSession(panel: KanbanWebviewPanel, issueNum
// worktree 里:代码就在当前工作目录,不用 tea 拉取,直接测;
// 主 worktreePR 已合并,先用 tea 熟悉改动再测。
const prompt = "/pr-acceptance-testing"
const prompt = '/pr-acceptance-testing'
if (prompt.includes('\'')) {
void window.showErrorMessage('启动测试失败:prompt 含单引号,拒绝执行')
return