diff --git a/AGENTS.md b/AGENTS.md index c7babb5..4618d91 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -160,6 +160,10 @@ for a full audit or `--fast` for pre-commit speed. Bypass with `--no-verify` The Crush hook (`hooks/ticket-gate.sh`) blocks modifying operations until this file exists. If no ticket exists, CREATE ONE FIRST via redmine-cli, then set it. Clear when done: `> .crush/active-ticket`. + **Parallel sessions:** each session uses its OWN suffixed file (e.g. + `.crush/active-ticket-plant`, `.crush/active-ticket-core`) so concurrent + sessions never clobber each other's ticket; any non-empty + `.crush/active-ticket*` satisfies the gate. - **WORKING.md** is the only in-repo task tracker — a scratchpad for the current session. The pre-commit hook blocks commits while any task remains unchecked. - **Parallel sessions:** when two sessions share this repo (e.g. physical plant diff --git a/hooks/ticket-gate.sh b/hooks/ticket-gate.sh index 6a09fa9..582f335 100755 --- a/hooks/ticket-gate.sh +++ b/hooks/ticket-gate.sh @@ -9,7 +9,6 @@ # run audits, check status, etc.). set -euo pipefail -TICKET_FILE="${CRUSH_PROJECT_DIR}/.crush/active-ticket" TOOL="${CRUSH_TOOL_NAME:-}" CMD="${CRUSH_TOOL_INPUT_COMMAND:-}" @@ -54,12 +53,18 @@ case "$FILE_PATH" in ;; esac -# Check for active ticket -if [ -f "$TICKET_FILE" ] && [ -s "$TICKET_FILE" ]; then - TICKET=$(cat "$TICKET_FILE") - printf '{"context":"Active ticket: %s"}\n' "$TICKET" - exit 0 -fi +# Check for active ticket. Parallel sessions each use their OWN file: +# .crush/active-ticket (default / single session) +# .crush/active-ticket- (suffixed per session; any non-empty one +# satisfies the gate — sessions never fight +# over one file) +GATE_OK=0 +for f in "$CRUSH_PROJECT_DIR"/.crush/active-ticket*; do + [ -f "$f" ] && [ -s "$f" ] || continue + GATE_OK=1 + printf '{"context":"Active ticket(s): %s -> %s"}\n' "$(basename "$f")" "$(cat "$f")" +done +[ "$GATE_OK" -eq 1 ] && exit 0 # No active ticket — block cat >&2 <<'MSG' diff --git a/scripts/check-rules.sh b/scripts/check-rules.sh index 57336c5..d863be6 100755 --- a/scripts/check-rules.sh +++ b/scripts/check-rules.sh @@ -41,7 +41,7 @@ TODAY="$(date +%Y-%m-%d)" # Runs in Docker so the host stays clean (no native shellcheck required). # ---------------------------------------------------------------------------- $RULE_VERBOSE && log_step "Shell scripts (shellcheck)" -mapfile -d '' SH_FILES < <(find . -path ./.git -prune -o -path ./.tmp -prune -o -path ./vendor -prune -o -path ./archive -prune -o -path ./node_modules -prune -o \( -name '*.sh' -o -name '*.bash' \) -print0 2>/dev/null) +mapfile -d '' SH_FILES < <(find . -path ./.git -prune -o -path ./.tmp -prune -o -path ./.crush -prune -o -path ./vendor -prune -o -path ./archive -prune -o -path ./node_modules -prune -o \( -name '*.sh' -o -name '*.bash' \) -print0 2>/dev/null) if [ "${#SH_FILES[@]}" -gt 0 ]; then if have shellcheck; then if shellcheck "${SH_FILES[@]}" >/dev/null 2>&1; then diff --git a/tests/shellcheck.sh b/tests/shellcheck.sh index e3105f9..0876839 100644 --- a/tests/shellcheck.sh +++ b/tests/shellcheck.sh @@ -36,7 +36,8 @@ mapfile -t FILES < <( *) echo "$f_abs" ;; esac done < <(find "$ROOT" -type f -name '*.sh' \ - -not -path '*/.git/*' -not -path "$ROOT/vendor/*") + -not -path '*/.git/*' -not -path "$ROOT/vendor/*" \ + -not -path "$ROOT/.crush/*") fi )