@jonit-dev/night-watch-cli 1.8.10-beta.1 → 1.8.10-beta.11
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 +2453 -1378
- package/dist/commands/dashboard/tab-config.d.ts.map +1 -1
- package/dist/commands/queue.d.ts.map +1 -1
- package/dist/commands/shared/env-builder.d.ts.map +1 -1
- package/dist/scripts/night-watch-cron.sh +344 -53
- package/dist/scripts/night-watch-helpers.sh +182 -7
- package/dist/scripts/night-watch-merger-cron.sh +8 -2
- package/dist/scripts/night-watch-plan-cron.sh +1 -1
- package/dist/scripts/night-watch-pr-resolver-cron.sh +7 -3
- package/dist/scripts/night-watch-pr-reviewer-cron.sh +5 -0
- package/dist/scripts/night-watch-qa-cron.sh +5 -0
- package/dist/scripts/night-watch-slicer-cron.sh +1 -1
- package/dist/web/assets/index-B6E6kOoR.js +406 -0
- package/dist/web/assets/index-DIMUXIP8.css +1 -0
- package/dist/web/assets/index-Ds8OqaCa.css +1 -0
- package/dist/web/assets/index-NR27JE3b.js +406 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/cli.d.ts +0 -3
- package/dist/cli.js.map +0 -1
- package/dist/commands/analytics.d.ts +0 -14
- package/dist/commands/analytics.js +0 -69
- package/dist/commands/analytics.js.map +0 -1
- package/dist/commands/audit.d.ts +0 -19
- package/dist/commands/audit.js +0 -144
- package/dist/commands/audit.js.map +0 -1
- package/dist/commands/board.d.ts +0 -9
- package/dist/commands/board.js +0 -702
- package/dist/commands/board.js.map +0 -1
- package/dist/commands/cancel.d.ts +0 -46
- package/dist/commands/cancel.js +0 -239
- package/dist/commands/cancel.js.map +0 -1
- package/dist/commands/cron.d.ts +0 -8
- package/dist/commands/cron.js +0 -134
- package/dist/commands/cron.js.map +0 -1
- package/dist/commands/dashboard/tab-actions.d.ts +0 -10
- package/dist/commands/dashboard/tab-actions.js +0 -247
- package/dist/commands/dashboard/tab-actions.js.map +0 -1
- package/dist/commands/dashboard/tab-config.d.ts +0 -21
- package/dist/commands/dashboard/tab-config.js +0 -873
- package/dist/commands/dashboard/tab-config.js.map +0 -1
- package/dist/commands/dashboard/tab-logs.d.ts +0 -10
- package/dist/commands/dashboard/tab-logs.js +0 -202
- package/dist/commands/dashboard/tab-logs.js.map +0 -1
- package/dist/commands/dashboard/tab-schedules.d.ts +0 -21
- package/dist/commands/dashboard/tab-schedules.js +0 -320
- package/dist/commands/dashboard/tab-schedules.js.map +0 -1
- package/dist/commands/dashboard/tab-status.d.ts +0 -32
- package/dist/commands/dashboard/tab-status.js +0 -424
- package/dist/commands/dashboard/tab-status.js.map +0 -1
- package/dist/commands/dashboard/types.d.ts +0 -42
- package/dist/commands/dashboard/types.js +0 -5
- package/dist/commands/dashboard/types.js.map +0 -1
- package/dist/commands/dashboard.d.ts +0 -11
- package/dist/commands/dashboard.js +0 -242
- package/dist/commands/dashboard.js.map +0 -1
- package/dist/commands/doctor.d.ts +0 -16
- package/dist/commands/doctor.js +0 -195
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/history.d.ts +0 -7
- package/dist/commands/history.js +0 -49
- package/dist/commands/history.js.map +0 -1
- package/dist/commands/init.d.ts +0 -45
- package/dist/commands/init.js +0 -777
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/install.d.ts +0 -65
- package/dist/commands/install.js +0 -405
- package/dist/commands/install.js.map +0 -1
- package/dist/commands/logs.d.ts +0 -15
- package/dist/commands/logs.js +0 -155
- package/dist/commands/logs.js.map +0 -1
- package/dist/commands/merge.d.ts +0 -26
- package/dist/commands/merge.js +0 -159
- package/dist/commands/merge.js.map +0 -1
- package/dist/commands/notify.d.ts +0 -7
- package/dist/commands/notify.js +0 -43
- package/dist/commands/notify.js.map +0 -1
- package/dist/commands/plan.d.ts +0 -19
- package/dist/commands/plan.js +0 -88
- package/dist/commands/plan.js.map +0 -1
- package/dist/commands/prd-state.d.ts +0 -12
- package/dist/commands/prd-state.js +0 -47
- package/dist/commands/prd-state.js.map +0 -1
- package/dist/commands/prd.d.ts +0 -18
- package/dist/commands/prd.js +0 -363
- package/dist/commands/prd.js.map +0 -1
- package/dist/commands/prds.d.ts +0 -13
- package/dist/commands/prds.js +0 -194
- package/dist/commands/prds.js.map +0 -1
- package/dist/commands/prs.d.ts +0 -14
- package/dist/commands/prs.js +0 -104
- package/dist/commands/prs.js.map +0 -1
- package/dist/commands/qa.d.ts +0 -34
- package/dist/commands/qa.js +0 -214
- package/dist/commands/qa.js.map +0 -1
- package/dist/commands/queue.d.ts +0 -8
- package/dist/commands/queue.js +0 -376
- package/dist/commands/queue.js.map +0 -1
- package/dist/commands/resolve.d.ts +0 -26
- package/dist/commands/resolve.js +0 -186
- package/dist/commands/resolve.js.map +0 -1
- package/dist/commands/retry.d.ts +0 -9
- package/dist/commands/retry.js +0 -71
- package/dist/commands/retry.js.map +0 -1
- package/dist/commands/review.d.ts +0 -82
- package/dist/commands/review.js +0 -479
- package/dist/commands/review.js.map +0 -1
- package/dist/commands/run.d.ts +0 -73
- package/dist/commands/run.js +0 -509
- package/dist/commands/run.js.map +0 -1
- package/dist/commands/serve.d.ts +0 -19
- package/dist/commands/serve.js +0 -142
- package/dist/commands/serve.js.map +0 -1
- package/dist/commands/shared/env-builder.d.ts +0 -49
- package/dist/commands/shared/env-builder.js +0 -150
- package/dist/commands/shared/env-builder.js.map +0 -1
- package/dist/commands/slice.d.ts +0 -35
- package/dist/commands/slice.js +0 -316
- package/dist/commands/slice.js.map +0 -1
- package/dist/commands/state.d.ts +0 -8
- package/dist/commands/state.js +0 -54
- package/dist/commands/state.js.map +0 -1
- package/dist/commands/status.d.ts +0 -14
- package/dist/commands/status.js +0 -297
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/summary.d.ts +0 -14
- package/dist/commands/summary.js +0 -193
- package/dist/commands/summary.js.map +0 -1
- package/dist/commands/uninstall.d.ts +0 -25
- package/dist/commands/uninstall.js +0 -134
- package/dist/commands/uninstall.js.map +0 -1
- package/dist/commands/update.d.ts +0 -22
- package/dist/commands/update.js +0 -90
- package/dist/commands/update.js.map +0 -1
- package/dist/web/assets/index-2JY0x_Ij.js +0 -381
- package/dist/web/assets/index-3h8pgmqL.css +0 -1
- package/dist/web/assets/index-B-wbyZq7.js +0 -386
- package/dist/web/assets/index-B1BnOpiO.css +0 -1
- package/dist/web/assets/index-B3CnV08_.js +0 -365
- package/dist/web/assets/index-B5QjuFh9.css +0 -1
- package/dist/web/assets/index-B8FW2ecQ.js +0 -370
- package/dist/web/assets/index-BFxPiKyy.js +0 -381
- package/dist/web/assets/index-BGqNh_Da.js +0 -365
- package/dist/web/assets/index-BIONU0qz.css +0 -1
- package/dist/web/assets/index-B_l_3wnA.js +0 -370
- package/dist/web/assets/index-Ba-4YvTQ.js +0 -365
- package/dist/web/assets/index-Bbb4-39N.js +0 -370
- package/dist/web/assets/index-BdgdShEN.js +0 -365
- package/dist/web/assets/index-BhiC4Z-G.js +0 -381
- package/dist/web/assets/index-BjhCFjZi.js +0 -381
- package/dist/web/assets/index-BlRxmrnQ.css +0 -1
- package/dist/web/assets/index-BqwbXsHS.js +0 -365
- package/dist/web/assets/index-BsC7RT48.css +0 -1
- package/dist/web/assets/index-Bvh8XI8_.js +0 -370
- package/dist/web/assets/index-C01r2ymn.js +0 -381
- package/dist/web/assets/index-C51Rbsmk.js +0 -381
- package/dist/web/assets/index-C7lMNxRE.js +0 -370
- package/dist/web/assets/index-CJLObgsn.js +0 -386
- package/dist/web/assets/index-CLuRf7Zt.js +0 -381
- package/dist/web/assets/index-CM3xFd3e.css +0 -1
- package/dist/web/assets/index-CNkBtDK7.js +0 -370
- package/dist/web/assets/index-CPQbZ1BL.css +0 -1
- package/dist/web/assets/index-CTy5dUDU.css +0 -1
- package/dist/web/assets/index-CU15COKs.js +0 -370
- package/dist/web/assets/index-CiRJZI4z.js +0 -386
- package/dist/web/assets/index-Cp7RYjoy.css +0 -1
- package/dist/web/assets/index-CvPkZOWT.js +0 -381
- package/dist/web/assets/index-CvUk-33B.css +0 -1
- package/dist/web/assets/index-Cvmj-oF6.css +0 -1
- package/dist/web/assets/index-CxE5iQVO.js +0 -381
- package/dist/web/assets/index-D7lZQpFV.js +0 -365
- package/dist/web/assets/index-DAyP4GOi.css +0 -1
- package/dist/web/assets/index-DCG0n8Kg.js +0 -386
- package/dist/web/assets/index-DEEI8cyF.css +0 -1
- package/dist/web/assets/index-DF99BowV.js +0 -381
- package/dist/web/assets/index-DGWsvFj6.css +0 -1
- package/dist/web/assets/index-DGpU39Cp.css +0 -1
- package/dist/web/assets/index-DI4kFgOi.js +0 -370
- package/dist/web/assets/index-DIyTcPw5.css +0 -1
- package/dist/web/assets/index-DTsfDC7m.js +0 -381
- package/dist/web/assets/index-DcgNAi4A.js +0 -386
- package/dist/web/assets/index-DgOAgkZy.css +0 -1
- package/dist/web/assets/index-DnHkqbOa.js +0 -386
- package/dist/web/assets/index-DnR7Idcf.css +0 -1
- package/dist/web/assets/index-DpVirMEe.css +0 -1
- package/dist/web/assets/index-DsYIWZ86.css +0 -1
- package/dist/web/assets/index-DtrDkci5.js +0 -381
- package/dist/web/assets/index-DyjIth5M.js +0 -386
- package/dist/web/assets/index-FwIKfHPL.css +0 -1
- package/dist/web/assets/index-IKrZymWk.css +0 -1
- package/dist/web/assets/index-MA6fM0ab.js +0 -381
- package/dist/web/assets/index-N_QxaSEg.css +0 -1
- package/dist/web/assets/index-OcU-0TCQ.css +0 -1
- package/dist/web/assets/index-OyhrmG-L.js +0 -381
- package/dist/web/assets/index-SQlBKu_s.js +0 -386
- package/dist/web/assets/index-Sv2B60J4.js +0 -370
- package/dist/web/assets/index-Vgyivb5u.js +0 -365
- package/dist/web/assets/index-ZABWMEZR.js +0 -381
- package/dist/web/assets/index-ZE5lOeJp.js +0 -386
- package/dist/web/assets/index-aCHmkAcJ.css +0 -1
- package/dist/web/assets/index-bFijnpuU.js +0 -381
- package/dist/web/assets/index-bUPZgSoZ.css +0 -1
- package/dist/web/assets/index-mz1VIYsP.css +0 -1
- package/dist/web/assets/index-oOp_MFeE.js +0 -376
- package/dist/web/assets/index-rfU713Zm.js +0 -386
- package/dist/web/assets/index-tuNH9gmb.js +0 -448
- package/dist/web/assets/index-viSwHyDD.js +0 -365
- package/dist/web/assets/index-yKEQysks.js +0 -365
|
@@ -87,6 +87,123 @@ validate_provider() {
|
|
|
87
87
|
return 1
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
night_watch_push_uses_no_verify() {
|
|
91
|
+
[ "${NW_GIT_PUSH_NO_VERIFY:-0}" = "1" ]
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
git_push_for_project() {
|
|
95
|
+
local repo_dir="${1:?repo_dir required}"
|
|
96
|
+
shift
|
|
97
|
+
|
|
98
|
+
if night_watch_push_uses_no_verify; then
|
|
99
|
+
git -C "${repo_dir}" push --no-verify "$@"
|
|
100
|
+
else
|
|
101
|
+
git -C "${repo_dir}" push "$@"
|
|
102
|
+
fi
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
project_git_push_command() {
|
|
106
|
+
local branch_name="${1:?branch_name required}"
|
|
107
|
+
local mode="${2:-normal}"
|
|
108
|
+
local no_verify=""
|
|
109
|
+
|
|
110
|
+
if night_watch_push_uses_no_verify; then
|
|
111
|
+
no_verify=" --no-verify"
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
case "${mode}" in
|
|
115
|
+
force-with-lease)
|
|
116
|
+
printf 'git push%s --force-with-lease origin %s' "${no_verify}" "${branch_name}"
|
|
117
|
+
;;
|
|
118
|
+
*)
|
|
119
|
+
printf 'git push%s origin %s' "${no_verify}" "${branch_name}"
|
|
120
|
+
;;
|
|
121
|
+
esac
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
# ── Executor PR status labels ────────────────────────────────────────────────
|
|
125
|
+
|
|
126
|
+
NW_EXECUTOR_PARTIAL_LABEL="${NW_EXECUTOR_PARTIAL_LABEL:-nw:partial}"
|
|
127
|
+
NW_EXECUTOR_RESUMABLE_LABEL="${NW_EXECUTOR_RESUMABLE_LABEL:-nw:resumable}"
|
|
128
|
+
NW_EXECUTOR_READY_REVIEW_LABEL="${NW_EXECUTOR_READY_REVIEW_LABEL:-nw:ready-review}"
|
|
129
|
+
|
|
130
|
+
csv_has_label() {
|
|
131
|
+
local csv="${1:-}"
|
|
132
|
+
local label="${2:?label required}"
|
|
133
|
+
|
|
134
|
+
printf '%s\n' "${csv}" \
|
|
135
|
+
| tr ',' '\n' \
|
|
136
|
+
| sed '/^[[:space:]]*$/d' \
|
|
137
|
+
| grep -Fxq "${label}"
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
ensure_github_label() {
|
|
141
|
+
local label_name="${1:?label_name required}"
|
|
142
|
+
local description="${2:-}"
|
|
143
|
+
local color="${3:-1d76db}"
|
|
144
|
+
|
|
145
|
+
gh label create "${label_name}" \
|
|
146
|
+
--description "${description}" \
|
|
147
|
+
--color "${color}" \
|
|
148
|
+
--force 2>/dev/null || true
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
ensure_executor_status_labels() {
|
|
152
|
+
ensure_github_label \
|
|
153
|
+
"${NW_EXECUTOR_PARTIAL_LABEL}" \
|
|
154
|
+
"Executor started this PR and work is intentionally incomplete" \
|
|
155
|
+
"fbca04"
|
|
156
|
+
ensure_github_label \
|
|
157
|
+
"${NW_EXECUTOR_RESUMABLE_LABEL}" \
|
|
158
|
+
"Executor should resume this unfinished PR before starting new work" \
|
|
159
|
+
"d93f0b"
|
|
160
|
+
ensure_github_label \
|
|
161
|
+
"${NW_EXECUTOR_READY_REVIEW_LABEL}" \
|
|
162
|
+
"Executor finished implementation and the PR is ready for automated/human review" \
|
|
163
|
+
"0e8a16"
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
find_open_pr_for_branch() {
|
|
167
|
+
local branch_name="${1:?branch_name required}"
|
|
168
|
+
local pr_list=""
|
|
169
|
+
|
|
170
|
+
pr_list=$(gh pr list --state open --limit 200 \
|
|
171
|
+
--json number,headRefName,url,title,isDraft,labels,createdAt 2>/dev/null || echo "[]")
|
|
172
|
+
|
|
173
|
+
printf '%s' "${pr_list}" \
|
|
174
|
+
| jq -c --arg branch_name "${branch_name}" '
|
|
175
|
+
.[]
|
|
176
|
+
| select((.headRefName // "") == $branch_name)
|
|
177
|
+
' 2>/dev/null \
|
|
178
|
+
| head -n 1 || true
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
find_executor_resume_pr() {
|
|
182
|
+
local branch_prefix="${1:-night-watch}"
|
|
183
|
+
local pr_list=""
|
|
184
|
+
|
|
185
|
+
pr_list=$(gh pr list --state open --limit 200 \
|
|
186
|
+
--json number,headRefName,url,title,isDraft,labels,createdAt 2>/dev/null || echo "[]")
|
|
187
|
+
|
|
188
|
+
printf '%s' "${pr_list}" \
|
|
189
|
+
| jq -c \
|
|
190
|
+
--arg primary_prefix "${branch_prefix}/" \
|
|
191
|
+
--arg resumable_label "${NW_EXECUTOR_RESUMABLE_LABEL}" '
|
|
192
|
+
[
|
|
193
|
+
.[]
|
|
194
|
+
| select(
|
|
195
|
+
(.headRefName // "" | startswith($primary_prefix))
|
|
196
|
+
or
|
|
197
|
+
(.headRefName // "" | startswith("feat/"))
|
|
198
|
+
)
|
|
199
|
+
| .labelNames = ((.labels // []) | map(.name))
|
|
200
|
+
| select((.labelNames | index($resumable_label)) != null)
|
|
201
|
+
]
|
|
202
|
+
| sort_by(.createdAt // "")
|
|
203
|
+
| .[0] // empty
|
|
204
|
+
' 2>/dev/null || true
|
|
205
|
+
}
|
|
206
|
+
|
|
90
207
|
# ── Generic Provider Command Builder ──────────────────────────────────────────
|
|
91
208
|
|
|
92
209
|
# Build a provider command from NW_PROVIDER_* environment variables.
|
|
@@ -180,6 +297,13 @@ resolve_night_watch_cli() {
|
|
|
180
297
|
|
|
181
298
|
local bundled_bin="${script_dir}/../bin/night-watch.mjs"
|
|
182
299
|
if [ -x "${bundled_bin}" ]; then
|
|
300
|
+
# Verify dist/ exists — prevents ERR_MODULE_NOT_FOUND crashes
|
|
301
|
+
local dist_dir
|
|
302
|
+
dist_dir="$(cd "$(dirname "${bundled_bin}")" && pwd)/../dist"
|
|
303
|
+
if [ ! -d "${dist_dir}" ]; then
|
|
304
|
+
echo "ERROR: night-watch dist/ not found at ${dist_dir}; run 'yarn build'" >&2
|
|
305
|
+
return 1
|
|
306
|
+
fi
|
|
183
307
|
printf "%s" "${bundled_bin}"
|
|
184
308
|
return 0
|
|
185
309
|
fi
|
|
@@ -360,20 +484,58 @@ acquire_lock() {
|
|
|
360
484
|
local lock_file="${1:?lock_file required}"
|
|
361
485
|
|
|
362
486
|
if [ -f "${lock_file}" ]; then
|
|
363
|
-
local lock_pid
|
|
364
|
-
|
|
487
|
+
local lock_content lock_pid lock_ts
|
|
488
|
+
lock_content=$(cat "${lock_file}" 2>/dev/null || echo "")
|
|
489
|
+
lock_pid=$(echo "${lock_content}" | awk '{print $1}')
|
|
490
|
+
lock_ts=$(echo "${lock_content}" | awk '{print $2}')
|
|
491
|
+
|
|
365
492
|
if [ -n "${lock_pid}" ] && kill -0 "${lock_pid}" 2>/dev/null; then
|
|
366
|
-
|
|
367
|
-
|
|
493
|
+
# PID is alive — but guard against PID reuse via /proc start time
|
|
494
|
+
if _is_lock_holder_alive "${lock_pid}" "${lock_ts}"; then
|
|
495
|
+
log "SKIP: Previous run (PID ${lock_pid}) still active"
|
|
496
|
+
return 1
|
|
497
|
+
fi
|
|
498
|
+
log "WARN: PID ${lock_pid} reused by another process, lock is stale"
|
|
499
|
+
else
|
|
500
|
+
log "WARN: Stale lock file found (PID ${lock_pid}), removing"
|
|
368
501
|
fi
|
|
369
|
-
log "WARN: Stale lock file found (PID ${lock_pid}), removing"
|
|
370
502
|
rm -f "${lock_file}"
|
|
371
503
|
fi
|
|
372
504
|
|
|
373
505
|
local quoted_lock_file=""
|
|
374
506
|
printf -v quoted_lock_file '%q' "${lock_file}"
|
|
375
507
|
append_exit_trap "rm -f -- ${quoted_lock_file}"
|
|
376
|
-
echo $$ > "${lock_file}"
|
|
508
|
+
echo "$$ $(date +%s)" > "${lock_file}"
|
|
509
|
+
return 0
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
# Check if the lock holder process is genuinely the one that wrote the lock.
|
|
513
|
+
# Guards against PID reuse: if the process started after the lock was created,
|
|
514
|
+
# it's a different process that reused the same PID.
|
|
515
|
+
_is_lock_holder_alive() {
|
|
516
|
+
local pid="${1}" lock_ts="${2:-}"
|
|
517
|
+
|
|
518
|
+
# No timestamp in lock file (old format) — fall back to simple PID check
|
|
519
|
+
if [ -z "${lock_ts}" ]; then
|
|
520
|
+
return 0
|
|
521
|
+
fi
|
|
522
|
+
|
|
523
|
+
# On Linux, check /proc/<pid>/stat for process start time
|
|
524
|
+
if [ -f "/proc/${pid}/stat" ]; then
|
|
525
|
+
local stat_content boot_time_secs start_ticks clk_tck proc_start_secs
|
|
526
|
+
stat_content=$(cat "/proc/${pid}/stat" 2>/dev/null) || return 0
|
|
527
|
+
# Field 22 is starttime (in clock ticks since boot)
|
|
528
|
+
start_ticks=$(echo "${stat_content}" | awk '{print $22}')
|
|
529
|
+
clk_tck=$(getconf CLK_TCK 2>/dev/null || echo 100)
|
|
530
|
+
boot_time_secs=$(awk '/^btime/{print $2}' /proc/stat 2>/dev/null) || return 0
|
|
531
|
+
proc_start_secs=$(( boot_time_secs + start_ticks / clk_tck ))
|
|
532
|
+
|
|
533
|
+
# If the process started more than 2 seconds after the lock was written, PID was reused
|
|
534
|
+
if [ "${proc_start_secs}" -gt "$(( lock_ts + 2 ))" ]; then
|
|
535
|
+
return 1
|
|
536
|
+
fi
|
|
537
|
+
fi
|
|
538
|
+
|
|
377
539
|
return 0
|
|
378
540
|
}
|
|
379
541
|
|
|
@@ -802,6 +964,19 @@ check_rate_limited() {
|
|
|
802
964
|
fi
|
|
803
965
|
}
|
|
804
966
|
|
|
967
|
+
# Detect transient API network errors (e.g. "Network error" in a 400 response).
|
|
968
|
+
# Usage: check_network_error <log_file> [start_line]
|
|
969
|
+
# Returns 0 if a network error was detected, 1 otherwise.
|
|
970
|
+
check_network_error() {
|
|
971
|
+
local log_file="${1:?log_file required}"
|
|
972
|
+
local start_line="${2:-0}"
|
|
973
|
+
if [ "${start_line}" -gt 0 ] 2>/dev/null; then
|
|
974
|
+
tail -n "+$((start_line + 1))" "${log_file}" 2>/dev/null | grep -qi "Network error"
|
|
975
|
+
else
|
|
976
|
+
tail -20 "${log_file}" 2>/dev/null | grep -qi "Network error"
|
|
977
|
+
fi
|
|
978
|
+
}
|
|
979
|
+
|
|
805
980
|
# Detect context window exhaustion from Claude API logs.
|
|
806
981
|
# Usage: check_context_exhausted <log_file> [start_line]
|
|
807
982
|
# Returns 0 if context exhausted, 1 otherwise.
|
|
@@ -1105,7 +1280,7 @@ claim_or_enqueue() {
|
|
|
1105
1280
|
}
|
|
1106
1281
|
|
|
1107
1282
|
local claim_id
|
|
1108
|
-
if claim_id=$("${cli_bin}" queue claim "${script_type}" "${project_dir}" --provider-key "${provider_key}" 2>/dev/null); then
|
|
1283
|
+
if claim_id=$("${cli_bin}" queue claim "${script_type}" "${project_dir}" --provider-key "${provider_key}" --pid $$ 2>/dev/null); then
|
|
1109
1284
|
NW_QUEUE_ENTRY_ID="${claim_id}"
|
|
1110
1285
|
export NW_QUEUE_ENTRY_ID
|
|
1111
1286
|
arm_global_queue_cleanup
|
|
@@ -187,12 +187,12 @@ fi
|
|
|
187
187
|
kill -TERM $$ 2>/dev/null || true
|
|
188
188
|
) &
|
|
189
189
|
WATCHDOG_PID=$!
|
|
190
|
-
|
|
190
|
+
append_exit_trap "kill ${WATCHDOG_PID} 2>/dev/null || true"
|
|
191
191
|
|
|
192
192
|
# Discover open PRs sorted by creation date (oldest first = FIFO)
|
|
193
193
|
log "INFO: Scanning open PRs..."
|
|
194
194
|
PR_LIST_JSON=$(gh pr list --state open \
|
|
195
|
-
--json number,headRefName,createdAt,isDraft \
|
|
195
|
+
--json number,headRefName,createdAt,isDraft,labels \
|
|
196
196
|
--jq 'sort_by(.createdAt)' \
|
|
197
197
|
2>/dev/null || echo "[]")
|
|
198
198
|
|
|
@@ -211,6 +211,7 @@ while IFS= read -r pr_json; do
|
|
|
211
211
|
pr_number=$(echo "${pr_json}" | jq -r '.number')
|
|
212
212
|
pr_branch=$(echo "${pr_json}" | jq -r '.headRefName')
|
|
213
213
|
is_draft=$(echo "${pr_json}" | jq -r '.isDraft')
|
|
214
|
+
pr_labels=$(echo "${pr_json}" | jq -r '[.labels[]?.name] | join(",")')
|
|
214
215
|
|
|
215
216
|
# Skip drafts
|
|
216
217
|
if [ "${is_draft}" = "true" ]; then
|
|
@@ -218,6 +219,11 @@ while IFS= read -r pr_json; do
|
|
|
218
219
|
continue
|
|
219
220
|
fi
|
|
220
221
|
|
|
222
|
+
if csv_has_label "${pr_labels:-}" "${NW_EXECUTOR_PARTIAL_LABEL}"; then
|
|
223
|
+
log "INFO: PR #${pr_number} (${pr_branch}): Skipping partial executor PR"
|
|
224
|
+
continue
|
|
225
|
+
fi
|
|
226
|
+
|
|
221
227
|
# Check branch pattern filter
|
|
222
228
|
if ! matches_branch_patterns "${pr_branch}"; then
|
|
223
229
|
log "DEBUG: PR #${pr_number} (${pr_branch}): Branch pattern mismatch, skipping"
|
|
@@ -167,6 +167,8 @@ process_pr() {
|
|
|
167
167
|
log "INFO: Invoking AI to resolve conflicts for PR #${pr_number}" "branch=${pr_branch}"
|
|
168
168
|
|
|
169
169
|
local ai_prompt
|
|
170
|
+
local force_push_cmd
|
|
171
|
+
force_push_cmd=$(project_git_push_command "${pr_branch}" "force-with-lease")
|
|
170
172
|
ai_prompt="You are working in a git repository at ${worktree_dir}. \
|
|
171
173
|
Branch '${pr_branch}' has merge conflicts with '${default_branch}'. \
|
|
172
174
|
Please resolve the merge conflicts by: \
|
|
@@ -174,7 +176,7 @@ Please resolve the merge conflicts by: \
|
|
|
174
176
|
2) Resolving any conflict markers in the affected files \
|
|
175
177
|
3) Staging resolved files with: git add <files> \
|
|
176
178
|
4) Continuing the rebase with: git rebase --continue \
|
|
177
|
-
5) Finally pushing with:
|
|
179
|
+
5) Finally pushing with: ${force_push_cmd} \
|
|
178
180
|
Work exclusively in the directory: ${worktree_dir}"
|
|
179
181
|
|
|
180
182
|
local -a cmd_parts
|
|
@@ -203,7 +205,7 @@ Work exclusively in the directory: ${worktree_dir}"
|
|
|
203
205
|
return 1
|
|
204
206
|
fi
|
|
205
207
|
# Push the rebased branch (AI may have already pushed; --force-with-lease is idempotent)
|
|
206
|
-
|
|
208
|
+
git_push_for_project "${worktree_dir}" --force-with-lease origin "${pr_branch}" >> "${LOG_FILE}" 2>&1 || {
|
|
207
209
|
log "WARN: Push after rebase failed for PR #${pr_number}" "branch=${pr_branch}"
|
|
208
210
|
}
|
|
209
211
|
fi
|
|
@@ -224,13 +226,15 @@ Work exclusively in the directory: ${worktree_dir}"
|
|
|
224
226
|
fi
|
|
225
227
|
|
|
226
228
|
local review_prompt
|
|
229
|
+
local review_push_cmd
|
|
230
|
+
review_push_cmd=$(project_git_push_command "${pr_branch}")
|
|
227
231
|
review_prompt="You are working in the git repository at ${review_workdir}. \
|
|
228
232
|
PR #${pr_number} on branch '${pr_branch}' has unresolved review comments requesting changes. \
|
|
229
233
|
Please: \
|
|
230
234
|
1) Run 'gh pr view ${pr_number} --comments' to read the review comments \
|
|
231
235
|
2) Implement the requested changes \
|
|
232
236
|
3) Commit the changes with a descriptive message \
|
|
233
|
-
4) Push with:
|
|
237
|
+
4) Push with: ${review_push_cmd} \
|
|
234
238
|
Work in the directory: ${review_workdir}"
|
|
235
239
|
|
|
236
240
|
local -a review_cmd_parts
|
|
@@ -631,6 +631,11 @@ while IFS=$'\t' read -r pr_number pr_branch pr_labels; do
|
|
|
631
631
|
continue
|
|
632
632
|
fi
|
|
633
633
|
|
|
634
|
+
if csv_has_label "${pr_labels:-}" "${NW_EXECUTOR_PARTIAL_LABEL}"; then
|
|
635
|
+
log "INFO: PR #${pr_number} (${pr_branch}) is labeled ${NW_EXECUTOR_PARTIAL_LABEL}; waiting for executor to finish"
|
|
636
|
+
continue
|
|
637
|
+
fi
|
|
638
|
+
|
|
634
639
|
# Merge-conflict signal: this PR needs action even if CI and score look fine.
|
|
635
640
|
MERGE_STATE=$(gh pr view "${pr_number}" --json mergeStateStatus --jq '.mergeStateStatus' 2>/dev/null || echo "")
|
|
636
641
|
if [ "${MERGE_STATE}" = "DIRTY" ] || [ "${MERGE_STATE}" = "CONFLICTING" ]; then
|
|
@@ -426,6 +426,11 @@ while IFS=$'\t' read -r pr_number pr_branch pr_title pr_labels; do
|
|
|
426
426
|
continue
|
|
427
427
|
fi
|
|
428
428
|
|
|
429
|
+
if csv_has_label "${pr_labels:-}" "${NW_EXECUTOR_PARTIAL_LABEL}"; then
|
|
430
|
+
log "SKIP-QA: PR #${pr_number} (${pr_branch}) is labeled ${NW_EXECUTOR_PARTIAL_LABEL}"
|
|
431
|
+
continue
|
|
432
|
+
fi
|
|
433
|
+
|
|
429
434
|
# Skip PRs with the skip label
|
|
430
435
|
if echo "${pr_labels}" | grep -q "${SKIP_LABEL}"; then
|
|
431
436
|
log "SKIP-QA: PR #${pr_number} (${pr_branch}) has '${SKIP_LABEL}' label"
|
|
@@ -75,7 +75,7 @@ cleanup_on_exit() {
|
|
|
75
75
|
rm -f "${LOCK_FILE}"
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
append_exit_trap "cleanup_on_exit"
|
|
79
79
|
|
|
80
80
|
log "START: Running roadmap slicer for ${PROJECT_DIR}"
|
|
81
81
|
send_telegram_status_message "📋 Night Watch Planner: started" "Project: ${PROJECT_NAME}
|