feat: interactive mode — full CC sessions visible in tmux, headless mode via --headless flag
This commit is contained in:
39
loop.sh
39
loop.sh
@@ -122,6 +122,7 @@ while [[ $# -gt 0 ]]; do
|
||||
--tool=*) TOOL="${1#*=}"; shift ;;
|
||||
--no-hooks) AUTO_HOOKS=false; shift ;;
|
||||
--dry-run) DRY_RUN=true; shift ;;
|
||||
--headless) export LOOP_HEADLESS=true; shift ;;
|
||||
--resume) RESUME=true; shift ;;
|
||||
--replan) log "ERROR: --replan is not yet implemented. Use /loop-plan interactively."; exit 1 ;;
|
||||
[0-9]*) MAX_ITERATIONS="$1"; shift ;;
|
||||
@@ -186,8 +187,13 @@ if [ -n "$BRANCH" ]; then
|
||||
fi
|
||||
|
||||
# --- Agent runner ---
|
||||
# Runs a prompt through the selected AI tool and captures output.
|
||||
# Output is displayed live via tee to /dev/tty (if available) and captured to a temp file.
|
||||
# Runs a prompt through the selected AI tool.
|
||||
# Two modes:
|
||||
# Interactive (default when TTY available): runs claude in full interactive mode.
|
||||
# The user sees the complete CC session (tool calls, file edits, etc.) in the terminal.
|
||||
# Output is captured via `script` for verdict parsing.
|
||||
# Headless (no TTY or LOOP_HEADLESS=true): uses claude --print for fully autonomous operation.
|
||||
#
|
||||
# The function prints the captured output to stdout for the caller to capture.
|
||||
run_agent() {
|
||||
local prompt="$1"
|
||||
@@ -195,23 +201,29 @@ run_agent() {
|
||||
output_file=$(mktemp)
|
||||
LOOP_AGENT_TMPFILE="$output_file" # exposed for trap cleanup
|
||||
|
||||
# Determine whether we can display live output
|
||||
local prompt_file
|
||||
prompt_file=$(mktemp)
|
||||
printf '%s\n' "$prompt" > "$prompt_file"
|
||||
|
||||
# Determine whether we can run interactively
|
||||
local has_tty=false
|
||||
if { true > /dev/tty; } 2>/dev/null; then
|
||||
if [ "${LOOP_HEADLESS:-false}" != "true" ] && { true > /dev/tty; } 2>/dev/null; then
|
||||
has_tty=true
|
||||
fi
|
||||
|
||||
# Run in subshell so a non-zero exit from the AI tool doesn't kill the loop.
|
||||
# The subshell inherits set -e but its exit status is captured, not propagated.
|
||||
local agent_exit=0
|
||||
(
|
||||
case "$TOOL" in
|
||||
claude)
|
||||
if [ "$has_tty" = true ]; then
|
||||
printf '%s\n' "$prompt" | timeout "${LOOP_AGENT_TIMEOUT:-600}" \
|
||||
claude --dangerously-skip-permissions --output-format text \
|
||||
--print 2>&1 | tee /dev/tty > "$output_file"
|
||||
# Interactive mode: full CC session visible in terminal.
|
||||
# Use script to capture output while showing it live.
|
||||
# The prompt is piped via stdin; claude reads it as the initial message.
|
||||
script -q "$output_file" \
|
||||
sh -c "printf '%s\n' \"\$(cat '$prompt_file')\" | claude --dangerously-skip-permissions"
|
||||
else
|
||||
# Headless mode: --print for autonomous operation
|
||||
printf '%s\n' "$prompt" | timeout "${LOOP_AGENT_TIMEOUT:-600}" \
|
||||
claude --dangerously-skip-permissions --output-format text \
|
||||
--print 2>&1 > "$output_file"
|
||||
@@ -219,8 +231,8 @@ run_agent() {
|
||||
;;
|
||||
amp)
|
||||
if [ "$has_tty" = true ]; then
|
||||
printf '%s\n' "$prompt" | timeout "${LOOP_AGENT_TIMEOUT:-600}" \
|
||||
amp --dangerously-allow-all 2>&1 | tee /dev/tty > "$output_file"
|
||||
script -q "$output_file" \
|
||||
sh -c "printf '%s\n' \"\$(cat '$prompt_file')\" | amp --dangerously-allow-all"
|
||||
else
|
||||
printf '%s\n' "$prompt" | timeout "${LOOP_AGENT_TIMEOUT:-600}" \
|
||||
amp --dangerously-allow-all 2>&1 > "$output_file"
|
||||
@@ -233,11 +245,18 @@ run_agent() {
|
||||
esac
|
||||
) || agent_exit=$?
|
||||
|
||||
rm -f "$prompt_file"
|
||||
|
||||
if [ "$agent_exit" -ne 0 ] && [ ! -s "$output_file" ]; then
|
||||
log "WARNING: Agent exited with code $agent_exit and produced no output."
|
||||
fi
|
||||
|
||||
# Strip ANSI escape codes for clean verdict parsing
|
||||
if command -v sed &>/dev/null; then
|
||||
sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' "$output_file"
|
||||
else
|
||||
cat "$output_file"
|
||||
fi
|
||||
rm -f "$output_file"
|
||||
LOOP_AGENT_TMPFILE=""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user