@jonit-dev/night-watch-cli 1.8.10-beta.0 → 1.8.10-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +2501 -1387
- package/dist/commands/dashboard/tab-config.d.ts.map +1 -1
- package/dist/commands/queue.d.ts.map +1 -1
- package/dist/commands/shared/env-builder.d.ts.map +1 -1
- package/dist/scripts/night-watch-cron.sh +344 -53
- package/dist/scripts/night-watch-helpers.sh +208 -7
- package/dist/scripts/night-watch-merger-cron.sh +8 -2
- package/dist/scripts/night-watch-plan-cron.sh +1 -1
- package/dist/scripts/night-watch-pr-resolver-cron.sh +7 -3
- package/dist/scripts/night-watch-pr-reviewer-cron.sh +11 -8
- package/dist/scripts/night-watch-qa-cron.sh +8 -3
- 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 -363
- 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;
|
|
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"}
|
|
@@ -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
|
|
@@ -250,6 +311,194 @@ count_prs_for_branch() {
|
|
|
250
311
|
echo "${count:-0}"
|
|
251
312
|
}
|
|
252
313
|
|
|
314
|
+
extract_prd_title() {
|
|
315
|
+
local prd_path=""
|
|
316
|
+
local title=""
|
|
317
|
+
|
|
318
|
+
if [ -n "${ISSUE_TITLE_RAW}" ]; then
|
|
319
|
+
printf '%s' "${ISSUE_TITLE_RAW}"
|
|
320
|
+
return 0
|
|
321
|
+
fi
|
|
322
|
+
|
|
323
|
+
if [ -f "${PRD_DIR}/${ELIGIBLE_PRD}" ]; then
|
|
324
|
+
prd_path="${PRD_DIR}/${ELIGIBLE_PRD}"
|
|
325
|
+
elif [ -f "${PROJECT_DIR}/${PRD_DIR_REL}/${ELIGIBLE_PRD}" ]; then
|
|
326
|
+
prd_path="${PROJECT_DIR}/${PRD_DIR_REL}/${ELIGIBLE_PRD}"
|
|
327
|
+
fi
|
|
328
|
+
|
|
329
|
+
if [ -n "${prd_path}" ]; then
|
|
330
|
+
title=$(awk '/^[[:space:]]*#[[:space:]]+/ { sub(/^[[:space:]]*#[[:space:]]+/, "", $0); print; exit }' "${prd_path}" 2>/dev/null || true)
|
|
331
|
+
fi
|
|
332
|
+
|
|
333
|
+
if [ -n "${title}" ]; then
|
|
334
|
+
printf '%s' "${title}"
|
|
335
|
+
else
|
|
336
|
+
printf '%s' "${PRD_NAME}"
|
|
337
|
+
fi
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
build_executor_pr_title() {
|
|
341
|
+
local raw_title=""
|
|
342
|
+
|
|
343
|
+
raw_title=$(extract_prd_title)
|
|
344
|
+
raw_title=$(printf '%s' "${raw_title}" | tr '\r\n' ' ' | sed -E 's/[[:space:]]+/ /g; s/^[[:space:]]+//; s/[[:space:]]+$//')
|
|
345
|
+
if [ -z "${raw_title}" ]; then
|
|
346
|
+
raw_title="${PRD_NAME}"
|
|
347
|
+
fi
|
|
348
|
+
|
|
349
|
+
if printf '%s' "${raw_title}" | grep -Eqi '^feat:'; then
|
|
350
|
+
printf '%s' "${raw_title}"
|
|
351
|
+
else
|
|
352
|
+
printf 'feat: %s' "${raw_title}"
|
|
353
|
+
fi
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
build_executor_pr_body() {
|
|
357
|
+
local status_blurb=""
|
|
358
|
+
|
|
359
|
+
status_blurb="Status labels:
|
|
360
|
+
- ${NW_EXECUTOR_PARTIAL_LABEL}: implementation is in progress and intentionally incomplete
|
|
361
|
+
- ${NW_EXECUTOR_RESUMABLE_LABEL}: resume this PR before starting new work
|
|
362
|
+
- ${NW_EXECUTOR_READY_REVIEW_LABEL}: implementation is complete and ready for review"
|
|
363
|
+
|
|
364
|
+
if [ -n "${ISSUE_NUMBER}" ]; then
|
|
365
|
+
printf 'Closes #%s\n\nNight Watch manages this draft PR automatically so progress is preserved across retries and timeouts.\n\n%s\n' \
|
|
366
|
+
"${ISSUE_NUMBER}" \
|
|
367
|
+
"${status_blurb}"
|
|
368
|
+
else
|
|
369
|
+
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' \
|
|
370
|
+
"${PRD_DIR_REL}" \
|
|
371
|
+
"${ELIGIBLE_PRD}" \
|
|
372
|
+
"${status_blurb}"
|
|
373
|
+
fi
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
refresh_executor_pr_metadata() {
|
|
377
|
+
EXECUTOR_PR_JSON=$(find_open_pr_for_branch "${BRANCH_NAME}" || true)
|
|
378
|
+
EXECUTOR_PR_NUMBER=$(printf '%s' "${EXECUTOR_PR_JSON}" | jq -r '.number // empty' 2>/dev/null || true)
|
|
379
|
+
EXECUTOR_PR_URL=$(printf '%s' "${EXECUTOR_PR_JSON}" | jq -r '.url // empty' 2>/dev/null || true)
|
|
380
|
+
EXECUTOR_PR_DRAFT=$(printf '%s' "${EXECUTOR_PR_JSON}" | jq -r '.isDraft // false' 2>/dev/null || true)
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
sync_executor_pr_status() {
|
|
384
|
+
local add_labels="${1:-}"
|
|
385
|
+
local remove_labels="${2:-}"
|
|
386
|
+
local mark_ready="${3:-0}"
|
|
387
|
+
|
|
388
|
+
if [ -z "${EXECUTOR_PR_NUMBER}" ]; then
|
|
389
|
+
return 1
|
|
390
|
+
fi
|
|
391
|
+
|
|
392
|
+
ensure_executor_status_labels
|
|
393
|
+
|
|
394
|
+
if [ -n "${add_labels}" ]; then
|
|
395
|
+
gh pr edit "${EXECUTOR_PR_NUMBER}" --add-label "${add_labels}" >> "${LOG_FILE}" 2>&1 || true
|
|
396
|
+
fi
|
|
397
|
+
if [ -n "${remove_labels}" ]; then
|
|
398
|
+
gh pr edit "${EXECUTOR_PR_NUMBER}" --remove-label "${remove_labels}" >> "${LOG_FILE}" 2>&1 || true
|
|
399
|
+
fi
|
|
400
|
+
if [ "${mark_ready}" = "1" ]; then
|
|
401
|
+
gh pr ready "${EXECUTOR_PR_NUMBER}" >> "${LOG_FILE}" 2>&1 || true
|
|
402
|
+
fi
|
|
403
|
+
|
|
404
|
+
refresh_executor_pr_metadata
|
|
405
|
+
return 0
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
mark_executor_pr_incomplete() {
|
|
409
|
+
sync_executor_pr_status \
|
|
410
|
+
"${NW_EXECUTOR_PARTIAL_LABEL},${NW_EXECUTOR_RESUMABLE_LABEL}" \
|
|
411
|
+
"${NW_EXECUTOR_READY_REVIEW_LABEL}" \
|
|
412
|
+
"0"
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
mark_executor_pr_ready_for_review() {
|
|
416
|
+
sync_executor_pr_status \
|
|
417
|
+
"${NW_EXECUTOR_READY_REVIEW_LABEL}" \
|
|
418
|
+
"${NW_EXECUTOR_PARTIAL_LABEL},${NW_EXECUTOR_RESUMABLE_LABEL}" \
|
|
419
|
+
"1"
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
push_executor_branch() {
|
|
423
|
+
local push_mode="${1:-update}"
|
|
424
|
+
|
|
425
|
+
if [ "${push_mode}" = "initial" ]; then
|
|
426
|
+
if git_push_for_project "${WORKTREE_DIR}" -u origin "${BRANCH_NAME}" >> "${LOG_FILE}" 2>&1; then
|
|
427
|
+
return 0
|
|
428
|
+
fi
|
|
429
|
+
fi
|
|
430
|
+
|
|
431
|
+
if git_push_for_project "${WORKTREE_DIR}" origin "${BRANCH_NAME}" --force-with-lease >> "${LOG_FILE}" 2>&1; then
|
|
432
|
+
return 0
|
|
433
|
+
fi
|
|
434
|
+
|
|
435
|
+
git_push_for_project "${WORKTREE_DIR}" -u origin "${BRANCH_NAME}" >> "${LOG_FILE}" 2>&1
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
executor_branch_has_commits_ahead_of_base() {
|
|
439
|
+
local base_ref=""
|
|
440
|
+
local ahead_count="0"
|
|
441
|
+
|
|
442
|
+
if ! base_ref=$(resolve_worktree_base_ref "${WORKTREE_DIR}" "${DEFAULT_BRANCH}" 2>/dev/null); then
|
|
443
|
+
return 1
|
|
444
|
+
fi
|
|
445
|
+
|
|
446
|
+
ahead_count=$(git -C "${WORKTREE_DIR}" rev-list --count "${base_ref}..HEAD" 2>/dev/null || echo "0")
|
|
447
|
+
[ "${ahead_count}" -gt 0 ]
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
ensure_executor_pr() {
|
|
451
|
+
local pr_title=""
|
|
452
|
+
local pr_body=""
|
|
453
|
+
local create_output=""
|
|
454
|
+
|
|
455
|
+
refresh_executor_pr_metadata
|
|
456
|
+
if [ -n "${EXECUTOR_PR_NUMBER}" ]; then
|
|
457
|
+
log "PR: Reusing existing open PR #${EXECUTOR_PR_NUMBER} for ${BRANCH_NAME}"
|
|
458
|
+
mark_executor_pr_incomplete
|
|
459
|
+
return 0
|
|
460
|
+
fi
|
|
461
|
+
|
|
462
|
+
pr_title=$(build_executor_pr_title)
|
|
463
|
+
pr_body=$(build_executor_pr_body)
|
|
464
|
+
|
|
465
|
+
if ! executor_branch_has_commits_ahead_of_base; then
|
|
466
|
+
log "PR: Deferring draft PR creation for ${BRANCH_NAME} until it has commits beyond ${DEFAULT_BRANCH}"
|
|
467
|
+
return 0
|
|
468
|
+
fi
|
|
469
|
+
|
|
470
|
+
log "PR: Creating draft PR for ${BRANCH_NAME}"
|
|
471
|
+
if ! push_executor_branch "initial"; then
|
|
472
|
+
log "WARN: Initial push for ${BRANCH_NAME} failed before PR creation"
|
|
473
|
+
fi
|
|
474
|
+
|
|
475
|
+
ensure_executor_status_labels
|
|
476
|
+
if ! create_output=$(
|
|
477
|
+
gh pr create \
|
|
478
|
+
--draft \
|
|
479
|
+
--base "${DEFAULT_BRANCH}" \
|
|
480
|
+
--head "${BRANCH_NAME}" \
|
|
481
|
+
--title "${pr_title}" \
|
|
482
|
+
--body "${pr_body}" 2>> "${LOG_FILE}"
|
|
483
|
+
); then
|
|
484
|
+
log "FAIL: gh pr create failed for ${BRANCH_NAME}"
|
|
485
|
+
return 1
|
|
486
|
+
fi
|
|
487
|
+
|
|
488
|
+
refresh_executor_pr_metadata
|
|
489
|
+
if [ -z "${EXECUTOR_PR_URL}" ]; then
|
|
490
|
+
EXECUTOR_PR_URL=$(printf '%s' "${create_output}" | grep -Eo 'https://[^[:space:]]+/pull/[0-9]+' | tail -n 1 || true)
|
|
491
|
+
fi
|
|
492
|
+
if [ -n "${EXECUTOR_PR_NUMBER}" ]; then
|
|
493
|
+
mark_executor_pr_incomplete
|
|
494
|
+
log "PR: Draft PR ready at ${EXECUTOR_PR_URL:-unknown} for ${BRANCH_NAME}"
|
|
495
|
+
else
|
|
496
|
+
log "WARN: gh pr create succeeded for ${BRANCH_NAME}, but PR metadata lookup did not resolve a number yet"
|
|
497
|
+
fi
|
|
498
|
+
|
|
499
|
+
return 0
|
|
500
|
+
}
|
|
501
|
+
|
|
253
502
|
checkpoint_timeout_progress() {
|
|
254
503
|
local worktree_dir="${1:?worktree_dir required}"
|
|
255
504
|
local branch_name="${2:?branch_name required}"
|
|
@@ -360,7 +609,7 @@ finalize_prd_done() {
|
|
|
360
609
|
git -C "${BOOKKEEP_WORKTREE_DIR}" commit -m "chore: mark ${ELIGIBLE_PRD} as done (${reason})
|
|
361
610
|
|
|
362
611
|
Co-Authored-By: Night Watch [${EFFECTIVE_PROVIDER_LABEL}] <noreply@anthropic.com>" || true
|
|
363
|
-
|
|
612
|
+
git_push_for_project "${BOOKKEEP_WORKTREE_DIR}" origin "HEAD:${DEFAULT_BRANCH}" || true
|
|
364
613
|
log "DONE: ${ELIGIBLE_PRD} ${reason}, PRD moved to done/"
|
|
365
614
|
return 0
|
|
366
615
|
fi
|
|
@@ -396,6 +645,7 @@ if [ -z "${EXECUTOR_PROMPT_PATH}" ]; then
|
|
|
396
645
|
exit 1
|
|
397
646
|
fi
|
|
398
647
|
EXECUTOR_PROMPT_REF=$(instruction_ref_for_prompt "${PROJECT_DIR}" "${EXECUTOR_PROMPT_PATH}")
|
|
648
|
+
PROGRESS_PUSH_CMD=$(project_git_push_command "${BRANCH_NAME}")
|
|
399
649
|
|
|
400
650
|
if [ -n "${ISSUE_NUMBER}" ]; then
|
|
401
651
|
PROMPT="Implement the following PRD (GitHub issue #${ISSUE_NUMBER}: ${ISSUE_TITLE_RAW}):
|
|
@@ -418,13 +668,13 @@ Read ${EXECUTOR_PROMPT_REF} and follow the FULL execution pipeline:
|
|
|
418
668
|
5. Run the project's verify/test command between waves to catch issues early
|
|
419
669
|
Follow all CLAUDE.md conventions (if present).
|
|
420
670
|
|
|
421
|
-
##
|
|
422
|
-
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
-
|
|
671
|
+
## PR Lifecycle
|
|
672
|
+
- The controller owns PR lifecycle and labels for this branch
|
|
673
|
+
- If a draft PR already exists, do NOT create another one and do NOT edit its labels
|
|
674
|
+
- If no PR exists yet, do NOT create one manually; keep pushing to ${BRANCH_NAME} and the controller will open/update it automatically
|
|
675
|
+
- After each completed phase/wave milestone, commit and push progress to the existing branch:
|
|
676
|
+
${PROGRESS_PUSH_CMD}
|
|
677
|
+
- When all implementation is complete, run final verification (lint, typecheck, tests). If anything fails, fix it, commit, and push again.
|
|
428
678
|
- STOP immediately after the final push — do NOT do any additional work, visual checks, or exploration.
|
|
429
679
|
- Do NOT process any other issues — only issue #${ISSUE_NUMBER}"
|
|
430
680
|
else
|
|
@@ -447,11 +697,13 @@ Read ${EXECUTOR_PROMPT_REF} and follow the FULL execution pipeline:
|
|
|
447
697
|
5. Run the project's verify/test command between waves to catch issues early
|
|
448
698
|
Follow all CLAUDE.md conventions (if present).
|
|
449
699
|
|
|
450
|
-
##
|
|
451
|
-
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
- After
|
|
700
|
+
## PR Lifecycle
|
|
701
|
+
- The controller owns PR lifecycle and labels for this branch
|
|
702
|
+
- If a draft PR already exists, do NOT create another one and do NOT edit its labels
|
|
703
|
+
- If no PR exists yet, do NOT create one manually; keep pushing to ${BRANCH_NAME} and the controller will open/update it automatically
|
|
704
|
+
- After each completed phase/wave milestone, commit and push progress to the existing branch:
|
|
705
|
+
${PROGRESS_PUSH_CMD}
|
|
706
|
+
- When all implementation is complete, run final verification (lint, typecheck, tests). If anything fails, fix it, commit, and push again.
|
|
455
707
|
- STOP immediately after the final push — do NOT do any additional work, visual checks, or exploration.
|
|
456
708
|
- Do NOT move the PRD to done/ — the cron script handles that
|
|
457
709
|
- Do NOT process any other PRDs — only ${ELIGIBLE_PRD}"
|
|
@@ -507,6 +759,19 @@ if ! assert_isolated_worktree "${PROJECT_DIR}" "${WORKTREE_DIR}" "executor"; the
|
|
|
507
759
|
exit 1
|
|
508
760
|
fi
|
|
509
761
|
|
|
762
|
+
if ! ensure_executor_pr; then
|
|
763
|
+
log "FAIL: Unable to create or reuse executor PR for ${BRANCH_NAME}"
|
|
764
|
+
restore_issue_to_ready "Failed to create or reuse the draft PR for branch ${BRANCH_NAME}. Moved back to Ready for retry."
|
|
765
|
+
night_watch_history record "${PROJECT_DIR}" "${ELIGIBLE_PRD}" failure --exit-code 1 2>/dev/null || true
|
|
766
|
+
emit_result "failure" "prd=${ELIGIBLE_PRD}|branch=${BRANCH_NAME}|reason=pr_setup_failed|detail=$(latest_failure_detail "${LOG_FILE}")"
|
|
767
|
+
exit 1
|
|
768
|
+
fi
|
|
769
|
+
|
|
770
|
+
if [ -n "${ISSUE_NUMBER}" ] && [ -n "${NW_CLI}" ] && [ -n "${EXECUTOR_PR_URL}" ] && [ "${RESUME_FROM_EXISTING_PR}" != "1" ]; then
|
|
771
|
+
"${NW_CLI}" board comment "${ISSUE_NUMBER}" \
|
|
772
|
+
--body "Draft PR opened at executor start: ${EXECUTOR_PR_URL} (labels: \`${NW_EXECUTOR_PARTIAL_LABEL}\`, \`${NW_EXECUTOR_RESUMABLE_LABEL}\`)." 2>>"${LOG_FILE}" || true
|
|
773
|
+
fi
|
|
774
|
+
|
|
510
775
|
# Sandbox: prevent the agent from modifying crontab during execution
|
|
511
776
|
export NW_EXECUTION_CONTEXT=agent
|
|
512
777
|
|
|
@@ -567,6 +832,15 @@ while [ "${ATTEMPT}" -lt "${MAX_RETRIES}" ]; do
|
|
|
567
832
|
BACKOFF_MIN=$(( BACKOFF / 60 ))
|
|
568
833
|
log "RATE-LIMITED: Attempt ${ATTEMPT}/${MAX_RETRIES}, retrying in ${BACKOFF_MIN}m"
|
|
569
834
|
sleep "${BACKOFF}"
|
|
835
|
+
elif check_network_error "${LOG_FILE}" "${LOG_LINE_BEFORE}"; then
|
|
836
|
+
# Transient API network error — retry with a short backoff
|
|
837
|
+
ATTEMPT=$((ATTEMPT + 1))
|
|
838
|
+
if [ "${ATTEMPT}" -ge "${MAX_RETRIES}" ]; then
|
|
839
|
+
log "NETWORK-ERROR: All ${MAX_RETRIES} attempts exhausted for ${ELIGIBLE_PRD}"
|
|
840
|
+
break
|
|
841
|
+
fi
|
|
842
|
+
log "NETWORK-ERROR: Attempt ${ATTEMPT}/${MAX_RETRIES}, retrying in 60s"
|
|
843
|
+
sleep 60
|
|
570
844
|
elif check_context_exhausted "${LOG_FILE}" "${LOG_LINE_BEFORE}"; then
|
|
571
845
|
# Context window exhausted — checkpoint progress and resume in a fresh session
|
|
572
846
|
ATTEMPT=$((ATTEMPT + 1))
|
|
@@ -576,7 +850,8 @@ while [ "${ATTEMPT}" -lt "${MAX_RETRIES}" ]; do
|
|
|
576
850
|
fi
|
|
577
851
|
log "CONTEXT-EXHAUSTED: Session ${ATTEMPT_NUM} hit context limit — checkpointing and resuming (${ATTEMPT}/${MAX_RETRIES})"
|
|
578
852
|
checkpoint_timeout_progress "${WORKTREE_DIR}" "${BRANCH_NAME}" "${ELIGIBLE_PRD}"
|
|
579
|
-
|
|
853
|
+
push_executor_branch "update" >> "${LOG_FILE}" 2>&1 || true
|
|
854
|
+
ensure_executor_pr >> "${LOG_FILE}" 2>&1 || true
|
|
580
855
|
# Switch prompt to "continue" mode for the next attempt (fresh context)
|
|
581
856
|
if [ -n "${ISSUE_NUMBER}" ]; then
|
|
582
857
|
PROMPT="Continue implementing PRD (GitHub issue #${ISSUE_NUMBER}: ${ISSUE_TITLE_RAW}).
|
|
@@ -599,13 +874,13 @@ The previous session ran out of context window. Progress has been committed on b
|
|
|
599
874
|
Read ${EXECUTOR_PROMPT_REF} and follow the FULL execution pipeline for remaining phases only.
|
|
600
875
|
Follow all CLAUDE.md conventions (if present).
|
|
601
876
|
|
|
602
|
-
##
|
|
603
|
-
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
-
|
|
877
|
+
## PR Lifecycle
|
|
878
|
+
- The controller owns PR lifecycle and labels for this branch
|
|
879
|
+
- If a draft PR already exists, do NOT create another one and do NOT edit its labels
|
|
880
|
+
- If no PR exists yet, do NOT create one manually; keep pushing to ${BRANCH_NAME} and the controller will open/update it automatically
|
|
881
|
+
- After each completed phase/wave milestone, commit and push progress to the existing branch:
|
|
882
|
+
${PROGRESS_PUSH_CMD}
|
|
883
|
+
- When all implementation is complete, run final verification (lint, typecheck, tests). If anything fails, fix it, commit, and push again.
|
|
609
884
|
- STOP immediately after the final push — do NOT do any additional work, visual checks, or exploration.
|
|
610
885
|
- Do NOT process any other issues — only issue #${ISSUE_NUMBER}"
|
|
611
886
|
else
|
|
@@ -629,11 +904,13 @@ The previous session ran out of context window. Progress has been committed on b
|
|
|
629
904
|
Read ${EXECUTOR_PROMPT_REF} and follow the FULL execution pipeline for remaining phases only.
|
|
630
905
|
Follow all CLAUDE.md conventions (if present).
|
|
631
906
|
|
|
632
|
-
##
|
|
633
|
-
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
- After
|
|
907
|
+
## PR Lifecycle
|
|
908
|
+
- The controller owns PR lifecycle and labels for this branch
|
|
909
|
+
- If a draft PR already exists, do NOT create another one and do NOT edit its labels
|
|
910
|
+
- If no PR exists yet, do NOT create one manually; keep pushing to ${BRANCH_NAME} and the controller will open/update it automatically
|
|
911
|
+
- After each completed phase/wave milestone, commit and push progress to the existing branch:
|
|
912
|
+
${PROGRESS_PUSH_CMD}
|
|
913
|
+
- When all implementation is complete, run final verification (lint, typecheck, tests). If anything fails, fix it, commit, and push again.
|
|
637
914
|
- STOP immediately after the final push — do NOT do any additional work, visual checks, or exploration.
|
|
638
915
|
- Do NOT move the PRD to done/ — the cron script handles that
|
|
639
916
|
- Do NOT process any other PRDs — only ${ELIGIBLE_PRD}"
|
|
@@ -793,9 +1070,20 @@ if [ "${EXIT_CODE}" -eq 0 ] && grep -qiF 'Exceeded USD budget' "${LOG_FILE}" 2>/
|
|
|
793
1070
|
EXIT_CODE=1
|
|
794
1071
|
fi
|
|
795
1072
|
|
|
1073
|
+
if [ ${EXIT_CODE} -eq 0 ]; then
|
|
1074
|
+
if ! ensure_executor_pr; then
|
|
1075
|
+
log "FAIL: Unable to create or reuse executor PR for ${BRANCH_NAME} after provider completion"
|
|
1076
|
+
night_watch_history record "${PROJECT_DIR}" "${ELIGIBLE_PRD}" failure --exit-code 1 2>/dev/null || true
|
|
1077
|
+
emit_result "failure" "prd=${ELIGIBLE_PRD}|branch=${BRANCH_NAME}|reason=pr_setup_failed|detail=$(latest_failure_detail "${LOG_FILE}")"
|
|
1078
|
+
EXIT_CODE=1
|
|
1079
|
+
fi
|
|
1080
|
+
fi
|
|
1081
|
+
|
|
796
1082
|
if [ ${EXIT_CODE} -eq 0 ]; then
|
|
797
1083
|
OPEN_PR_COUNT=$(count_prs_for_branch open "${BRANCH_NAME}")
|
|
798
1084
|
if [ "${OPEN_PR_COUNT}" -gt 0 ]; then
|
|
1085
|
+
refresh_executor_pr_metadata
|
|
1086
|
+
mark_executor_pr_ready_for_review || true
|
|
799
1087
|
if [ -n "${ISSUE_NUMBER}" ]; then
|
|
800
1088
|
# Board mode: comment with PR URL, then close issue and move to Done
|
|
801
1089
|
PR_URL=$(gh pr list --state open --json headRefName,url \
|
|
@@ -851,6 +1139,8 @@ if [ ${EXIT_CODE} -eq 0 ]; then
|
|
|
851
1139
|
elif [ ${EXIT_CODE} -eq 124 ]; then
|
|
852
1140
|
log "TIMEOUT: Session limit hit after ${SESSION_MAX_RUNTIME}s while processing ${ELIGIBLE_PRD}"
|
|
853
1141
|
checkpoint_timeout_progress "${WORKTREE_DIR}" "${BRANCH_NAME}" "${ELIGIBLE_PRD}"
|
|
1142
|
+
push_executor_branch "update" >> "${LOG_FILE}" 2>&1 || true
|
|
1143
|
+
ensure_executor_pr >> "${LOG_FILE}" 2>&1 || true
|
|
854
1144
|
if [ -n "${ISSUE_NUMBER}" ]; then
|
|
855
1145
|
"${NW_CLI}" board move-issue "${ISSUE_NUMBER}" --column "Ready" 2>>"${LOG_FILE}" || true
|
|
856
1146
|
if [ "${SESSION_MAX_RUNTIME}" != "${MAX_RUNTIME}" ]; then
|
|
@@ -881,7 +1171,8 @@ elif check_context_exhausted "${LOG_FILE}" "${LOG_LINE_BEFORE}"; then
|
|
|
881
1171
|
# All resume attempts for context exhaustion were used up
|
|
882
1172
|
log "FAIL: Context window exhausted after ${MAX_RETRIES} resume attempts for ${ELIGIBLE_PRD}"
|
|
883
1173
|
checkpoint_timeout_progress "${WORKTREE_DIR}" "${BRANCH_NAME}" "${ELIGIBLE_PRD}"
|
|
884
|
-
|
|
1174
|
+
push_executor_branch "update" >> "${LOG_FILE}" 2>&1 || true
|
|
1175
|
+
ensure_executor_pr >> "${LOG_FILE}" 2>&1 || true
|
|
885
1176
|
if [ -n "${ISSUE_NUMBER}" ]; then
|
|
886
1177
|
"${NW_CLI}" board move-issue "${ISSUE_NUMBER}" --column "Ready" 2>>"${LOG_FILE}" || true
|
|
887
1178
|
"${NW_CLI}" board comment "${ISSUE_NUMBER}" \
|