@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.
Files changed (65) hide show
  1. package/dist/cli.js +6 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/cancel.d.ts +46 -0
  4. package/dist/commands/cancel.d.ts.map +1 -0
  5. package/dist/commands/cancel.js +239 -0
  6. package/dist/commands/cancel.js.map +1 -0
  7. package/dist/commands/doctor.d.ts +1 -1
  8. package/dist/commands/doctor.d.ts.map +1 -1
  9. package/dist/commands/doctor.js +101 -58
  10. package/dist/commands/doctor.js.map +1 -1
  11. package/dist/commands/history.d.ts +7 -0
  12. package/dist/commands/history.d.ts.map +1 -0
  13. package/dist/commands/history.js +56 -0
  14. package/dist/commands/history.js.map +1 -0
  15. package/dist/commands/init.d.ts.map +1 -1
  16. package/dist/commands/init.js +11 -73
  17. package/dist/commands/init.js.map +1 -1
  18. package/dist/commands/install.d.ts +11 -0
  19. package/dist/commands/install.d.ts.map +1 -1
  20. package/dist/commands/install.js +47 -11
  21. package/dist/commands/install.js.map +1 -1
  22. package/dist/commands/prds.d.ts +13 -0
  23. package/dist/commands/prds.d.ts.map +1 -0
  24. package/dist/commands/prds.js +192 -0
  25. package/dist/commands/prds.js.map +1 -0
  26. package/dist/commands/prs.d.ts +13 -0
  27. package/dist/commands/prs.d.ts.map +1 -0
  28. package/dist/commands/prs.js +101 -0
  29. package/dist/commands/prs.js.map +1 -0
  30. package/dist/commands/retry.d.ts +9 -0
  31. package/dist/commands/retry.d.ts.map +1 -0
  32. package/dist/commands/retry.js +72 -0
  33. package/dist/commands/retry.js.map +1 -0
  34. package/dist/commands/review.d.ts.map +1 -1
  35. package/dist/commands/review.js +6 -0
  36. package/dist/commands/review.js.map +1 -1
  37. package/dist/commands/run.d.ts.map +1 -1
  38. package/dist/commands/run.js +11 -0
  39. package/dist/commands/run.js.map +1 -1
  40. package/dist/commands/update.d.ts +21 -0
  41. package/dist/commands/update.d.ts.map +1 -0
  42. package/dist/commands/update.js +87 -0
  43. package/dist/commands/update.js.map +1 -0
  44. package/dist/config.d.ts.map +1 -1
  45. package/dist/config.js +36 -1
  46. package/dist/config.js.map +1 -1
  47. package/dist/constants.d.ts +4 -0
  48. package/dist/constants.d.ts.map +1 -1
  49. package/dist/constants.js +7 -0
  50. package/dist/constants.js.map +1 -1
  51. package/dist/types.d.ts +4 -0
  52. package/dist/types.d.ts.map +1 -1
  53. package/dist/utils/crontab.d.ts.map +1 -1
  54. package/dist/utils/crontab.js +4 -0
  55. package/dist/utils/crontab.js.map +1 -1
  56. package/dist/utils/execution-history.d.ts +48 -0
  57. package/dist/utils/execution-history.d.ts.map +1 -0
  58. package/dist/utils/execution-history.js +183 -0
  59. package/dist/utils/execution-history.js.map +1 -0
  60. package/package.json +1 -1
  61. package/scripts/night-watch-cron.sh +142 -55
  62. package/scripts/night-watch-helpers.sh +189 -1
  63. package/scripts/night-watch-pr-reviewer-cron.sh +64 -15
  64. package/templates/night-watch-pr-reviewer.md +7 -11
  65. package/templates/night-watch.md +9 -20
@@ -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
@@ -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 */
@@ -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;IAIzB,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
+ {"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,CA2BlD;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"}
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"}
@@ -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":"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"}
1
+ {"version":3,"file":"crontab.js","sourceRoot":"","sources":["../../src/utils/crontab.ts"],"names":[],"mappings":"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"}
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jonit-dev/night-watch-cli",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "Autonomous PRD execution using AI Provider CLIs + cron",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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="/tmp/night-watch-${PROJECT_NAME}.lock"
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
- cleanup_worktrees "${PROJECT_DIR}"
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
- cd "${PROJECT_DIR}"
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
- - Branch name MUST be exactly: ${BRANCH_NAME}
87
- - Create the branch from ${DEFAULT_BRANCH}: git checkout ${DEFAULT_BRANCH} && git pull origin ${DEFAULT_BRANCH} && git checkout -b ${BRANCH_NAME}
88
- - Use a git worktree: git worktree add ../${PROJECT_NAME}-nw-${PRD_NAME} ${BRANCH_NAME}
89
- - cd into the worktree, install dependencies
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
- case "${PROVIDER_CMD}" in
125
- claude)
126
- if timeout "${MAX_RUNTIME}" \
127
- claude -p "${PROMPT}" \
128
- --dangerously-skip-permissions \
129
- >> "${LOG_FILE}" 2>&1; then
130
- EXIT_CODE=0
131
- else
132
- EXIT_CODE=$?
133
- fi
134
- ;;
135
- codex)
136
- if timeout "${MAX_RUNTIME}" \
137
- codex --quiet \
138
- --yolo \
139
- --prompt "${PROMPT}" \
140
- >> "${LOG_FILE}" 2>&1; then
141
- EXIT_CODE=0
142
- else
143
- EXIT_CODE=$?
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 "ERROR: Unknown provider: ${PROVIDER_CMD}"
148
- exit 1
149
- ;;
150
- esac
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
- git -C "${PROJECT_DIR}" add -A docs/PRDs/night-watch/
158
- git -C "${PROJECT_DIR}" commit -m "chore: mark ${ELIGIBLE_PRD} as done (PR opened on ${BRANCH_NAME})
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
- git -C "${PROJECT_DIR}" push origin "${DEFAULT_BRANCH}" || true
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
- cleanup_worktrees "${PROJECT_DIR}"
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
- cleanup_worktrees "${PROJECT_DIR}"
258
+ night_watch_history record "${PROJECT_DIR}" "${ELIGIBLE_PRD}" failure --exit-code "${EXIT_CODE}" 2>/dev/null || true
172
259
  fi