@jonit-dev/night-watch-cli 1.8.10-beta.1 → 1.8.10-beta.12
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-audit-cron.sh +6 -0
- package/dist/scripts/night-watch-cron.sh +352 -53
- package/dist/scripts/night-watch-helpers.sh +212 -12
- 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 +11 -0
- package/dist/scripts/night-watch-qa-cron.sh +11 -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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tab-config.d.ts","sourceRoot":"","sources":["../../../src/commands/dashboard/tab-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAGL,iBAAiB,EAKlB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,IAAI,EAAe,MAAM,YAAY,CAAC;AAE/C,KAAK,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;AAEjG,UAAU,YAAY;IACpB,GAAG,EAAE,MAAM,iBAAiB,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAC7C;AAiDD,eAAO,MAAM,aAAa,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"tab-config.d.ts","sourceRoot":"","sources":["../../../src/commands/dashboard/tab-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAGL,iBAAiB,EAKlB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,IAAI,EAAe,MAAM,YAAY,CAAC;AAE/C,KAAK,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;AAEjG,UAAU,YAAY;IACpB,GAAG,EAAE,MAAM,iBAAiB,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAC7C;AAiDD,eAAO,MAAM,aAAa,EAAE,YAAY,EAgDvC,CAAC;AA0BF;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAyzBtC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/commands/queue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+DpC,wBAAgB,kBAAkB,IAAI,OAAO,
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../../src/commands/queue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+DpC,wBAAgB,kBAAkB,IAAI,OAAO,CAyU5C;AAkED,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEnD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-builder.d.ts","sourceRoot":"","sources":["../../../src/commands/shared/env-builder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEL,iBAAiB,EAEjB,WAAW,EAEX,iBAAiB,EAKlB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,OAAO,EAAY,MAAM,mBAAmB,CAAC;AAmB3D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,OAAO,GAChB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"env-builder.d.ts","sourceRoot":"","sources":["../../../src/commands/shared/env-builder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEL,iBAAiB,EAEjB,WAAW,EAEX,iBAAiB,EAKlB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,OAAO,EAAY,MAAM,mBAAmB,CAAC;AAmB3D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,OAAO,GAChB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAoExB;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,+CAGnB;AAED,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC,CAY/C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAO1F;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAG5E;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,iBAAiB,GACxB,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAW7C"}
|
|
@@ -116,6 +116,12 @@ fi
|
|
|
116
116
|
AUDIT_WORKTREE_BASENAME="${PROJECT_NAME}-nw-audit-runner"
|
|
117
117
|
AUDIT_WORKTREE_DIR="$(dirname "${PROJECT_DIR}")/${AUDIT_WORKTREE_BASENAME}"
|
|
118
118
|
|
|
119
|
+
cleanup_audit_worktree_on_exit() {
|
|
120
|
+
cleanup_worktree_path "${PROJECT_DIR}" "${AUDIT_WORKTREE_DIR}"
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
append_exit_trap "cleanup_audit_worktree_on_exit"
|
|
124
|
+
|
|
119
125
|
cleanup_worktrees "${PROJECT_DIR}" "${AUDIT_WORKTREE_BASENAME}"
|
|
120
126
|
|
|
121
127
|
if ! prepare_detached_worktree "${PROJECT_DIR}" "${AUDIT_WORKTREE_DIR}" "${DEFAULT_BRANCH}" "${LOG_FILE}"; then
|
|
@@ -140,6 +140,12 @@ ISSUE_NUMBER="" # board mode: GitHub issue number
|
|
|
140
140
|
ISSUE_BODY="" # board mode: issue body (PRD content)
|
|
141
141
|
ISSUE_TITLE_RAW="" # board mode: issue title
|
|
142
142
|
NW_CLI="" # board mode: resolved night-watch CLI binary
|
|
143
|
+
EXECUTOR_PR_JSON=""
|
|
144
|
+
EXECUTOR_PR_NUMBER=""
|
|
145
|
+
EXECUTOR_PR_URL=""
|
|
146
|
+
EXECUTOR_PR_DRAFT=""
|
|
147
|
+
RESUME_FROM_EXISTING_PR=0
|
|
148
|
+
RESUME_BRANCH_NAME=""
|
|
143
149
|
|
|
144
150
|
restore_issue_to_ready() {
|
|
145
151
|
local reason="${1:-Execution failed before implementation started.}"
|
|
@@ -149,6 +155,26 @@ restore_issue_to_ready() {
|
|
|
149
155
|
fi
|
|
150
156
|
}
|
|
151
157
|
|
|
158
|
+
if [ -z "${NW_TARGET_ISSUE:-}" ]; then
|
|
159
|
+
EXECUTOR_PR_JSON=$(find_executor_resume_pr "${BRANCH_PREFIX}" || true)
|
|
160
|
+
if [ -n "${EXECUTOR_PR_JSON}" ]; then
|
|
161
|
+
RESUME_FROM_EXISTING_PR=1
|
|
162
|
+
RESUME_BRANCH_NAME=$(printf '%s' "${EXECUTOR_PR_JSON}" | jq -r '.headRefName // empty' 2>/dev/null || true)
|
|
163
|
+
EXECUTOR_PR_NUMBER=$(printf '%s' "${EXECUTOR_PR_JSON}" | jq -r '.number // empty' 2>/dev/null || true)
|
|
164
|
+
EXECUTOR_PR_URL=$(printf '%s' "${EXECUTOR_PR_JSON}" | jq -r '.url // empty' 2>/dev/null || true)
|
|
165
|
+
EXECUTOR_PR_DRAFT=$(printf '%s' "${EXECUTOR_PR_JSON}" | jq -r '.isDraft // false' 2>/dev/null || true)
|
|
166
|
+
if [ -n "${RESUME_BRANCH_NAME}" ]; then
|
|
167
|
+
log "RESUME: Prioritizing resumable PR #${EXECUTOR_PR_NUMBER:-unknown} on ${RESUME_BRANCH_NAME}"
|
|
168
|
+
else
|
|
169
|
+
RESUME_FROM_EXISTING_PR=0
|
|
170
|
+
EXECUTOR_PR_JSON=""
|
|
171
|
+
EXECUTOR_PR_NUMBER=""
|
|
172
|
+
EXECUTOR_PR_URL=""
|
|
173
|
+
EXECUTOR_PR_DRAFT=""
|
|
174
|
+
fi
|
|
175
|
+
fi
|
|
176
|
+
fi
|
|
177
|
+
|
|
152
178
|
if [ "${NW_BOARD_ENABLED:-}" = "true" ]; then
|
|
153
179
|
# Board mode: discover next task from GitHub Projects board
|
|
154
180
|
NW_CLI=$(resolve_night_watch_cli 2>/dev/null || true)
|
|
@@ -169,37 +195,52 @@ if [ "${NW_BOARD_ENABLED:-}" = "true" ]; then
|
|
|
169
195
|
ISSUE_TITLE_RAW=$(printf '%s' "${ISSUE_JSON}" | jq -r '.title // empty' 2>/dev/null || true)
|
|
170
196
|
ISSUE_BODY=$(printf '%s' "${ISSUE_JSON}" | jq -r '.body // empty' 2>/dev/null || true)
|
|
171
197
|
else
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
198
|
+
if [ "${RESUME_FROM_EXISTING_PR}" = "1" ] && [ -n "${RESUME_BRANCH_NAME}" ]; then
|
|
199
|
+
ELIGIBLE_PRD="${RESUME_BRANCH_NAME#*/}"
|
|
200
|
+
ISSUE_NUMBER=$(printf '%s' "${ELIGIBLE_PRD}" | grep -oE '^[0-9]+' || true)
|
|
201
|
+
if [ -n "${ISSUE_NUMBER}" ]; then
|
|
202
|
+
ISSUE_JSON=$(gh issue view "${ISSUE_NUMBER}" --json number,title,body 2>/dev/null || true)
|
|
203
|
+
ISSUE_TITLE_RAW=$(printf '%s' "${ISSUE_JSON}" | jq -r '.title // empty' 2>/dev/null || true)
|
|
204
|
+
ISSUE_BODY=$(printf '%s' "${ISSUE_JSON}" | jq -r '.body // empty' 2>/dev/null || true)
|
|
205
|
+
"${NW_CLI}" board move-issue "${ISSUE_NUMBER}" --column "In Progress" 2>>"${LOG_FILE}" || \
|
|
206
|
+
log "WARN: Failed to move resumed issue #${ISSUE_NUMBER} to In Progress"
|
|
181
207
|
else
|
|
182
|
-
|
|
208
|
+
ISSUE_TITLE_RAW=$(printf '%s' "${EXECUTOR_PR_JSON}" | jq -r '.title // empty' 2>/dev/null || true)
|
|
183
209
|
fi
|
|
184
210
|
else
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
211
|
+
BOARD_DISCOVERY_STATUS=0
|
|
212
|
+
if ISSUE_JSON=$(find_eligible_board_issue "${PROJECT_DIR}" "${MAX_RUNTIME}"); then
|
|
213
|
+
BOARD_DISCOVERY_STATUS=0
|
|
214
|
+
else
|
|
215
|
+
BOARD_DISCOVERY_STATUS=$?
|
|
216
|
+
fi
|
|
217
|
+
if [ -z "${ISSUE_JSON}" ]; then
|
|
218
|
+
if [ "${BOARD_DISCOVERY_STATUS}" -eq 2 ]; then
|
|
219
|
+
log "INFO: Ready board issues were found, but all are in cooldown; skipping this run"
|
|
220
|
+
else
|
|
221
|
+
log "INFO: No Ready board issues found; skipping this run"
|
|
222
|
+
fi
|
|
223
|
+
else
|
|
224
|
+
ISSUE_NUMBER=$(printf '%s' "${ISSUE_JSON}" | jq -r '.number // empty' 2>/dev/null || true)
|
|
225
|
+
ISSUE_TITLE_RAW=$(printf '%s' "${ISSUE_JSON}" | jq -r '.title // empty' 2>/dev/null || true)
|
|
226
|
+
ISSUE_BODY=$(printf '%s' "${ISSUE_JSON}" | jq -r '.body // empty' 2>/dev/null || true)
|
|
227
|
+
if [ -z "${ISSUE_NUMBER}" ]; then
|
|
228
|
+
log "ERROR: Board mode: failed to parse issue number from JSON"
|
|
229
|
+
exit 1
|
|
230
|
+
fi
|
|
231
|
+
# Move issue to In Progress (claim it on the board)
|
|
232
|
+
"${NW_CLI}" board move-issue "${ISSUE_NUMBER}" --column "In Progress" 2>>"${LOG_FILE}" || \
|
|
233
|
+
log "WARN: Failed to move issue #${ISSUE_NUMBER} to In Progress"
|
|
191
234
|
fi
|
|
192
|
-
# Move issue to In Progress (claim it on the board)
|
|
193
|
-
"${NW_CLI}" board move-issue "${ISSUE_NUMBER}" --column "In Progress" 2>>"${LOG_FILE}" || \
|
|
194
|
-
log "WARN: Failed to move issue #${ISSUE_NUMBER} to In Progress"
|
|
195
235
|
fi
|
|
196
236
|
fi
|
|
197
237
|
|
|
198
238
|
if [ -n "${ISSUE_NUMBER}" ]; then
|
|
199
|
-
# Slugify title for branch naming
|
|
200
|
-
|
|
239
|
+
# Slugify title for branch naming unless we're resuming an existing PR branch.
|
|
240
|
+
if [ "${RESUME_FROM_EXISTING_PR}" != "1" ] || [ -z "${ELIGIBLE_PRD:-}" ]; then
|
|
241
|
+
ELIGIBLE_PRD="${ISSUE_NUMBER}-$(printf '%s' "${ISSUE_TITLE_RAW}" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9' '-' | sed 's/^-\|-$//g')"
|
|
242
|
+
fi
|
|
201
243
|
log "BOARD: Processing issue #${ISSUE_NUMBER}: ${ISSUE_TITLE_RAW}"
|
|
202
|
-
trap "rm -f '${LOCK_FILE}'" EXIT
|
|
203
244
|
fi
|
|
204
245
|
fi
|
|
205
246
|
|
|
@@ -209,8 +250,25 @@ if [ -z "${ISSUE_NUMBER}" ]; then
|
|
|
209
250
|
emit_result "skip_no_eligible_prd"
|
|
210
251
|
exit 0
|
|
211
252
|
fi
|
|
253
|
+
if [ "${RESUME_FROM_EXISTING_PR}" = "1" ] && [ -n "${RESUME_BRANCH_NAME}" ]; then
|
|
254
|
+
RESUME_PRD_NAME="${RESUME_BRANCH_NAME#*/}"
|
|
255
|
+
if [ -f "${PRD_DIR}/${RESUME_PRD_NAME}.md" ]; then
|
|
256
|
+
ELIGIBLE_PRD="${RESUME_PRD_NAME}.md"
|
|
257
|
+
log "RESUME: Using resumable filesystem PRD ${ELIGIBLE_PRD}"
|
|
258
|
+
else
|
|
259
|
+
log "WARN: Resumable PR branch ${RESUME_BRANCH_NAME} has no matching PRD file in ${PRD_DIR}; falling back to normal selection"
|
|
260
|
+
RESUME_FROM_EXISTING_PR=0
|
|
261
|
+
EXECUTOR_PR_JSON=""
|
|
262
|
+
EXECUTOR_PR_NUMBER=""
|
|
263
|
+
EXECUTOR_PR_URL=""
|
|
264
|
+
EXECUTOR_PR_DRAFT=""
|
|
265
|
+
RESUME_BRANCH_NAME=""
|
|
266
|
+
fi
|
|
267
|
+
fi
|
|
212
268
|
# Filesystem mode: scan PRD directory
|
|
213
|
-
|
|
269
|
+
if [ -z "${ELIGIBLE_PRD:-}" ]; then
|
|
270
|
+
ELIGIBLE_PRD=$(find_eligible_prd "${PRD_DIR}" "${MAX_RUNTIME}" "${PROJECT_DIR}")
|
|
271
|
+
fi
|
|
214
272
|
if [ -z "${ELIGIBLE_PRD}" ]; then
|
|
215
273
|
log "SKIP: No eligible PRDs (all done, in-progress, or blocked)"
|
|
216
274
|
emit_result "skip_no_eligible_prd"
|
|
@@ -218,12 +276,15 @@ if [ -z "${ISSUE_NUMBER}" ]; then
|
|
|
218
276
|
fi
|
|
219
277
|
# Claim the PRD to prevent other runs from selecting it
|
|
220
278
|
claim_prd "${PRD_DIR}" "${ELIGIBLE_PRD}"
|
|
221
|
-
|
|
222
|
-
trap "rm -f '${LOCK_FILE}'; release_claim '${PRD_DIR}' '${ELIGIBLE_PRD}'" EXIT
|
|
279
|
+
append_exit_trap "release_claim '${PRD_DIR}' '${ELIGIBLE_PRD}'"
|
|
223
280
|
fi
|
|
224
281
|
|
|
225
282
|
PRD_NAME="${ELIGIBLE_PRD%.md}"
|
|
226
|
-
|
|
283
|
+
if [ -n "${RESUME_BRANCH_NAME}" ]; then
|
|
284
|
+
BRANCH_NAME="${RESUME_BRANCH_NAME}"
|
|
285
|
+
else
|
|
286
|
+
BRANCH_NAME="${BRANCH_PREFIX}/${PRD_NAME}"
|
|
287
|
+
fi
|
|
227
288
|
WORKTREE_DIR="$(dirname "${PROJECT_DIR}")/${PROJECT_NAME}-nw-${PRD_NAME}"
|
|
228
289
|
BOOKKEEP_WORKTREE_DIR="$(dirname "${PROJECT_DIR}")/${PROJECT_NAME}-nw-bookkeeping"
|
|
229
290
|
if [ -n "${NW_DEFAULT_BRANCH:-}" ]; then
|
|
@@ -231,6 +292,14 @@ if [ -n "${NW_DEFAULT_BRANCH:-}" ]; then
|
|
|
231
292
|
else
|
|
232
293
|
DEFAULT_BRANCH=$(detect_default_branch "${PROJECT_DIR}")
|
|
233
294
|
fi
|
|
295
|
+
|
|
296
|
+
cleanup_executor_worktrees_on_exit() {
|
|
297
|
+
cleanup_worktree_path "${PROJECT_DIR}" "${WORKTREE_DIR}"
|
|
298
|
+
cleanup_worktree_path "${PROJECT_DIR}" "${BOOKKEEP_WORKTREE_DIR}"
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
append_exit_trap "cleanup_executor_worktrees_on_exit"
|
|
302
|
+
|
|
234
303
|
if [[ "${PRD_DIR_REL}" = /* ]]; then
|
|
235
304
|
BOOKKEEP_PRD_DIR="${PRD_DIR_REL}"
|
|
236
305
|
else
|
|
@@ -250,6 +319,194 @@ count_prs_for_branch() {
|
|
|
250
319
|
echo "${count:-0}"
|
|
251
320
|
}
|
|
252
321
|
|
|
322
|
+
extract_prd_title() {
|
|
323
|
+
local prd_path=""
|
|
324
|
+
local title=""
|
|
325
|
+
|
|
326
|
+
if [ -n "${ISSUE_TITLE_RAW}" ]; then
|
|
327
|
+
printf '%s' "${ISSUE_TITLE_RAW}"
|
|
328
|
+
return 0
|
|
329
|
+
fi
|
|
330
|
+
|
|
331
|
+
if [ -f "${PRD_DIR}/${ELIGIBLE_PRD}" ]; then
|
|
332
|
+
prd_path="${PRD_DIR}/${ELIGIBLE_PRD}"
|
|
333
|
+
elif [ -f "${PROJECT_DIR}/${PRD_DIR_REL}/${ELIGIBLE_PRD}" ]; then
|
|
334
|
+
prd_path="${PROJECT_DIR}/${PRD_DIR_REL}/${ELIGIBLE_PRD}"
|
|
335
|
+
fi
|
|
336
|
+
|
|
337
|
+
if [ -n "${prd_path}" ]; then
|
|
338
|
+
title=$(awk '/^[[:space:]]*#[[:space:]]+/ { sub(/^[[:space:]]*#[[:space:]]+/, "", $0); print; exit }' "${prd_path}" 2>/dev/null || true)
|
|
339
|
+
fi
|
|
340
|
+
|
|
341
|
+
if [ -n "${title}" ]; then
|
|
342
|
+
printf '%s' "${title}"
|
|
343
|
+
else
|
|
344
|
+
printf '%s' "${PRD_NAME}"
|
|
345
|
+
fi
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
build_executor_pr_title() {
|
|
349
|
+
local raw_title=""
|
|
350
|
+
|
|
351
|
+
raw_title=$(extract_prd_title)
|
|
352
|
+
raw_title=$(printf '%s' "${raw_title}" | tr '\r\n' ' ' | sed -E 's/[[:space:]]+/ /g; s/^[[:space:]]+//; s/[[:space:]]+$//')
|
|
353
|
+
if [ -z "${raw_title}" ]; then
|
|
354
|
+
raw_title="${PRD_NAME}"
|
|
355
|
+
fi
|
|
356
|
+
|
|
357
|
+
if printf '%s' "${raw_title}" | grep -Eqi '^feat:'; then
|
|
358
|
+
printf '%s' "${raw_title}"
|
|
359
|
+
else
|
|
360
|
+
printf 'feat: %s' "${raw_title}"
|
|
361
|
+
fi
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
build_executor_pr_body() {
|
|
365
|
+
local status_blurb=""
|
|
366
|
+
|
|
367
|
+
status_blurb="Status labels:
|
|
368
|
+
- ${NW_EXECUTOR_PARTIAL_LABEL}: implementation is in progress and intentionally incomplete
|
|
369
|
+
- ${NW_EXECUTOR_RESUMABLE_LABEL}: resume this PR before starting new work
|
|
370
|
+
- ${NW_EXECUTOR_READY_REVIEW_LABEL}: implementation is complete and ready for review"
|
|
371
|
+
|
|
372
|
+
if [ -n "${ISSUE_NUMBER}" ]; then
|
|
373
|
+
printf 'Closes #%s\n\nNight Watch manages this draft PR automatically so progress is preserved across retries and timeouts.\n\n%s\n' \
|
|
374
|
+
"${ISSUE_NUMBER}" \
|
|
375
|
+
"${status_blurb}"
|
|
376
|
+
else
|
|
377
|
+
printf 'Source PRD: `%s/%s`\n\nNight Watch manages this draft PR automatically so progress is preserved across retries and timeouts.\n\n%s\n' \
|
|
378
|
+
"${PRD_DIR_REL}" \
|
|
379
|
+
"${ELIGIBLE_PRD}" \
|
|
380
|
+
"${status_blurb}"
|
|
381
|
+
fi
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
refresh_executor_pr_metadata() {
|
|
385
|
+
EXECUTOR_PR_JSON=$(find_open_pr_for_branch "${BRANCH_NAME}" || true)
|
|
386
|
+
EXECUTOR_PR_NUMBER=$(printf '%s' "${EXECUTOR_PR_JSON}" | jq -r '.number // empty' 2>/dev/null || true)
|
|
387
|
+
EXECUTOR_PR_URL=$(printf '%s' "${EXECUTOR_PR_JSON}" | jq -r '.url // empty' 2>/dev/null || true)
|
|
388
|
+
EXECUTOR_PR_DRAFT=$(printf '%s' "${EXECUTOR_PR_JSON}" | jq -r '.isDraft // false' 2>/dev/null || true)
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
sync_executor_pr_status() {
|
|
392
|
+
local add_labels="${1:-}"
|
|
393
|
+
local remove_labels="${2:-}"
|
|
394
|
+
local mark_ready="${3:-0}"
|
|
395
|
+
|
|
396
|
+
if [ -z "${EXECUTOR_PR_NUMBER}" ]; then
|
|
397
|
+
return 1
|
|
398
|
+
fi
|
|
399
|
+
|
|
400
|
+
ensure_executor_status_labels
|
|
401
|
+
|
|
402
|
+
if [ -n "${add_labels}" ]; then
|
|
403
|
+
gh pr edit "${EXECUTOR_PR_NUMBER}" --add-label "${add_labels}" >> "${LOG_FILE}" 2>&1 || true
|
|
404
|
+
fi
|
|
405
|
+
if [ -n "${remove_labels}" ]; then
|
|
406
|
+
gh pr edit "${EXECUTOR_PR_NUMBER}" --remove-label "${remove_labels}" >> "${LOG_FILE}" 2>&1 || true
|
|
407
|
+
fi
|
|
408
|
+
if [ "${mark_ready}" = "1" ]; then
|
|
409
|
+
gh pr ready "${EXECUTOR_PR_NUMBER}" >> "${LOG_FILE}" 2>&1 || true
|
|
410
|
+
fi
|
|
411
|
+
|
|
412
|
+
refresh_executor_pr_metadata
|
|
413
|
+
return 0
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
mark_executor_pr_incomplete() {
|
|
417
|
+
sync_executor_pr_status \
|
|
418
|
+
"${NW_EXECUTOR_PARTIAL_LABEL},${NW_EXECUTOR_RESUMABLE_LABEL}" \
|
|
419
|
+
"${NW_EXECUTOR_READY_REVIEW_LABEL}" \
|
|
420
|
+
"0"
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
mark_executor_pr_ready_for_review() {
|
|
424
|
+
sync_executor_pr_status \
|
|
425
|
+
"${NW_EXECUTOR_READY_REVIEW_LABEL}" \
|
|
426
|
+
"${NW_EXECUTOR_PARTIAL_LABEL},${NW_EXECUTOR_RESUMABLE_LABEL}" \
|
|
427
|
+
"1"
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
push_executor_branch() {
|
|
431
|
+
local push_mode="${1:-update}"
|
|
432
|
+
|
|
433
|
+
if [ "${push_mode}" = "initial" ]; then
|
|
434
|
+
if git_push_for_project "${WORKTREE_DIR}" -u origin "${BRANCH_NAME}" >> "${LOG_FILE}" 2>&1; then
|
|
435
|
+
return 0
|
|
436
|
+
fi
|
|
437
|
+
fi
|
|
438
|
+
|
|
439
|
+
if git_push_for_project "${WORKTREE_DIR}" origin "${BRANCH_NAME}" --force-with-lease >> "${LOG_FILE}" 2>&1; then
|
|
440
|
+
return 0
|
|
441
|
+
fi
|
|
442
|
+
|
|
443
|
+
git_push_for_project "${WORKTREE_DIR}" -u origin "${BRANCH_NAME}" >> "${LOG_FILE}" 2>&1
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
executor_branch_has_commits_ahead_of_base() {
|
|
447
|
+
local base_ref=""
|
|
448
|
+
local ahead_count="0"
|
|
449
|
+
|
|
450
|
+
if ! base_ref=$(resolve_worktree_base_ref "${WORKTREE_DIR}" "${DEFAULT_BRANCH}" 2>/dev/null); then
|
|
451
|
+
return 1
|
|
452
|
+
fi
|
|
453
|
+
|
|
454
|
+
ahead_count=$(git -C "${WORKTREE_DIR}" rev-list --count "${base_ref}..HEAD" 2>/dev/null || echo "0")
|
|
455
|
+
[ "${ahead_count}" -gt 0 ]
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
ensure_executor_pr() {
|
|
459
|
+
local pr_title=""
|
|
460
|
+
local pr_body=""
|
|
461
|
+
local create_output=""
|
|
462
|
+
|
|
463
|
+
refresh_executor_pr_metadata
|
|
464
|
+
if [ -n "${EXECUTOR_PR_NUMBER}" ]; then
|
|
465
|
+
log "PR: Reusing existing open PR #${EXECUTOR_PR_NUMBER} for ${BRANCH_NAME}"
|
|
466
|
+
mark_executor_pr_incomplete
|
|
467
|
+
return 0
|
|
468
|
+
fi
|
|
469
|
+
|
|
470
|
+
pr_title=$(build_executor_pr_title)
|
|
471
|
+
pr_body=$(build_executor_pr_body)
|
|
472
|
+
|
|
473
|
+
if ! executor_branch_has_commits_ahead_of_base; then
|
|
474
|
+
log "PR: Deferring draft PR creation for ${BRANCH_NAME} until it has commits beyond ${DEFAULT_BRANCH}"
|
|
475
|
+
return 0
|
|
476
|
+
fi
|
|
477
|
+
|
|
478
|
+
log "PR: Creating draft PR for ${BRANCH_NAME}"
|
|
479
|
+
if ! push_executor_branch "initial"; then
|
|
480
|
+
log "WARN: Initial push for ${BRANCH_NAME} failed before PR creation"
|
|
481
|
+
fi
|
|
482
|
+
|
|
483
|
+
ensure_executor_status_labels
|
|
484
|
+
if ! create_output=$(
|
|
485
|
+
gh pr create \
|
|
486
|
+
--draft \
|
|
487
|
+
--base "${DEFAULT_BRANCH}" \
|
|
488
|
+
--head "${BRANCH_NAME}" \
|
|
489
|
+
--title "${pr_title}" \
|
|
490
|
+
--body "${pr_body}" 2>> "${LOG_FILE}"
|
|
491
|
+
); then
|
|
492
|
+
log "FAIL: gh pr create failed for ${BRANCH_NAME}"
|
|
493
|
+
return 1
|
|
494
|
+
fi
|
|
495
|
+
|
|
496
|
+
refresh_executor_pr_metadata
|
|
497
|
+
if [ -z "${EXECUTOR_PR_URL}" ]; then
|
|
498
|
+
EXECUTOR_PR_URL=$(printf '%s' "${create_output}" | grep -Eo 'https://[^[:space:]]+/pull/[0-9]+' | tail -n 1 || true)
|
|
499
|
+
fi
|
|
500
|
+
if [ -n "${EXECUTOR_PR_NUMBER}" ]; then
|
|
501
|
+
mark_executor_pr_incomplete
|
|
502
|
+
log "PR: Draft PR ready at ${EXECUTOR_PR_URL:-unknown} for ${BRANCH_NAME}"
|
|
503
|
+
else
|
|
504
|
+
log "WARN: gh pr create succeeded for ${BRANCH_NAME}, but PR metadata lookup did not resolve a number yet"
|
|
505
|
+
fi
|
|
506
|
+
|
|
507
|
+
return 0
|
|
508
|
+
}
|
|
509
|
+
|
|
253
510
|
checkpoint_timeout_progress() {
|
|
254
511
|
local worktree_dir="${1:?worktree_dir required}"
|
|
255
512
|
local branch_name="${2:?branch_name required}"
|
|
@@ -360,7 +617,7 @@ finalize_prd_done() {
|
|
|
360
617
|
git -C "${BOOKKEEP_WORKTREE_DIR}" commit -m "chore: mark ${ELIGIBLE_PRD} as done (${reason})
|
|
361
618
|
|
|
362
619
|
Co-Authored-By: Night Watch [${EFFECTIVE_PROVIDER_LABEL}] <noreply@anthropic.com>" || true
|
|
363
|
-
|
|
620
|
+
git_push_for_project "${BOOKKEEP_WORKTREE_DIR}" origin "HEAD:${DEFAULT_BRANCH}" || true
|
|
364
621
|
log "DONE: ${ELIGIBLE_PRD} ${reason}, PRD moved to done/"
|
|
365
622
|
return 0
|
|
366
623
|
fi
|
|
@@ -396,6 +653,7 @@ if [ -z "${EXECUTOR_PROMPT_PATH}" ]; then
|
|
|
396
653
|
exit 1
|
|
397
654
|
fi
|
|
398
655
|
EXECUTOR_PROMPT_REF=$(instruction_ref_for_prompt "${PROJECT_DIR}" "${EXECUTOR_PROMPT_PATH}")
|
|
656
|
+
PROGRESS_PUSH_CMD=$(project_git_push_command "${BRANCH_NAME}")
|
|
399
657
|
|
|
400
658
|
if [ -n "${ISSUE_NUMBER}" ]; then
|
|
401
659
|
PROMPT="Implement the following PRD (GitHub issue #${ISSUE_NUMBER}: ${ISSUE_TITLE_RAW}):
|
|
@@ -418,13 +676,13 @@ Read ${EXECUTOR_PROMPT_REF} and follow the FULL execution pipeline:
|
|
|
418
676
|
5. Run the project's verify/test command between waves to catch issues early
|
|
419
677
|
Follow all CLAUDE.md conventions (if present).
|
|
420
678
|
|
|
421
|
-
##
|
|
422
|
-
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
-
|
|
679
|
+
## PR Lifecycle
|
|
680
|
+
- The controller owns PR lifecycle and labels for this branch
|
|
681
|
+
- If a draft PR already exists, do NOT create another one and do NOT edit its labels
|
|
682
|
+
- If no PR exists yet, do NOT create one manually; keep pushing to ${BRANCH_NAME} and the controller will open/update it automatically
|
|
683
|
+
- After each completed phase/wave milestone, commit and push progress to the existing branch:
|
|
684
|
+
${PROGRESS_PUSH_CMD}
|
|
685
|
+
- When all implementation is complete, run final verification (lint, typecheck, tests). If anything fails, fix it, commit, and push again.
|
|
428
686
|
- STOP immediately after the final push — do NOT do any additional work, visual checks, or exploration.
|
|
429
687
|
- Do NOT process any other issues — only issue #${ISSUE_NUMBER}"
|
|
430
688
|
else
|
|
@@ -447,11 +705,13 @@ Read ${EXECUTOR_PROMPT_REF} and follow the FULL execution pipeline:
|
|
|
447
705
|
5. Run the project's verify/test command between waves to catch issues early
|
|
448
706
|
Follow all CLAUDE.md conventions (if present).
|
|
449
707
|
|
|
450
|
-
##
|
|
451
|
-
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
- After
|
|
708
|
+
## PR Lifecycle
|
|
709
|
+
- The controller owns PR lifecycle and labels for this branch
|
|
710
|
+
- If a draft PR already exists, do NOT create another one and do NOT edit its labels
|
|
711
|
+
- If no PR exists yet, do NOT create one manually; keep pushing to ${BRANCH_NAME} and the controller will open/update it automatically
|
|
712
|
+
- After each completed phase/wave milestone, commit and push progress to the existing branch:
|
|
713
|
+
${PROGRESS_PUSH_CMD}
|
|
714
|
+
- When all implementation is complete, run final verification (lint, typecheck, tests). If anything fails, fix it, commit, and push again.
|
|
455
715
|
- STOP immediately after the final push — do NOT do any additional work, visual checks, or exploration.
|
|
456
716
|
- Do NOT move the PRD to done/ — the cron script handles that
|
|
457
717
|
- Do NOT process any other PRDs — only ${ELIGIBLE_PRD}"
|
|
@@ -507,6 +767,19 @@ if ! assert_isolated_worktree "${PROJECT_DIR}" "${WORKTREE_DIR}" "executor"; the
|
|
|
507
767
|
exit 1
|
|
508
768
|
fi
|
|
509
769
|
|
|
770
|
+
if ! ensure_executor_pr; then
|
|
771
|
+
log "FAIL: Unable to create or reuse executor PR for ${BRANCH_NAME}"
|
|
772
|
+
restore_issue_to_ready "Failed to create or reuse the draft PR for branch ${BRANCH_NAME}. Moved back to Ready for retry."
|
|
773
|
+
night_watch_history record "${PROJECT_DIR}" "${ELIGIBLE_PRD}" failure --exit-code 1 2>/dev/null || true
|
|
774
|
+
emit_result "failure" "prd=${ELIGIBLE_PRD}|branch=${BRANCH_NAME}|reason=pr_setup_failed|detail=$(latest_failure_detail "${LOG_FILE}")"
|
|
775
|
+
exit 1
|
|
776
|
+
fi
|
|
777
|
+
|
|
778
|
+
if [ -n "${ISSUE_NUMBER}" ] && [ -n "${NW_CLI}" ] && [ -n "${EXECUTOR_PR_URL}" ] && [ "${RESUME_FROM_EXISTING_PR}" != "1" ]; then
|
|
779
|
+
"${NW_CLI}" board comment "${ISSUE_NUMBER}" \
|
|
780
|
+
--body "Draft PR opened at executor start: ${EXECUTOR_PR_URL} (labels: \`${NW_EXECUTOR_PARTIAL_LABEL}\`, \`${NW_EXECUTOR_RESUMABLE_LABEL}\`)." 2>>"${LOG_FILE}" || true
|
|
781
|
+
fi
|
|
782
|
+
|
|
510
783
|
# Sandbox: prevent the agent from modifying crontab during execution
|
|
511
784
|
export NW_EXECUTION_CONTEXT=agent
|
|
512
785
|
|
|
@@ -567,6 +840,15 @@ while [ "${ATTEMPT}" -lt "${MAX_RETRIES}" ]; do
|
|
|
567
840
|
BACKOFF_MIN=$(( BACKOFF / 60 ))
|
|
568
841
|
log "RATE-LIMITED: Attempt ${ATTEMPT}/${MAX_RETRIES}, retrying in ${BACKOFF_MIN}m"
|
|
569
842
|
sleep "${BACKOFF}"
|
|
843
|
+
elif check_network_error "${LOG_FILE}" "${LOG_LINE_BEFORE}"; then
|
|
844
|
+
# Transient API network error — retry with a short backoff
|
|
845
|
+
ATTEMPT=$((ATTEMPT + 1))
|
|
846
|
+
if [ "${ATTEMPT}" -ge "${MAX_RETRIES}" ]; then
|
|
847
|
+
log "NETWORK-ERROR: All ${MAX_RETRIES} attempts exhausted for ${ELIGIBLE_PRD}"
|
|
848
|
+
break
|
|
849
|
+
fi
|
|
850
|
+
log "NETWORK-ERROR: Attempt ${ATTEMPT}/${MAX_RETRIES}, retrying in 60s"
|
|
851
|
+
sleep 60
|
|
570
852
|
elif check_context_exhausted "${LOG_FILE}" "${LOG_LINE_BEFORE}"; then
|
|
571
853
|
# Context window exhausted — checkpoint progress and resume in a fresh session
|
|
572
854
|
ATTEMPT=$((ATTEMPT + 1))
|
|
@@ -576,7 +858,8 @@ while [ "${ATTEMPT}" -lt "${MAX_RETRIES}" ]; do
|
|
|
576
858
|
fi
|
|
577
859
|
log "CONTEXT-EXHAUSTED: Session ${ATTEMPT_NUM} hit context limit — checkpointing and resuming (${ATTEMPT}/${MAX_RETRIES})"
|
|
578
860
|
checkpoint_timeout_progress "${WORKTREE_DIR}" "${BRANCH_NAME}" "${ELIGIBLE_PRD}"
|
|
579
|
-
|
|
861
|
+
push_executor_branch "update" >> "${LOG_FILE}" 2>&1 || true
|
|
862
|
+
ensure_executor_pr >> "${LOG_FILE}" 2>&1 || true
|
|
580
863
|
# Switch prompt to "continue" mode for the next attempt (fresh context)
|
|
581
864
|
if [ -n "${ISSUE_NUMBER}" ]; then
|
|
582
865
|
PROMPT="Continue implementing PRD (GitHub issue #${ISSUE_NUMBER}: ${ISSUE_TITLE_RAW}).
|
|
@@ -599,13 +882,13 @@ The previous session ran out of context window. Progress has been committed on b
|
|
|
599
882
|
Read ${EXECUTOR_PROMPT_REF} and follow the FULL execution pipeline for remaining phases only.
|
|
600
883
|
Follow all CLAUDE.md conventions (if present).
|
|
601
884
|
|
|
602
|
-
##
|
|
603
|
-
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
-
|
|
885
|
+
## PR Lifecycle
|
|
886
|
+
- The controller owns PR lifecycle and labels for this branch
|
|
887
|
+
- If a draft PR already exists, do NOT create another one and do NOT edit its labels
|
|
888
|
+
- If no PR exists yet, do NOT create one manually; keep pushing to ${BRANCH_NAME} and the controller will open/update it automatically
|
|
889
|
+
- After each completed phase/wave milestone, commit and push progress to the existing branch:
|
|
890
|
+
${PROGRESS_PUSH_CMD}
|
|
891
|
+
- When all implementation is complete, run final verification (lint, typecheck, tests). If anything fails, fix it, commit, and push again.
|
|
609
892
|
- STOP immediately after the final push — do NOT do any additional work, visual checks, or exploration.
|
|
610
893
|
- Do NOT process any other issues — only issue #${ISSUE_NUMBER}"
|
|
611
894
|
else
|
|
@@ -629,11 +912,13 @@ The previous session ran out of context window. Progress has been committed on b
|
|
|
629
912
|
Read ${EXECUTOR_PROMPT_REF} and follow the FULL execution pipeline for remaining phases only.
|
|
630
913
|
Follow all CLAUDE.md conventions (if present).
|
|
631
914
|
|
|
632
|
-
##
|
|
633
|
-
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
- After
|
|
915
|
+
## PR Lifecycle
|
|
916
|
+
- The controller owns PR lifecycle and labels for this branch
|
|
917
|
+
- If a draft PR already exists, do NOT create another one and do NOT edit its labels
|
|
918
|
+
- If no PR exists yet, do NOT create one manually; keep pushing to ${BRANCH_NAME} and the controller will open/update it automatically
|
|
919
|
+
- After each completed phase/wave milestone, commit and push progress to the existing branch:
|
|
920
|
+
${PROGRESS_PUSH_CMD}
|
|
921
|
+
- When all implementation is complete, run final verification (lint, typecheck, tests). If anything fails, fix it, commit, and push again.
|
|
637
922
|
- STOP immediately after the final push — do NOT do any additional work, visual checks, or exploration.
|
|
638
923
|
- Do NOT move the PRD to done/ — the cron script handles that
|
|
639
924
|
- Do NOT process any other PRDs — only ${ELIGIBLE_PRD}"
|
|
@@ -793,9 +1078,20 @@ if [ "${EXIT_CODE}" -eq 0 ] && grep -qiF 'Exceeded USD budget' "${LOG_FILE}" 2>/
|
|
|
793
1078
|
EXIT_CODE=1
|
|
794
1079
|
fi
|
|
795
1080
|
|
|
1081
|
+
if [ ${EXIT_CODE} -eq 0 ]; then
|
|
1082
|
+
if ! ensure_executor_pr; then
|
|
1083
|
+
log "FAIL: Unable to create or reuse executor PR for ${BRANCH_NAME} after provider completion"
|
|
1084
|
+
night_watch_history record "${PROJECT_DIR}" "${ELIGIBLE_PRD}" failure --exit-code 1 2>/dev/null || true
|
|
1085
|
+
emit_result "failure" "prd=${ELIGIBLE_PRD}|branch=${BRANCH_NAME}|reason=pr_setup_failed|detail=$(latest_failure_detail "${LOG_FILE}")"
|
|
1086
|
+
EXIT_CODE=1
|
|
1087
|
+
fi
|
|
1088
|
+
fi
|
|
1089
|
+
|
|
796
1090
|
if [ ${EXIT_CODE} -eq 0 ]; then
|
|
797
1091
|
OPEN_PR_COUNT=$(count_prs_for_branch open "${BRANCH_NAME}")
|
|
798
1092
|
if [ "${OPEN_PR_COUNT}" -gt 0 ]; then
|
|
1093
|
+
refresh_executor_pr_metadata
|
|
1094
|
+
mark_executor_pr_ready_for_review || true
|
|
799
1095
|
if [ -n "${ISSUE_NUMBER}" ]; then
|
|
800
1096
|
# Board mode: comment with PR URL, then close issue and move to Done
|
|
801
1097
|
PR_URL=$(gh pr list --state open --json headRefName,url \
|
|
@@ -851,6 +1147,8 @@ if [ ${EXIT_CODE} -eq 0 ]; then
|
|
|
851
1147
|
elif [ ${EXIT_CODE} -eq 124 ]; then
|
|
852
1148
|
log "TIMEOUT: Session limit hit after ${SESSION_MAX_RUNTIME}s while processing ${ELIGIBLE_PRD}"
|
|
853
1149
|
checkpoint_timeout_progress "${WORKTREE_DIR}" "${BRANCH_NAME}" "${ELIGIBLE_PRD}"
|
|
1150
|
+
push_executor_branch "update" >> "${LOG_FILE}" 2>&1 || true
|
|
1151
|
+
ensure_executor_pr >> "${LOG_FILE}" 2>&1 || true
|
|
854
1152
|
if [ -n "${ISSUE_NUMBER}" ]; then
|
|
855
1153
|
"${NW_CLI}" board move-issue "${ISSUE_NUMBER}" --column "Ready" 2>>"${LOG_FILE}" || true
|
|
856
1154
|
if [ "${SESSION_MAX_RUNTIME}" != "${MAX_RUNTIME}" ]; then
|
|
@@ -881,7 +1179,8 @@ elif check_context_exhausted "${LOG_FILE}" "${LOG_LINE_BEFORE}"; then
|
|
|
881
1179
|
# All resume attempts for context exhaustion were used up
|
|
882
1180
|
log "FAIL: Context window exhausted after ${MAX_RETRIES} resume attempts for ${ELIGIBLE_PRD}"
|
|
883
1181
|
checkpoint_timeout_progress "${WORKTREE_DIR}" "${BRANCH_NAME}" "${ELIGIBLE_PRD}"
|
|
884
|
-
|
|
1182
|
+
push_executor_branch "update" >> "${LOG_FILE}" 2>&1 || true
|
|
1183
|
+
ensure_executor_pr >> "${LOG_FILE}" 2>&1 || true
|
|
885
1184
|
if [ -n "${ISSUE_NUMBER}" ]; then
|
|
886
1185
|
"${NW_CLI}" board move-issue "${ISSUE_NUMBER}" --column "Ready" 2>>"${LOG_FILE}" || true
|
|
887
1186
|
"${NW_CLI}" board comment "${ISSUE_NUMBER}" \
|