@imdeadpool/guardex 7.0.2 → 7.0.4
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 +22 -0
- package/package.json +1 -1
- package/templates/githooks/pre-commit +13 -8
- package/templates/githooks/pre-push +12 -0
- package/templates/scripts/agent-branch-start.sh +71 -57
package/README.md
CHANGED
|
@@ -373,6 +373,28 @@ npm pack --dry-run
|
|
|
373
373
|
|
|
374
374
|
## Release notes
|
|
375
375
|
|
|
376
|
+
### v7.0.4
|
|
377
|
+
|
|
378
|
+
- **Fixed: publish collision on npm.** Advanced the package metadata from `7.0.3` to `7.0.4` so `npm publish` no longer targets an already published version.
|
|
379
|
+
- **Changed: release-note sync for versioning rule.** Added this versioned entry in README in the same change as the package bump to keep publish metadata and release notes aligned.
|
|
380
|
+
|
|
381
|
+
### v7.0.3
|
|
382
|
+
|
|
383
|
+
- **Branch/worktree naming refactor.** `agent-branch-start.sh` now produces `agent/<role>/<task>-<YYYY-MM-DD>-<HH-MM>` instead of `agent/<role+account-email>/<snapshot-slug>-<task>-<cksum6>`. Codex account names (e.g. `Zeus Edix Hu`) and 6-hex checksums no longer leak into branch or worktree paths.
|
|
384
|
+
- **Role normalization.** `AGENT_NAME` is collapsed to `{claude, codex, <explicit>}` via (in order) the `GUARDEX_AGENT_TYPE` env override, a substring match against `claude`/`codex`, the `CLAUDECODE=1` sentinel, or a fallback to `codex`. Other roles (`integrator`, `executor`, etc.) pass through when set via `GUARDEX_AGENT_TYPE`.
|
|
385
|
+
- **New `--print-name-only` flag** on `agent-branch-start.sh` for deterministic tests; honours `GUARDEX_BRANCH_TIMESTAMP` for reproducible output.
|
|
386
|
+
- **`--tier` flag accepted silently** for CLAUDE.md compatibility (scaffold sizing not wired through yet).
|
|
387
|
+
- Tests `install.test.js` covering the old snapshot-slug format were rewritten to assert the new role-datetime shape.
|
|
388
|
+
|
|
389
|
+
### v7.0.2
|
|
390
|
+
|
|
391
|
+
- **Fix: `__source-probe-*` worktree leak on conflict exit.** `agent-branch-finish.sh` was registering its `cleanup()` trap *after* the sync-guard rebase block, so when that rebase hit conflicts and the script exited, the throwaway probe worktree was never removed. `gx doctor` sweeps against stalled branches accumulated one new probe per run.
|
|
392
|
+
- The cleanup trap is now installed immediately after probe creation, and aborts any in-progress `rebase`/`merge` before `worktree remove --force` so conflict-stuck probes are cleaned up reliably.
|
|
393
|
+
|
|
394
|
+
### v7.0.1
|
|
395
|
+
|
|
396
|
+
- Maintenance release.
|
|
397
|
+
|
|
376
398
|
### v7.0.0
|
|
377
399
|
|
|
378
400
|
- **Breaking (soft).** Consolidated 17 commands into 12 visible commands with flag-based subcommands. Five removed names (`init`, `install`, `fix`, `scan`, `copy-prompt`, `copy-commands`, `print-agents-snippet`, `review`) still work but print a one-line deprecation notice on stderr and will be removed in v8. See the migration table in "Copy-paste: common commands" above.
|
package/package.json
CHANGED
|
@@ -23,6 +23,14 @@ if [[ -n "${CODEX_THREAD_ID:-}" || -n "${OMX_SESSION_ID:-}" || "${CODEX_CI:-0}"
|
|
|
23
23
|
is_codex_session=1
|
|
24
24
|
fi
|
|
25
25
|
|
|
26
|
+
# Superset of is_codex_session that also covers Claude Code sessions so the
|
|
27
|
+
# protected-branch gate below only triggers for automated agents — humans stay
|
|
28
|
+
# free to commit directly on main/dev/master.
|
|
29
|
+
is_agent_session=$is_codex_session
|
|
30
|
+
if [[ -n "${CLAUDECODE:-}" || -n "${CLAUDE_CODE_SESSION_ID:-}" ]]; then
|
|
31
|
+
is_agent_session=1
|
|
32
|
+
fi
|
|
33
|
+
|
|
26
34
|
is_vscode_git_context=0
|
|
27
35
|
if [[ -n "${VSCODE_GIT_IPC_HANDLE:-}" || -n "${VSCODE_GIT_ASKPASS_NODE:-}" || -n "${VSCODE_IPC_HOOK_CLI:-}" ]]; then
|
|
28
36
|
is_vscode_git_context=1
|
|
@@ -124,10 +132,10 @@ MSG
|
|
|
124
132
|
fi
|
|
125
133
|
|
|
126
134
|
if [[ "$is_protected_branch" == "1" ]]; then
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
135
|
+
# Humans may commit directly on protected branches; only agent sessions
|
|
136
|
+
# (Codex / Claude Code / OMX) are blocked.
|
|
137
|
+
if [[ "$is_agent_session" != "1" ]]; then
|
|
138
|
+
exit 0
|
|
131
139
|
fi
|
|
132
140
|
|
|
133
141
|
if [[ "$is_unborn_branch" == "1" && "$is_codex_session" != "1" ]]; then
|
|
@@ -146,16 +154,13 @@ Use an agent branch first:
|
|
|
146
154
|
After finishing work:
|
|
147
155
|
bash scripts/agent-branch-finish.sh
|
|
148
156
|
|
|
149
|
-
Optional repo opt-in for VS Code protected-branch commits:
|
|
150
|
-
git config multiagent.allowVscodeProtectedBranchWrites true
|
|
151
|
-
|
|
152
157
|
Temporary bypass (not recommended):
|
|
153
158
|
ALLOW_COMMIT_ON_PROTECTED_BRANCH=1 git commit ...
|
|
154
159
|
MSG
|
|
155
160
|
exit 1
|
|
156
161
|
fi
|
|
157
162
|
|
|
158
|
-
if [[ "$
|
|
163
|
+
if [[ "$is_agent_session" == "1" && "$branch" != agent/* ]]; then
|
|
159
164
|
cat >&2 <<'MSG'
|
|
160
165
|
[agent-branch-guard] Agent commits must run on dedicated agent/* branches.
|
|
161
166
|
Start an agent branch first:
|
|
@@ -28,6 +28,13 @@ if [[ -n "${CODEX_THREAD_ID:-}" || -n "${OMX_SESSION_ID:-}" || "${CODEX_CI:-0}"
|
|
|
28
28
|
is_codex_session=1
|
|
29
29
|
fi
|
|
30
30
|
|
|
31
|
+
# Superset covering Claude Code so only agents are blocked from pushing to
|
|
32
|
+
# protected refs; humans push directly from their primary checkout.
|
|
33
|
+
is_agent_session=$is_codex_session
|
|
34
|
+
if [[ -n "${CLAUDECODE:-}" || -n "${CLAUDE_CODE_SESSION_ID:-}" ]]; then
|
|
35
|
+
is_agent_session=1
|
|
36
|
+
fi
|
|
37
|
+
|
|
31
38
|
protected_branches_raw="${GUARDEX_PROTECTED_BRANCHES:-$(git config --get multiagent.protectedBranches || true)}"
|
|
32
39
|
if [[ -z "$protected_branches_raw" ]]; then
|
|
33
40
|
protected_branches_raw="dev main master"
|
|
@@ -69,6 +76,11 @@ if [[ "${#blocked_refs[@]}" -gt 0 ]]; then
|
|
|
69
76
|
exit 1
|
|
70
77
|
fi
|
|
71
78
|
|
|
79
|
+
# Humans may push directly to protected branches; only agent sessions are blocked.
|
|
80
|
+
if [[ "$is_agent_session" != "1" ]]; then
|
|
81
|
+
exit 0
|
|
82
|
+
fi
|
|
83
|
+
|
|
72
84
|
if [[ "$is_vscode_git_context" == "1" && "$allow_vscode_protected_branch_writes" == "1" ]]; then
|
|
73
85
|
exit 0
|
|
74
86
|
fi
|
|
@@ -10,6 +10,7 @@ OPENSPEC_AUTO_INIT_RAW="${GUARDEX_OPENSPEC_AUTO_INIT:-false}"
|
|
|
10
10
|
OPENSPEC_PLAN_SLUG_OVERRIDE="${GUARDEX_OPENSPEC_PLAN_SLUG:-}"
|
|
11
11
|
OPENSPEC_CHANGE_SLUG_OVERRIDE="${GUARDEX_OPENSPEC_CHANGE_SLUG:-}"
|
|
12
12
|
OPENSPEC_CAPABILITY_SLUG_OVERRIDE="${GUARDEX_OPENSPEC_CAPABILITY_SLUG:-}"
|
|
13
|
+
PRINT_NAME_ONLY=0
|
|
13
14
|
POSITIONAL_ARGS=()
|
|
14
15
|
|
|
15
16
|
while [[ $# -gt 0 ]]; do
|
|
@@ -27,6 +28,15 @@ while [[ $# -gt 0 ]]; do
|
|
|
27
28
|
BASE_BRANCH_EXPLICIT=1
|
|
28
29
|
shift 2
|
|
29
30
|
;;
|
|
31
|
+
--print-name-only)
|
|
32
|
+
PRINT_NAME_ONLY=1
|
|
33
|
+
shift
|
|
34
|
+
;;
|
|
35
|
+
--tier)
|
|
36
|
+
# Accepted for CLAUDE.md compatibility; scaffold size is not yet wired
|
|
37
|
+
# through this script. Consume the value so callers can pass it.
|
|
38
|
+
shift 2
|
|
39
|
+
;;
|
|
30
40
|
--in-place|--allow-in-place)
|
|
31
41
|
echo "[agent-branch-start] In-place branch mode is disabled." >&2
|
|
32
42
|
echo "[agent-branch-start] This command always creates an isolated worktree to keep your active checkout unchanged." >&2
|
|
@@ -46,7 +56,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
46
56
|
;;
|
|
47
57
|
-*)
|
|
48
58
|
echo "[agent-branch-start] Unknown option: $1" >&2
|
|
49
|
-
echo "Usage: $0 [task] [agent] [base] [--worktree-root <path>]" >&2
|
|
59
|
+
echo "Usage: $0 [task] [agent] [base] [--worktree-root <path>] [--print-name-only]" >&2
|
|
50
60
|
exit 1
|
|
51
61
|
;;
|
|
52
62
|
*)
|
|
@@ -86,16 +96,6 @@ sanitize_slug() {
|
|
|
86
96
|
printf '%s' "$slug"
|
|
87
97
|
}
|
|
88
98
|
|
|
89
|
-
sanitize_optional_slug() {
|
|
90
|
-
local raw="$1"
|
|
91
|
-
local fallback="${2:-snapshot}"
|
|
92
|
-
if [[ -z "$raw" ]]; then
|
|
93
|
-
printf ''
|
|
94
|
-
return 0
|
|
95
|
-
fi
|
|
96
|
-
sanitize_slug "$raw" "$fallback"
|
|
97
|
-
}
|
|
98
|
-
|
|
99
99
|
normalize_positive_int() {
|
|
100
100
|
local raw="$1"
|
|
101
101
|
local fallback="$2"
|
|
@@ -123,29 +123,58 @@ shorten_slug() {
|
|
|
123
123
|
printf '%s' "$shortened"
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
126
|
+
# Collapse arbitrary agent identifiers to a clean role token: claude | codex |
|
|
127
|
+
# <other-kebab>. Priority: GUARDEX_AGENT_TYPE env override, then the raw
|
|
128
|
+
# AGENT_NAME (if it contains 'claude' or 'codex'), then CLAUDECODE=1 sentinel
|
|
129
|
+
# (set by Claude Code CLI), else fall back to 'codex'. Any other role name
|
|
130
|
+
# (integrator, executor, rust-port, etc.) is preserved as-is after slug
|
|
131
|
+
# sanitization.
|
|
132
|
+
normalize_role() {
|
|
133
|
+
local raw_agent="$1"
|
|
134
|
+
local override="${GUARDEX_AGENT_TYPE:-}"
|
|
135
|
+
if [[ -n "$override" ]]; then
|
|
136
|
+
sanitize_slug "$override" "agent"
|
|
137
|
+
return 0
|
|
138
|
+
fi
|
|
139
|
+
local lowered
|
|
140
|
+
lowered="$(printf '%s' "$raw_agent" | tr '[:upper:]' '[:lower:]')"
|
|
141
|
+
if [[ "$lowered" == *claude* ]]; then
|
|
142
|
+
printf 'claude'
|
|
143
|
+
return 0
|
|
144
|
+
fi
|
|
145
|
+
if [[ "$lowered" == *codex* ]]; then
|
|
146
|
+
printf 'codex'
|
|
147
|
+
return 0
|
|
148
|
+
fi
|
|
149
|
+
if [[ -n "${CLAUDECODE:-}" && "${CLAUDECODE}" != "0" && "${CLAUDECODE}" != "false" ]]; then
|
|
150
|
+
printf 'claude'
|
|
151
|
+
return 0
|
|
152
|
+
fi
|
|
153
|
+
# Unrecognized raw name (rust-port-lead, some-worker, empty, ...): default to
|
|
154
|
+
# codex. To get a different role (integrator, executor, ...) pass the role
|
|
155
|
+
# explicitly via GUARDEX_AGENT_TYPE, handled above.
|
|
156
|
+
printf 'codex'
|
|
131
157
|
}
|
|
132
158
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if [[ -n "$snapshot_slug" ]]; then
|
|
141
|
-
snapshot_part="$(shorten_slug "$snapshot_slug" "$snapshot_max")"
|
|
142
|
-
checksum_input="${snapshot_slug}--${task_slug}"
|
|
143
|
-
checksum_part="$(checksum_slug_suffix "$checksum_input")"
|
|
144
|
-
printf '%s-%s-%s' "$snapshot_part" "$task_part" "$checksum_part"
|
|
159
|
+
# Timestamp the branch/worktree/openspec slug so parallel agents never collide
|
|
160
|
+
# and names sort chronologically. Format: YYYY-MM-DD-HH-MM (local time).
|
|
161
|
+
# Colons are illegal in git refs, so the HH:MM the user sees is stored as
|
|
162
|
+
# HH-MM in the slug. Can be overridden for tests via GUARDEX_BRANCH_TIMESTAMP.
|
|
163
|
+
compose_branch_timestamp() {
|
|
164
|
+
if [[ -n "${GUARDEX_BRANCH_TIMESTAMP:-}" ]]; then
|
|
165
|
+
printf '%s' "$GUARDEX_BRANCH_TIMESTAMP"
|
|
145
166
|
return 0
|
|
146
167
|
fi
|
|
147
|
-
|
|
148
|
-
|
|
168
|
+
date +%Y-%m-%d-%H-%M
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
compose_branch_descriptor() {
|
|
172
|
+
local task_slug="$1"
|
|
173
|
+
local stamp="$2"
|
|
174
|
+
local task_max task_part
|
|
175
|
+
task_max="$(normalize_positive_int "${GUARDEX_BRANCH_TASK_SLUG_MAX:-40}" "40")"
|
|
176
|
+
task_part="$(shorten_slug "$task_slug" "$task_max")"
|
|
177
|
+
printf '%s-%s' "$task_part" "$stamp"
|
|
149
178
|
}
|
|
150
179
|
|
|
151
180
|
normalize_bool() {
|
|
@@ -192,24 +221,6 @@ resolve_openspec_capability_slug() {
|
|
|
192
221
|
sanitize_slug "$task_slug" "general-behavior"
|
|
193
222
|
}
|
|
194
223
|
|
|
195
|
-
resolve_active_codex_snapshot_name() {
|
|
196
|
-
local override="${GUARDEX_CODEX_AUTH_SNAPSHOT:-}"
|
|
197
|
-
if [[ -n "$override" ]]; then
|
|
198
|
-
printf '%s' "$override"
|
|
199
|
-
return 0
|
|
200
|
-
fi
|
|
201
|
-
|
|
202
|
-
local codex_auth_bin="${GUARDEX_CODEX_AUTH_BIN:-codex-auth}"
|
|
203
|
-
if ! command -v "$codex_auth_bin" >/dev/null 2>&1; then
|
|
204
|
-
return 0
|
|
205
|
-
fi
|
|
206
|
-
|
|
207
|
-
"$codex_auth_bin" list 2>/dev/null \
|
|
208
|
-
| sed -n 's/^[[:space:]]*\*[[:space:]]\+//p' \
|
|
209
|
-
| head -n 1 \
|
|
210
|
-
| tr -d '\r' || true
|
|
211
|
-
}
|
|
212
|
-
|
|
213
224
|
has_local_changes() {
|
|
214
225
|
local root="$1"
|
|
215
226
|
if ! git -C "$root" diff --quiet; then
|
|
@@ -383,6 +394,18 @@ if [[ "$BASE_BRANCH_EXPLICIT" -eq 1 && -z "$BASE_BRANCH" ]]; then
|
|
|
383
394
|
exit 1
|
|
384
395
|
fi
|
|
385
396
|
|
|
397
|
+
task_slug="$(sanitize_slug "$TASK_NAME" "task")"
|
|
398
|
+
agent_slug="$(normalize_role "$AGENT_NAME")"
|
|
399
|
+
branch_timestamp="$(compose_branch_timestamp)"
|
|
400
|
+
branch_descriptor="$(compose_branch_descriptor "$task_slug" "$branch_timestamp")"
|
|
401
|
+
branch_name_base="agent/${agent_slug}/${branch_descriptor}"
|
|
402
|
+
|
|
403
|
+
branch_name="$branch_name_base"
|
|
404
|
+
if [[ "$PRINT_NAME_ONLY" -eq 1 ]]; then
|
|
405
|
+
printf '%s\n' "$branch_name"
|
|
406
|
+
exit 0
|
|
407
|
+
fi
|
|
408
|
+
|
|
386
409
|
if [[ "$BASE_BRANCH_EXPLICIT" -eq 0 ]]; then
|
|
387
410
|
current_branch="$(git -C "$repo_root" rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
|
|
388
411
|
protected_branches_raw="$(resolve_protected_branches "$repo_root")"
|
|
@@ -411,16 +434,7 @@ else
|
|
|
411
434
|
start_ref="${BASE_BRANCH}"
|
|
412
435
|
fi
|
|
413
436
|
|
|
414
|
-
task_slug="$(sanitize_slug "$TASK_NAME" "task")"
|
|
415
|
-
agent_slug_raw="$(sanitize_slug "$AGENT_NAME" "agent")"
|
|
416
|
-
agent_slug="$(shorten_slug "$agent_slug_raw" "${GUARDEX_BRANCH_AGENT_SLUG_MAX:-24}")"
|
|
417
|
-
snapshot_name="$(resolve_active_codex_snapshot_name)"
|
|
418
|
-
snapshot_slug="$(sanitize_optional_slug "$snapshot_name" "snapshot")"
|
|
419
|
-
branch_descriptor="$(compose_branch_descriptor "$snapshot_slug" "$task_slug")"
|
|
420
437
|
timestamp="$(date +%Y%m%d-%H%M%S)"
|
|
421
|
-
branch_name_base="agent/${agent_slug}/${branch_descriptor}"
|
|
422
|
-
|
|
423
|
-
branch_name="$branch_name_base"
|
|
424
438
|
branch_suffix=2
|
|
425
439
|
while git show-ref --verify --quiet "refs/heads/${branch_name}"; do
|
|
426
440
|
branch_name="${branch_name_base}-${branch_suffix}"
|