prizmkit 1.1.92 → 1.1.94
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/lib/heartbeat.sh +4 -50
- package/bundled/dev-pipeline/run-bugfix.sh +9 -77
- package/bundled/dev-pipeline/run-feature.sh +8 -94
- package/bundled/dev-pipeline/run-recovery.sh +1 -32
- package/bundled/dev-pipeline/run-refactor.sh +8 -78
- 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 +19 -139
- 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
|
@@ -17,7 +17,6 @@ set -euo pipefail
|
|
|
17
17
|
# Environment Variables:
|
|
18
18
|
# MAX_RETRIES Max code retries per feature (default: 3)
|
|
19
19
|
# MAX_INFRA_RETRIES Max infrastructure/provider retries per feature (default: 3)
|
|
20
|
-
# SESSION_TIMEOUT Session timeout in seconds (default: 0 = no limit)
|
|
21
20
|
# AI_CLI AI CLI command name (override; also readable from .prizmkit/config.json)
|
|
22
21
|
# CODEBUDDY_CLI Legacy alias for AI_CLI (deprecated, use AI_CLI instead)
|
|
23
22
|
# PRIZMKIT_PLATFORM Platform hint for custom AI_CLI wrappers: codebuddy, claude, or codex
|
|
@@ -26,9 +25,6 @@ set -euo pipefail
|
|
|
26
25
|
# HEARTBEAT_INTERVAL Heartbeat log interval in seconds (default: 30)
|
|
27
26
|
# STALE_KILL_THRESHOLD Auto-kill session after N seconds of no progress (default: 900)
|
|
28
27
|
# HEARTBEAT_STALE_THRESHOLD Heartbeat stale threshold in seconds (default: 600)
|
|
29
|
-
# LOG_CLEANUP_ENABLED Run periodic log cleanup (default: 1)
|
|
30
|
-
# LOG_RETENTION_DAYS Delete logs older than N days (default: 14)
|
|
31
|
-
# LOG_MAX_TOTAL_MB Keep total logs under N MB via oldest-first cleanup (default: 1024)
|
|
32
28
|
# PIPELINE_MODE Override mode for all features: lite|standard|full (used by daemon)
|
|
33
29
|
# DEV_BRANCH Custom dev branch name (default: auto-generated dev/{feature_id}-YYYYMMDDHHmm)
|
|
34
30
|
# AUTO_PUSH Auto-push to remote after successful feature (default: 0). Set to 1 to enable.
|
|
@@ -47,13 +43,9 @@ SCRIPTS_DIR="$SCRIPT_DIR/scripts"
|
|
|
47
43
|
# Configuration (override via environment variables)
|
|
48
44
|
MAX_RETRIES=${MAX_RETRIES:-3}
|
|
49
45
|
MAX_INFRA_RETRIES=${MAX_INFRA_RETRIES:-3}
|
|
50
|
-
SESSION_TIMEOUT=${SESSION_TIMEOUT:-0}
|
|
51
46
|
HEARTBEAT_STALE_THRESHOLD=${HEARTBEAT_STALE_THRESHOLD:-600}
|
|
52
47
|
HEARTBEAT_INTERVAL=${HEARTBEAT_INTERVAL:-30}
|
|
53
48
|
STALE_KILL_THRESHOLD=${STALE_KILL_THRESHOLD:-900}
|
|
54
|
-
LOG_CLEANUP_ENABLED=${LOG_CLEANUP_ENABLED:-1}
|
|
55
|
-
LOG_RETENTION_DAYS=${LOG_RETENTION_DAYS:-14}
|
|
56
|
-
LOG_MAX_TOTAL_MB=${LOG_MAX_TOTAL_MB:-1024}
|
|
57
49
|
VERBOSE=${VERBOSE:-0}
|
|
58
50
|
MODEL=${MODEL:-""}
|
|
59
51
|
PRIZMKIT_EFFORT=${PRIZMKIT_EFFORT:-""}
|
|
@@ -126,13 +118,6 @@ spawn_and_wait_session() {
|
|
|
126
118
|
start_progress_parser "$session_log" "$progress_json" "$SCRIPTS_DIR"
|
|
127
119
|
local parser_pid="${_PARSER_PID:-}"
|
|
128
120
|
|
|
129
|
-
# Timeout watchdog (only if SESSION_TIMEOUT > 0)
|
|
130
|
-
local watcher_pid=""
|
|
131
|
-
if [[ $SESSION_TIMEOUT -gt 0 ]]; then
|
|
132
|
-
( sleep "$SESSION_TIMEOUT" && kill -TERM "$cbc_pid" 2>/dev/null ) &
|
|
133
|
-
watcher_pid=$!
|
|
134
|
-
fi
|
|
135
|
-
|
|
136
121
|
# Heartbeat monitor (reads progress.json when available, falls back to tail)
|
|
137
122
|
# Also monitors for stale sessions and auto-kills if no progress for STALE_KILL_THRESHOLD seconds
|
|
138
123
|
start_heartbeat "$cbc_pid" "$session_log" "$progress_json" "$HEARTBEAT_INTERVAL" "$STALE_KILL_THRESHOLD"
|
|
@@ -146,19 +131,13 @@ spawn_and_wait_session() {
|
|
|
146
131
|
exit_code=$?
|
|
147
132
|
fi
|
|
148
133
|
|
|
149
|
-
# Clean up
|
|
150
|
-
[[ -n "$watcher_pid" ]] && kill "$watcher_pid" 2>/dev/null || true
|
|
134
|
+
# Clean up heartbeat and parser
|
|
151
135
|
stop_heartbeat "$heartbeat_pid"
|
|
152
136
|
stop_progress_parser "$parser_pid"
|
|
153
|
-
[[ -n "$watcher_pid" ]] && wait "$watcher_pid" 2>/dev/null || true
|
|
154
137
|
|
|
155
138
|
# Recover session log from backup if truncated by subagent stdout redirection
|
|
156
139
|
prizm_recover_session_log "$session_log"
|
|
157
140
|
|
|
158
|
-
# Map SIGTERM (143) to timeout code 124
|
|
159
|
-
if [[ $exit_code -eq 143 ]]; then
|
|
160
|
-
exit_code=124
|
|
161
|
-
fi
|
|
162
141
|
_SPAWN_EXIT_CODE="$exit_code"
|
|
163
142
|
|
|
164
143
|
# Check for stale-kill marker (heartbeat killed the process due to no progress)
|
|
@@ -176,11 +155,7 @@ except Exception:
|
|
|
176
155
|
pass
|
|
177
156
|
PY
|
|
178
157
|
)
|
|
179
|
-
|
|
180
|
-
log_warn "Session was killed by heartbeat monitor due to repeated read-offset/wasted-call errors"
|
|
181
|
-
else
|
|
182
|
-
log_warn "Session was stale-killed by heartbeat monitor (no progress for too long)"
|
|
183
|
-
fi
|
|
158
|
+
log_warn "Session was stale-killed by heartbeat monitor (no progress for too long)"
|
|
184
159
|
fi
|
|
185
160
|
|
|
186
161
|
local was_infra_error=false
|
|
@@ -229,19 +204,12 @@ PY
|
|
|
229
204
|
log_warn "Session failed due to structured AI runtime/context error"
|
|
230
205
|
log_warn "AI runtime errors are retried without consuming code retry budget"
|
|
231
206
|
session_status="infra_error"
|
|
232
|
-
elif [[ $exit_code -eq 124 ]]; then
|
|
233
|
-
log_warn "Session timed out after ${SESSION_TIMEOUT}s"
|
|
234
|
-
session_status="timed_out"
|
|
235
207
|
elif [[ "$was_infra_error" == true ]]; then
|
|
236
208
|
log_warn "Session failed due to AI CLI/provider infrastructure error"
|
|
237
209
|
log_warn "Infrastructure errors are retried without consuming code retry budget"
|
|
238
210
|
session_status="infra_error"
|
|
239
211
|
elif [[ "$was_stale_killed" == true ]]; then
|
|
240
|
-
|
|
241
|
-
log_warn "Session killed due to repeated read-offset/wasted-call error loop"
|
|
242
|
-
else
|
|
243
|
-
log_warn "Session stale-killed (no progress for ${STALE_KILL_THRESHOLD}s)"
|
|
244
|
-
fi
|
|
212
|
+
log_warn "Session stale-killed (no progress for ${STALE_KILL_THRESHOLD}s)"
|
|
245
213
|
log_warn "Heartbeat-killed sessions are treated as failed; dev branch is preserved for inspection"
|
|
246
214
|
session_status="crashed"
|
|
247
215
|
elif [[ $exit_code -ne 0 ]]; then
|
|
@@ -521,29 +489,6 @@ check_dependencies() {
|
|
|
521
489
|
prizm_ensure_git_repo "$_project_root"
|
|
522
490
|
}
|
|
523
491
|
|
|
524
|
-
run_log_cleanup() {
|
|
525
|
-
if [[ "$LOG_CLEANUP_ENABLED" != "1" ]]; then
|
|
526
|
-
return 0
|
|
527
|
-
fi
|
|
528
|
-
|
|
529
|
-
local cleanup_result
|
|
530
|
-
cleanup_result=$(python3 "$SCRIPTS_DIR/cleanup-logs.py" \
|
|
531
|
-
--state-dir "$STATE_DIR" \
|
|
532
|
-
--retention-days "$LOG_RETENTION_DAYS" \
|
|
533
|
-
--max-total-mb "$LOG_MAX_TOTAL_MB" 2>/dev/null) || {
|
|
534
|
-
log_warn "Log cleanup failed (continuing)"
|
|
535
|
-
return 0
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
local deleted reclaimed_kb
|
|
539
|
-
deleted=$(echo "$cleanup_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('deleted_files', 0))" 2>/dev/null || echo "0")
|
|
540
|
-
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")
|
|
541
|
-
|
|
542
|
-
if [[ "$deleted" -gt 0 ]]; then
|
|
543
|
-
log_info "Log cleanup: deleted $deleted files, reclaimed ${reclaimed_kb}KB"
|
|
544
|
-
fi
|
|
545
|
-
}
|
|
546
|
-
|
|
547
492
|
# ============================================================
|
|
548
493
|
# run-one: Run a single feature with full control
|
|
549
494
|
# ============================================================
|
|
@@ -607,15 +552,6 @@ run_one() {
|
|
|
607
552
|
critic_override="false"
|
|
608
553
|
shift
|
|
609
554
|
;;
|
|
610
|
-
--timeout)
|
|
611
|
-
shift
|
|
612
|
-
if [[ $# -eq 0 ]]; then
|
|
613
|
-
log_error "--timeout requires a value in seconds"
|
|
614
|
-
exit 1
|
|
615
|
-
fi
|
|
616
|
-
SESSION_TIMEOUT="$1"
|
|
617
|
-
shift
|
|
618
|
-
;;
|
|
619
555
|
--max-infra-retries)
|
|
620
556
|
shift
|
|
621
557
|
if [[ $# -eq 0 ]]; then
|
|
@@ -669,7 +605,6 @@ run_one() {
|
|
|
669
605
|
fi
|
|
670
606
|
|
|
671
607
|
check_dependencies
|
|
672
|
-
run_log_cleanup
|
|
673
608
|
|
|
674
609
|
# Initialize pipeline state if needed (same logic as run_all)
|
|
675
610
|
if [[ ! -f "$STATE_DIR/pipeline.json" ]]; then
|
|
@@ -921,11 +856,6 @@ else:
|
|
|
921
856
|
esac
|
|
922
857
|
log_info "Pipeline mode: ${BOLD}$pipeline_mode${NC} ($_run_one_mode_desc)"
|
|
923
858
|
log_info "Agents: $agent_count (critic: $([ "$critic_enabled" = "true" ] && echo "enabled" || echo "disabled"))"
|
|
924
|
-
if [[ $SESSION_TIMEOUT -gt 0 ]]; then
|
|
925
|
-
log_info "Session timeout: ${SESSION_TIMEOUT}s"
|
|
926
|
-
else
|
|
927
|
-
log_info "Session timeout: none"
|
|
928
|
-
fi
|
|
929
859
|
log_info "Prompt: $bootstrap_prompt"
|
|
930
860
|
log_info "Log: $session_dir/logs/session.log"
|
|
931
861
|
echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
|
|
@@ -1065,7 +995,6 @@ main() {
|
|
|
1065
995
|
fi
|
|
1066
996
|
|
|
1067
997
|
check_dependencies
|
|
1068
|
-
run_log_cleanup
|
|
1069
998
|
|
|
1070
999
|
# Initialize pipeline state if needed
|
|
1071
1000
|
if [[ ! -f "$STATE_DIR/pipeline.json" ]]; then
|
|
@@ -1118,11 +1047,6 @@ main() {
|
|
|
1118
1047
|
fi
|
|
1119
1048
|
log_info "Max code retries per feature: $MAX_RETRIES"
|
|
1120
1049
|
log_info "Max infrastructure retries per feature: $MAX_INFRA_RETRIES"
|
|
1121
|
-
if [[ $SESSION_TIMEOUT -gt 0 ]]; then
|
|
1122
|
-
log_info "Session timeout: ${SESSION_TIMEOUT}s"
|
|
1123
|
-
else
|
|
1124
|
-
log_info "Session timeout: none"
|
|
1125
|
-
fi
|
|
1126
1050
|
log_info "AI CLI: $CLI_CMD (platform: $PLATFORM)"
|
|
1127
1051
|
if [[ -n "${MODEL:-}" ]]; then
|
|
1128
1052
|
log_info "Default Model: $MODEL"
|
|
@@ -1313,17 +1237,14 @@ DEPLOY_PROMPT_EOF
|
|
|
1313
1237
|
fi
|
|
1314
1238
|
echo -e "${BOLD}────────────────────────────────────────────────────${NC}"
|
|
1315
1239
|
|
|
1316
|
-
#
|
|
1317
|
-
#
|
|
1318
|
-
# submodule dirt, specs, and root-level hidden tool temporary worktrees
|
|
1319
|
-
# must never be swept into main by a broad git add.
|
|
1240
|
+
# Auto-commit any uncommitted workspace changes before starting the pipeline.
|
|
1241
|
+
# This ensures a clean baseline without blocking execution.
|
|
1320
1242
|
local _dirty_files=""
|
|
1321
1243
|
_dirty_files=$(prizm_git_status_non_bookkeeping "$_proj_root" "$STATE_DIR" "$feature_list" || true)
|
|
1322
1244
|
if [[ -n "$_dirty_files" ]]; then
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
break
|
|
1245
|
+
log_info "Auto-committing workspace changes before $feature_id..."
|
|
1246
|
+
prizm_git_add_all_safe "$_proj_root"
|
|
1247
|
+
git -C "$_proj_root" commit --no-verify -m "chore: workspace snapshot ready for run $feature_id" 2>/dev/null || true
|
|
1327
1248
|
fi
|
|
1328
1249
|
|
|
1329
1250
|
local _bookkeeping_dirty=""
|
|
@@ -1508,7 +1429,6 @@ show_help() {
|
|
|
1508
1429
|
echo " --no-critic Disable critic review (overrides feature-list setting)"
|
|
1509
1430
|
echo " --clean Delete artifacts and reset before running"
|
|
1510
1431
|
echo " --no-reset Skip feature status reset step"
|
|
1511
|
-
echo " --timeout N Session timeout in seconds (default: 0 = no limit)"
|
|
1512
1432
|
echo " --max-infra-retries N Max infrastructure/provider retries (default: 3)"
|
|
1513
1433
|
echo ""
|
|
1514
1434
|
echo "Pipeline Options (run all):"
|
|
@@ -1517,16 +1437,12 @@ show_help() {
|
|
|
1517
1437
|
echo "Environment Variables:"
|
|
1518
1438
|
echo " MAX_RETRIES Max code retries per feature (default: 3)"
|
|
1519
1439
|
echo " MAX_INFRA_RETRIES Max infrastructure/provider retries per feature (default: 3)"
|
|
1520
|
-
echo " SESSION_TIMEOUT Session timeout in seconds (default: 0 = no limit)"
|
|
1521
1440
|
echo " AI_CLI AI CLI command name (auto-detected: cbc, claude, or codex)"
|
|
1522
1441
|
echo " MODEL AI model ID (e.g. claude-opus-4.6, claude-sonnet-4.6, claude-haiku-4.5)"
|
|
1523
1442
|
echo " PRIZMKIT_EFFORT AI reasoning effort (low|medium|high|xhigh|max; max is Claude Code only)"
|
|
1524
1443
|
echo " HEARTBEAT_INTERVAL Heartbeat log interval in seconds (default: 30)"
|
|
1525
1444
|
echo " STALE_KILL_THRESHOLD Auto-kill session after N seconds of no progress (default: 900)"
|
|
1526
1445
|
echo " HEARTBEAT_STALE_THRESHOLD Heartbeat stale threshold in seconds (default: 600)"
|
|
1527
|
-
echo " LOG_CLEANUP_ENABLED Run log cleanup before execution (default: 1)"
|
|
1528
|
-
echo " LOG_RETENTION_DAYS Delete logs older than N days (default: 14)"
|
|
1529
|
-
echo " LOG_MAX_TOTAL_MB Keep total logs under N MB (default: 1024)"
|
|
1530
1446
|
echo " PIPELINE_MODE Override mode for all features: lite|standard|full"
|
|
1531
1447
|
echo " ENABLE_CRITIC Enable critic review for all features: true|false"
|
|
1532
1448
|
echo " STOP_ON_FAILURE Stop pipeline when a task exhausts retries: 0|1 (default: 0)"
|
|
@@ -1538,10 +1454,8 @@ show_help() {
|
|
|
1538
1454
|
echo " ./run-feature.sh run F-007 --dry-run # Inspect generated prompt"
|
|
1539
1455
|
echo " ./run-feature.sh run F-007 --dry-run --mode lite # Test lite mode"
|
|
1540
1456
|
echo " ./run-feature.sh run F-007 --resume-phase 6 # Skip to implementation"
|
|
1541
|
-
echo " ./run-feature.sh run F-007 --mode full --timeout 3600 # Full mode, 1h timeout"
|
|
1542
1457
|
echo " ./run-feature.sh run F-007 --clean --mode standard # Clean + run standard"
|
|
1543
1458
|
echo " ./run-feature.sh status # Show pipeline status"
|
|
1544
|
-
echo " MAX_RETRIES=5 SESSION_TIMEOUT=7200 ./run-feature.sh run # Custom config"
|
|
1545
1459
|
echo " MODEL=claude-sonnet-4.6 ./run-feature.sh run # Use Sonnet model"
|
|
1546
1460
|
echo " MODEL=claude-haiku-4.5 ./run-feature.sh test-cli # Test with Haiku"
|
|
1547
1461
|
}
|
|
@@ -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
|
|
@@ -164,11 +145,7 @@ except Exception:
|
|
|
164
145
|
pass
|
|
165
146
|
PY
|
|
166
147
|
)
|
|
167
|
-
|
|
168
|
-
log_warn "Session was killed by heartbeat monitor due to repeated read-offset/wasted-call errors"
|
|
169
|
-
else
|
|
170
|
-
log_warn "Session was stale-killed by heartbeat monitor (no progress for too long)"
|
|
171
|
-
fi
|
|
148
|
+
log_warn "Session was stale-killed by heartbeat monitor (no progress for too long)"
|
|
172
149
|
fi
|
|
173
150
|
|
|
174
151
|
local was_infra_error=false
|
|
@@ -194,19 +171,12 @@ PY
|
|
|
194
171
|
project_root="$PROJECT_ROOT"
|
|
195
172
|
local default_branch="$base_branch"
|
|
196
173
|
|
|
197
|
-
if [[ $
|
|
198
|
-
log_warn "Session timed out after ${SESSION_TIMEOUT}s"
|
|
199
|
-
session_status="timed_out"
|
|
200
|
-
elif [[ "$was_infra_error" == true ]]; then
|
|
174
|
+
if [[ "$was_infra_error" == true ]]; then
|
|
201
175
|
log_warn "Session failed due to AI CLI/provider infrastructure error"
|
|
202
176
|
log_warn "Infrastructure errors are retried without consuming code retry budget"
|
|
203
177
|
session_status="infra_error"
|
|
204
178
|
elif [[ "$was_stale_killed" == true ]]; then
|
|
205
|
-
|
|
206
|
-
log_warn "Session killed due to repeated read-offset/wasted-call error loop"
|
|
207
|
-
else
|
|
208
|
-
log_warn "Session stale-killed (no progress for ${STALE_KILL_THRESHOLD}s)"
|
|
209
|
-
fi
|
|
179
|
+
log_warn "Session stale-killed (no progress for ${STALE_KILL_THRESHOLD}s)"
|
|
210
180
|
log_warn "Stale-killed sessions are treated as failed; dev branch is preserved for inspection"
|
|
211
181
|
session_status="crashed"
|
|
212
182
|
elif [[ $exit_code -ne 0 ]]; then
|
|
@@ -426,29 +396,6 @@ check_dependencies() {
|
|
|
426
396
|
prizm_ensure_git_repo "$_project_root"
|
|
427
397
|
}
|
|
428
398
|
|
|
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
399
|
# ============================================================
|
|
453
400
|
# run-one: Run a single refactor
|
|
454
401
|
# ============================================================
|
|
@@ -467,7 +414,6 @@ run_one() {
|
|
|
467
414
|
--dry-run) dry_run=true; shift ;;
|
|
468
415
|
--clean) do_clean=true; shift ;;
|
|
469
416
|
--no-reset) no_reset=true; shift ;;
|
|
470
|
-
--timeout) shift; SESSION_TIMEOUT="${1:-0}"; shift ;;
|
|
471
417
|
--max-infra-retries)
|
|
472
418
|
shift
|
|
473
419
|
if [[ $# -eq 0 ]]; then
|
|
@@ -518,7 +464,6 @@ run_one() {
|
|
|
518
464
|
fi
|
|
519
465
|
|
|
520
466
|
check_dependencies
|
|
521
|
-
run_log_cleanup
|
|
522
467
|
|
|
523
468
|
# Initialize state if needed
|
|
524
469
|
if [[ ! -f "$STATE_DIR/pipeline.json" ]]; then
|
|
@@ -907,7 +852,6 @@ main() {
|
|
|
907
852
|
fi
|
|
908
853
|
|
|
909
854
|
check_dependencies
|
|
910
|
-
run_log_cleanup
|
|
911
855
|
|
|
912
856
|
# Initialize pipeline state if needed
|
|
913
857
|
if [[ ! -f "$STATE_DIR/pipeline.json" ]]; then
|
|
@@ -956,11 +900,6 @@ main() {
|
|
|
956
900
|
log_info "Refactor list: $refactor_list"
|
|
957
901
|
log_info "Max code retries per refactor: $MAX_RETRIES"
|
|
958
902
|
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
903
|
log_info "AI CLI: $CLI_CMD (platform: $PLATFORM)"
|
|
965
904
|
if [[ -n "${MODEL:-}" ]]; then
|
|
966
905
|
log_info "Default Model: $MODEL"
|
|
@@ -1112,17 +1051,14 @@ DEPLOY_PROMPT_EOF
|
|
|
1112
1051
|
fi
|
|
1113
1052
|
echo -e "${BOLD}────────────────────────────────────────────────────${NC}"
|
|
1114
1053
|
|
|
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.
|
|
1054
|
+
# Auto-commit any uncommitted workspace changes before starting the pipeline.
|
|
1055
|
+
# This ensures a clean baseline without blocking execution.
|
|
1119
1056
|
local _dirty_files=""
|
|
1120
1057
|
_dirty_files=$(prizm_git_status_non_bookkeeping "$_proj_root" "$STATE_DIR" "$refactor_list" || true)
|
|
1121
1058
|
if [[ -n "$_dirty_files" ]]; then
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
break
|
|
1059
|
+
log_info "Auto-committing workspace changes before $refactor_id..."
|
|
1060
|
+
prizm_git_add_all_safe "$_proj_root"
|
|
1061
|
+
git -C "$_proj_root" commit --no-verify -m "chore: workspace snapshot ready for run $refactor_id" 2>/dev/null || true
|
|
1126
1062
|
fi
|
|
1127
1063
|
|
|
1128
1064
|
local _bookkeeping_dirty=""
|
|
@@ -1315,7 +1251,6 @@ show_help() {
|
|
|
1315
1251
|
echo " --dry-run Generate bootstrap prompt only, don't spawn session"
|
|
1316
1252
|
echo " --clean Delete artifacts and reset before running"
|
|
1317
1253
|
echo " --no-reset Skip status reset (preserve retry count)"
|
|
1318
|
-
echo " --timeout N Session timeout in seconds (default: 0 = no limit)"
|
|
1319
1254
|
echo " --max-infra-retries N Max infrastructure/provider retries (default: 3)"
|
|
1320
1255
|
echo " --mode <lite|standard|full> Override pipeline mode"
|
|
1321
1256
|
echo " --critic Enable adversarial critic review"
|
|
@@ -1327,7 +1262,6 @@ show_help() {
|
|
|
1327
1262
|
echo "Environment Variables:"
|
|
1328
1263
|
echo " MAX_RETRIES Max code retries per refactor (default: 3)"
|
|
1329
1264
|
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
1265
|
echo " MODEL Default AI model (overridden by per-refactor model in refactor list)"
|
|
1332
1266
|
echo " PRIZMKIT_EFFORT AI reasoning effort (low|medium|high|xhigh|max; max is Claude Code only)"
|
|
1333
1267
|
echo " PIPELINE_MODE Default pipeline mode: lite|standard|full (overridden by --mode)"
|
|
@@ -1338,15 +1272,11 @@ show_help() {
|
|
|
1338
1272
|
echo " HEARTBEAT_INTERVAL Heartbeat log interval in seconds (default: 30)"
|
|
1339
1273
|
echo " STALE_KILL_THRESHOLD Auto-kill session after N seconds of no progress (default: 900)"
|
|
1340
1274
|
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
1275
|
echo ""
|
|
1345
1276
|
echo "Examples:"
|
|
1346
1277
|
echo " ./run-refactor.sh run # Run all refactors"
|
|
1347
1278
|
echo " ./run-refactor.sh run .prizmkit/plans/refactor-list.json # Custom refactor list"
|
|
1348
1279
|
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
1280
|
echo " ./run-refactor.sh status # Show status"
|
|
1351
1281
|
echo " STRICT_BEHAVIOR_CHECK=0 ./run-refactor.sh run # Skip full test suite"
|
|
1352
1282
|
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
|
|