@jonit-dev/night-watch-cli 1.7.27 → 1.7.29
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/shared/types.d.ts +1 -0
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/src/cli.js +3 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/audit.d.ts +19 -0
- package/dist/src/commands/audit.d.ts.map +1 -0
- package/dist/src/commands/audit.js +98 -0
- package/dist/src/commands/audit.js.map +1 -0
- package/dist/src/commands/dashboard.js +1 -1
- package/dist/src/commands/dashboard.js.map +1 -1
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +1 -6
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/install.d.ts +4 -0
- package/dist/src/commands/install.d.ts.map +1 -1
- package/dist/src/commands/install.js +25 -20
- package/dist/src/commands/install.js.map +1 -1
- package/dist/src/commands/logs.js +3 -3
- package/dist/src/commands/logs.js.map +1 -1
- package/dist/src/commands/prs.js +2 -2
- package/dist/src/commands/prs.js.map +1 -1
- package/dist/src/commands/review.d.ts.map +1 -1
- package/dist/src/commands/review.js +13 -5
- package/dist/src/commands/review.js.map +1 -1
- package/dist/src/commands/uninstall.d.ts.map +1 -1
- package/dist/src/commands/uninstall.js +3 -22
- package/dist/src/commands/uninstall.js.map +1 -1
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +30 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/constants.d.ts +10 -3
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +15 -2
- package/dist/src/constants.js.map +1 -1
- package/dist/src/server/index.d.ts.map +1 -1
- package/dist/src/server/index.js +50 -3
- package/dist/src/server/index.js.map +1 -1
- package/dist/src/slack/client.d.ts +3 -2
- package/dist/src/slack/client.d.ts.map +1 -1
- package/dist/src/slack/client.js +5 -6
- package/dist/src/slack/client.js.map +1 -1
- package/dist/src/slack/deliberation.d.ts +13 -1
- package/dist/src/slack/deliberation.d.ts.map +1 -1
- package/dist/src/slack/deliberation.js +585 -71
- package/dist/src/slack/deliberation.js.map +1 -1
- package/dist/src/slack/interaction-listener.d.ts +27 -9
- package/dist/src/slack/interaction-listener.d.ts.map +1 -1
- package/dist/src/slack/interaction-listener.js +357 -197
- package/dist/src/slack/interaction-listener.js.map +1 -1
- package/dist/src/storage/repositories/sqlite/agent-persona-repository.d.ts +3 -2
- package/dist/src/storage/repositories/sqlite/agent-persona-repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/sqlite/agent-persona-repository.js +14 -11
- package/dist/src/storage/repositories/sqlite/agent-persona-repository.js.map +1 -1
- package/dist/src/types.d.ts +13 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/notify.d.ts.map +1 -1
- package/dist/src/utils/notify.js +5 -1
- package/dist/src/utils/notify.js.map +1 -1
- package/dist/src/utils/status-data.d.ts +2 -2
- package/dist/src/utils/status-data.d.ts.map +1 -1
- package/dist/src/utils/status-data.js +78 -123
- package/dist/src/utils/status-data.js.map +1 -1
- package/package.json +3 -1
- package/scripts/night-watch-audit-cron.sh +149 -0
- package/scripts/night-watch-cron.sh +33 -14
- package/scripts/night-watch-helpers.sh +10 -2
- package/scripts/night-watch-pr-reviewer-cron.sh +224 -18
- package/web/dist/assets/index-BiJf9LFT.js +458 -0
- package/web/dist/assets/index-OpSgvsYu.css +1 -0
- package/web/dist/index.html +2 -2
- package/web/dist/assets/index-CndIPm_F.js +0 -473
- package/web/dist/assets/index-w6Q6gxCS.css +0 -1
|
@@ -16,7 +16,7 @@ set -euo pipefail
|
|
|
16
16
|
PROJECT_DIR="${1:?Usage: $0 /path/to/project}"
|
|
17
17
|
PROJECT_NAME=$(basename "${PROJECT_DIR}")
|
|
18
18
|
LOG_DIR="${PROJECT_DIR}/logs"
|
|
19
|
-
LOG_FILE="${LOG_DIR}/
|
|
19
|
+
LOG_FILE="${LOG_DIR}/reviewer.log"
|
|
20
20
|
MAX_RUNTIME="${NW_REVIEWER_MAX_RUNTIME:-3600}" # 1 hour
|
|
21
21
|
MAX_LOG_SIZE="524288" # 512 KB
|
|
22
22
|
PROVIDER_CMD="${NW_PROVIDER_CMD:-claude}"
|
|
@@ -25,6 +25,8 @@ BRANCH_PATTERNS_RAW="${NW_BRANCH_PATTERNS:-feat/,night-watch/}"
|
|
|
25
25
|
AUTO_MERGE="${NW_AUTO_MERGE:-0}"
|
|
26
26
|
AUTO_MERGE_METHOD="${NW_AUTO_MERGE_METHOD:-squash}"
|
|
27
27
|
TARGET_PR="${NW_TARGET_PR:-}"
|
|
28
|
+
PARALLEL_ENABLED="${NW_REVIEWER_PARALLEL:-1}"
|
|
29
|
+
WORKER_MODE="${NW_REVIEWER_WORKER_MODE:-0}"
|
|
28
30
|
|
|
29
31
|
# Ensure NVM / Node / Claude are on PATH
|
|
30
32
|
export NVM_DIR="${HOME}/.nvm"
|
|
@@ -39,8 +41,13 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
39
41
|
# shellcheck source=night-watch-helpers.sh
|
|
40
42
|
source "${SCRIPT_DIR}/night-watch-helpers.sh"
|
|
41
43
|
PROJECT_RUNTIME_KEY=$(project_runtime_key "${PROJECT_DIR}")
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
GLOBAL_LOCK_FILE="/tmp/night-watch-pr-reviewer-${PROJECT_RUNTIME_KEY}.lock"
|
|
45
|
+
if [ "${WORKER_MODE}" = "1" ] && [ -n "${TARGET_PR}" ]; then
|
|
46
|
+
LOCK_FILE="/tmp/night-watch-pr-reviewer-${PROJECT_RUNTIME_KEY}-pr-${TARGET_PR}.lock"
|
|
47
|
+
else
|
|
48
|
+
# NOTE: Lock file path must match reviewerLockPath() in src/utils/status-data.ts
|
|
49
|
+
LOCK_FILE="${GLOBAL_LOCK_FILE}"
|
|
50
|
+
fi
|
|
44
51
|
|
|
45
52
|
emit_result() {
|
|
46
53
|
local status="${1:?status required}"
|
|
@@ -52,6 +59,38 @@ emit_result() {
|
|
|
52
59
|
fi
|
|
53
60
|
}
|
|
54
61
|
|
|
62
|
+
emit_final_status() {
|
|
63
|
+
local exit_code="${1:?exit code required}"
|
|
64
|
+
local prs_csv="${2:-}"
|
|
65
|
+
local auto_merged="${3:-}"
|
|
66
|
+
local auto_merge_failed="${4:-}"
|
|
67
|
+
|
|
68
|
+
if [ "${exit_code}" -eq 0 ]; then
|
|
69
|
+
log "DONE: PR reviewer completed successfully"
|
|
70
|
+
emit_result "success_reviewed" "prs=${prs_csv}|auto_merged=${auto_merged}|auto_merge_failed=${auto_merge_failed}"
|
|
71
|
+
elif [ "${exit_code}" -eq 124 ]; then
|
|
72
|
+
log "TIMEOUT: PR reviewer killed after ${MAX_RUNTIME}s"
|
|
73
|
+
emit_result "timeout" "prs=${prs_csv}"
|
|
74
|
+
else
|
|
75
|
+
log "FAIL: PR reviewer exited with code ${exit_code}"
|
|
76
|
+
emit_result "failure" "prs=${prs_csv}"
|
|
77
|
+
fi
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
append_csv() {
|
|
81
|
+
local current="${1:-}"
|
|
82
|
+
local incoming="${2:-}"
|
|
83
|
+
if [ -z "${incoming}" ]; then
|
|
84
|
+
printf "%s" "${current}"
|
|
85
|
+
return 0
|
|
86
|
+
fi
|
|
87
|
+
if [ -z "${current}" ]; then
|
|
88
|
+
printf "%s" "${incoming}"
|
|
89
|
+
else
|
|
90
|
+
printf "%s,%s" "${current}" "${incoming}"
|
|
91
|
+
fi
|
|
92
|
+
}
|
|
93
|
+
|
|
55
94
|
# Validate provider
|
|
56
95
|
if ! validate_provider "${PROVIDER_CMD}"; then
|
|
57
96
|
echo "ERROR: Unknown provider: ${PROVIDER_CMD}" >&2
|
|
@@ -159,6 +198,62 @@ done < <(gh pr list --state open --json number,headRefName --jq '.[] | [.number,
|
|
|
159
198
|
|
|
160
199
|
if [ "${NEEDS_WORK}" -eq 0 ]; then
|
|
161
200
|
log "SKIP: All ${OPEN_PRS} open PR(s) have passing CI and review score >= ${MIN_REVIEW_SCORE} (or no score yet)"
|
|
201
|
+
|
|
202
|
+
# ── Auto-merge eligible PRs ───────────────────────────────
|
|
203
|
+
if [ "${NW_AUTO_MERGE:-0}" = "1" ]; then
|
|
204
|
+
AUTO_MERGE_METHOD="${NW_AUTO_MERGE_METHOD:-squash}"
|
|
205
|
+
AUTO_MERGED_COUNT=0
|
|
206
|
+
|
|
207
|
+
log "AUTO-MERGE: Checking for merge-ready PRs (method: ${AUTO_MERGE_METHOD})"
|
|
208
|
+
|
|
209
|
+
while IFS=$'\t' read -r pr_number pr_branch; do
|
|
210
|
+
[ -z "${pr_number}" ] || [ -z "${pr_branch}" ] && continue
|
|
211
|
+
printf '%s\n' "${pr_branch}" | grep -Eq "${BRANCH_REGEX}" || continue
|
|
212
|
+
|
|
213
|
+
# Check CI status
|
|
214
|
+
FAILED_CHECKS=$(gh pr checks "${pr_number}" 2>/dev/null | grep -ci 'fail' || true)
|
|
215
|
+
[ "${FAILED_CHECKS}" -gt 0 ] && continue
|
|
216
|
+
|
|
217
|
+
# Check review score
|
|
218
|
+
PR_COMMENTS=$(
|
|
219
|
+
{
|
|
220
|
+
gh pr view "${pr_number}" --json comments --jq '.comments[].body' 2>/dev/null || true
|
|
221
|
+
if [ -n "${REPO}" ]; then
|
|
222
|
+
gh api "repos/${REPO}/issues/${pr_number}/comments" --jq '.[].body' 2>/dev/null || true
|
|
223
|
+
fi
|
|
224
|
+
} | sort -u
|
|
225
|
+
)
|
|
226
|
+
PR_SCORE=$(echo "${PR_COMMENTS}" \
|
|
227
|
+
| grep -oP 'Overall Score:\*?\*?\s*(\d+)/100' \
|
|
228
|
+
| tail -1 \
|
|
229
|
+
| grep -oP '\d+(?=/100)' || echo "")
|
|
230
|
+
|
|
231
|
+
# Skip PRs without a score or with score below threshold
|
|
232
|
+
[ -z "${PR_SCORE}" ] && continue
|
|
233
|
+
[ "${PR_SCORE}" -lt "${MIN_REVIEW_SCORE}" ] && continue
|
|
234
|
+
|
|
235
|
+
# PR is merge-ready
|
|
236
|
+
log "AUTO-MERGE: PR #${pr_number} (${pr_branch}) — score ${PR_SCORE}/100, CI passing"
|
|
237
|
+
|
|
238
|
+
# Dry-run mode: show what would be merged
|
|
239
|
+
if [ "${NW_DRY_RUN:-0}" = "1" ]; then
|
|
240
|
+
log "AUTO-MERGE (dry-run): Would queue merge for PR #${pr_number} using ${AUTO_MERGE_METHOD}"
|
|
241
|
+
continue
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
if gh pr merge "${pr_number}" --"${AUTO_MERGE_METHOD}" --auto --delete-branch 2>>"${LOG_FILE}"; then
|
|
245
|
+
log "AUTO-MERGE: Successfully queued merge for PR #${pr_number}"
|
|
246
|
+
AUTO_MERGED_COUNT=$((AUTO_MERGED_COUNT + 1))
|
|
247
|
+
else
|
|
248
|
+
log "WARN: Auto-merge failed for PR #${pr_number}"
|
|
249
|
+
fi
|
|
250
|
+
done < <(gh pr list --state open --json number,headRefName --jq '.[] | [.number, .headRefName] | @tsv' 2>/dev/null || true)
|
|
251
|
+
|
|
252
|
+
if [ "${AUTO_MERGED_COUNT}" -gt 0 ]; then
|
|
253
|
+
log "AUTO-MERGE: Queued ${AUTO_MERGED_COUNT} PR(s) for merge"
|
|
254
|
+
fi
|
|
255
|
+
fi
|
|
256
|
+
|
|
162
257
|
emit_result "skip_all_passing"
|
|
163
258
|
exit 0
|
|
164
259
|
fi
|
|
@@ -172,11 +267,121 @@ if [ -n "${NW_DEFAULT_BRANCH:-}" ]; then
|
|
|
172
267
|
else
|
|
173
268
|
DEFAULT_BRANCH=$(detect_default_branch "${PROJECT_DIR}")
|
|
174
269
|
fi
|
|
175
|
-
REVIEW_WORKTREE_DIR="$(dirname "${PROJECT_DIR}")/${PROJECT_NAME}-nw-review-runner"
|
|
176
270
|
|
|
177
271
|
log "START: Found PR(s) needing work:${PRS_NEEDING_WORK}"
|
|
178
272
|
|
|
179
|
-
|
|
273
|
+
# Convert "#12 #34" into ["12", "34"] for worker fan-out.
|
|
274
|
+
PR_NUMBER_ARRAY=()
|
|
275
|
+
for pr_token in ${PRS_NEEDING_WORK}; do
|
|
276
|
+
PR_NUMBER_ARRAY+=("${pr_token#\#}")
|
|
277
|
+
done
|
|
278
|
+
|
|
279
|
+
if [ -z "${TARGET_PR}" ] && [ "${WORKER_MODE}" != "1" ] && [ "${PARALLEL_ENABLED}" = "1" ] && [ "${#PR_NUMBER_ARRAY[@]}" -gt 1 ]; then
|
|
280
|
+
# Dry-run mode: print diagnostics and exit
|
|
281
|
+
if [ "${NW_DRY_RUN:-0}" = "1" ]; then
|
|
282
|
+
echo "=== Dry Run: PR Reviewer ==="
|
|
283
|
+
echo "Provider: ${PROVIDER_CMD}"
|
|
284
|
+
echo "Branch Patterns: ${BRANCH_PATTERNS_RAW}"
|
|
285
|
+
echo "Min Review Score: ${MIN_REVIEW_SCORE}"
|
|
286
|
+
echo "Auto-merge: ${AUTO_MERGE}"
|
|
287
|
+
if [ "${AUTO_MERGE}" = "1" ]; then
|
|
288
|
+
echo "Auto-merge Method: ${AUTO_MERGE_METHOD}"
|
|
289
|
+
fi
|
|
290
|
+
echo "Open PRs needing work:${PRS_NEEDING_WORK}"
|
|
291
|
+
echo "Default Branch: ${DEFAULT_BRANCH}"
|
|
292
|
+
echo "Parallel Workers: ${#PR_NUMBER_ARRAY[@]}"
|
|
293
|
+
echo "Timeout: ${MAX_RUNTIME}s"
|
|
294
|
+
exit 0
|
|
295
|
+
fi
|
|
296
|
+
|
|
297
|
+
log "PARALLEL: Launching ${#PR_NUMBER_ARRAY[@]} reviewer worker(s)"
|
|
298
|
+
|
|
299
|
+
declare -a WORKER_PIDS=()
|
|
300
|
+
declare -a WORKER_PRS=()
|
|
301
|
+
declare -a WORKER_OUTPUTS=()
|
|
302
|
+
|
|
303
|
+
for pr_number in "${PR_NUMBER_ARRAY[@]}"; do
|
|
304
|
+
worker_output=$(mktemp "/tmp/night-watch-pr-reviewer-${PROJECT_RUNTIME_KEY}-pr-${pr_number}.XXXXXX")
|
|
305
|
+
WORKER_OUTPUTS+=("${worker_output}")
|
|
306
|
+
WORKER_PRS+=("${pr_number}")
|
|
307
|
+
|
|
308
|
+
(
|
|
309
|
+
NW_TARGET_PR="${pr_number}" \
|
|
310
|
+
NW_REVIEWER_WORKER_MODE="1" \
|
|
311
|
+
NW_REVIEWER_PARALLEL="0" \
|
|
312
|
+
bash "${SCRIPT_DIR}/night-watch-pr-reviewer-cron.sh" "${PROJECT_DIR}" > "${worker_output}" 2>&1
|
|
313
|
+
) &
|
|
314
|
+
|
|
315
|
+
worker_pid=$!
|
|
316
|
+
WORKER_PIDS+=("${worker_pid}")
|
|
317
|
+
log "PARALLEL: Worker PID ${worker_pid} started for PR #${pr_number}"
|
|
318
|
+
done
|
|
319
|
+
|
|
320
|
+
EXIT_CODE=0
|
|
321
|
+
AUTO_MERGED_PRS=""
|
|
322
|
+
AUTO_MERGE_FAILED_PRS=""
|
|
323
|
+
|
|
324
|
+
for idx in "${!WORKER_PIDS[@]}"; do
|
|
325
|
+
worker_pid="${WORKER_PIDS[$idx]}"
|
|
326
|
+
worker_pr="${WORKER_PRS[$idx]}"
|
|
327
|
+
worker_output="${WORKER_OUTPUTS[$idx]}"
|
|
328
|
+
|
|
329
|
+
worker_exit_code=0
|
|
330
|
+
if wait "${worker_pid}"; then
|
|
331
|
+
worker_exit_code=0
|
|
332
|
+
else
|
|
333
|
+
worker_exit_code=$?
|
|
334
|
+
fi
|
|
335
|
+
|
|
336
|
+
if [ -f "${worker_output}" ] && [ -s "${worker_output}" ]; then
|
|
337
|
+
cat "${worker_output}" >> "${LOG_FILE}"
|
|
338
|
+
fi
|
|
339
|
+
|
|
340
|
+
worker_result=$(grep -o 'NIGHT_WATCH_RESULT:.*' "${worker_output}" 2>/dev/null | tail -1 || true)
|
|
341
|
+
worker_status=$(printf '%s' "${worker_result}" | sed -n 's/^NIGHT_WATCH_RESULT:\([^|]*\).*$/\1/p')
|
|
342
|
+
worker_auto_merged=$(printf '%s' "${worker_result}" | grep -oP '(?<=auto_merged=)[^|]+' || true)
|
|
343
|
+
worker_auto_merge_failed=$(printf '%s' "${worker_result}" | grep -oP '(?<=auto_merge_failed=)[^|]+' || true)
|
|
344
|
+
|
|
345
|
+
AUTO_MERGED_PRS=$(append_csv "${AUTO_MERGED_PRS}" "${worker_auto_merged}")
|
|
346
|
+
AUTO_MERGE_FAILED_PRS=$(append_csv "${AUTO_MERGE_FAILED_PRS}" "${worker_auto_merge_failed}")
|
|
347
|
+
|
|
348
|
+
rm -f "${worker_output}"
|
|
349
|
+
|
|
350
|
+
if [ "${worker_status}" = "failure" ] || { [ -n "${worker_status}" ] && [ "${worker_status}" != "success_reviewed" ] && [ "${worker_status}" != "timeout" ] && [ "${worker_status#skip_}" = "${worker_status}" ]; }; then
|
|
351
|
+
if [ "${EXIT_CODE}" -eq 0 ] || [ "${EXIT_CODE}" -eq 124 ]; then
|
|
352
|
+
EXIT_CODE=1
|
|
353
|
+
fi
|
|
354
|
+
log "PARALLEL: Worker for PR #${worker_pr} reported status '${worker_status:-unknown}'"
|
|
355
|
+
elif [ "${worker_status}" = "timeout" ]; then
|
|
356
|
+
if [ "${EXIT_CODE}" -eq 0 ]; then
|
|
357
|
+
EXIT_CODE=124
|
|
358
|
+
fi
|
|
359
|
+
log "PARALLEL: Worker for PR #${worker_pr} timed out"
|
|
360
|
+
elif [ "${worker_exit_code}" -ne 0 ]; then
|
|
361
|
+
if [ "${worker_exit_code}" -eq 124 ]; then
|
|
362
|
+
if [ "${EXIT_CODE}" -eq 0 ]; then
|
|
363
|
+
EXIT_CODE=124
|
|
364
|
+
fi
|
|
365
|
+
elif [ "${EXIT_CODE}" -eq 0 ] || [ "${EXIT_CODE}" -eq 124 ]; then
|
|
366
|
+
EXIT_CODE="${worker_exit_code}"
|
|
367
|
+
fi
|
|
368
|
+
log "PARALLEL: Worker for PR #${worker_pr} exited with code ${worker_exit_code}"
|
|
369
|
+
else
|
|
370
|
+
log "PARALLEL: Worker for PR #${worker_pr} completed"
|
|
371
|
+
fi
|
|
372
|
+
done
|
|
373
|
+
|
|
374
|
+
emit_final_status "${EXIT_CODE}" "${PRS_NEEDING_WORK_CSV}" "${AUTO_MERGED_PRS}" "${AUTO_MERGE_FAILED_PRS}"
|
|
375
|
+
exit 0
|
|
376
|
+
fi
|
|
377
|
+
|
|
378
|
+
REVIEW_WORKTREE_BASENAME="${PROJECT_NAME}-nw-review-runner"
|
|
379
|
+
if [ -n "${TARGET_PR}" ]; then
|
|
380
|
+
REVIEW_WORKTREE_BASENAME="${REVIEW_WORKTREE_BASENAME}-pr-${TARGET_PR}"
|
|
381
|
+
fi
|
|
382
|
+
REVIEW_WORKTREE_DIR="$(dirname "${PROJECT_DIR}")/${REVIEW_WORKTREE_BASENAME}"
|
|
383
|
+
|
|
384
|
+
cleanup_worktrees "${PROJECT_DIR}" "${REVIEW_WORKTREE_BASENAME}"
|
|
180
385
|
|
|
181
386
|
# Dry-run mode: print diagnostics and exit
|
|
182
387
|
if [ "${NW_DRY_RUN:-0}" = "1" ]; then
|
|
@@ -191,6 +396,10 @@ if [ "${NW_DRY_RUN:-0}" = "1" ]; then
|
|
|
191
396
|
echo "Open PRs needing work:${PRS_NEEDING_WORK}"
|
|
192
397
|
echo "Default Branch: ${DEFAULT_BRANCH}"
|
|
193
398
|
echo "Review Worktree: ${REVIEW_WORKTREE_DIR}"
|
|
399
|
+
echo "Target PR: ${TARGET_PR:-all}"
|
|
400
|
+
if [ -n "${TARGET_PR}" ]; then
|
|
401
|
+
echo "Worker Mode: ${WORKER_MODE}"
|
|
402
|
+
fi
|
|
194
403
|
echo "Timeout: ${MAX_RUNTIME}s"
|
|
195
404
|
exit 0
|
|
196
405
|
fi
|
|
@@ -201,12 +410,17 @@ if ! prepare_detached_worktree "${PROJECT_DIR}" "${REVIEW_WORKTREE_DIR}" "${DEFA
|
|
|
201
410
|
fi
|
|
202
411
|
|
|
203
412
|
EXIT_CODE=0
|
|
413
|
+
TARGET_SCOPE_PROMPT=""
|
|
414
|
+
if [ -n "${TARGET_PR}" ]; then
|
|
415
|
+
TARGET_SCOPE_PROMPT=$'\n\n## Target Scope\n- Only process PR #'"${TARGET_PR}"$'.\n- Ignore all other PRs.\n- If this PR no longer needs work, stop immediately.\n'
|
|
416
|
+
fi
|
|
204
417
|
|
|
205
418
|
case "${PROVIDER_CMD}" in
|
|
206
419
|
claude)
|
|
420
|
+
CLAUDE_PROMPT="/night-watch-pr-reviewer${TARGET_SCOPE_PROMPT}"
|
|
207
421
|
if (
|
|
208
422
|
cd "${REVIEW_WORKTREE_DIR}" && timeout "${MAX_RUNTIME}" \
|
|
209
|
-
claude -p "
|
|
423
|
+
claude -p "${CLAUDE_PROMPT}" \
|
|
210
424
|
--dangerously-skip-permissions \
|
|
211
425
|
>> "${LOG_FILE}" 2>&1
|
|
212
426
|
); then
|
|
@@ -216,11 +430,12 @@ case "${PROVIDER_CMD}" in
|
|
|
216
430
|
fi
|
|
217
431
|
;;
|
|
218
432
|
codex)
|
|
433
|
+
CODEX_PROMPT="$(cat "${REVIEW_WORKTREE_DIR}/.claude/commands/night-watch-pr-reviewer.md")${TARGET_SCOPE_PROMPT}"
|
|
219
434
|
if (
|
|
220
435
|
cd "${REVIEW_WORKTREE_DIR}" && timeout "${MAX_RUNTIME}" \
|
|
221
436
|
codex --quiet \
|
|
222
437
|
--yolo \
|
|
223
|
-
--prompt "$
|
|
438
|
+
--prompt "${CODEX_PROMPT}" \
|
|
224
439
|
>> "${LOG_FILE}" 2>&1
|
|
225
440
|
); then
|
|
226
441
|
EXIT_CODE=0
|
|
@@ -234,7 +449,7 @@ case "${PROVIDER_CMD}" in
|
|
|
234
449
|
;;
|
|
235
450
|
esac
|
|
236
451
|
|
|
237
|
-
cleanup_worktrees "${PROJECT_DIR}"
|
|
452
|
+
cleanup_worktrees "${PROJECT_DIR}" "${REVIEW_WORKTREE_BASENAME}"
|
|
238
453
|
|
|
239
454
|
# ── Auto-merge eligible PRs ─────────────────────────────────────────────────────
|
|
240
455
|
# After the reviewer completes, check for PRs that are merge-ready and queue them
|
|
@@ -310,13 +525,4 @@ if [ "${AUTO_MERGE}" = "1" ] && [ ${EXIT_CODE} -eq 0 ]; then
|
|
|
310
525
|
done < <(gh pr list --state open --json number,headRefName --jq '.[] | [.number, .headRefName] | @tsv' 2>/dev/null || true)
|
|
311
526
|
fi
|
|
312
527
|
|
|
313
|
-
|
|
314
|
-
log "DONE: PR reviewer completed successfully"
|
|
315
|
-
emit_result "success_reviewed" "prs=${PRS_NEEDING_WORK_CSV}|auto_merged=${AUTO_MERGED_PRS}|auto_merge_failed=${AUTO_MERGE_FAILED_PRS}"
|
|
316
|
-
elif [ ${EXIT_CODE} -eq 124 ]; then
|
|
317
|
-
log "TIMEOUT: PR reviewer killed after ${MAX_RUNTIME}s"
|
|
318
|
-
emit_result "timeout" "prs=${PRS_NEEDING_WORK_CSV}"
|
|
319
|
-
else
|
|
320
|
-
log "FAIL: PR reviewer exited with code ${EXIT_CODE}"
|
|
321
|
-
emit_result "failure" "prs=${PRS_NEEDING_WORK_CSV}"
|
|
322
|
-
fi
|
|
528
|
+
emit_final_status "${EXIT_CODE}" "${PRS_NEEDING_WORK_CSV}" "${AUTO_MERGED_PRS}" "${AUTO_MERGE_FAILED_PRS}"
|