diff --git a/.github/workflows/first-tree-sync.yml b/.github/workflows/first-tree-sync.yml index 39c85a9..2fbc1a7 100644 --- a/.github/workflows/first-tree-sync.yml +++ b/.github/workflows/first-tree-sync.yml @@ -61,24 +61,23 @@ jobs: GIT_ASKPASS="$askpass_script" git -c credential.helper= clone --depth 1 "$tree_repo_url" "$tree_repo_dir" rm -f "$askpass_script" + - name: Setup pnpm + uses: pnpm/action-setup@v4 + - name: Setup Node uses: actions/setup-node@v4 with: node-version: "22" + cache: "pnpm" + + - name: Install repo dependencies + run: pnpm install --frozen-lockfile + + - name: Build local CLI + run: pnpm build - - name: Install CLIs (first-tree + claude) - # `npx -p first-tree first-tree …` (the gardener-install-workflow - # template's default) is flaky on Node 22 / newer npm — it - # fails with `first-tree: not found` after install. Install both - # globally instead. - # - # Gardener's verdict classifier is designed to shell out to the - # `claude` CLI (see first-tree sync.ts). Pre-install - # @anthropic-ai/claude-code so any future upstream CLI upgrade - # that wires a real classifier into `gardener comment` will - # authenticate via CLAUDE_CODE_OAUTH_TOKEN below without another - # workflow change. - run: npm install -g first-tree @anthropic-ai/claude-code + - name: Install Claude Code + run: npm install -g @anthropic-ai/claude-code - name: Run first-tree gardener env: @@ -90,7 +89,7 @@ jobs: # bot identity is enough for the self-loop guard. GARDENER_USER: github-actions[bot] run: | - first-tree gardener comment \ + node dist/cli.js gardener comment \ --pr ${{ github.event.pull_request.number }} \ --repo ${{ github.repository }} \ --tree-path .first-tree-cache/tree \ diff --git a/src/products/gardener/engine/classifiers/claude-cli.ts b/src/products/gardener/engine/classifiers/claude-cli.ts index 52805b3..2933d59 100644 --- a/src/products/gardener/engine/classifiers/claude-cli.ts +++ b/src/products/gardener/engine/classifiers/claude-cli.ts @@ -141,6 +141,11 @@ function runClaude( "text", "--model", model, + "--disable-slash-commands", + "--setting-sources", + "user", + "--tools", + "", ], { stdio: ["pipe", "pipe", "pipe"], env, diff --git a/tests/gardener/gardener-claude-cli-classifier.test.ts b/tests/gardener/gardener-claude-cli-classifier.test.ts index bf2d068..8063297 100644 --- a/tests/gardener/gardener-claude-cli-classifier.test.ts +++ b/tests/gardener/gardener-claude-cli-classifier.test.ts @@ -148,7 +148,7 @@ describe("createClaudeCliClassifier", () => { }); it("scrubs ANTHROPIC_API_KEY from injected env", async () => { - const calls: Array<{ env?: NodeJS.ProcessEnv }> = []; + const calls: Array<{ env?: NodeJS.ProcessEnv; args?: string[] }> = []; const classifier = createClaudeCliClassifier({ env: { PATH: "/usr/bin:/bin", @@ -157,10 +157,10 @@ describe("createClaudeCliClassifier", () => { }, spawnImpl: (( _command: string, - _args: string[], + args: string[], options?: { env?: NodeJS.ProcessEnv }, ) => { - calls.push(options ?? {}); + calls.push({ ...(options ?? {}), args }); return makeFakeChild({ stdout: JSON.stringify({ verdict: "ALIGNED", @@ -176,6 +176,13 @@ describe("createClaudeCliClassifier", () => { expect(calls).toHaveLength(1); expect(calls[0]?.env?.ANTHROPIC_API_KEY).toBeUndefined(); expect(calls[0]?.env?.GARDENER_DIR).toBe("/tmp/gardener"); + expect(calls[0]?.args).toEqual(expect.arrayContaining([ + "--disable-slash-commands", + "--setting-sources", + "user", + "--tools", + "", + ])); }); it("ClaudeCliClassifierError carries kind and stderr", () => {