@imdeadpool/guardex 5.0.0 → 5.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -13
- package/bin/multiagent-safety.js +307 -7
- package/package.json +1 -1
- package/templates/AGENTS.multiagent-safety.md +7 -1
- package/templates/codex/skills/guardex/SKILL.md +5 -0
- package/templates/githooks/pre-commit +22 -0
- package/templates/scripts/agent-branch-finish.sh +81 -31
- package/templates/scripts/agent-worktree-prune.sh +128 -17
- package/templates/scripts/codex-agent.sh +336 -3
|
@@ -50,9 +50,31 @@ case "$codex_require_agent_branch" in
|
|
|
50
50
|
*) should_require_codex_agent_branch=1 ;;
|
|
51
51
|
esac
|
|
52
52
|
|
|
53
|
+
is_codex_managed_only_commit_on_protected=0
|
|
54
|
+
if [[ "$is_codex_session" == "1" && "$is_protected_branch" == "1" ]]; then
|
|
55
|
+
deleted_paths="$(git diff --cached --name-only --diff-filter=D)"
|
|
56
|
+
staged_paths="$(git diff --cached --name-only --diff-filter=ACMRTUXB)"
|
|
57
|
+
if [[ -z "$deleted_paths" && -n "$staged_paths" ]]; then
|
|
58
|
+
managed_only=1
|
|
59
|
+
while IFS= read -r staged_path; do
|
|
60
|
+
case "$staged_path" in
|
|
61
|
+
AGENTS.md|.gitignore) ;;
|
|
62
|
+
*) managed_only=0; break ;;
|
|
63
|
+
esac
|
|
64
|
+
done <<< "$staged_paths"
|
|
65
|
+
if [[ "$managed_only" == "1" ]]; then
|
|
66
|
+
is_codex_managed_only_commit_on_protected=1
|
|
67
|
+
fi
|
|
68
|
+
fi
|
|
69
|
+
fi
|
|
70
|
+
|
|
53
71
|
if [[ "$should_require_codex_agent_branch" == "1" && "${MUSAFETY_ALLOW_CODEX_ON_NON_AGENT:-0}" != "1" ]]; then
|
|
54
72
|
if [[ "$is_codex_session" == "1" && "$branch" != agent/* ]]; then
|
|
55
73
|
if [[ "$is_protected_branch" == "1" ]]; then
|
|
74
|
+
if [[ "$is_codex_managed_only_commit_on_protected" == "1" ]]; then
|
|
75
|
+
exit 0
|
|
76
|
+
fi
|
|
77
|
+
|
|
56
78
|
cat >&2 <<'MSG'
|
|
57
79
|
[guardex-preedit-guard] Codex edit/commit detected on a protected branch.
|
|
58
80
|
GuardeX requires Codex work to run from an isolated agent/* branch.
|
|
@@ -5,9 +5,26 @@ BASE_BRANCH=""
|
|
|
5
5
|
BASE_BRANCH_EXPLICIT=0
|
|
6
6
|
SOURCE_BRANCH=""
|
|
7
7
|
PUSH_ENABLED=1
|
|
8
|
-
DELETE_REMOTE_BRANCH=
|
|
8
|
+
DELETE_REMOTE_BRANCH=0
|
|
9
|
+
DELETE_REMOTE_BRANCH_EXPLICIT=0
|
|
9
10
|
MERGE_MODE="auto"
|
|
10
11
|
GH_BIN="${MUSAFETY_GH_BIN:-gh}"
|
|
12
|
+
CLEANUP_AFTER_MERGE_RAW="${MUSAFETY_FINISH_CLEANUP:-false}"
|
|
13
|
+
|
|
14
|
+
normalize_bool() {
|
|
15
|
+
local raw="${1:-}"
|
|
16
|
+
local fallback="${2:-0}"
|
|
17
|
+
local lowered
|
|
18
|
+
lowered="$(printf '%s' "$raw" | tr '[:upper:]' '[:lower:]')"
|
|
19
|
+
case "$lowered" in
|
|
20
|
+
1|true|yes|on) printf '1' ;;
|
|
21
|
+
0|false|no|off) printf '0' ;;
|
|
22
|
+
'') printf '%s' "$fallback" ;;
|
|
23
|
+
*) printf '%s' "$fallback" ;;
|
|
24
|
+
esac
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
CLEANUP_AFTER_MERGE="$(normalize_bool "$CLEANUP_AFTER_MERGE_RAW" "0")"
|
|
11
28
|
|
|
12
29
|
while [[ $# -gt 0 ]]; do
|
|
13
30
|
case "$1" in
|
|
@@ -26,6 +43,20 @@ while [[ $# -gt 0 ]]; do
|
|
|
26
43
|
;;
|
|
27
44
|
--keep-remote-branch)
|
|
28
45
|
DELETE_REMOTE_BRANCH=0
|
|
46
|
+
DELETE_REMOTE_BRANCH_EXPLICIT=1
|
|
47
|
+
shift
|
|
48
|
+
;;
|
|
49
|
+
--delete-remote-branch)
|
|
50
|
+
DELETE_REMOTE_BRANCH=1
|
|
51
|
+
DELETE_REMOTE_BRANCH_EXPLICIT=1
|
|
52
|
+
shift
|
|
53
|
+
;;
|
|
54
|
+
--cleanup)
|
|
55
|
+
CLEANUP_AFTER_MERGE=1
|
|
56
|
+
shift
|
|
57
|
+
;;
|
|
58
|
+
--no-cleanup)
|
|
59
|
+
CLEANUP_AFTER_MERGE=0
|
|
29
60
|
shift
|
|
30
61
|
;;
|
|
31
62
|
--mode)
|
|
@@ -42,12 +73,16 @@ while [[ $# -gt 0 ]]; do
|
|
|
42
73
|
;;
|
|
43
74
|
*)
|
|
44
75
|
echo "[agent-branch-finish] Unknown argument: $1" >&2
|
|
45
|
-
echo "Usage: $0 [--base <branch>] [--branch <branch>] [--no-push] [--keep-remote-branch] [--mode auto|direct|pr|--via-pr|--direct-only]" >&2
|
|
76
|
+
echo "Usage: $0 [--base <branch>] [--branch <branch>] [--no-push] [--cleanup|--no-cleanup] [--keep-remote-branch|--delete-remote-branch] [--mode auto|direct|pr|--via-pr|--direct-only]" >&2
|
|
46
77
|
exit 1
|
|
47
78
|
;;
|
|
48
79
|
esac
|
|
49
80
|
done
|
|
50
81
|
|
|
82
|
+
if [[ "$CLEANUP_AFTER_MERGE" -eq 1 && "$DELETE_REMOTE_BRANCH_EXPLICIT" -eq 0 ]]; then
|
|
83
|
+
DELETE_REMOTE_BRANCH=1
|
|
84
|
+
fi
|
|
85
|
+
|
|
51
86
|
case "$MERGE_MODE" in
|
|
52
87
|
auto|direct|pr) ;;
|
|
53
88
|
*)
|
|
@@ -347,43 +382,58 @@ if [[ -x "${repo_root}/scripts/agent-file-locks.py" ]]; then
|
|
|
347
382
|
python3 "${repo_root}/scripts/agent-file-locks.py" release --branch "$SOURCE_BRANCH" >/dev/null 2>&1 || true
|
|
348
383
|
fi
|
|
349
384
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
385
|
+
base_worktree="$(get_worktree_for_branch "$BASE_BRANCH")"
|
|
386
|
+
if [[ -n "$base_worktree" ]] && is_clean_worktree "$base_worktree" && [[ "$PUSH_ENABLED" -eq 1 ]]; then
|
|
387
|
+
git -C "$base_worktree" pull --ff-only origin "$BASE_BRANCH" >/dev/null 2>&1 || true
|
|
388
|
+
fi
|
|
389
|
+
|
|
390
|
+
if [[ "$CLEANUP_AFTER_MERGE" -eq 1 ]]; then
|
|
391
|
+
if [[ "$source_worktree" == "$repo_root" ]]; then
|
|
392
|
+
if is_clean_worktree "$source_worktree"; then
|
|
393
|
+
git -C "$source_worktree" checkout "$BASE_BRANCH" >/dev/null 2>&1 || true
|
|
394
|
+
if [[ "$PUSH_ENABLED" -eq 1 ]] && git -C "$repo_root" show-ref --verify --quiet "refs/remotes/origin/${BASE_BRANCH}"; then
|
|
395
|
+
git -C "$source_worktree" pull --ff-only origin "$BASE_BRANCH" >/dev/null 2>&1 || true
|
|
396
|
+
fi
|
|
355
397
|
fi
|
|
398
|
+
elif [[ "$source_worktree" == "$current_worktree" && "$source_worktree" == "${repo_root}/.omx/agent-worktrees"/* ]]; then
|
|
399
|
+
git -C "$source_worktree" checkout --detach >/dev/null 2>&1 || true
|
|
356
400
|
fi
|
|
357
|
-
elif [[ "$source_worktree" == "$current_worktree" && "$source_worktree" == "${repo_root}/.omx/agent-worktrees"/* ]]; then
|
|
358
|
-
git -C "$source_worktree" checkout --detach >/dev/null 2>&1 || true
|
|
359
|
-
fi
|
|
360
401
|
|
|
361
|
-
if [[ "$source_worktree" != "$current_worktree" && "$source_worktree" == "${repo_root}/.omx/agent-worktrees"/* ]]; then
|
|
362
|
-
|
|
363
|
-
fi
|
|
402
|
+
if [[ "$source_worktree" != "$current_worktree" && "$source_worktree" == "${repo_root}/.omx/agent-worktrees"/* ]]; then
|
|
403
|
+
git -C "$repo_root" worktree remove "$source_worktree" --force >/dev/null 2>&1 || true
|
|
404
|
+
fi
|
|
364
405
|
|
|
365
|
-
git -C "$repo_root" branch -d "$SOURCE_BRANCH"
|
|
406
|
+
git -C "$repo_root" branch -d "$SOURCE_BRANCH"
|
|
366
407
|
|
|
367
|
-
if [[ "$PUSH_ENABLED" -eq 1 && "$DELETE_REMOTE_BRANCH" -eq 1 ]]; then
|
|
368
|
-
|
|
369
|
-
|
|
408
|
+
if [[ "$PUSH_ENABLED" -eq 1 && "$DELETE_REMOTE_BRANCH" -eq 1 ]]; then
|
|
409
|
+
if git -C "$repo_root" ls-remote --exit-code --heads origin "$SOURCE_BRANCH" >/dev/null 2>&1; then
|
|
410
|
+
git -C "$repo_root" push origin --delete "$SOURCE_BRANCH"
|
|
411
|
+
fi
|
|
370
412
|
fi
|
|
371
|
-
fi
|
|
372
413
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
414
|
+
if [[ -x "${repo_root}/scripts/agent-worktree-prune.sh" ]]; then
|
|
415
|
+
prune_args=(--base "$BASE_BRANCH" --delete-branches)
|
|
416
|
+
if [[ "$DELETE_REMOTE_BRANCH" -eq 1 ]]; then
|
|
417
|
+
prune_args+=(--delete-remote-branches)
|
|
418
|
+
fi
|
|
419
|
+
if ! bash "${repo_root}/scripts/agent-worktree-prune.sh" "${prune_args[@]}"; then
|
|
420
|
+
echo "[agent-branch-finish] Warning: automatic worktree prune failed." >&2
|
|
421
|
+
echo "[agent-branch-finish] You can run manual cleanup: bash scripts/agent-worktree-prune.sh --base ${BASE_BRANCH} --delete-branches" >&2
|
|
422
|
+
fi
|
|
423
|
+
fi
|
|
377
424
|
|
|
378
|
-
|
|
379
|
-
if
|
|
380
|
-
echo "[agent-branch-finish]
|
|
381
|
-
echo "[agent-branch-finish]
|
|
425
|
+
echo "[agent-branch-finish] Merged '${SOURCE_BRANCH}' into '${BASE_BRANCH}' via ${merge_status} flow and cleaned source branch/worktree."
|
|
426
|
+
if [[ "$source_worktree" == "$current_worktree" && "$source_worktree" == "${repo_root}/.omx/agent-worktrees"/* ]]; then
|
|
427
|
+
echo "[agent-branch-finish] Current worktree '${source_worktree}' still exists because it is the active shell cwd." >&2
|
|
428
|
+
echo "[agent-branch-finish] Leave this directory, then run: bash scripts/agent-worktree-prune.sh --base ${BASE_BRANCH} --delete-branches" >&2
|
|
429
|
+
fi
|
|
430
|
+
else
|
|
431
|
+
if [[ -x "${repo_root}/scripts/agent-worktree-prune.sh" ]]; then
|
|
432
|
+
if ! bash "${repo_root}/scripts/agent-worktree-prune.sh" --base "$BASE_BRANCH"; then
|
|
433
|
+
echo "[agent-branch-finish] Warning: temporary worktree prune failed." >&2
|
|
434
|
+
fi
|
|
382
435
|
fi
|
|
383
|
-
fi
|
|
384
436
|
|
|
385
|
-
echo "[agent-branch-finish] Merged '${SOURCE_BRANCH}' into '${BASE_BRANCH}' via ${merge_status} flow and
|
|
386
|
-
|
|
387
|
-
echo "[agent-branch-finish] Current worktree '${source_worktree}' still exists because it is the active shell cwd." >&2
|
|
388
|
-
echo "[agent-branch-finish] Leave this directory, then run: bash scripts/agent-worktree-prune.sh --base ${BASE_BRANCH}" >&2
|
|
437
|
+
echo "[agent-branch-finish] Merged '${SOURCE_BRANCH}' into '${BASE_BRANCH}' via ${merge_status} flow and kept source branch/worktree."
|
|
438
|
+
echo "[agent-branch-finish] Cleanup later with: bash scripts/agent-worktree-prune.sh --base ${BASE_BRANCH} --delete-branches --delete-remote-branches"
|
|
389
439
|
fi
|
|
@@ -1,22 +1,48 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
|
-
BASE_BRANCH="
|
|
4
|
+
BASE_BRANCH="${MUSAFETY_BASE_BRANCH:-}"
|
|
5
|
+
BASE_BRANCH_EXPLICIT=0
|
|
5
6
|
DRY_RUN=0
|
|
7
|
+
FORCE_DIRTY=0
|
|
8
|
+
DELETE_BRANCHES=0
|
|
9
|
+
DELETE_REMOTE_BRANCHES=0
|
|
10
|
+
TARGET_BRANCH=""
|
|
11
|
+
|
|
12
|
+
if [[ -n "$BASE_BRANCH" ]]; then
|
|
13
|
+
BASE_BRANCH_EXPLICIT=1
|
|
14
|
+
fi
|
|
6
15
|
|
|
7
16
|
while [[ $# -gt 0 ]]; do
|
|
8
17
|
case "$1" in
|
|
9
18
|
--base)
|
|
10
|
-
BASE_BRANCH="${2:-
|
|
19
|
+
BASE_BRANCH="${2:-}"
|
|
20
|
+
BASE_BRANCH_EXPLICIT=1
|
|
11
21
|
shift 2
|
|
12
22
|
;;
|
|
13
23
|
--dry-run)
|
|
14
24
|
DRY_RUN=1
|
|
15
25
|
shift
|
|
16
26
|
;;
|
|
27
|
+
--force-dirty)
|
|
28
|
+
FORCE_DIRTY=1
|
|
29
|
+
shift
|
|
30
|
+
;;
|
|
31
|
+
--delete-branches)
|
|
32
|
+
DELETE_BRANCHES=1
|
|
33
|
+
shift
|
|
34
|
+
;;
|
|
35
|
+
--delete-remote-branches)
|
|
36
|
+
DELETE_REMOTE_BRANCHES=1
|
|
37
|
+
shift
|
|
38
|
+
;;
|
|
39
|
+
--branch)
|
|
40
|
+
TARGET_BRANCH="${2:-}"
|
|
41
|
+
shift 2
|
|
42
|
+
;;
|
|
17
43
|
*)
|
|
18
44
|
echo "[agent-worktree-prune] Unknown argument: $1" >&2
|
|
19
|
-
echo "Usage: $0 [--base <branch>] [--dry-run]" >&2
|
|
45
|
+
echo "Usage: $0 [--base <branch>] [--dry-run] [--force-dirty] [--delete-branches] [--delete-remote-branches] [--branch <agent/...>]" >&2
|
|
20
46
|
exit 1
|
|
21
47
|
;;
|
|
22
48
|
esac
|
|
@@ -31,6 +57,51 @@ repo_root="$(git rev-parse --show-toplevel)"
|
|
|
31
57
|
current_pwd="$(pwd -P)"
|
|
32
58
|
worktree_root="${repo_root}/.omx/agent-worktrees"
|
|
33
59
|
|
|
60
|
+
resolve_base_branch() {
|
|
61
|
+
local configured=""
|
|
62
|
+
local current=""
|
|
63
|
+
|
|
64
|
+
configured="$(git -C "$repo_root" config --get multiagent.baseBranch || true)"
|
|
65
|
+
if [[ -n "$configured" ]] && git -C "$repo_root" show-ref --verify --quiet "refs/heads/${configured}"; then
|
|
66
|
+
printf '%s' "$configured"
|
|
67
|
+
return 0
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
current="$(git -C "$repo_root" rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
|
|
71
|
+
if [[ -n "$current" && "$current" != "HEAD" ]] && git -C "$repo_root" show-ref --verify --quiet "refs/heads/${current}"; then
|
|
72
|
+
printf '%s' "$current"
|
|
73
|
+
return 0
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
for fallback in main dev; do
|
|
77
|
+
if git -C "$repo_root" show-ref --verify --quiet "refs/heads/${fallback}"; then
|
|
78
|
+
printf '%s' "$fallback"
|
|
79
|
+
return 0
|
|
80
|
+
fi
|
|
81
|
+
done
|
|
82
|
+
|
|
83
|
+
printf '%s' ""
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if [[ "$BASE_BRANCH_EXPLICIT" -eq 1 && -z "$BASE_BRANCH" ]]; then
|
|
87
|
+
echo "[agent-worktree-prune] --base requires a non-empty branch name." >&2
|
|
88
|
+
exit 1
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
if [[ -n "$TARGET_BRANCH" && "$TARGET_BRANCH" != agent/* ]]; then
|
|
92
|
+
echo "[agent-worktree-prune] --branch must reference an agent/* branch: ${TARGET_BRANCH}" >&2
|
|
93
|
+
exit 1
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
if [[ "$BASE_BRANCH_EXPLICIT" -eq 0 ]]; then
|
|
97
|
+
BASE_BRANCH="$(resolve_base_branch)"
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
if [[ -z "$BASE_BRANCH" ]]; then
|
|
101
|
+
echo "[agent-worktree-prune] Unable to infer base branch. Pass --base <branch>." >&2
|
|
102
|
+
exit 1
|
|
103
|
+
fi
|
|
104
|
+
|
|
34
105
|
if ! git -C "$repo_root" show-ref --verify --quiet "refs/heads/${BASE_BRANCH}"; then
|
|
35
106
|
echo "[agent-worktree-prune] Base branch not found: ${BASE_BRANCH}" >&2
|
|
36
107
|
exit 1
|
|
@@ -49,9 +120,17 @@ branch_has_worktree() {
|
|
|
49
120
|
git -C "$repo_root" worktree list --porcelain | grep -q "^branch refs/heads/${branch}$"
|
|
50
121
|
}
|
|
51
122
|
|
|
123
|
+
is_clean_worktree() {
|
|
124
|
+
local wt="$1"
|
|
125
|
+
git -C "$wt" diff --quiet -- . ":(exclude).omx/state/agent-file-locks.json" \
|
|
126
|
+
&& git -C "$wt" diff --cached --quiet -- . ":(exclude).omx/state/agent-file-locks.json" \
|
|
127
|
+
&& [[ -z "$(git -C "$wt" ls-files --others --exclude-standard)" ]]
|
|
128
|
+
}
|
|
129
|
+
|
|
52
130
|
removed_worktrees=0
|
|
53
131
|
removed_branches=0
|
|
54
132
|
skipped_active=0
|
|
133
|
+
skipped_dirty=0
|
|
55
134
|
|
|
56
135
|
process_entry() {
|
|
57
136
|
local wt="$1"
|
|
@@ -65,6 +144,10 @@ process_entry() {
|
|
|
65
144
|
branch="${branch_ref#refs/heads/}"
|
|
66
145
|
fi
|
|
67
146
|
|
|
147
|
+
if [[ -n "$TARGET_BRANCH" && "$branch" != "$TARGET_BRANCH" ]]; then
|
|
148
|
+
return
|
|
149
|
+
fi
|
|
150
|
+
|
|
68
151
|
if [[ "$wt" == "$current_pwd" ]]; then
|
|
69
152
|
skipped_active=$((skipped_active + 1))
|
|
70
153
|
echo "[agent-worktree-prune] Skipping active cwd worktree: ${wt}"
|
|
@@ -79,7 +162,9 @@ process_entry() {
|
|
|
79
162
|
remove_reason="missing-branch"
|
|
80
163
|
elif [[ "$branch" == agent/* ]]; then
|
|
81
164
|
if git -C "$repo_root" merge-base --is-ancestor "$branch" "$BASE_BRANCH"; then
|
|
82
|
-
|
|
165
|
+
if [[ "$DELETE_BRANCHES" -eq 1 ]]; then
|
|
166
|
+
remove_reason="merged-agent-branch"
|
|
167
|
+
fi
|
|
83
168
|
fi
|
|
84
169
|
elif [[ "$branch" == __agent_integrate_* || "$branch" == __source-probe-* ]]; then
|
|
85
170
|
remove_reason="temporary-worktree"
|
|
@@ -89,6 +174,12 @@ process_entry() {
|
|
|
89
174
|
return
|
|
90
175
|
fi
|
|
91
176
|
|
|
177
|
+
if [[ "$FORCE_DIRTY" -ne 1 ]] && ! is_clean_worktree "$wt"; then
|
|
178
|
+
skipped_dirty=$((skipped_dirty + 1))
|
|
179
|
+
echo "[agent-worktree-prune] Skipping dirty worktree (${remove_reason}): ${wt}"
|
|
180
|
+
return
|
|
181
|
+
fi
|
|
182
|
+
|
|
92
183
|
echo "[agent-worktree-prune] Removing worktree (${remove_reason}): ${wt}"
|
|
93
184
|
run_cmd git -C "$repo_root" worktree remove "$wt" --force
|
|
94
185
|
removed_worktrees=$((removed_worktrees + 1))
|
|
@@ -98,10 +189,16 @@ process_entry() {
|
|
|
98
189
|
fi
|
|
99
190
|
|
|
100
191
|
if git -C "$repo_root" show-ref --verify --quiet "refs/heads/${branch}" && ! branch_has_worktree "$branch"; then
|
|
101
|
-
if [[ "$branch" == agent/* ]]; then
|
|
192
|
+
if [[ "$branch" == agent/* && "$DELETE_BRANCHES" -eq 1 ]]; then
|
|
102
193
|
if run_cmd git -C "$repo_root" branch -d "$branch" >/dev/null 2>&1; then
|
|
103
194
|
removed_branches=$((removed_branches + 1))
|
|
104
195
|
echo "[agent-worktree-prune] Deleted merged branch: ${branch}"
|
|
196
|
+
if [[ "$DELETE_REMOTE_BRANCHES" -eq 1 ]]; then
|
|
197
|
+
if git -C "$repo_root" ls-remote --exit-code --heads origin "$branch" >/dev/null 2>&1; then
|
|
198
|
+
run_cmd git -C "$repo_root" push origin --delete "$branch" >/dev/null 2>&1 || true
|
|
199
|
+
echo "[agent-worktree-prune] Deleted merged remote branch: ${branch}"
|
|
200
|
+
fi
|
|
201
|
+
fi
|
|
105
202
|
fi
|
|
106
203
|
elif [[ "$branch" == __agent_integrate_* || "$branch" == __source-probe-* ]]; then
|
|
107
204
|
run_cmd git -C "$repo_root" branch -D "$branch" >/dev/null 2>&1 || true
|
|
@@ -134,22 +231,36 @@ done < <(git -C "$repo_root" worktree list --porcelain)
|
|
|
134
231
|
|
|
135
232
|
process_entry "$current_wt" "$current_branch_ref"
|
|
136
233
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if git -C "$repo_root" merge-base --is-ancestor "$branch" "$BASE_BRANCH"; then
|
|
143
|
-
if run_cmd git -C "$repo_root" branch -d "$branch" >/dev/null 2>&1; then
|
|
144
|
-
removed_branches=$((removed_branches + 1))
|
|
145
|
-
echo "[agent-worktree-prune] Deleted stale merged branch: ${branch}"
|
|
234
|
+
if [[ "$DELETE_BRANCHES" -eq 1 ]]; then
|
|
235
|
+
while IFS= read -r branch; do
|
|
236
|
+
[[ -z "$branch" ]] && continue
|
|
237
|
+
if [[ -n "$TARGET_BRANCH" && "$branch" != "$TARGET_BRANCH" ]]; then
|
|
238
|
+
continue
|
|
146
239
|
fi
|
|
147
|
-
|
|
148
|
-
|
|
240
|
+
if branch_has_worktree "$branch"; then
|
|
241
|
+
continue
|
|
242
|
+
fi
|
|
243
|
+
if git -C "$repo_root" merge-base --is-ancestor "$branch" "$BASE_BRANCH"; then
|
|
244
|
+
if run_cmd git -C "$repo_root" branch -d "$branch" >/dev/null 2>&1; then
|
|
245
|
+
removed_branches=$((removed_branches + 1))
|
|
246
|
+
echo "[agent-worktree-prune] Deleted stale merged branch: ${branch}"
|
|
247
|
+
if [[ "$DELETE_REMOTE_BRANCHES" -eq 1 ]]; then
|
|
248
|
+
if git -C "$repo_root" ls-remote --exit-code --heads origin "$branch" >/dev/null 2>&1; then
|
|
249
|
+
run_cmd git -C "$repo_root" push origin --delete "$branch" >/dev/null 2>&1 || true
|
|
250
|
+
echo "[agent-worktree-prune] Deleted stale merged remote branch: ${branch}"
|
|
251
|
+
fi
|
|
252
|
+
fi
|
|
253
|
+
fi
|
|
254
|
+
fi
|
|
255
|
+
done < <(git -C "$repo_root" for-each-ref --format='%(refname:short)' refs/heads/agent)
|
|
256
|
+
fi
|
|
149
257
|
|
|
150
258
|
run_cmd git -C "$repo_root" worktree prune
|
|
151
259
|
|
|
152
|
-
echo "[agent-worktree-prune] Summary: removed_worktrees=${removed_worktrees}, removed_branches=${removed_branches}, skipped_active=${skipped_active}"
|
|
260
|
+
echo "[agent-worktree-prune] Summary: base=${BASE_BRANCH}, removed_worktrees=${removed_worktrees}, removed_branches=${removed_branches}, skipped_active=${skipped_active}, skipped_dirty=${skipped_dirty}"
|
|
153
261
|
if [[ "$skipped_active" -gt 0 ]]; then
|
|
154
262
|
echo "[agent-worktree-prune] Tip: leave active agent worktree directories, then run this command again for full cleanup." >&2
|
|
155
263
|
fi
|
|
264
|
+
if [[ "$skipped_dirty" -gt 0 ]]; then
|
|
265
|
+
echo "[agent-worktree-prune] Tip: dirty worktrees were preserved. Clean/finish them first, or pass --force-dirty to remove anyway." >&2
|
|
266
|
+
fi
|