diff --git a/scripts/agent-branch-finish.sh b/scripts/agent-branch-finish.sh index 7a84f8d..a87cec4 100755 --- a/scripts/agent-branch-finish.sh +++ b/scripts/agent-branch-finish.sh @@ -172,9 +172,25 @@ if [[ "$should_require_sync" -eq 1 ]] && git -C "$repo_root" show-ref --verify - behind_count="${behind_count:-0}" if [[ "$behind_count" -gt 0 ]]; then echo "[agent-sync-guard] Branch '${SOURCE_BRANCH}' is behind origin/${BASE_BRANCH} by ${behind_count} commit(s)." >&2 - echo "[agent-sync-guard] Run: musafety sync --base ${BASE_BRANCH}" >&2 - echo "[agent-sync-guard] Then retry: bash scripts/agent-branch-finish.sh --branch \"${SOURCE_BRANCH}\"" >&2 - exit 1 + echo "[agent-sync-guard] Auto-syncing '${SOURCE_BRANCH}' onto origin/${BASE_BRANCH} before finish..." >&2 + if ! git -C "$source_worktree" rebase "origin/${BASE_BRANCH}"; then + git_dir="$(git -C "$source_worktree" rev-parse --git-dir)" + rebase_active=0 + if [[ -e "${git_dir}/rebase-merge" || -e "${git_dir}/rebase-apply" ]]; then + rebase_active=1 + fi + + echo "[agent-sync-guard] Auto-sync failed while rebasing '${SOURCE_BRANCH}' onto origin/${BASE_BRANCH}." >&2 + if [[ "$rebase_active" -eq 1 ]]; then + echo "[agent-sync-guard] Resolve conflicts, then run: git -C \"$source_worktree\" rebase --continue" >&2 + echo "[agent-sync-guard] Or abort: git -C \"$source_worktree\" rebase --abort" >&2 + fi + exit 1 + fi + + behind_after="$(git -C "$repo_root" rev-list --left-right --count "${SOURCE_BRANCH}...origin/${BASE_BRANCH}" 2>/dev/null | awk '{print $2}')" + behind_after="${behind_after:-0}" + echo "[agent-sync-guard] Auto-sync complete (behind now: ${behind_after})." >&2 fi fi @@ -334,6 +350,9 @@ fi if [[ "$source_worktree" == "$repo_root" ]]; then if is_clean_worktree "$source_worktree"; then git -C "$source_worktree" checkout "$BASE_BRANCH" >/dev/null 2>&1 || true + if [[ "$PUSH_ENABLED" -eq 1 ]] && git -C "$repo_root" show-ref --verify --quiet "refs/remotes/origin/${BASE_BRANCH}"; then + git -C "$source_worktree" pull --ff-only origin "$BASE_BRANCH" >/dev/null 2>&1 || true + fi fi elif [[ "$source_worktree" == "$current_worktree" && "$source_worktree" == "${repo_root}/.omx/agent-worktrees"/* ]]; then git -C "$source_worktree" checkout --detach >/dev/null 2>&1 || true diff --git a/templates/scripts/agent-branch-finish.sh b/templates/scripts/agent-branch-finish.sh index 7a84f8d..a87cec4 100755 --- a/templates/scripts/agent-branch-finish.sh +++ b/templates/scripts/agent-branch-finish.sh @@ -172,9 +172,25 @@ if [[ "$should_require_sync" -eq 1 ]] && git -C "$repo_root" show-ref --verify - behind_count="${behind_count:-0}" if [[ "$behind_count" -gt 0 ]]; then echo "[agent-sync-guard] Branch '${SOURCE_BRANCH}' is behind origin/${BASE_BRANCH} by ${behind_count} commit(s)." >&2 - echo "[agent-sync-guard] Run: musafety sync --base ${BASE_BRANCH}" >&2 - echo "[agent-sync-guard] Then retry: bash scripts/agent-branch-finish.sh --branch \"${SOURCE_BRANCH}\"" >&2 - exit 1 + echo "[agent-sync-guard] Auto-syncing '${SOURCE_BRANCH}' onto origin/${BASE_BRANCH} before finish..." >&2 + if ! git -C "$source_worktree" rebase "origin/${BASE_BRANCH}"; then + git_dir="$(git -C "$source_worktree" rev-parse --git-dir)" + rebase_active=0 + if [[ -e "${git_dir}/rebase-merge" || -e "${git_dir}/rebase-apply" ]]; then + rebase_active=1 + fi + + echo "[agent-sync-guard] Auto-sync failed while rebasing '${SOURCE_BRANCH}' onto origin/${BASE_BRANCH}." >&2 + if [[ "$rebase_active" -eq 1 ]]; then + echo "[agent-sync-guard] Resolve conflicts, then run: git -C \"$source_worktree\" rebase --continue" >&2 + echo "[agent-sync-guard] Or abort: git -C \"$source_worktree\" rebase --abort" >&2 + fi + exit 1 + fi + + behind_after="$(git -C "$repo_root" rev-list --left-right --count "${SOURCE_BRANCH}...origin/${BASE_BRANCH}" 2>/dev/null | awk '{print $2}')" + behind_after="${behind_after:-0}" + echo "[agent-sync-guard] Auto-sync complete (behind now: ${behind_after})." >&2 fi fi @@ -334,6 +350,9 @@ fi if [[ "$source_worktree" == "$repo_root" ]]; then if is_clean_worktree "$source_worktree"; then git -C "$source_worktree" checkout "$BASE_BRANCH" >/dev/null 2>&1 || true + if [[ "$PUSH_ENABLED" -eq 1 ]] && git -C "$repo_root" show-ref --verify --quiet "refs/remotes/origin/${BASE_BRANCH}"; then + git -C "$source_worktree" pull --ff-only origin "$BASE_BRANCH" >/dev/null 2>&1 || true + fi fi elif [[ "$source_worktree" == "$current_worktree" && "$source_worktree" == "${repo_root}/.omx/agent-worktrees"/* ]]; then git -C "$source_worktree" checkout --detach >/dev/null 2>&1 || true diff --git a/test/install.test.js b/test/install.test.js index 953c371..526381e 100644 --- a/test/install.test.js +++ b/test/install.test.js @@ -814,7 +814,7 @@ test('pre-commit sync gate honors maxBehindCommits threshold', () => { assert.equal(commitAttempt.status, 0, commitAttempt.stderr || commitAttempt.stdout); }); -test('agent-branch-finish blocks when source branch is behind origin/dev', () => { +test('agent-branch-finish auto-syncs source branch when behind origin/dev', () => { const repoDir = initRepo(); seedCommit(repoDir); attachOriginRemote(repoDir); @@ -848,9 +848,17 @@ test('agent-branch-finish blocks when source branch is behind origin/dev', () => ['scripts/agent-branch-finish.sh', '--branch', 'agent/test-finish-sync-guard'], repoDir, ); - assert.equal(finish.status, 1, finish.stderr || finish.stdout); + assert.equal(finish.status, 0, finish.stderr || finish.stdout); assert.match(finish.stderr, /agent-sync-guard/); - assert.match(finish.stderr, /musafety sync --base dev/); + assert.match(finish.stderr, /Auto-syncing 'agent\/test-finish-sync-guard' onto origin\/dev before finish/); + assert.match(finish.stderr, /Auto-sync complete \(behind now: 0\)/); + assert.match( + finish.stdout, + /Merged 'agent\/test-finish-sync-guard' into 'dev' via direct flow and removed branch\./, + ); + + result = runCmd('git', ['show-ref', '--verify', '--quiet', 'refs/heads/agent/test-finish-sync-guard'], repoDir); + assert.notEqual(result.status, 0, 'agent branch should be deleted locally after finish'); }); test('agent-branch-finish pr mode continues cleanup when gh merge only fails local branch deletion', () => {