Commit Graph

1 Commits

  • feat: active hours + idle detection gates for session-guardian (#413)
    * feat: add project cooldown log to prevent rapid observer re-spawn
    
    Adds session-guardian.sh, called by observer-loop.sh before each Haiku
    spawn. It reads ~/.claude/observer-last-run.log and blocks the cycle if
    the same project was observed within OBSERVER_INTERVAL_SECONDS (default
    300s).
    
    Prevents self-referential loops where a spawned session triggers
    observe.sh, which signals the observer before the cooldown has elapsed.
    
    Uses a mkdir-based lock for safe concurrent access across multiple
    simultaneously-observed projects. Log entries use tab-delimited format
    to handle paths containing spaces. Fails open on lock contention.
    
    Config:
      OBSERVER_INTERVAL_SECONDS   default: 300
      OBSERVER_LAST_RUN_LOG       default: ~/.claude/observer-last-run.log
    
    No external dependencies. Works on macOS, Linux, Windows (Git Bash/MSYS2).
    
    * feat: extend session-guardian with time window and idle detection gates
    
    Adds Gate 1 (active hours check) and Gate 3 (system idle detection) to
    session-guardian.sh, building on the per-project cooldown log from PR 1.
    
    Gate 1 — Time Window:
    - OBSERVER_ACTIVE_HOURS_START/END (default 800–2300 local time)
    - Uses date +%k%M with 10# prefix to avoid octal crash at midnight
    - Toolless on all platforms; set both vars to 0 to disable
    
    Gate 3 — Idle Detection:
    - macOS: ioreg + awk (built-in, no deps)
    - Linux: xprintidle if available, else fail open
    - Windows (Git Bash/MSYS2): PowerShell GetLastInputInfo via Add-Type
    - Unknown/headless: always returns 0 (fail open)
    - OBSERVER_MAX_IDLE_SECONDS=0 disables gate
    
    Fixes in this commit:
    - 10# base-10 prefix prevents octal arithmetic crash on midnight minutes
      containing digits 8 or 9 (e.g. 00:08 = "008" is invalid octal)
    - PowerShell output piped through tr -d '\r' to strip Windows CRLF;
      also uses [long] cast to avoid TickCount 32-bit overflow after 24 days
    - mktemp now uses log file directory instead of TMPDIR to ensure
      same-filesystem mv on Linux (atomic rename instead of copy+unlink)
    - mkdir -p failure exits 0 (fail open) rather than crashing under set -e
    - Numeric validation on last_spawn prevents arithmetic error on corrupt log
    
    Gate execution order: 1 (time, ~0ms) → 2 (cooldown, ~1ms) → 3 (idle, ~50ms)
    
    * fix: harden session guardian gates
    
    ---------
    
    Co-authored-by: Affaan Mustafa <affaan@dcube.ai>