@jonit-dev/night-watch-cli 1.8.14-beta.1 → 1.8.14-beta.2

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.
@@ -269,19 +269,93 @@ wait_for_ci_passing_on_head() {
269
269
  [ "${LAST_CI_STATUS}" = "passing" ]
270
270
  }
271
271
 
272
- run_local_checks_for_head() {
272
+ find_existing_worktree_for_head() {
273
+ local pr_branch="${1}"
274
+ local expected_head="${2}"
275
+ local project_real=""
276
+ local worktree_path=""
277
+ local branch=""
278
+ local head=""
279
+
280
+ project_real=$(cd "${PROJECT_DIR}" && pwd -P 2>/dev/null || echo "${PROJECT_DIR}")
281
+
282
+ while IFS= read -r line; do
283
+ if [[ "${line}" == worktree\ * ]]; then
284
+ worktree_path="${line#worktree }"
285
+ branch=""
286
+ head=""
287
+ continue
288
+ fi
289
+ if [[ "${line}" == HEAD\ * ]]; then
290
+ head="${line#HEAD }"
291
+ continue
292
+ fi
293
+ if [[ "${line}" == branch\ * ]]; then
294
+ branch="${line#branch refs/heads/}"
295
+ if [ -n "${worktree_path}" ] \
296
+ && [ "${branch}" = "${pr_branch}" ] \
297
+ && [ "${head}" = "${expected_head}" ] \
298
+ && [ -d "${worktree_path}" ]; then
299
+ local worktree_real=""
300
+ worktree_real=$(cd "${worktree_path}" && pwd -P 2>/dev/null || echo "${worktree_path}")
301
+ if [ "${worktree_real}" = "${project_real}" ]; then
302
+ continue
303
+ fi
304
+ if git -C "${worktree_path}" diff --quiet >/dev/null 2>&1 \
305
+ && git -C "${worktree_path}" diff --cached --quiet >/dev/null 2>&1; then
306
+ printf "%s" "${worktree_path}"
307
+ return 0
308
+ fi
309
+ fi
310
+ fi
311
+ done < <(git worktree list --porcelain 2>/dev/null || true)
312
+
313
+ return 1
314
+ }
315
+
316
+ run_local_check_command_in_dir() {
273
317
  local pr_number="${1}"
274
318
  local expected_head="${2}"
319
+ local check_dir="${3}"
320
+ local check_exit=1
321
+
322
+ set +e
323
+ (
324
+ cd "${check_dir}"
325
+ bash -lc "${LOCAL_CHECK_COMMAND}"
326
+ ) 2>&1 | tee -a "${LOG_FILE}"
327
+ check_exit=${PIPESTATUS[0]}
328
+ set -e
329
+
330
+ if [ "${check_exit}" -eq 0 ]; then
331
+ log "INFO: PR #${pr_number}: Local checks passed for head ${expected_head}"
332
+ return 0
333
+ fi
334
+
335
+ log "INFO: PR #${pr_number}: Local checks failed for head ${expected_head} (exit ${check_exit})"
336
+ return 1
337
+ }
338
+
339
+ run_local_checks_for_head() {
340
+ local pr_number="${1}"
341
+ local pr_branch="${2}"
342
+ local expected_head="${3}"
275
343
  local temp_parent=""
276
344
  local worktree_dir=""
345
+ local existing_worktree_dir=""
277
346
  local temp_ref=""
278
- local check_exit=1
279
347
 
280
348
  if [ -z "${LOCAL_CHECK_COMMAND}" ]; then
281
349
  log "INFO: PR #${pr_number}: Local check command is empty, treating fallback as failed"
282
350
  return 1
283
351
  fi
284
352
 
353
+ if existing_worktree_dir=$(find_existing_worktree_for_head "${pr_branch}" "${expected_head}"); then
354
+ log "INFO: PR #${pr_number}: Reusing existing worktree for local checks: ${existing_worktree_dir}"
355
+ run_local_check_command_in_dir "${pr_number}" "${expected_head}" "${existing_worktree_dir}"
356
+ return $?
357
+ fi
358
+
285
359
  temp_parent=$(mktemp -d "${TMPDIR:-/tmp}/night-watch-merger-${pr_number}.XXXXXX")
286
360
  worktree_dir="${temp_parent}/worktree"
287
361
  temp_ref="refs/night-watch/merger/${pr_number}-${expected_head}"
@@ -311,23 +385,12 @@ run_local_checks_for_head() {
311
385
  fi
312
386
  fi
313
387
 
314
- set +e
315
- (
316
- cd "${worktree_dir}"
317
- bash -lc "${LOCAL_CHECK_COMMAND}"
318
- ) 2>&1 | tee -a "${LOG_FILE}"
319
- check_exit=${PIPESTATUS[0]}
320
- set -e
388
+ run_local_check_command_in_dir "${pr_number}" "${expected_head}" "${worktree_dir}"
389
+ local check_result=$?
321
390
 
322
391
  cleanup_local_check_worktree
323
392
 
324
- if [ "${check_exit}" -eq 0 ]; then
325
- log "INFO: PR #${pr_number}: Local checks passed for head ${expected_head}"
326
- return 0
327
- fi
328
-
329
- log "INFO: PR #${pr_number}: Local checks failed for head ${expected_head} (exit ${check_exit})"
330
- return 1
393
+ return "${check_result}"
331
394
  }
332
395
 
333
396
  ci_gate_allows_head() {
@@ -349,7 +412,7 @@ ci_gate_allows_head() {
349
412
 
350
413
  if [ "${CI_POLICY}" = "fallback-local" ]; then
351
414
  log "INFO: PR #${pr_number} (${pr_branch}): ${context} not passing on head ${expected_head} (${ci_status}); trying local checks"
352
- if run_local_checks_for_head "${pr_number}" "${expected_head}"; then
415
+ if run_local_checks_for_head "${pr_number}" "${pr_branch}" "${expected_head}"; then
353
416
  return 0
354
417
  fi
355
418
  log "INFO: PR #${pr_number} (${pr_branch}): Local check fallback failed, skipping"
@@ -540,7 +603,7 @@ while IFS= read -r pr_json; do
540
603
  if ! wait_for_ci_passing_on_head "${pr_number}" "${pr_head_after_rebase}"; then
541
604
  log "INFO: PR #${pr_number}: Fresh CI not passing on head ${pr_head_after_rebase} after rebase (${LAST_CI_STATUS}, waited ${CI_MAX_WAIT}s)"
542
605
  if [ "${CI_POLICY}" = "fallback-local" ]; then
543
- if ! run_local_checks_for_head "${pr_number}" "${pr_head_after_rebase}"; then
606
+ if ! run_local_checks_for_head "${pr_number}" "${pr_branch}" "${pr_head_after_rebase}"; then
544
607
  log "INFO: PR #${pr_number}: Fresh local check fallback failed after rebase, skipping"
545
608
  continue
546
609
  fi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jonit-dev/night-watch-cli",
3
- "version": "1.8.14-beta.1",
3
+ "version": "1.8.14-beta.2",
4
4
  "description": "AI agent that implements your specs, opens PRs, and reviews code overnight. Queue GitHub issues or PRDs, wake up to pull requests.",
5
5
  "type": "module",
6
6
  "bin": {