From c9dfa708f08e92ac198e0a42434a90c92e461268 Mon Sep 17 00:00:00 2001 From: cc Date: Thu, 2 Jul 2026 16:00:50 -0700 Subject: [PATCH 1/4] feat: support OpenCode autofix agent --- misc/auto-fixes/auto-fix.sh | 111 +++++++++++++++++++++++++++----- misc/auto-fixes/fix_template.md | 2 +- 2 files changed, 95 insertions(+), 18 deletions(-) diff --git a/misc/auto-fixes/auto-fix.sh b/misc/auto-fixes/auto-fix.sh index 915484a260..078aaf1459 100755 --- a/misc/auto-fixes/auto-fix.sh +++ b/misc/auto-fixes/auto-fix.sh @@ -1,26 +1,78 @@ #!/usr/bin/env bash # Scan a contributor's branch for code-quality issues and open a PR of fixes back into that branch. # -# Usage: misc/auto-fixes/auto-fix.sh +# Usage: misc/auto-fixes/auto-fix.sh [--agent claude|opencode] # set -euo pipefail -# Print the script's own messages in green so they stand out from git/uv/claude output. +# Print the script's own messages in green so they stand out from git/uv/agent output. GREEN=$'\033[0;32m' RESET=$'\033[0m' log() { echo "${GREEN}$*${RESET}"; } # stdout (progress) err() { echo "${GREEN}$*${RESET}" >&2; } # stderr (errors) usage() { - err "usage: $0 " + err "usage: $0 [--agent claude|opencode] " + err " AUTO_FIX_AGENT=opencode $0 " exit 2 } -[[ $# -eq 1 ]] || usage -BRANCH="$1" +AGENT="${AUTO_FIX_AGENT:-claude}" +BRANCH="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --agent|-a) + [[ $# -ge 2 ]] || usage + AGENT="$2" + shift 2 + ;; + --agent=*) + AGENT="${1#*=}" + shift + ;; + -h|--help) + usage + ;; + --) + shift + break + ;; + -*) + err "unknown option: $1" + usage + ;; + *) + [[ -z "$BRANCH" ]] || usage + BRANCH="$1" + shift + ;; + esac +done + +if [[ $# -gt 0 ]]; then + [[ -z "$BRANCH" && $# -eq 1 ]] || usage + BRANCH="$1" +fi + +[[ -n "$BRANCH" ]] || usage + +case "$AGENT" in + claude|opencode) + ;; + *) + err "unsupported agent: $AGENT (expected claude or opencode)" + exit 2 + ;; +esac + +command -v "$AGENT" >/dev/null 2>&1 || { err "missing $AGENT on PATH"; exit 1; } + # shellcheck disable=SC2016 PLACEHOLDER='$$BRANCH$$' # shellcheck disable=SC2016 +AUTOFIX_PLACEHOLDER='$$AUTOFIX_BRANCH$$' +# shellcheck disable=SC2016 RULES_PLACEHOLDER='$$RULES$$' REPO_ROOT="$(git rev-parse --show-toplevel)" @@ -46,6 +98,32 @@ SUFFIX="$(openssl rand -hex 4)" WORKTREE="$(cd "$REPO_ROOT/.." && pwd)/dimos-worktree-${SUFFIX}" AUTOFIX_BRANCH="" # set once we know there are issues; cleanup uses it +run_scan_agent() { + local prompt="$1" + case "$AGENT" in + claude) + ( cd "$WORKTREE" && claude -p "$prompt" --dangerously-skip-permissions ) + ;; + opencode) + opencode run --auto --dir "$WORKTREE" "$prompt" + ;; + esac +} + +run_fix_agent() { + local prompt="$1" + case "$AGENT" in + claude) + ( cd "$WORKTREE" && claude -p "$prompt" \ + --dangerously-skip-permissions \ + --settings '{"includeCoAuthoredBy": false}' ) + ;; + opencode) + opencode run --auto --dir "$WORKTREE" "$prompt" + ;; + esac +} + # Leave no state in the user's repo: remove the worktree, then (it shares the common git dir) the # local autofix branch and any filter-branch backup ref. On success the branch lives on origin; on # failure this is a throwaway attempt, so deleting the local ref is intended. @@ -70,15 +148,15 @@ log ">> creating worktree $WORKTREE (detached on origin/$BRANCH)" git -C "$REPO_ROOT" worktree add --detach "$WORKTREE" "origin/$BRANCH" log ">> installing dependencies" -( cd "$WORKTREE" && CYCLONEDDS_HOME=/opt/cyclonedds uv sync --all-extras --all-groups ) +( cd "$WORKTREE" && uv sync --extra all --all-groups ) -log ">> running scan agent" +log ">> running scan agent ($AGENT)" # In the detached worktree the bare local ref may not exist, so the template's # `git diff main...$$BRANCH$$` is pointed at origin/. scan_prompt="$(cat "$SCAN_TEMPLATE")" scan_prompt="${scan_prompt//"$RULES_PLACEHOLDER"/$(cat "$RULES_FILE")}" scan_prompt="${scan_prompt//"$PLACEHOLDER"/origin/$BRANCH}" -if ! ( cd "$WORKTREE" && claude -p "$scan_prompt" --dangerously-skip-permissions ); then +if ! run_scan_agent "$scan_prompt"; then err "scan agent failed" exit 1 fi @@ -108,12 +186,11 @@ log ">> autofix branch: $AUTOFIX_BRANCH" BASE_SHA="$(git -C "$WORKTREE" rev-parse HEAD)" git -C "$WORKTREE" checkout -b "$AUTOFIX_BRANCH" -log ">> running fix agent" +log ">> running fix agent ($AGENT)" fix_prompt="$(cat "$FIX_TEMPLATE")" fix_prompt="${fix_prompt//"$PLACEHOLDER"/$BRANCH}" -if ! ( cd "$WORKTREE" && claude -p "$fix_prompt" \ - --dangerously-skip-permissions \ - --settings '{"includeCoAuthoredBy": false}' ); then +fix_prompt="${fix_prompt//"$AUTOFIX_PLACEHOLDER"/$AUTOFIX_BRANCH}" +if ! run_fix_agent "$fix_prompt"; then err "fix agent failed" exit 1 fi @@ -135,16 +212,16 @@ if [[ "$n_commits" -eq 0 ]]; then fi log ">> fix agent made $n_commits commit(s)" -# Safety net: --settings includeCoAuthoredBy=false is the primary guard, but --print silently ignores -# an invalid settings string, so mechanically strip any attribution lines from the new commits and -# verify nothing slipped through. +# Safety net: Claude's includeCoAuthoredBy=false is the primary guard for Claude, but settings can be +# ignored or future agents may add their own trailer, so mechanically strip attribution lines from the +# new commits and verify nothing slipped through. log ">> stripping any agent attribution from commit messages" FILTER_BRANCH_SQUELCH_WARNING=1 git -C "$WORKTREE" filter-branch -f --msg-filter \ - 'grep -viE "^(Co-authored-by:|Generated with \[Claude Code\])|🤖"' \ + 'grep -viE "^(Co-authored-by:|Generated with .*(Claude Code|OpenCode))|🤖"' \ -- "$BASE_SHA"..HEAD if git -C "$WORKTREE" log --format='%B' "$BASE_SHA"..HEAD \ - | grep -qiE 'co-authored-by:|generated with \[claude code\]|🤖'; then + | grep -qiE 'co-authored-by:|generated with .*(claude code|opencode)|🤖'; then err "agent attribution survived strip; aborting." exit 1 fi diff --git a/misc/auto-fixes/fix_template.md b/misc/auto-fixes/fix_template.md index a7f9084d95..a37ce3d3da 100644 --- a/misc/auto-fixes/fix_template.md +++ b/misc/auto-fixes/fix_template.md @@ -1,5 +1,5 @@ You are fixing the issues recorded in `issues.ignore.md` in this working tree. The branch under -review is $$BRANCH$$; you are on a fresh branch `$$BRANCH$$-autofixes` whose tip matches that +review is $$BRANCH$$; you are on a fresh branch `$$AUTOFIX_BRANCH$$` whose tip matches that branch. A pull request back into $$BRANCH$$ will be opened from your commits. Read `issues.ignore.md` and fix every issue it lists, following the repo's existing conventions. From 67a234510dab782928494213d42b74640d34a0d2 Mon Sep 17 00:00:00 2001 From: cc <55869557+TomCC7@users.noreply.github.com> Date: Thu, 2 Jul 2026 16:06:28 -0700 Subject: [PATCH 2/4] Apply suggestion from @TomCC7 --- misc/auto-fixes/fix_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/auto-fixes/fix_template.md b/misc/auto-fixes/fix_template.md index a37ce3d3da..a7f9084d95 100644 --- a/misc/auto-fixes/fix_template.md +++ b/misc/auto-fixes/fix_template.md @@ -1,5 +1,5 @@ You are fixing the issues recorded in `issues.ignore.md` in this working tree. The branch under -review is $$BRANCH$$; you are on a fresh branch `$$AUTOFIX_BRANCH$$` whose tip matches that +review is $$BRANCH$$; you are on a fresh branch `$$BRANCH$$-autofixes` whose tip matches that branch. A pull request back into $$BRANCH$$ will be opened from your commits. Read `issues.ignore.md` and fix every issue it lists, following the repo's existing conventions. From 803d180d858f58fb4a43401b443aeb274c85e6ad Mon Sep 17 00:00:00 2001 From: cc Date: Thu, 2 Jul 2026 16:09:33 -0700 Subject: [PATCH 3/4] fix: keep attribution filtering Claude-specific --- misc/auto-fixes/auto-fix.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/misc/auto-fixes/auto-fix.sh b/misc/auto-fixes/auto-fix.sh index 078aaf1459..4c5de7db72 100755 --- a/misc/auto-fixes/auto-fix.sh +++ b/misc/auto-fixes/auto-fix.sh @@ -212,16 +212,16 @@ if [[ "$n_commits" -eq 0 ]]; then fi log ">> fix agent made $n_commits commit(s)" -# Safety net: Claude's includeCoAuthoredBy=false is the primary guard for Claude, but settings can be -# ignored or future agents may add their own trailer, so mechanically strip attribution lines from the -# new commits and verify nothing slipped through. +# Safety net: --settings includeCoAuthoredBy=false is the primary guard, but --print silently ignores +# an invalid settings string, so mechanically strip any attribution lines from the new commits and +# verify nothing slipped through. log ">> stripping any agent attribution from commit messages" FILTER_BRANCH_SQUELCH_WARNING=1 git -C "$WORKTREE" filter-branch -f --msg-filter \ - 'grep -viE "^(Co-authored-by:|Generated with .*(Claude Code|OpenCode))|🤖"' \ + 'grep -viE "^(Co-authored-by:|Generated with \[Claude Code\])|🤖"' \ -- "$BASE_SHA"..HEAD if git -C "$WORKTREE" log --format='%B' "$BASE_SHA"..HEAD \ - | grep -qiE 'co-authored-by:|generated with .*(claude code|opencode)|🤖'; then + | grep -qiE 'co-authored-by:|generated with \[claude code\]|🤖'; then err "agent attribution survived strip; aborting." exit 1 fi From 528cb3697b24af01a5c8c216f4e7d9c88547662c Mon Sep 17 00:00:00 2001 From: cc Date: Thu, 2 Jul 2026 16:24:59 -0700 Subject: [PATCH 4/4] fix: scan autofix branch against origin main --- misc/auto-fixes/auto-fix.sh | 2 +- misc/auto-fixes/scan_template.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/misc/auto-fixes/auto-fix.sh b/misc/auto-fixes/auto-fix.sh index 4c5de7db72..9ff6d0d893 100755 --- a/misc/auto-fixes/auto-fix.sh +++ b/misc/auto-fixes/auto-fix.sh @@ -152,7 +152,7 @@ log ">> installing dependencies" log ">> running scan agent ($AGENT)" # In the detached worktree the bare local ref may not exist, so the template's -# `git diff main...$$BRANCH$$` is pointed at origin/. +# `git diff origin/main...$$BRANCH$$` is pointed at origin/. scan_prompt="$(cat "$SCAN_TEMPLATE")" scan_prompt="${scan_prompt//"$RULES_PLACEHOLDER"/$(cat "$RULES_FILE")}" scan_prompt="${scan_prompt//"$PLACEHOLDER"/origin/$BRANCH}" diff --git a/misc/auto-fixes/scan_template.md b/misc/auto-fixes/scan_template.md index e8b8112e2e..cbefeb1ee7 100644 --- a/misc/auto-fixes/scan_template.md +++ b/misc/auto-fixes/scan_template.md @@ -1,6 +1,6 @@ I want you to automatically fix the following issues. First, scan the current branch and identify any code which breaks the following. Write down the issues to fix into a file called `issues.ignore.md`. -The branch is $$BRANCH$$. You can perform a diff with `git diff main...$$BRANCH$$ -- . ':(exclude)*.lock' ':(exclude)uv.lock' ':(exclude)package-lock.json' ':(exclude)yarn.lock' ':(exclude)pnpm-lock.yaml' ':(exclude)Cargo.lock' ':(exclude)*.pdf' ':(exclude)*.png' ':(exclude)*.jpg' +The branch is $$BRANCH$$. You can perform a diff with `git diff origin/main...$$BRANCH$$ -- . ':(exclude)*.lock' ':(exclude)uv.lock' ':(exclude)package-lock.json' ':(exclude)yarn.lock' ':(exclude)pnpm-lock.yaml' ':(exclude)Cargo.lock' ':(exclude)*.pdf' ':(exclude)*.png' ':(exclude)*.jpg' ` The `issues.ignore.md` file will be used as the input for a second agent which will fix the issues which have been identified. It's okay if there are no issues to fix. Just leave the file empty or don't create it at all.