2026-03-23 08:59:56 +00:00
#!/usr/bin/env bash
2026-03-19 14:57:54 +01:00
# on-idle-stop.sh — Stop hook for dark-factory agent sessions.
#
# Called by Claude Code when it finishes a response. Writes a timestamp
# to a marker file so monitor_phase_loop can detect idle sessions
# without fragile tmux pane scraping.
#
2026-03-23 09:56:49 +00:00
# When a phase file is provided and exists but is empty, Claude likely
# returned to the prompt without following the phase protocol. Instead
# of marking idle, inject a nudge into the tmux session (up to 2 times).
#
2026-03-19 14:57:54 +01:00
# Usage (in .claude/settings.json):
2026-03-23 09:56:49 +00:00
# {"type": "command", "command": "this-script /tmp/claude-idle-SESSION.ts [PHASE_FILE SESSION_NAME]"}
2026-03-19 14:57:54 +01:00
#
# Args: $1 = marker file path
2026-03-23 09:56:49 +00:00
# $2 = phase file path (optional)
# $3 = tmux session name (optional)
2026-03-19 14:57:54 +01:00
cat > /dev/null # consume hook JSON from stdin
2026-03-23 09:56:49 +00:00
MARKER = " ${ 1 :- } "
[ -z " $MARKER " ] && exit 0
PHASE_FILE = " ${ 2 :- } "
SESSION_NAME = " ${ 3 :- } "
# If phase file is provided, exists, and is empty — Claude forgot to signal.
# Nudge via tmux instead of marking idle (up to 2 attempts).
if [ -n " $PHASE_FILE " ] && [ -n " $SESSION_NAME " ] && [ -f " $PHASE_FILE " ] && [ ! -s " $PHASE_FILE " ] ; then
NUDGE_FILE = " /tmp/claude-nudge- ${ SESSION_NAME } .count "
NUDGE_COUNT = $( cat " $NUDGE_FILE " 2>/dev/null || echo 0)
if [ " $NUDGE_COUNT " -lt 2 ] ; then
echo $(( NUDGE_COUNT + 1 )) > " $NUDGE_FILE "
tmux send-keys -t " $SESSION_NAME " \
" You returned to the prompt without writing to the PHASE file. Checklist: (1) Did you complete the commit-and-pr step? (2) Did you write PHASE:done or PHASE:awaiting_ci to ${ PHASE_FILE } ? If no file changes were needed, write PHASE:done now. " Enter
exit 0
fi
fi
# Normal idle mark — either no phase file, phase already has content,
# or nudge limit reached.
date +%s > " $MARKER "