cancel-rlcr-loop.sh 5.79 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/env bash
#
# Cancel script for cancel-rlcr-loop
#
# Cancels an active RLCR loop by creating a cancel signal file
# and renaming the state file to cancel-state.md.
#
# Usage:
#   cancel-rlcr-loop.sh [--force]
#
# Exit codes:
#   0 - Successfully cancelled
#   1 - No active loop found
#   2 - Finalize phase detected, confirmation required (use --force to override)
#   3 - Other error
#

set -euo pipefail

# ========================================
# Parse Arguments
# ========================================

FORCE="false"

while [[ $# -gt 0 ]]; do
    case $1 in
        --force)
            FORCE="true"
            shift
            ;;
        -h|--help)
            cat << 'HELP_EOF'
cancel-rlcr-loop - Cancel active RLCR loop

USAGE:
  cancel-rlcr-loop.sh [OPTIONS]

OPTIONS:
  --force        Force cancel even during Finalize Phase
  -h, --help     Show this help message

EXIT CODES:
  0 - Successfully cancelled
  1 - No active loop found
  2 - Finalize phase detected, confirmation required
  3 - Other error

DESCRIPTION:
  Cancels the active RLCR loop by:
  1. Finding the most recent loop directory
  2. Creating a .cancel-requested signal file
  3. Renaming state.md, methodology-analysis-state.md, or finalize-state.md to cancel-state.md
HELP_EOF
            exit 0
            ;;
        *)
            echo "Unknown option: $1" >&2
            echo "Use --help for usage information" >&2
            exit 3
            ;;
    esac
done

# ========================================
# Find Loop Directory
# ========================================

# Source shared loop library for find_active_loop and resolve_project_root
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
source "$SCRIPT_DIR/../hooks/lib/loop-common.sh"

PROJECT_ROOT="$(resolve_project_root)" || {
    echo "Error: Cannot determine humanize project root." >&2
    echo "  Set CLAUDE_PROJECT_DIR or run inside a git repository." >&2
    exit 3
}
LOOP_BASE_DIR="$PROJECT_ROOT/.humanize/rlcr"

# PRODUCT DECISION: Cancel operates globally (no session_id filtering).
#
# Cancel is invoked as a standalone Bash command via /cancel-rlcr-loop slash command.
# Unlike hooks (PreToolUse, PostToolUse, Stop) which receive JSON with session_id,
# this script has no access to the calling session's session_id.
#
# This is intentional per AC-6: cancel is an explicit user action that should always
# succeed regardless of which session invokes it. If a user types /cancel-rlcr-loop,
# they want to cancel whatever loop is running in the current project directory.
#
# Find newest active loop directory (any session) using the same lookup as hooks
LOOP_DIR=$(find_active_loop "$LOOP_BASE_DIR")

if [[ -z "$LOOP_DIR" ]]; then
    echo "NO_LOOP"
    echo "No active RLCR loop found."
    exit 1
fi

# ========================================
# Check Loop State
# ========================================

STATE_FILE="$LOOP_DIR/state.md"
FINALIZE_STATE_FILE="$LOOP_DIR/finalize-state.md"
METHODOLOGY_ANALYSIS_STATE_FILE="$LOOP_DIR/methodology-analysis-state.md"
CANCEL_SIGNAL="$LOOP_DIR/.cancel-requested"

if [[ -f "$STATE_FILE" ]]; then
    LOOP_STATE="NORMAL_LOOP"
    ACTIVE_STATE_FILE="$STATE_FILE"
elif [[ -f "$METHODOLOGY_ANALYSIS_STATE_FILE" ]]; then
    LOOP_STATE="METHODOLOGY_ANALYSIS_PHASE"
    ACTIVE_STATE_FILE="$METHODOLOGY_ANALYSIS_STATE_FILE"
elif [[ -f "$FINALIZE_STATE_FILE" ]]; then
    LOOP_STATE="FINALIZE_PHASE"
    ACTIVE_STATE_FILE="$FINALIZE_STATE_FILE"
else
    echo "NO_ACTIVE_LOOP"
    echo "No active RLCR loop found. The loop directory exists but no active state file is present."
    exit 1
fi

# ========================================
# Extract Round Info
# ========================================

# Extract current_round and max_iterations from the state file
CURRENT_ROUND=$(grep -E '^current_round:' "$ACTIVE_STATE_FILE" | sed 's/^current_round:[[:space:]]*//' | tr -d ' ')
MAX_ITERATIONS=$(grep -E '^max_iterations:' "$ACTIVE_STATE_FILE" | sed 's/^max_iterations:[[:space:]]*//' | tr -d ' ')

# Default values if not found
CURRENT_ROUND=${CURRENT_ROUND:-"?"}
MAX_ITERATIONS=${MAX_ITERATIONS:-"?"}

# ========================================
# Handle Finalize Phase
# ========================================

if [[ "$LOOP_STATE" == "FINALIZE_PHASE" && "$FORCE" != "true" ]]; then
    echo "FINALIZE_NEEDS_CONFIRM"
    echo "loop_dir: $LOOP_DIR"
    echo "current_round: $CURRENT_ROUND"
    echo "max_iterations: $MAX_ITERATIONS"
    echo ""
    echo "The loop is currently in Finalize Phase."
    echo "After this phase completes, the loop will end without returning to Codex review."
    echo ""
    echo "Use --force to cancel anyway."
    exit 2
fi

# ========================================
# Perform Cancellation
# ========================================

# Create cancel signal file
touch "$CANCEL_SIGNAL"

# Clean up any pending session_id signal file (setup may not have completed)
rm -f "$PROJECT_ROOT/.humanize/.pending-session-id"

# Clean up methodology analysis marker files if present
rm -f "$LOOP_DIR/.methodology-exit-reason"

# Rename state file to cancel-state.md
mv "$ACTIVE_STATE_FILE" "$LOOP_DIR/cancel-state.md"

# ========================================
# Output Result
# ========================================

if [[ "$LOOP_STATE" == "NORMAL_LOOP" ]]; then
    echo "CANCELLED"
    echo "Cancelled RLCR loop (was at round $CURRENT_ROUND of $MAX_ITERATIONS)."
    echo "State preserved as cancel-state.md"
elif [[ "$LOOP_STATE" == "METHODOLOGY_ANALYSIS_PHASE" ]]; then
    echo "CANCELLED_METHODOLOGY_ANALYSIS"
    echo "Cancelled RLCR loop during Methodology Analysis Phase (was at round $CURRENT_ROUND of $MAX_ITERATIONS)."
    echo "State preserved as cancel-state.md"
else
    echo "CANCELLED_FINALIZE"
    echo "Cancelled RLCR loop during Finalize Phase (was at round $CURRENT_ROUND of $MAX_ITERATIONS)."
    echo "State preserved as cancel-state.md"
fi

exit 0