{"kind":"Skill","metadata":{"namespace":"community","name":"autoreview","version":"0.1.0"},"spec":{"description":"Autoreview closeout: local dirty changes, PR branch vs main, parallel tests.","files":{"SKILL.md":"---\nname: autoreview\ndescription: \"Autoreview closeout: local dirty changes, PR branch vs main, parallel tests.\"\n---\n\n# Autoreview\n\nRun Codex's built-in code review as a closeout check. This is code review (`codex review`), not Guardian `auto_review` approval routing.\n\nCodex native review mode performs best and is recommended. Non-Codex reviewers are fallback/second-opinion paths that receive a generated diff prompt, not the full Codex review-mode runtime.\n\nUse when:\n- user asks for Codex review / autoreview / second-model review\n- after non-trivial code edits, before final/commit/ship\n- reviewing a local branch or PR branch after fixes\n\n## Contract\n\n- Treat review output as advisory. Never blindly apply it.\n- Verify every finding by reading the real code path and adjacent files.\n- Read dependency docs/source/types when the finding depends on external behavior.\n- Reject unrealistic edge cases, speculative risks, broad rewrites, and fixes that over-complicate the codebase.\n- Prefer small fixes at the right ownership boundary; no refactor unless it clearly improves the bug class.\n- Keep going until the selected review path returns no accepted/actionable findings.\n- If a review-triggered fix changes code, rerun focused tests and rerun the review helper.\n- Default to Codex review. If Codex is unavailable or exits with an error, the helper falls back to the first configured CLI from `claude -p`, `pi -p`, `opencode run`, `droid exec`, or `copilot`. Prefer Codex for final closeout because it uses native review mode; non-Codex reviewers use a Codex-inspired generated diff prompt. The helper runs nested Codex review in yolo/full-access mode by default; use `--no-yolo` only when intentionally testing sandbox behavior.\n- Stop as soon as the review command/helper exits 0 with no accepted/actionable findings. Do not run an extra direct `codex review` just to get a nicer \"clean\" line, a second opinion, or clearer closeout wording.\n- Treat the helper's successful exit plus absence of actionable findings as the clean review result, even if the underlying Codex CLI output is terse.\n- If rejecting a finding as intentional/not worth fixing, add a brief inline code comment only when it explains a real invariant or ownership decision that future reviewers should know.\n- Do not push just to review. Push only when the user requested push/ship/PR update.\n- For OpenClaw maintainers, keep autoreview validation Crabbox/Testbox-aware when maintainer validation mode is enabled (`OPENCLAW_TESTBOX=1` or `AUTOREVIEW_OPENCLAW_MAINTAINER_VALIDATION=1`). A review pass may inspect files and run cheap non-Node probes, but it must not start local `pnpm`, Vitest, `tsgo`, `npm test`, or `node scripts/run-vitest.mjs` from a Codex/worktree review unless the operator explicitly requested local proof. For runtime proof, use existing evidence or route through Crabbox/Testbox and report the id. Do not apply this rule to ordinary contributors who do not have maintainer Testbox access.\n\n## Pick Target\n\nDirty local work:\n\n```bash\ncodex review --uncommitted\n```\n\nUse this only when the patch is actually unstaged/staged/untracked in the\ncurrent checkout. For committed, pushed, or PR work, point Codex at the commit\nor branch diff instead; do not force `--mode local` / `--uncommitted` just\nbecause the helper docs mention dirty work first. A clean `--uncommitted` review\nonly proves there is no local patch.\n\nBranch/PR work:\n\n```bash\ngit fetch origin\ncodex review --base origin/main\n```\n\nDo not pass any prompt with `--base`. Some Codex CLI versions reject both inline\nand stdin prompt forms, including the helper's `codex review --base \u003cref\u003e -`,\nwith `--base \u003cBRANCH\u003e cannot be used with [PROMPT]`. If the helper hits this\nerror, run plain `codex review --base \u003cref\u003e` and report that the helper prompt\ninjection was skipped.\n\nIf an open PR exists, use its actual base:\n\n```bash\nbase=$(gh pr view --json baseRefName --jq .baseRefName)\ncodex review --base \"origin/$base\"\n```\n\nCommitted single change:\n\n```bash\ncodex review --commit HEAD\n```\n\nor with the helper:\n\n```bash\n.agents/skills/autoreview/scripts/autoreview --mode commit --commit HEAD\n```\n\nUse commit review for already-landed or already-pushed work on `main`. Reviewing\nclean `main` against `origin/main` is usually an empty diff after push. For a\nsmall stack, review each commit explicitly or review the branch before merging\nwith `--base`.\n\n## Parallel Closeout\n\nFormat first if formatting can change line locations. Then it is OK to run tests and review in parallel:\n\n```bash\n.agents/skills/autoreview/scripts/autoreview --parallel-tests \"\u003cfocused test command\u003e\"\n```\n\nTradeoff: tests may force code changes that stale the review. If tests or review lead to code edits, rerun the affected tests and rerun review until no accepted/actionable findings remain. Once that rerun exits cleanly, stop; do not spend another long review cycle on redundant confirmation.\n\n## Context Efficiency\n\nCodex review is usually noisy. Default to a subagent filter when subagents are available. Ask it to run the review and return only:\n- actionable findings it accepts\n- findings it rejects, with one-line reason\n- exact files/tests to rerun\n\nRun inline only for tiny changes or when subagents are unavailable.\n\n## Helper\n\nBundled helper:\n\n```bash\n.agents/skills/autoreview/scripts/autoreview --help\n```\n\nThe helper:\n- chooses dirty `--uncommitted` first\n- otherwise uses current PR base if `gh pr view` works\n- otherwise uses `origin/main` for non-main branches\n- auto-runs `PNPM_CONFIG_PM_ON_FAIL=ignore PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN=false PNPM_CONFIG_OFFLINE=true pnpm run check` in parallel when a repo has `package.json`, `pnpm-lock.yaml`, `node_modules`, and a `check` script; disable with `AUTOREVIEW_AUTO_TESTS=0`\n- use `--mode commit --commit \u003cref\u003e` for already-committed work, especially clean `main` after landing\n- should be left in `--mode auto` or forced to `--mode branch` for PR/branch work; do not force `--mode local` after committing\n- supports `--reviewer codex|claude|pi|opencode|droid|copilot|auto`; `auto` means Codex first\n- supports `--fallback-reviewer auto|claude|pi|opencode|droid|copilot|none`; default is configured CLI fallback\n- falls back only when Codex is unavailable or exits nonzero, not when Codex reports findings\n- writes only to stdout unless `--output` or `AUTOREVIEW_OUTPUT` is set\n- supports `--dry-run`, `--parallel-tests`, and commit refs\n- runs nested review with `--dangerously-bypass-approvals-and-sandbox --sandbox danger-full-access` by default\n- injects maintainer-only OpenClaw validation policy into native Codex review when `OPENCLAW_TESTBOX=1` or `AUTOREVIEW_OPENCLAW_MAINTAINER_VALIDATION=1`, so local memory-heavy Node/Vitest checks are avoided in favor of Crabbox/Testbox proof\n- branch mode may fail on Codex CLI versions that reject `--base` plus the helper's stdin prompt; on that exact parser error, rerun plain `codex review --base \u003cref\u003e` instead of falling back to a non-Codex reviewer\n- keeps accepting `--full-access`; use `--no-yolo` or `AUTOREVIEW_YOLO=0` to opt out\n- still accepts legacy `CODEX_REVIEW_*` env vars when the matching `AUTOREVIEW_*` var is unset\n- prints `autoreview clean: no accepted/actionable findings reported` when the selected review command exits 0\n\n## Final Report\n\nInclude:\n- review command used\n- tests/proof run\n- findings accepted/rejected, briefly why\n- the clean review result from the final helper/review run, or why a remaining finding was consciously rejected\n\nDo not run another Codex review solely to improve the final report wording. If the final helper run exited 0 and produced no accepted/actionable findings, report that exact run as clean.\n\n## PR / CI Closeout\n\n- Prefer direct run/job APIs after CI starts: `gh run view \u003crun-id\u003e --json jobs`; use PR rollup only for final mergeability.\n- After rebase, compare `origin/main..HEAD`; drop CI-fix commits already upstream before pushing.\n- For prompt snapshot CI failures, prove/generate with Linux Node 24 before rerunning the failed job.\n- Update PR body once near the final head unless proof labels are missing or stale enough to block CI.\n","scripts/autoreview":"#!/usr/bin/env bash\nset -euo pipefail\n\nusage() {\n  cat \u003c\u003c'EOF'\nUsage: autoreview [options]\n\nOptions:\n  --mode auto|local|branch|commit\n                              Target selection. Default: auto.\n  --base REF                 Base ref for branch review. Default: PR base or origin/main.\n  --commit REF               Commit ref for commit review. Default: HEAD.\n  --reviewer codex|claude|pi|opencode|droid|copilot|auto\n                              Review engine. Default: Codex with configured fallback on error.\n  --fallback-reviewer auto|claude|pi|opencode|droid|copilot|none\n                              Fallback when Codex is unavailable or exits nonzero. Default: auto.\n  --codex-bin PATH           Codex binary. Default: codex.\n  --claude-bin PATH          Claude binary. Default: claude.\n  --pi-bin PATH              Pi binary. Default: pi.\n  --opencode-bin PATH        OpenCode binary. Default: opencode.\n  --droid-bin PATH           Droid binary. Default: droid.\n  --copilot-bin PATH         GitHub Copilot binary. Default: copilot.\n  --full-access              Keep yolo/full-access mode enabled. Default.\n  --no-yolo                  Run nested Codex review with normal sandbox/approval prompts.\n  --output FILE              Also save output to file.\n  --parallel-tests CMD       Run review and test command concurrently.\n                              Default: PNPM_CONFIG_PM_ON_FAIL=ignore PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN=false PNPM_CONFIG_OFFLINE=true pnpm run check when available.\n  --dry-run                  Print selected commands, do not run.\n  -h, --help                 Show help.\n\nEnvironment:\n  OPENCLAW_TESTBOX=1 or AUTOREVIEW_OPENCLAW_MAINTAINER_VALIDATION=1\n                              Enable maintainer-only OpenClaw Crabbox/Testbox validation policy.\n\nModes:\n  local   codex review --uncommitted\n  branch  codex review --base \u003cbase\u003e\n  commit  codex review --commit \u003ccommit\u003e\n  auto    dirty tree -\u003e local, else PR/current branch -\u003e branch\nEOF\n}\n\nmode=auto\nbase_ref=\ncommit_ref=HEAD\nreviewer=${AUTOREVIEW_REVIEWER:-${CODEX_REVIEW_REVIEWER:-auto}}\nfallback_reviewer=${AUTOREVIEW_FALLBACK_REVIEWER:-${CODEX_REVIEW_FALLBACK_REVIEWER:-auto}}\ncodex_bin=${CODEX_BIN:-codex}\nclaude_bin=${CLAUDE_BIN:-claude}\npi_bin=${PI_BIN:-pi}\nopencode_bin=${OPENCODE_BIN:-opencode}\ndroid_bin=${DROID_BIN:-droid}\ncopilot_bin=${COPILOT_BIN:-copilot}\ncodex_args=()\nyolo=${AUTOREVIEW_YOLO:-${CODEX_REVIEW_YOLO:-1}}\noutput=${AUTOREVIEW_OUTPUT:-${CODEX_REVIEW_OUTPUT:-}}\nparallel_tests=\nparallel_tests_auto=false\ndry_run=false\ncodex_review_prompt=\ncodex_review_stdin_prompt=false\ncodex_review_prompt_file=false\nopenclaw_maintainer_validation=${AUTOREVIEW_OPENCLAW_MAINTAINER_VALIDATION:-${OPENCLAW_TESTBOX:-0}}\n\nwhile [[ $# -gt 0 ]]; do\n  case \"$1\" in\n    --mode)\n      mode=${2:-}\n      shift 2\n      ;;\n    --base)\n      base_ref=${2:-}\n      shift 2\n      ;;\n    --commit)\n      commit_ref=${2:-}\n      shift 2\n      ;;\n    --reviewer)\n      reviewer=${2:-}\n      shift 2\n      ;;\n    --fallback-reviewer)\n      fallback_reviewer=${2:-}\n      shift 2\n      ;;\n    --codex-bin)\n      codex_bin=${2:-}\n      shift 2\n      ;;\n    --claude-bin)\n      claude_bin=${2:-}\n      shift 2\n      ;;\n    --pi-bin)\n      pi_bin=${2:-}\n      shift 2\n      ;;\n    --opencode-bin)\n      opencode_bin=${2:-}\n      shift 2\n      ;;\n    --droid-bin)\n      droid_bin=${2:-}\n      shift 2\n      ;;\n    --copilot-bin)\n      copilot_bin=${2:-}\n      shift 2\n      ;;\n    --full-access)\n      yolo=1\n      shift\n      ;;\n    --no-yolo)\n      yolo=0\n      shift\n      ;;\n    --output)\n      output=${2:-}\n      shift 2\n      ;;\n    --parallel-tests)\n      parallel_tests=${2:-}\n      shift 2\n      ;;\n    --dry-run)\n      dry_run=true\n      shift\n      ;;\n    -h|--help)\n      usage\n      exit 0\n      ;;\n    *)\n      usage \u003e\u00262\n      exit 2\n      ;;\n  esac\ndone\n\ncase \"$yolo\" in\n  0|false|False|FALSE|no|No|NO|off|Off|OFF) ;;\n  *) codex_args+=(--dangerously-bypass-approvals-and-sandbox --sandbox danger-full-access) ;;\nesac\n\ncase \"$mode\" in\n  auto|local|branch|commit) ;;\n  *)\n    echo \"invalid --mode: $mode\" \u003e\u00262\n    exit 2\n    ;;\nesac\n\ncase \"$reviewer\" in\n  auto|codex|claude|pi|opencode|droid|copilot) ;;\n  *)\n    echo \"invalid --reviewer: $reviewer\" \u003e\u00262\n    exit 2\n    ;;\nesac\n\ncase \"$fallback_reviewer\" in\n  auto|claude|pi|opencode|droid|copilot|none) ;;\n  *)\n    echo \"invalid --fallback-reviewer: $fallback_reviewer\" \u003e\u00262\n    exit 2\n    ;;\nesac\n\nrepo_root=$(git rev-parse --show-toplevel)\nprintf -v quoted_repo_root '%q' \"$repo_root\"\n\nhas_package_check_script() {\n  command -v node \u003e/dev/null 2\u003e\u00261 || return 1\n  node -e 'const { readFileSync } = require(\"node:fs\"); const p = JSON.parse(readFileSync(process.argv[1], \"utf8\")); process.exit(p.scripts?.check ? 0 : 1)' \\\n    \"$repo_root/package.json\" \\\n    \u003e/dev/null 2\u003e\u00261\n}\n\nauto_tests_disabled() {\n  case \"${AUTOREVIEW_AUTO_TESTS:-${CODEX_REVIEW_AUTO_TESTS:-1}}\" in\n    0|false|False|FALSE|no|No|NO|off|Off|OFF) return 0 ;;\n    *) return 1 ;;\n  esac\n}\n\ncurrent_branch=$(git branch --show-current 2\u003e/dev/null || true)\ndirty=false\nif [[ -n \"$(git status --porcelain)\" ]]; then\n  dirty=true\nfi\n\npr_url=\nif [[ -z \"$base_ref\" \u0026\u0026 \"$mode\" != local ]] \u0026\u0026 command -v gh \u003e/dev/null 2\u003e\u00261; then\n  if pr_lines=$(gh pr view --json baseRefName,url --jq '[.baseRefName, .url] | @tsv' 2\u003e/dev/null); then\n    base_name=${pr_lines%%$'\\t'*}\n    pr_url=${pr_lines#*$'\\t'}\n    if [[ -n \"$base_name\" ]]; then\n      base_ref=\"origin/$base_name\"\n    fi\n  fi\nfi\n\nif [[ -z \"$base_ref\" ]]; then\n  base_ref=origin/main\nfi\n\nreview_kind=\nif [[ \"$mode\" == local || ( \"$mode\" == auto \u0026\u0026 \"$dirty\" == true ) ]]; then\n  review_kind=local\nelif [[ \"$mode\" == commit ]]; then\n  review_kind=commit\nelif [[ \"$mode\" == branch || ( \"$mode\" == auto \u0026\u0026 -n \"$current_branch\" \u0026\u0026 \"$current_branch\" != \"main\" ) ]]; then\n  review_kind=branch\nelse\n  echo \"no review target: clean main checkout and no forced mode\" \u003e\u00262\n  exit 1\nfi\n\nif [[ \"$review_kind\" == local ]]; then\n  review_cmd=(\"$codex_bin\" \"${codex_args[@]}\" review --uncommitted)\nelif [[ \"$review_kind\" == commit ]]; then\n  review_cmd=(\"$codex_bin\" \"${codex_args[@]}\" review --commit \"$commit_ref\")\nelse\n  review_cmd=(\"$codex_bin\" \"${codex_args[@]}\" review --base \"$base_ref\")\nfi\n\nrepo_url=$(git -C \"$repo_root\" config --get remote.origin.url 2\u003e/dev/null || true)\ncase \"$openclaw_maintainer_validation\" in\n  1|true|True|TRUE|yes|Yes|YES|on|On|ON) openclaw_maintainer_validation=1 ;;\n  *) openclaw_maintainer_validation=0 ;;\nesac\nif [[ -z \"$parallel_tests\" \u0026\u0026 \"$openclaw_maintainer_validation\" != 1 ]] \u0026\u0026\n  ! auto_tests_disabled; then\n  if [[ -f \"$repo_root/package.json\" \u0026\u0026 -f \"$repo_root/pnpm-lock.yaml\" \u0026\u0026 -d \"$repo_root/node_modules\" ]] \u0026\u0026\n    command -v pnpm \u003e/dev/null 2\u003e\u00261 \u0026\u0026\n    has_package_check_script; then\n    parallel_tests=\"cd $quoted_repo_root \u0026\u0026 PNPM_CONFIG_PM_ON_FAIL=ignore PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN=false PNPM_CONFIG_OFFLINE=true pnpm run check\"\n    parallel_tests_auto=true\n  fi\nfi\nif [[ \"$repo_url\" == *\"openclaw/openclaw\"* \u0026\u0026 \"$openclaw_maintainer_validation\" == 1 ]]; then\n  codex_review_prompt=$(cat \u003c\u003c'EOF'\nOpenClaw maintainer autoreview validation policy:\n- Review the diff by reading code, tests, and dependency contracts.\n- Do not run local memory-heavy Node validation from review mode. This includes local pnpm checks/tests, Vitest, tsgo, npm test, and node scripts/run-vitest.mjs.\n- If runtime proof is needed, use existing proof or route validation through Crabbox / Blacksmith Testbox and report the exact provider and id.\n- If remote validation is not necessary for the finding, state the targeted proof that should be run instead of starting local tests.\nEOF\n)\n  if [[ \"$review_kind\" == local ]]; then\n    review_cmd+=(-)\n    codex_review_stdin_prompt=true\n  else\n    review_cmd=(\"$codex_bin\" \"${codex_args[@]}\" review -)\n    codex_review_prompt_file=true\n  fi\nfi\n\nprintf 'autoreview target: %s\\n' \"$review_kind\"\nprintf 'branch: %s\\n' \"${current_branch:-detached}\"\nif [[ -n \"$pr_url\" ]]; then\n  printf 'pr: %s\\n' \"$pr_url\"\nfi\nif [[ \"$reviewer\" == auto ]]; then\n  printf 'reviewer: codex\\n'\nelse\n  printf 'reviewer: %s\\n' \"$reviewer\"\nfi\ncase \"$reviewer\" in\n  codex|auto) ;;\n  *)\n    printf 'note: Codex native review mode is the recommended and best-supported review path; %s uses a generated diff prompt.\\n' \"$reviewer\"\n    ;;\nesac\nif [[ \"$reviewer\" == auto || \"$reviewer\" == codex ]]; then\n  printf 'review:'\n  printf ' %q' \"${review_cmd[@]}\"\n  printf '\\n'\n  if [[ \"$codex_review_stdin_prompt\" == true || \"$codex_review_prompt_file\" == true ]]; then\n    printf 'review policy: OpenClaw maintainer Crabbox/Testbox-aware validation prompt injected\\n'\n  fi\nelse\n  printf 'review: %s prompt review\\n' \"$reviewer\"\nfi\nif [[ -n \"$parallel_tests\" ]]; then\n  printf 'tests: %s' \"$parallel_tests\"\n  if [[ \"$parallel_tests_auto\" == true ]]; then\n    printf ' (auto)'\n  fi\n  printf '\\n'\nfi\nif [[ \"$review_kind\" == branch ]]; then\n  printf 'fetch: git fetch origin --quiet\\n'\nfi\nif [[ -n \"$output\" ]]; then\n  printf 'output: %s\\n' \"$output\"\nfi\n\nif [[ \"$dry_run\" == true ]]; then\n  exit 0\nfi\n\nif [[ \"$review_kind\" == branch ]]; then\n  git fetch origin --quiet || {\n    echo \"warning: git fetch origin failed; reviewing with existing refs\" \u003e\u00262\n  }\nfi\n\nreview_output=$output\nreview_output_is_temp=false\nif [[ -z \"$review_output\" ]]; then\n  review_output=$(mktemp)\n  review_output_is_temp=true\nfi\nmkdir -p \"$(dirname \"$review_output\")\"\n: \u003e \"$review_output\"\n\ncleanup() {\n  if [[ \"${review_output_is_temp:-false}\" == true \u0026\u0026 -n \"${review_output:-}\" ]]; then\n    rm -f \"$review_output\"\n  fi\n  if [[ -n \"${prompt_file:-}\" ]]; then\n    rm -f \"$prompt_file\"\n  fi\n}\ntrap cleanup EXIT\n\nrun_review() {\n  local status=0\n  mkdir -p \"$(dirname \"$review_output\")\"\n  if [[ \"$codex_review_prompt_file\" == true ]]; then\n    build_prompt_file || return\n    \"${review_cmd[@]}\" \u003c \"$prompt_file\" 2\u003e\u00261 | tee \"$review_output\"\n    status=${PIPESTATUS[0]}\n    rm -f \"$prompt_file\"\n    prompt_file=\n    return \"$status\"\n  elif [[ \"$codex_review_stdin_prompt\" == true ]]; then\n    printf '%s\\n' \"$codex_review_prompt\" | \"${review_cmd[@]}\" 2\u003e\u00261 | tee \"$review_output\"\n  else\n    \"${review_cmd[@]}\" 2\u003e\u00261 | tee \"$review_output\"\n  fi\n}\n\ndiff_for_review() {\n  case \"$review_kind\" in\n    local)\n      git -C \"$repo_root\" diff --stat\n      git -C \"$repo_root\" diff --cached --stat\n      git -C \"$repo_root\" diff --find-renames\n      git -C \"$repo_root\" diff --cached --find-renames\n      while IFS= read -r untracked_file; do\n        [[ -n \"$untracked_file\" ]] || continue\n        git -C \"$repo_root\" diff --no-index -- /dev/null \"$untracked_file\" || true\n      done \u003c \u003c(git -C \"$repo_root\" ls-files --others --exclude-standard)\n      ;;\n    commit)\n      git -C \"$repo_root\" show --find-renames --stat --format=fuller \"$commit_ref\"\n      git -C \"$repo_root\" show --find-renames --format=medium \"$commit_ref\"\n      ;;\n    branch)\n      git -C \"$repo_root\" diff --find-renames --stat \"$base_ref\"...HEAD\n      git -C \"$repo_root\" diff --find-renames \"$base_ref\"...HEAD\n      ;;\n  esac\n}\n\nbuild_prompt_file() {\n  prompt_file=$(mktemp)\n  {\n    cat \u003c\u003cEOF\nYou are performing a closeout code review for the current repository.\n\nReview target: $review_kind\nBranch: ${current_branch:-detached}\nBase: ${base_ref:-}\nCommit: ${commit_ref:-}\n\nRules:\n- Review the proposed code change as a closeout reviewer.\n- Focus on the diff below. If your CLI exposes read-only repository tools, inspect surrounding code and tests to verify findings; never modify files.\n- Do not modify files.\n${codex_review_prompt}\n- Report only discrete, actionable issues introduced by this change.\n- Prioritize correctness, regressions, security, data loss, performance cliffs, and missing tests that would catch a real bug.\n- Do not report pre-existing issues, speculative risks, broad rewrites, style nits, changelog gaps, or findings that depend on unstated assumptions.\n- Identify the concrete scenario where the issue appears, and keep the line reference as small as possible.\n- A finding should overlap changed code or clearly cite changed code as the cause.\n- For each accepted/actionable finding, use exactly this format:\n  [P\u003c0-3\u003e] Short title\n  File: path:line\n  Why: one sentence\n  Fix: one sentence\n- If no accepted/actionable findings, output exactly:\n  autoreview clean: no accepted/actionable findings reported\n\nDiff:\nEOF\n    diff_for_review\n  } \u003e \"$prompt_file\" || return\n}\n\nreviewer_output_has_clean_marker() {\n  local path=$1\n  grep -Eq '^[^[:alnum:]]*autoreview clean: no accepted/actionable findings reported[[:space:]]*$' \"$path\"\n}\n\nrun_prompt_reviewer() {\n  local selected=$1\n  local copilot_prompt=\n  local prompt_bytes=0\n  local reviewer_output\n  local status=0\n\n  if ! build_prompt_file; then\n    rm -f \"${prompt_file:-}\"\n    prompt_file=\n    return 1\n  fi\n  reviewer_output=$(mktemp)\n  mkdir -p \"$(dirname \"$review_output\")\"\n\n  case \"$selected\" in\n    claude)\n      if ! command -v \"$claude_bin\" \u003e/dev/null 2\u003e\u00261; then\n        echo \"fallback reviewer unavailable: $claude_bin\" \u003e\u00262\n        status=127\n      elif printf 'fallback: claude -p\\n' | tee -a \"$review_output\"; then\n        \"$claude_bin\" --tools \"\" --no-session-persistence -p \u003c \"$prompt_file\" 2\u003e\u00261 | tee -a \"$review_output\" \"$reviewer_output\"\n        status=$?\n      else\n        status=$?\n      fi\n      ;;\n    pi)\n      if ! command -v \"$pi_bin\" \u003e/dev/null 2\u003e\u00261; then\n        echo \"fallback reviewer unavailable: $pi_bin\" \u003e\u00262\n        status=127\n      elif printf 'fallback: pi -p\\n' | tee -a \"$review_output\"; then\n        \"$pi_bin\" --no-tools --no-session -p \u003c \"$prompt_file\" 2\u003e\u00261 | tee -a \"$review_output\" \"$reviewer_output\"\n        status=$?\n      else\n        status=$?\n      fi\n      ;;\n    opencode)\n      if ! command -v \"$opencode_bin\" \u003e/dev/null 2\u003e\u00261; then\n        echo \"fallback reviewer unavailable: $opencode_bin\" \u003e\u00262\n        status=127\n      elif printf 'fallback: opencode run\\n' | tee -a \"$review_output\"; then\n        \"$opencode_bin\" run --pure --dir \"$repo_root\" \\\n          \"Review the attached prompt file. Do not modify files.\" \\\n          --file \"$prompt_file\" 2\u003e\u00261 | tee -a \"$review_output\" \"$reviewer_output\"\n        status=$?\n      else\n        status=$?\n      fi\n      ;;\n    droid)\n      if ! command -v \"$droid_bin\" \u003e/dev/null 2\u003e\u00261; then\n        echo \"fallback reviewer unavailable: $droid_bin\" \u003e\u00262\n        status=127\n      elif printf 'fallback: droid exec\\n' | tee -a \"$review_output\"; then\n        \"$droid_bin\" exec --cwd \"$repo_root\" -f \"$prompt_file\" 2\u003e\u00261 | tee -a \"$review_output\" \"$reviewer_output\"\n        status=$?\n      else\n        status=$?\n      fi\n      ;;\n    copilot)\n      if ! command -v \"$copilot_bin\" \u003e/dev/null 2\u003e\u00261; then\n        echo \"fallback reviewer unavailable: $copilot_bin\" \u003e\u00262\n        status=127\n      elif printf 'fallback: copilot\\n' | tee -a \"$review_output\"; then\n        prompt_bytes=$(wc -c \u003c \"$prompt_file\" | tr -d '[:space:]')\n        if (( prompt_bytes \u003e 120000 )); then\n          echo \"copilot reviewer unavailable: generated prompt is too large for copilot -p; use codex, droid, or another file/stdin-capable reviewer\" \\\n            2\u003e\u00261 | tee -a \"$review_output\" \"$reviewer_output\"\n          status=1\n        else\n          copilot_prompt=$(\u003c \"$prompt_file\")\n          \"$copilot_bin\" -C \"$repo_root\" --available-tools=none --stream off --output-format text --silent \\\n            -p \"$copilot_prompt\" \\\n            2\u003e\u00261 | tee -a \"$review_output\" \"$reviewer_output\"\n          status=$?\n        fi\n      else\n        status=$?\n      fi\n      ;;\n    *)\n      echo \"unsupported prompt reviewer: $selected\" \u003e\u00262\n      status=2\n      ;;\n  esac\n  if [[ \"$status\" == 0 ]]; then\n    if grep -Eq '\\[P[0-3]\\]' \"$reviewer_output\"; then\n      status=1\n    elif ! grep -q '[^[:space:]]' \"$reviewer_output\"; then\n      status=1\n    elif ! reviewer_output_has_clean_marker \"$reviewer_output\"; then\n      status=1\n    fi\n  fi\n  rm -f \"$reviewer_output\"\n  rm -f \"$prompt_file\"\n  prompt_file=\n  return \"$status\"\n}\n\nrun_selected_review() {\n  local selected=$1\n  case \"$selected\" in\n    codex)\n      if ! command -v \"$codex_bin\" \u003e/dev/null 2\u003e\u00261; then\n        echo \"codex reviewer unavailable: $codex_bin\" \u003e\u00262\n        return 127\n      fi\n      run_review\n      ;;\n    claude|pi|opencode|droid|copilot)\n      run_prompt_reviewer \"$selected\"\n      ;;\n    *)\n      echo \"unsupported reviewer: $selected\" \u003e\u00262\n      return 2\n      ;;\n  esac\n}\n\nfallback_reviewer_is_available() {\n  local selected=$1\n  case \"$selected\" in\n    claude) command -v \"$claude_bin\" \u003e/dev/null 2\u003e\u00261 ;;\n    pi) command -v \"$pi_bin\" \u003e/dev/null 2\u003e\u00261 ;;\n    opencode) command -v \"$opencode_bin\" \u003e/dev/null 2\u003e\u00261 ;;\n    droid) command -v \"$droid_bin\" \u003e/dev/null 2\u003e\u00261 ;;\n    copilot) command -v \"$copilot_bin\" \u003e/dev/null 2\u003e\u00261 ;;\n    *) return 1 ;;\n  esac\n}\n\nrun_auto_fallback_review() {\n  local selected\n  if [[ \"$fallback_reviewer\" != auto ]]; then\n    run_selected_review \"$fallback_reviewer\"\n    return $?\n  fi\n\n  for selected in claude pi opencode droid copilot; do\n    if fallback_reviewer_is_available \"$selected\"; then\n      run_selected_review \"$selected\"\n      return $?\n    fi\n  done\n\n  echo \"fallback reviewer unavailable: no configured fallback CLI found\" \u003e\u00262\n  return 127\n}\n\nrun_auto_review() {\n  run_selected_review codex\n  local status=$?\n  if [[ \"$status\" == 0 ]]; then\n    return 0\n  fi\n  if (( status \u003e 128 \u0026\u0026 status \u003c 192 )); then\n    return \"$status\"\n  fi\n  if review_output_has_findings; then\n    return \"$status\"\n  fi\n  if [[ \"$fallback_reviewer\" == none ]]; then\n    return \"$status\"\n  fi\n  if [[ \"$fallback_reviewer\" == auto ]]; then\n    printf 'autoreview warning: codex exited %s; trying configured fallback reviewers\\n' \"$status\" \u003e\u00262\n  else\n    printf 'autoreview warning: codex exited %s; falling back to %s\\n' \"$status\" \"$fallback_reviewer\" \u003e\u00262\n  fi\n  run_auto_fallback_review\n}\n\nelapsed_since() {\n  local started_at=$1\n  local finished_at\n  finished_at=$(date +%s)\n  printf '%s\\n' \"$((finished_at - started_at))\"\n}\n\nformat_elapsed() {\n  local seconds=$1\n  if (( seconds \u003c 60 )); then\n    printf '%ss\\n' \"$seconds\"\n  else\n    printf '%sm%ss\\n' \"$((seconds / 60))\" \"$((seconds % 60))\"\n  fi\n}\n\nreview_output_empty() {\n  [[ ! -s \"$review_output\" ]] || ! grep -q '[^[:space:]]' \"$review_output\"\n}\n\nreview_findings_text() {\n  if grep -Fxq 'codex' \"$review_output\"; then\n    awk '\n      $0 == \"codex\" {\n        capture = 1\n        output = $0 ORS\n        next\n      }\n      capture {\n        output = output $0 ORS\n      }\n      END {\n        printf \"%s\", output\n      }\n    ' \"$review_output\"\n    return\n  fi\n  cat \"$review_output\"\n}\n\nreview_output_has_findings() {\n  review_findings_text | grep -Eq '\\[P[0-3]\\]'\n}\n\nreport_clean_review_or_fail() {\n  local elapsed_text\n  elapsed_text=$(format_elapsed \"${review_elapsed_seconds:-0}\")\n\n  if review_output_has_findings; then\n    printf 'autoreview complete after %s\\n' \"$elapsed_text\"\n    printf 'autoreview findings: accepted/actionable findings reported\\n'\n    return 1\n  fi\n  if review_output_empty; then\n    printf 'autoreview complete after %s; no output\\n' \"$elapsed_text\"\n    return 1\n  fi\n  printf 'autoreview complete after %s\\n' \"$elapsed_text\"\n  printf 'autoreview clean: no accepted/actionable findings reported\\n'\n}\n\nif [[ -z \"$parallel_tests\" ]]; then\n  review_started_at=$(date +%s)\n  set +e\n  if [[ \"$reviewer\" == auto ]]; then\n    run_auto_review\n  else\n    run_selected_review \"$reviewer\"\n  fi\n  review_status=$?\n  review_elapsed_seconds=$(elapsed_since \"$review_started_at\")\n  set -e\n  if [[ \"$review_status\" == 0 ]]; then\n    report_clean_review_or_fail\n    exit $?\n  fi\n  exit \"$review_status\"\nfi\n\nreview_status_file=$(mktemp)\nreview_elapsed_file=$(mktemp)\ntests_status_file=$(mktemp)\n\n(\n  set +e\n  review_started_at=$(date +%s)\n  if [[ \"$reviewer\" == auto ]]; then\n    run_auto_review\n  else\n    run_selected_review \"$reviewer\"\n  fi\n  status=$?\n  elapsed=$(elapsed_since \"$review_started_at\")\n  printf '%s\\n' \"$status\" \u003e \"$review_status_file\"\n  printf '%s\\n' \"$elapsed\" \u003e \"$review_elapsed_file\"\n) \u0026\nreview_pid=$!\n\n(\n  set +e\n  bash -lc \"$parallel_tests\"\n  status=$?\n  printf '%s\\n' \"$status\" \u003e \"$tests_status_file\"\n) \u0026\ntests_pid=$!\n\nwait \"$review_pid\" || true\nwait \"$tests_pid\" || true\n\nreview_status=$(cat \"$review_status_file\")\nreview_elapsed_seconds=$(cat \"$review_elapsed_file\")\ntests_status=$(cat \"$tests_status_file\")\nrm -f \"$review_status_file\" \"$review_elapsed_file\" \"$tests_status_file\"\n\nprintf 'autoreview exit: %s\\n' \"$review_status\"\nprintf 'tests exit: %s\\n' \"$tests_status\"\n\nif [[ \"$review_status\" != 0 || \"$tests_status\" != 0 ]]; then\n  exit 1\nfi\n\nreport_clean_review_or_fail\n"},"import":{"commit_sha":"424c6d0a5f4665b803ad6768d08b0be7659deaf4","imported_at":"2026-05-18T20:13:36Z","license_text":"MIT License\n\nCopyright (c) 2025 Peter Steinberger\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n","owner":"openclaw","repo":"openclaw/openclaw","source_url":"https://github.com/openclaw/openclaw/tree/424c6d0a5f4665b803ad6768d08b0be7659deaf4/.agents/skills/autoreview"}},"content_hash":[10,206,51,158,212,199,25,13,33,192,179,246,179,18,16,126,56,222,5,74,206,71,182,50,113,210,78,45,194,156,12,188],"trust_level":"unsigned","yanked":false}
