prizmkit 1.1.92 → 1.1.93
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/dev-pipeline/.env.example +0 -4
- package/bundled/dev-pipeline/README.md +9 -39
- package/bundled/dev-pipeline/SCHEMA_ANALYSIS.md +0 -4
- package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +0 -2
- package/bundled/dev-pipeline/launch-bugfix-daemon.sh +0 -1
- package/bundled/dev-pipeline/launch-feature-daemon.sh +2 -3
- package/bundled/dev-pipeline/launch-refactor-daemon.sh +0 -1
- package/bundled/dev-pipeline/run-bugfix.sh +7 -67
- package/bundled/dev-pipeline/run-feature.sh +6 -84
- package/bundled/dev-pipeline/run-recovery.sh +1 -32
- package/bundled/dev-pipeline/run-refactor.sh +6 -68
- package/bundled/dev-pipeline/tests/test-deploy-safety.sh +3 -3
- package/bundled/dev-pipeline-windows/.env.example +0 -4
- package/bundled/dev-pipeline-windows/SCHEMA_ANALYSIS.md +0 -4
- package/bundled/dev-pipeline-windows/assets/prizm-dev-team-integration.md +0 -2
- package/bundled/dev-pipeline-windows/lib/pipeline.ps1 +13 -90
- package/bundled/dev-pipeline-windows/run-recovery.ps1 +4 -19
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +1 -1
- package/bundled/skills/bugfix-pipeline-launcher/references/configuration.md +5 -15
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +4 -4
- package/bundled/skills/feature-pipeline-launcher/references/configuration.md +3 -13
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +3 -3
- package/bundled/skills/refactor-pipeline-launcher/references/configuration.md +4 -14
- package/bundled/skills-windows/bugfix-pipeline-launcher/SKILL.md +1 -1
- package/bundled/skills-windows/bugfix-pipeline-launcher/references/configuration.md +4 -14
- package/bundled/skills-windows/feature-pipeline-launcher/SKILL.md +4 -4
- package/bundled/skills-windows/feature-pipeline-launcher/references/configuration.md +2 -12
- package/bundled/skills-windows/refactor-pipeline-launcher/SKILL.md +3 -3
- package/bundled/skills-windows/refactor-pipeline-launcher/references/configuration.md +4 -14
- package/package.json +1 -1
- package/bundled/dev-pipeline/scripts/cleanup-logs.py +0 -192
- package/bundled/dev-pipeline-windows/scripts/cleanup-logs.py +0 -192
|
@@ -23,7 +23,6 @@ set -euo pipefail
|
|
|
23
23
|
# ./run-recovery.sh help Show help
|
|
24
24
|
#
|
|
25
25
|
# Environment Variables:
|
|
26
|
-
# SESSION_TIMEOUT Session timeout in seconds (default: 0 = no limit)
|
|
27
26
|
# AI_CLI AI CLI command name (auto-detected: cbc, claude, or codex)
|
|
28
27
|
# PRIZMKIT_PLATFORM Platform hint for custom AI_CLI wrappers: codebuddy, claude, or codex
|
|
29
28
|
# MODEL AI model to use (e.g. claude-opus-4.6)
|
|
@@ -62,7 +61,6 @@ if [[ -z "$RECOVERY_DETECT_SCRIPT" ]]; then
|
|
|
62
61
|
fi
|
|
63
62
|
|
|
64
63
|
# Configuration
|
|
65
|
-
SESSION_TIMEOUT=${SESSION_TIMEOUT:-0}
|
|
66
64
|
HEARTBEAT_INTERVAL=${HEARTBEAT_INTERVAL:-30}
|
|
67
65
|
STALE_KILL_THRESHOLD=${STALE_KILL_THRESHOLD:-900}
|
|
68
66
|
VERBOSE=${VERBOSE:-0}
|
|
@@ -108,7 +106,6 @@ Options (for 'run' command):
|
|
|
108
106
|
--model M Override AI model (e.g. claude-opus-4.6)
|
|
109
107
|
|
|
110
108
|
Environment Variables:
|
|
111
|
-
SESSION_TIMEOUT Session timeout in seconds (default: 0 = no limit)
|
|
112
109
|
MODEL AI model to use
|
|
113
110
|
PRIZMKIT_EFFORT AI reasoning effort (low|medium|high|xhigh|max; max is Claude Code only)
|
|
114
111
|
VERBOSE Set to 1 for verbose AI CLI output
|
|
@@ -283,13 +280,6 @@ spawn_recovery_session() {
|
|
|
283
280
|
start_progress_parser "$session_log" "$progress_json" "$SCRIPTS_DIR"
|
|
284
281
|
local parser_pid="${_PARSER_PID:-}"
|
|
285
282
|
|
|
286
|
-
# Timeout watchdog
|
|
287
|
-
local watcher_pid=""
|
|
288
|
-
if [[ $SESSION_TIMEOUT -gt 0 ]]; then
|
|
289
|
-
( sleep "$SESSION_TIMEOUT" && kill -TERM "$_SESSION_PID" 2>/dev/null ) &
|
|
290
|
-
watcher_pid=$!
|
|
291
|
-
fi
|
|
292
|
-
|
|
293
283
|
# Heartbeat monitor
|
|
294
284
|
start_heartbeat "$_SESSION_PID" "$session_log" "$progress_json" "$HEARTBEAT_INTERVAL" "$STALE_KILL_THRESHOLD"
|
|
295
285
|
_HEARTBEAT_PID="${_HEARTBEAT_PID:-}"
|
|
@@ -303,17 +293,10 @@ spawn_recovery_session() {
|
|
|
303
293
|
fi
|
|
304
294
|
_SESSION_PID=""
|
|
305
295
|
|
|
306
|
-
#
|
|
307
|
-
[[ -n "$watcher_pid" ]] && kill "$watcher_pid" 2>/dev/null || true
|
|
296
|
+
# Clean up heartbeat and parser
|
|
308
297
|
stop_heartbeat "${_HEARTBEAT_PID:-}"
|
|
309
298
|
_HEARTBEAT_PID=""
|
|
310
299
|
stop_progress_parser "$parser_pid"
|
|
311
|
-
[[ -n "$watcher_pid" ]] && wait "$watcher_pid" 2>/dev/null || true
|
|
312
|
-
|
|
313
|
-
# Map SIGTERM to timeout
|
|
314
|
-
if [[ $exit_code -eq 143 ]]; then
|
|
315
|
-
exit_code=124
|
|
316
|
-
fi
|
|
317
300
|
|
|
318
301
|
# Check for stale-kill
|
|
319
302
|
local stale_kill_marker="$session_dir/logs/stale-kill.json"
|
|
@@ -347,12 +330,6 @@ detect_session_outcome() {
|
|
|
347
330
|
local was_stale_killed=false
|
|
348
331
|
[[ -f "$stale_kill_marker" ]] && was_stale_killed=true
|
|
349
332
|
|
|
350
|
-
if [[ $exit_code -eq 124 ]]; then
|
|
351
|
-
log_warn "Session timed out"
|
|
352
|
-
echo "timed_out"
|
|
353
|
-
return
|
|
354
|
-
fi
|
|
355
|
-
|
|
356
333
|
if [[ "$was_stale_killed" == true ]]; then
|
|
357
334
|
log_warn "Session stale-killed"
|
|
358
335
|
fi
|
|
@@ -611,14 +588,6 @@ cmd_run() {
|
|
|
611
588
|
echo " • Commit manually: git add <files> && git commit"
|
|
612
589
|
echo ""
|
|
613
590
|
;;
|
|
614
|
-
timed_out)
|
|
615
|
-
log_warn "Session timed out before completing."
|
|
616
|
-
echo ""
|
|
617
|
-
echo " Options:"
|
|
618
|
-
echo " • Run recovery again: ./run-recovery.sh"
|
|
619
|
-
echo " • Increase timeout: SESSION_TIMEOUT=3600 ./run-recovery.sh"
|
|
620
|
-
echo ""
|
|
621
|
-
;;
|
|
622
591
|
no_changes)
|
|
623
592
|
log_warn "Session completed but produced no changes."
|
|
624
593
|
echo ""
|
|
@@ -16,7 +16,6 @@ set -euo pipefail
|
|
|
16
16
|
# Environment Variables:
|
|
17
17
|
# MAX_RETRIES Max code retries per refactor (default: 3)
|
|
18
18
|
# MAX_INFRA_RETRIES Max infrastructure/provider retries per refactor (default: 3)
|
|
19
|
-
# SESSION_TIMEOUT Session timeout in seconds (default: 0 = no limit)
|
|
20
19
|
# AI_CLI AI CLI command name (auto-detected: cbc, claude, or codex)
|
|
21
20
|
# CODEBUDDY_CLI Legacy alias for AI_CLI (deprecated, use AI_CLI instead)
|
|
22
21
|
# PRIZMKIT_PLATFORM Platform hint for custom AI_CLI wrappers: codebuddy, claude, or codex
|
|
@@ -24,9 +23,6 @@ set -euo pipefail
|
|
|
24
23
|
# HEARTBEAT_INTERVAL Heartbeat log interval in seconds (default: 30)
|
|
25
24
|
# STALE_KILL_THRESHOLD Auto-kill session after N seconds of no progress (default: 900)
|
|
26
25
|
# HEARTBEAT_STALE_THRESHOLD Heartbeat stale threshold in seconds (default: 600)
|
|
27
|
-
# LOG_CLEANUP_ENABLED Run periodic log cleanup (default: 1)
|
|
28
|
-
# LOG_RETENTION_DAYS Delete logs older than N days (default: 14)
|
|
29
|
-
# LOG_MAX_TOTAL_MB Keep total logs under N MB via oldest-first cleanup (default: 1024)
|
|
30
26
|
# DEV_BRANCH Custom dev branch name (default: auto-generated refactor/pipeline-{run_id})
|
|
31
27
|
# AUTO_PUSH Auto-push to remote after successful refactor (default: 0). Set to 1 to enable.
|
|
32
28
|
# STOP_ON_FAILURE Stop pipeline after a task exhausts all retries (default: 0). Set to 1 to stop.
|
|
@@ -45,13 +41,9 @@ SCRIPTS_DIR="$SCRIPT_DIR/scripts"
|
|
|
45
41
|
# Configuration
|
|
46
42
|
MAX_RETRIES=${MAX_RETRIES:-3}
|
|
47
43
|
MAX_INFRA_RETRIES=${MAX_INFRA_RETRIES:-3}
|
|
48
|
-
SESSION_TIMEOUT=${SESSION_TIMEOUT:-0}
|
|
49
44
|
HEARTBEAT_STALE_THRESHOLD=${HEARTBEAT_STALE_THRESHOLD:-600}
|
|
50
45
|
HEARTBEAT_INTERVAL=${HEARTBEAT_INTERVAL:-30}
|
|
51
46
|
STALE_KILL_THRESHOLD=${STALE_KILL_THRESHOLD:-900}
|
|
52
|
-
LOG_CLEANUP_ENABLED=${LOG_CLEANUP_ENABLED:-1}
|
|
53
|
-
LOG_RETENTION_DAYS=${LOG_RETENTION_DAYS:-14}
|
|
54
|
-
LOG_MAX_TOTAL_MB=${LOG_MAX_TOTAL_MB:-1024}
|
|
55
47
|
VERBOSE=${VERBOSE:-0}
|
|
56
48
|
MODEL=${MODEL:-""}
|
|
57
49
|
PRIZMKIT_EFFORT=${PRIZMKIT_EFFORT:-""}
|
|
@@ -119,13 +111,6 @@ spawn_and_wait_session() {
|
|
|
119
111
|
start_progress_parser "$session_log" "$progress_json" "$SCRIPTS_DIR"
|
|
120
112
|
local parser_pid="${_PARSER_PID:-}"
|
|
121
113
|
|
|
122
|
-
# Timeout watchdog
|
|
123
|
-
local watcher_pid=""
|
|
124
|
-
if [[ $SESSION_TIMEOUT -gt 0 ]]; then
|
|
125
|
-
( sleep "$SESSION_TIMEOUT" && kill -TERM "$cli_pid" 2>/dev/null ) &
|
|
126
|
-
watcher_pid=$!
|
|
127
|
-
fi
|
|
128
|
-
|
|
129
114
|
# Heartbeat monitor (with stale-kill protection)
|
|
130
115
|
start_heartbeat "$cli_pid" "$session_log" "$progress_json" "$HEARTBEAT_INTERVAL" "$STALE_KILL_THRESHOLD"
|
|
131
116
|
local heartbeat_pid="${_HEARTBEAT_PID:-}"
|
|
@@ -139,16 +124,12 @@ spawn_and_wait_session() {
|
|
|
139
124
|
fi
|
|
140
125
|
|
|
141
126
|
# Cleanup
|
|
142
|
-
[[ -n "$watcher_pid" ]] && kill "$watcher_pid" 2>/dev/null || true
|
|
143
127
|
stop_heartbeat "$heartbeat_pid"
|
|
144
128
|
stop_progress_parser "$parser_pid"
|
|
145
|
-
[[ -n "$watcher_pid" ]] && wait "$watcher_pid" 2>/dev/null || true
|
|
146
129
|
|
|
147
130
|
# Recover session log from backup if truncated by subagent stdout redirection
|
|
148
131
|
prizm_recover_session_log "$session_log"
|
|
149
132
|
|
|
150
|
-
[[ $exit_code -eq 143 ]] && exit_code=124
|
|
151
|
-
|
|
152
133
|
# Check for stale-kill marker (heartbeat killed the process due to no progress)
|
|
153
134
|
local stale_kill_marker="$session_dir/logs/stale-kill.json"
|
|
154
135
|
local was_stale_killed=false
|
|
@@ -194,10 +175,7 @@ PY
|
|
|
194
175
|
project_root="$PROJECT_ROOT"
|
|
195
176
|
local default_branch="$base_branch"
|
|
196
177
|
|
|
197
|
-
if [[ $
|
|
198
|
-
log_warn "Session timed out after ${SESSION_TIMEOUT}s"
|
|
199
|
-
session_status="timed_out"
|
|
200
|
-
elif [[ "$was_infra_error" == true ]]; then
|
|
178
|
+
if [[ "$was_infra_error" == true ]]; then
|
|
201
179
|
log_warn "Session failed due to AI CLI/provider infrastructure error"
|
|
202
180
|
log_warn "Infrastructure errors are retried without consuming code retry budget"
|
|
203
181
|
session_status="infra_error"
|
|
@@ -426,29 +404,6 @@ check_dependencies() {
|
|
|
426
404
|
prizm_ensure_git_repo "$_project_root"
|
|
427
405
|
}
|
|
428
406
|
|
|
429
|
-
run_log_cleanup() {
|
|
430
|
-
if [[ "$LOG_CLEANUP_ENABLED" != "1" ]]; then
|
|
431
|
-
return 0
|
|
432
|
-
fi
|
|
433
|
-
|
|
434
|
-
local cleanup_result
|
|
435
|
-
cleanup_result=$(python3 "$SCRIPTS_DIR/cleanup-logs.py" \
|
|
436
|
-
--state-dir "$STATE_DIR" \
|
|
437
|
-
--retention-days "$LOG_RETENTION_DAYS" \
|
|
438
|
-
--max-total-mb "$LOG_MAX_TOTAL_MB" 2>/dev/null) || {
|
|
439
|
-
log_warn "Log cleanup failed (continuing)"
|
|
440
|
-
return 0
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
local deleted reclaimed_kb
|
|
444
|
-
deleted=$(echo "$cleanup_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('deleted_files', 0))" 2>/dev/null || echo "0")
|
|
445
|
-
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")
|
|
446
|
-
|
|
447
|
-
if [[ "$deleted" -gt 0 ]]; then
|
|
448
|
-
log_info "Log cleanup: deleted $deleted files, reclaimed ${reclaimed_kb}KB"
|
|
449
|
-
fi
|
|
450
|
-
}
|
|
451
|
-
|
|
452
407
|
# ============================================================
|
|
453
408
|
# run-one: Run a single refactor
|
|
454
409
|
# ============================================================
|
|
@@ -467,7 +422,6 @@ run_one() {
|
|
|
467
422
|
--dry-run) dry_run=true; shift ;;
|
|
468
423
|
--clean) do_clean=true; shift ;;
|
|
469
424
|
--no-reset) no_reset=true; shift ;;
|
|
470
|
-
--timeout) shift; SESSION_TIMEOUT="${1:-0}"; shift ;;
|
|
471
425
|
--max-infra-retries)
|
|
472
426
|
shift
|
|
473
427
|
if [[ $# -eq 0 ]]; then
|
|
@@ -518,7 +472,6 @@ run_one() {
|
|
|
518
472
|
fi
|
|
519
473
|
|
|
520
474
|
check_dependencies
|
|
521
|
-
run_log_cleanup
|
|
522
475
|
|
|
523
476
|
# Initialize state if needed
|
|
524
477
|
if [[ ! -f "$STATE_DIR/pipeline.json" ]]; then
|
|
@@ -907,7 +860,6 @@ main() {
|
|
|
907
860
|
fi
|
|
908
861
|
|
|
909
862
|
check_dependencies
|
|
910
|
-
run_log_cleanup
|
|
911
863
|
|
|
912
864
|
# Initialize pipeline state if needed
|
|
913
865
|
if [[ ! -f "$STATE_DIR/pipeline.json" ]]; then
|
|
@@ -956,11 +908,6 @@ main() {
|
|
|
956
908
|
log_info "Refactor list: $refactor_list"
|
|
957
909
|
log_info "Max code retries per refactor: $MAX_RETRIES"
|
|
958
910
|
log_info "Max infrastructure retries per refactor: $MAX_INFRA_RETRIES"
|
|
959
|
-
if [[ $SESSION_TIMEOUT -gt 0 ]]; then
|
|
960
|
-
log_info "Session timeout: ${SESSION_TIMEOUT}s"
|
|
961
|
-
else
|
|
962
|
-
log_info "Session timeout: none"
|
|
963
|
-
fi
|
|
964
911
|
log_info "AI CLI: $CLI_CMD (platform: $PLATFORM)"
|
|
965
912
|
if [[ -n "${MODEL:-}" ]]; then
|
|
966
913
|
log_info "Default Model: $MODEL"
|
|
@@ -1112,17 +1059,14 @@ DEPLOY_PROMPT_EOF
|
|
|
1112
1059
|
fi
|
|
1113
1060
|
echo -e "${BOLD}────────────────────────────────────────────────────${NC}"
|
|
1114
1061
|
|
|
1115
|
-
#
|
|
1116
|
-
#
|
|
1117
|
-
# submodule dirt, specs, and root-level hidden tool temporary worktrees
|
|
1118
|
-
# must never be swept into main by a broad git add.
|
|
1062
|
+
# Auto-commit any uncommitted workspace changes before starting the pipeline.
|
|
1063
|
+
# This ensures a clean baseline without blocking execution.
|
|
1119
1064
|
local _dirty_files=""
|
|
1120
1065
|
_dirty_files=$(prizm_git_status_non_bookkeeping "$_proj_root" "$STATE_DIR" "$refactor_list" || true)
|
|
1121
1066
|
if [[ -n "$_dirty_files" ]]; then
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
break
|
|
1067
|
+
log_info "Auto-committing workspace changes before $refactor_id..."
|
|
1068
|
+
prizm_git_add_all_safe "$_proj_root"
|
|
1069
|
+
git -C "$_proj_root" commit --no-verify -m "chore: workspace snapshot ready for run $refactor_id" 2>/dev/null || true
|
|
1126
1070
|
fi
|
|
1127
1071
|
|
|
1128
1072
|
local _bookkeeping_dirty=""
|
|
@@ -1315,7 +1259,6 @@ show_help() {
|
|
|
1315
1259
|
echo " --dry-run Generate bootstrap prompt only, don't spawn session"
|
|
1316
1260
|
echo " --clean Delete artifacts and reset before running"
|
|
1317
1261
|
echo " --no-reset Skip status reset (preserve retry count)"
|
|
1318
|
-
echo " --timeout N Session timeout in seconds (default: 0 = no limit)"
|
|
1319
1262
|
echo " --max-infra-retries N Max infrastructure/provider retries (default: 3)"
|
|
1320
1263
|
echo " --mode <lite|standard|full> Override pipeline mode"
|
|
1321
1264
|
echo " --critic Enable adversarial critic review"
|
|
@@ -1327,7 +1270,6 @@ show_help() {
|
|
|
1327
1270
|
echo "Environment Variables:"
|
|
1328
1271
|
echo " MAX_RETRIES Max code retries per refactor (default: 3)"
|
|
1329
1272
|
echo " MAX_INFRA_RETRIES Max infrastructure/provider retries per refactor (default: 3)"
|
|
1330
|
-
echo " SESSION_TIMEOUT Session timeout in seconds (default: 0 = no limit)"
|
|
1331
1273
|
echo " MODEL Default AI model (overridden by per-refactor model in refactor list)"
|
|
1332
1274
|
echo " PRIZMKIT_EFFORT AI reasoning effort (low|medium|high|xhigh|max; max is Claude Code only)"
|
|
1333
1275
|
echo " PIPELINE_MODE Default pipeline mode: lite|standard|full (overridden by --mode)"
|
|
@@ -1338,15 +1280,11 @@ show_help() {
|
|
|
1338
1280
|
echo " HEARTBEAT_INTERVAL Heartbeat log interval in seconds (default: 30)"
|
|
1339
1281
|
echo " STALE_KILL_THRESHOLD Auto-kill session after N seconds of no progress (default: 900)"
|
|
1340
1282
|
echo " STOP_ON_FAILURE Stop pipeline when a task exhausts retries: 0|1 (default: 0)"
|
|
1341
|
-
echo " LOG_CLEANUP_ENABLED Run log cleanup before execution (default: 1)"
|
|
1342
|
-
echo " LOG_RETENTION_DAYS Delete logs older than N days (default: 14)"
|
|
1343
|
-
echo " LOG_MAX_TOTAL_MB Keep total logs under N MB (default: 1024)"
|
|
1344
1283
|
echo ""
|
|
1345
1284
|
echo "Examples:"
|
|
1346
1285
|
echo " ./run-refactor.sh run # Run all refactors"
|
|
1347
1286
|
echo " ./run-refactor.sh run .prizmkit/plans/refactor-list.json # Custom refactor list"
|
|
1348
1287
|
echo " ./run-refactor.sh run R-001 --dry-run # Inspect generated prompt"
|
|
1349
|
-
echo " ./run-refactor.sh run R-001 --timeout 3600 # 1h timeout"
|
|
1350
1288
|
echo " ./run-refactor.sh status # Show status"
|
|
1351
1289
|
echo " STRICT_BEHAVIOR_CHECK=0 ./run-refactor.sh run # Skip full test suite"
|
|
1352
1290
|
echo " MAX_RETRIES=5 ./run-refactor.sh run # Custom retries"
|
|
@@ -80,10 +80,10 @@ else
|
|
|
80
80
|
fail "incomplete_count=$count, expected 0"
|
|
81
81
|
fi
|
|
82
82
|
|
|
83
|
-
# --- Test 4:
|
|
84
|
-
echo "[Test 4] '
|
|
83
|
+
# --- Test 4: auto_skipped status -> deploy blocked ---
|
|
84
|
+
echo "[Test 4] 'auto_skipped' status: incomplete_count should be 1"
|
|
85
85
|
cat > /tmp/test-deploy-timeout.json << 'JSON'
|
|
86
|
-
{"features": [{"id": "F-A", "status": "completed"}, {"id": "F-B", "status": "
|
|
86
|
+
{"features": [{"id": "F-A", "status": "completed"}, {"id": "F-B", "status": "auto_skipped"}]}
|
|
87
87
|
JSON
|
|
88
88
|
count=$(python3 -c "
|
|
89
89
|
import json
|
|
@@ -19,16 +19,12 @@
|
|
|
19
19
|
|
|
20
20
|
# ─── Pipeline Execution ──────────────────────────────────────────────
|
|
21
21
|
# MAX_RETRIES=3 # Max retry attempts per task before marking failed
|
|
22
|
-
# SESSION_TIMEOUT=0 # Session timeout in seconds (0 = no limit)
|
|
23
22
|
# VERBOSE=1 # Verbose logging (1=on, 0=off)
|
|
24
23
|
# HEARTBEAT_INTERVAL=30 # Poll interval for session progress/stale checks
|
|
25
24
|
# STALE_KILL_THRESHOLD=900 # Auto-kill session after N seconds without parent log progress (0 = disabled)
|
|
26
25
|
# STALE_KILL_GRACE_SECONDS=10 # Grace period after stale-kill before force-stopping the job
|
|
27
26
|
# CODEX_WAIT_STALE_KILL_THRESHOLD=3600 # Longer no-log window while Codex waits on subagents
|
|
28
27
|
# CODEX_SUBAGENT_TIMEOUT_SECONDS=3300 # Codex subagent max runtime; defaults to wait threshold - 300
|
|
29
|
-
# LOG_CLEANUP_ENABLED=1 # Run periodic session log cleanup
|
|
30
|
-
# LOG_RETENTION_DAYS=14 # Delete session logs older than N days
|
|
31
|
-
# LOG_MAX_TOTAL_MB=1024 # Keep total logs under N MB via oldest-first cleanup
|
|
32
28
|
# STOP_ON_FAILURE=0 # Stop after the first failed task (1=stop, 0=continue)
|
|
33
29
|
# ENABLE_DEPLOY=0 # Start a deploy session after all tasks complete successfully
|
|
34
30
|
# DEV_BRANCH= # Optional custom dev branch name for each task
|
|
@@ -343,16 +343,12 @@ pending, in_progress, completed, failed, skipped
|
|
|
343
343
|
| `AI_CLI` | string | auto-detect | codex, claude, or cbc |
|
|
344
344
|
| `MODEL` | string | (unset) | AI model override (per-task overrides this) |
|
|
345
345
|
| `MAX_RETRIES` | integer | (not specified) | Retry attempts per task |
|
|
346
|
-
| `SESSION_TIMEOUT` | integer | 0 | 0 = no limit |
|
|
347
346
|
| `VERBOSE` | integer | (not specified) | 1=on, 0=off |
|
|
348
347
|
| `HEARTBEAT_INTERVAL` | integer | 30 | Poll interval for session progress/stale checks |
|
|
349
348
|
| `STALE_KILL_THRESHOLD` | integer | 900 | Auto-kill after N seconds without parent log progress; 0 disables |
|
|
350
349
|
| `STALE_KILL_GRACE_SECONDS` | integer | 10 | Grace period after stale-kill before force-stopping |
|
|
351
350
|
| `CODEX_WAIT_STALE_KILL_THRESHOLD` | integer | 3600 | Longer no-log stale window while Codex waits on subagents |
|
|
352
351
|
| `CODEX_SUBAGENT_TIMEOUT_SECONDS` | integer | 3300 | Codex subagent max runtime |
|
|
353
|
-
| `LOG_CLEANUP_ENABLED` | boolean | 1 | Periodic session log cleanup |
|
|
354
|
-
| `LOG_RETENTION_DAYS` | integer | 14 | Delete session logs older than N days |
|
|
355
|
-
| `LOG_MAX_TOTAL_MB` | integer | 1024 | Keep total logs under N MB |
|
|
356
352
|
| `STOP_ON_FAILURE` | boolean | 0 | Stop after a task exhausts retries |
|
|
357
353
|
| `ENABLE_DEPLOY` | boolean | 0 | Start deploy session after all tasks complete |
|
|
358
354
|
| `DEV_BRANCH` | string | auto-generated | Optional custom dev branch name |
|
|
@@ -51,7 +51,6 @@ Located at `.prizmkit/dev-pipeline/scripts/`:
|
|
|
51
51
|
| `check-session-status.py` | Read and validate session-status.json output |
|
|
52
52
|
| `detect-stuck.py` | Detect stuck/hung pipeline sessions via heartbeat |
|
|
53
53
|
| `parse-stream-progress.py` | Parse AI CLI output stream for progress tracking |
|
|
54
|
-
| `cleanup-logs.py` | Clean up old pipeline logs and state files |
|
|
55
54
|
| `utils.py` | Shared utility functions for pipeline scripts |
|
|
56
55
|
|
|
57
56
|
## Artifact Mapping
|
|
@@ -125,7 +124,6 @@ The agent MUST write `session-status.json` before exiting:
|
|
|
125
124
|
| `status: "partial"`, `can_resume: false` | Retry from scratch |
|
|
126
125
|
| `status: "failed"` | Retry (up to MAX_RETRIES) |
|
|
127
126
|
| No status file (crash) | Treat as failed, retry |
|
|
128
|
-
| Timeout (exit 124) | Treat as timed_out, retry |
|
|
129
127
|
|
|
130
128
|
## Team Naming Convention
|
|
131
129
|
|
|
@@ -44,7 +44,7 @@ function Invoke-PrizmPipeline {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
if ($command -in @('help','--help','-h')) {
|
|
47
|
-
Write-Host "Usage: .\run-$Kind.ps1 run [item-id] [list-path] [--dry-run] [--mode lite|standard|full] [--critic] [--max-retries N] [--max-infra-retries N]
|
|
47
|
+
Write-Host "Usage: .\run-$Kind.ps1 run [item-id] [list-path] [--dry-run] [--mode lite|standard|full] [--critic] [--max-retries N] [--max-infra-retries N]"
|
|
48
48
|
Write-Host " .\run-$Kind.ps1 status [list-path]"
|
|
49
49
|
Write-Host " .\run-$Kind.ps1 reset"
|
|
50
50
|
Write-Host ""
|
|
@@ -90,14 +90,6 @@ function Invoke-PrizmPipeline {
|
|
|
90
90
|
$maxInfraRetries = $null
|
|
91
91
|
if ($envMaxInfraRetryArgs.Count -gt 0) { $maxInfraRetries = [int]$envMaxInfraRetryArgs[1] }
|
|
92
92
|
$verboseEnabled = $env:VERBOSE -in @('1','true','yes','on')
|
|
93
|
-
$timeoutSeconds = 0
|
|
94
|
-
if ($env:SESSION_TIMEOUT) {
|
|
95
|
-
$parsedEnvTimeout = 0
|
|
96
|
-
if (-not [int]::TryParse($env:SESSION_TIMEOUT, [ref]$parsedEnvTimeout) -or $parsedEnvTimeout -lt 0) {
|
|
97
|
-
throw "SESSION_TIMEOUT must be a non-negative integer: $($env:SESSION_TIMEOUT)"
|
|
98
|
-
}
|
|
99
|
-
$timeoutSeconds = $parsedEnvTimeout
|
|
100
|
-
}
|
|
101
93
|
$heartbeatInterval = 30
|
|
102
94
|
if ($env:HEARTBEAT_INTERVAL) {
|
|
103
95
|
$parsedHeartbeatInterval = 0
|
|
@@ -126,26 +118,6 @@ function Invoke-PrizmPipeline {
|
|
|
126
118
|
$enableDeploy = $env:ENABLE_DEPLOY -in @('1','true','yes','on')
|
|
127
119
|
$stopOnFailure = $env:STOP_ON_FAILURE -in @('1','true','yes','on')
|
|
128
120
|
$devBranchOverride = if ($env:DEV_BRANCH) { $env:DEV_BRANCH.Trim() } else { '' }
|
|
129
|
-
$logCleanupEnabled = $true
|
|
130
|
-
if ($env:LOG_CLEANUP_ENABLED) {
|
|
131
|
-
$logCleanupEnabled = $env:LOG_CLEANUP_ENABLED -in @('1','true','yes','on')
|
|
132
|
-
}
|
|
133
|
-
$logRetentionDays = 14
|
|
134
|
-
if ($env:LOG_RETENTION_DAYS) {
|
|
135
|
-
$parsedLogRetentionDays = 0
|
|
136
|
-
if (-not [int]::TryParse($env:LOG_RETENTION_DAYS, [ref]$parsedLogRetentionDays) -or $parsedLogRetentionDays -lt 0) {
|
|
137
|
-
throw "LOG_RETENTION_DAYS must be a non-negative integer: $($env:LOG_RETENTION_DAYS)"
|
|
138
|
-
}
|
|
139
|
-
$logRetentionDays = $parsedLogRetentionDays
|
|
140
|
-
}
|
|
141
|
-
$logMaxTotalMb = 1024
|
|
142
|
-
if ($env:LOG_MAX_TOTAL_MB) {
|
|
143
|
-
$parsedLogMaxTotalMb = 0
|
|
144
|
-
if (-not [int]::TryParse($env:LOG_MAX_TOTAL_MB, [ref]$parsedLogMaxTotalMb) -or $parsedLogMaxTotalMb -lt 0) {
|
|
145
|
-
throw "LOG_MAX_TOTAL_MB must be a non-negative integer: $($env:LOG_MAX_TOTAL_MB)"
|
|
146
|
-
}
|
|
147
|
-
$logMaxTotalMb = $parsedLogMaxTotalMb
|
|
148
|
-
}
|
|
149
121
|
$featuresFilter = $null
|
|
150
122
|
|
|
151
123
|
for ($i = 0; $i -lt $remaining.Count; $i++) {
|
|
@@ -173,16 +145,6 @@ function Invoke-PrizmPipeline {
|
|
|
173
145
|
$maxInfraRetries = $parsedMaxInfraRetries
|
|
174
146
|
continue
|
|
175
147
|
}
|
|
176
|
-
'^--timeout$' {
|
|
177
|
-
$i++
|
|
178
|
-
if ($i -ge $remaining.Count) { throw '--timeout requires a seconds value.' }
|
|
179
|
-
$parsedTimeout = 0
|
|
180
|
-
if (-not [int]::TryParse($remaining[$i], [ref]$parsedTimeout) -or $parsedTimeout -lt 0) {
|
|
181
|
-
throw "--timeout must be a non-negative integer: $($remaining[$i])"
|
|
182
|
-
}
|
|
183
|
-
$timeoutSeconds = $parsedTimeout
|
|
184
|
-
continue
|
|
185
|
-
}
|
|
186
148
|
'^--features$' { $i++; $featuresFilter = $remaining[$i]; continue }
|
|
187
149
|
'^-' { Write-PrizmWarn "Ignoring unsupported option: $arg"; continue }
|
|
188
150
|
default {
|
|
@@ -205,7 +167,7 @@ function Invoke-PrizmPipeline {
|
|
|
205
167
|
$retryLabel = if ($maxRetries -ne $null) { [string]$maxRetries } else { 'default' }
|
|
206
168
|
$infraRetryLabel = if ($maxInfraRetries -ne $null) { [string]$maxInfraRetries } else { 'default' }
|
|
207
169
|
Write-PrizmInfo "Verbose mode enabled."
|
|
208
|
-
Write-PrizmInfo "Effective options: mode=$modeLabel critic=$criticLabel maxRetries=$retryLabel maxInfraRetries=$infraRetryLabel
|
|
170
|
+
Write-PrizmInfo "Effective options: mode=$modeLabel critic=$criticLabel maxRetries=$retryLabel maxInfraRetries=$infraRetryLabel staleKillThreshold=$staleKillThreshold dryRun=$dryRun"
|
|
209
171
|
}
|
|
210
172
|
|
|
211
173
|
# Validate PRIZMKIT_EFFORT early (fail-fast before any sessions are spawned)
|
|
@@ -571,26 +533,6 @@ function Invoke-PrizmPipeline {
|
|
|
571
533
|
}
|
|
572
534
|
}
|
|
573
535
|
|
|
574
|
-
function Invoke-PrizmLogCleanup {
|
|
575
|
-
if (-not $logCleanupEnabled) { return }
|
|
576
|
-
if (-not (Test-Path $stateDir)) { return }
|
|
577
|
-
|
|
578
|
-
try {
|
|
579
|
-
$cleanup = Invoke-PrizmPythonJson $python @(
|
|
580
|
-
(Join-Path $paths.ScriptsDir 'cleanup-logs.py'),
|
|
581
|
-
'--state-dir', $stateDir,
|
|
582
|
-
'--retention-days', [string]$logRetentionDays,
|
|
583
|
-
'--max-total-mb', [string]$logMaxTotalMb
|
|
584
|
-
)
|
|
585
|
-
if ($cleanup -and $cleanup.deleted_files -gt 0) {
|
|
586
|
-
$reclaimedKb = [int]([int64]$cleanup.reclaimed_bytes / 1024)
|
|
587
|
-
Write-PrizmInfo "Log cleanup: deleted $($cleanup.deleted_files) files, reclaimed ${reclaimedKb}KB"
|
|
588
|
-
}
|
|
589
|
-
} catch {
|
|
590
|
-
Write-PrizmWarn "Log cleanup failed (continuing)"
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
|
|
594
536
|
function Get-PrizmDeployIncompleteItems {
|
|
595
537
|
param([string]$Kind, [string]$ListPath)
|
|
596
538
|
|
|
@@ -694,11 +636,12 @@ function Invoke-PrizmPipeline {
|
|
|
694
636
|
$devBranchName = ''
|
|
695
637
|
$hadDirtyBaseline = if ($isGitRepository) { Test-PrizmGitWorkDirty $paths.ProjectRoot $stateDir $listPath } else { $false }
|
|
696
638
|
if ($hadDirtyBaseline) {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
639
|
+
if ($dryRun) {
|
|
640
|
+
Write-PrizmWarn "Dirty working tree detected before $CurrentItemId; would auto-commit snapshot in real run."
|
|
641
|
+
} else {
|
|
642
|
+
Write-PrizmInfo "Dirty working tree detected before $CurrentItemId; auto-committing snapshot."
|
|
643
|
+
Invoke-PrizmGitAutoCommit $paths.ProjectRoot "chore: workspace snapshot ready for run $CurrentItemId" | Out-Null
|
|
644
|
+
}
|
|
702
645
|
}
|
|
703
646
|
|
|
704
647
|
if ($dryRun) {
|
|
@@ -788,16 +731,13 @@ function Invoke-PrizmPipeline {
|
|
|
788
731
|
$previousProgressSignature = ''
|
|
789
732
|
$previousChildActivitySignature = ''
|
|
790
733
|
$previousErrorLoopSignature = ''
|
|
791
|
-
$wasTimedOut = $false
|
|
792
734
|
$staleKillMarker = Join-Path $logsDir 'stale-kill.json'
|
|
793
735
|
$wasStaleKilled = $false
|
|
794
736
|
while ($true) {
|
|
795
|
-
$
|
|
796
|
-
$waitSeconds = if ($timeoutSeconds -gt 0) { [Math]::Min($heartbeatInterval, [Math]::Max(1, $remainingTimeout)) } else { $heartbeatInterval }
|
|
797
|
-
$completed = Wait-Job $job -Timeout $waitSeconds
|
|
737
|
+
$completed = Wait-Job $job -Timeout $heartbeatInterval
|
|
798
738
|
if ($completed) { break }
|
|
799
739
|
|
|
800
|
-
$elapsedSeconds += $
|
|
740
|
+
$elapsedSeconds += $heartbeatInterval
|
|
801
741
|
$currentLogSize = 0
|
|
802
742
|
if (Test-Path $sessionLog) {
|
|
803
743
|
$currentLogSize = [int64](Get-Item $sessionLog).Length
|
|
@@ -851,13 +791,7 @@ function Invoke-PrizmPipeline {
|
|
|
851
791
|
$staleSeconds = 0
|
|
852
792
|
} else {
|
|
853
793
|
$staleReason = 'stale_session'
|
|
854
|
-
$staleSeconds += $
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
if ($timeoutSeconds -gt 0 -and $elapsedSeconds -ge $timeoutSeconds) {
|
|
858
|
-
$wasTimedOut = $true
|
|
859
|
-
Stop-PrizmSessionProcess $pidPath
|
|
860
|
-
break
|
|
794
|
+
$staleSeconds += $heartbeatInterval
|
|
861
795
|
}
|
|
862
796
|
|
|
863
797
|
$fatalErrorCode = Get-PrizmProgressFatalErrorCode -ProgressFile $progressJson
|
|
@@ -886,11 +820,7 @@ function Invoke-PrizmPipeline {
|
|
|
886
820
|
}
|
|
887
821
|
|
|
888
822
|
$exitCode = 0
|
|
889
|
-
if ($
|
|
890
|
-
Stop-Job $job
|
|
891
|
-
Remove-Job $job
|
|
892
|
-
$exitCode = 124
|
|
893
|
-
} elseif ($wasStaleKilled) {
|
|
823
|
+
if ($wasStaleKilled) {
|
|
894
824
|
Stop-Job $job
|
|
895
825
|
Remove-Job $job
|
|
896
826
|
$exitCode = 143
|
|
@@ -923,7 +853,7 @@ function Invoke-PrizmPipeline {
|
|
|
923
853
|
$status = 'crashed'
|
|
924
854
|
if ($semanticCompletion) {
|
|
925
855
|
$status = 'success'
|
|
926
|
-
if ($exitCode -ne 0 -or $wasStaleKilled -or $
|
|
856
|
+
if ($exitCode -ne 0 -or $wasStaleKilled -or $wasAiRuntimeError) {
|
|
927
857
|
Write-PrizmWarn "Session ended with a failure signal after semantic completion; treating as finalized success"
|
|
928
858
|
Write-PrizmWarn "Semantic completion commit: $($semanticCompletion.CommitSha)"
|
|
929
859
|
}
|
|
@@ -931,9 +861,6 @@ function Invoke-PrizmPipeline {
|
|
|
931
861
|
$status = 'infra_error'
|
|
932
862
|
Write-PrizmWarn "AI session failed due to structured AI runtime/context error"
|
|
933
863
|
Write-PrizmWarn "AI runtime errors are retried without consuming code retry budget"
|
|
934
|
-
} elseif ($wasTimedOut) {
|
|
935
|
-
$status = 'timed_out'
|
|
936
|
-
Write-PrizmWarn "AI session timed out after $timeoutSeconds seconds"
|
|
937
864
|
} elseif ($wasInfraError) {
|
|
938
865
|
$status = 'infra_error'
|
|
939
866
|
Write-PrizmWarn "AI session failed due to AI CLI/provider infrastructure error"
|
|
@@ -1027,10 +954,6 @@ function Invoke-PrizmPipeline {
|
|
|
1027
954
|
return
|
|
1028
955
|
}
|
|
1029
956
|
|
|
1030
|
-
if (-not $dryRun) {
|
|
1031
|
-
Invoke-PrizmLogCleanup
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
957
|
if ($itemId) {
|
|
1035
958
|
Invoke-PrizmPipelineItem $itemId
|
|
1036
959
|
$global:PRIZM_EXIT_CODE = $script:PRIZM_ITEM_EXIT_CODE
|
|
@@ -62,7 +62,6 @@ function Get-PrizmRecoveryIntEnv {
|
|
|
62
62
|
return $parsed
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
$timeoutSeconds = Get-PrizmRecoveryIntEnv 'SESSION_TIMEOUT' 0 0
|
|
66
65
|
$heartbeatInterval = Get-PrizmRecoveryIntEnv 'HEARTBEAT_INTERVAL' 30 1
|
|
67
66
|
$staleKillThreshold = Get-PrizmRecoveryIntEnv 'STALE_KILL_THRESHOLD' 900 0
|
|
68
67
|
$staleKillGraceSeconds = Get-PrizmRecoveryIntEnv 'STALE_KILL_GRACE_SECONDS' 10 0
|
|
@@ -123,15 +122,12 @@ $staleSeconds = 0
|
|
|
123
122
|
$previousLogSize = 0
|
|
124
123
|
$previousProgressSignature = ''
|
|
125
124
|
$previousChildActivitySignature = ''
|
|
126
|
-
$wasTimedOut = $false
|
|
127
125
|
$wasStaleKilled = $false
|
|
128
126
|
while ($true) {
|
|
129
|
-
$
|
|
130
|
-
$waitSeconds = if ($timeoutSeconds -gt 0) { [Math]::Min($heartbeatInterval, [Math]::Max(1, $remainingTimeout)) } else { $heartbeatInterval }
|
|
131
|
-
$completed = Wait-Job $job -Timeout $waitSeconds
|
|
127
|
+
$completed = Wait-Job $job -Timeout $heartbeatInterval
|
|
132
128
|
if ($completed) { break }
|
|
133
129
|
|
|
134
|
-
$elapsedSeconds += $
|
|
130
|
+
$elapsedSeconds += $heartbeatInterval
|
|
135
131
|
$currentLogSize = 0
|
|
136
132
|
if (Test-Path $logPath) { $currentLogSize = [int64](Get-Item $logPath).Length }
|
|
137
133
|
$growth = $currentLogSize - $previousLogSize
|
|
@@ -145,13 +141,7 @@ while ($true) {
|
|
|
145
141
|
$childAdvanced = ($childSignature -and $childSignature -ne $previousChildActivitySignature)
|
|
146
142
|
$previousChildActivitySignature = $childSignature
|
|
147
143
|
|
|
148
|
-
if ($growth -gt 0 -or $childAdvanced -or $progressAdvanced) { $staleSeconds = 0 } else { $staleSeconds += $
|
|
149
|
-
|
|
150
|
-
if ($timeoutSeconds -gt 0 -and $elapsedSeconds -ge $timeoutSeconds) {
|
|
151
|
-
$wasTimedOut = $true
|
|
152
|
-
Stop-PrizmSessionProcess $pidPath
|
|
153
|
-
break
|
|
154
|
-
}
|
|
144
|
+
if ($growth -gt 0 -or $childAdvanced -or $progressAdvanced) { $staleSeconds = 0 } else { $staleSeconds += $heartbeatInterval }
|
|
155
145
|
|
|
156
146
|
if ($staleKillThreshold -gt 0 -and $staleSeconds -ge $staleKillThreshold) {
|
|
157
147
|
$wasStaleKilled = $true
|
|
@@ -164,11 +154,7 @@ while ($true) {
|
|
|
164
154
|
}
|
|
165
155
|
|
|
166
156
|
$exitCode = 0
|
|
167
|
-
if ($
|
|
168
|
-
Stop-Job $job
|
|
169
|
-
Remove-Job $job
|
|
170
|
-
$exitCode = 124
|
|
171
|
-
} elseif ($wasStaleKilled) {
|
|
157
|
+
if ($wasStaleKilled) {
|
|
172
158
|
Stop-Job $job
|
|
173
159
|
Remove-Job $job
|
|
174
160
|
$exitCode = 143
|
|
@@ -188,7 +174,6 @@ if (Test-Path $logPath) {
|
|
|
188
174
|
$sizeKb = [int](([int64](Get-Item $logPath).Length) / 1024)
|
|
189
175
|
Write-PrizmInfo "Session log: $lineCount lines, ${sizeKb}KB"
|
|
190
176
|
}
|
|
191
|
-
if ($wasTimedOut) { Write-PrizmWarn "Recovery session timed out after $timeoutSeconds seconds." }
|
|
192
177
|
if ($wasStaleKilled -or (Test-Path $staleKillMarker)) { Write-PrizmWarn "Recovery session was stale-killed." }
|
|
193
178
|
if ($exitCode -eq 0) { Write-PrizmSuccess "Recovery session completed." } else { Write-PrizmError "Recovery session failed. Log: $logPath" }
|
|
194
179
|
exit $exitCode
|
|
@@ -129,7 +129,7 @@ Detect user intent from their message, then follow the corresponding workflow:
|
|
|
129
129
|
```
|
|
130
130
|
With all options:
|
|
131
131
|
```bash
|
|
132
|
-
VERBOSE=1 MAX_RETRIES=5
|
|
132
|
+
VERBOSE=1 MAX_RETRIES=5 ENABLE_DEPLOY=1 PRIZMKIT_EFFORT=high \
|
|
133
133
|
.prizmkit/dev-pipeline/run-bugfix.sh run .prizmkit/plans/bug-fix-list.json
|
|
134
134
|
```
|
|
135
135
|
|