@imdeadpool/guardex 6.0.1 → 7.0.0
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 +63 -39
- package/bin/multiagent-safety.js +368 -280
- package/package.json +3 -5
- package/templates/AGENTS.multiagent-safety.md +9 -81
- package/templates/claude/commands/guardex.md +6 -12
- package/templates/codex/skills/guardex/SKILL.md +18 -64
- package/templates/githooks/post-merge +39 -3
- package/templates/githooks/pre-commit +27 -193
- package/templates/githooks/pre-push +0 -0
- package/templates/scripts/agent-branch-finish.sh +70 -702
- package/templates/scripts/agent-branch-start.sh +76 -877
- package/templates/scripts/agent-worktree-prune.sh +65 -353
- package/templates/scripts/codex-agent.sh +626 -238
- package/templates/scripts/install-agent-git-hooks.sh +4 -27
- package/templates/scripts/openspec/init-change-workspace.sh +4 -50
- package/templates/scripts/openspec/init-plan-workspace.sh +48 -495
- package/templates/scripts/review-bot-watch.sh +11 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imdeadpool/guardex",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "GuardeX: the Guardian T-Rex for your repo, with hardened multi-agent git guardrails.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"preferGlobal": true,
|
|
@@ -10,8 +10,6 @@
|
|
|
10
10
|
"multiagent-safety": "bin/multiagent-safety.js"
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
|
-
"prepack": "node pack-helpers/dereference-templates.mjs",
|
|
14
|
-
"postpack": "git checkout -- templates",
|
|
15
13
|
"test": "node --test test/*.test.js",
|
|
16
14
|
"agent:codex": "bash ./scripts/codex-agent.sh",
|
|
17
15
|
"agent:branch:start": "bash ./scripts/agent-branch-start.sh",
|
|
@@ -27,8 +25,8 @@
|
|
|
27
25
|
"agent:branch:sync": "gx sync",
|
|
28
26
|
"agent:branch:sync:check": "gx sync --check",
|
|
29
27
|
"agent:safety:setup": "gx setup",
|
|
30
|
-
"agent:safety:scan": "gx
|
|
31
|
-
"agent:safety:fix": "gx
|
|
28
|
+
"agent:safety:scan": "gx status --strict",
|
|
29
|
+
"agent:safety:fix": "gx setup --repair",
|
|
32
30
|
"agent:safety:doctor": "gx doctor",
|
|
33
31
|
"agent:review:watch": "bash ./scripts/review-bot-watch.sh",
|
|
34
32
|
"agent:finish": "gx finish --all"
|
|
@@ -1,91 +1,19 @@
|
|
|
1
1
|
<!-- multiagent-safety:START -->
|
|
2
|
-
## Multi-Agent
|
|
2
|
+
## Multi-Agent Safety Contract
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
**Isolation.** Every task runs on a dedicated `agent/*` branch + worktree. Start with `scripts/agent-branch-start.sh "<task>" "<agent-name>"`. Treat the base branch (`main`/`dev`) as read-only while an agent branch is active.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
- plan/change name (or checkpoint id),
|
|
8
|
-
- owned files/scope,
|
|
9
|
-
- intended action.
|
|
10
|
-
- Before deleting/replacing code, each agent must read the latest session comments/handoffs first and confirm the target code is in their owned scope.
|
|
11
|
-
- If ownership is unclear or overlaps, stop that edit, post a blocker comment, and let the leader/integrator reassign scope.
|
|
12
|
-
- For git isolation, each agent must start on a dedicated branch via `scripts/agent-branch-start.sh "<task-or-plan>" "<agent-name>"`.
|
|
13
|
-
- In-place branch mode is disallowed: never switch the active local/base checkout to an agent branch.
|
|
14
|
-
- Treat the base branch (`main` or the user's current local base branch) as read-only while the agent branch is active.
|
|
15
|
-
- Agent completion defaults to `scripts/codex-agent.sh`, which auto-finishes the branch (auto-commit changed files, push/create PR, attempt merge, and pull the local base branch after merge).
|
|
16
|
-
- OMX completion policy: when a task is done, the agent must commit the task changes, push the agent branch, and create/update a PR for those changes (via `codex-agent` or `agent-branch-finish`).
|
|
17
|
-
- Auto-finish now waits for required checks/merge and then cleans merged sandbox branch/worktree by default.
|
|
18
|
-
- Use `--no-cleanup` only when you explicitly need to keep a merged sandbox for audit/debug follow-up.
|
|
19
|
-
- If codex-agent auto-finish cannot complete, immediately run `scripts/agent-branch-finish.sh --branch "<agent-branch>" --base dev --via-pr --wait-for-merge` and keep the branch open until checks/review pass.
|
|
20
|
-
- If merge/rebase conflicts block auto-finish, run a conflict-resolution review pass in that sandbox branch, then rerun `agent-branch-finish.sh --base dev --via-pr --wait-for-merge` until merged.
|
|
21
|
-
- Completion is not valid until these are true: commit exists on the agent branch, branch is pushed to `origin`, and PR/merge status is produced by `agent-branch-finish.sh` or `codex-agent`.
|
|
22
|
-
- For every new task, including follow-up work in the same chat/session, if an assigned agent sub-branch/worktree is already open, continue in that sub-branch; otherwise create a fresh one from the current local base snapshot with `scripts/agent-branch-start.sh`.
|
|
23
|
-
- Never implement directly on the local/base branch checkout; keep it unchanged and perform all edits in the agent sub-branch/worktree.
|
|
24
|
-
- If the change publishes or bumps a version, the same change must also update release notes/changelog entries.
|
|
6
|
+
**Ownership.** Before editing, claim files: `scripts/agent-file-locks.py claim --branch "<agent-branch>" <file...>`. Before deleting, confirm the path is in your claim. Don't edit outside your scope unless reassigned.
|
|
25
7
|
|
|
26
|
-
|
|
8
|
+
**Handoff gate.** Post a one-line handoff note (plan/change, owned scope, intended action) before editing. Re-read the latest handoffs before replacing others' code.
|
|
27
9
|
|
|
28
|
-
|
|
29
|
-
- Do not edit files outside your assigned scope unless the leader reassigns ownership.
|
|
10
|
+
**Completion.** Finish with `scripts/agent-branch-finish.sh --branch "<agent-branch>" --via-pr --wait-for-merge --cleanup` (or `gx finish --all`). Task is only complete when: commit pushed, PR URL recorded, state = `MERGED`, sandbox worktree pruned. If anything blocks, append a `BLOCKED:` note and stop — don't half-finish.
|
|
30
11
|
|
|
31
|
-
|
|
12
|
+
**Parallel safety.** Assume other agents edit nearby. Never revert unrelated changes. Report conflicts in the handoff.
|
|
32
13
|
|
|
33
|
-
|
|
34
|
-
- Never revert unrelated changes authored by others.
|
|
35
|
-
- If another change conflicts with your approach, adapt and report the conflict in handoff.
|
|
14
|
+
**Reporting.** Every completion handoff includes: files changed, behavior touched, verification commands + results, risks/follow-ups.
|
|
36
15
|
|
|
37
|
-
|
|
16
|
+
**OpenSpec (when change-driven).** Keep `openspec/changes/<slug>/tasks.md` checkboxes current during work, not batched at the end. Verify specs with `openspec validate --specs` before archive. Don't archive unverified.
|
|
38
17
|
|
|
39
|
-
|
|
40
|
-
- Do not mark work complete without command output evidence.
|
|
41
|
-
|
|
42
|
-
4. Required handoff format (every agent)
|
|
43
|
-
|
|
44
|
-
- Files changed
|
|
45
|
-
- Behavior touched
|
|
46
|
-
- Verification commands + results
|
|
47
|
-
- Risks / follow-ups
|
|
48
|
-
|
|
49
|
-
## OpenSpec Workspaces (required for agent sub-branch changes)
|
|
50
|
-
|
|
51
|
-
OMX Codex execution flows must use OpenSpec. `scripts/codex-agent.sh` bootstraps
|
|
52
|
-
per-branch OpenSpec workspaces automatically:
|
|
53
|
-
|
|
54
|
-
```text
|
|
55
|
-
openspec/changes/<agent-branch-slug>/
|
|
56
|
-
openspec/plan/<agent-branch-slug>/
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
For manual `scripts/agent-branch-start.sh` usage, enable auto-bootstrap with
|
|
60
|
-
`GUARDEX_OPENSPEC_AUTO_INIT=true` or scaffold manually before implementation:
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
bash scripts/openspec/init-change-workspace.sh "<change-slug>" "<capability-slug>"
|
|
64
|
-
bash scripts/openspec/init-plan-workspace.sh "<plan-slug>"
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Expected change shape:
|
|
68
|
-
|
|
69
|
-
```text
|
|
70
|
-
openspec/changes/<change-slug>/
|
|
71
|
-
.openspec.yaml
|
|
72
|
-
proposal.md
|
|
73
|
-
tasks.md
|
|
74
|
-
specs/<capability-slug>/spec.md
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
Expected plan shape:
|
|
78
|
-
|
|
79
|
-
```text
|
|
80
|
-
openspec/plan/<plan-slug>/
|
|
81
|
-
summary.md
|
|
82
|
-
checkpoints.md
|
|
83
|
-
planner/plan.md
|
|
84
|
-
planner/tasks.md
|
|
85
|
-
architect/tasks.md
|
|
86
|
-
critic/tasks.md
|
|
87
|
-
executor/tasks.md
|
|
88
|
-
writer/tasks.md
|
|
89
|
-
verifier/tasks.md
|
|
90
|
-
```
|
|
18
|
+
**Version bumps.** If a change bumps a published version, the same PR updates release notes/changelog.
|
|
91
19
|
<!-- multiagent-safety:END -->
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
# /guardex
|
|
2
2
|
|
|
3
|
-
Run a GuardeX check-and-repair
|
|
3
|
+
Run a GuardeX check-and-repair for the current repo.
|
|
4
4
|
|
|
5
5
|
## Steps
|
|
6
6
|
|
|
7
|
-
1.
|
|
8
|
-
2. If
|
|
9
|
-
3. If still degraded,
|
|
10
|
-
4. Report
|
|
11
|
-
- `Repo is guarded`
|
|
12
|
-
- `Repo is not guarded` (include blockers)
|
|
7
|
+
1. `gx status` — if green, stop.
|
|
8
|
+
2. If degraded, `gx doctor`.
|
|
9
|
+
3. If still degraded, `gx status --strict` and summarize each finding with a fix.
|
|
10
|
+
4. Report verdict: `Repo is guarded` or `Repo is not guarded` (list blockers).
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- Keep output short and operational.
|
|
17
|
-
- Include exact commands you executed.
|
|
18
|
-
- Prefer concrete next actions over generic advice.
|
|
12
|
+
Keep output short, include the exact commands you ran.
|
|
@@ -1,89 +1,43 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: guardex
|
|
3
|
-
description: "
|
|
3
|
+
description: "Check, repair, or bootstrap multi-agent safety guardrails in this repository."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# GuardeX (Codex skill)
|
|
7
7
|
|
|
8
|
-
Use
|
|
8
|
+
Use when branch safety, lock ownership, or guardrail setup may be broken.
|
|
9
9
|
|
|
10
10
|
## Fast path
|
|
11
11
|
|
|
12
|
-
1.
|
|
13
|
-
2. If
|
|
14
|
-
3. If issues remain,
|
|
12
|
+
1. `gx status` — one-glance health check.
|
|
13
|
+
2. If degraded, `gx doctor` — repair + verify in one pass.
|
|
14
|
+
3. If issues remain, `gx status --strict` and address each finding.
|
|
15
15
|
|
|
16
|
-
##
|
|
17
|
-
|
|
18
|
-
If guardrails are missing entirely, run:
|
|
19
|
-
|
|
20
|
-
```sh
|
|
21
|
-
gx setup
|
|
22
|
-
# alias
|
|
23
|
-
gx init
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
Then verify:
|
|
16
|
+
## Bootstrap (missing guardrails)
|
|
27
17
|
|
|
28
18
|
```sh
|
|
29
|
-
gx
|
|
30
|
-
gx
|
|
19
|
+
gx setup # install + repair + verify
|
|
20
|
+
gx status # confirm green
|
|
31
21
|
```
|
|
32
22
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
- Prefer `gx doctor` for one-step repair + verification.
|
|
36
|
-
- Keep agent work isolated (`agent/*` branches + lock claims).
|
|
37
|
-
- For every new user message/task, restart the full loop on a fresh agent branch/worktree.
|
|
38
|
-
- For one-command Codex sandbox startup, use `bash scripts/codex-agent.sh "<task>" "<agent-name>"`.
|
|
39
|
-
- `scripts/codex-agent.sh` auto-syncs the sandbox branch against base before each task and auto-finishes merge/PR flow after Codex exits.
|
|
40
|
-
- Auto-finish keeps the branch/worktree by default; remove merged branches explicitly with `gx cleanup` (or `gx cleanup --branch "<agent-branch>"`).
|
|
41
|
-
- For skill-file-only merges into the local base branch (`dev` by default), use `$guardex-merge-skills-to-dev`.
|
|
42
|
-
- Do not bypass protected branch safeguards unless explicitly required.
|
|
23
|
+
In a monorepo with nested git repos (top-level `.git` plus `apps/*/.git`), `gx setup` auto-installs into every discovered repo. Submodules and guardex-managed worktrees are skipped. Pass `--no-recursive` to limit to the top-level only.
|
|
43
24
|
|
|
44
|
-
##
|
|
25
|
+
## Notes
|
|
45
26
|
|
|
46
|
-
|
|
27
|
+
- Isolation: `scripts/codex-agent.sh "<task>" "<agent>"` is the one-command sandbox start/finish loop.
|
|
28
|
+
- Completion: auto-finish keeps the branch until explicit `gx cleanup`.
|
|
29
|
+
- Never bypass protected-branch safeguards.
|
|
47
30
|
|
|
48
|
-
|
|
31
|
+
## Bulk finish
|
|
49
32
|
|
|
50
33
|
```sh
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
gx scan
|
|
34
|
+
gx finish --all # commit + PR + merge all ready agent/* branches
|
|
35
|
+
gx cleanup # prune merged/stale branches and worktrees
|
|
54
36
|
```
|
|
55
37
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
```sh
|
|
59
|
-
gx finish --all
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
3. If a branch fails with `already used by worktree` or stale rebase hints, clear the stale state in that worktree, then retry targeted finish:
|
|
38
|
+
If a branch fails with stale rebase/worktree state:
|
|
63
39
|
|
|
64
40
|
```sh
|
|
65
41
|
git -C "<worktree>" rebase --abort || true
|
|
66
|
-
gx finish --branch "<agent-branch>" --
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
4. If `gh pr merge` exits non-zero due local branch deletion but PR is already merged, treat it as merged and verify with:
|
|
70
|
-
|
|
71
|
-
```sh
|
|
72
|
-
gh pr view "<pr-number>" --json state,mergedAt,url
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
5. If a branch is still ahead of base with no open PR, create and merge a follow-up PR manually:
|
|
76
|
-
|
|
77
|
-
```sh
|
|
78
|
-
gh pr create --base "<base-branch>" --head "<agent-branch>" --title "Auto-finish: <agent-branch>" --body "Follow-up merge for pending branch commits."
|
|
79
|
-
gh pr merge "<pr-number>" --squash --delete-branch
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
6. Final verification:
|
|
83
|
-
|
|
84
|
-
```sh
|
|
85
|
-
gh pr list --state open --search "head:agent/ base:<base-branch>"
|
|
86
|
-
git pull --ff-only origin "<base-branch>"
|
|
87
|
-
gx cleanup
|
|
88
|
-
gx scan
|
|
42
|
+
gx finish --branch "<agent-branch>" --cleanup
|
|
89
43
|
```
|
|
@@ -1,7 +1,43 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
bash scripts/agent-sync-on-base-update.sh --quiet || true
|
|
4
|
+
if [[ "${GUARDEX_DISABLE_POST_MERGE_CLEANUP:-0}" == "1" ]]; then
|
|
5
|
+
exit 0
|
|
7
6
|
fi
|
|
7
|
+
|
|
8
|
+
repo_root="$(git rev-parse --show-toplevel 2>/dev/null || true)"
|
|
9
|
+
if [[ -z "$repo_root" ]]; then
|
|
10
|
+
exit 0
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
branch="$(git -C "$repo_root" rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
|
|
14
|
+
if [[ -z "$branch" || "$branch" == "HEAD" ]]; then
|
|
15
|
+
exit 0
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
base_branch="${GUARDEX_BASE_BRANCH:-$(git -C "$repo_root" config --get multiagent.baseBranch || true)}"
|
|
19
|
+
if [[ -z "$base_branch" ]]; then
|
|
20
|
+
base_branch="dev"
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
if [[ "$branch" != "$base_branch" ]]; then
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
cli_path="$repo_root/bin/multiagent-safety.js"
|
|
28
|
+
if [[ ! -f "$cli_path" ]]; then
|
|
29
|
+
exit 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
node_bin="${GUARDEX_NODE_BIN:-node}"
|
|
33
|
+
if ! command -v "$node_bin" >/dev/null 2>&1; then
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
"$node_bin" "$cli_path" cleanup \
|
|
38
|
+
--target "$repo_root" \
|
|
39
|
+
--base "$base_branch" \
|
|
40
|
+
--include-pr-merged \
|
|
41
|
+
--keep-clean-worktrees >/dev/null 2>&1 || true
|
|
42
|
+
|
|
43
|
+
exit 0
|
|
@@ -9,12 +9,6 @@ if [[ -z "$branch" ]]; then
|
|
|
9
9
|
exit 0
|
|
10
10
|
fi
|
|
11
11
|
|
|
12
|
-
git_dir="$(git rev-parse --git-dir 2>/dev/null || true)"
|
|
13
|
-
is_linked_worktree=0
|
|
14
|
-
if [[ -n "$git_dir" && "$git_dir" == *"/worktrees/"* ]]; then
|
|
15
|
-
is_linked_worktree=1
|
|
16
|
-
fi
|
|
17
|
-
|
|
18
12
|
if [[ "${ALLOW_COMMIT_ON_PROTECTED_BRANCH:-0}" == "1" ]]; then
|
|
19
13
|
exit 0
|
|
20
14
|
fi
|
|
@@ -30,7 +24,7 @@ if [[ -n "${CODEX_THREAD_ID:-}" || -n "${OMX_SESSION_ID:-}" || "${CODEX_CI:-0}"
|
|
|
30
24
|
fi
|
|
31
25
|
|
|
32
26
|
is_vscode_git_context=0
|
|
33
|
-
if [[ -n "${VSCODE_GIT_IPC_HANDLE:-}" || -n "${VSCODE_GIT_ASKPASS_NODE:-}" || -n "${VSCODE_IPC_HOOK_CLI:-}"
|
|
27
|
+
if [[ -n "${VSCODE_GIT_IPC_HANDLE:-}" || -n "${VSCODE_GIT_ASKPASS_NODE:-}" || -n "${VSCODE_IPC_HOOK_CLI:-}" ]]; then
|
|
34
28
|
is_vscode_git_context=1
|
|
35
29
|
fi
|
|
36
30
|
|
|
@@ -74,163 +68,6 @@ case "$codex_require_agent_branch" in
|
|
|
74
68
|
*) should_require_codex_agent_branch=1 ;;
|
|
75
69
|
esac
|
|
76
70
|
|
|
77
|
-
sanitize_slug() {
|
|
78
|
-
local raw="$1"
|
|
79
|
-
local fallback="${2:-task}"
|
|
80
|
-
local slug
|
|
81
|
-
slug="$(printf '%s' "$raw" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-+//; s/-+$//; s/-{2,}/-/g')"
|
|
82
|
-
if [[ -z "$slug" ]]; then
|
|
83
|
-
slug="$fallback"
|
|
84
|
-
fi
|
|
85
|
-
printf '%s' "$slug"
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
resolve_agent_branch_base() {
|
|
89
|
-
local branch_name="$1"
|
|
90
|
-
git config --get "branch.${branch_name}.guardexBase" || true
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
is_helper_agent_branch() {
|
|
94
|
-
local branch_name="$1"
|
|
95
|
-
local base_branch=""
|
|
96
|
-
base_branch="$(resolve_agent_branch_base "$branch_name")"
|
|
97
|
-
[[ "$base_branch" == agent/* ]]
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
ensure_agent_branch_openspec_workspace() {
|
|
101
|
-
local branch_name="$1"
|
|
102
|
-
local change_slug change_dir specs_dir capability_slug branch_base
|
|
103
|
-
local missing_workspace=0
|
|
104
|
-
local openspec_script="scripts/openspec/init-change-workspace.sh"
|
|
105
|
-
|
|
106
|
-
branch_base="$(git config --get "branch.${branch_name}.guardexBase" || true)"
|
|
107
|
-
if [[ "$branch_base" == agent/* ]]; then
|
|
108
|
-
echo "[agent-openspec-guard] Skipping OpenSpec change workspace bootstrap for helper branch '${branch_name}' (base '${branch_base}')."
|
|
109
|
-
return 0
|
|
110
|
-
fi
|
|
111
|
-
|
|
112
|
-
change_slug="$(sanitize_slug "${branch_name//\//-}" "change")"
|
|
113
|
-
change_dir="openspec/changes/${change_slug}"
|
|
114
|
-
specs_dir="${change_dir}/specs"
|
|
115
|
-
|
|
116
|
-
if [[ ! -f "${change_dir}/.openspec.yaml" || ! -f "${change_dir}/proposal.md" || ! -f "${change_dir}/tasks.md" ]]; then
|
|
117
|
-
missing_workspace=1
|
|
118
|
-
elif [[ ! -d "$specs_dir" ]] || ! find "$specs_dir" -mindepth 2 -maxdepth 2 -type f -name spec.md | grep -q .; then
|
|
119
|
-
missing_workspace=1
|
|
120
|
-
fi
|
|
121
|
-
|
|
122
|
-
if [[ "$missing_workspace" -ne 1 ]]; then
|
|
123
|
-
return 0
|
|
124
|
-
fi
|
|
125
|
-
|
|
126
|
-
if [[ ! -f "$openspec_script" ]]; then
|
|
127
|
-
cat >&2 <<MSG
|
|
128
|
-
[agent-openspec-guard] Missing OpenSpec change workspace for '${branch_name}'.
|
|
129
|
-
Expected path:
|
|
130
|
-
${change_dir}
|
|
131
|
-
Cannot auto-initialize because '${openspec_script}' is missing.
|
|
132
|
-
Run:
|
|
133
|
-
gx setup --target "$(git rev-parse --show-toplevel)"
|
|
134
|
-
bash scripts/openspec/init-change-workspace.sh "${change_slug}" "<capability-slug>"
|
|
135
|
-
MSG
|
|
136
|
-
exit 1
|
|
137
|
-
fi
|
|
138
|
-
|
|
139
|
-
if [[ ! -x "$openspec_script" ]]; then
|
|
140
|
-
chmod +x "$openspec_script" 2>/dev/null || true
|
|
141
|
-
fi
|
|
142
|
-
|
|
143
|
-
capability_slug="$(sanitize_slug "${branch_name##*/}" "general-behavior")"
|
|
144
|
-
init_output=""
|
|
145
|
-
if ! init_output="$(bash "$openspec_script" "$change_slug" "$capability_slug" 2>&1)"; then
|
|
146
|
-
printf '%s\n' "$init_output" >&2
|
|
147
|
-
cat >&2 <<MSG
|
|
148
|
-
[agent-openspec-guard] OpenSpec auto-init failed for '${branch_name}'.
|
|
149
|
-
Run manually:
|
|
150
|
-
bash scripts/openspec/init-change-workspace.sh "${change_slug}" "${capability_slug}"
|
|
151
|
-
MSG
|
|
152
|
-
exit 1
|
|
153
|
-
fi
|
|
154
|
-
|
|
155
|
-
if [[ -n "$init_output" ]]; then
|
|
156
|
-
printf '%s\n' "$init_output"
|
|
157
|
-
fi
|
|
158
|
-
|
|
159
|
-
git add "$change_dir"
|
|
160
|
-
|
|
161
|
-
if [[ -x scripts/agent-file-locks.py ]]; then
|
|
162
|
-
staged_openspec="$(git diff --cached --name-only -- "$change_dir" | sed '/^$/d' || true)"
|
|
163
|
-
if [[ -n "$staged_openspec" ]]; then
|
|
164
|
-
mapfile -t openspec_files < <(printf '%s\n' "$staged_openspec")
|
|
165
|
-
python3 scripts/agent-file-locks.py claim --branch "$branch_name" "${openspec_files[@]}" >/dev/null 2>&1 || true
|
|
166
|
-
fi
|
|
167
|
-
fi
|
|
168
|
-
|
|
169
|
-
echo "[agent-openspec-guard] Bootstrapped OpenSpec change workspace: ${change_dir}"
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
should_auto_reroute_protected_branch() {
|
|
173
|
-
local raw="${GUARDEX_AUTO_REROUTE_PROTECTED_BRANCH:-$(git config --get multiagent.autoRerouteProtectedBranch || true)}"
|
|
174
|
-
local lowered=""
|
|
175
|
-
if [[ -z "$raw" ]]; then
|
|
176
|
-
raw="true"
|
|
177
|
-
fi
|
|
178
|
-
lowered="$(printf '%s' "$raw" | tr '[:upper:]' '[:lower:]')"
|
|
179
|
-
case "$lowered" in
|
|
180
|
-
1|true|yes|on) return 0 ;;
|
|
181
|
-
*) return 1 ;;
|
|
182
|
-
esac
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
auto_reroute_protected_branch_commit() {
|
|
186
|
-
local branch_name="$1"
|
|
187
|
-
local starter_script="scripts/agent-branch-start.sh"
|
|
188
|
-
local task_name="${GUARDEX_AUTO_REROUTE_TASK_NAME:-protected-branch-commit-reroute}"
|
|
189
|
-
local agent_name="${GUARDEX_AUTO_REROUTE_AGENT_NAME:-auto-reroute}"
|
|
190
|
-
local changed_paths=""
|
|
191
|
-
local start_output=""
|
|
192
|
-
local start_status=0
|
|
193
|
-
local new_branch=""
|
|
194
|
-
local worktree_path=""
|
|
195
|
-
|
|
196
|
-
changed_paths="$({
|
|
197
|
-
git diff --name-only
|
|
198
|
-
git diff --cached --name-only
|
|
199
|
-
git ls-files --others --exclude-standard
|
|
200
|
-
} | sed '/^$/d' | sort -u)"
|
|
201
|
-
|
|
202
|
-
if [[ -z "$changed_paths" ]]; then
|
|
203
|
-
return 1
|
|
204
|
-
fi
|
|
205
|
-
|
|
206
|
-
if [[ ! -x "$starter_script" ]]; then
|
|
207
|
-
return 1
|
|
208
|
-
fi
|
|
209
|
-
|
|
210
|
-
set +e
|
|
211
|
-
start_output="$(bash "$starter_script" "$task_name" "$agent_name" "$branch_name" 2>&1)"
|
|
212
|
-
start_status=$?
|
|
213
|
-
set -e
|
|
214
|
-
|
|
215
|
-
if [[ "$start_status" -ne 0 ]]; then
|
|
216
|
-
printf '%s\n' "$start_output" >&2
|
|
217
|
-
return 1
|
|
218
|
-
fi
|
|
219
|
-
|
|
220
|
-
new_branch="$(printf '%s\n' "$start_output" | sed -n 's/^\[agent-branch-start\] Created branch: //p' | tail -n 1)"
|
|
221
|
-
worktree_path="$(printf '%s\n' "$start_output" | sed -n 's/^\[agent-branch-start\] Worktree: //p' | tail -n 1)"
|
|
222
|
-
|
|
223
|
-
printf '%s\n' "$start_output" >&2
|
|
224
|
-
cat >&2 <<MSG
|
|
225
|
-
[agent-branch-guard] Protected-branch commit rerouted automatically.
|
|
226
|
-
Changes from '${branch_name}' were moved to:
|
|
227
|
-
branch: ${new_branch:-<see output>}
|
|
228
|
-
worktree: ${worktree_path:-<see output>}
|
|
229
|
-
Continue work and commit from that agent worktree.
|
|
230
|
-
MSG
|
|
231
|
-
return 0
|
|
232
|
-
}
|
|
233
|
-
|
|
234
71
|
is_codex_managed_only_commit_on_protected=0
|
|
235
72
|
if [[ "$is_codex_session" == "1" && "$is_protected_branch" == "1" ]]; then
|
|
236
73
|
deleted_paths="$(git diff --cached --name-only --diff-filter=D)"
|
|
@@ -286,30 +123,15 @@ MSG
|
|
|
286
123
|
fi
|
|
287
124
|
fi
|
|
288
125
|
|
|
289
|
-
if [[ "$is_codex_session" == "1" && "$branch" == agent/* ]]; then
|
|
290
|
-
if [[ "$is_linked_worktree" != "1" && "${GUARDEX_ALLOW_CODEX_ON_PRIMARY_WORKTREE:-0}" != "1" ]]; then
|
|
291
|
-
cat >&2 <<'MSG'
|
|
292
|
-
[codex-worktree-guard] Codex agent commits are blocked from the primary checkout.
|
|
293
|
-
Use a linked agent worktree for agent/* branches:
|
|
294
|
-
bash scripts/agent-branch-start.sh "<task-or-plan>" "<agent-name>"
|
|
295
|
-
Then commit from the printed worktree path.
|
|
296
|
-
|
|
297
|
-
Temporary bypass (not recommended):
|
|
298
|
-
GUARDEX_ALLOW_CODEX_ON_PRIMARY_WORKTREE=1 git commit ...
|
|
299
|
-
MSG
|
|
300
|
-
exit 1
|
|
301
|
-
fi
|
|
302
|
-
fi
|
|
303
|
-
|
|
304
126
|
if [[ "$is_protected_branch" == "1" ]]; then
|
|
305
|
-
if [[ "$is_codex_session" != "1" && "$is_vscode_git_context" == "1"
|
|
306
|
-
|
|
127
|
+
if [[ "$is_codex_session" != "1" && "$is_vscode_git_context" == "1" ]]; then
|
|
128
|
+
if [[ "$allow_vscode_protected_branch_writes" == "1" ]]; then
|
|
129
|
+
exit 0
|
|
130
|
+
fi
|
|
307
131
|
fi
|
|
308
132
|
|
|
309
|
-
if
|
|
310
|
-
|
|
311
|
-
exit 1
|
|
312
|
-
fi
|
|
133
|
+
if [[ "$is_unborn_branch" == "1" && "$is_codex_session" != "1" ]]; then
|
|
134
|
+
exit 0
|
|
313
135
|
fi
|
|
314
136
|
|
|
315
137
|
git_dir="$(git rev-parse --git-dir)"
|
|
@@ -323,10 +145,8 @@ Use an agent branch first:
|
|
|
323
145
|
bash scripts/agent-branch-start.sh "<task-or-plan>" "<agent-name>"
|
|
324
146
|
After finishing work:
|
|
325
147
|
bash scripts/agent-branch-finish.sh
|
|
326
|
-
Auto-reroute can be disabled (not recommended):
|
|
327
|
-
GUARDEX_AUTO_REROUTE_PROTECTED_BRANCH=0 git commit ...
|
|
328
148
|
|
|
329
|
-
Optional repo
|
|
149
|
+
Optional repo opt-in for VS Code protected-branch commits:
|
|
330
150
|
git config multiagent.allowVscodeProtectedBranchWrites true
|
|
331
151
|
|
|
332
152
|
Temporary bypass (not recommended):
|
|
@@ -335,12 +155,26 @@ MSG
|
|
|
335
155
|
exit 1
|
|
336
156
|
fi
|
|
337
157
|
|
|
158
|
+
if [[ "$is_agent_context" == "1" && "$branch" != agent/* ]]; then
|
|
159
|
+
cat >&2 <<'MSG'
|
|
160
|
+
[agent-branch-guard] Agent commits must run on dedicated agent/* branches.
|
|
161
|
+
Start an agent branch first:
|
|
162
|
+
bash scripts/agent-branch-start.sh "<task-or-plan>" "<agent-name>"
|
|
163
|
+
Then commit on that branch.
|
|
164
|
+
|
|
165
|
+
Temporary bypass (not recommended):
|
|
166
|
+
ALLOW_COMMIT_ON_PROTECTED_BRANCH=1 git commit ...
|
|
167
|
+
MSG
|
|
168
|
+
exit 1
|
|
169
|
+
fi
|
|
170
|
+
|
|
338
171
|
if [[ "$branch" == agent/* ]]; then
|
|
339
|
-
if
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
172
|
+
if [[ "${GUARDEX_AUTOCLAIM_STAGED_LOCKS:-1}" == "1" ]]; then
|
|
173
|
+
while IFS= read -r staged_file; do
|
|
174
|
+
[[ -z "$staged_file" ]] && continue
|
|
175
|
+
[[ "$staged_file" == ".omx/state/agent-file-locks.json" ]] && continue
|
|
176
|
+
python3 scripts/agent-file-locks.py claim --branch "$branch" "$staged_file" >/dev/null 2>&1 || true
|
|
177
|
+
done < <(git diff --cached --name-only --diff-filter=ACMRDTUXB)
|
|
344
178
|
fi
|
|
345
179
|
|
|
346
180
|
if ! python3 scripts/agent-file-locks.py validate --branch "$branch" --staged; then
|
|
File without changes
|