Files
istosandClaude Opus 5 47779a35bc Assert the review launch's flag list whole, and say why it moves
The MultiEdit deny rule was already dropped in the hotfix; this is task
10's follow-up half — the guard that catches the next fossil.

The claude adapter's review branch spells "cannot edit files" in the
vendor's own tool names, and that roster moves: a rule naming a tool the
installed CLI does not have is refused at startup, so the launch dies
before the agent speaks. Membership assertions could not see that
happening, so the stub-binary test now asserts each mode's flag list
literally (settings payload elided) — a deny name added or renamed shows
up as a diff a reviewer must re-verify against the installed CLI. The
run script carries the same warning where the list actually lives.

The helper drops a leaked AGENT_MODEL, since --model would otherwise
appear in an argv now compared whole; test_agent_model.py owns that flag.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 14:34:19 +02:00

56 lines
2.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# Claude adapter: run one headless job to completion.
#
# Contract (same for every adapter):
# env in: AGENT_PROMPT the full prompt
# AGENT_MODE work | act-pr | review — the launch intent
# (see core/adapters/README.md)
# AGENT_COMMANDS comma-separated neutral command prefixes the
# project lets agents run (tests/checks)
# AGENT_MODEL optional; a claude model name/alias passed
# through as --model. Absent = the CLI's own
# resolution (user settings), untouched.
# AGENT_CWD working directory (already set as cwd by the board)
# BOARD_* passthrough for the event bridge
# stdout: captured by the board as the job log; the closing report's
# marker lines (NOT READY:, PR REVIEW:, ...) are parsed from it
# exit: 0 = completed; anything else = failed
#
# Headless runs have no human to answer permission prompts: whatever the
# generated settings do not allow is denied. hook_settings.py grants each
# intent exactly what its own prompt demands (commit and test for work,
# push for act-pr, gh pr review for review) — never bypassPermissions.
#
# BOARD_CLAUDE_BIN overrides the binary (used by the test stubs).
set -euo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BIN="${BOARD_CLAUDE_BIN:-claude}"
MODE="${AGENT_MODE:-work}"
SETTINGS="$(python3 "$HERE/hook_settings.py" "$MODE")"
# The ${arr[@]+...} expansion keeps set -u happy on bash 3.2 when unset.
MODEL_ARGS=()
if [ -n "${AGENT_MODEL:-}" ]; then
MODEL_ARGS=(--model "$AGENT_MODEL")
fi
if [ "$MODE" = "review" ]; then
# "Cannot edit files" has to be spelled in the vendor's own tool names,
# and that roster moves under us: a deny rule naming a tool the
# installed CLI does not have is refused outright ("matches no known
# tool"), so the launch dies before the agent speaks — which is how the
# retired MultiEdit killed every review and relevance launch (task 10).
# Re-check these names against the installed CLI rather than memory
# whenever the list is touched; tests/test_adapter_permissions.py
# asserts the flag list whole so any edit surfaces in review.
exec "$BIN" -p "$AGENT_PROMPT" --settings "$SETTINGS" \
${MODEL_ARGS[@]+"${MODEL_ARGS[@]}"} \
--permission-mode default \
--disallowedTools Edit Write NotebookEdit
else
# work and act-pr both mutate the worktree; the allowlist differs.
exec "$BIN" -p "$AGENT_PROMPT" --settings "$SETTINGS" \
${MODEL_ARGS[@]+"${MODEL_ARGS[@]}"} \
--permission-mode acceptEdits
fi