@jonit-dev/night-watch-cli 1.7.55 → 1.7.57
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 +487 -320
- package/dist/commands/update.d.ts +2 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +4 -1
- package/dist/commands/update.js.map +1 -1
- package/dist/scripts/night-watch-helpers.sh +22 -8
- package/dist/scripts/night-watch-pr-reviewer-cron.sh +123 -18
- package/dist/scripts/night-watch-qa-cron.sh +13 -8
- package/dist/web/assets/index-BqwbXsHS.js +365 -0
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
|
@@ -7,13 +7,14 @@ export declare const DEFAULT_GLOBAL_SPEC = "@jonit-dev/night-watch-cli@latest";
|
|
|
7
7
|
export interface IUpdateOptions {
|
|
8
8
|
projects?: string;
|
|
9
9
|
globalSpec: string;
|
|
10
|
-
|
|
10
|
+
global?: boolean;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* Parse project directories from a comma-separated CLI option.
|
|
14
14
|
* Defaults to current working directory when option is omitted.
|
|
15
15
|
*/
|
|
16
16
|
export declare function parseProjectDirs(projects: string | undefined, cwd: string): string[];
|
|
17
|
+
export declare function shouldInstallGlobal(options: Pick<IUpdateOptions, 'global'>): boolean;
|
|
17
18
|
/**
|
|
18
19
|
* Register update command.
|
|
19
20
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,mBAAmB,sCAAsC,CAAC;AAEvE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,mBAAmB,sCAAsC,CAAC;AAEvE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAYpF;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,GAAG,OAAO,CAEpF;AAgCD;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsCpD"}
|
package/dist/commands/update.js
CHANGED
|
@@ -22,6 +22,9 @@ export function parseProjectDirs(projects, cwd) {
|
|
|
22
22
|
.map((entry) => path.resolve(cwd, entry));
|
|
23
23
|
return Array.from(new Set(dirs));
|
|
24
24
|
}
|
|
25
|
+
export function shouldInstallGlobal(options) {
|
|
26
|
+
return options.global !== false;
|
|
27
|
+
}
|
|
25
28
|
function runCommand(command, args, cwd) {
|
|
26
29
|
const result = spawnSync(command, args, {
|
|
27
30
|
cwd,
|
|
@@ -60,7 +63,7 @@ export function updateCommand(program) {
|
|
|
60
63
|
try {
|
|
61
64
|
const cwd = process.cwd();
|
|
62
65
|
const projectDirs = parseProjectDirs(options.projects, cwd);
|
|
63
|
-
if (
|
|
66
|
+
if (shouldInstallGlobal(options)) {
|
|
64
67
|
dim(`Updating global install: npm install -g ${options.globalSpec}`);
|
|
65
68
|
runCommand('npm', ['install', '-g', options.globalSpec]);
|
|
66
69
|
success('Global CLI update completed.');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
|
|
@@ -112,6 +112,8 @@ prefer_bundled_prompt_if_legacy_command() {
|
|
|
112
112
|
local script_dir=""
|
|
113
113
|
local bundled_prompt_path=""
|
|
114
114
|
local rel_path=""
|
|
115
|
+
local first_content_line=""
|
|
116
|
+
local looks_like_wrapper=1
|
|
115
117
|
|
|
116
118
|
if [ -n "${SCRIPT_DIR:-}" ]; then
|
|
117
119
|
script_dir="${SCRIPT_DIR}"
|
|
@@ -121,15 +123,27 @@ prefer_bundled_prompt_if_legacy_command() {
|
|
|
121
123
|
|
|
122
124
|
bundled_prompt_path="${script_dir}/../templates/${bundled_prompt_name}"
|
|
123
125
|
|
|
124
|
-
#
|
|
125
|
-
# rather than the full automation prompt.
|
|
126
|
-
if [
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
# Some instruction files only contain slash-command wrappers (e.g. "/night-watch-qa")
|
|
127
|
+
# rather than the full automation prompt. If detected, force bundled templates.
|
|
128
|
+
if [ -f "${bundled_prompt_path}" ] && [ -f "${resolved_prompt_path}" ]; then
|
|
129
|
+
first_content_line=$(
|
|
130
|
+
awk 'NF {print; exit}' "${resolved_prompt_path}" 2>/dev/null \
|
|
131
|
+
| sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'
|
|
132
|
+
)
|
|
133
|
+
if printf '%s' "${first_content_line}" | grep -Eqi '^/[a-z0-9._/-]+'; then
|
|
134
|
+
looks_like_wrapper=0
|
|
135
|
+
fi
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
if [ "${looks_like_wrapper}" -eq 0 ]; then
|
|
139
|
+
if [[ "${resolved_prompt_path}" == "${project_root}/"* ]]; then
|
|
140
|
+
rel_path="${resolved_prompt_path#${project_root}/}"
|
|
141
|
+
else
|
|
142
|
+
rel_path="${resolved_prompt_path}"
|
|
132
143
|
fi
|
|
144
|
+
log "WARN: Prompt ${rel_path} looks like a slash-command wrapper; using bundled template ${bundled_prompt_name}"
|
|
145
|
+
printf "%s" "${bundled_prompt_path}"
|
|
146
|
+
return 0
|
|
133
147
|
fi
|
|
134
148
|
|
|
135
149
|
printf "%s" "${resolved_prompt_path}"
|
|
@@ -172,6 +172,17 @@ append_csv() {
|
|
|
172
172
|
fi
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
provider_output_looks_invalid() {
|
|
176
|
+
local from_line="${1:-0}"
|
|
177
|
+
if [ ! -f "${LOG_FILE}" ]; then
|
|
178
|
+
return 1
|
|
179
|
+
fi
|
|
180
|
+
|
|
181
|
+
tail -n "+$((from_line + 1))" "${LOG_FILE}" 2>/dev/null \
|
|
182
|
+
| grep -Eqi \
|
|
183
|
+
'Unknown skill:|session is in a broken state|working directory .* no longer exists|Path ".*" does not exist|Please restart this session|failed to start LSP server plugin|spawn .* ENOENT'
|
|
184
|
+
}
|
|
185
|
+
|
|
175
186
|
truncate_for_prompt() {
|
|
176
187
|
local text="${1:-}"
|
|
177
188
|
local limit="${2:-7000}"
|
|
@@ -830,9 +841,10 @@ if [ -z "${TARGET_PR}" ] && [ "${WORKER_MODE}" != "1" ] && [ "${PARALLEL_ENABLED
|
|
|
830
841
|
exit 0
|
|
831
842
|
fi
|
|
832
843
|
|
|
833
|
-
|
|
844
|
+
REVIEW_RUN_TOKEN="${PROJECT_RUNTIME_KEY}-$$"
|
|
845
|
+
REVIEW_WORKTREE_BASENAME="${PROJECT_NAME}-nw-review-runner-${REVIEW_RUN_TOKEN}"
|
|
834
846
|
if [ -n "${TARGET_PR}" ]; then
|
|
835
|
-
REVIEW_WORKTREE_BASENAME="${
|
|
847
|
+
REVIEW_WORKTREE_BASENAME="${PROJECT_NAME}-nw-review-runner-pr-${TARGET_PR}-${REVIEW_RUN_TOKEN}"
|
|
836
848
|
fi
|
|
837
849
|
REVIEW_WORKTREE_DIR="$(dirname "${PROJECT_DIR}")/${REVIEW_WORKTREE_BASENAME}"
|
|
838
850
|
|
|
@@ -934,6 +946,51 @@ if [ -n "${TARGET_PR}" ]; then
|
|
|
934
946
|
fi
|
|
935
947
|
RUN_STARTED_AT=$(date +%s)
|
|
936
948
|
|
|
949
|
+
remaining_runtime_budget() {
|
|
950
|
+
local now_ts
|
|
951
|
+
local elapsed
|
|
952
|
+
local remaining
|
|
953
|
+
|
|
954
|
+
now_ts=$(date +%s)
|
|
955
|
+
elapsed=$((now_ts - RUN_STARTED_AT))
|
|
956
|
+
remaining=$((MAX_RUNTIME - elapsed))
|
|
957
|
+
printf "%s" "${remaining}"
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
sleep_with_runtime_budget() {
|
|
961
|
+
local requested_sleep="${1:-0}"
|
|
962
|
+
local remaining
|
|
963
|
+
local sleep_for
|
|
964
|
+
|
|
965
|
+
if ! [[ "${requested_sleep}" =~ ^[0-9]+$ ]]; then
|
|
966
|
+
requested_sleep=0
|
|
967
|
+
fi
|
|
968
|
+
if [ "${requested_sleep}" -le 0 ]; then
|
|
969
|
+
return 0
|
|
970
|
+
fi
|
|
971
|
+
|
|
972
|
+
if [ -z "${TARGET_PR}" ]; then
|
|
973
|
+
sleep "${requested_sleep}"
|
|
974
|
+
return 0
|
|
975
|
+
fi
|
|
976
|
+
|
|
977
|
+
remaining=$(remaining_runtime_budget)
|
|
978
|
+
if [ "${remaining}" -le 0 ]; then
|
|
979
|
+
return 124
|
|
980
|
+
fi
|
|
981
|
+
|
|
982
|
+
sleep_for="${requested_sleep}"
|
|
983
|
+
if [ "${sleep_for}" -gt "${remaining}" ]; then
|
|
984
|
+
sleep_for="${remaining}"
|
|
985
|
+
fi
|
|
986
|
+
if [ "${sleep_for}" -le 0 ]; then
|
|
987
|
+
return 124
|
|
988
|
+
fi
|
|
989
|
+
|
|
990
|
+
sleep "${sleep_for}"
|
|
991
|
+
return 0
|
|
992
|
+
}
|
|
993
|
+
|
|
937
994
|
for ATTEMPT in $(seq 1 "${TOTAL_ATTEMPTS}"); do
|
|
938
995
|
ATTEMPTS_MADE="${ATTEMPT}"
|
|
939
996
|
|
|
@@ -956,6 +1013,17 @@ for ATTEMPT in $(seq 1 "${TOTAL_ATTEMPTS}"); do
|
|
|
956
1013
|
fi
|
|
957
1014
|
fi
|
|
958
1015
|
|
|
1016
|
+
# Recreate worktree if it was removed unexpectedly between attempts.
|
|
1017
|
+
if [ ! -d "${REVIEW_WORKTREE_DIR}" ] || ! git -C "${REVIEW_WORKTREE_DIR}" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
1018
|
+
log "RETRY: Reviewer worktree missing for attempt ${ATTEMPT}; recreating ${REVIEW_WORKTREE_DIR}"
|
|
1019
|
+
cleanup_reviewer_worktrees "${REVIEW_WORKTREE_BASENAME}"
|
|
1020
|
+
if ! prepare_detached_worktree "${PROJECT_DIR}" "${REVIEW_WORKTREE_DIR}" "${DEFAULT_BRANCH}" "${LOG_FILE}"; then
|
|
1021
|
+
EXIT_CODE=1
|
|
1022
|
+
log "RETRY: Unable to recreate reviewer worktree; aborting"
|
|
1023
|
+
break
|
|
1024
|
+
fi
|
|
1025
|
+
fi
|
|
1026
|
+
|
|
959
1027
|
log "RETRY: Starting attempt ${ATTEMPT}/${TOTAL_ATTEMPTS} (timeout: ${ATTEMPT_TIMEOUT}s)"
|
|
960
1028
|
LOG_LINE_BEFORE=$(wc -l < "${LOG_FILE}" 2>/dev/null || echo 0)
|
|
961
1029
|
REVIEWER_PROMPT="${REVIEWER_PROMPT_BASE}${TARGET_SCOPE_PROMPT}${PRD_CONTEXT_PROMPT}"
|
|
@@ -994,23 +1062,56 @@ for ATTEMPT in $(seq 1 "${TOTAL_ATTEMPTS}"); do
|
|
|
994
1062
|
|
|
995
1063
|
# If provider failed (non-zero exit), check for rate limit before giving up
|
|
996
1064
|
if [ "${EXIT_CODE}" -ne 0 ]; then
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1065
|
+
if [ "${EXIT_CODE}" -ne 124 ] && \
|
|
1066
|
+
check_rate_limited "${LOG_FILE}" "${LOG_LINE_BEFORE}" && \
|
|
1067
|
+
[ -n "${TARGET_PR}" ] && \
|
|
1068
|
+
[ "${ATTEMPT}" -lt "${TOTAL_ATTEMPTS}" ]; then
|
|
1069
|
+
log "RATE-LIMITED: 429 detected for PR #${TARGET_PR} (attempt ${ATTEMPT}/${TOTAL_ATTEMPTS}), retrying in 120s..."
|
|
1070
|
+
if ! sleep_with_runtime_budget 120; then
|
|
1071
|
+
EXIT_CODE=124
|
|
1072
|
+
log "RETRY: Runtime budget exhausted while waiting to retry PR #${TARGET_PR}"
|
|
1073
|
+
break
|
|
1074
|
+
fi
|
|
1075
|
+
continue
|
|
1076
|
+
fi
|
|
1005
1077
|
log "RETRY: Provider exited with code ${EXIT_CODE}, not retrying"
|
|
1006
1078
|
break
|
|
1007
1079
|
fi
|
|
1008
1080
|
|
|
1081
|
+
if provider_output_looks_invalid "${LOG_LINE_BEFORE}"; then
|
|
1082
|
+
log "RETRY: Invalid provider output detected for attempt ${ATTEMPT} (broken session/wrapper output)"
|
|
1083
|
+
if [ "${ATTEMPT}" -lt "${TOTAL_ATTEMPTS}" ]; then
|
|
1084
|
+
if ! sleep_with_runtime_budget "${REVIEWER_RETRY_DELAY}"; then
|
|
1085
|
+
EXIT_CODE=124
|
|
1086
|
+
log "RETRY: Runtime budget exhausted before retrying invalid provider output"
|
|
1087
|
+
break
|
|
1088
|
+
fi
|
|
1089
|
+
continue
|
|
1090
|
+
fi
|
|
1091
|
+
EXIT_CODE=1
|
|
1092
|
+
break
|
|
1093
|
+
fi
|
|
1094
|
+
|
|
1009
1095
|
# Re-check score for the target PR (only in targeted mode)
|
|
1010
1096
|
if [ -n "${TARGET_PR}" ]; then
|
|
1011
1097
|
CURRENT_SCORE=$(get_pr_score "${TARGET_PR}")
|
|
1012
1098
|
if [ -z "${CURRENT_SCORE}" ]; then
|
|
1013
|
-
|
|
1099
|
+
CURRENT_FAILED_CHECKS=$(get_pr_failed_ci_summary "${TARGET_PR}")
|
|
1100
|
+
if [ -z "${CURRENT_FAILED_CHECKS}" ]; then
|
|
1101
|
+
log "RETRY: No review score for PR #${TARGET_PR}, but CI shows no failing checks; treating as successful."
|
|
1102
|
+
break
|
|
1103
|
+
fi
|
|
1104
|
+
if [ "${ATTEMPT}" -lt "${TOTAL_ATTEMPTS}" ]; then
|
|
1105
|
+
log "RETRY: No review score found for PR #${TARGET_PR} after attempt ${ATTEMPT}; retrying in ${REVIEWER_RETRY_DELAY}s..."
|
|
1106
|
+
if ! sleep_with_runtime_budget "${REVIEWER_RETRY_DELAY}"; then
|
|
1107
|
+
EXIT_CODE=124
|
|
1108
|
+
log "RETRY: Runtime budget exhausted before retrying missing score for PR #${TARGET_PR}"
|
|
1109
|
+
break
|
|
1110
|
+
fi
|
|
1111
|
+
continue
|
|
1112
|
+
fi
|
|
1113
|
+
log "RETRY: No review score found for PR #${TARGET_PR} after ${TOTAL_ATTEMPTS} attempts; failing run."
|
|
1114
|
+
EXIT_CODE=1
|
|
1014
1115
|
break
|
|
1015
1116
|
fi
|
|
1016
1117
|
|
|
@@ -1018,13 +1119,17 @@ for ATTEMPT in $(seq 1 "${TOTAL_ATTEMPTS}"); do
|
|
|
1018
1119
|
if [ "${CURRENT_SCORE}" -ge "${MIN_REVIEW_SCORE}" ]; then
|
|
1019
1120
|
log "RETRY: PR #${TARGET_PR} now scores ${CURRENT_SCORE}/100 (>= ${MIN_REVIEW_SCORE}) after attempt ${ATTEMPT}"
|
|
1020
1121
|
break
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1122
|
+
fi
|
|
1123
|
+
if [ "${ATTEMPT}" -lt "${TOTAL_ATTEMPTS}" ]; then
|
|
1124
|
+
log "RETRY: PR #${TARGET_PR} scores ${CURRENT_SCORE:-unknown}/100 after attempt ${ATTEMPT}/${TOTAL_ATTEMPTS}, retrying in ${REVIEWER_RETRY_DELAY}s..."
|
|
1125
|
+
if ! sleep_with_runtime_budget "${REVIEWER_RETRY_DELAY}"; then
|
|
1126
|
+
EXIT_CODE=124
|
|
1127
|
+
log "RETRY: Runtime budget exhausted before retrying low score for PR #${TARGET_PR}"
|
|
1128
|
+
break
|
|
1129
|
+
fi
|
|
1130
|
+
else
|
|
1131
|
+
log "RETRY: PR #${TARGET_PR} still at ${CURRENT_SCORE:-unknown}/100 after ${TOTAL_ATTEMPTS} attempts - giving up"
|
|
1132
|
+
gh pr edit "${TARGET_PR}" --add-label "needs-human-review" 2>/dev/null || true
|
|
1028
1133
|
fi
|
|
1029
1134
|
else
|
|
1030
1135
|
# Non-targeted mode: no retry (reviewer handles all PRs in one shot)
|
|
@@ -514,14 +514,19 @@ Action: generating QA tests and evidence."
|
|
|
514
514
|
fi
|
|
515
515
|
|
|
516
516
|
log "QA: Checking out PR #${pr_num} in worktree"
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
517
|
+
# Prefer detached checkout to avoid "branch already used by worktree" failures
|
|
518
|
+
# when the same branch is already checked out in another local worktree.
|
|
519
|
+
if ! (cd "${QA_WORKTREE_DIR}" && gh pr checkout "${pr_num}" --detach >> "${LOG_FILE}" 2>&1); then
|
|
520
|
+
log "WARN: Detached checkout failed for PR #${pr_num}; retrying with standard checkout"
|
|
521
|
+
if ! (cd "${QA_WORKTREE_DIR}" && gh pr checkout "${pr_num}" >> "${LOG_FILE}" 2>&1); then
|
|
522
|
+
log "WARN: Failed to checkout PR #${pr_num}, skipping"
|
|
523
|
+
FAILED_AUTOMATION_PRS_CSV=$(append_csv "${FAILED_AUTOMATION_PRS_CSV}" "#${pr_num}")
|
|
524
|
+
FAILED_PR="#${pr_num}"
|
|
525
|
+
FAILED_REASON="checkout_failed"
|
|
526
|
+
EXIT_CODE=1
|
|
527
|
+
cleanup_worktrees "${PROJECT_DIR}"
|
|
528
|
+
continue
|
|
529
|
+
fi
|
|
525
530
|
fi
|
|
526
531
|
|
|
527
532
|
QA_PROMPT_PATH=$(resolve_instruction_path_with_fallback "${QA_WORKTREE_DIR}" "qa.md" "night-watch-qa.md" || true)
|