diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index d7cf5d8..9f6470b 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -28,9 +28,15 @@ jobs: with: ref: ${{ github.event.workflow_run.head_sha }} fetch-depth: 0 + # setup-node@v5 默认 package-manager-cache=true,看到 pnpm-lock.yaml 就找 + # pnpm 来确定 cache 目录;所以 pnpm/action-setup 必须先于 setup-node。 + # PR #7 dogfood 揭示的第 4 个 bug(无 pnpm → setup-node 报 'Unable to + # locate executable file: pnpm')。 + - uses: pnpm/action-setup@v5 - uses: actions/setup-node@v5 with: node-version: '22' + cache: pnpm - name: Resolve PR number from workflow_run id: pr diff --git a/.gitignore b/.gitignore index acd15b9..50f907e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,9 @@ coverage/ *.tsbuildinfo packages/*/.teamagent/ .teamagent/ +# Required-mode hook generated by `teamagent init`(与 .teamagent/required.json 同流程, +# 同样应忽略;之前漏了让 CI 的「Working tree must be clean」检查炸。issue #3 Gap 2 dogfood 揭示。) +.claude/hooks/check-teamagent.sh .worktrees/ .claude/worktrees/ .codex/worktrees/ diff --git a/packages/cli/src/__tests__/codex-hooks-config.test.ts b/packages/cli/src/__tests__/codex-hooks-config.test.ts index 6fbb525..aa71b70 100644 --- a/packages/cli/src/__tests__/codex-hooks-config.test.ts +++ b/packages/cli/src/__tests__/codex-hooks-config.test.ts @@ -38,6 +38,15 @@ function findRepoRoot(): string { const repoRoot = findRepoRoot(); const hooksJsonPath = path.join(repoRoot, ".codex", "hooks.json"); +// Matrix baseline 是 history-stripped fork(2026-05-14),没把 TeamBrain 的 +// .codex/ 目录(Codex CLI hook adapter,issue #290 范围)带过来。本测试套件 +// 来自上游,但 target 文件不存在,在 Matrix 上跑会 7 个全挂 ENOENT。 +// +// 用 describe.skipIf 自适应:.codex/hooks.json 存在 → 测试激活(TeamBrain 路径); +// 不存在 → 整个 describe block 跳过(Matrix 路径)。无须 Matrix 维护这套 fixture, +// 也无须删测试丢上游 contract 文档。issue #3 Gap 2 收尾。 +const codexHooksExist = existsSync(hooksJsonPath); + interface CodexHookEntry { matcher?: string; hooks: Array<{ type: string; command: string; timeout?: number }>; @@ -50,7 +59,7 @@ function loadConfig(): CodexHooksConfig { return JSON.parse(readFileSync(hooksJsonPath, "utf8")) as CodexHooksConfig; } -describe(".codex/hooks.json (issue #290)", () => { +describe.skipIf(!codexHooksExist)(".codex/hooks.json (issue #290)", () => { it("registers SessionStart, PreToolUse, and Stop events", () => { const cfg = loadConfig(); expect(Object.keys(cfg.hooks).sort()).toEqual([ diff --git a/scripts/review/post-pr-comment.ts b/scripts/review/post-pr-comment.ts index fc62e07..fc1429a 100644 --- a/scripts/review/post-pr-comment.ts +++ b/scripts/review/post-pr-comment.ts @@ -67,16 +67,19 @@ function parseArgv(argv: string[]): CliOpts { } function postOrUpdateComment(pr: number, body: string): void { - // 找现有的 marker 评论 - const list = spawnSync("gh", ["pr", "view", String(pr), "--json", "comments"], { encoding: "utf-8" }); - if (list.status !== 0) throw new Error(`gh pr view 失败: ${list.stderr}`); - const parsed = JSON.parse(list.stdout) as { comments?: Array<{ id?: string; body?: string }> }; - const comments = parsed.comments ?? []; + const repo = process.env["GITHUB_REPOSITORY"]; + if (!repo) throw new Error("GITHUB_REPOSITORY env 未设"); + // 一定要走 REST API 列评论 —— `gh pr view --json comments` 返回的是 GraphQL + // node id (IC_kwDOI...),不能喂给 `gh api /repos/.../issues/comments/{id}` + // 的 PATCH(那个要 REST integer id),否则 404。本 session PR #7 v2 翻车 + // 揭示的 bug;PR #2/#4 每个 PR 只跑过一次 → 只走 CREATE 路径 → 没暴露。 + const list = spawnSync("gh", [ + "api", `repos/${repo}/issues/${pr}/comments?per_page=100`, + ], { encoding: "utf-8" }); + if (list.status !== 0) throw new Error(`list comments 失败: ${list.stderr}`); + const comments = JSON.parse(list.stdout) as Array<{ id?: number; body?: string }>; const existing = comments.find((c) => (c.body ?? "").startsWith(COMMENT_MARKER)); - if (existing && existing.id) { - // gh 不直接支持 update comment,用 API - const repo = process.env["GITHUB_REPOSITORY"]; - if (!repo) throw new Error("GITHUB_REPOSITORY env 未设"); + if (existing && existing.id !== undefined) { const r = spawnSync("gh", [ "api", "--method", "PATCH", `repos/${repo}/issues/comments/${existing.id}`, @@ -84,8 +87,13 @@ function postOrUpdateComment(pr: number, body: string): void { ], { encoding: "utf-8" }); if (r.status !== 0) throw new Error(`update comment 失败: ${r.stderr}`); } else { - const r = spawnSync("gh", ["pr", "comment", String(pr), "--body", body], { encoding: "utf-8" }); - if (r.status !== 0) throw new Error(`gh pr comment 失败: ${r.stderr}`); + // 也走 REST API 保持对称(REST ids → 下次能正确 UPDATE)。 + const r = spawnSync("gh", [ + "api", "--method", "POST", + `repos/${repo}/issues/${pr}/comments`, + "-f", `body=${body}`, + ], { encoding: "utf-8" }); + if (r.status !== 0) throw new Error(`create comment 失败: ${r.stderr}`); } }