signal.sh 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. #!/usr/bin/env bash
  2. # fleet-ops/signal.sh — called by Claude sessions to signal lane status
  3. # Auto-detects the current branch. Refuses dirty trees.
  4. # Resolves .fleet/ via git common dir, so it works from inside worktrees.
  5. set -euo pipefail
  6. GIT_COMMON_DIR=$(git rev-parse --git-common-dir 2>/dev/null || true)
  7. [[ -z "$GIT_COMMON_DIR" ]] && { echo "signal.sh ERROR: not in a git repo" >&2; exit 2; }
  8. # git-common-dir is .git/ at main repo root → parent is the main worktree
  9. MAIN_REPO_ROOT=$(cd "$GIT_COMMON_DIR/.." && pwd)
  10. LANES_DIR="$MAIN_REPO_ROOT/.claude/fleet/lanes"
  11. BRANCH=$(git branch --show-current 2>/dev/null || true)
  12. if [[ -z "$BRANCH" ]]; then
  13. echo "signal.sh ERROR: not on a branch (detached HEAD?)" >&2
  14. exit 2
  15. fi
  16. if [[ ! -f "$LANES_DIR/$BRANCH" ]]; then
  17. echo "signal.sh ERROR: branch '$BRANCH' is not a registered lane (run: fleet track $BRANCH)" >&2
  18. exit 2
  19. fi
  20. STATE=${1:-}
  21. case "$STATE" in
  22. READY)
  23. if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then
  24. echo "signal.sh REFUSE: '$BRANCH' has uncommitted tracked changes — commit or stash before signaling READY" >&2
  25. git status --short >&2
  26. exit 1
  27. fi
  28. LOG=${2:-}
  29. if [[ -n "$LOG" ]]; then
  30. [[ -f "$LOG" ]] || { echo "signal.sh ERROR: test log '$LOG' not found" >&2; exit 1; }
  31. # crude pass detection — works for pytest, jest, go test, cargo test, mocha
  32. if grep -qiE "(failed|error|fail:)" "$LOG" && ! grep -qiE "0 (failed|errors)" "$LOG"; then
  33. echo "signal.sh REFUSE: test log '$LOG' shows failures" >&2
  34. grep -iE "(failed|error)" "$LOG" | head -5 >&2
  35. exit 1
  36. fi
  37. fi
  38. { echo "READY"; [[ -n "$LOG" ]] && echo "log=$LOG"; } > "$LANES_DIR/$BRANCH"
  39. echo "signal: $BRANCH → READY"
  40. ;;
  41. CONFLICT)
  42. REASON=${2:-"unspecified"}
  43. { echo "CONFLICT"; echo "reason=$REASON"; } > "$LANES_DIR/$BRANCH"
  44. echo "signal: $BRANCH → CONFLICT ($REASON)"
  45. ;;
  46. RUNNING)
  47. echo "RUNNING" > "$LANES_DIR/$BRANCH"
  48. echo "signal: $BRANCH → RUNNING"
  49. ;;
  50. *)
  51. echo "usage: signal.sh READY [test-log] | CONFLICT [reason] | RUNNING" >&2
  52. exit 1
  53. ;;
  54. esac