(baseRef?: string)
| 11 | * If not provided or not an origin/ ref, auto-detects. |
| 12 | */ |
| 13 | export function generateGitStatusScript(baseRef?: string): string { |
| 14 | // Extract branch name if it's an origin/ ref, otherwise empty for auto-detect |
| 15 | const preferredBranch = baseRef?.startsWith("origin/") ? baseRef.replace(/^origin\//, "") : ""; |
| 16 | // Security rationale: baseRef is client-controlled in some IPC paths, so quote as a single-quoted |
| 17 | // shell literal to prevent command substitution / quote-breaking injection when embedding in bash. |
| 18 | const shellSafePreferredBranch = `'${preferredBranch.replace(/'/g, `'\\''`)}'`; |
| 19 | |
| 20 | return ` |
| 21 | # Determine primary branch to compare against |
| 22 | PRIMARY_BRANCH="" |
| 23 | PREFERRED_BRANCH=${shellSafePreferredBranch} |
| 24 | |
| 25 | # Try preferred branch first if specified |
| 26 | if [ -n "$PREFERRED_BRANCH" ]; then |
| 27 | if git rev-parse --verify "refs/remotes/origin/$PREFERRED_BRANCH" >/dev/null 2>&1; then |
| 28 | PRIMARY_BRANCH="$PREFERRED_BRANCH" |
| 29 | fi |
| 30 | fi |
| 31 | |
| 32 | # Fall back to auto-detection |
| 33 | if [ -z "$PRIMARY_BRANCH" ]; then |
| 34 | # Method 1: symbolic-ref (fastest) |
| 35 | PRIMARY_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@') |
| 36 | |
| 37 | # Method 2: remote show origin (fallback) |
| 38 | if [ -z "$PRIMARY_BRANCH" ]; then |
| 39 | PRIMARY_BRANCH=$(git remote show origin 2>/dev/null | grep 'HEAD branch' | cut -d' ' -f5) |
| 40 | fi |
| 41 | |
| 42 | # Method 3: check for main or master |
| 43 | if [ -z "$PRIMARY_BRANCH" ]; then |
| 44 | PRIMARY_BRANCH=$(git branch -r 2>/dev/null | grep -E 'origin/(main|master)$' | head -1 | sed 's@^.*origin/@@') |
| 45 | fi |
| 46 | fi |
| 47 | |
| 48 | # Exit if we can't determine primary branch |
| 49 | if [ -z "$PRIMARY_BRANCH" ]; then |
| 50 | echo "ERROR: Could not determine primary branch" |
| 51 | exit 1 |
| 52 | fi |
| 53 | |
| 54 | # Avoid sampling while git is holding the index lock (e.g., mid-commit) |
| 55 | GIT_DIR=$(git rev-parse --git-dir 2>/dev/null || echo "") |
| 56 | if [ -n "$GIT_DIR" ]; then |
| 57 | LOCK_PATH="$GIT_DIR/index.lock" |
| 58 | retries=0 |
| 59 | while [ -f "$LOCK_PATH" ] && [ $retries -lt 20 ]; do |
| 60 | sleep 0.05 |
| 61 | retries=$((retries + 1)) |
| 62 | done |
| 63 | fi |
| 64 | |
| 65 | # Stable ahead/behind counts (rev-list is format-stable across git versions) |
| 66 | AHEAD_BEHIND=$(git rev-list --left-right --count HEAD..."origin/$PRIMARY_BRANCH" 2>/dev/null || echo "") |
| 67 | if [ -z "$AHEAD_BEHIND" ]; then |
| 68 | AHEAD_BEHIND="0 0" |
| 69 | fi |
| 70 |
no outgoing calls
no test coverage detected