prizmkit 1.1.1 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled/VERSION.json +3 -3
- package/bundled/adapters/claude/agent-adapter.js +18 -0
- package/bundled/adapters/claude/command-adapter.js +1 -27
- package/bundled/agents/prizm-dev-team-critic.md +2 -0
- package/bundled/agents/prizm-dev-team-dev.md +2 -0
- package/bundled/agents/prizm-dev-team-reviewer.md +2 -0
- package/bundled/dev-pipeline/README.md +63 -63
- package/bundled/dev-pipeline/assets/feature-list-example.json +1 -1
- package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +1 -1
- package/bundled/dev-pipeline/{launch-daemon.sh → launch-feature-daemon.sh} +33 -33
- package/bundled/dev-pipeline/launch-refactor-daemon.sh +454 -0
- package/bundled/dev-pipeline/lib/branch.sh +1 -1
- package/bundled/dev-pipeline/reset-feature.sh +3 -3
- package/bundled/dev-pipeline/reset-refactor.sh +312 -0
- package/bundled/dev-pipeline/{retry-bug.sh → retry-bugfix.sh} +47 -59
- package/bundled/dev-pipeline/retry-feature.sh +41 -54
- package/bundled/dev-pipeline/retry-refactor.sh +358 -0
- package/bundled/dev-pipeline/run-bugfix.sh +41 -0
- package/bundled/dev-pipeline/{run.sh → run-feature.sh} +64 -31
- package/bundled/dev-pipeline/run-refactor.sh +787 -0
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +398 -10
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +124 -0
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +419 -0
- package/bundled/dev-pipeline/scripts/init-refactor-pipeline.py +393 -0
- package/bundled/dev-pipeline/scripts/update-refactor-status.py +726 -0
- package/bundled/dev-pipeline/templates/agent-prompts/critic-code-challenge.md +13 -0
- package/bundled/dev-pipeline/templates/agent-prompts/critic-plan-challenge.md +7 -0
- package/bundled/dev-pipeline/templates/agent-prompts/dev-fix.md +7 -0
- package/bundled/dev-pipeline/templates/agent-prompts/dev-implement.md +27 -0
- package/bundled/dev-pipeline/templates/agent-prompts/dev-resume.md +5 -0
- package/bundled/dev-pipeline/templates/agent-prompts/reviewer-analyze.md +5 -0
- package/bundled/dev-pipeline/templates/agent-prompts/reviewer-review.md +12 -0
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +33 -2
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +13 -9
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +16 -12
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +22 -4
- package/bundled/dev-pipeline/templates/feature-list-schema.json +1 -1
- package/bundled/dev-pipeline/templates/refactor-list-schema.json +159 -0
- package/bundled/dev-pipeline/templates/sections/ac-verification-checklist.md +13 -0
- package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +36 -0
- package/bundled/dev-pipeline/templates/sections/failure-log-check.md +2 -1
- package/bundled/dev-pipeline/templates/sections/feature-context.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase-analyze-agent.md +11 -7
- package/bundled/dev-pipeline/templates/sections/phase-analyze-full.md +11 -7
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification.md +5 -1
- package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-commit.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-critic-code.md +11 -10
- package/bundled/dev-pipeline/templates/sections/phase-critic-plan-full.md +12 -10
- package/bundled/dev-pipeline/templates/sections/phase-critic-plan.md +11 -9
- package/bundled/dev-pipeline/templates/sections/phase-deploy-verification.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +10 -10
- package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +12 -16
- package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +11 -13
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +12 -20
- package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase0-init.md +3 -0
- package/bundled/dev-pipeline/templates/sections/phase0-test-baseline.md +3 -0
- package/bundled/dev-pipeline/templates/sections/resume-header.md +4 -1
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery.md +75 -0
- package/bundled/rules/prizm/prizm-commit-workflow.md +1 -0
- package/bundled/rules/prizm/prizm-documentation.md +15 -15
- package/bundled/rules/prizm/prizm-progressive-loading.md +2 -1
- package/bundled/skills/_metadata.json +33 -6
- package/bundled/skills/app-planner/SKILL.md +105 -320
- package/bundled/skills/app-planner/assets/app-design-guide.md +101 -0
- package/bundled/skills/app-planner/references/frontend-design-guide.md +1 -1
- package/bundled/skills/app-planner/references/project-brief-guide.md +49 -80
- package/bundled/skills/bug-fix-workflow/SKILL.md +2 -2
- package/bundled/skills/bug-planner/SKILL.md +68 -5
- package/bundled/skills/bug-planner/scripts/validate-bug-list.py +3 -2
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +19 -5
- package/bundled/skills/{dev-pipeline-launcher → feature-pipeline-launcher}/SKILL.md +32 -32
- package/bundled/skills/feature-planner/SKILL.md +337 -0
- package/bundled/skills/{app-planner → feature-planner}/assets/evaluation-guide.md +4 -4
- package/bundled/skills/{app-planner → feature-planner}/assets/planning-guide.md +3 -171
- package/bundled/skills/{app-planner → feature-planner}/references/browser-interaction.md +6 -5
- package/bundled/skills/feature-planner/references/decomposition-patterns.md +75 -0
- package/bundled/skills/{app-planner → feature-planner}/references/error-recovery.md +8 -8
- package/bundled/skills/{app-planner → feature-planner}/references/incremental-feature-planning.md +1 -1
- package/bundled/skills/{app-planner/references/new-app-planning.md → feature-planner/references/new-project-planning.md} +1 -1
- package/bundled/skills/{app-planner → feature-planner}/scripts/validate-and-generate.py +4 -4
- package/bundled/skills/feature-workflow/SKILL.md +23 -23
- package/bundled/skills/prizm-kit/SKILL.md +1 -3
- package/bundled/skills/prizm-kit/assets/project-memory-template.md +4 -2
- package/bundled/skills/prizmkit-analyze/SKILL.md +2 -5
- package/bundled/skills/prizmkit-code-review/SKILL.md +2 -2
- package/bundled/skills/prizmkit-committer/SKILL.md +32 -8
- package/bundled/skills/prizmkit-deploy/SKILL.md +1 -5
- package/bundled/skills/prizmkit-implement/SKILL.md +5 -51
- package/bundled/skills/prizmkit-init/SKILL.md +7 -78
- package/bundled/skills/prizmkit-plan/SKILL.md +1 -12
- package/bundled/skills/prizmkit-prizm-docs/SKILL.md +13 -28
- package/bundled/skills/prizmkit-prizm-docs/assets/PRIZM-SPEC.md +52 -1
- package/bundled/skills/prizmkit-retrospective/SKILL.md +12 -117
- package/bundled/skills/recovery-workflow/SKILL.md +168 -316
- package/bundled/skills/recovery-workflow/evals/evals.json +29 -13
- package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +232 -274
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +352 -0
- package/bundled/skills/refactor-planner/SKILL.md +436 -0
- package/bundled/skills/refactor-planner/assets/planning-guide.md +292 -0
- package/bundled/skills/refactor-planner/references/behavior-preservation.md +301 -0
- package/bundled/skills/refactor-planner/references/refactor-scoping-guide.md +221 -0
- package/bundled/skills/refactor-planner/scripts/validate-and-generate-refactor.py +786 -0
- package/bundled/skills/refactor-workflow/SKILL.md +299 -319
- package/bundled/team/prizm-dev-team.json +1 -1
- package/package.json +1 -1
- package/src/clean.js +3 -3
- package/src/scaffold.js +6 -6
- package/bundled/skills/prizmkit-plan/assets/spec-template.md +0 -56
- package/bundled/skills/prizmkit-plan/references/clarify-guide.md +0 -67
- package/src/config.js +0 -504
- package/src/prompts.js +0 -210
- /package/bundled/skills/{dev-pipeline-launcher → feature-pipeline-launcher}/scripts/preflight-check.py +0 -0
|
@@ -0,0 +1,787 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# ============================================================
|
|
5
|
+
# dev-pipeline/run-refactor.sh - Autonomous Refactor Pipeline Runner
|
|
6
|
+
#
|
|
7
|
+
# Drives the prizm-dev-team through iterative AI CLI sessions to
|
|
8
|
+
# execute refactors from a refactor-list.json specification.
|
|
9
|
+
#
|
|
10
|
+
# Usage:
|
|
11
|
+
# ./run-refactor.sh run [refactor-list.json] Run all refactors
|
|
12
|
+
# ./run-refactor.sh run <refactor-id> [options] Run a single refactor
|
|
13
|
+
# ./run-refactor.sh status [refactor-list.json] Show pipeline status
|
|
14
|
+
# ./run-refactor.sh reset Clear all state
|
|
15
|
+
#
|
|
16
|
+
# Environment Variables:
|
|
17
|
+
# MAX_RETRIES Max retries per refactor (default: 3)
|
|
18
|
+
# SESSION_TIMEOUT Session timeout in seconds (default: 0 = no limit)
|
|
19
|
+
# AI_CLI AI CLI command name (auto-detected: cbc or claude)
|
|
20
|
+
# CODEBUDDY_CLI Legacy alias for AI_CLI (deprecated, use AI_CLI instead)
|
|
21
|
+
# PRIZMKIT_PLATFORM Force platform: 'codebuddy' or 'claude' (auto-detected)
|
|
22
|
+
# VERBOSE Set to 1 to enable --verbose on AI CLI
|
|
23
|
+
# HEARTBEAT_INTERVAL Heartbeat log interval in seconds (default: 30)
|
|
24
|
+
# HEARTBEAT_STALE_THRESHOLD Heartbeat stale threshold in seconds (default: 600)
|
|
25
|
+
# LOG_CLEANUP_ENABLED Run periodic log cleanup (default: 1)
|
|
26
|
+
# LOG_RETENTION_DAYS Delete logs older than N days (default: 14)
|
|
27
|
+
# LOG_MAX_TOTAL_MB Keep total logs under N MB via oldest-first cleanup (default: 1024)
|
|
28
|
+
# DEV_BRANCH Custom dev branch name (default: auto-generated refactor/pipeline-{run_id})
|
|
29
|
+
# AUTO_PUSH Auto-push to remote after successful refactor (default: 0). Set to 1 to enable.
|
|
30
|
+
# STRICT_BEHAVIOR_CHECK Force full test suite after each refactor item (default: 1)
|
|
31
|
+
# ============================================================
|
|
32
|
+
|
|
33
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
34
|
+
STATE_DIR="$SCRIPT_DIR/refactor-state"
|
|
35
|
+
SCRIPTS_DIR="$SCRIPT_DIR/scripts"
|
|
36
|
+
|
|
37
|
+
# Configuration
|
|
38
|
+
MAX_RETRIES=${MAX_RETRIES:-3}
|
|
39
|
+
SESSION_TIMEOUT=${SESSION_TIMEOUT:-0}
|
|
40
|
+
HEARTBEAT_STALE_THRESHOLD=${HEARTBEAT_STALE_THRESHOLD:-600}
|
|
41
|
+
HEARTBEAT_INTERVAL=${HEARTBEAT_INTERVAL:-30}
|
|
42
|
+
LOG_CLEANUP_ENABLED=${LOG_CLEANUP_ENABLED:-1}
|
|
43
|
+
LOG_RETENTION_DAYS=${LOG_RETENTION_DAYS:-14}
|
|
44
|
+
LOG_MAX_TOTAL_MB=${LOG_MAX_TOTAL_MB:-1024}
|
|
45
|
+
VERBOSE=${VERBOSE:-0}
|
|
46
|
+
DEV_BRANCH=${DEV_BRANCH:-""}
|
|
47
|
+
AUTO_PUSH=${AUTO_PUSH:-0}
|
|
48
|
+
STRICT_BEHAVIOR_CHECK=${STRICT_BEHAVIOR_CHECK:-1}
|
|
49
|
+
|
|
50
|
+
# Source shared common helpers (CLI/platform detection + logs + deps)
|
|
51
|
+
source "$SCRIPT_DIR/lib/common.sh"
|
|
52
|
+
prizm_detect_cli_and_platform
|
|
53
|
+
|
|
54
|
+
# Source shared heartbeat library
|
|
55
|
+
source "$SCRIPT_DIR/lib/heartbeat.sh"
|
|
56
|
+
|
|
57
|
+
# Source shared branch library
|
|
58
|
+
source "$SCRIPT_DIR/lib/branch.sh"
|
|
59
|
+
|
|
60
|
+
# Detect stream-json support
|
|
61
|
+
detect_stream_json_support "$CLI_CMD"
|
|
62
|
+
|
|
63
|
+
# Refactor list path (set in main, used by cleanup trap)
|
|
64
|
+
REFACTOR_LIST=""
|
|
65
|
+
|
|
66
|
+
# Branch tracking (for cleanup on interrupt)
|
|
67
|
+
_ORIGINAL_BRANCH=""
|
|
68
|
+
_DEV_BRANCH_NAME=""
|
|
69
|
+
|
|
70
|
+
# ============================================================
|
|
71
|
+
# Shared: Spawn AI CLI session and wait for result
|
|
72
|
+
# ============================================================
|
|
73
|
+
|
|
74
|
+
spawn_and_wait_session() {
|
|
75
|
+
local refactor_id="$1"
|
|
76
|
+
local refactor_list="$2"
|
|
77
|
+
local session_id="$3"
|
|
78
|
+
local bootstrap_prompt="$4"
|
|
79
|
+
local session_dir="$5"
|
|
80
|
+
local max_retries="$6"
|
|
81
|
+
local base_branch="${7:-main}"
|
|
82
|
+
|
|
83
|
+
local session_log="$session_dir/logs/session.log"
|
|
84
|
+
local progress_json="$session_dir/logs/progress.json"
|
|
85
|
+
|
|
86
|
+
local verbose_flag=""
|
|
87
|
+
if [[ "$VERBOSE" == "1" ]]; then
|
|
88
|
+
verbose_flag="--verbose"
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
local stream_json_flag=""
|
|
92
|
+
if [[ "$USE_STREAM_JSON" == "true" ]]; then
|
|
93
|
+
stream_json_flag="--output-format stream-json"
|
|
94
|
+
# claude-internal requires --verbose when using stream-json with -p/--print
|
|
95
|
+
verbose_flag="--verbose"
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
local model_flag=""
|
|
99
|
+
if [[ -n "${MODEL:-}" ]]; then
|
|
100
|
+
model_flag="--model $MODEL"
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# Unset CLAUDECODE to prevent "nested session" error when launched from
|
|
104
|
+
# within an existing Claude Code session (e.g. via launch-refactor-daemon.sh).
|
|
105
|
+
unset CLAUDECODE 2>/dev/null || true
|
|
106
|
+
|
|
107
|
+
case "$CLI_CMD" in
|
|
108
|
+
*claude*)
|
|
109
|
+
# Claude Code: prompt via -p, --dangerously-skip-permissions for auto-accept
|
|
110
|
+
"$CLI_CMD" \
|
|
111
|
+
-p "$(cat "$bootstrap_prompt")" \
|
|
112
|
+
--dangerously-skip-permissions \
|
|
113
|
+
$verbose_flag \
|
|
114
|
+
$stream_json_flag \
|
|
115
|
+
$model_flag \
|
|
116
|
+
> "$session_log" 2>&1 &
|
|
117
|
+
;;
|
|
118
|
+
*)
|
|
119
|
+
# CodeBuddy (cbc) and others: prompt via stdin, -y for auto-accept
|
|
120
|
+
"$CLI_CMD" \
|
|
121
|
+
--print \
|
|
122
|
+
-y \
|
|
123
|
+
$verbose_flag \
|
|
124
|
+
$stream_json_flag \
|
|
125
|
+
$model_flag \
|
|
126
|
+
< "$bootstrap_prompt" \
|
|
127
|
+
> "$session_log" 2>&1 &
|
|
128
|
+
;;
|
|
129
|
+
esac
|
|
130
|
+
local cli_pid=$!
|
|
131
|
+
|
|
132
|
+
# Start progress parser (no-op if stream-json not supported)
|
|
133
|
+
start_progress_parser "$session_log" "$progress_json" "$SCRIPTS_DIR"
|
|
134
|
+
local parser_pid="${_PARSER_PID:-}"
|
|
135
|
+
|
|
136
|
+
# Timeout watchdog
|
|
137
|
+
local watcher_pid=""
|
|
138
|
+
if [[ $SESSION_TIMEOUT -gt 0 ]]; then
|
|
139
|
+
( sleep "$SESSION_TIMEOUT" && kill -TERM "$cli_pid" 2>/dev/null ) &
|
|
140
|
+
watcher_pid=$!
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
# Heartbeat monitor
|
|
144
|
+
start_heartbeat "$cli_pid" "$session_log" "$progress_json" "$HEARTBEAT_INTERVAL"
|
|
145
|
+
local heartbeat_pid="${_HEARTBEAT_PID:-}"
|
|
146
|
+
|
|
147
|
+
# Wait for AI CLI to finish
|
|
148
|
+
local exit_code=0
|
|
149
|
+
if wait "$cli_pid" 2>/dev/null; then
|
|
150
|
+
exit_code=0
|
|
151
|
+
else
|
|
152
|
+
exit_code=$?
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
# Cleanup
|
|
156
|
+
[[ -n "$watcher_pid" ]] && kill "$watcher_pid" 2>/dev/null || true
|
|
157
|
+
stop_heartbeat "$heartbeat_pid"
|
|
158
|
+
stop_progress_parser "$parser_pid"
|
|
159
|
+
[[ -n "$watcher_pid" ]] && wait "$watcher_pid" 2>/dev/null || true
|
|
160
|
+
|
|
161
|
+
[[ $exit_code -eq 143 ]] && exit_code=124
|
|
162
|
+
|
|
163
|
+
# Session summary
|
|
164
|
+
if [[ -f "$session_log" ]]; then
|
|
165
|
+
local final_size=$(wc -c < "$session_log" 2>/dev/null | tr -d ' ')
|
|
166
|
+
local final_lines=$(wc -l < "$session_log" 2>/dev/null | tr -d ' ')
|
|
167
|
+
log_info "Session log: $final_lines lines, $((final_size / 1024))KB"
|
|
168
|
+
fi
|
|
169
|
+
log_info "exit_code=$exit_code"
|
|
170
|
+
|
|
171
|
+
# ── Determine session outcome from observable signals ──────────────
|
|
172
|
+
local session_status
|
|
173
|
+
local project_root
|
|
174
|
+
project_root="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
175
|
+
local default_branch="$base_branch"
|
|
176
|
+
|
|
177
|
+
if [[ $exit_code -eq 124 ]]; then
|
|
178
|
+
log_warn "Session timed out after ${SESSION_TIMEOUT}s"
|
|
179
|
+
session_status="timed_out"
|
|
180
|
+
elif [[ $exit_code -ne 0 ]]; then
|
|
181
|
+
log_warn "Session exited with code $exit_code"
|
|
182
|
+
session_status="crashed"
|
|
183
|
+
else
|
|
184
|
+
# Exit code 0 — check if the session actually produced commits
|
|
185
|
+
local has_commits=""
|
|
186
|
+
if git -C "$project_root" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
187
|
+
has_commits=$(git -C "$project_root" log "${default_branch}..HEAD" --oneline 2>/dev/null | head -1)
|
|
188
|
+
fi
|
|
189
|
+
|
|
190
|
+
if [[ -n "$has_commits" ]]; then
|
|
191
|
+
session_status="success"
|
|
192
|
+
else
|
|
193
|
+
local uncommitted=""
|
|
194
|
+
uncommitted=$(git -C "$project_root" status --porcelain 2>/dev/null | head -1 || true)
|
|
195
|
+
if [[ -n "$uncommitted" ]]; then
|
|
196
|
+
log_warn "Session exited cleanly but produced no commits (uncommitted changes found) — auto-committing..."
|
|
197
|
+
git -C "$project_root" add -A 2>/dev/null || true
|
|
198
|
+
if git -C "$project_root" commit --no-verify -m "chore($refactor_id): auto-commit session work" 2>/dev/null; then
|
|
199
|
+
log_info "Auto-commit succeeded"
|
|
200
|
+
session_status="success"
|
|
201
|
+
else
|
|
202
|
+
log_warn "Auto-commit failed — no changes to commit"
|
|
203
|
+
session_status="crashed"
|
|
204
|
+
fi
|
|
205
|
+
else
|
|
206
|
+
log_warn "Session exited cleanly but produced no commits and no changes"
|
|
207
|
+
session_status="crashed"
|
|
208
|
+
fi
|
|
209
|
+
fi
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
# ── Post-success validation ──────────────────────────────────────────
|
|
213
|
+
if [[ "$session_status" == "success" ]]; then
|
|
214
|
+
if git -C "$project_root" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
215
|
+
local dirty_files=""
|
|
216
|
+
dirty_files=$(git -C "$project_root" status --porcelain 2>/dev/null || true)
|
|
217
|
+
if [[ -n "$dirty_files" ]]; then
|
|
218
|
+
log_info "Auto-committing remaining session artifacts..."
|
|
219
|
+
git -C "$project_root" add -A 2>/dev/null || true
|
|
220
|
+
git -C "$project_root" commit --no-verify --amend --no-edit 2>/dev/null \
|
|
221
|
+
|| git -C "$project_root" commit --no-verify -m "chore($refactor_id): include remaining session artifacts" 2>/dev/null \
|
|
222
|
+
|| true
|
|
223
|
+
fi
|
|
224
|
+
fi
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
log_info "Session result: $session_status"
|
|
228
|
+
|
|
229
|
+
# Subagent detection
|
|
230
|
+
prizm_detect_subagents "$session_log"
|
|
231
|
+
|
|
232
|
+
# Update refactor status
|
|
233
|
+
python3 "$SCRIPTS_DIR/update-refactor-status.py" \
|
|
234
|
+
--refactor-list "$refactor_list" \
|
|
235
|
+
--state-dir "$STATE_DIR" \
|
|
236
|
+
--refactor-id "$refactor_id" \
|
|
237
|
+
--session-status "$session_status" \
|
|
238
|
+
--session-id "$session_id" \
|
|
239
|
+
--max-retries "$max_retries" \
|
|
240
|
+
--action update >/dev/null 2>&1 || true
|
|
241
|
+
|
|
242
|
+
# Commit refactor-list.json status update (pipeline management commit)
|
|
243
|
+
if ! git -C "$project_root" diff --quiet "$refactor_list" 2>/dev/null; then
|
|
244
|
+
git -C "$project_root" add "$refactor_list"
|
|
245
|
+
git -C "$project_root" commit --no-verify -m "chore($refactor_id): update refactor status" 2>/dev/null || true
|
|
246
|
+
fi
|
|
247
|
+
|
|
248
|
+
_SPAWN_RESULT="$session_status"
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
# ============================================================
|
|
252
|
+
# Graceful Shutdown
|
|
253
|
+
# ============================================================
|
|
254
|
+
|
|
255
|
+
cleanup() {
|
|
256
|
+
echo ""
|
|
257
|
+
log_warn "Received interrupt signal. Saving state..."
|
|
258
|
+
|
|
259
|
+
# Kill all child processes (claude-internal, heartbeat, progress parser, etc.)
|
|
260
|
+
kill 0 2>/dev/null || true
|
|
261
|
+
|
|
262
|
+
# Log current branch info for recovery
|
|
263
|
+
if [[ -n "$_DEV_BRANCH_NAME" ]]; then
|
|
264
|
+
log_info "Development was on branch: $_DEV_BRANCH_NAME"
|
|
265
|
+
log_info "Original branch was: $_ORIGINAL_BRANCH"
|
|
266
|
+
fi
|
|
267
|
+
|
|
268
|
+
if [[ -n "$REFACTOR_LIST" && -f "$REFACTOR_LIST" ]]; then
|
|
269
|
+
python3 "$SCRIPTS_DIR/update-refactor-status.py" \
|
|
270
|
+
--refactor-list "$REFACTOR_LIST" \
|
|
271
|
+
--state-dir "$STATE_DIR" \
|
|
272
|
+
--action pause 2>/dev/null || true
|
|
273
|
+
fi
|
|
274
|
+
|
|
275
|
+
log_info "Refactor pipeline paused. Run './run-refactor.sh run' to resume."
|
|
276
|
+
exit 130
|
|
277
|
+
}
|
|
278
|
+
trap cleanup SIGINT SIGTERM
|
|
279
|
+
|
|
280
|
+
# ============================================================
|
|
281
|
+
# Dependency Check
|
|
282
|
+
# ============================================================
|
|
283
|
+
|
|
284
|
+
check_dependencies() {
|
|
285
|
+
prizm_check_common_dependencies "$CLI_CMD"
|
|
286
|
+
local _project_root
|
|
287
|
+
_project_root="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
288
|
+
prizm_ensure_git_repo "$_project_root"
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
run_log_cleanup() {
|
|
292
|
+
if [[ "$LOG_CLEANUP_ENABLED" != "1" ]]; then
|
|
293
|
+
return 0
|
|
294
|
+
fi
|
|
295
|
+
|
|
296
|
+
local cleanup_result
|
|
297
|
+
cleanup_result=$(python3 "$SCRIPTS_DIR/cleanup-logs.py" \
|
|
298
|
+
--state-dir "$STATE_DIR" \
|
|
299
|
+
--retention-days "$LOG_RETENTION_DAYS" \
|
|
300
|
+
--max-total-mb "$LOG_MAX_TOTAL_MB" 2>/dev/null) || {
|
|
301
|
+
log_warn "Log cleanup failed (continuing)"
|
|
302
|
+
return 0
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
local deleted reclaimed_kb
|
|
306
|
+
deleted=$(echo "$cleanup_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('deleted_files', 0))" 2>/dev/null || echo "0")
|
|
307
|
+
reclaimed_kb=$(echo "$cleanup_result" | python3 -c "import sys,json; print(int(json.load(sys.stdin).get('reclaimed_bytes', 0)/1024))" 2>/dev/null || echo "0")
|
|
308
|
+
|
|
309
|
+
if [[ "$deleted" -gt 0 ]]; then
|
|
310
|
+
log_info "Log cleanup: deleted $deleted files, reclaimed ${reclaimed_kb}KB"
|
|
311
|
+
fi
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
# ============================================================
|
|
315
|
+
# run-one: Run a single refactor
|
|
316
|
+
# ============================================================
|
|
317
|
+
|
|
318
|
+
run_one() {
|
|
319
|
+
local refactor_id=""
|
|
320
|
+
local refactor_list=""
|
|
321
|
+
local dry_run=false
|
|
322
|
+
|
|
323
|
+
while [[ $# -gt 0 ]]; do
|
|
324
|
+
case "$1" in
|
|
325
|
+
--dry-run) dry_run=true; shift ;;
|
|
326
|
+
--timeout) shift; SESSION_TIMEOUT="${1:-0}"; shift ;;
|
|
327
|
+
R-*|r-*) refactor_id="$1"; shift ;;
|
|
328
|
+
*) refactor_list="$1"; shift ;;
|
|
329
|
+
esac
|
|
330
|
+
done
|
|
331
|
+
|
|
332
|
+
if [[ -z "$refactor_id" ]]; then
|
|
333
|
+
log_error "Refactor ID is required (e.g. R-001)"
|
|
334
|
+
echo ""
|
|
335
|
+
show_help
|
|
336
|
+
exit 1
|
|
337
|
+
fi
|
|
338
|
+
|
|
339
|
+
if [[ -z "$refactor_list" ]]; then
|
|
340
|
+
refactor_list="refactor-list.json"
|
|
341
|
+
fi
|
|
342
|
+
if [[ ! "$refactor_list" = /* ]]; then
|
|
343
|
+
refactor_list="$(pwd)/$refactor_list"
|
|
344
|
+
fi
|
|
345
|
+
REFACTOR_LIST="$refactor_list"
|
|
346
|
+
|
|
347
|
+
if [[ ! -f "$refactor_list" ]]; then
|
|
348
|
+
log_error "Refactor list not found: $refactor_list"
|
|
349
|
+
exit 1
|
|
350
|
+
fi
|
|
351
|
+
|
|
352
|
+
check_dependencies
|
|
353
|
+
run_log_cleanup
|
|
354
|
+
|
|
355
|
+
# Initialize state if needed
|
|
356
|
+
if [[ ! -f "$STATE_DIR/pipeline.json" ]]; then
|
|
357
|
+
log_info "Initializing refactor pipeline state..."
|
|
358
|
+
python3 "$SCRIPTS_DIR/init-refactor-pipeline.py" \
|
|
359
|
+
--refactor-list "$refactor_list" \
|
|
360
|
+
--state-dir "$STATE_DIR" >/dev/null 2>&1 || {
|
|
361
|
+
log_error "Failed to initialize refactor pipeline state"
|
|
362
|
+
exit 1
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
# Ensure state directory is gitignored
|
|
366
|
+
local _gitignore_path
|
|
367
|
+
_gitignore_path="$(cd "$SCRIPT_DIR/.." && pwd)/.gitignore"
|
|
368
|
+
local _state_rel
|
|
369
|
+
_state_rel=$(python3 -c "import os; print(os.path.relpath('$STATE_DIR', '$(cd "$SCRIPT_DIR/.." && pwd)'))" 2>/dev/null || echo "dev-pipeline/refactor-state")
|
|
370
|
+
if [[ -f "$_gitignore_path" ]]; then
|
|
371
|
+
if ! grep -qF "$_state_rel" "$_gitignore_path" 2>/dev/null; then
|
|
372
|
+
printf '\n# Pipeline runtime state (auto-added by dev-pipeline)\n%s/\n' "$_state_rel" >> "$_gitignore_path"
|
|
373
|
+
fi
|
|
374
|
+
else
|
|
375
|
+
printf '# Pipeline runtime state (auto-added by dev-pipeline)\n%s/\n' "$_state_rel" > "$_gitignore_path"
|
|
376
|
+
fi
|
|
377
|
+
fi
|
|
378
|
+
|
|
379
|
+
# Verify refactor exists
|
|
380
|
+
local refactor_title
|
|
381
|
+
refactor_title=$(python3 -c "
|
|
382
|
+
import json, sys
|
|
383
|
+
with open(sys.argv[1]) as f:
|
|
384
|
+
data = json.load(f)
|
|
385
|
+
for item in data.get('refactors', []):
|
|
386
|
+
if item.get('id') == sys.argv[2]:
|
|
387
|
+
print(item.get('title', ''))
|
|
388
|
+
sys.exit(0)
|
|
389
|
+
sys.exit(1)
|
|
390
|
+
" "$refactor_list" "$refactor_id" 2>/dev/null) || {
|
|
391
|
+
log_error "Refactor $refactor_id not found in $refactor_list"
|
|
392
|
+
exit 1
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
local refactor_complexity
|
|
396
|
+
refactor_complexity=$(python3 -c "
|
|
397
|
+
import json, sys
|
|
398
|
+
with open(sys.argv[1]) as f:
|
|
399
|
+
data = json.load(f)
|
|
400
|
+
for item in data.get('refactors', []):
|
|
401
|
+
if item.get('id') == sys.argv[2]:
|
|
402
|
+
print(item.get('complexity', 'medium'))
|
|
403
|
+
sys.exit(0)
|
|
404
|
+
sys.exit(1)
|
|
405
|
+
" "$refactor_list" "$refactor_id" 2>/dev/null) || refactor_complexity="medium"
|
|
406
|
+
|
|
407
|
+
# Reset refactor status
|
|
408
|
+
python3 "$SCRIPTS_DIR/update-refactor-status.py" \
|
|
409
|
+
--refactor-list "$refactor_list" \
|
|
410
|
+
--state-dir "$STATE_DIR" \
|
|
411
|
+
--refactor-id "$refactor_id" \
|
|
412
|
+
--action reset >/dev/null 2>&1 || true
|
|
413
|
+
|
|
414
|
+
# Generate bootstrap prompt
|
|
415
|
+
local run_id session_id session_dir bootstrap_prompt
|
|
416
|
+
run_id=$(jq -r '.run_id' "$STATE_DIR/pipeline.json")
|
|
417
|
+
session_id="${refactor_id}-$(date +%Y%m%d%H%M%S)"
|
|
418
|
+
session_dir="$STATE_DIR/refactors/$refactor_id/sessions/$session_id"
|
|
419
|
+
mkdir -p "$session_dir/logs"
|
|
420
|
+
|
|
421
|
+
bootstrap_prompt="$session_dir/bootstrap-prompt.md"
|
|
422
|
+
|
|
423
|
+
log_info "Generating refactor bootstrap prompt..."
|
|
424
|
+
python3 "$SCRIPTS_DIR/generate-refactor-prompt.py" \
|
|
425
|
+
--refactor-list "$refactor_list" \
|
|
426
|
+
--refactor-id "$refactor_id" \
|
|
427
|
+
--session-id "$session_id" \
|
|
428
|
+
--run-id "$run_id" \
|
|
429
|
+
--retry-count 0 \
|
|
430
|
+
--resume-phase "null" \
|
|
431
|
+
--state-dir "$STATE_DIR" \
|
|
432
|
+
--output "$bootstrap_prompt" >/dev/null 2>&1
|
|
433
|
+
|
|
434
|
+
if [[ "$dry_run" == true ]]; then
|
|
435
|
+
echo ""
|
|
436
|
+
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
437
|
+
echo -e "${BOLD} Dry Run: $refactor_id — $refactor_title${NC}"
|
|
438
|
+
echo -e "${BOLD} Complexity: $refactor_complexity${NC}"
|
|
439
|
+
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
440
|
+
echo ""
|
|
441
|
+
log_info "Bootstrap prompt written to:"
|
|
442
|
+
echo " $bootstrap_prompt"
|
|
443
|
+
echo ""
|
|
444
|
+
log_success "Dry run complete. Inspect full prompt with:"
|
|
445
|
+
echo " cat $bootstrap_prompt"
|
|
446
|
+
return 0
|
|
447
|
+
fi
|
|
448
|
+
|
|
449
|
+
echo ""
|
|
450
|
+
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
451
|
+
echo -e "${BOLD} Refactor: $refactor_id — $refactor_title${NC}"
|
|
452
|
+
echo -e "${BOLD} Complexity: $refactor_complexity${NC}"
|
|
453
|
+
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
454
|
+
log_info "Session ID: $session_id"
|
|
455
|
+
log_info "Prompt: $bootstrap_prompt"
|
|
456
|
+
log_info "Log: $session_dir/logs/session.log"
|
|
457
|
+
if [[ "$STRICT_BEHAVIOR_CHECK" == "1" ]]; then
|
|
458
|
+
log_info "Strict behavior check: enabled"
|
|
459
|
+
fi
|
|
460
|
+
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
461
|
+
echo ""
|
|
462
|
+
|
|
463
|
+
cleanup_single_refactor() {
|
|
464
|
+
echo ""
|
|
465
|
+
log_warn "Interrupted. Killing session..."
|
|
466
|
+
kill 0 2>/dev/null || true
|
|
467
|
+
# Log current branch info
|
|
468
|
+
if [[ -n "$_DEV_BRANCH_NAME" ]]; then
|
|
469
|
+
log_info "Development was on branch: $_DEV_BRANCH_NAME"
|
|
470
|
+
fi
|
|
471
|
+
log_info "Session log: $session_dir/logs/session.log"
|
|
472
|
+
exit 130
|
|
473
|
+
}
|
|
474
|
+
trap cleanup_single_refactor SIGINT SIGTERM
|
|
475
|
+
|
|
476
|
+
_SPAWN_RESULT=""
|
|
477
|
+
|
|
478
|
+
# Branch lifecycle: create and checkout refactor branch
|
|
479
|
+
local _proj_root
|
|
480
|
+
_proj_root="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
481
|
+
local _source_branch
|
|
482
|
+
_source_branch=$(git -C "$_proj_root" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "main")
|
|
483
|
+
_ORIGINAL_BRANCH="$_source_branch"
|
|
484
|
+
|
|
485
|
+
local _branch_name="${DEV_BRANCH:-refactor/${refactor_id}-$(date +%s)}"
|
|
486
|
+
if branch_create "$_proj_root" "$_branch_name" "$_source_branch"; then
|
|
487
|
+
_DEV_BRANCH_NAME="$_branch_name"
|
|
488
|
+
else
|
|
489
|
+
log_warn "Failed to create branch; running session on current branch"
|
|
490
|
+
fi
|
|
491
|
+
|
|
492
|
+
spawn_and_wait_session \
|
|
493
|
+
"$refactor_id" "$refactor_list" "$session_id" \
|
|
494
|
+
"$bootstrap_prompt" "$session_dir" 999 "$_ORIGINAL_BRANCH"
|
|
495
|
+
local session_status="$_SPAWN_RESULT"
|
|
496
|
+
|
|
497
|
+
# Merge dev branch back to original on success
|
|
498
|
+
if [[ "$session_status" == "success" && -n "$_DEV_BRANCH_NAME" ]]; then
|
|
499
|
+
if branch_merge "$_proj_root" "$_DEV_BRANCH_NAME" "$_ORIGINAL_BRANCH" "$AUTO_PUSH"; then
|
|
500
|
+
_DEV_BRANCH_NAME=""
|
|
501
|
+
else
|
|
502
|
+
log_warn "Auto-merge failed — dev branch preserved: $_DEV_BRANCH_NAME"
|
|
503
|
+
fi
|
|
504
|
+
fi
|
|
505
|
+
|
|
506
|
+
echo ""
|
|
507
|
+
if [[ "$session_status" == "success" ]]; then
|
|
508
|
+
log_success "════════════════════════════════════════════════════"
|
|
509
|
+
log_success " $refactor_id completed successfully!"
|
|
510
|
+
log_success "════════════════════════════════════════════════════"
|
|
511
|
+
else
|
|
512
|
+
log_error "════════════════════════════════════════════════════"
|
|
513
|
+
log_error " $refactor_id result: $session_status"
|
|
514
|
+
log_error " Review log: $session_dir/logs/session.log"
|
|
515
|
+
log_error "════════════════════════════════════════════════════"
|
|
516
|
+
fi
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
# ============================================================
|
|
520
|
+
# Main Loop: Run all refactors
|
|
521
|
+
# ============================================================
|
|
522
|
+
|
|
523
|
+
main() {
|
|
524
|
+
local refactor_list="${1:-refactor-list.json}"
|
|
525
|
+
|
|
526
|
+
if [[ ! "$refactor_list" = /* ]]; then
|
|
527
|
+
refactor_list="$(pwd)/$refactor_list"
|
|
528
|
+
fi
|
|
529
|
+
REFACTOR_LIST="$refactor_list"
|
|
530
|
+
|
|
531
|
+
if [[ ! -f "$refactor_list" ]]; then
|
|
532
|
+
log_error "Refactor list not found: $refactor_list"
|
|
533
|
+
log_info "Create a refactor list first using the refactor-planner skill,"
|
|
534
|
+
log_info "or provide a path: ./run-refactor.sh run <path-to-refactor-list.json>"
|
|
535
|
+
exit 1
|
|
536
|
+
fi
|
|
537
|
+
|
|
538
|
+
check_dependencies
|
|
539
|
+
run_log_cleanup
|
|
540
|
+
|
|
541
|
+
# Initialize pipeline state if needed
|
|
542
|
+
if [[ ! -f "$STATE_DIR/pipeline.json" ]]; then
|
|
543
|
+
log_info "Initializing refactor pipeline state..."
|
|
544
|
+
local init_result
|
|
545
|
+
init_result=$(python3 "$SCRIPTS_DIR/init-refactor-pipeline.py" \
|
|
546
|
+
--refactor-list "$refactor_list" \
|
|
547
|
+
--state-dir "$STATE_DIR" 2>&1)
|
|
548
|
+
|
|
549
|
+
local init_valid
|
|
550
|
+
init_valid=$(echo "$init_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('valid', False))" 2>/dev/null || echo "False")
|
|
551
|
+
|
|
552
|
+
if [[ "$init_valid" != "True" ]]; then
|
|
553
|
+
log_error "Refactor pipeline initialization failed:"
|
|
554
|
+
echo "$init_result"
|
|
555
|
+
exit 1
|
|
556
|
+
fi
|
|
557
|
+
|
|
558
|
+
local refactors_count
|
|
559
|
+
refactors_count=$(echo "$init_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('refactors_count', 0))" 2>/dev/null || echo "0")
|
|
560
|
+
log_success "Refactor pipeline initialized with $refactors_count refactors"
|
|
561
|
+
|
|
562
|
+
# Ensure state directory is gitignored
|
|
563
|
+
local _gitignore_path
|
|
564
|
+
_gitignore_path="$(cd "$SCRIPT_DIR/.." && pwd)/.gitignore"
|
|
565
|
+
local _state_rel
|
|
566
|
+
_state_rel=$(python3 -c "import os; print(os.path.relpath('$STATE_DIR', '$(cd "$SCRIPT_DIR/.." && pwd)'))" 2>/dev/null || echo "dev-pipeline/refactor-state")
|
|
567
|
+
if [[ -f "$_gitignore_path" ]]; then
|
|
568
|
+
if ! grep -qF "$_state_rel" "$_gitignore_path" 2>/dev/null; then
|
|
569
|
+
printf '\n# Pipeline runtime state (auto-added by dev-pipeline)\n%s/\n' "$_state_rel" >> "$_gitignore_path"
|
|
570
|
+
fi
|
|
571
|
+
else
|
|
572
|
+
printf '# Pipeline runtime state (auto-added by dev-pipeline)\n%s/\n' "$_state_rel" > "$_gitignore_path"
|
|
573
|
+
fi
|
|
574
|
+
else
|
|
575
|
+
log_info "Resuming existing refactor pipeline..."
|
|
576
|
+
fi
|
|
577
|
+
|
|
578
|
+
# Print header
|
|
579
|
+
echo ""
|
|
580
|
+
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
581
|
+
echo -e "${BOLD} Refactor Pipeline Runner Started${NC}"
|
|
582
|
+
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
583
|
+
log_info "Refactor list: $refactor_list"
|
|
584
|
+
log_info "Max retries per refactor: $MAX_RETRIES"
|
|
585
|
+
if [[ $SESSION_TIMEOUT -gt 0 ]]; then
|
|
586
|
+
log_info "Session timeout: ${SESSION_TIMEOUT}s"
|
|
587
|
+
else
|
|
588
|
+
log_info "Session timeout: none"
|
|
589
|
+
fi
|
|
590
|
+
log_info "AI CLI: $CLI_CMD (platform: $PLATFORM)"
|
|
591
|
+
if [[ -n "${MODEL:-}" ]]; then
|
|
592
|
+
log_info "Default Model: $MODEL"
|
|
593
|
+
fi
|
|
594
|
+
if [[ "$STRICT_BEHAVIOR_CHECK" == "1" ]]; then
|
|
595
|
+
log_info "Strict behavior check: enabled"
|
|
596
|
+
else
|
|
597
|
+
log_info "Strict behavior check: disabled"
|
|
598
|
+
fi
|
|
599
|
+
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
600
|
+
echo ""
|
|
601
|
+
|
|
602
|
+
# Branch lifecycle: create refactor branch for this pipeline run
|
|
603
|
+
local _proj_root
|
|
604
|
+
_proj_root="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
605
|
+
local _source_branch
|
|
606
|
+
_source_branch=$(git -C "$_proj_root" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "main")
|
|
607
|
+
_ORIGINAL_BRANCH="$_source_branch"
|
|
608
|
+
|
|
609
|
+
local run_id_for_branch
|
|
610
|
+
run_id_for_branch=$(jq -r '.run_id' "$STATE_DIR/pipeline.json" 2>/dev/null || echo "$$")
|
|
611
|
+
local _branch_name="${DEV_BRANCH:-refactor/pipeline-${run_id_for_branch}}"
|
|
612
|
+
if branch_create "$_proj_root" "$_branch_name" "$_source_branch"; then
|
|
613
|
+
_DEV_BRANCH_NAME="$_branch_name"
|
|
614
|
+
log_info "Dev branch: $_branch_name"
|
|
615
|
+
else
|
|
616
|
+
log_warn "Failed to create refactor branch; running on current branch: $_source_branch"
|
|
617
|
+
fi
|
|
618
|
+
|
|
619
|
+
local session_count=0
|
|
620
|
+
local total_subagent_calls=0
|
|
621
|
+
|
|
622
|
+
while true; do
|
|
623
|
+
# Find next refactor to process (dependency-topological order)
|
|
624
|
+
local next_refactor
|
|
625
|
+
next_refactor=$(python3 "$SCRIPTS_DIR/update-refactor-status.py" \
|
|
626
|
+
--refactor-list "$refactor_list" \
|
|
627
|
+
--state-dir "$STATE_DIR" \
|
|
628
|
+
--max-retries "$MAX_RETRIES" \
|
|
629
|
+
--action get_next 2>/dev/null) || true
|
|
630
|
+
|
|
631
|
+
if [[ "$next_refactor" == "PIPELINE_COMPLETE" ]]; then
|
|
632
|
+
echo ""
|
|
633
|
+
log_success "════════════════════════════════════════════════════"
|
|
634
|
+
log_success " All refactors processed! Refactor pipeline finished."
|
|
635
|
+
log_success " Total sessions: $session_count"
|
|
636
|
+
log_success " Total subagent calls: $total_subagent_calls"
|
|
637
|
+
log_success "════════════════════════════════════════════════════"
|
|
638
|
+
|
|
639
|
+
# Merge dev branch back to original
|
|
640
|
+
if [[ -n "$_DEV_BRANCH_NAME" ]]; then
|
|
641
|
+
if branch_merge "$_proj_root" "$_DEV_BRANCH_NAME" "$_ORIGINAL_BRANCH" "$AUTO_PUSH"; then
|
|
642
|
+
_DEV_BRANCH_NAME=""
|
|
643
|
+
else
|
|
644
|
+
log_warn "Auto-merge failed — dev branch preserved: $_DEV_BRANCH_NAME"
|
|
645
|
+
log_warn "Merge manually: git checkout $_ORIGINAL_BRANCH && git rebase $_DEV_BRANCH_NAME"
|
|
646
|
+
fi
|
|
647
|
+
fi
|
|
648
|
+
break
|
|
649
|
+
fi
|
|
650
|
+
|
|
651
|
+
if [[ "$next_refactor" == "PIPELINE_BLOCKED" ]]; then
|
|
652
|
+
log_warn "All remaining refactors are blocked (needs_info/failed)."
|
|
653
|
+
log_warn "Run './run-refactor.sh status' to see details."
|
|
654
|
+
log_warn "Waiting 60s before re-checking... (Ctrl+C to stop)"
|
|
655
|
+
sleep 60
|
|
656
|
+
continue
|
|
657
|
+
fi
|
|
658
|
+
|
|
659
|
+
# Parse refactor info
|
|
660
|
+
local refactor_id refactor_title refactor_complexity retry_count resume_phase
|
|
661
|
+
refactor_id=$(echo "$next_refactor" | jq -r '.refactor_id')
|
|
662
|
+
refactor_title=$(echo "$next_refactor" | jq -r '.title')
|
|
663
|
+
refactor_complexity=$(echo "$next_refactor" | jq -r '.complexity')
|
|
664
|
+
retry_count=$(echo "$next_refactor" | jq -r '.retry_count // 0')
|
|
665
|
+
resume_phase=$(echo "$next_refactor" | jq -r '.resume_from_phase // "null"')
|
|
666
|
+
|
|
667
|
+
echo ""
|
|
668
|
+
echo -e "${BOLD}────────────────────────────────────────────────────${NC}"
|
|
669
|
+
log_info "Refactor: ${BOLD}$refactor_id${NC} — $refactor_title"
|
|
670
|
+
log_info "Complexity: $refactor_complexity | Retry: $retry_count / $MAX_RETRIES"
|
|
671
|
+
if [[ "$resume_phase" != "null" ]]; then
|
|
672
|
+
log_info "Resuming from Phase $resume_phase"
|
|
673
|
+
fi
|
|
674
|
+
echo -e "${BOLD}────────────────────────────────────────────────────${NC}"
|
|
675
|
+
|
|
676
|
+
# Generate session
|
|
677
|
+
local session_id run_id
|
|
678
|
+
run_id=$(jq -r '.run_id' "$STATE_DIR/pipeline.json")
|
|
679
|
+
session_id="${refactor_id}-$(date +%Y%m%d%H%M%S)"
|
|
680
|
+
|
|
681
|
+
local session_dir="$STATE_DIR/refactors/$refactor_id/sessions/$session_id"
|
|
682
|
+
mkdir -p "$session_dir/logs"
|
|
683
|
+
|
|
684
|
+
local bootstrap_prompt="$session_dir/bootstrap-prompt.md"
|
|
685
|
+
python3 "$SCRIPTS_DIR/generate-refactor-prompt.py" \
|
|
686
|
+
--refactor-list "$refactor_list" \
|
|
687
|
+
--refactor-id "$refactor_id" \
|
|
688
|
+
--session-id "$session_id" \
|
|
689
|
+
--run-id "$run_id" \
|
|
690
|
+
--retry-count "$retry_count" \
|
|
691
|
+
--resume-phase "$resume_phase" \
|
|
692
|
+
--state-dir "$STATE_DIR" \
|
|
693
|
+
--output "$bootstrap_prompt" >/dev/null 2>&1
|
|
694
|
+
|
|
695
|
+
# Log agent configuration (refactor always uses dual-agent: Orchestrator + Dev + Reviewer)
|
|
696
|
+
log_info "Pipeline mode: ${BOLD}standard${NC} (Dual Agent — Orchestrator + Dev + Reviewer)"
|
|
697
|
+
log_info "Agents: 3 (critic: disabled)"
|
|
698
|
+
|
|
699
|
+
# Spawn session
|
|
700
|
+
log_info "Spawning AI CLI session: $session_id"
|
|
701
|
+
_SPAWN_RESULT=""
|
|
702
|
+
|
|
703
|
+
spawn_and_wait_session \
|
|
704
|
+
"$refactor_id" "$refactor_list" "$session_id" \
|
|
705
|
+
"$bootstrap_prompt" "$session_dir" "$MAX_RETRIES" "$_ORIGINAL_BRANCH"
|
|
706
|
+
|
|
707
|
+
session_count=$((session_count + 1))
|
|
708
|
+
total_subagent_calls=$((total_subagent_calls + _SUBAGENT_COUNT))
|
|
709
|
+
|
|
710
|
+
log_info "Pausing 5s before next refactor..."
|
|
711
|
+
sleep 5
|
|
712
|
+
done
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
# ============================================================
|
|
716
|
+
# Entry Point
|
|
717
|
+
# ============================================================
|
|
718
|
+
|
|
719
|
+
show_help() {
|
|
720
|
+
echo "Usage: $0 <command> [options]"
|
|
721
|
+
echo ""
|
|
722
|
+
echo "Commands:"
|
|
723
|
+
echo " run [refactor-list.json] Run all refactors in dependency-topological order"
|
|
724
|
+
echo " run <refactor-id> [options] Run a single refactor"
|
|
725
|
+
echo " status [refactor-list.json] Show refactor pipeline status"
|
|
726
|
+
echo " reset Clear all refactor state"
|
|
727
|
+
echo " help Show this help message"
|
|
728
|
+
echo ""
|
|
729
|
+
echo "Single Refactor Options (run <refactor-id>):"
|
|
730
|
+
echo " --dry-run Generate bootstrap prompt only, don't spawn session"
|
|
731
|
+
echo " --timeout N Session timeout in seconds (default: 0 = no limit)"
|
|
732
|
+
echo ""
|
|
733
|
+
echo "Environment Variables:"
|
|
734
|
+
echo " MAX_RETRIES Max retries per refactor (default: 3)"
|
|
735
|
+
echo " SESSION_TIMEOUT Session timeout in seconds (default: 0 = no limit)"
|
|
736
|
+
echo " AI_CLI AI CLI command name (auto-detected: cbc or claude)"
|
|
737
|
+
echo " VERBOSE Set to 1 for verbose AI CLI output"
|
|
738
|
+
echo " STRICT_BEHAVIOR_CHECK Force full test suite after each refactor (default: 1)"
|
|
739
|
+
echo " HEARTBEAT_INTERVAL Heartbeat log interval in seconds (default: 30)"
|
|
740
|
+
echo " LOG_CLEANUP_ENABLED Run log cleanup before execution (default: 1)"
|
|
741
|
+
echo " LOG_RETENTION_DAYS Delete logs older than N days (default: 14)"
|
|
742
|
+
echo " LOG_MAX_TOTAL_MB Keep total logs under N MB (default: 1024)"
|
|
743
|
+
echo ""
|
|
744
|
+
echo "Examples:"
|
|
745
|
+
echo " ./run-refactor.sh run # Run all refactors"
|
|
746
|
+
echo " ./run-refactor.sh run refactor-list.json # Custom refactor list"
|
|
747
|
+
echo " ./run-refactor.sh run R-001 --dry-run # Inspect generated prompt"
|
|
748
|
+
echo " ./run-refactor.sh run R-001 --timeout 3600 # 1h timeout"
|
|
749
|
+
echo " ./run-refactor.sh status # Show status"
|
|
750
|
+
echo " STRICT_BEHAVIOR_CHECK=0 ./run-refactor.sh run # Skip full test suite"
|
|
751
|
+
echo " MAX_RETRIES=5 ./run-refactor.sh run # Custom retries"
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
case "${1:-run}" in
|
|
755
|
+
run|resume)
|
|
756
|
+
shift || true
|
|
757
|
+
if [[ "${1:-}" =~ ^[Rr]-[0-9]+ ]]; then
|
|
758
|
+
run_one "$@"
|
|
759
|
+
else
|
|
760
|
+
main "${1:-refactor-list.json}"
|
|
761
|
+
fi
|
|
762
|
+
;;
|
|
763
|
+
status)
|
|
764
|
+
check_dependencies
|
|
765
|
+
if [[ ! -f "$STATE_DIR/pipeline.json" ]]; then
|
|
766
|
+
log_error "No refactor pipeline state found. Run './run-refactor.sh run' first."
|
|
767
|
+
exit 1
|
|
768
|
+
fi
|
|
769
|
+
python3 "$SCRIPTS_DIR/update-refactor-status.py" \
|
|
770
|
+
--refactor-list "${2:-refactor-list.json}" \
|
|
771
|
+
--state-dir "$STATE_DIR" \
|
|
772
|
+
--action status
|
|
773
|
+
;;
|
|
774
|
+
reset)
|
|
775
|
+
log_warn "Resetting refactor pipeline state..."
|
|
776
|
+
rm -rf "$STATE_DIR"
|
|
777
|
+
log_success "Refactor state cleared. Run './run-refactor.sh run' to start fresh."
|
|
778
|
+
;;
|
|
779
|
+
help|--help|-h)
|
|
780
|
+
show_help
|
|
781
|
+
;;
|
|
782
|
+
*)
|
|
783
|
+
log_error "Unknown command: $1"
|
|
784
|
+
show_help
|
|
785
|
+
exit 1
|
|
786
|
+
;;
|
|
787
|
+
esac
|