@jonit-dev/night-watch-cli 1.5.0 → 1.5.2
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 +6 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/cancel.d.ts +46 -0
- package/dist/commands/cancel.d.ts.map +1 -0
- package/dist/commands/cancel.js +239 -0
- package/dist/commands/cancel.js.map +1 -0
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +101 -58
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/history.d.ts +7 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +56 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +11 -73
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install.d.ts +11 -0
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +47 -11
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/prds.d.ts +13 -0
- package/dist/commands/prds.d.ts.map +1 -0
- package/dist/commands/prds.js +192 -0
- package/dist/commands/prds.js.map +1 -0
- package/dist/commands/prs.d.ts +13 -0
- package/dist/commands/prs.d.ts.map +1 -0
- package/dist/commands/prs.js +101 -0
- package/dist/commands/prs.js.map +1 -0
- package/dist/commands/retry.d.ts +9 -0
- package/dist/commands/retry.d.ts.map +1 -0
- package/dist/commands/retry.js +72 -0
- package/dist/commands/retry.js.map +1 -0
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +6 -0
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +11 -0
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/update.d.ts +21 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +87 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +36 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +4 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +7 -0
- package/dist/constants.js.map +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/crontab.d.ts.map +1 -1
- package/dist/utils/crontab.js +4 -0
- package/dist/utils/crontab.js.map +1 -1
- package/dist/utils/execution-history.d.ts +48 -0
- package/dist/utils/execution-history.d.ts.map +1 -0
- package/dist/utils/execution-history.js +183 -0
- package/dist/utils/execution-history.js.map +1 -0
- package/package.json +1 -1
- package/scripts/night-watch-cron.sh +142 -55
- package/scripts/night-watch-helpers.sh +189 -1
- package/scripts/night-watch-pr-reviewer-cron.sh +64 -15
- package/templates/night-watch-pr-reviewer.md +7 -11
- package/templates/night-watch.md +9 -20
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGlF,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAGzC,eAAO,MAAM,eAAe,0BAA0B,CAAC;AAGvD,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAGjD,eAAO,MAAM,qBAAqB,iBAAiB,CAAC;AACpD,eAAO,MAAM,yBAAyB,gCAAgC,CAAC;AAGvE,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AACnD,eAAO,MAAM,uBAAuB,UAA4B,CAAC;AAGjE,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAG3C,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAG3C,eAAO,MAAM,gBAAgB,EAAE,QAAmB,CAAC;AACnD,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,CAAC;AAG/D,eAAO,MAAM,qBAAqB,EAAE,mBAAsC,CAAC;AAG3E,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAAO,CAAC;AAGjD,eAAO,MAAM,uBAAuB,EAAE,qBAIrC,CAAC;AAGF,eAAO,MAAM,eAAe,EAAE,QAAQ,EAAwB,CAAC;AAG/D,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAGtD,CAAC;AAGF,eAAO,MAAM,gBAAgB,4BAA4B,CAAC;AAC1D,eAAO,MAAM,gBAAgB,sBAAsB,CAAC;AACpD,eAAO,MAAM,OAAO,SAAS,CAAC;AAC9B,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAG7C,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAChD,eAAO,MAAM,kBAAkB,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGlF,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAGzC,eAAO,MAAM,eAAe,0BAA0B,CAAC;AAGvD,eAAO,MAAM,mBAAmB,OAAO,CAAC;AACxC,eAAO,MAAM,4BAA4B,OAAO,CAAC;AAGjD,eAAO,MAAM,qBAAqB,iBAAiB,CAAC;AACpD,eAAO,MAAM,yBAAyB,gCAAgC,CAAC;AAGvE,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAG9C,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAGrC,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AACnD,eAAO,MAAM,uBAAuB,UAA4B,CAAC;AAGjE,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAG3C,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAG3C,eAAO,MAAM,gBAAgB,EAAE,QAAmB,CAAC;AACnD,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,CAAC;AAG/D,eAAO,MAAM,qBAAqB,EAAE,mBAAsC,CAAC;AAG3E,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAAO,CAAC;AAGjD,eAAO,MAAM,uBAAuB,EAAE,qBAIrC,CAAC;AAGF,eAAO,MAAM,eAAe,EAAE,QAAQ,EAAwB,CAAC;AAG/D,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAGtD,CAAC;AAGF,eAAO,MAAM,gBAAgB,4BAA4B,CAAC;AAC1D,eAAO,MAAM,gBAAgB,sBAAsB,CAAC;AACpD,eAAO,MAAM,OAAO,SAAS,CAAC;AAC9B,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAG7C,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAChD,eAAO,MAAM,kBAAkB,kBAAkB,CAAC;AAClD,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAGhD,eAAO,MAAM,2BAA2B,KAAK,CAAC"}
|
package/dist/constants.js
CHANGED
|
@@ -11,6 +11,10 @@ export const DEFAULT_REVIEWER_MAX_RUNTIME = 3600;
|
|
|
11
11
|
// Cron Schedule Configuration
|
|
12
12
|
export const DEFAULT_CRON_SCHEDULE = "0 0-21 * * *";
|
|
13
13
|
export const DEFAULT_REVIEWER_SCHEDULE = "0 0,3,6,9,12,15,18,21 * * *";
|
|
14
|
+
// Schedule Offset
|
|
15
|
+
export const DEFAULT_CRON_SCHEDULE_OFFSET = 0;
|
|
16
|
+
// Max Retries for rate-limited API calls
|
|
17
|
+
export const DEFAULT_MAX_RETRIES = 3;
|
|
14
18
|
// Branch Configuration
|
|
15
19
|
export const DEFAULT_BRANCH_PREFIX = "night-watch";
|
|
16
20
|
export const DEFAULT_BRANCH_PATTERNS = ["feat/", "night-watch/"];
|
|
@@ -47,4 +51,7 @@ export const CLAIM_FILE_EXTENSION = ".claim";
|
|
|
47
51
|
// Global Registry
|
|
48
52
|
export const GLOBAL_CONFIG_DIR = ".night-watch";
|
|
49
53
|
export const REGISTRY_FILE_NAME = "projects.json";
|
|
54
|
+
export const HISTORY_FILE_NAME = "history.json";
|
|
55
|
+
// Execution History
|
|
56
|
+
export const MAX_HISTORY_RECORDS_PER_PRD = 10;
|
|
50
57
|
//# sourceMappingURL=constants.js.map
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,wCAAwC;AACxC,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC,CAAC,sBAAsB;AAEhE,oBAAoB;AACpB,MAAM,CAAC,MAAM,eAAe,GAAG,uBAAuB,CAAC;AAEvD,qCAAqC;AACrC,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AACxC,MAAM,CAAC,MAAM,4BAA4B,GAAG,IAAI,CAAC;AAEjD,8BAA8B;AAC9B,MAAM,CAAC,MAAM,qBAAqB,GAAG,cAAc,CAAC;AACpD,MAAM,CAAC,MAAM,yBAAyB,GAAG,6BAA6B,CAAC;AAEvE,uBAAuB;AACvB,MAAM,CAAC,MAAM,qBAAqB,GAAG,aAAa,CAAC;AACnD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;AAEjE,uBAAuB;AACvB,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAE3C,oBAAoB;AACpB,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,CAAC,SAAS;AAErD,yBAAyB;AACzB,MAAM,CAAC,MAAM,gBAAgB,GAAa,QAAQ,CAAC;AACnD,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAC7C,MAAM,CAAC,MAAM,oBAAoB,GAA2B,EAAE,CAAC;AAE/D,6BAA6B;AAC7B,MAAM,CAAC,MAAM,qBAAqB,GAAwB,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAE3E,6BAA6B;AAC7B,MAAM,CAAC,MAAM,oBAAoB,GAAa,EAAE,CAAC;AAEjD,gCAAgC;AAChC,MAAM,CAAC,MAAM,uBAAuB,GAA0B;IAC5D,OAAO,EAAE,KAAK;IACd,WAAW,EAAE,YAAY;IACzB,gBAAgB,EAAE,GAAG;CACtB,CAAC;AAEF,kBAAkB;AAClB,MAAM,CAAC,MAAM,eAAe,GAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAE/D,kCAAkC;AAClC,MAAM,CAAC,MAAM,iBAAiB,GAA6B;IACzD,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO;CACf,CAAC;AAEF,uBAAuB;AACvB,MAAM,CAAC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AAC1D,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;AACpD,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC;AAC9B,MAAM,CAAC,MAAM,oBAAoB,GAAG,QAAQ,CAAC;AAE7C,kBAAkB;AAClB,MAAM,CAAC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAChD,MAAM,CAAC,MAAM,kBAAkB,GAAG,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,wCAAwC;AACxC,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC,CAAC,sBAAsB;AAEhE,oBAAoB;AACpB,MAAM,CAAC,MAAM,eAAe,GAAG,uBAAuB,CAAC;AAEvD,qCAAqC;AACrC,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AACxC,MAAM,CAAC,MAAM,4BAA4B,GAAG,IAAI,CAAC;AAEjD,8BAA8B;AAC9B,MAAM,CAAC,MAAM,qBAAqB,GAAG,cAAc,CAAC;AACpD,MAAM,CAAC,MAAM,yBAAyB,GAAG,6BAA6B,CAAC;AAEvE,kBAAkB;AAClB,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAE9C,yCAAyC;AACzC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAErC,uBAAuB;AACvB,MAAM,CAAC,MAAM,qBAAqB,GAAG,aAAa,CAAC;AACnD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;AAEjE,uBAAuB;AACvB,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAE3C,oBAAoB;AACpB,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,CAAC,SAAS;AAErD,yBAAyB;AACzB,MAAM,CAAC,MAAM,gBAAgB,GAAa,QAAQ,CAAC;AACnD,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAC7C,MAAM,CAAC,MAAM,oBAAoB,GAA2B,EAAE,CAAC;AAE/D,6BAA6B;AAC7B,MAAM,CAAC,MAAM,qBAAqB,GAAwB,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAE3E,6BAA6B;AAC7B,MAAM,CAAC,MAAM,oBAAoB,GAAa,EAAE,CAAC;AAEjD,gCAAgC;AAChC,MAAM,CAAC,MAAM,uBAAuB,GAA0B;IAC5D,OAAO,EAAE,KAAK;IACd,WAAW,EAAE,YAAY;IACzB,gBAAgB,EAAE,GAAG;CACtB,CAAC;AAEF,kBAAkB;AAClB,MAAM,CAAC,MAAM,eAAe,GAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAE/D,kCAAkC;AAClC,MAAM,CAAC,MAAM,iBAAiB,GAA6B;IACzD,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO;CACf,CAAC;AAEF,uBAAuB;AACvB,MAAM,CAAC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AAC1D,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;AACpD,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC;AAC9B,MAAM,CAAC,MAAM,oBAAoB,GAAG,QAAQ,CAAC;AAE7C,kBAAkB;AAClB,MAAM,CAAC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAChD,MAAM,CAAC,MAAM,kBAAkB,GAAG,eAAe,CAAC;AAClD,MAAM,CAAC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAEhD,oBAAoB;AACpB,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -29,6 +29,10 @@ export interface INightWatchConfig {
|
|
|
29
29
|
cronSchedule: string;
|
|
30
30
|
/** Cron schedule for PR reviewer */
|
|
31
31
|
reviewerSchedule: string;
|
|
32
|
+
/** Minute offset (0-59) applied to cron schedules during install. Helps stagger multiple projects. */
|
|
33
|
+
cronScheduleOffset: number;
|
|
34
|
+
/** Maximum retry attempts for rate-limited API calls (default: 3) */
|
|
35
|
+
maxRetries: number;
|
|
32
36
|
/** AI provider to use for execution */
|
|
33
37
|
provider: Provider;
|
|
34
38
|
/** Whether the reviewer is enabled */
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE1C;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAGhC,qFAAqF;IACrF,aAAa,EAAE,MAAM,CAAC;IAEtB,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IAEf,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IAEnB,iDAAiD;IACjD,kBAAkB,EAAE,MAAM,CAAC;IAE3B,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;IAErB,+CAA+C;IAC/C,cAAc,EAAE,MAAM,EAAE,CAAC;IAEzB,gEAAgE;IAChE,cAAc,EAAE,MAAM,CAAC;IAEvB,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;IAInB,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;IAErB,oCAAoC;IACpC,gBAAgB,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE1C;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAGhC,qFAAqF;IACrF,aAAa,EAAE,MAAM,CAAC;IAEtB,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IAEf,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IAEnB,iDAAiD;IACjD,kBAAkB,EAAE,MAAM,CAAC;IAE3B,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;IAErB,+CAA+C;IAC/C,cAAc,EAAE,MAAM,EAAE,CAAC;IAEzB,gEAAgE;IAChE,cAAc,EAAE,MAAM,CAAC;IAEvB,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;IAInB,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;IAErB,oCAAoC;IACpC,gBAAgB,EAAE,MAAM,CAAC;IAEzB,sGAAsG;IACtG,kBAAkB,EAAE,MAAM,CAAC;IAE3B,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;IAInB,uCAAuC;IACvC,QAAQ,EAAE,QAAQ,CAAC;IAEnB,sCAAsC;IACtC,eAAe,EAAE,OAAO,CAAC;IAEzB,yFAAyF;IACzF,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEpC,yCAAyC;IACzC,aAAa,EAAE,mBAAmB,CAAC;IAEnC,qEAAqE;IACrE,WAAW,EAAE,MAAM,EAAE,CAAC;IAEtB,oCAAoC;IACpC,cAAc,EAAE,qBAAqB,CAAC;CACvC;AAED,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;AAC3D,MAAM,MAAM,iBAAiB,GAAG,eAAe,GAAG,YAAY,GAAG,aAAa,GAAG,kBAAkB,CAAC;AAEpG,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,iBAAiB,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,6CAA6C;IAC7C,OAAO,EAAE,OAAO,CAAC;IAEjB,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IAEpB,kDAAkD;IAClD,gBAAgB,EAAE,MAAM,CAAC;CAC1B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crontab.d.ts","sourceRoot":"","sources":["../../src/utils/crontab.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH;;GAEG;AACH,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAqB1D;;;GAGG;AACH,wBAAgB,WAAW,IAAI,MAAM,EAAE,CAYtC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"crontab.d.ts","sourceRoot":"","sources":["../../src/utils/crontab.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH;;GAEG;AACH,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAqB1D;;;GAGG;AACH,wBAAgB,WAAW,IAAI,MAAM,EAAE,CAYtC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAkClD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAiB/D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAUpD;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGhD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAGnD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAG9D;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAYnF"}
|
package/dist/utils/crontab.js
CHANGED
|
@@ -50,6 +50,10 @@ export function readCrontab() {
|
|
|
50
50
|
* @throws Error if crontab write fails
|
|
51
51
|
*/
|
|
52
52
|
export function writeCrontab(lines) {
|
|
53
|
+
if (process.env.NW_EXECUTION_CONTEXT === "agent") {
|
|
54
|
+
throw new Error("Crontab writes are blocked during agent execution (NW_EXECUTION_CONTEXT=agent). " +
|
|
55
|
+
"This prevents the running agent from accidentally modifying its own scheduling.");
|
|
56
|
+
}
|
|
53
57
|
const content = lines.join("\n");
|
|
54
58
|
// Create a backup first
|
|
55
59
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crontab.js","sourceRoot":"","sources":["../../src/utils/crontab.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,oBAAoB,CAAC;AAE1D;;;GAGG;AACH,SAAS,iBAAiB,CAAC,IAAY,EAAE,UAAkB;IACzD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG;QACjB,MAAM,UAAU,EAAE;QAClB,OAAO,UAAU,GAAG;QACpB,OAAO,UAAU,GAAG;KACrB,CAAC;IAEF,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AAClE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,wBAAwB,EAAE;YAChD,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;QAChD,iDAAiD;QACjD,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,KAAe;IAC1C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjC,wBAAwB;IACxB,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,WAAW,EAAE,CAAC;QACrC,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,QAAQ,CAAC,8DAA8D,EAAE;gBACvE,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,uBAAuB;IACzB,CAAC;IAED,oEAAoE;IACpE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,uBAAuB,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAChF,IAAI,CAAC;QACH,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC;QAC1C,QAAQ,CAAC,WAAW,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,4BAA4B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACrF,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,2BAA2B,CAAC,CAAC;IACvE,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,WAAmB;IAChD,OAAO,GAAG,qBAAqB,IAAI,WAAW,EAAE,CAAC;AACnD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,MAAc;IACpD,gCAAgC;IAChC,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAE5B,qDAAqD;IACrD,MAAM,eAAe,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC5C,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,GAAG,KAAK,KAAK,MAAM,EAAE,CAAC;IAE1B,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC5B,YAAY,CAAC,KAAK,CAAC,CAAC;IAEpB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAChE,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAEpD,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACrB,YAAY,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AACrD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AACvD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAkB;IAClD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;AACrE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,UAAkB,EAAE,MAAe;IACzE,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAC3B,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CACrF,CAAC;IACF,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAEpD,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACrB,YAAY,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
|
1
|
+
{"version":3,"file":"crontab.js","sourceRoot":"","sources":["../../src/utils/crontab.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,oBAAoB,CAAC;AAE1D;;;GAGG;AACH,SAAS,iBAAiB,CAAC,IAAY,EAAE,UAAkB;IACzD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG;QACjB,MAAM,UAAU,EAAE;QAClB,OAAO,UAAU,GAAG;QACpB,OAAO,UAAU,GAAG;KACrB,CAAC;IAEF,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AAClE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,wBAAwB,EAAE;YAChD,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;QAChD,iDAAiD;QACjD,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,KAAe;IAC1C,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,OAAO,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CACb,kFAAkF;YAClF,iFAAiF,CAClF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjC,wBAAwB;IACxB,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,WAAW,EAAE,CAAC;QACrC,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,QAAQ,CAAC,8DAA8D,EAAE;gBACvE,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,uBAAuB;IACzB,CAAC;IAED,oEAAoE;IACpE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,uBAAuB,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAChF,IAAI,CAAC;QACH,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC;QAC1C,QAAQ,CAAC,WAAW,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,4BAA4B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACrF,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,2BAA2B,CAAC,CAAC;IACvE,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,WAAmB;IAChD,OAAO,GAAG,qBAAqB,IAAI,WAAW,EAAE,CAAC;AACnD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,MAAc;IACpD,gCAAgC;IAChC,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAE5B,qDAAqD;IACrD,MAAM,eAAe,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC5C,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,GAAG,KAAK,KAAK,MAAM,EAAE,CAAC;IAE1B,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC5B,YAAY,CAAC,KAAK,CAAC,CAAC;IAEpB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAChE,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAEpD,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACrB,YAAY,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AACrD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AACvD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAkB;IAClD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;AACrE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,UAAkB,EAAE,MAAe;IACzE,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAC3B,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CACrF,CAAC;IACF,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAEpD,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACrB,YAAY,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execution history ledger for Night Watch CLI
|
|
3
|
+
* Stores PRD execution records in ~/.night-watch/history.json
|
|
4
|
+
* Decoupled from PRD file paths — keyed by project directory + PRD filename.
|
|
5
|
+
*/
|
|
6
|
+
export type ExecutionOutcome = "success" | "failure" | "timeout" | "rate_limited";
|
|
7
|
+
export interface IExecutionRecord {
|
|
8
|
+
timestamp: number;
|
|
9
|
+
outcome: ExecutionOutcome;
|
|
10
|
+
exitCode: number;
|
|
11
|
+
attempt: number;
|
|
12
|
+
}
|
|
13
|
+
interface IPrdHistory {
|
|
14
|
+
records: IExecutionRecord[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Full history structure: projectDir -> prdFile -> records
|
|
18
|
+
*/
|
|
19
|
+
export type IExecutionHistory = Record<string, Record<string, IPrdHistory>>;
|
|
20
|
+
/**
|
|
21
|
+
* Get the path to the history file
|
|
22
|
+
*/
|
|
23
|
+
export declare function getHistoryPath(): string;
|
|
24
|
+
/**
|
|
25
|
+
* Load execution history from disk. Returns empty object if missing or invalid.
|
|
26
|
+
*/
|
|
27
|
+
export declare function loadHistory(): IExecutionHistory;
|
|
28
|
+
/**
|
|
29
|
+
* Save execution history to disk.
|
|
30
|
+
*/
|
|
31
|
+
export declare function saveHistory(history: IExecutionHistory): void;
|
|
32
|
+
/**
|
|
33
|
+
* Record a PRD execution result.
|
|
34
|
+
* Appends a record and trims to MAX_HISTORY_RECORDS_PER_PRD.
|
|
35
|
+
*/
|
|
36
|
+
export declare function recordExecution(projectDir: string, prdFile: string, outcome: ExecutionOutcome, exitCode: number, attempt?: number): void;
|
|
37
|
+
/**
|
|
38
|
+
* Get the most recent execution record for a PRD.
|
|
39
|
+
* Returns null if no history exists.
|
|
40
|
+
*/
|
|
41
|
+
export declare function getLastExecution(projectDir: string, prdFile: string): IExecutionRecord | null;
|
|
42
|
+
/**
|
|
43
|
+
* Check if a PRD is in cooldown after a recent non-success execution.
|
|
44
|
+
* Returns true if the PRD should be skipped.
|
|
45
|
+
*/
|
|
46
|
+
export declare function isInCooldown(projectDir: string, prdFile: string, cooldownPeriod: number): boolean;
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=execution-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-history.d.ts","sourceRoot":"","sources":["../../src/utils/execution-history.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,cAAc,CAAC;AAElF,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,WAAW;IACnB,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;AAS5E;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAIvC;AAwFD;;GAEG;AACH,wBAAgB,WAAW,IAAI,iBAAiB,CAE/C;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAQ5D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,MAAU,GAClB,IAAI,CAmCN;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,gBAAgB,GAAG,IAAI,CAQzB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,GACrB,OAAO,CAYT"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execution history ledger for Night Watch CLI
|
|
3
|
+
* Stores PRD execution records in ~/.night-watch/history.json
|
|
4
|
+
* Decoupled from PRD file paths — keyed by project directory + PRD filename.
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as os from "os";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import { GLOBAL_CONFIG_DIR, HISTORY_FILE_NAME, MAX_HISTORY_RECORDS_PER_PRD, } from "../constants.js";
|
|
10
|
+
const HISTORY_LOCK_SUFFIX = ".lock";
|
|
11
|
+
const HISTORY_LOCK_TIMEOUT_MS = 5000;
|
|
12
|
+
const HISTORY_LOCK_STALE_MS = 30000;
|
|
13
|
+
const HISTORY_LOCK_POLL_MS = 25;
|
|
14
|
+
const sleepState = new Int32Array(new SharedArrayBuffer(4));
|
|
15
|
+
/**
|
|
16
|
+
* Get the path to the history file
|
|
17
|
+
*/
|
|
18
|
+
export function getHistoryPath() {
|
|
19
|
+
const base = process.env.NIGHT_WATCH_HOME || path.join(os.homedir(), GLOBAL_CONFIG_DIR);
|
|
20
|
+
return path.join(base, HISTORY_FILE_NAME);
|
|
21
|
+
}
|
|
22
|
+
function sleepMs(ms) {
|
|
23
|
+
Atomics.wait(sleepState, 0, 0, ms);
|
|
24
|
+
}
|
|
25
|
+
function acquireHistoryLock(historyPath) {
|
|
26
|
+
const lockPath = `${historyPath}${HISTORY_LOCK_SUFFIX}`;
|
|
27
|
+
fs.mkdirSync(path.dirname(lockPath), { recursive: true });
|
|
28
|
+
const deadline = Date.now() + HISTORY_LOCK_TIMEOUT_MS;
|
|
29
|
+
while (true) {
|
|
30
|
+
try {
|
|
31
|
+
return fs.openSync(lockPath, "wx");
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const err = error;
|
|
35
|
+
if (err.code !== "EEXIST") {
|
|
36
|
+
throw err;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const lockStats = fs.statSync(lockPath);
|
|
40
|
+
if (Date.now() - lockStats.mtimeMs > HISTORY_LOCK_STALE_MS) {
|
|
41
|
+
fs.unlinkSync(lockPath);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Lock may have disappeared between checks; retry.
|
|
47
|
+
}
|
|
48
|
+
if (Date.now() >= deadline) {
|
|
49
|
+
throw new Error(`Timed out acquiring execution history lock: ${lockPath}`);
|
|
50
|
+
}
|
|
51
|
+
sleepMs(HISTORY_LOCK_POLL_MS);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function releaseHistoryLock(lockFd, historyPath) {
|
|
56
|
+
const lockPath = `${historyPath}${HISTORY_LOCK_SUFFIX}`;
|
|
57
|
+
try {
|
|
58
|
+
fs.closeSync(lockFd);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Ignore close errors; lock cleanup still attempted.
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
fs.unlinkSync(lockPath);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Ignore lock cleanup errors.
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function loadHistoryFromPath(historyPath) {
|
|
71
|
+
if (!fs.existsSync(historyPath)) {
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const content = fs.readFileSync(historyPath, "utf-8");
|
|
76
|
+
const parsed = JSON.parse(content);
|
|
77
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
78
|
+
return {};
|
|
79
|
+
}
|
|
80
|
+
return parsed;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return {};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function saveHistoryAtomic(historyPath, history) {
|
|
87
|
+
const dir = path.dirname(historyPath);
|
|
88
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
89
|
+
const tmpPath = path.join(dir, `${HISTORY_FILE_NAME}.${process.pid}.${Date.now()}.tmp`);
|
|
90
|
+
try {
|
|
91
|
+
fs.writeFileSync(tmpPath, JSON.stringify(history, null, 2) + "\n");
|
|
92
|
+
fs.renameSync(tmpPath, historyPath);
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
if (fs.existsSync(tmpPath)) {
|
|
96
|
+
fs.rmSync(tmpPath, { force: true });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Load execution history from disk. Returns empty object if missing or invalid.
|
|
102
|
+
*/
|
|
103
|
+
export function loadHistory() {
|
|
104
|
+
return loadHistoryFromPath(getHistoryPath());
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Save execution history to disk.
|
|
108
|
+
*/
|
|
109
|
+
export function saveHistory(history) {
|
|
110
|
+
const historyPath = getHistoryPath();
|
|
111
|
+
const lockFd = acquireHistoryLock(historyPath);
|
|
112
|
+
try {
|
|
113
|
+
saveHistoryAtomic(historyPath, history);
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
releaseHistoryLock(lockFd, historyPath);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Record a PRD execution result.
|
|
121
|
+
* Appends a record and trims to MAX_HISTORY_RECORDS_PER_PRD.
|
|
122
|
+
*/
|
|
123
|
+
export function recordExecution(projectDir, prdFile, outcome, exitCode, attempt = 1) {
|
|
124
|
+
const historyPath = getHistoryPath();
|
|
125
|
+
const lockFd = acquireHistoryLock(historyPath);
|
|
126
|
+
const resolved = path.resolve(projectDir);
|
|
127
|
+
try {
|
|
128
|
+
const history = loadHistoryFromPath(historyPath);
|
|
129
|
+
if (!history[resolved]) {
|
|
130
|
+
history[resolved] = {};
|
|
131
|
+
}
|
|
132
|
+
if (!history[resolved][prdFile]) {
|
|
133
|
+
history[resolved][prdFile] = { records: [] };
|
|
134
|
+
}
|
|
135
|
+
const record = {
|
|
136
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
137
|
+
outcome,
|
|
138
|
+
exitCode,
|
|
139
|
+
attempt,
|
|
140
|
+
};
|
|
141
|
+
history[resolved][prdFile].records.push(record);
|
|
142
|
+
// Trim to max records (keep most recent)
|
|
143
|
+
const records = history[resolved][prdFile].records;
|
|
144
|
+
if (records.length > MAX_HISTORY_RECORDS_PER_PRD) {
|
|
145
|
+
history[resolved][prdFile].records = records.slice(records.length - MAX_HISTORY_RECORDS_PER_PRD);
|
|
146
|
+
}
|
|
147
|
+
saveHistoryAtomic(historyPath, history);
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
releaseHistoryLock(lockFd, historyPath);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Get the most recent execution record for a PRD.
|
|
155
|
+
* Returns null if no history exists.
|
|
156
|
+
*/
|
|
157
|
+
export function getLastExecution(projectDir, prdFile) {
|
|
158
|
+
const resolved = path.resolve(projectDir);
|
|
159
|
+
const history = loadHistory();
|
|
160
|
+
const prdHistory = history[resolved]?.[prdFile];
|
|
161
|
+
if (!prdHistory || prdHistory.records.length === 0) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
return prdHistory.records[prdHistory.records.length - 1];
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Check if a PRD is in cooldown after a recent non-success execution.
|
|
168
|
+
* Returns true if the PRD should be skipped.
|
|
169
|
+
*/
|
|
170
|
+
export function isInCooldown(projectDir, prdFile, cooldownPeriod) {
|
|
171
|
+
const last = getLastExecution(projectDir, prdFile);
|
|
172
|
+
if (!last) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
// Success records don't trigger cooldown
|
|
176
|
+
if (last.outcome === "success") {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
const now = Math.floor(Date.now() / 1000);
|
|
180
|
+
const age = now - last.timestamp;
|
|
181
|
+
return age < cooldownPeriod;
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=execution-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-history.js","sourceRoot":"","sources":["../../src/utils/execution-history.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -15,17 +15,17 @@ set -euo pipefail
|
|
|
15
15
|
PROJECT_DIR="${1:?Usage: $0 /path/to/project}"
|
|
16
16
|
PROJECT_NAME=$(basename "${PROJECT_DIR}")
|
|
17
17
|
PRD_DIR_REL="${NW_PRD_DIR:-docs/PRDs/night-watch}"
|
|
18
|
-
if [[ "${PRD_DIR_REL}" = /* ]]; then
|
|
19
|
-
PRD_DIR="${PRD_DIR_REL}"
|
|
20
|
-
else
|
|
21
|
-
PRD_DIR="${PROJECT_DIR}/${PRD_DIR_REL}"
|
|
22
|
-
fi
|
|
23
18
|
LOG_DIR="${PROJECT_DIR}/logs"
|
|
24
19
|
LOG_FILE="${LOG_DIR}/night-watch.log"
|
|
25
|
-
LOCK_FILE="
|
|
20
|
+
LOCK_FILE=""
|
|
26
21
|
MAX_RUNTIME="${NW_MAX_RUNTIME:-7200}" # 2 hours
|
|
27
22
|
MAX_LOG_SIZE="524288" # 512 KB
|
|
28
23
|
PROVIDER_CMD="${NW_PROVIDER_CMD:-claude}"
|
|
24
|
+
RUNTIME_MIRROR_DIR=""
|
|
25
|
+
RUNTIME_PROJECT_DIR=""
|
|
26
|
+
PRD_DIR=""
|
|
27
|
+
ELIGIBLE_PRD=""
|
|
28
|
+
CLAIMED=0
|
|
29
29
|
|
|
30
30
|
# Ensure NVM / Node / Claude are on PATH
|
|
31
31
|
export NVM_DIR="${HOME}/.nvm"
|
|
@@ -40,6 +40,8 @@ mkdir -p "${LOG_DIR}"
|
|
|
40
40
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
41
41
|
# shellcheck source=night-watch-helpers.sh
|
|
42
42
|
source "${SCRIPT_DIR}/night-watch-helpers.sh"
|
|
43
|
+
PROJECT_RUNTIME_KEY=$(project_runtime_key "${PROJECT_DIR}")
|
|
44
|
+
LOCK_FILE="/tmp/night-watch-${PROJECT_RUNTIME_KEY}.lock"
|
|
43
45
|
|
|
44
46
|
# Validate provider
|
|
45
47
|
if ! validate_provider "${PROVIDER_CMD}"; then
|
|
@@ -53,9 +55,47 @@ if ! acquire_lock "${LOCK_FILE}"; then
|
|
|
53
55
|
exit 0
|
|
54
56
|
fi
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
cleanup_on_exit() {
|
|
59
|
+
rm -f "${LOCK_FILE}"
|
|
60
|
+
|
|
61
|
+
if [ "${CLAIMED}" = "1" ] && [ -n "${ELIGIBLE_PRD}" ] && [ -n "${PRD_DIR}" ]; then
|
|
62
|
+
release_claim "${PRD_DIR}" "${ELIGIBLE_PRD}" || true
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
if [ -n "${RUNTIME_MIRROR_DIR}" ] && [ -n "${RUNTIME_PROJECT_DIR}" ]; then
|
|
66
|
+
cleanup_runtime_workspace "${RUNTIME_MIRROR_DIR}" "${RUNTIME_PROJECT_DIR}" || true
|
|
67
|
+
fi
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
trap cleanup_on_exit EXIT
|
|
71
|
+
|
|
72
|
+
if [ -n "${NW_DEFAULT_BRANCH:-}" ]; then
|
|
73
|
+
DEFAULT_BRANCH="${NW_DEFAULT_BRANCH}"
|
|
74
|
+
else
|
|
75
|
+
DEFAULT_BRANCH=$(detect_default_branch "${PROJECT_DIR}")
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
runtime_info=()
|
|
79
|
+
if mapfile -t runtime_info < <(prepare_runtime_workspace "${PROJECT_DIR}" "${DEFAULT_BRANCH}" "${LOG_FILE}"); then
|
|
80
|
+
RUNTIME_MIRROR_DIR="${runtime_info[0]:-}"
|
|
81
|
+
RUNTIME_PROJECT_DIR="${runtime_info[1]:-}"
|
|
82
|
+
else
|
|
83
|
+
log "FAIL: Could not prepare runtime workspace for ${PROJECT_DIR}"
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
if [ -z "${RUNTIME_MIRROR_DIR}" ] || [ -z "${RUNTIME_PROJECT_DIR}" ]; then
|
|
88
|
+
log "FAIL: Runtime workspace paths are missing"
|
|
89
|
+
exit 1
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
if [[ "${PRD_DIR_REL}" = /* ]]; then
|
|
93
|
+
PRD_DIR="${PRD_DIR_REL}"
|
|
94
|
+
else
|
|
95
|
+
PRD_DIR="${RUNTIME_PROJECT_DIR}/${PRD_DIR_REL}"
|
|
96
|
+
fi
|
|
57
97
|
|
|
58
|
-
ELIGIBLE_PRD=$(find_eligible_prd "${PRD_DIR}" "${MAX_RUNTIME}")
|
|
98
|
+
ELIGIBLE_PRD=$(find_eligible_prd "${PRD_DIR}" "${MAX_RUNTIME}" "${PROJECT_DIR}")
|
|
59
99
|
|
|
60
100
|
if [ -z "${ELIGIBLE_PRD}" ]; then
|
|
61
101
|
log "SKIP: No eligible PRDs (all done, in-progress, or blocked)"
|
|
@@ -64,29 +104,26 @@ fi
|
|
|
64
104
|
|
|
65
105
|
# Claim the PRD to prevent other runs from selecting it
|
|
66
106
|
claim_prd "${PRD_DIR}" "${ELIGIBLE_PRD}"
|
|
67
|
-
|
|
68
|
-
# Update EXIT trap to also release claim
|
|
69
|
-
trap "rm -f '${LOCK_FILE}'; release_claim '${PRD_DIR}' '${ELIGIBLE_PRD}'" EXIT
|
|
107
|
+
CLAIMED=1
|
|
70
108
|
|
|
71
109
|
PRD_NAME="${ELIGIBLE_PRD%.md}"
|
|
72
110
|
BRANCH_NAME="night-watch/${PRD_NAME}"
|
|
73
|
-
if [ -n "${NW_DEFAULT_BRANCH:-}" ]; then
|
|
74
|
-
DEFAULT_BRANCH="${NW_DEFAULT_BRANCH}"
|
|
75
|
-
else
|
|
76
|
-
DEFAULT_BRANCH=$(detect_default_branch "${PROJECT_DIR}")
|
|
77
|
-
fi
|
|
78
111
|
|
|
79
|
-
log "START: Processing ${ELIGIBLE_PRD} on branch ${BRANCH_NAME}"
|
|
112
|
+
log "START: Processing ${ELIGIBLE_PRD} on branch ${BRANCH_NAME} in runtime workspace ${RUNTIME_PROJECT_DIR}"
|
|
80
113
|
|
|
81
|
-
|
|
114
|
+
if ! prepare_branch_checkout "${RUNTIME_PROJECT_DIR}" "${BRANCH_NAME}" "${DEFAULT_BRANCH}" "${LOG_FILE}"; then
|
|
115
|
+
log "FAIL: Could not prepare branch ${BRANCH_NAME} in runtime workspace"
|
|
116
|
+
night_watch_history record "${PROJECT_DIR}" "${ELIGIBLE_PRD}" failure --exit-code 1 2>/dev/null || true
|
|
117
|
+
exit 1
|
|
118
|
+
fi
|
|
82
119
|
|
|
83
120
|
PROMPT="Implement the PRD at docs/PRDs/night-watch/${ELIGIBLE_PRD}
|
|
84
121
|
|
|
85
122
|
## Setup
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
123
|
+
- You are already inside an isolated runtime workspace: ${RUNTIME_PROJECT_DIR}
|
|
124
|
+
- Current branch is already prepared: ${BRANCH_NAME}
|
|
125
|
+
- Do not run git checkout/switch in ${PROJECT_DIR}
|
|
126
|
+
- Do not create or remove worktrees; the runtime controller handles isolation and cleanup
|
|
90
127
|
|
|
91
128
|
## Implementation — PRD Executor Workflow
|
|
92
129
|
Read .claude/commands/prd-executor.md and follow its FULL execution pipeline:
|
|
@@ -102,7 +139,6 @@ Follow all CLAUDE.md conventions (if present).
|
|
|
102
139
|
- Commit all changes, push, and open a PR:
|
|
103
140
|
git push -u origin ${BRANCH_NAME}
|
|
104
141
|
gh pr create --title \"feat: <short title>\" --body \"<summary referencing PRD>\"
|
|
105
|
-
- After PR is created, clean up: git worktree remove ../${PROJECT_NAME}-nw-${PRD_NAME}
|
|
106
142
|
- Do NOT move the PRD to done/ — the cron script handles that
|
|
107
143
|
- Do NOT process any other PRDs — only ${ELIGIBLE_PRD}"
|
|
108
144
|
|
|
@@ -115,58 +151,109 @@ if [ "${NW_DRY_RUN:-0}" = "1" ]; then
|
|
|
115
151
|
echo "Provider: ${PROVIDER_CMD}"
|
|
116
152
|
echo "Eligible PRD: ${ELIGIBLE_PRD}"
|
|
117
153
|
echo "Branch: ${BRANCH_NAME}"
|
|
154
|
+
echo "Runtime Dir: ${RUNTIME_PROJECT_DIR}"
|
|
118
155
|
echo "Timeout: ${MAX_RUNTIME}s"
|
|
119
156
|
exit 0
|
|
120
157
|
fi
|
|
121
158
|
|
|
159
|
+
# Sandbox: prevent the agent from modifying crontab during execution
|
|
160
|
+
export NW_EXECUTION_CONTEXT=agent
|
|
161
|
+
|
|
162
|
+
MAX_RETRIES="${NW_MAX_RETRIES:-3}"
|
|
163
|
+
if ! [[ "${MAX_RETRIES}" =~ ^[0-9]+$ ]] || [ "${MAX_RETRIES}" -lt 1 ]; then
|
|
164
|
+
MAX_RETRIES=1
|
|
165
|
+
fi
|
|
166
|
+
BACKOFF_BASE=300 # 5 minutes in seconds
|
|
122
167
|
EXIT_CODE=0
|
|
168
|
+
ATTEMPT=0
|
|
123
169
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
170
|
+
while [ "${ATTEMPT}" -lt "${MAX_RETRIES}" ]; do
|
|
171
|
+
EXIT_CODE=0
|
|
172
|
+
|
|
173
|
+
case "${PROVIDER_CMD}" in
|
|
174
|
+
claude)
|
|
175
|
+
if (
|
|
176
|
+
cd "${RUNTIME_PROJECT_DIR}" && timeout "${MAX_RUNTIME}" \
|
|
177
|
+
claude -p "${PROMPT}" \
|
|
178
|
+
--dangerously-skip-permissions \
|
|
179
|
+
>> "${LOG_FILE}" 2>&1
|
|
180
|
+
); then
|
|
181
|
+
EXIT_CODE=0
|
|
182
|
+
else
|
|
183
|
+
EXIT_CODE=$?
|
|
184
|
+
fi
|
|
185
|
+
;;
|
|
186
|
+
codex)
|
|
187
|
+
if (
|
|
188
|
+
cd "${RUNTIME_PROJECT_DIR}" && timeout "${MAX_RUNTIME}" \
|
|
189
|
+
codex --quiet \
|
|
190
|
+
--yolo \
|
|
191
|
+
--prompt "${PROMPT}" \
|
|
192
|
+
>> "${LOG_FILE}" 2>&1
|
|
193
|
+
); then
|
|
194
|
+
EXIT_CODE=0
|
|
195
|
+
else
|
|
196
|
+
EXIT_CODE=$?
|
|
197
|
+
fi
|
|
198
|
+
;;
|
|
199
|
+
*)
|
|
200
|
+
log "ERROR: Unknown provider: ${PROVIDER_CMD}"
|
|
201
|
+
exit 1
|
|
202
|
+
;;
|
|
203
|
+
esac
|
|
204
|
+
|
|
205
|
+
# Success or timeout — don't retry
|
|
206
|
+
if [ ${EXIT_CODE} -eq 0 ] || [ ${EXIT_CODE} -eq 124 ]; then
|
|
207
|
+
break
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
# Check if this was a rate limit (429) error
|
|
211
|
+
if check_rate_limited "${LOG_FILE}"; then
|
|
212
|
+
ATTEMPT=$((ATTEMPT + 1))
|
|
213
|
+
if [ "${ATTEMPT}" -ge "${MAX_RETRIES}" ]; then
|
|
214
|
+
log "RATE-LIMITED: All ${MAX_RETRIES} attempts exhausted for ${ELIGIBLE_PRD}"
|
|
215
|
+
night_watch_history record "${PROJECT_DIR}" "${ELIGIBLE_PRD}" rate_limited --exit-code "${EXIT_CODE}" --attempt "${ATTEMPT}" 2>/dev/null || true
|
|
216
|
+
break
|
|
144
217
|
fi
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
log "
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
218
|
+
BACKOFF=$(( BACKOFF_BASE * (1 << (ATTEMPT - 1)) ))
|
|
219
|
+
BACKOFF_MIN=$(( BACKOFF / 60 ))
|
|
220
|
+
log "RATE-LIMITED: Attempt ${ATTEMPT}/${MAX_RETRIES}, retrying in ${BACKOFF_MIN}m"
|
|
221
|
+
sleep "${BACKOFF}"
|
|
222
|
+
else
|
|
223
|
+
# Non-retryable failure
|
|
224
|
+
break
|
|
225
|
+
fi
|
|
226
|
+
done
|
|
151
227
|
|
|
152
228
|
if [ ${EXIT_CODE} -eq 0 ]; then
|
|
153
|
-
PR_EXISTS=$(gh pr list --state open --json headRefName --jq '.[].headRefName' 2>/dev/null | grep -cF "${BRANCH_NAME}" || echo "0")
|
|
229
|
+
PR_EXISTS=$(cd "${RUNTIME_PROJECT_DIR}" && gh pr list --state open --json headRefName --jq '.[].headRefName' 2>/dev/null | grep -cF "${BRANCH_NAME}" || echo "0")
|
|
154
230
|
if [ "${PR_EXISTS}" -gt 0 ]; then
|
|
155
231
|
release_claim "${PRD_DIR}" "${ELIGIBLE_PRD}"
|
|
232
|
+
CLAIMED=0
|
|
233
|
+
if ! checkout_default_branch "${RUNTIME_PROJECT_DIR}" "${DEFAULT_BRANCH}" "${LOG_FILE}"; then
|
|
234
|
+
log "WARN: Could not switch runtime workspace to ${DEFAULT_BRANCH}; PRD not moved to done/"
|
|
235
|
+
exit 0
|
|
236
|
+
fi
|
|
237
|
+
|
|
156
238
|
mark_prd_done "${PRD_DIR}" "${ELIGIBLE_PRD}"
|
|
157
|
-
|
|
158
|
-
|
|
239
|
+
night_watch_history record "${PROJECT_DIR}" "${ELIGIBLE_PRD}" success --exit-code 0 2>/dev/null || true
|
|
240
|
+
if [[ "${PRD_DIR_REL}" = /* ]]; then
|
|
241
|
+
log "WARN: PRD directory is absolute; skipping auto-commit of done/ move"
|
|
242
|
+
else
|
|
243
|
+
git -C "${RUNTIME_PROJECT_DIR}" add -A "${PRD_DIR_REL}/" || true
|
|
244
|
+
git -C "${RUNTIME_PROJECT_DIR}" commit -m "chore: mark ${ELIGIBLE_PRD} as done (PR opened on ${BRANCH_NAME})
|
|
159
245
|
|
|
160
246
|
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" || true
|
|
161
|
-
|
|
247
|
+
git -C "${RUNTIME_PROJECT_DIR}" push origin "${DEFAULT_BRANCH}" || true
|
|
248
|
+
fi
|
|
162
249
|
log "DONE: ${ELIGIBLE_PRD} implemented, PR opened, PRD moved to done/"
|
|
163
250
|
else
|
|
164
251
|
log "WARN: ${PROVIDER_CMD} exited 0 but no PR found on ${BRANCH_NAME} — PRD NOT moved to done"
|
|
165
252
|
fi
|
|
166
253
|
elif [ ${EXIT_CODE} -eq 124 ]; then
|
|
167
254
|
log "TIMEOUT: Night watch killed after ${MAX_RUNTIME}s while processing ${ELIGIBLE_PRD}"
|
|
168
|
-
|
|
255
|
+
night_watch_history record "${PROJECT_DIR}" "${ELIGIBLE_PRD}" timeout --exit-code 124 2>/dev/null || true
|
|
169
256
|
else
|
|
170
257
|
log "FAIL: Night watch exited with code ${EXIT_CODE} while processing ${ELIGIBLE_PRD}"
|
|
171
|
-
|
|
258
|
+
night_watch_history record "${PROJECT_DIR}" "${ELIGIBLE_PRD}" failure --exit-code "${EXIT_CODE}" 2>/dev/null || true
|
|
172
259
|
fi
|