@jonit-dev/night-watch-cli 1.7.58 → 1.7.59
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/dist/cli.js +2 -0
- package/dist/scripts/night-watch-audit-cron.sh +12 -1
- package/dist/scripts/night-watch-cron.sh +21 -2
- package/dist/scripts/night-watch-helpers.sh +20 -1
- package/dist/scripts/night-watch-pr-reviewer-cron.sh +11 -1
- package/dist/scripts/night-watch-qa-cron.sh +15 -2
- package/dist/scripts/night-watch-slicer-cron.sh +10 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ MAX_RUNTIME="${NW_AUDIT_MAX_RUNTIME:-1800}" # 30 minutes
|
|
|
20
20
|
MAX_LOG_SIZE="524288" # 512 KB
|
|
21
21
|
PROVIDER_CMD="${NW_PROVIDER_CMD:-claude}"
|
|
22
22
|
PROVIDER_LABEL="${NW_PROVIDER_LABEL:-}"
|
|
23
|
+
SCRIPT_START_TIME=$(date +%s)
|
|
23
24
|
|
|
24
25
|
# Ensure NVM / Node / Claude are on PATH
|
|
25
26
|
export NVM_DIR="${HOME}/.nvm"
|
|
@@ -54,6 +55,9 @@ if ! validate_provider "${PROVIDER_CMD}"; then
|
|
|
54
55
|
fi
|
|
55
56
|
|
|
56
57
|
rotate_log
|
|
58
|
+
log_separator
|
|
59
|
+
log "RUN-START: audit invoked project=${PROJECT_DIR} provider=${PROVIDER_CMD} dry_run=${NW_DRY_RUN:-0}"
|
|
60
|
+
log "CONFIG: max_runtime=${MAX_RUNTIME}s max_retries=${NW_AUDIT_MAX_RETRIES:-3} retry_delay=${NW_AUDIT_RETRY_DELAY:-120}s"
|
|
57
61
|
|
|
58
62
|
if ! acquire_lock "${LOCK_FILE}"; then
|
|
59
63
|
emit_result "skip_locked"
|
|
@@ -121,7 +125,8 @@ EXIT_CODE=0
|
|
|
121
125
|
|
|
122
126
|
for AUDIT_ATTEMPT in $(seq 1 "${AUDIT_MAX_RETRIES}"); do
|
|
123
127
|
LOG_LINE_BEFORE=$(wc -l < "${LOG_FILE}" 2>/dev/null || echo 0)
|
|
124
|
-
|
|
128
|
+
AUDIT_ATTEMPT_START=$(date +%s)
|
|
129
|
+
log "AUDIT: Attempt ${AUDIT_ATTEMPT}/${AUDIT_MAX_RETRIES} starting provider=${PROVIDER_CMD} timeout=${MAX_RUNTIME}s"
|
|
125
130
|
|
|
126
131
|
case "${PROVIDER_CMD}" in
|
|
127
132
|
claude)
|
|
@@ -156,6 +161,9 @@ for AUDIT_ATTEMPT in $(seq 1 "${AUDIT_MAX_RETRIES}"); do
|
|
|
156
161
|
;;
|
|
157
162
|
esac
|
|
158
163
|
|
|
164
|
+
AUDIT_ATTEMPT_ELAPSED=$(( $(date +%s) - AUDIT_ATTEMPT_START ))
|
|
165
|
+
log "AUDIT: Attempt ${AUDIT_ATTEMPT}/${AUDIT_MAX_RETRIES} finished exit_code=${EXIT_CODE} elapsed=${AUDIT_ATTEMPT_ELAPSED}s"
|
|
166
|
+
|
|
159
167
|
# Success or timeout — don't retry
|
|
160
168
|
if [ "${EXIT_CODE}" -eq 0 ] || [ "${EXIT_CODE}" -eq 124 ]; then
|
|
161
169
|
break
|
|
@@ -181,6 +189,9 @@ fi
|
|
|
181
189
|
|
|
182
190
|
cleanup_worktrees "${PROJECT_DIR}" "${AUDIT_WORKTREE_BASENAME}"
|
|
183
191
|
|
|
192
|
+
AUDIT_TOTAL_ELAPSED=$(( $(date +%s) - SCRIPT_START_TIME ))
|
|
193
|
+
log "OUTCOME: exit_code=${EXIT_CODE} total_elapsed=${AUDIT_TOTAL_ELAPSED}s project=${PROJECT_NAME}"
|
|
194
|
+
|
|
184
195
|
if [ "${EXIT_CODE}" -eq 0 ]; then
|
|
185
196
|
if [ ! -f "${REPORT_FILE}" ]; then
|
|
186
197
|
log "FAIL: Audit provider exited 0 but no report was generated at ${REPORT_FILE}"
|
|
@@ -31,6 +31,7 @@ PROVIDER_CMD="${NW_PROVIDER_CMD:-claude}"
|
|
|
31
31
|
PROVIDER_LABEL="${NW_PROVIDER_LABEL:-${PROVIDER_CMD}}"
|
|
32
32
|
EFFECTIVE_PROVIDER_LABEL="${PROVIDER_LABEL}"
|
|
33
33
|
BRANCH_PREFIX="${NW_BRANCH_PREFIX:-night-watch}"
|
|
34
|
+
SCRIPT_START_TIME=$(date +%s)
|
|
34
35
|
|
|
35
36
|
# Ensure NVM / Node / Claude are on PATH
|
|
36
37
|
export NVM_DIR="${HOME}/.nvm"
|
|
@@ -73,6 +74,8 @@ if ! validate_provider "${PROVIDER_CMD}"; then
|
|
|
73
74
|
fi
|
|
74
75
|
|
|
75
76
|
rotate_log
|
|
77
|
+
log_separator
|
|
78
|
+
log "RUN-START: executor invoked project=${PROJECT_DIR} provider=${PROVIDER_CMD} board=${NW_BOARD_ENABLED:-false} dry_run=${NW_DRY_RUN:-0}"
|
|
76
79
|
|
|
77
80
|
if ! acquire_lock "${LOCK_FILE}"; then
|
|
78
81
|
emit_result "skip_locked"
|
|
@@ -307,6 +310,10 @@ Co-Authored-By: Night Watch [${EFFECTIVE_PROVIDER_LABEL}] <noreply@anthropic.com
|
|
|
307
310
|
return 1
|
|
308
311
|
}
|
|
309
312
|
|
|
313
|
+
log "CONFIG: prd=${ELIGIBLE_PRD} branch=${BRANCH_NAME}"
|
|
314
|
+
log "CONFIG: worktree=${WORKTREE_DIR}"
|
|
315
|
+
log "CONFIG: default_branch=${DEFAULT_BRANCH} provider=${PROVIDER_CMD} label=${PROVIDER_LABEL:-none}"
|
|
316
|
+
log "CONFIG: max_runtime=${MAX_RUNTIME}s max_retries=${NW_MAX_RETRIES:-3} board=${NW_BOARD_ENABLED:-false}"
|
|
310
317
|
log "START: Processing ${ELIGIBLE_PRD} on branch ${BRANCH_NAME} (worktree: ${WORKTREE_DIR})"
|
|
311
318
|
|
|
312
319
|
EXECUTOR_PROMPT_PATH=$(resolve_instruction_path "${PROJECT_DIR}" "prd-executor.md" || true)
|
|
@@ -430,8 +437,12 @@ EXIT_CODE=0
|
|
|
430
437
|
ATTEMPT=0
|
|
431
438
|
RATE_LIMIT_FALLBACK_TRIGGERED=0
|
|
432
439
|
|
|
440
|
+
ATTEMPT_NUM=0
|
|
433
441
|
while [ "${ATTEMPT}" -lt "${MAX_RETRIES}" ]; do
|
|
434
442
|
EXIT_CODE=0
|
|
443
|
+
ATTEMPT_NUM=$((ATTEMPT_NUM + 1))
|
|
444
|
+
ATTEMPT_START_TIME=$(date +%s)
|
|
445
|
+
log "ATTEMPT: ${ATTEMPT_NUM}/${MAX_RETRIES} starting provider=${PROVIDER_CMD} prd=${ELIGIBLE_PRD}"
|
|
435
446
|
# Capture log position before this attempt so check_rate_limited only
|
|
436
447
|
# scans lines written by the current invocation (not leftover 429s from
|
|
437
448
|
# previous runs that would cause false-positive rate-limit retries).
|
|
@@ -469,6 +480,9 @@ while [ "${ATTEMPT}" -lt "${MAX_RETRIES}" ]; do
|
|
|
469
480
|
;;
|
|
470
481
|
esac
|
|
471
482
|
|
|
483
|
+
ATTEMPT_ELAPSED=$(( $(date +%s) - ATTEMPT_START_TIME ))
|
|
484
|
+
log "ATTEMPT: ${ATTEMPT_NUM}/${MAX_RETRIES} finished exit_code=${EXIT_CODE} elapsed=${ATTEMPT_ELAPSED}s prd=${ELIGIBLE_PRD}"
|
|
485
|
+
|
|
472
486
|
# Success or timeout — don't retry
|
|
473
487
|
if [ ${EXIT_CODE} -eq 0 ] || [ ${EXIT_CODE} -eq 124 ]; then
|
|
474
488
|
break
|
|
@@ -503,12 +517,13 @@ done
|
|
|
503
517
|
# same prompt with native Claude (OAuth), bypassing the proxy entirely.
|
|
504
518
|
if [ "${RATE_LIMIT_FALLBACK_TRIGGERED}" = "1" ]; then
|
|
505
519
|
FALLBACK_MODEL="${NW_CLAUDE_MODEL_ID:-claude-sonnet-4-6}"
|
|
506
|
-
log "RATE-LIMIT-FALLBACK: Running native Claude (${FALLBACK_MODEL})"
|
|
520
|
+
log "RATE-LIMIT-FALLBACK: Running native Claude (${FALLBACK_MODEL}) prd=${ELIGIBLE_PRD}"
|
|
507
521
|
|
|
508
522
|
# Send immediate Telegram warning (fire-and-forget)
|
|
509
523
|
send_rate_limit_fallback_warning "${FALLBACK_MODEL}" "$(basename "${PROJECT_DIR}")"
|
|
510
524
|
|
|
511
525
|
LOG_LINE_BEFORE=$(wc -l < "${LOG_FILE}" 2>/dev/null || echo 0)
|
|
526
|
+
FALLBACK_START_TIME=$(date +%s)
|
|
512
527
|
|
|
513
528
|
if (
|
|
514
529
|
cd "${WORKTREE_DIR}" && \
|
|
@@ -525,11 +540,15 @@ if [ "${RATE_LIMIT_FALLBACK_TRIGGERED}" = "1" ]; then
|
|
|
525
540
|
EXIT_CODE=$?
|
|
526
541
|
fi
|
|
527
542
|
|
|
528
|
-
|
|
543
|
+
FALLBACK_ELAPSED=$(( $(date +%s) - FALLBACK_START_TIME ))
|
|
544
|
+
log "RATE-LIMIT-FALLBACK: Native Claude exited with code ${EXIT_CODE} elapsed=${FALLBACK_ELAPSED}s"
|
|
529
545
|
# Update effective provider label to reflect actual executor used
|
|
530
546
|
EFFECTIVE_PROVIDER_LABEL="Claude ${FALLBACK_MODEL} (fallback)"
|
|
531
547
|
fi
|
|
532
548
|
|
|
549
|
+
TOTAL_ELAPSED=$(( $(date +%s) - SCRIPT_START_TIME ))
|
|
550
|
+
log "OUTCOME: exit_code=${EXIT_CODE} total_elapsed=${TOTAL_ELAPSED}s prd=${ELIGIBLE_PRD} branch=${BRANCH_NAME}"
|
|
551
|
+
|
|
533
552
|
if [ ${EXIT_CODE} -eq 0 ]; then
|
|
534
553
|
OPEN_PR_COUNT=$(count_prs_for_branch open "${BRANCH_NAME}")
|
|
535
554
|
if [ "${OPEN_PR_COUNT}" -gt 0 ]; then
|
|
@@ -159,7 +159,26 @@ night_watch_history() {
|
|
|
159
159
|
|
|
160
160
|
log() {
|
|
161
161
|
local log_file="${LOG_FILE:?LOG_FILE not set}"
|
|
162
|
-
|
|
162
|
+
local elapsed_str=""
|
|
163
|
+
if [ -n "${SCRIPT_START_TIME:-}" ]; then
|
|
164
|
+
local _now _elapsed _emin _esec
|
|
165
|
+
_now=$(date +%s)
|
|
166
|
+
_elapsed=$(( _now - SCRIPT_START_TIME ))
|
|
167
|
+
_emin=$(( _elapsed / 60 ))
|
|
168
|
+
_esec=$(( _elapsed % 60 ))
|
|
169
|
+
elapsed_str=" [+${_emin}m${_esec}s]"
|
|
170
|
+
fi
|
|
171
|
+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [PID:$$]${elapsed_str} $*" >> "${log_file}"
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# Write a visual separator line to the log to delimit separate runs.
|
|
175
|
+
log_separator() {
|
|
176
|
+
local log_file="${LOG_FILE:?LOG_FILE not set}"
|
|
177
|
+
{
|
|
178
|
+
echo ""
|
|
179
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
180
|
+
echo ""
|
|
181
|
+
} >> "${log_file}"
|
|
163
182
|
}
|
|
164
183
|
|
|
165
184
|
# ── Log rotation ─────────────────────────────────────────────────────────────
|
|
@@ -38,6 +38,7 @@ fi
|
|
|
38
38
|
# Retry configuration
|
|
39
39
|
REVIEWER_MAX_RETRIES="${NW_REVIEWER_MAX_RETRIES:-2}"
|
|
40
40
|
REVIEWER_RETRY_DELAY="${NW_REVIEWER_RETRY_DELAY:-30}"
|
|
41
|
+
SCRIPT_START_TIME=$(date +%s)
|
|
41
42
|
|
|
42
43
|
# Normalize retry settings to safe numeric ranges
|
|
43
44
|
if ! [[ "${REVIEWER_MAX_RETRIES}" =~ ^[0-9]+$ ]]; then
|
|
@@ -507,6 +508,9 @@ if ! validate_provider "${PROVIDER_CMD}"; then
|
|
|
507
508
|
fi
|
|
508
509
|
|
|
509
510
|
rotate_log
|
|
511
|
+
log_separator
|
|
512
|
+
log "RUN-START: reviewer invoked project=${PROJECT_DIR} provider=${PROVIDER_CMD} worker=${WORKER_MODE} target_pr=${TARGET_PR:-all} parallel=${PARALLEL_ENABLED}"
|
|
513
|
+
log "CONFIG: max_runtime=${MAX_RUNTIME}s min_review_score=${MIN_REVIEW_SCORE} auto_merge=${AUTO_MERGE} branch_patterns=${BRANCH_PATTERNS_RAW}"
|
|
510
514
|
|
|
511
515
|
if ! acquire_lock "${LOCK_FILE}"; then
|
|
512
516
|
emit_result "skip_locked"
|
|
@@ -1024,8 +1028,9 @@ for ATTEMPT in $(seq 1 "${TOTAL_ATTEMPTS}"); do
|
|
|
1024
1028
|
fi
|
|
1025
1029
|
fi
|
|
1026
1030
|
|
|
1027
|
-
log "RETRY: Starting attempt ${ATTEMPT}/${TOTAL_ATTEMPTS} (timeout: ${ATTEMPT_TIMEOUT}s)"
|
|
1031
|
+
log "RETRY: Starting attempt ${ATTEMPT}/${TOTAL_ATTEMPTS} (timeout: ${ATTEMPT_TIMEOUT}s) pr=${TARGET_PR:-all}"
|
|
1028
1032
|
LOG_LINE_BEFORE=$(wc -l < "${LOG_FILE}" 2>/dev/null || echo 0)
|
|
1033
|
+
REVIEWER_ATTEMPT_START=$(date +%s)
|
|
1029
1034
|
REVIEWER_PROMPT="${REVIEWER_PROMPT_BASE}${TARGET_SCOPE_PROMPT}${PRD_CONTEXT_PROMPT}"
|
|
1030
1035
|
|
|
1031
1036
|
case "${PROVIDER_CMD}" in
|
|
@@ -1060,6 +1065,9 @@ for ATTEMPT in $(seq 1 "${TOTAL_ATTEMPTS}"); do
|
|
|
1060
1065
|
;;
|
|
1061
1066
|
esac
|
|
1062
1067
|
|
|
1068
|
+
REVIEWER_ATTEMPT_ELAPSED=$(( $(date +%s) - REVIEWER_ATTEMPT_START ))
|
|
1069
|
+
log "RETRY: Attempt ${ATTEMPT}/${TOTAL_ATTEMPTS} finished exit_code=${EXIT_CODE} elapsed=${REVIEWER_ATTEMPT_ELAPSED}s pr=${TARGET_PR:-all}"
|
|
1070
|
+
|
|
1063
1071
|
# If provider failed (non-zero exit), check for rate limit before giving up
|
|
1064
1072
|
if [ "${EXIT_CODE}" -ne 0 ]; then
|
|
1065
1073
|
if [ "${EXIT_CODE}" -ne 124 ] && \
|
|
@@ -1214,4 +1222,6 @@ if [ "${AUTO_MERGE}" = "1" ] && [ ${EXIT_CODE} -eq 0 ]; then
|
|
|
1214
1222
|
done < <(gh pr list --state open --json number,headRefName --jq '.[] | [.number, .headRefName] | @tsv' 2>/dev/null || true)
|
|
1215
1223
|
fi
|
|
1216
1224
|
|
|
1225
|
+
REVIEWER_TOTAL_ELAPSED=$(( $(date +%s) - SCRIPT_START_TIME ))
|
|
1226
|
+
log "OUTCOME: exit_code=${EXIT_CODE} total_elapsed=${REVIEWER_TOTAL_ELAPSED}s prs=${PRS_NEEDING_WORK_CSV:-none} attempts=${ATTEMPTS_MADE}"
|
|
1217
1227
|
emit_final_status "${EXIT_CODE}" "${PRS_NEEDING_WORK_CSV}" "${AUTO_MERGED_PRS}" "${AUTO_MERGE_FAILED_PRS}" "${ATTEMPTS_MADE}" "${FINAL_SCORE}"
|
|
@@ -27,6 +27,7 @@ BRANCH_PATTERNS_RAW="${NW_BRANCH_PATTERNS:-feat/,night-watch/}"
|
|
|
27
27
|
SKIP_LABEL="${NW_QA_SKIP_LABEL:-skip-qa}"
|
|
28
28
|
QA_ARTIFACTS="${NW_QA_ARTIFACTS:-both}"
|
|
29
29
|
QA_AUTO_INSTALL_PLAYWRIGHT="${NW_QA_AUTO_INSTALL_PLAYWRIGHT:-1}"
|
|
30
|
+
SCRIPT_START_TIME=$(date +%s)
|
|
30
31
|
|
|
31
32
|
# Ensure NVM / Node / Claude are on PATH
|
|
32
33
|
export NVM_DIR="${HOME}/.nvm"
|
|
@@ -341,6 +342,9 @@ if ! validate_provider "${PROVIDER_CMD}"; then
|
|
|
341
342
|
fi
|
|
342
343
|
|
|
343
344
|
rotate_log
|
|
345
|
+
log_separator
|
|
346
|
+
log "RUN-START: qa invoked project=${PROJECT_DIR} provider=${PROVIDER_CMD} dry_run=${NW_DRY_RUN:-0}"
|
|
347
|
+
log "CONFIG: max_runtime=${MAX_RUNTIME}s artifacts=${QA_ARTIFACTS} skip_label=${SKIP_LABEL} branch_patterns=${BRANCH_PATTERNS_RAW}"
|
|
344
348
|
|
|
345
349
|
if ! acquire_lock "${LOCK_FILE}"; then
|
|
346
350
|
emit_result "skip_locked"
|
|
@@ -552,6 +556,8 @@ Action: generating QA tests and evidence."
|
|
|
552
556
|
QA_PROMPT="${QA_PROMPT}"$'\n\n'"## QA Attribution (Required)"$'\n'"At the very end of each QA result comment you post, add this footer on its own line:"$'\n'"> 🧪 QA run by ${QA_PROVIDER_LABEL}"
|
|
553
557
|
|
|
554
558
|
LOG_LINE_BEFORE=$(wc -l < "${LOG_FILE}" 2>/dev/null || echo 0)
|
|
559
|
+
QA_ATTEMPT_START=$(date +%s)
|
|
560
|
+
log "QA: PR #${pr_num} — starting provider=${PROVIDER_CMD} timeout=${MAX_RUNTIME}s"
|
|
555
561
|
PROVIDER_OK=0
|
|
556
562
|
case "${PROVIDER_CMD}" in
|
|
557
563
|
claude)
|
|
@@ -564,7 +570,8 @@ Action: generating QA tests and evidence."
|
|
|
564
570
|
PROVIDER_OK=1
|
|
565
571
|
else
|
|
566
572
|
local_exit=$?
|
|
567
|
-
|
|
573
|
+
QA_ATTEMPT_ELAPSED=$(( $(date +%s) - QA_ATTEMPT_START ))
|
|
574
|
+
log "QA: PR #${pr_num} — provider exited with code ${local_exit} elapsed=${QA_ATTEMPT_ELAPSED}s"
|
|
568
575
|
if [ ${local_exit} -eq 124 ]; then
|
|
569
576
|
FAILED_AUTOMATION_PRS_CSV=$(append_csv "${FAILED_AUTOMATION_PRS_CSV}" "#${pr_num}")
|
|
570
577
|
FAILED_PR="#${pr_num}"
|
|
@@ -589,7 +596,8 @@ Action: generating QA tests and evidence."
|
|
|
589
596
|
PROVIDER_OK=1
|
|
590
597
|
else
|
|
591
598
|
local_exit=$?
|
|
592
|
-
|
|
599
|
+
QA_ATTEMPT_ELAPSED=$(( $(date +%s) - QA_ATTEMPT_START ))
|
|
600
|
+
log "QA: PR #${pr_num} — provider exited with code ${local_exit} elapsed=${QA_ATTEMPT_ELAPSED}s"
|
|
593
601
|
if [ ${local_exit} -eq 124 ]; then
|
|
594
602
|
FAILED_AUTOMATION_PRS_CSV=$(append_csv "${FAILED_AUTOMATION_PRS_CSV}" "#${pr_num}")
|
|
595
603
|
FAILED_PR="#${pr_num}"
|
|
@@ -610,6 +618,8 @@ Action: generating QA tests and evidence."
|
|
|
610
618
|
esac
|
|
611
619
|
|
|
612
620
|
if [ "${PROVIDER_OK}" -eq 1 ]; then
|
|
621
|
+
QA_ATTEMPT_ELAPSED=$(( $(date +%s) - QA_ATTEMPT_START ))
|
|
622
|
+
log "QA: PR #${pr_num} — provider completed exit_code=0 elapsed=${QA_ATTEMPT_ELAPSED}s"
|
|
613
623
|
if provider_output_looks_invalid "${LOG_LINE_BEFORE}"; then
|
|
614
624
|
log "FAIL-QA-EVIDENCE: PR #${pr_num} provider output indicates an invalid automation run"
|
|
615
625
|
FAILED_AUTOMATION_PRS_CSV=$(append_csv "${FAILED_AUTOMATION_PRS_CSV}" "#${pr_num}")
|
|
@@ -660,6 +670,9 @@ UNCLASSIFIED_PRS_SUMMARY=$(csv_or_none "${UNCLASSIFIED_PRS_CSV}")
|
|
|
660
670
|
FAILED_AUTOMATION_PRS_SUMMARY=$(csv_or_none "${FAILED_AUTOMATION_PRS_CSV}")
|
|
661
671
|
FAILED_PR_SUMMARY=$(csv_or_none "${FAILED_PR}")
|
|
662
672
|
|
|
673
|
+
QA_TOTAL_ELAPSED=$(( $(date +%s) - SCRIPT_START_TIME ))
|
|
674
|
+
log "OUTCOME: exit_code=${EXIT_CODE} total_elapsed=${QA_TOTAL_ELAPSED}s processed_prs=${FINAL_PROCESSED_PRS_CSV:-none}"
|
|
675
|
+
|
|
663
676
|
if [ ${EXIT_CODE} -eq 0 ]; then
|
|
664
677
|
log "DONE: QA runner completed successfully"
|
|
665
678
|
TELEGRAM_SUCCESS_BODY="Project: ${PROJECT_NAME}
|
|
@@ -23,6 +23,7 @@ MAX_RUNTIME="${NW_SLICER_MAX_RUNTIME:-600}" # 10 minutes
|
|
|
23
23
|
MAX_LOG_SIZE="524288" # 512 KB
|
|
24
24
|
PROVIDER_CMD="${NW_PROVIDER_CMD:-claude}"
|
|
25
25
|
PROVIDER_LABEL="${NW_PROVIDER_LABEL:-}"
|
|
26
|
+
SCRIPT_START_TIME=$(date +%s)
|
|
26
27
|
|
|
27
28
|
# Ensure NVM / Node / Night Watch CLI are on PATH
|
|
28
29
|
export NVM_DIR="${HOME}/.nvm"
|
|
@@ -44,6 +45,9 @@ if ! validate_provider "${PROVIDER_CMD}"; then
|
|
|
44
45
|
fi
|
|
45
46
|
|
|
46
47
|
rotate_log
|
|
48
|
+
log_separator
|
|
49
|
+
log "RUN-START: slicer invoked project=${PROJECT_DIR} provider=${PROVIDER_CMD} dry_run=${NW_DRY_RUN:-0}"
|
|
50
|
+
log "CONFIG: max_runtime=${MAX_RUNTIME}s roadmap_path=${NW_ROADMAP_PATH:-ROADMAP.md}"
|
|
47
51
|
|
|
48
52
|
if ! acquire_lock "${LOCK_FILE}"; then
|
|
49
53
|
exit 0
|
|
@@ -83,12 +87,18 @@ fi
|
|
|
83
87
|
|
|
84
88
|
# Run the slice command with timeout
|
|
85
89
|
EXIT_CODE=0
|
|
90
|
+
SLICER_RUN_START=$(date +%s)
|
|
91
|
+
log "SLICER: Starting night-watch slice timeout=${MAX_RUNTIME}s"
|
|
86
92
|
if timeout "${MAX_RUNTIME}" "${CLI_BIN}" slice >> "${LOG_FILE}" 2>&1; then
|
|
87
93
|
EXIT_CODE=0
|
|
88
94
|
else
|
|
89
95
|
EXIT_CODE=$?
|
|
90
96
|
fi
|
|
91
97
|
|
|
98
|
+
SLICER_ELAPSED=$(( $(date +%s) - SLICER_RUN_START ))
|
|
99
|
+
SLICER_TOTAL_ELAPSED=$(( $(date +%s) - SCRIPT_START_TIME ))
|
|
100
|
+
log "OUTCOME: exit_code=${EXIT_CODE} run_elapsed=${SLICER_ELAPSED}s total_elapsed=${SLICER_TOTAL_ELAPSED}s project=${PROJECT_NAME}"
|
|
101
|
+
|
|
92
102
|
if [ ${EXIT_CODE} -eq 0 ]; then
|
|
93
103
|
log "DONE: Slicer completed successfully"
|
|
94
104
|
send_telegram_status_message "📋 Night Watch Planner: completed" "Project: ${PROJECT_NAME}
|