@jonit-dev/night-watch-cli 1.8.12-beta.0 → 1.8.12-beta.10
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.d.ts +3 -0
- package/dist/cli.js +3281 -651
- package/dist/cli.js.map +1 -0
- package/dist/commands/agent.d.ts +12 -0
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +307 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/analytics.d.ts +14 -0
- package/dist/commands/analytics.d.ts.map +1 -1
- package/dist/commands/analytics.js +129 -0
- package/dist/commands/analytics.js.map +1 -0
- package/dist/commands/audit.d.ts +19 -0
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +189 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/board.d.ts +9 -0
- package/dist/commands/board.js +702 -0
- package/dist/commands/board.js.map +1 -0
- package/dist/commands/cancel.d.ts +46 -0
- package/dist/commands/cancel.js +239 -0
- package/dist/commands/cancel.js.map +1 -0
- package/dist/commands/cron.d.ts +8 -0
- package/dist/commands/cron.js +134 -0
- package/dist/commands/cron.js.map +1 -0
- package/dist/commands/dashboard/tab-actions.d.ts +10 -0
- package/dist/commands/dashboard/tab-actions.js +247 -0
- package/dist/commands/dashboard/tab-actions.js.map +1 -0
- package/dist/commands/dashboard/tab-config.d.ts +21 -0
- package/dist/commands/dashboard/tab-config.js +874 -0
- package/dist/commands/dashboard/tab-config.js.map +1 -0
- package/dist/commands/dashboard/tab-logs.d.ts +10 -0
- package/dist/commands/dashboard/tab-logs.js +202 -0
- package/dist/commands/dashboard/tab-logs.js.map +1 -0
- package/dist/commands/dashboard/tab-schedules.d.ts +21 -0
- package/dist/commands/dashboard/tab-schedules.js +320 -0
- package/dist/commands/dashboard/tab-schedules.js.map +1 -0
- package/dist/commands/dashboard/tab-status.d.ts +32 -0
- package/dist/commands/dashboard/tab-status.js +424 -0
- package/dist/commands/dashboard/tab-status.js.map +1 -0
- package/dist/commands/dashboard/types.d.ts +42 -0
- package/dist/commands/dashboard/types.js +5 -0
- package/dist/commands/dashboard/types.js.map +1 -0
- package/dist/commands/dashboard.d.ts +11 -0
- package/dist/commands/dashboard.js +242 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/doctor.d.ts +16 -0
- package/dist/commands/doctor.js +195 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/history.d.ts +7 -0
- package/dist/commands/history.js +49 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/init.d.ts +45 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +13 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install.d.ts +65 -0
- package/dist/commands/install.js +405 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/logs.d.ts +15 -0
- package/dist/commands/logs.js +155 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/merge.d.ts +26 -0
- package/dist/commands/merge.d.ts.map +1 -1
- package/dist/commands/merge.js +186 -0
- package/dist/commands/merge.js.map +1 -0
- package/dist/commands/notify.d.ts +7 -0
- package/dist/commands/notify.js +43 -0
- package/dist/commands/notify.js.map +1 -0
- package/dist/commands/plan.d.ts +19 -0
- package/dist/commands/plan.d.ts.map +1 -1
- package/dist/commands/plan.js +133 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/prd-state.d.ts +12 -0
- package/dist/commands/prd-state.js +47 -0
- package/dist/commands/prd-state.js.map +1 -0
- package/dist/commands/prd.d.ts +18 -0
- package/dist/commands/prd.js +363 -0
- package/dist/commands/prd.js.map +1 -0
- package/dist/commands/prds.d.ts +13 -0
- package/dist/commands/prds.js +194 -0
- package/dist/commands/prds.js.map +1 -0
- package/dist/commands/prs.d.ts +14 -0
- package/dist/commands/prs.js +104 -0
- package/dist/commands/prs.js.map +1 -0
- package/dist/commands/qa.d.ts +34 -0
- package/dist/commands/qa.d.ts.map +1 -1
- package/dist/commands/qa.js +238 -0
- package/dist/commands/qa.js.map +1 -0
- package/dist/commands/queue.d.ts +8 -0
- package/dist/commands/queue.d.ts.map +1 -1
- package/dist/commands/queue.js +398 -0
- package/dist/commands/queue.js.map +1 -0
- package/dist/commands/resolve.d.ts +26 -0
- package/dist/commands/resolve.d.ts.map +1 -1
- package/dist/commands/resolve.js +212 -0
- package/dist/commands/resolve.js.map +1 -0
- package/dist/commands/retry.d.ts +9 -0
- package/dist/commands/retry.js +71 -0
- package/dist/commands/retry.js.map +1 -0
- package/dist/commands/review.d.ts +79 -0
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +47 -75
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/run.d.ts +88 -0
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +85 -1
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/serve.d.ts +19 -0
- package/dist/commands/serve.js +142 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/shared/env-builder.d.ts +49 -0
- package/dist/commands/shared/env-builder.d.ts.map +1 -1
- package/dist/commands/shared/env-builder.js +152 -0
- package/dist/commands/shared/env-builder.js.map +1 -0
- package/dist/commands/shared/feedback.d.ts +24 -0
- package/dist/commands/shared/feedback.d.ts.map +1 -0
- package/dist/commands/shared/feedback.js +38 -0
- package/dist/commands/shared/feedback.js.map +1 -0
- package/dist/commands/slice.d.ts +35 -0
- package/dist/commands/slice.d.ts.map +1 -1
- package/dist/commands/slice.js +363 -0
- package/dist/commands/slice.js.map +1 -0
- package/dist/commands/state.d.ts +8 -0
- package/dist/commands/state.js +54 -0
- package/dist/commands/state.js.map +1 -0
- package/dist/commands/status.d.ts +14 -0
- package/dist/commands/status.js +297 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/summary.d.ts +14 -0
- package/dist/commands/summary.js +193 -0
- package/dist/commands/summary.js.map +1 -0
- package/dist/commands/uninstall.d.ts +25 -0
- package/dist/commands/uninstall.js +134 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/update.d.ts +22 -0
- package/dist/commands/update.js +90 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/scripts/night-watch-audit-cron.sh +1 -0
- package/dist/scripts/night-watch-cron.sh +186 -23
- package/dist/scripts/night-watch-helpers.sh +65 -2
- package/dist/scripts/night-watch-merger-cron.sh +137 -36
- package/dist/scripts/night-watch-plan-cron.sh +2 -0
- package/dist/scripts/night-watch-pr-resolver-cron.sh +6 -0
- package/dist/scripts/night-watch-pr-reviewer-cron.sh +22 -5
- package/dist/scripts/night-watch-qa-cron.sh +8 -1
- package/dist/scripts/night-watch-slicer-cron.sh +3 -0
- package/dist/templates/night-watch.config.json +21 -20
- package/dist/templates/slicer.md +3 -0
- package/dist/web/assets/index-C-xpWpS8.css +1 -0
- package/dist/web/assets/index-CEYe-290.js +412 -0
- package/dist/web/assets/index-DpvzoXEv.js +442 -0
- package/dist/web/assets/index-DyME41HV.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +3 -1
|
@@ -126,6 +126,7 @@ project_git_push_command() {
|
|
|
126
126
|
NW_EXECUTOR_PARTIAL_LABEL="${NW_EXECUTOR_PARTIAL_LABEL:-nw:partial}"
|
|
127
127
|
NW_EXECUTOR_RESUMABLE_LABEL="${NW_EXECUTOR_RESUMABLE_LABEL:-nw:resumable}"
|
|
128
128
|
NW_EXECUTOR_READY_REVIEW_LABEL="${NW_EXECUTOR_READY_REVIEW_LABEL:-nw:ready-review}"
|
|
129
|
+
NW_PR_RESOLVER_READY_LABEL="${NW_PR_RESOLVER_READY_LABEL:-ready-to-merge}"
|
|
129
130
|
|
|
130
131
|
csv_has_label() {
|
|
131
132
|
local csv="${1:-}"
|
|
@@ -188,7 +189,8 @@ find_executor_resume_pr() {
|
|
|
188
189
|
printf '%s' "${pr_list}" \
|
|
189
190
|
| jq -c \
|
|
190
191
|
--arg primary_prefix "${branch_prefix}/" \
|
|
191
|
-
--arg resumable_label "${NW_EXECUTOR_RESUMABLE_LABEL}"
|
|
192
|
+
--arg resumable_label "${NW_EXECUTOR_RESUMABLE_LABEL}" \
|
|
193
|
+
--arg ready_label "${NW_PR_RESOLVER_READY_LABEL}" '
|
|
192
194
|
[
|
|
193
195
|
.[]
|
|
194
196
|
| select(
|
|
@@ -198,6 +200,7 @@ find_executor_resume_pr() {
|
|
|
198
200
|
)
|
|
199
201
|
| .labelNames = ((.labels // []) | map(.name))
|
|
200
202
|
| select((.labelNames | index($resumable_label)) != null)
|
|
203
|
+
| select((.labelNames | index($ready_label)) == null)
|
|
201
204
|
]
|
|
202
205
|
| sort_by(.createdAt // "")
|
|
203
206
|
| .[0] // empty
|
|
@@ -1243,8 +1246,40 @@ or set primaryFallbackPreset / primaryFallbackModel in night-watch.config.json."
|
|
|
1243
1246
|
|
|
1244
1247
|
# ── Board mode issue discovery ────────────────────────────────────────────────
|
|
1245
1248
|
|
|
1249
|
+
is_audit_board_issue_json() {
|
|
1250
|
+
local issue_json="${1:?issue_json required}"
|
|
1251
|
+
|
|
1252
|
+
printf '%s' "${issue_json}" \
|
|
1253
|
+
| jq -r '[.title // "", .body // ""] | join("\n")' 2>/dev/null \
|
|
1254
|
+
| grep -Eiq '(^|[[:space:]])Audit:|Night Watch audit detected|Report:[[:space:]]+`?logs/audit-report\.md`?|Finding:[[:space:]]+[0-9]+'
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
is_audit_paused_or_disabled() {
|
|
1258
|
+
local cli_bin="${1:?cli_bin required}"
|
|
1259
|
+
local project_dir="${2:?project_dir required}"
|
|
1260
|
+
|
|
1261
|
+
if (cd "${project_dir}" && "${cli_bin}" job is-paused audit >/dev/null 2>&1); then
|
|
1262
|
+
return 0
|
|
1263
|
+
fi
|
|
1264
|
+
|
|
1265
|
+
local audit_enabled
|
|
1266
|
+
audit_enabled=$(
|
|
1267
|
+
cd "${project_dir}" \
|
|
1268
|
+
&& "${cli_bin}" config get audit.enabled 2>/dev/null \
|
|
1269
|
+
| tr '[:upper:]' '[:lower:]' \
|
|
1270
|
+
| sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//'
|
|
1271
|
+
) || true
|
|
1272
|
+
|
|
1273
|
+
if [ "${audit_enabled}" = "false" ]; then
|
|
1274
|
+
return 0
|
|
1275
|
+
fi
|
|
1276
|
+
|
|
1277
|
+
return 1
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1246
1280
|
# Get the next eligible issue from the board provider.
|
|
1247
|
-
# Iterates through Ready issues sorted by priority, skipping
|
|
1281
|
+
# Iterates through Ready issues sorted by priority, skipping audit findings when
|
|
1282
|
+
# audit is disabled/paused and skipping any in cooldown.
|
|
1248
1283
|
# Prints the JSON of the first eligible issue to stdout, or nothing if none found.
|
|
1249
1284
|
# Returns 0 on success, 1 if no Ready issues were returned, 2 if Ready issues
|
|
1250
1285
|
# were found but every candidate was skipped due to cooldown.
|
|
@@ -1292,6 +1327,16 @@ find_eligible_board_issue() {
|
|
|
1292
1327
|
number=$(printf '%s' "${issue}" | jq -r '.number' 2>/dev/null)
|
|
1293
1328
|
title=$(printf '%s' "${issue}" | jq -r '.title // empty' 2>/dev/null)
|
|
1294
1329
|
|
|
1330
|
+
# Skip stale audit findings while the audit job is paused/disabled. Audit
|
|
1331
|
+
# cron/config gates stop new scans, but Ready board issues can outlive them.
|
|
1332
|
+
if [ -n "${project_dir}" ] \
|
|
1333
|
+
&& is_audit_board_issue_json "${issue}" \
|
|
1334
|
+
&& is_audit_paused_or_disabled "${cli_bin}" "${project_dir}"; then
|
|
1335
|
+
log "SKIP-BOARD: Issue #${number} — audit issue skipped because audit is paused or disabled"
|
|
1336
|
+
i=$((i + 1))
|
|
1337
|
+
continue
|
|
1338
|
+
fi
|
|
1339
|
+
|
|
1295
1340
|
# Derive PRD name (same slug format used by the cron script for history keys)
|
|
1296
1341
|
prd_name="${number}-$(printf '%s' "${title}" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9' '-' | sed 's/^-\|-$//g')"
|
|
1297
1342
|
|
|
@@ -1335,6 +1380,22 @@ arm_global_queue_cleanup() {
|
|
|
1335
1380
|
append_exit_trap "__night_watch_queue_cleanup \$?"
|
|
1336
1381
|
}
|
|
1337
1382
|
|
|
1383
|
+
skip_if_job_paused() {
|
|
1384
|
+
local script_type="${1:?script_type required}"
|
|
1385
|
+
local project_dir="${2:?project_dir required}"
|
|
1386
|
+
|
|
1387
|
+
local cli_bin
|
|
1388
|
+
cli_bin=$(resolve_night_watch_cli) || return 0
|
|
1389
|
+
|
|
1390
|
+
if (cd "${project_dir}" && "${cli_bin}" job is-paused "${script_type}" >/dev/null 2>&1); then
|
|
1391
|
+
log "SKIP: ${script_type} is paused in night-watch.config.json"
|
|
1392
|
+
if command -v emit_result >/dev/null 2>&1; then
|
|
1393
|
+
emit_result "skip_paused"
|
|
1394
|
+
fi
|
|
1395
|
+
exit 0
|
|
1396
|
+
fi
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1338
1399
|
# Atomically claim a queue slot or enqueue for later dispatch.
|
|
1339
1400
|
# Uses DB transaction (via `queue claim` CLI) for atomicity — no flock needed.
|
|
1340
1401
|
# Sets NW_QUEUE_ENTRY_ID on success and arms the cleanup trap.
|
|
@@ -1342,6 +1403,8 @@ arm_global_queue_cleanup() {
|
|
|
1342
1403
|
claim_or_enqueue() {
|
|
1343
1404
|
local script_type="${1:?script_type required}"
|
|
1344
1405
|
local project_dir="${2:?project_dir required}"
|
|
1406
|
+
skip_if_job_paused "${script_type}" "${project_dir}"
|
|
1407
|
+
|
|
1345
1408
|
local provider_key
|
|
1346
1409
|
provider_key=$(resolve_provider_key "${project_dir}" "${script_type}")
|
|
1347
1410
|
|
|
@@ -14,6 +14,8 @@ set -euo pipefail
|
|
|
14
14
|
# NW_MERGER_BRANCH_PATTERNS= - Comma-separated branch prefixes (empty = all)
|
|
15
15
|
# NW_MERGER_REBASE_BEFORE_MERGE=1 - Set to 1 to rebase before merging
|
|
16
16
|
# NW_MERGER_MAX_PRS_PER_RUN=0 - Max PRs to merge per run (0 = unlimited)
|
|
17
|
+
# NW_MERGER_CI_MAX_WAIT=300 - Max seconds to wait for checks after rebase
|
|
18
|
+
# NW_MERGER_CI_POLL_INTERVAL=15 - Seconds between check polls after rebase
|
|
17
19
|
# NW_DRY_RUN=0 - Set to 1 for dry-run mode
|
|
18
20
|
|
|
19
21
|
PROJECT_DIR="${1:?Usage: $0 /path/to/project}"
|
|
@@ -26,7 +28,10 @@ MERGE_METHOD="${NW_MERGER_MERGE_METHOD:-squash}"
|
|
|
26
28
|
MIN_REVIEW_SCORE="${NW_MERGER_MIN_REVIEW_SCORE:-80}"
|
|
27
29
|
REBASE_BEFORE_MERGE="${NW_MERGER_REBASE_BEFORE_MERGE:-1}"
|
|
28
30
|
MAX_PRS_PER_RUN="${NW_MERGER_MAX_PRS_PER_RUN:-0}"
|
|
31
|
+
CI_MAX_WAIT="${NW_MERGER_CI_MAX_WAIT:-300}"
|
|
32
|
+
CI_POLL_INTERVAL="${NW_MERGER_CI_POLL_INTERVAL:-15}"
|
|
29
33
|
BRANCH_PATTERNS_RAW="${NW_MERGER_BRANCH_PATTERNS:-}"
|
|
34
|
+
READY_TO_MERGE_LABEL="${NW_PR_RESOLVER_READY_LABEL:-ready-to-merge}"
|
|
30
35
|
SCRIPT_START_TIME=$(date +%s)
|
|
31
36
|
DRY_RUN="${NW_DRY_RUN:-0}"
|
|
32
37
|
PROVIDER_CMD="${NW_PROVIDER_CMD:-claude}"
|
|
@@ -39,6 +44,12 @@ fi
|
|
|
39
44
|
if ! [[ "${MIN_REVIEW_SCORE}" =~ ^[0-9]+$ ]]; then
|
|
40
45
|
MIN_REVIEW_SCORE="80"
|
|
41
46
|
fi
|
|
47
|
+
if ! [[ "${CI_MAX_WAIT}" =~ ^[0-9]+$ ]]; then
|
|
48
|
+
CI_MAX_WAIT="300"
|
|
49
|
+
fi
|
|
50
|
+
if ! [[ "${CI_POLL_INTERVAL}" =~ ^[0-9]+$ ]] || [ "${CI_POLL_INTERVAL}" = "0" ]; then
|
|
51
|
+
CI_POLL_INTERVAL="15"
|
|
52
|
+
fi
|
|
42
53
|
# Clamp merge method to valid values
|
|
43
54
|
case "${MERGE_METHOD}" in
|
|
44
55
|
squash|merge|rebase) ;;
|
|
@@ -55,6 +66,7 @@ PROJECT_RUNTIME_KEY=$(project_runtime_key "${PROJECT_DIR}")
|
|
|
55
66
|
# NOTE: Lock file path must match mergerLockPath() in src/utils/status-data.ts
|
|
56
67
|
LOCK_FILE="/tmp/night-watch-merger-${PROJECT_RUNTIME_KEY}.lock"
|
|
57
68
|
SCRIPT_TYPE="merger"
|
|
69
|
+
skip_if_job_paused "${SCRIPT_TYPE}" "${PROJECT_DIR}"
|
|
58
70
|
|
|
59
71
|
MERGED_PRS=0
|
|
60
72
|
FAILED_PRS=0
|
|
@@ -103,29 +115,83 @@ get_review_score() {
|
|
|
103
115
|
# Look for review score comment from night-watch
|
|
104
116
|
local score
|
|
105
117
|
score=$(gh pr view "${pr_number}" --json comments \
|
|
106
|
-
--jq '[.comments[].body | select(test("
|
|
118
|
+
--jq '[.comments[].body | select(test("score[^0-9]{0,30}[0-9]+/100"; "i")) | capture("(?i)score[^0-9]{0,30}(?<s>[0-9]+)/100") | .s] | last | tonumber // -1' \
|
|
107
119
|
2>/dev/null || echo "-1")
|
|
108
120
|
echo "${score}"
|
|
109
121
|
}
|
|
110
122
|
|
|
111
|
-
#
|
|
112
|
-
|
|
123
|
+
# Get the current head OID for a PR.
|
|
124
|
+
get_pr_head_oid() {
|
|
113
125
|
local pr_number="${1}"
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
return
|
|
126
|
+
gh pr view "${pr_number}" --json headRefOid --jq '.headRefOid // ""' 2>/dev/null || echo ""
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
# Return the CI state for the PR's status rollup on the expected head OID.
|
|
130
|
+
ci_status_for_head() {
|
|
131
|
+
local pr_number="${1}"
|
|
132
|
+
local expected_head="${2:-}"
|
|
133
|
+
local status_json
|
|
134
|
+
|
|
135
|
+
status_json=$(gh pr view "${pr_number}" --json headRefOid,statusCheckRollup 2>/dev/null || echo "")
|
|
136
|
+
if [ -z "${status_json}" ]; then
|
|
137
|
+
echo "unknown"
|
|
138
|
+
return 0
|
|
127
139
|
fi
|
|
128
|
-
|
|
140
|
+
|
|
141
|
+
echo "${status_json}" | jq -r --arg expected_head "${expected_head}" '
|
|
142
|
+
def in_list($values): . as $value | $values | index($value);
|
|
143
|
+
def check_run_failure:
|
|
144
|
+
.__typename == "CheckRun"
|
|
145
|
+
and ((.conclusion // "") | in_list(["FAILURE", "TIMED_OUT", "CANCELLED", "ACTION_REQUIRED", "STALE", "STARTUP_FAILURE"]));
|
|
146
|
+
def status_context_failure:
|
|
147
|
+
.__typename == "StatusContext"
|
|
148
|
+
and ((.state // "") | in_list(["FAILURE", "ERROR"]));
|
|
149
|
+
def check_run_pending:
|
|
150
|
+
.__typename == "CheckRun"
|
|
151
|
+
and ((.status // "") != "COMPLETED" or .conclusion == null);
|
|
152
|
+
def status_context_pending:
|
|
153
|
+
.__typename == "StatusContext"
|
|
154
|
+
and ((.state // "") | in_list(["PENDING", "EXPECTED"]));
|
|
155
|
+
def check_run_nonpassing:
|
|
156
|
+
.__typename == "CheckRun"
|
|
157
|
+
and ((.conclusion // "") | in_list(["SUCCESS", "NEUTRAL", "SKIPPED"]) | not);
|
|
158
|
+
def status_context_nonpassing:
|
|
159
|
+
.__typename == "StatusContext"
|
|
160
|
+
and (.state // "") != "SUCCESS";
|
|
161
|
+
if ($expected_head != "" and (.headRefOid // "") != $expected_head) then
|
|
162
|
+
"head_mismatch"
|
|
163
|
+
elif ((.statusCheckRollup // []) | length) == 0 then
|
|
164
|
+
"absent"
|
|
165
|
+
elif any((.statusCheckRollup // [])[]; check_run_failure or status_context_failure) then
|
|
166
|
+
"failed"
|
|
167
|
+
elif any((.statusCheckRollup // [])[]; check_run_pending or status_context_pending) then
|
|
168
|
+
"pending"
|
|
169
|
+
elif any((.statusCheckRollup // [])[]; check_run_nonpassing or status_context_nonpassing) then
|
|
170
|
+
"failed"
|
|
171
|
+
else
|
|
172
|
+
"passing"
|
|
173
|
+
end
|
|
174
|
+
' 2>/dev/null || echo "unknown"
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
wait_for_ci_passing_on_head() {
|
|
178
|
+
local pr_number="${1}"
|
|
179
|
+
local expected_head="${2}"
|
|
180
|
+
local ci_waited=0
|
|
181
|
+
LAST_CI_STATUS="unknown"
|
|
182
|
+
|
|
183
|
+
while [ "${ci_waited}" -lt "${CI_MAX_WAIT}" ]; do
|
|
184
|
+
LAST_CI_STATUS=$(ci_status_for_head "${pr_number}" "${expected_head}")
|
|
185
|
+
if [ "${LAST_CI_STATUS}" = "passing" ]; then
|
|
186
|
+
return 0
|
|
187
|
+
fi
|
|
188
|
+
log "INFO: PR #${pr_number}: Waiting for fresh CI on head ${expected_head} (${LAST_CI_STATUS}, ${ci_waited}s/${CI_MAX_WAIT}s)..."
|
|
189
|
+
sleep "${CI_POLL_INTERVAL}"
|
|
190
|
+
ci_waited=$((ci_waited + CI_POLL_INTERVAL))
|
|
191
|
+
done
|
|
192
|
+
|
|
193
|
+
LAST_CI_STATUS=$(ci_status_for_head "${pr_number}" "${expected_head}")
|
|
194
|
+
[ "${LAST_CI_STATUS}" = "passing" ]
|
|
129
195
|
}
|
|
130
196
|
|
|
131
197
|
# Rebase a PR against its base branch
|
|
@@ -140,6 +206,23 @@ rebase_pr() {
|
|
|
140
206
|
return $?
|
|
141
207
|
}
|
|
142
208
|
|
|
209
|
+
cleanup_watchdog() {
|
|
210
|
+
local pid="${1:-}"
|
|
211
|
+
local child_pids=""
|
|
212
|
+
|
|
213
|
+
if [ -z "${pid}" ]; then
|
|
214
|
+
return 0
|
|
215
|
+
fi
|
|
216
|
+
|
|
217
|
+
child_pids=$(pgrep -P "${pid}" 2>/dev/null || true)
|
|
218
|
+
if [ -n "${child_pids}" ]; then
|
|
219
|
+
kill ${child_pids} 2>/dev/null || true
|
|
220
|
+
fi
|
|
221
|
+
|
|
222
|
+
kill "${pid}" 2>/dev/null || true
|
|
223
|
+
wait "${pid}" 2>/dev/null || true
|
|
224
|
+
}
|
|
225
|
+
|
|
143
226
|
log() {
|
|
144
227
|
echo "[$(date '+%Y-%m-%dT%H:%M:%S')] $*" | tee -a "${LOG_FILE}"
|
|
145
228
|
}
|
|
@@ -158,7 +241,7 @@ cd "${PROJECT_DIR}"
|
|
|
158
241
|
|
|
159
242
|
log "========================================"
|
|
160
243
|
log "RUN-START: merger invoked project=${PROJECT_DIR} dry_run=${DRY_RUN}"
|
|
161
|
-
log "CONFIG: merge_method=${MERGE_METHOD} min_review_score=${MIN_REVIEW_SCORE} rebase_before_merge=${REBASE_BEFORE_MERGE} max_prs=${MAX_PRS_PER_RUN} max_runtime=${MAX_RUNTIME}s branch_patterns=${BRANCH_PATTERNS_RAW:-<all>}"
|
|
244
|
+
log "CONFIG: merge_method=${MERGE_METHOD} min_review_score=${MIN_REVIEW_SCORE} rebase_before_merge=${REBASE_BEFORE_MERGE} max_prs=${MAX_PRS_PER_RUN} max_runtime=${MAX_RUNTIME}s ready_label=${READY_TO_MERGE_LABEL} branch_patterns=${BRANCH_PATTERNS_RAW:-<all>}"
|
|
162
245
|
log "========================================"
|
|
163
246
|
|
|
164
247
|
if ! acquire_lock "${LOCK_FILE}"; then
|
|
@@ -187,7 +270,7 @@ fi
|
|
|
187
270
|
kill -TERM $$ 2>/dev/null || true
|
|
188
271
|
) &
|
|
189
272
|
WATCHDOG_PID=$!
|
|
190
|
-
append_exit_trap "
|
|
273
|
+
append_exit_trap "cleanup_watchdog ${WATCHDOG_PID}"
|
|
191
274
|
|
|
192
275
|
# Discover open PRs sorted by creation date (oldest first = FIFO)
|
|
193
276
|
log "INFO: Scanning open PRs..."
|
|
@@ -224,15 +307,27 @@ while IFS= read -r pr_json; do
|
|
|
224
307
|
continue
|
|
225
308
|
fi
|
|
226
309
|
|
|
310
|
+
if csv_has_label "${pr_labels:-}" "${READY_TO_MERGE_LABEL}"; then
|
|
311
|
+
log "INFO: PR #${pr_number} (${pr_branch}): Skipping PR labeled ${READY_TO_MERGE_LABEL}"
|
|
312
|
+
continue
|
|
313
|
+
fi
|
|
314
|
+
|
|
227
315
|
# Check branch pattern filter
|
|
228
316
|
if ! matches_branch_patterns "${pr_branch}"; then
|
|
229
317
|
log "DEBUG: PR #${pr_number} (${pr_branch}): Branch pattern mismatch, skipping"
|
|
230
318
|
continue
|
|
231
319
|
fi
|
|
232
320
|
|
|
321
|
+
pr_head_oid=$(get_pr_head_oid "${pr_number}")
|
|
322
|
+
if [ -z "${pr_head_oid}" ]; then
|
|
323
|
+
log "INFO: PR #${pr_number} (${pr_branch}): Unable to determine PR head, skipping"
|
|
324
|
+
continue
|
|
325
|
+
fi
|
|
326
|
+
|
|
233
327
|
# Check CI status
|
|
234
|
-
|
|
235
|
-
|
|
328
|
+
ci_status=$(ci_status_for_head "${pr_number}" "${pr_head_oid}")
|
|
329
|
+
if [ "${ci_status}" != "passing" ]; then
|
|
330
|
+
log "INFO: PR #${pr_number} (${pr_branch}): CI not passing on head ${pr_head_oid} (${ci_status}), skipping"
|
|
236
331
|
continue
|
|
237
332
|
fi
|
|
238
333
|
|
|
@@ -249,6 +344,7 @@ while IFS= read -r pr_json; do
|
|
|
249
344
|
|
|
250
345
|
# Rebase before merge if configured
|
|
251
346
|
if [ "${REBASE_BEFORE_MERGE}" = "1" ]; then
|
|
347
|
+
pr_head_before_rebase="${pr_head_oid}"
|
|
252
348
|
if ! rebase_pr "${pr_number}"; then
|
|
253
349
|
log "WARN: PR #${pr_number}: Rebase failed, skipping"
|
|
254
350
|
FAILED_PRS=$((FAILED_PRS + 1))
|
|
@@ -256,20 +352,20 @@ while IFS= read -r pr_json; do
|
|
|
256
352
|
fi
|
|
257
353
|
log "INFO: PR #${pr_number}: Rebase successful"
|
|
258
354
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if !
|
|
272
|
-
log "INFO: PR #${pr_number}: CI not passing after rebase (waited ${
|
|
355
|
+
pr_head_after_rebase=$(get_pr_head_oid "${pr_number}")
|
|
356
|
+
if [ -z "${pr_head_after_rebase}" ]; then
|
|
357
|
+
log "INFO: PR #${pr_number}: Unable to determine PR head after rebase, skipping"
|
|
358
|
+
continue
|
|
359
|
+
fi
|
|
360
|
+
if [ "${pr_head_after_rebase}" != "${pr_head_before_rebase}" ]; then
|
|
361
|
+
log "INFO: PR #${pr_number}: Head changed after rebase ${pr_head_before_rebase} -> ${pr_head_after_rebase}; waiting for fresh CI"
|
|
362
|
+
else
|
|
363
|
+
log "INFO: PR #${pr_number}: Head unchanged after rebase (${pr_head_after_rebase}); confirming CI"
|
|
364
|
+
fi
|
|
365
|
+
|
|
366
|
+
# Poll CI until all checks attached to the post-rebase head are complete and passing.
|
|
367
|
+
if ! wait_for_ci_passing_on_head "${pr_number}" "${pr_head_after_rebase}"; then
|
|
368
|
+
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), skipping"
|
|
273
369
|
continue
|
|
274
370
|
fi
|
|
275
371
|
fi
|
|
@@ -284,12 +380,17 @@ while IFS= read -r pr_json; do
|
|
|
284
380
|
# Rebase remaining PRs after each successful merge
|
|
285
381
|
log "INFO: Rebasing remaining open PRs after merging #${pr_number}..."
|
|
286
382
|
REMAINING_JSON=$(gh pr list --state open \
|
|
287
|
-
--json number,headRefName \
|
|
383
|
+
--json number,headRefName,labels \
|
|
288
384
|
2>/dev/null || echo "[]")
|
|
289
385
|
while IFS= read -r remaining_pr; do
|
|
290
386
|
remaining_number=$(echo "${remaining_pr}" | jq -r '.number')
|
|
291
387
|
remaining_branch=$(echo "${remaining_pr}" | jq -r '.headRefName')
|
|
388
|
+
remaining_labels=$(echo "${remaining_pr}" | jq -r '[.labels[]?.name] | join(",")')
|
|
292
389
|
if [ "${remaining_number}" != "${pr_number}" ]; then
|
|
390
|
+
if csv_has_label "${remaining_labels:-}" "${READY_TO_MERGE_LABEL}"; then
|
|
391
|
+
log "INFO: Skipping post-merge rebase for PR #${remaining_number} (${remaining_branch}) because it is labeled ${READY_TO_MERGE_LABEL}"
|
|
392
|
+
continue
|
|
393
|
+
fi
|
|
293
394
|
log "INFO: Rebasing remaining PR #${remaining_number} (${remaining_branch})"
|
|
294
395
|
gh pr update-branch --rebase "${remaining_number}" 2>/dev/null || \
|
|
295
396
|
log "WARN: PR #${remaining_number}: Rebase failed (continuing)"
|
|
@@ -61,6 +61,8 @@ PROVIDER_MODEL_DISPLAY=$(resolve_provider_model_display "${PROVIDER_CMD}" "${PRO
|
|
|
61
61
|
PRD_DIR="${NW_PRD_DIR:-docs/PRDs}"
|
|
62
62
|
PLAN_TASK="${NW_PLAN_TASK:-}"
|
|
63
63
|
|
|
64
|
+
skip_if_job_paused "${SCRIPT_TYPE}" "${PROJECT_DIR}"
|
|
65
|
+
|
|
64
66
|
rotate_log
|
|
65
67
|
log_separator
|
|
66
68
|
log "RUN-START: planner invoked project=${PROJECT_DIR} provider=${PROVIDER_CMD} dry_run=${NW_DRY_RUN:-0}"
|
|
@@ -63,6 +63,7 @@ PROVIDER_MODEL_DISPLAY=$(resolve_provider_model_display "${PROVIDER_CMD}" "${PRO
|
|
|
63
63
|
# NOTE: Lock file path must match resolverLockPath() in src/utils/status-data.ts
|
|
64
64
|
LOCK_FILE="/tmp/night-watch-pr-resolver-${PROJECT_RUNTIME_KEY}.lock"
|
|
65
65
|
SCRIPT_TYPE="pr-resolver"
|
|
66
|
+
skip_if_job_paused "${SCRIPT_TYPE}" "${PROJECT_DIR}"
|
|
66
67
|
|
|
67
68
|
emit_result() {
|
|
68
69
|
local status="${1:?status required}"
|
|
@@ -359,6 +360,11 @@ while IFS= read -r pr_line; do
|
|
|
359
360
|
continue
|
|
360
361
|
fi
|
|
361
362
|
|
|
363
|
+
if csv_has_label "${labels:-}" "${READY_LABEL}"; then
|
|
364
|
+
log "INFO: Skipping PR #${pr_number} (${pr_branch}) because it is labeled ${READY_LABEL}"
|
|
365
|
+
continue
|
|
366
|
+
fi
|
|
367
|
+
|
|
362
368
|
# Apply branch pattern filter
|
|
363
369
|
if ! matches_branch_patterns "${pr_branch}"; then
|
|
364
370
|
log "DEBUG: Skipping PR #${pr_number} — branch '${pr_branch}' does not match patterns" "patterns=${BRANCH_PATTERNS_RAW}"
|
|
@@ -63,11 +63,6 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
63
63
|
# shellcheck source=night-watch-helpers.sh
|
|
64
64
|
source "${SCRIPT_DIR}/night-watch-helpers.sh"
|
|
65
65
|
|
|
66
|
-
# Ensure provider CLI is on PATH (nvm, fnm, volta, common bin dirs)
|
|
67
|
-
if ! ensure_provider_on_path "${PROVIDER_CMD}"; then
|
|
68
|
-
echo "ERROR: Provider '${PROVIDER_CMD}' not found in PATH or common installation locations" >&2
|
|
69
|
-
exit 127
|
|
70
|
-
fi
|
|
71
66
|
PROJECT_RUNTIME_KEY=$(project_runtime_key "${PROJECT_DIR}")
|
|
72
67
|
PROVIDER_MODEL_DISPLAY=$(resolve_provider_model_display "${PROVIDER_CMD}" "${PROVIDER_LABEL}")
|
|
73
68
|
GLOBAL_LOCK_FILE="/tmp/night-watch-pr-reviewer-${PROJECT_RUNTIME_KEY}.lock"
|
|
@@ -79,8 +74,10 @@ else
|
|
|
79
74
|
fi
|
|
80
75
|
|
|
81
76
|
SCRIPT_TYPE="reviewer"
|
|
77
|
+
skip_if_job_paused "${SCRIPT_TYPE}" "${PROJECT_DIR}"
|
|
82
78
|
READY_FOR_REVIEW_LABEL="${NW_READY_FOR_REVIEW_LABEL:-ready-for-review}"
|
|
83
79
|
READY_FOR_REVIEW_MARKER_NAME="night-watch-ready-for-review"
|
|
80
|
+
READY_TO_MERGE_LABEL="${NW_PR_RESOLVER_READY_LABEL:-ready-to-merge}"
|
|
84
81
|
|
|
85
82
|
emit_result() {
|
|
86
83
|
local status="${1:?status required}"
|
|
@@ -92,6 +89,13 @@ emit_result() {
|
|
|
92
89
|
fi
|
|
93
90
|
}
|
|
94
91
|
|
|
92
|
+
require_provider_on_path() {
|
|
93
|
+
if ! ensure_provider_on_path "${PROVIDER_CMD}"; then
|
|
94
|
+
echo "ERROR: Provider '${PROVIDER_CMD}' not found in PATH or common installation locations" >&2
|
|
95
|
+
exit 127
|
|
96
|
+
fi
|
|
97
|
+
}
|
|
98
|
+
|
|
95
99
|
extract_review_score_from_text() {
|
|
96
100
|
local review_text="${1:-}"
|
|
97
101
|
printf '%s' "${review_text}" \
|
|
@@ -701,6 +705,11 @@ while IFS=$'\t' read -r pr_number pr_branch pr_labels; do
|
|
|
701
705
|
continue
|
|
702
706
|
fi
|
|
703
707
|
|
|
708
|
+
if csv_has_label "${pr_labels:-}" "${READY_TO_MERGE_LABEL}"; then
|
|
709
|
+
log "INFO: PR #${pr_number} (${pr_branch}) is labeled ${READY_TO_MERGE_LABEL}; skipping automated review"
|
|
710
|
+
continue
|
|
711
|
+
fi
|
|
712
|
+
|
|
704
713
|
if printf '%s\n' "${pr_labels:-}" | tr ',' '\n' | grep -Fxq 'needs-human-review'; then
|
|
705
714
|
log "INFO: PR #${pr_number} (${pr_branch}) is labeled needs-human-review; skipping automated review"
|
|
706
715
|
continue
|
|
@@ -847,6 +856,8 @@ if [ -z "${TARGET_PR}" ] && [ "${WORKER_MODE}" != "1" ] && [ "${PARALLEL_ENABLED
|
|
|
847
856
|
exit 0
|
|
848
857
|
fi
|
|
849
858
|
|
|
859
|
+
require_provider_on_path
|
|
860
|
+
|
|
850
861
|
log "PARALLEL: Launching ${#PR_NUMBER_ARRAY[@]} reviewer worker(s)"
|
|
851
862
|
|
|
852
863
|
declare -a WORKER_PIDS=()
|
|
@@ -1016,6 +1027,8 @@ if [ "${NW_DRY_RUN:-0}" = "1" ]; then
|
|
|
1016
1027
|
exit 0
|
|
1017
1028
|
fi
|
|
1018
1029
|
|
|
1030
|
+
require_provider_on_path
|
|
1031
|
+
|
|
1019
1032
|
if ! prepare_detached_worktree "${PROJECT_DIR}" "${REVIEW_WORKTREE_DIR}" "${DEFAULT_BRANCH}" "${LOG_FILE}"; then
|
|
1020
1033
|
log "FAIL: Unable to create isolated reviewer worktree ${REVIEW_WORKTREE_DIR}"
|
|
1021
1034
|
exit 1
|
|
@@ -1220,6 +1233,10 @@ for ATTEMPT in $(seq 1 "${TOTAL_ATTEMPTS}"); do
|
|
|
1220
1233
|
LOG_LINE_BEFORE=$(wc -l < "${LOG_FILE}" 2>/dev/null || echo 0)
|
|
1221
1234
|
REVIEWER_ATTEMPT_START=$(date +%s)
|
|
1222
1235
|
REVIEWER_PROMPT="${REVIEWER_PROMPT_BASE}${TARGET_SCOPE_PROMPT}${PRD_CONTEXT_PROMPT}"
|
|
1236
|
+
if [ -n "${NW_PROJECT_FEEDBACK_PROMPT:-}" ]; then
|
|
1237
|
+
REVIEWER_PROMPT="${REVIEWER_PROMPT}"$'\n\n'"${NW_PROJECT_FEEDBACK_PROMPT}"
|
|
1238
|
+
log "INFO: Added project feedback prompt context"
|
|
1239
|
+
fi
|
|
1223
1240
|
|
|
1224
1241
|
# Build provider command array using generic helper
|
|
1225
1242
|
mapfile -d '' -t PROVIDER_CMD_PARTS < <(build_provider_cmd "${REVIEW_WORKTREE_DIR}" "${REVIEWER_PROMPT}")
|
|
@@ -26,6 +26,7 @@ PROVIDER_LABEL="${NW_PROVIDER_LABEL:-}"
|
|
|
26
26
|
BRANCH_PATTERNS_RAW="${NW_BRANCH_PATTERNS:-feat/,night-watch/}"
|
|
27
27
|
SKIP_LABEL="${NW_QA_SKIP_LABEL:-skip-qa}"
|
|
28
28
|
VALIDATED_LABEL="${NW_QA_VALIDATED_LABEL:-e2e-validated}"
|
|
29
|
+
READY_TO_MERGE_LABEL="${NW_PR_RESOLVER_READY_LABEL:-ready-to-merge}"
|
|
29
30
|
QA_ARTIFACTS="${NW_QA_ARTIFACTS:-both}"
|
|
30
31
|
QA_AUTO_INSTALL_PLAYWRIGHT="${NW_QA_AUTO_INSTALL_PLAYWRIGHT:-1}"
|
|
31
32
|
SCRIPT_START_TIME=$(date +%s)
|
|
@@ -45,6 +46,7 @@ PROJECT_RUNTIME_KEY=$(project_runtime_key "${PROJECT_DIR}")
|
|
|
45
46
|
# NOTE: Lock file path must match qaLockPath() in src/utils/status-data.ts
|
|
46
47
|
LOCK_FILE="/tmp/night-watch-qa-${PROJECT_RUNTIME_KEY}.lock"
|
|
47
48
|
SCRIPT_TYPE="qa"
|
|
49
|
+
skip_if_job_paused "${SCRIPT_TYPE}" "${PROJECT_DIR}"
|
|
48
50
|
|
|
49
51
|
emit_result() {
|
|
50
52
|
local status="${1:?status required}"
|
|
@@ -366,7 +368,7 @@ fi
|
|
|
366
368
|
rotate_log
|
|
367
369
|
log_separator
|
|
368
370
|
log "RUN-START: qa invoked project=${PROJECT_DIR} provider=${PROVIDER_CMD} dry_run=${NW_DRY_RUN:-0}"
|
|
369
|
-
log "CONFIG: max_runtime=${MAX_RUNTIME}s artifacts=${QA_ARTIFACTS} skip_label=${SKIP_LABEL} branch_patterns=${BRANCH_PATTERNS_RAW}"
|
|
371
|
+
log "CONFIG: max_runtime=${MAX_RUNTIME}s artifacts=${QA_ARTIFACTS} skip_label=${SKIP_LABEL} ready_label=${READY_TO_MERGE_LABEL} branch_patterns=${BRANCH_PATTERNS_RAW}"
|
|
370
372
|
|
|
371
373
|
if ! acquire_lock "${LOCK_FILE}"; then
|
|
372
374
|
emit_result "skip_locked"
|
|
@@ -431,6 +433,11 @@ while IFS=$'\t' read -r pr_number pr_branch pr_title pr_labels; do
|
|
|
431
433
|
continue
|
|
432
434
|
fi
|
|
433
435
|
|
|
436
|
+
if csv_has_label "${pr_labels:-}" "${READY_TO_MERGE_LABEL}"; then
|
|
437
|
+
log "SKIP-QA: PR #${pr_number} (${pr_branch}) is labeled ${READY_TO_MERGE_LABEL}"
|
|
438
|
+
continue
|
|
439
|
+
fi
|
|
440
|
+
|
|
434
441
|
# Skip PRs with the skip label
|
|
435
442
|
if echo "${pr_labels}" | grep -q "${SKIP_LABEL}"; then
|
|
436
443
|
log "SKIP-QA: PR #${pr_number} (${pr_branch}) has '${SKIP_LABEL}' label"
|
|
@@ -35,6 +35,7 @@ source "${SCRIPT_DIR}/night-watch-helpers.sh"
|
|
|
35
35
|
ensure_provider_on_path "${PROVIDER_CMD}" || true
|
|
36
36
|
PROJECT_RUNTIME_KEY=$(project_runtime_key "${PROJECT_DIR}")
|
|
37
37
|
LOCK_FILE="/tmp/night-watch-slicer-${PROJECT_RUNTIME_KEY}.lock"
|
|
38
|
+
SCRIPT_TYPE="slicer"
|
|
38
39
|
PROVIDER_MODEL_DISPLAY=$(resolve_provider_model_display "${PROVIDER_CMD}" "${PROVIDER_LABEL}")
|
|
39
40
|
|
|
40
41
|
emit_result() {
|
|
@@ -53,6 +54,8 @@ if ! validate_provider "${PROVIDER_CMD}"; then
|
|
|
53
54
|
exit 1
|
|
54
55
|
fi
|
|
55
56
|
|
|
57
|
+
skip_if_job_paused "${SCRIPT_TYPE}" "${PROJECT_DIR}"
|
|
58
|
+
|
|
56
59
|
rotate_log
|
|
57
60
|
log_separator
|
|
58
61
|
log "RUN-START: slicer invoked project=${PROJECT_DIR} provider=${PROVIDER_CMD} dry_run=${NW_DRY_RUN:-0}"
|
|
@@ -55,9 +55,28 @@
|
|
|
55
55
|
"audit": 10
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
|
-
"
|
|
59
|
-
"
|
|
58
|
+
"webhookTriggers": {
|
|
59
|
+
"enabled": false,
|
|
60
|
+
"secretEnv": "NIGHT_WATCH_WEBHOOK_SECRET",
|
|
61
|
+
"allowedJobIds": [
|
|
62
|
+
"executor",
|
|
63
|
+
"reviewer",
|
|
64
|
+
"pr-resolver",
|
|
65
|
+
"slicer",
|
|
66
|
+
"qa",
|
|
67
|
+
"audit",
|
|
68
|
+
"analytics",
|
|
69
|
+
"merger"
|
|
70
|
+
],
|
|
71
|
+
"requireTimestamp": false,
|
|
72
|
+
"maxSkewSeconds": 300,
|
|
73
|
+
"github": {
|
|
74
|
+
"enabled": false,
|
|
75
|
+
"events": [],
|
|
76
|
+
"rules": []
|
|
77
|
+
}
|
|
60
78
|
},
|
|
79
|
+
"jobProviders": {},
|
|
61
80
|
"autoMerge": false,
|
|
62
81
|
"autoMergeMethod": "squash",
|
|
63
82
|
"fallbackOnRateLimit": true,
|
|
@@ -75,23 +94,5 @@
|
|
|
75
94
|
"enabled": true,
|
|
76
95
|
"schedule": "50 3 * * 1",
|
|
77
96
|
"maxRuntime": 1800
|
|
78
|
-
},
|
|
79
|
-
"providerPresets": {
|
|
80
|
-
"g51claude": {
|
|
81
|
-
"name": "GLM-5.1 Claude",
|
|
82
|
-
"command": "claude",
|
|
83
|
-
"promptFlag": "-p",
|
|
84
|
-
"autoApproveFlag": "--dangerously-skip-permissions",
|
|
85
|
-
"modelFlag": "--model",
|
|
86
|
-
"model": "glm-5.1",
|
|
87
|
-
"envVars": {
|
|
88
|
-
"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
|
|
89
|
-
"API_TIMEOUT_MS": "3000000",
|
|
90
|
-
"ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-5.1",
|
|
91
|
-
"ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-5.1",
|
|
92
|
-
"ANTHROPIC_AUTH_TOKEN": "efaeca456dab4ae69cb9ce1fa8d99a1a.KSTifNTWPS6NgC6L",
|
|
93
|
-
"ANTHROPIC_API_KEY": "efaeca456dab4ae69cb9ce1fa8d99a1a.KSTifNTWPS6NgC6L"
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
97
|
}
|
|
97
98
|
}
|
package/dist/templates/slicer.md
CHANGED
|
@@ -32,6 +32,8 @@ The PRD directory is: `{{PRD_DIR}}`
|
|
|
32
32
|
|
|
33
33
|
3. **Write a Complete PRD** — Follow the exact template structure below. Every section must be filled with concrete information. No placeholder text.
|
|
34
34
|
|
|
35
|
+
The PRD MUST include these sections: Context (with Problem, Files Analyzed, Current Behavior, Integration Points), Solution (with Approach, Key Decisions), Execution Phases (with Files, Implementation steps, Tests), and Acceptance Criteria.
|
|
36
|
+
|
|
35
37
|
4. **Write the PRD File** — Use the Write tool to create the PRD file at `{{OUTPUT_FILE_PATH}}`.
|
|
36
38
|
|
|
37
39
|
---
|
|
@@ -146,6 +148,7 @@ sequenceDiagram
|
|
|
146
148
|
## 4. Execution Phases
|
|
147
149
|
|
|
148
150
|
Critical rules:
|
|
151
|
+
|
|
149
152
|
1. Each phase = ONE user-testable vertical slice
|
|
150
153
|
2. Max 5 files per phase (split if larger)
|
|
151
154
|
3. Each phase MUST include concrete tests
|