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.
Files changed (119) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/adapters/claude/agent-adapter.js +18 -0
  3. package/bundled/adapters/claude/command-adapter.js +1 -27
  4. package/bundled/agents/prizm-dev-team-critic.md +2 -0
  5. package/bundled/agents/prizm-dev-team-dev.md +2 -0
  6. package/bundled/agents/prizm-dev-team-reviewer.md +2 -0
  7. package/bundled/dev-pipeline/README.md +63 -63
  8. package/bundled/dev-pipeline/assets/feature-list-example.json +1 -1
  9. package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +1 -1
  10. package/bundled/dev-pipeline/{launch-daemon.sh → launch-feature-daemon.sh} +33 -33
  11. package/bundled/dev-pipeline/launch-refactor-daemon.sh +454 -0
  12. package/bundled/dev-pipeline/lib/branch.sh +1 -1
  13. package/bundled/dev-pipeline/reset-feature.sh +3 -3
  14. package/bundled/dev-pipeline/reset-refactor.sh +312 -0
  15. package/bundled/dev-pipeline/{retry-bug.sh → retry-bugfix.sh} +47 -59
  16. package/bundled/dev-pipeline/retry-feature.sh +41 -54
  17. package/bundled/dev-pipeline/retry-refactor.sh +358 -0
  18. package/bundled/dev-pipeline/run-bugfix.sh +41 -0
  19. package/bundled/dev-pipeline/{run.sh → run-feature.sh} +64 -31
  20. package/bundled/dev-pipeline/run-refactor.sh +787 -0
  21. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +398 -10
  22. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +124 -0
  23. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +419 -0
  24. package/bundled/dev-pipeline/scripts/init-refactor-pipeline.py +393 -0
  25. package/bundled/dev-pipeline/scripts/update-refactor-status.py +726 -0
  26. package/bundled/dev-pipeline/templates/agent-prompts/critic-code-challenge.md +13 -0
  27. package/bundled/dev-pipeline/templates/agent-prompts/critic-plan-challenge.md +7 -0
  28. package/bundled/dev-pipeline/templates/agent-prompts/dev-fix.md +7 -0
  29. package/bundled/dev-pipeline/templates/agent-prompts/dev-implement.md +27 -0
  30. package/bundled/dev-pipeline/templates/agent-prompts/dev-resume.md +5 -0
  31. package/bundled/dev-pipeline/templates/agent-prompts/reviewer-analyze.md +5 -0
  32. package/bundled/dev-pipeline/templates/agent-prompts/reviewer-review.md +12 -0
  33. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +33 -2
  34. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +13 -9
  35. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +16 -12
  36. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +22 -4
  37. package/bundled/dev-pipeline/templates/feature-list-schema.json +1 -1
  38. package/bundled/dev-pipeline/templates/refactor-list-schema.json +159 -0
  39. package/bundled/dev-pipeline/templates/sections/ac-verification-checklist.md +13 -0
  40. package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +36 -0
  41. package/bundled/dev-pipeline/templates/sections/failure-log-check.md +2 -1
  42. package/bundled/dev-pipeline/templates/sections/feature-context.md +1 -1
  43. package/bundled/dev-pipeline/templates/sections/phase-analyze-agent.md +11 -7
  44. package/bundled/dev-pipeline/templates/sections/phase-analyze-full.md +11 -7
  45. package/bundled/dev-pipeline/templates/sections/phase-browser-verification.md +5 -1
  46. package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +3 -0
  47. package/bundled/dev-pipeline/templates/sections/phase-commit.md +3 -0
  48. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +3 -0
  49. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +3 -0
  50. package/bundled/dev-pipeline/templates/sections/phase-critic-code.md +11 -10
  51. package/bundled/dev-pipeline/templates/sections/phase-critic-plan-full.md +12 -10
  52. package/bundled/dev-pipeline/templates/sections/phase-critic-plan.md +11 -9
  53. package/bundled/dev-pipeline/templates/sections/phase-deploy-verification.md +3 -0
  54. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +10 -10
  55. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +12 -16
  56. package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +3 -0
  57. package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +3 -0
  58. package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +3 -0
  59. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +11 -13
  60. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +12 -20
  61. package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +3 -0
  62. package/bundled/dev-pipeline/templates/sections/phase0-init.md +3 -0
  63. package/bundled/dev-pipeline/templates/sections/phase0-test-baseline.md +3 -0
  64. package/bundled/dev-pipeline/templates/sections/resume-header.md +4 -1
  65. package/bundled/dev-pipeline/templates/sections/test-failure-recovery.md +75 -0
  66. package/bundled/rules/prizm/prizm-commit-workflow.md +1 -0
  67. package/bundled/rules/prizm/prizm-documentation.md +15 -15
  68. package/bundled/rules/prizm/prizm-progressive-loading.md +2 -1
  69. package/bundled/skills/_metadata.json +33 -6
  70. package/bundled/skills/app-planner/SKILL.md +105 -320
  71. package/bundled/skills/app-planner/assets/app-design-guide.md +101 -0
  72. package/bundled/skills/app-planner/references/frontend-design-guide.md +1 -1
  73. package/bundled/skills/app-planner/references/project-brief-guide.md +49 -80
  74. package/bundled/skills/bug-fix-workflow/SKILL.md +2 -2
  75. package/bundled/skills/bug-planner/SKILL.md +68 -5
  76. package/bundled/skills/bug-planner/scripts/validate-bug-list.py +3 -2
  77. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +19 -5
  78. package/bundled/skills/{dev-pipeline-launcher → feature-pipeline-launcher}/SKILL.md +32 -32
  79. package/bundled/skills/feature-planner/SKILL.md +337 -0
  80. package/bundled/skills/{app-planner → feature-planner}/assets/evaluation-guide.md +4 -4
  81. package/bundled/skills/{app-planner → feature-planner}/assets/planning-guide.md +3 -171
  82. package/bundled/skills/{app-planner → feature-planner}/references/browser-interaction.md +6 -5
  83. package/bundled/skills/feature-planner/references/decomposition-patterns.md +75 -0
  84. package/bundled/skills/{app-planner → feature-planner}/references/error-recovery.md +8 -8
  85. package/bundled/skills/{app-planner → feature-planner}/references/incremental-feature-planning.md +1 -1
  86. package/bundled/skills/{app-planner/references/new-app-planning.md → feature-planner/references/new-project-planning.md} +1 -1
  87. package/bundled/skills/{app-planner → feature-planner}/scripts/validate-and-generate.py +4 -4
  88. package/bundled/skills/feature-workflow/SKILL.md +23 -23
  89. package/bundled/skills/prizm-kit/SKILL.md +1 -3
  90. package/bundled/skills/prizm-kit/assets/project-memory-template.md +4 -2
  91. package/bundled/skills/prizmkit-analyze/SKILL.md +2 -5
  92. package/bundled/skills/prizmkit-code-review/SKILL.md +2 -2
  93. package/bundled/skills/prizmkit-committer/SKILL.md +32 -8
  94. package/bundled/skills/prizmkit-deploy/SKILL.md +1 -5
  95. package/bundled/skills/prizmkit-implement/SKILL.md +5 -51
  96. package/bundled/skills/prizmkit-init/SKILL.md +7 -78
  97. package/bundled/skills/prizmkit-plan/SKILL.md +1 -12
  98. package/bundled/skills/prizmkit-prizm-docs/SKILL.md +13 -28
  99. package/bundled/skills/prizmkit-prizm-docs/assets/PRIZM-SPEC.md +52 -1
  100. package/bundled/skills/prizmkit-retrospective/SKILL.md +12 -117
  101. package/bundled/skills/recovery-workflow/SKILL.md +168 -316
  102. package/bundled/skills/recovery-workflow/evals/evals.json +29 -13
  103. package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +232 -274
  104. package/bundled/skills/refactor-pipeline-launcher/SKILL.md +352 -0
  105. package/bundled/skills/refactor-planner/SKILL.md +436 -0
  106. package/bundled/skills/refactor-planner/assets/planning-guide.md +292 -0
  107. package/bundled/skills/refactor-planner/references/behavior-preservation.md +301 -0
  108. package/bundled/skills/refactor-planner/references/refactor-scoping-guide.md +221 -0
  109. package/bundled/skills/refactor-planner/scripts/validate-and-generate-refactor.py +786 -0
  110. package/bundled/skills/refactor-workflow/SKILL.md +299 -319
  111. package/bundled/team/prizm-dev-team.json +1 -1
  112. package/package.json +1 -1
  113. package/src/clean.js +3 -3
  114. package/src/scaffold.js +6 -6
  115. package/bundled/skills/prizmkit-plan/assets/spec-template.md +0 -56
  116. package/bundled/skills/prizmkit-plan/references/clarify-guide.md +0 -67
  117. package/src/config.js +0 -504
  118. package/src/prompts.js +0 -210
  119. /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