@jonit-dev/night-watch-cli 1.7.49 → 1.7.50

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 CHANGED
@@ -5,8 +5,6 @@ import 'reflect-metadata';
5
5
  import "reflect-metadata";
6
6
  import "reflect-metadata";
7
7
  import "reflect-metadata";
8
- import "reflect-metadata";
9
- import "reflect-metadata";
10
8
  import * as fs from "fs";
11
9
  import * as path from "path";
12
10
  import { fileURLToPath } from "url";
@@ -48,115 +46,127 @@ import * as fs6 from "fs";
48
46
  import * as fs7 from "fs";
49
47
  import * as path6 from "path";
50
48
  import { execSync as execSync2 } from "child_process";
51
- import * as fs8 from "fs";
52
- import * as path7 from "path";
53
49
  import * as os3 from "os";
50
+ import * as path7 from "path";
51
+ import * as fs8 from "fs";
52
+ import * as fs9 from "fs";
54
53
  import * as path8 from "path";
54
+ import * as os4 from "os";
55
+ import * as path9 from "path";
55
56
  import { execFileSync } from "child_process";
57
+ import { execFileSync as execFileSync2 } from "child_process";
58
+ import * as fs10 from "fs";
56
59
  import chalk from "chalk";
57
60
  import ora from "ora";
58
61
  import Table from "cli-table3";
59
- import * as fs9 from "fs";
60
- import * as fs10 from "fs";
61
- import * as os4 from "os";
62
- import * as path9 from "path";
63
- import * as crypto from "crypto";
62
+ import { execFileSync as execFileSync3 } from "child_process";
64
63
  import * as fs11 from "fs";
65
64
  import * as path10 from "path";
66
65
  import * as fs12 from "fs";
67
66
  import * as path11 from "path";
68
67
  import * as fs13 from "fs";
68
+ import * as os5 from "os";
69
69
  import * as path12 from "path";
70
+ import * as crypto from "crypto";
71
+ import * as fs14 from "fs";
72
+ import * as path13 from "path";
73
+ import * as fs15 from "fs";
74
+ import * as path14 from "path";
75
+ import * as fs16 from "fs";
76
+ import * as path15 from "path";
70
77
  import { spawn } from "child_process";
71
78
  import { createHash as createHash3 } from "crypto";
72
79
  import { spawn as spawn2 } from "child_process";
80
+ import { execFileSync as execFileSync4 } from "child_process";
81
+ import * as fs17 from "fs";
82
+ import * as path16 from "path";
73
83
  import "reflect-metadata";
74
84
  import { Command as Command2 } from "commander";
75
- import { existsSync as existsSync26, readFileSync as readFileSync16 } from "fs";
85
+ import { existsSync as existsSync30, readFileSync as readFileSync18 } from "fs";
76
86
  import { fileURLToPath as fileURLToPath4 } from "url";
77
- import { dirname as dirname8, join as join30 } from "path";
78
- import fs14 from "fs";
79
- import path13 from "path";
87
+ import { dirname as dirname8, join as join33 } from "path";
88
+ import fs18 from "fs";
89
+ import path17 from "path";
80
90
  import { execSync as execSync3 } from "child_process";
81
91
  import { fileURLToPath as fileURLToPath2 } from "url";
82
- import { dirname as dirname4, join as join13 } from "path";
92
+ import { dirname as dirname4, join as join16 } from "path";
83
93
  import * as readline from "readline";
84
- import * as fs15 from "fs";
85
- import * as path14 from "path";
86
- import { execFileSync as execFileSync2 } from "child_process";
87
- import * as path15 from "path";
88
- import * as path16 from "path";
89
- import * as fs16 from "fs";
90
- import * as path17 from "path";
91
- import { execSync as execSync4 } from "child_process";
94
+ import * as fs19 from "fs";
92
95
  import * as path18 from "path";
93
- import * as fs17 from "fs";
96
+ import { execFileSync as execFileSync5 } from "child_process";
94
97
  import * as path19 from "path";
95
- import * as fs18 from "fs";
96
- import chalk2 from "chalk";
97
- import { spawn as spawn3 } from "child_process";
98
98
  import * as path20 from "path";
99
- import * as fs19 from "fs";
100
99
  import * as fs20 from "fs";
101
100
  import * as path21 from "path";
101
+ import { execSync as execSync4 } from "child_process";
102
+ import * as path22 from "path";
103
+ import * as fs21 from "fs";
104
+ import * as path23 from "path";
105
+ import * as fs22 from "fs";
106
+ import chalk2 from "chalk";
107
+ import { spawn as spawn3 } from "child_process";
108
+ import * as path24 from "path";
109
+ import * as fs23 from "fs";
110
+ import * as fs24 from "fs";
111
+ import * as path25 from "path";
102
112
  import * as readline2 from "readline";
103
113
  import blessed6 from "blessed";
104
114
  import blessed from "blessed";
105
- import * as fs21 from "fs";
115
+ import * as fs25 from "fs";
106
116
  import blessed2 from "blessed";
107
117
  import blessed3 from "blessed";
108
118
  import cronstrue from "cronstrue";
109
119
  import blessed4 from "blessed";
110
120
  import { spawn as spawn4 } from "child_process";
111
121
  import blessed5 from "blessed";
112
- import * as fs22 from "fs";
113
- import * as path22 from "path";
114
- import * as fs27 from "fs";
115
122
  import * as fs26 from "fs";
116
- import * as path28 from "path";
123
+ import * as path26 from "path";
124
+ import * as fs31 from "fs";
125
+ import * as fs30 from "fs";
126
+ import * as path32 from "path";
117
127
  import { dirname as dirname7 } from "path";
118
128
  import { fileURLToPath as fileURLToPath3 } from "url";
119
129
  import cors from "cors";
120
130
  import express from "express";
121
- import * as fs23 from "fs";
122
- import * as path23 from "path";
123
- import * as fs24 from "fs";
124
- import * as path24 from "path";
131
+ import * as fs27 from "fs";
132
+ import * as path27 from "path";
133
+ import * as fs28 from "fs";
134
+ import * as path28 from "path";
125
135
  import { spawn as spawn5 } from "child_process";
126
136
  import { Router } from "express";
127
137
  import { Router as Router2 } from "express";
128
138
  import { Router as Router3 } from "express";
129
139
  import { Router as Router4 } from "express";
130
- import * as fs25 from "fs";
131
- import * as path25 from "path";
140
+ import * as fs29 from "fs";
141
+ import * as path29 from "path";
132
142
  import { execSync as execSync5 } from "child_process";
133
143
  import { Router as Router5 } from "express";
134
- import * as path26 from "path";
144
+ import * as path30 from "path";
135
145
  import { Router as Router6 } from "express";
136
146
  import { Router as Router7 } from "express";
137
- import * as path27 from "path";
147
+ import * as path31 from "path";
138
148
  import { Router as Router8 } from "express";
139
149
  import { Router as Router9 } from "express";
140
150
  import { CronExpressionParser } from "cron-parser";
141
151
  import { spawnSync } from "child_process";
142
- import * as fs28 from "fs";
143
- import * as path29 from "path";
144
- import * as fs29 from "fs";
145
- import * as path30 from "path";
152
+ import * as fs32 from "fs";
153
+ import * as path33 from "path";
154
+ import * as fs33 from "fs";
155
+ import * as path34 from "path";
146
156
  import chalk3 from "chalk";
147
157
  import chalk4 from "chalk";
148
158
  import { execSync as execSync6 } from "child_process";
149
- import * as fs30 from "fs";
159
+ import * as fs34 from "fs";
150
160
  import * as readline3 from "readline";
151
- import * as fs31 from "fs";
152
- import * as path31 from "path";
153
- import * as os5 from "os";
154
- import * as path32 from "path";
161
+ import * as fs35 from "fs";
162
+ import * as path35 from "path";
163
+ import * as os6 from "os";
164
+ import * as path36 from "path";
155
165
  import chalk5 from "chalk";
156
166
  import { Command } from "commander";
157
- import { execFileSync as execFileSync3 } from "child_process";
158
- import * as fs32 from "fs";
159
- import * as path33 from "path";
167
+ import { execFileSync as execFileSync6 } from "child_process";
168
+ import * as fs36 from "fs";
169
+ import * as path37 from "path";
160
170
  import * as readline4 from "readline";
161
171
  import chalk6 from "chalk";
162
172
  var __defProp = Object.defineProperty;
@@ -3455,101 +3465,107 @@ function findMatchingIssue(targetTitle, issues, threshold = 0.8) {
3455
3465
  }
3456
3466
  return bestMatch;
3457
3467
  }
3468
+ var HORIZON_SHORT_TERM;
3469
+ var HORIZON_MEDIUM_TERM;
3470
+ var HORIZON_LONG_TERM;
3458
3471
  var ROADMAP_SECTION_MAPPINGS;
3459
3472
  var init_roadmap_mapping = __esm({
3460
3473
  "../core/dist/board/roadmap-mapping.js"() {
3461
3474
  "use strict";
3475
+ HORIZON_SHORT_TERM = "short-term";
3476
+ HORIZON_MEDIUM_TERM = "medium-term";
3477
+ HORIZON_LONG_TERM = "long-term";
3462
3478
  ROADMAP_SECTION_MAPPINGS = [
3463
3479
  {
3464
3480
  sectionPattern: /§1.*Reliability.*correctness/i,
3465
3481
  category: "reliability",
3466
- horizon: "short-term"
3482
+ horizon: HORIZON_SHORT_TERM
3467
3483
  },
3468
3484
  {
3469
3485
  sectionPattern: /§2.*Quality.*developer/i,
3470
3486
  category: "quality",
3471
- horizon: "short-term"
3487
+ horizon: HORIZON_SHORT_TERM
3472
3488
  },
3473
3489
  {
3474
3490
  sectionPattern: /§3.*Product.*operators/i,
3475
3491
  category: "product",
3476
- horizon: "short-term"
3492
+ horizon: HORIZON_SHORT_TERM
3477
3493
  },
3478
3494
  {
3479
3495
  sectionPattern: /§4.*Unified.*operations/i,
3480
3496
  category: "ux",
3481
- horizon: "medium-term"
3497
+ horizon: HORIZON_MEDIUM_TERM
3482
3498
  },
3483
3499
  {
3484
3500
  sectionPattern: /§5.*Provider.*execution/i,
3485
3501
  category: "provider",
3486
- horizon: "medium-term"
3502
+ horizon: HORIZON_MEDIUM_TERM
3487
3503
  },
3488
3504
  {
3489
3505
  sectionPattern: /§6.*Team.*multi-project/i,
3490
3506
  category: "team",
3491
- horizon: "medium-term"
3507
+ horizon: HORIZON_MEDIUM_TERM
3492
3508
  },
3493
3509
  {
3494
3510
  sectionPattern: /§7.*Platformization.*enterprise/i,
3495
3511
  category: "platform",
3496
- horizon: "long-term"
3512
+ horizon: HORIZON_LONG_TERM
3497
3513
  },
3498
3514
  {
3499
3515
  sectionPattern: /§8.*Intelligence.*autonomous/i,
3500
3516
  category: "intelligence",
3501
- horizon: "long-term"
3517
+ horizon: HORIZON_LONG_TERM
3502
3518
  },
3503
3519
  {
3504
3520
  sectionPattern: /§9.*Ecosystem.*adoption/i,
3505
3521
  category: "ecosystem",
3506
- horizon: "long-term"
3522
+ horizon: HORIZON_LONG_TERM
3507
3523
  },
3508
3524
  // Fallback patterns without section numbers
3509
3525
  {
3510
3526
  sectionPattern: /Reliability.*correctness/i,
3511
3527
  category: "reliability",
3512
- horizon: "short-term"
3528
+ horizon: HORIZON_SHORT_TERM
3513
3529
  },
3514
3530
  {
3515
3531
  sectionPattern: /Quality.*developer.*workflow/i,
3516
3532
  category: "quality",
3517
- horizon: "short-term"
3533
+ horizon: HORIZON_SHORT_TERM
3518
3534
  },
3519
3535
  {
3520
3536
  sectionPattern: /Product.*completeness/i,
3521
3537
  category: "product",
3522
- horizon: "short-term"
3538
+ horizon: HORIZON_SHORT_TERM
3523
3539
  },
3524
3540
  {
3525
3541
  sectionPattern: /Unified.*operations/i,
3526
3542
  category: "ux",
3527
- horizon: "medium-term"
3543
+ horizon: HORIZON_MEDIUM_TERM
3528
3544
  },
3529
3545
  {
3530
3546
  sectionPattern: /Provider.*execution/i,
3531
3547
  category: "provider",
3532
- horizon: "medium-term"
3548
+ horizon: HORIZON_MEDIUM_TERM
3533
3549
  },
3534
3550
  {
3535
3551
  sectionPattern: /Team.*multi-project/i,
3536
3552
  category: "team",
3537
- horizon: "medium-term"
3553
+ horizon: HORIZON_MEDIUM_TERM
3538
3554
  },
3539
3555
  {
3540
3556
  sectionPattern: /Platformization.*enterprise/i,
3541
3557
  category: "platform",
3542
- horizon: "long-term"
3558
+ horizon: HORIZON_LONG_TERM
3543
3559
  },
3544
3560
  {
3545
3561
  sectionPattern: /Intelligence.*autonomous/i,
3546
3562
  category: "intelligence",
3547
- horizon: "long-term"
3563
+ horizon: HORIZON_LONG_TERM
3548
3564
  },
3549
3565
  {
3550
3566
  sectionPattern: /Ecosystem.*adoption/i,
3551
3567
  category: "ecosystem",
3552
- horizon: "long-term"
3568
+ horizon: HORIZON_LONG_TERM
3553
3569
  }
3554
3570
  ];
3555
3571
  }
@@ -4288,6 +4304,34 @@ function checkLockFile(lockPath) {
4288
4304
  return { running: false, pid: null };
4289
4305
  }
4290
4306
  }
4307
+ function acquireLock(lockPath, pid) {
4308
+ const effectivePid = pid ?? process.pid;
4309
+ if (fs5.existsSync(lockPath)) {
4310
+ const lockInfo = checkLockFile(lockPath);
4311
+ if (lockInfo.running) {
4312
+ return false;
4313
+ }
4314
+ try {
4315
+ fs5.unlinkSync(lockPath);
4316
+ } catch {
4317
+ return false;
4318
+ }
4319
+ }
4320
+ try {
4321
+ fs5.writeFileSync(lockPath, String(effectivePid), "utf-8");
4322
+ return true;
4323
+ } catch {
4324
+ return false;
4325
+ }
4326
+ }
4327
+ function releaseLock(lockPath) {
4328
+ try {
4329
+ if (fs5.existsSync(lockPath)) {
4330
+ fs5.unlinkSync(lockPath);
4331
+ }
4332
+ } catch {
4333
+ }
4334
+ }
4291
4335
  function countPRDs(projectDir, prdDir, maxRuntime) {
4292
4336
  const fullPrdPath = path5.join(projectDir, prdDir);
4293
4337
  if (!fs5.existsSync(fullPrdPath)) {
@@ -4879,7 +4923,7 @@ function checkPrdDirectory(projectDir, prdDir) {
4879
4923
  }
4880
4924
  };
4881
4925
  }
4882
- const prds = fs7.readdirSync(prdPath).filter((f) => f.endsWith(".md") && f !== "NIGHT-WATCH-SUMMARY.md");
4926
+ const prds = fs7.readdirSync(prdPath).filter((f) => f.endsWith(".md"));
4883
4927
  return {
4884
4928
  passed: true,
4885
4929
  message: `PRD directory found: ${prdDir} (${prds.length} PRDs)`,
@@ -4952,12 +4996,90 @@ var init_checks = __esm({
4952
4996
  init_constants();
4953
4997
  }
4954
4998
  });
4999
+ function claimPrd(prdDir, prdFile, pid) {
5000
+ const claimPath = path7.join(prdDir, prdFile + CLAIM_FILE_EXTENSION);
5001
+ const claimData = {
5002
+ timestamp: Math.floor(Date.now() / 1e3),
5003
+ hostname: os3.hostname(),
5004
+ pid: pid ?? process.pid
5005
+ };
5006
+ fs8.writeFileSync(claimPath, JSON.stringify(claimData), "utf-8");
5007
+ }
5008
+ function releaseClaim(prdDir, prdFile) {
5009
+ const claimPath = path7.join(prdDir, prdFile + CLAIM_FILE_EXTENSION);
5010
+ try {
5011
+ if (fs8.existsSync(claimPath)) {
5012
+ fs8.unlinkSync(claimPath);
5013
+ }
5014
+ } catch {
5015
+ }
5016
+ }
5017
+ function isClaimed(prdDir, prdFile, maxRuntime) {
5018
+ const claimPath = path7.join(prdDir, prdFile + CLAIM_FILE_EXTENSION);
5019
+ if (!fs8.existsSync(claimPath)) {
5020
+ return false;
5021
+ }
5022
+ try {
5023
+ const content = fs8.readFileSync(claimPath, "utf-8");
5024
+ const claimData = JSON.parse(content);
5025
+ if (typeof claimData.timestamp !== "number") {
5026
+ fs8.unlinkSync(claimPath);
5027
+ return false;
5028
+ }
5029
+ const now = Math.floor(Date.now() / 1e3);
5030
+ const age = now - claimData.timestamp;
5031
+ if (age >= maxRuntime) {
5032
+ fs8.unlinkSync(claimPath);
5033
+ return false;
5034
+ }
5035
+ return true;
5036
+ } catch {
5037
+ try {
5038
+ fs8.unlinkSync(claimPath);
5039
+ } catch {
5040
+ }
5041
+ return false;
5042
+ }
5043
+ }
5044
+ function readClaimInfo(prdDir, prdFile, maxRuntime) {
5045
+ const claimPath = path7.join(prdDir, prdFile + CLAIM_FILE_EXTENSION);
5046
+ if (!fs8.existsSync(claimPath)) {
5047
+ return null;
5048
+ }
5049
+ try {
5050
+ const content = fs8.readFileSync(claimPath, "utf-8");
5051
+ const claimData = JSON.parse(content);
5052
+ if (typeof claimData.timestamp !== "number") {
5053
+ fs8.unlinkSync(claimPath);
5054
+ return null;
5055
+ }
5056
+ const now = Math.floor(Date.now() / 1e3);
5057
+ const age = now - claimData.timestamp;
5058
+ if (age >= maxRuntime) {
5059
+ fs8.unlinkSync(claimPath);
5060
+ return null;
5061
+ }
5062
+ return claimData;
5063
+ } catch {
5064
+ try {
5065
+ fs8.unlinkSync(claimPath);
5066
+ } catch {
5067
+ }
5068
+ return null;
5069
+ }
5070
+ }
5071
+ var init_claim_manager = __esm({
5072
+ "../core/dist/utils/claim-manager.js"() {
5073
+ "use strict";
5074
+ init_constants();
5075
+ }
5076
+ });
4955
5077
  function saveConfig(projectDir, changes) {
4956
- const configPath = path7.join(projectDir, CONFIG_FILE_NAME);
5078
+ const configPath = path8.join(projectDir, CONFIG_FILE_NAME);
4957
5079
  try {
4958
5080
  let existing = {};
4959
- if (fs8.existsSync(configPath)) {
4960
- const content = fs8.readFileSync(configPath, "utf-8");
5081
+ if (fs9.existsSync(configPath)) {
5082
+ const content = fs9.readFileSync(configPath, "utf-8");
4961
5083
  existing = JSON.parse(content);
4962
5084
  }
4963
5085
  const merged = { ...existing };
@@ -4970,7 +5092,7 @@ function saveConfig(projectDir, changes) {
4970
5092
  }
4971
5093
  }
4972
5094
  }
4973
- fs8.writeFileSync(configPath, JSON.stringify(merged, null, 2) + "\n");
5095
+ fs9.writeFileSync(configPath, JSON.stringify(merged, null, 2) + "\n");
4974
5096
  return { success: true };
4975
5097
  } catch (err) {
4976
5098
  return {
@@ -4986,8 +5108,8 @@ var init_config_writer = __esm({
4986
5108
  }
4987
5109
  });
4988
5110
  function getHistoryPath() {
4989
- const base = process.env.NIGHT_WATCH_HOME || path8.join(os3.homedir(), GLOBAL_CONFIG_DIR);
4990
- return path8.join(base, HISTORY_FILE_NAME);
5111
+ const base = process.env.NIGHT_WATCH_HOME || path9.join(os4.homedir(), GLOBAL_CONFIG_DIR);
5112
+ return path9.join(base, HISTORY_FILE_NAME);
4991
5113
  }
4992
5114
  function loadHistory() {
4993
5115
  const { executionHistory } = getRepositories();
@@ -4998,7 +5120,7 @@ function saveHistory(history) {
4998
5120
  executionHistory.replaceAll(history);
4999
5121
  }
5000
5122
  function recordExecution(projectDir, prdFile, outcome, exitCode, attempt = 1) {
5001
- const resolved = path8.resolve(projectDir);
5123
+ const resolved = path9.resolve(projectDir);
5002
5124
  const { executionHistory } = getRepositories();
5003
5125
  const record = {
5004
5126
  timestamp: Math.floor(Date.now() / 1e3),
@@ -5010,7 +5132,7 @@ function recordExecution(projectDir, prdFile, outcome, exitCode, attempt = 1) {
5010
5132
  executionHistory.trimRecords(resolved, prdFile, MAX_HISTORY_RECORDS_PER_PRD);
5011
5133
  }
5012
5134
  function getLastExecution(projectDir, prdFile) {
5013
- const resolved = path8.resolve(projectDir);
5135
+ const resolved = path9.resolve(projectDir);
5014
5136
  const { executionHistory } = getRepositories();
5015
5137
  const records = executionHistory.getRecords(resolved, prdFile);
5016
5138
  return records.length > 0 ? records[0] : null;
@@ -5035,6 +5157,94 @@ var init_execution_history = __esm({
5035
5157
  init_client();
5036
5158
  }
5037
5159
  });
5160
+ function getBranchTipTimestamp(projectDir, branch) {
5161
+ let remoteTs = null;
5162
+ let localTs = null;
5163
+ try {
5164
+ const output = execFileSync("git", ["-C", projectDir, "log", "-1", "--format=%ct", `refs/remotes/origin/${branch}`], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
5165
+ if (output) {
5166
+ remoteTs = parseInt(output, 10);
5167
+ }
5168
+ } catch {
5169
+ }
5170
+ try {
5171
+ const output = execFileSync("git", ["-C", projectDir, "log", "-1", "--format=%ct", `refs/heads/${branch}`], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
5172
+ if (output) {
5173
+ localTs = parseInt(output, 10);
5174
+ }
5175
+ } catch {
5176
+ }
5177
+ if (remoteTs !== null && localTs !== null) {
5178
+ return localTs > remoteTs ? localTs : remoteTs;
5179
+ }
5180
+ if (remoteTs !== null) {
5181
+ return remoteTs;
5182
+ }
5183
+ if (localTs !== null) {
5184
+ return localTs;
5185
+ }
5186
+ return null;
5187
+ }
5188
+ function detectDefaultBranch(projectDir) {
5189
+ const mainTs = getBranchTipTimestamp(projectDir, "main");
5190
+ const masterTs = getBranchTipTimestamp(projectDir, "master");
5191
+ if (mainTs !== null && masterTs !== null) {
5192
+ return mainTs >= masterTs ? "main" : "master";
5193
+ }
5194
+ if (mainTs !== null) {
5195
+ return "main";
5196
+ }
5197
+ if (masterTs !== null) {
5198
+ return "master";
5199
+ }
5200
+ try {
5201
+ const output = execFileSync("git", ["-C", projectDir, "symbolic-ref", "refs/remotes/origin/HEAD"], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
5202
+ const match = output.match(/^refs\/remotes\/origin\/(.+)$/);
5203
+ if (match) {
5204
+ return match[1];
5205
+ }
5206
+ } catch {
5207
+ }
5208
+ return "main";
5209
+ }
5210
+ function resolveWorktreeBaseRef(projectDir, defaultBranch) {
5211
+ try {
5212
+ execFileSync("git", [
5213
+ "-C",
5214
+ projectDir,
5215
+ "rev-parse",
5216
+ "--verify",
5217
+ "--quiet",
5218
+ `refs/remotes/origin/${defaultBranch}`
5219
+ ], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
5220
+ return `origin/${defaultBranch}`;
5221
+ } catch {
5222
+ }
5223
+ try {
5224
+ execFileSync("git", ["-C", projectDir, "rev-parse", "--verify", "--quiet", `refs/heads/${defaultBranch}`], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
5225
+ return defaultBranch;
5226
+ } catch {
5227
+ }
5228
+ try {
5229
+ execFileSync("git", ["-C", projectDir, "rev-parse", "--verify", "--quiet", "refs/remotes/origin/HEAD"], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
5230
+ return "origin/HEAD";
5231
+ } catch {
5232
+ }
5233
+ try {
5234
+ execFileSync("git", ["-C", projectDir, "rev-parse", "--verify", "--quiet", "HEAD"], {
5235
+ encoding: "utf-8",
5236
+ stdio: ["pipe", "pipe", "pipe"]
5237
+ });
5238
+ return "HEAD";
5239
+ } catch {
5240
+ }
5241
+ return null;
5242
+ }
5243
+ var init_git_utils = __esm({
5244
+ "../core/dist/utils/git-utils.js"() {
5245
+ "use strict";
5246
+ }
5247
+ });
5038
5248
  function parsePrDetails(raw) {
5039
5249
  try {
5040
5250
  const details = JSON.parse(raw);
@@ -5056,7 +5266,7 @@ function parsePrDetails(raw) {
5056
5266
  }
5057
5267
  function fetchPrBySelector(selector, cwd) {
5058
5268
  try {
5059
- const output = execFileSync("gh", ["pr", "view", selector, "--json", "number,title,url,body,additions,deletions,changedFiles"], { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
5269
+ const output = execFileSync2("gh", ["pr", "view", selector, "--json", "number,title,url,body,additions,deletions,changedFiles"], { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
5060
5270
  return parsePrDetails(output);
5061
5271
  } catch {
5062
5272
  return null;
@@ -5070,7 +5280,7 @@ function fetchPrDetailsByNumber(prNumber, cwd) {
5070
5280
  }
5071
5281
  function fetchPrDetails(branchPrefix, cwd) {
5072
5282
  try {
5073
- const listOutput = execFileSync("gh", ["pr", "list", "--state", "open", "--json", "number,headRefName", "--limit", "20"], { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
5283
+ const listOutput = execFileSync2("gh", ["pr", "list", "--state", "open", "--json", "number,headRefName", "--limit", "20"], { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
5074
5284
  const prs = JSON.parse(listOutput);
5075
5285
  const matching = prs.filter((pr) => pr.headRefName.startsWith(branchPrefix + "/"));
5076
5286
  if (matching.length === 0) {
@@ -5084,7 +5294,7 @@ function fetchPrDetails(branchPrefix, cwd) {
5084
5294
  }
5085
5295
  function fetchReviewedPrDetails(branchPatterns, cwd) {
5086
5296
  try {
5087
- const listOutput = execFileSync("gh", ["pr", "list", "--state", "open", "--json", "number,headRefName", "--limit", "20"], { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
5297
+ const listOutput = execFileSync2("gh", ["pr", "list", "--state", "open", "--json", "number,headRefName", "--limit", "20"], { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
5088
5298
  const prs = JSON.parse(listOutput);
5089
5299
  const matching = prs.filter((pr) => branchPatterns.some((pattern) => pr.headRefName.startsWith(pattern)));
5090
5300
  if (matching.length === 0) {
@@ -5125,6 +5335,45 @@ var init_github = __esm({
5125
5335
  "use strict";
5126
5336
  }
5127
5337
  });
5338
+ function rotateLog(logFile, maxSize = DEFAULT_MAX_LOG_SIZE) {
5339
+ if (!fs10.existsSync(logFile)) {
5340
+ return false;
5341
+ }
5342
+ try {
5343
+ const stats = fs10.statSync(logFile);
5344
+ if (stats.size > maxSize) {
5345
+ const oldPath = `${logFile}.old`;
5346
+ fs10.renameSync(logFile, oldPath);
5347
+ return true;
5348
+ }
5349
+ } catch {
5350
+ }
5351
+ return false;
5352
+ }
5353
+ function checkRateLimited(logFile, startLine) {
5354
+ if (!fs10.existsSync(logFile)) {
5355
+ return false;
5356
+ }
5357
+ try {
5358
+ const content = fs10.readFileSync(logFile, "utf-8");
5359
+ const lines = content.split("\n");
5360
+ let linesToCheck;
5361
+ if (startLine !== void 0 && startLine > 0) {
5362
+ linesToCheck = lines.slice(startLine);
5363
+ } else {
5364
+ linesToCheck = lines.slice(-20);
5365
+ }
5366
+ return linesToCheck.some((line) => line.includes("429"));
5367
+ } catch {
5368
+ return false;
5369
+ }
5370
+ }
5371
+ var init_log_utils = __esm({
5372
+ "../core/dist/utils/log-utils.js"() {
5373
+ "use strict";
5374
+ init_constants();
5375
+ }
5376
+ });
5128
5377
  function success(msg) {
5129
5378
  console.log(chalk.green("\u2714"), msg);
5130
5379
  }
@@ -5284,6 +5533,11 @@ function buildDescription(ctx) {
5284
5533
  if (ctx.duration !== void 0) {
5285
5534
  lines.push(`Duration: ${ctx.duration}s`);
5286
5535
  }
5536
+ if (ctx.event === "run_timeout") {
5537
+ lines.push("Cause: Execution hit the max runtime limit and was terminated.");
5538
+ lines.push("Resume: Progress is checkpointed on timeout, and the next run resumes from that branch state.");
5539
+ lines.push("Recommendation: Avoid huge PRDs; slice large work into smaller PRDs/phases.");
5540
+ }
5287
5541
  if (ctx.event === "review_completed" && ctx.attempts !== void 0 && ctx.attempts > 1) {
5288
5542
  const retryInfo = `Attempts: ${ctx.attempts}`;
5289
5543
  if (ctx.finalScore !== void 0) {
@@ -5455,27 +5709,145 @@ var init_notify = __esm({
5455
5709
  init_github();
5456
5710
  }
5457
5711
  });
5712
+ function getOpenBranches(projectDir) {
5713
+ try {
5714
+ const output = execFileSync3("gh", ["pr", "list", "--state", "open", "--json", "headRefName", "--jq", ".[].headRefName"], { cwd: projectDir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
5715
+ return output.trim().split("\n").filter((b) => b.length > 0);
5716
+ } catch {
5717
+ return [];
5718
+ }
5719
+ }
5720
+ function sortPrdsByPriority(files, priorityList) {
5721
+ if (!priorityList.length) {
5722
+ return files;
5723
+ }
5724
+ const prioritySet = new Set(priorityList);
5725
+ const prioritized = [];
5726
+ const remaining = [];
5727
+ for (const priorityName of priorityList) {
5728
+ const match = files.find((f) => f === `${priorityName}.md`);
5729
+ if (match) {
5730
+ prioritized.push(match);
5731
+ }
5732
+ }
5733
+ for (const file of files) {
5734
+ if (!prioritySet.has(file.replace(/\.md$/, ""))) {
5735
+ remaining.push(file);
5736
+ }
5737
+ }
5738
+ return [...prioritized, ...remaining];
5739
+ }
5740
+ function findEligiblePrd(options) {
5741
+ const { prdDir, projectDir, maxRuntime, prdPriority } = options;
5742
+ const doneDir = path10.join(prdDir, "done");
5743
+ if (!fs11.existsSync(prdDir)) {
5744
+ return null;
5745
+ }
5746
+ let prdFiles = fs11.readdirSync(prdDir).filter((f) => f.endsWith(".md") && fs11.statSync(path10.join(prdDir, f)).isFile()).sort();
5747
+ if (prdFiles.length === 0) {
5748
+ return null;
5749
+ }
5750
+ if (prdPriority) {
5751
+ const priorityList = prdPriority.split(":").filter((p) => p.length > 0);
5752
+ prdFiles = sortPrdsByPriority(prdFiles, priorityList);
5753
+ }
5754
+ const openBranches = getOpenBranches(projectDir);
5755
+ for (const prdFile of prdFiles) {
5756
+ const prdName = prdFile.replace(/\.md$/, "");
5757
+ const prdPath = path10.join(prdDir, prdFile);
5758
+ if (isClaimed(prdDir, prdFile, maxRuntime)) {
5759
+ continue;
5760
+ }
5761
+ if (isInCooldown(projectDir, prdFile, maxRuntime)) {
5762
+ continue;
5763
+ }
5764
+ if (openBranches.some((branch) => branch.includes(prdName))) {
5765
+ continue;
5766
+ }
5767
+ const dependencies = parsePrdDependencies(prdPath);
5768
+ let allDepsMet = true;
5769
+ for (const dep of dependencies) {
5770
+ const depFile = dep.endsWith(".md") ? dep : `${dep}.md`;
5771
+ const depPath = path10.join(doneDir, depFile);
5772
+ if (!fs11.existsSync(depPath)) {
5773
+ allDepsMet = false;
5774
+ break;
5775
+ }
5776
+ }
5777
+ if (!allDepsMet) {
5778
+ continue;
5779
+ }
5780
+ return prdFile;
5781
+ }
5782
+ return null;
5783
+ }
5784
+ function findEligibleBoardIssue(options) {
5785
+ const { projectDir, maxRuntime } = options;
5786
+ try {
5787
+ const output = execFileSync3("gh", ["issue", "list", "--state", "open", "--json", "number,title,body", "--jq", ".[]"], { cwd: projectDir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
5788
+ const issues = output.trim().split("\n").filter((line) => line.length > 0);
5789
+ for (const issueLine of issues) {
5790
+ try {
5791
+ const issue = JSON.parse(issueLine);
5792
+ const claimFile = `issue-${issue.number}`;
5793
+ if (isClaimed(projectDir, claimFile, maxRuntime)) {
5794
+ continue;
5795
+ }
5796
+ return {
5797
+ number: issue.number,
5798
+ title: issue.title,
5799
+ body: issue.body || ""
5800
+ };
5801
+ } catch {
5802
+ continue;
5803
+ }
5804
+ }
5805
+ } catch {
5806
+ }
5807
+ return null;
5808
+ }
5809
+ var init_prd_discovery = __esm({
5810
+ "../core/dist/utils/prd-discovery.js"() {
5811
+ "use strict";
5812
+ init_claim_manager();
5813
+ init_execution_history();
5814
+ init_status_data();
5815
+ }
5816
+ });
5458
5817
  function slugify(name) {
5459
5818
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
5460
5819
  }
5461
5820
  function getNextPrdNumber(prdDir) {
5462
- if (!fs9.existsSync(prdDir))
5821
+ if (!fs12.existsSync(prdDir))
5463
5822
  return 1;
5464
- const files = fs9.readdirSync(prdDir).filter((f) => f.endsWith(".md") && f !== "NIGHT-WATCH-SUMMARY.md");
5823
+ const files = fs12.readdirSync(prdDir).filter((f) => f.endsWith(".md"));
5465
5824
  const numbers = files.map((f) => {
5466
5825
  const match = f.match(/^(\d+)-/);
5467
5826
  return match ? parseInt(match[1], 10) : 0;
5468
5827
  });
5469
5828
  return Math.max(0, ...numbers) + 1;
5470
5829
  }
5830
+ function markPrdDone(prdDir, prdFile) {
5831
+ const sourcePath = path11.join(prdDir, prdFile);
5832
+ if (!fs12.existsSync(sourcePath)) {
5833
+ return false;
5834
+ }
5835
+ const doneDir = path11.join(prdDir, "done");
5836
+ if (!fs12.existsSync(doneDir)) {
5837
+ fs12.mkdirSync(doneDir, { recursive: true });
5838
+ }
5839
+ const destPath = path11.join(doneDir, prdFile);
5840
+ fs12.renameSync(sourcePath, destPath);
5841
+ return true;
5842
+ }
5471
5843
  var init_prd_utils = __esm({
5472
5844
  "../core/dist/utils/prd-utils.js"() {
5473
5845
  "use strict";
5474
5846
  }
5475
5847
  });
5476
5848
  function getRegistryPath() {
5477
- const base = process.env.NIGHT_WATCH_HOME || path9.join(os4.homedir(), GLOBAL_CONFIG_DIR);
5478
- return path9.join(base, REGISTRY_FILE_NAME);
5849
+ const base = process.env.NIGHT_WATCH_HOME || path12.join(os5.homedir(), GLOBAL_CONFIG_DIR);
5850
+ return path12.join(base, REGISTRY_FILE_NAME);
5479
5851
  }
5480
5852
  function loadRegistry() {
5481
5853
  const { projectRegistry } = getRepositories();
@@ -5489,7 +5861,7 @@ function saveRegistry(entries) {
5489
5861
  }
5490
5862
  }
5491
5863
  function registerProject(projectDir) {
5492
- const resolvedPath = path9.resolve(projectDir);
5864
+ const resolvedPath = path12.resolve(projectDir);
5493
5865
  const { projectRegistry } = getRepositories();
5494
5866
  const entries = projectRegistry.getAll();
5495
5867
  const existing = entries.find((e) => e.path === resolvedPath);
@@ -5498,13 +5870,13 @@ function registerProject(projectDir) {
5498
5870
  }
5499
5871
  const name = getProjectName(resolvedPath);
5500
5872
  const nameExists = entries.some((e) => e.name === name);
5501
- const finalName = nameExists ? `${name}-${path9.basename(resolvedPath)}` : name;
5873
+ const finalName = nameExists ? `${name}-${path12.basename(resolvedPath)}` : name;
5502
5874
  const entry = { name: finalName, path: resolvedPath };
5503
5875
  projectRegistry.upsert(entry);
5504
5876
  return entry;
5505
5877
  }
5506
5878
  function unregisterProject(projectDir) {
5507
- const resolvedPath = path9.resolve(projectDir);
5879
+ const resolvedPath = path12.resolve(projectDir);
5508
5880
  const { projectRegistry } = getRepositories();
5509
5881
  return projectRegistry.remove(resolvedPath);
5510
5882
  }
@@ -5513,7 +5885,7 @@ function validateRegistry() {
5513
5885
  const valid = [];
5514
5886
  const invalid = [];
5515
5887
  for (const entry of entries) {
5516
- if (fs10.existsSync(entry.path) && fs10.existsSync(path9.join(entry.path, CONFIG_FILE_NAME))) {
5888
+ if (fs13.existsSync(entry.path) && fs13.existsSync(path12.join(entry.path, CONFIG_FILE_NAME))) {
5517
5889
  valid.push(entry);
5518
5890
  } else {
5519
5891
  invalid.push(entry);
@@ -5706,15 +6078,15 @@ var init_roadmap_parser = __esm({
5706
6078
  }
5707
6079
  });
5708
6080
  function getStateFilePath(prdDir) {
5709
- return path10.join(prdDir, STATE_FILE_NAME);
6081
+ return path13.join(prdDir, STATE_FILE_NAME);
5710
6082
  }
5711
6083
  function readJsonState(prdDir) {
5712
6084
  const statePath = getStateFilePath(prdDir);
5713
- if (!fs11.existsSync(statePath)) {
6085
+ if (!fs14.existsSync(statePath)) {
5714
6086
  return null;
5715
6087
  }
5716
6088
  try {
5717
- const content = fs11.readFileSync(statePath, "utf-8");
6089
+ const content = fs14.readFileSync(statePath, "utf-8");
5718
6090
  const parsed = JSON.parse(content);
5719
6091
  if (typeof parsed !== "object" || parsed === null) {
5720
6092
  return null;
@@ -5752,11 +6124,11 @@ function saveRoadmapState(prdDir, state) {
5752
6124
  const { roadmapState } = getRepositories();
5753
6125
  roadmapState.save(prdDir, state);
5754
6126
  const statePath = getStateFilePath(prdDir);
5755
- const dir = path10.dirname(statePath);
5756
- if (!fs11.existsSync(dir)) {
5757
- fs11.mkdirSync(dir, { recursive: true });
6127
+ const dir = path13.dirname(statePath);
6128
+ if (!fs14.existsSync(dir)) {
6129
+ fs14.mkdirSync(dir, { recursive: true });
5758
6130
  }
5759
- fs11.writeFileSync(statePath, JSON.stringify(state, null, 2) + "\n", "utf-8");
6131
+ fs14.writeFileSync(statePath, JSON.stringify(state, null, 2) + "\n", "utf-8");
5760
6132
  }
5761
6133
  function createEmptyState() {
5762
6134
  return {
@@ -5799,9 +6171,9 @@ function loadSlicerTemplate(templateDir) {
5799
6171
  if (cachedTemplate) {
5800
6172
  return cachedTemplate;
5801
6173
  }
5802
- const templatePath = templateDir ? path11.join(templateDir, "night-watch-slicer.md") : path11.resolve(__dirname, "..", "..", "templates", "night-watch-slicer.md");
6174
+ const templatePath = templateDir ? path14.join(templateDir, "night-watch-slicer.md") : path14.resolve(__dirname, "..", "..", "templates", "night-watch-slicer.md");
5803
6175
  try {
5804
- cachedTemplate = fs12.readFileSync(templatePath, "utf-8");
6176
+ cachedTemplate = fs15.readFileSync(templatePath, "utf-8");
5805
6177
  return cachedTemplate;
5806
6178
  } catch (error2) {
5807
6179
  console.warn(`Warning: Could not load slicer template from ${templatePath}, using default:`, error2 instanceof Error ? error2.message : String(error2));
@@ -5826,7 +6198,7 @@ function createSlicerPromptVars(title, section, description, prdDir, prdFilename
5826
6198
  title,
5827
6199
  section,
5828
6200
  description: description || "(No description provided)",
5829
- outputFilePath: path11.join(prdDir, prdFilename),
6201
+ outputFilePath: path14.join(prdDir, prdFilename),
5830
6202
  prdDir
5831
6203
  };
5832
6204
  }
@@ -6017,11 +6389,11 @@ function auditFindingToRoadmapItem(finding) {
6017
6389
  };
6018
6390
  }
6019
6391
  function collectAuditPlannerItems(projectDir) {
6020
- const reportPath = path12.join(projectDir, "logs", "audit-report.md");
6021
- if (!fs13.existsSync(reportPath)) {
6392
+ const reportPath = path15.join(projectDir, "logs", "audit-report.md");
6393
+ if (!fs16.existsSync(reportPath)) {
6022
6394
  return [];
6023
6395
  }
6024
- const reportContent = fs13.readFileSync(reportPath, "utf-8");
6396
+ const reportContent = fs16.readFileSync(reportPath, "utf-8");
6025
6397
  if (!reportContent.trim() || /\bNO_ISSUES_FOUND\b/.test(reportContent)) {
6026
6398
  return [];
6027
6399
  }
@@ -6030,9 +6402,9 @@ function collectAuditPlannerItems(projectDir) {
6030
6402
  return findings.map(auditFindingToRoadmapItem);
6031
6403
  }
6032
6404
  function getRoadmapStatus(projectDir, config) {
6033
- const roadmapPath = path12.join(projectDir, config.roadmapScanner.roadmapPath);
6405
+ const roadmapPath = path15.join(projectDir, config.roadmapScanner.roadmapPath);
6034
6406
  const scannerEnabled = config.roadmapScanner.enabled;
6035
- if (!fs13.existsSync(roadmapPath)) {
6407
+ if (!fs16.existsSync(roadmapPath)) {
6036
6408
  return {
6037
6409
  found: false,
6038
6410
  enabled: scannerEnabled,
@@ -6043,9 +6415,9 @@ function getRoadmapStatus(projectDir, config) {
6043
6415
  items: []
6044
6416
  };
6045
6417
  }
6046
- const content = fs13.readFileSync(roadmapPath, "utf-8");
6418
+ const content = fs16.readFileSync(roadmapPath, "utf-8");
6047
6419
  const items = parseRoadmap(content);
6048
- const prdDir = path12.join(projectDir, config.prdDir);
6420
+ const prdDir = path15.join(projectDir, config.prdDir);
6049
6421
  const state = loadRoadmapState(prdDir);
6050
6422
  const existingPrdSlugs = scanExistingPrdSlugs(prdDir);
6051
6423
  const statusItems = items.map((item) => {
@@ -6082,12 +6454,12 @@ function getRoadmapStatus(projectDir, config) {
6082
6454
  }
6083
6455
  function scanExistingPrdSlugs(prdDir) {
6084
6456
  const slugs = /* @__PURE__ */ new Set();
6085
- if (!fs13.existsSync(prdDir)) {
6457
+ if (!fs16.existsSync(prdDir)) {
6086
6458
  return slugs;
6087
6459
  }
6088
- const files = fs13.readdirSync(prdDir);
6460
+ const files = fs16.readdirSync(prdDir);
6089
6461
  for (const file of files) {
6090
- if (!file.endsWith(".md") || file === "NIGHT-WATCH-SUMMARY.md") {
6462
+ if (!file.endsWith(".md")) {
6091
6463
  continue;
6092
6464
  }
6093
6465
  const match = file.match(/^\d+-(.+)\.md$/);
@@ -6121,19 +6493,19 @@ async function sliceRoadmapItem(projectDir, prdDir, item, config) {
6121
6493
  const nextNum = getNextPrdNumber(prdDir);
6122
6494
  const padded = String(nextNum).padStart(2, "0");
6123
6495
  const filename = `${padded}-${itemSlug}.md`;
6124
- const filePath = path12.join(prdDir, filename);
6125
- if (!fs13.existsSync(prdDir)) {
6126
- fs13.mkdirSync(prdDir, { recursive: true });
6496
+ const filePath = path15.join(prdDir, filename);
6497
+ if (!fs16.existsSync(prdDir)) {
6498
+ fs16.mkdirSync(prdDir, { recursive: true });
6127
6499
  }
6128
6500
  const promptVars = createSlicerPromptVars(item.title, item.section, item.description, prdDir, filename);
6129
6501
  const prompt2 = renderSlicerPrompt(promptVars);
6130
6502
  const providerArgs = buildProviderArgs(config.provider, prompt2);
6131
- const logDir = path12.join(projectDir, "logs");
6132
- if (!fs13.existsSync(logDir)) {
6133
- fs13.mkdirSync(logDir, { recursive: true });
6503
+ const logDir = path15.join(projectDir, "logs");
6504
+ if (!fs16.existsSync(logDir)) {
6505
+ fs16.mkdirSync(logDir, { recursive: true });
6134
6506
  }
6135
- const logFile = path12.join(logDir, `slicer-${itemSlug}.log`);
6136
- const logStream = fs13.createWriteStream(logFile, { flags: "w" });
6507
+ const logFile = path15.join(logDir, `slicer-${itemSlug}.log`);
6508
+ const logStream = fs16.createWriteStream(logFile, { flags: "w" });
6137
6509
  logStream.on("error", () => {
6138
6510
  });
6139
6511
  return new Promise((resolve9) => {
@@ -6170,7 +6542,7 @@ async function sliceRoadmapItem(projectDir, prdDir, item, config) {
6170
6542
  });
6171
6543
  return;
6172
6544
  }
6173
- if (!fs13.existsSync(filePath)) {
6545
+ if (!fs16.existsSync(filePath)) {
6174
6546
  resolve9({
6175
6547
  sliced: false,
6176
6548
  error: `Provider did not create expected file: ${filePath}`,
@@ -6193,23 +6565,23 @@ async function sliceNextItem(projectDir, config) {
6193
6565
  error: "Roadmap scanner is disabled"
6194
6566
  };
6195
6567
  }
6196
- const roadmapPath = path12.join(projectDir, config.roadmapScanner.roadmapPath);
6568
+ const roadmapPath = path15.join(projectDir, config.roadmapScanner.roadmapPath);
6197
6569
  const auditItems = collectAuditPlannerItems(projectDir);
6198
- const roadmapExists = fs13.existsSync(roadmapPath);
6570
+ const roadmapExists = fs16.existsSync(roadmapPath);
6199
6571
  if (!roadmapExists && auditItems.length === 0) {
6200
6572
  return {
6201
6573
  sliced: false,
6202
6574
  error: "ROADMAP.md not found"
6203
6575
  };
6204
6576
  }
6205
- const roadmapItems = roadmapExists ? parseRoadmap(fs13.readFileSync(roadmapPath, "utf-8")) : [];
6577
+ const roadmapItems = roadmapExists ? parseRoadmap(fs16.readFileSync(roadmapPath, "utf-8")) : [];
6206
6578
  if (roadmapExists && roadmapItems.length === 0 && auditItems.length === 0) {
6207
6579
  return {
6208
6580
  sliced: false,
6209
6581
  error: "No items in roadmap"
6210
6582
  };
6211
6583
  }
6212
- const prdDir = path12.join(projectDir, config.prdDir);
6584
+ const prdDir = path15.join(projectDir, config.prdDir);
6213
6585
  const state = loadRoadmapState(prdDir);
6214
6586
  const existingPrdSlugs = scanExistingPrdSlugs(prdDir);
6215
6587
  const pickEligibleItem = (items) => {
@@ -6425,6 +6797,162 @@ var init_webhook_validator = __esm({
6425
6797
  "use strict";
6426
6798
  }
6427
6799
  });
6800
+ function gitExec(args, cwd, logFile) {
6801
+ try {
6802
+ const result = execFileSync4("git", args, {
6803
+ cwd,
6804
+ encoding: "utf-8",
6805
+ stdio: ["pipe", "pipe", "pipe"]
6806
+ });
6807
+ if (logFile && result) {
6808
+ try {
6809
+ fs17.appendFileSync(logFile, result);
6810
+ } catch {
6811
+ }
6812
+ }
6813
+ return { success: true };
6814
+ } catch (error2) {
6815
+ const errorMessage = error2 instanceof Error ? error2.message : String(error2);
6816
+ if (logFile) {
6817
+ try {
6818
+ fs17.appendFileSync(logFile, errorMessage + "\n");
6819
+ } catch {
6820
+ }
6821
+ }
6822
+ return { success: false, error: errorMessage };
6823
+ }
6824
+ }
6825
+ function branchExistsLocally(projectDir, branchName) {
6826
+ try {
6827
+ execFileSync4("git", ["-C", projectDir, "rev-parse", "--verify", "--quiet", `refs/heads/${branchName}`], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
6828
+ return true;
6829
+ } catch {
6830
+ return false;
6831
+ }
6832
+ }
6833
+ function branchExistsRemotely(projectDir, branchName) {
6834
+ try {
6835
+ execFileSync4("git", ["-C", projectDir, "rev-parse", "--verify", "--quiet", `refs/remotes/origin/${branchName}`], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
6836
+ return true;
6837
+ } catch {
6838
+ return false;
6839
+ }
6840
+ }
6841
+ function prepareBranchWorktree(options) {
6842
+ const { projectDir, worktreeDir, branchName, defaultBranch, logFile } = options;
6843
+ gitExec(["fetch", "origin", defaultBranch], projectDir, logFile);
6844
+ const baseRef = resolveWorktreeBaseRef(projectDir, defaultBranch);
6845
+ if (!baseRef) {
6846
+ return {
6847
+ success: false,
6848
+ worktreePath: worktreeDir,
6849
+ error: "No valid base ref found for worktree"
6850
+ };
6851
+ }
6852
+ if (branchExistsLocally(projectDir, branchName)) {
6853
+ const result2 = gitExec(["worktree", "add", worktreeDir, branchName], projectDir, logFile);
6854
+ return {
6855
+ success: result2.success,
6856
+ worktreePath: worktreeDir,
6857
+ error: result2.error
6858
+ };
6859
+ }
6860
+ if (branchExistsRemotely(projectDir, branchName)) {
6861
+ const result2 = gitExec(["worktree", "add", "-b", branchName, worktreeDir, `origin/${branchName}`], projectDir, logFile);
6862
+ return {
6863
+ success: result2.success,
6864
+ worktreePath: worktreeDir,
6865
+ error: result2.error
6866
+ };
6867
+ }
6868
+ const result = gitExec(["worktree", "add", "-b", branchName, worktreeDir, baseRef], projectDir, logFile);
6869
+ return {
6870
+ success: result.success,
6871
+ worktreePath: worktreeDir,
6872
+ error: result.error
6873
+ };
6874
+ }
6875
+ function prepareDetachedWorktree(options) {
6876
+ const { projectDir, worktreeDir, defaultBranch, logFile } = options;
6877
+ if (fs17.existsSync(worktreeDir)) {
6878
+ const isRegistered = isWorktreeRegistered(projectDir, worktreeDir);
6879
+ if (!isRegistered) {
6880
+ try {
6881
+ fs17.rmSync(worktreeDir, { recursive: true, force: true });
6882
+ } catch {
6883
+ }
6884
+ }
6885
+ }
6886
+ gitExec(["fetch", "origin", defaultBranch], projectDir, logFile);
6887
+ const baseRef = resolveWorktreeBaseRef(projectDir, defaultBranch);
6888
+ if (!baseRef) {
6889
+ return {
6890
+ success: false,
6891
+ worktreePath: worktreeDir,
6892
+ error: "No valid base ref found for worktree"
6893
+ };
6894
+ }
6895
+ const result = gitExec(["worktree", "add", "--detach", worktreeDir, baseRef], projectDir, logFile);
6896
+ return {
6897
+ success: result.success,
6898
+ worktreePath: worktreeDir,
6899
+ error: result.error
6900
+ };
6901
+ }
6902
+ function isWorktreeRegistered(projectDir, worktreePath) {
6903
+ try {
6904
+ const output = execFileSync4("git", ["-C", projectDir, "worktree", "list", "--porcelain"], {
6905
+ encoding: "utf-8",
6906
+ stdio: ["pipe", "pipe", "pipe"]
6907
+ });
6908
+ const lines = output.split("\n");
6909
+ for (const line of lines) {
6910
+ if (line.startsWith("worktree ")) {
6911
+ const wtPath = line.substring("worktree ".length);
6912
+ if (wtPath === worktreePath) {
6913
+ return true;
6914
+ }
6915
+ }
6916
+ }
6917
+ return false;
6918
+ } catch {
6919
+ return false;
6920
+ }
6921
+ }
6922
+ function cleanupWorktrees(projectDir, scope) {
6923
+ const projectName = path16.basename(projectDir);
6924
+ const matchToken = scope ? scope : `${projectName}-nw`;
6925
+ const removed = [];
6926
+ try {
6927
+ const output = execFileSync4("git", ["-C", projectDir, "worktree", "list", "--porcelain"], {
6928
+ encoding: "utf-8",
6929
+ stdio: ["pipe", "pipe", "pipe"]
6930
+ });
6931
+ const lines = output.split("\n");
6932
+ const worktreePaths = [];
6933
+ for (const line of lines) {
6934
+ if (line.startsWith("worktree ")) {
6935
+ worktreePaths.push(line.substring("worktree ".length));
6936
+ }
6937
+ }
6938
+ for (const wtPath of worktreePaths) {
6939
+ if (wtPath.includes(matchToken)) {
6940
+ const result = gitExec(["worktree", "remove", "--force", wtPath], projectDir);
6941
+ if (result.success) {
6942
+ removed.push(wtPath);
6943
+ }
6944
+ }
6945
+ }
6946
+ } catch {
6947
+ }
6948
+ return removed;
6949
+ }
6950
+ var init_worktree_manager = __esm({
6951
+ "../core/dist/utils/worktree-manager.js"() {
6952
+ "use strict";
6953
+ init_git_utils();
6954
+ }
6955
+ });
6428
6956
  function renderDependsOn(deps) {
6429
6957
  if (deps.length === 0) {
6430
6958
  return "";
@@ -6680,6 +7208,7 @@ __export(dist_exports, {
6680
7208
  VALID_JOB_TYPES: () => VALID_JOB_TYPES,
6681
7209
  VALID_MERGE_METHODS: () => VALID_MERGE_METHODS,
6682
7210
  VALID_PROVIDERS: () => VALID_PROVIDERS,
7211
+ acquireLock: () => acquireLock,
6683
7212
  addEntry: () => addEntry,
6684
7213
  auditLockPath: () => auditLockPath,
6685
7214
  buildDescription: () => buildDescription,
@@ -6694,6 +7223,9 @@ __export(dist_exports, {
6694
7223
  checkNodeVersion: () => checkNodeVersion,
6695
7224
  checkPrdDirectory: () => checkPrdDirectory,
6696
7225
  checkProviderCli: () => checkProviderCli,
7226
+ checkRateLimited: () => checkRateLimited,
7227
+ claimPrd: () => claimPrd,
7228
+ cleanupWorktrees: () => cleanupWorktrees,
6697
7229
  clearPrdState: () => clearPrdState,
6698
7230
  clearTemplateCache: () => clearTemplateCache,
6699
7231
  closeDb: () => closeDb,
@@ -6713,6 +7245,7 @@ __export(dist_exports, {
6713
7245
  createSlicerPromptVars: () => createSlicerPromptVars,
6714
7246
  createSpinner: () => createSpinner,
6715
7247
  createTable: () => createTable,
7248
+ detectDefaultBranch: () => detectDefaultBranch,
6716
7249
  detectProviders: () => detectProviders,
6717
7250
  dim: () => dim,
6718
7251
  error: () => error,
@@ -6728,6 +7261,8 @@ __export(dist_exports, {
6728
7261
  fetchPrDetailsForBranch: () => fetchPrDetailsForBranch,
6729
7262
  fetchReviewedPrDetails: () => fetchReviewedPrDetails,
6730
7263
  fetchStatusSnapshot: () => fetchStatusSnapshot,
7264
+ findEligibleBoardIssue: () => findEligibleBoardIssue,
7265
+ findEligiblePrd: () => findEligiblePrd,
6731
7266
  findMatchingIssue: () => findMatchingIssue,
6732
7267
  formatDiscordPayload: () => formatDiscordPayload,
6733
7268
  formatInstalledStatus: () => formatInstalledStatus,
@@ -6737,6 +7272,7 @@ __export(dist_exports, {
6737
7272
  generateItemHash: () => generateItemHash,
6738
7273
  generateMarker: () => generateMarker,
6739
7274
  generatePersonaAvatar: () => generatePersonaAvatar,
7275
+ getBranchTipTimestamp: () => getBranchTipTimestamp,
6740
7276
  getCrontabInfo: () => getCrontabInfo,
6741
7277
  getDb: () => getDb,
6742
7278
  getDbPath: () => getDbPath,
@@ -6770,6 +7306,7 @@ __export(dist_exports, {
6770
7306
  header: () => header,
6771
7307
  info: () => info,
6772
7308
  initContainer: () => initContainer,
7309
+ isClaimed: () => isClaimed,
6773
7310
  isContainerInitialized: () => isContainerInitialized,
6774
7311
  isInCooldown: () => isInCooldown,
6775
7312
  isItemProcessed: () => isItemProcessed,
@@ -6786,25 +7323,33 @@ __export(dist_exports, {
6786
7323
  loadRoadmapState: () => loadRoadmapState,
6787
7324
  loadSlicerTemplate: () => loadSlicerTemplate,
6788
7325
  markItemProcessed: () => markItemProcessed,
7326
+ markPrdDone: () => markPrdDone,
6789
7327
  migrateJsonToSqlite: () => migrateJsonToSqlite,
6790
7328
  parsePrdDependencies: () => parsePrdDependencies,
6791
7329
  parseRoadmap: () => parseRoadmap,
6792
7330
  parseScriptResult: () => parseScriptResult,
6793
7331
  performCancel: () => performCancel,
6794
7332
  plannerLockPath: () => plannerLockPath,
7333
+ prepareBranchWorktree: () => prepareBranchWorktree,
7334
+ prepareDetachedWorktree: () => prepareDetachedWorktree,
6795
7335
  projectRuntimeKey: () => projectRuntimeKey,
6796
7336
  qaLockPath: () => qaLockPath,
7337
+ readClaimInfo: () => readClaimInfo,
6797
7338
  readCrontab: () => readCrontab,
6798
7339
  readPrdStates: () => readPrdStates,
6799
7340
  recordExecution: () => recordExecution,
6800
7341
  registerProject: () => registerProject,
7342
+ releaseClaim: () => releaseClaim,
7343
+ releaseLock: () => releaseLock,
6801
7344
  removeEntries: () => removeEntries,
6802
7345
  removeEntriesForProject: () => removeEntriesForProject,
6803
7346
  renderPrdTemplate: () => renderPrdTemplate,
6804
7347
  renderSlicerPrompt: () => renderSlicerPrompt,
6805
7348
  resetRepositories: () => resetRepositories,
6806
7349
  resolveJobProvider: () => resolveJobProvider,
7350
+ resolveWorktreeBaseRef: () => resolveWorktreeBaseRef,
6807
7351
  reviewerLockPath: () => reviewerLockPath,
7352
+ rotateLog: () => rotateLog,
6808
7353
  runAllChecks: () => runAllChecks,
6809
7354
  runMigrations: () => runMigrations,
6810
7355
  saveConfig: () => saveConfig,
@@ -6819,6 +7364,7 @@ __export(dist_exports, {
6819
7364
  sliceRoadmapItem: () => sliceRoadmapItem,
6820
7365
  slugify: () => slugify,
6821
7366
  sortByPriority: () => sortByPriority,
7367
+ sortPrdsByPriority: () => sortPrdsByPriority,
6822
7368
  step: () => step,
6823
7369
  success: () => success,
6824
7370
  unmarkItemProcessed: () => unmarkItemProcessed,
@@ -6852,11 +7398,15 @@ var init_dist = __esm({
6852
7398
  init_logger();
6853
7399
  init_cancel();
6854
7400
  init_checks();
7401
+ init_claim_manager();
6855
7402
  init_config_writer();
6856
7403
  init_crontab();
6857
7404
  init_execution_history();
7405
+ init_git_utils();
6858
7406
  init_github();
7407
+ init_log_utils();
6859
7408
  init_notify();
7409
+ init_prd_discovery();
6860
7410
  init_prd_states();
6861
7411
  init_prd_utils();
6862
7412
  init_registry();
@@ -6869,6 +7419,7 @@ var init_dist = __esm({
6869
7419
  init_status_data();
6870
7420
  init_ui();
6871
7421
  init_webhook_validator();
7422
+ init_worktree_manager();
6872
7423
  init_prd_template();
6873
7424
  init_slicer_prompt();
6874
7425
  }
@@ -6879,22 +7430,22 @@ var __dirname2 = dirname4(__filename);
6879
7430
  function findTemplatesDir(startDir) {
6880
7431
  let d = startDir;
6881
7432
  for (let i = 0; i < 8; i++) {
6882
- const candidate = join13(d, "templates");
6883
- if (fs14.existsSync(candidate) && fs14.statSync(candidate).isDirectory()) {
7433
+ const candidate = join16(d, "templates");
7434
+ if (fs18.existsSync(candidate) && fs18.statSync(candidate).isDirectory()) {
6884
7435
  return candidate;
6885
7436
  }
6886
7437
  d = dirname4(d);
6887
7438
  }
6888
- return join13(startDir, "templates");
7439
+ return join16(startDir, "templates");
6889
7440
  }
6890
7441
  var TEMPLATES_DIR = findTemplatesDir(__dirname2);
6891
7442
  function hasPlaywrightDependency(cwd) {
6892
- const packageJsonPath = path13.join(cwd, "package.json");
6893
- if (!fs14.existsSync(packageJsonPath)) {
7443
+ const packageJsonPath = path17.join(cwd, "package.json");
7444
+ if (!fs18.existsSync(packageJsonPath)) {
6894
7445
  return false;
6895
7446
  }
6896
7447
  try {
6897
- const packageJson2 = JSON.parse(fs14.readFileSync(packageJsonPath, "utf-8"));
7448
+ const packageJson2 = JSON.parse(fs18.readFileSync(packageJsonPath, "utf-8"));
6898
7449
  return Boolean(packageJson2.dependencies?.["@playwright/test"] || packageJson2.dependencies?.playwright || packageJson2.devDependencies?.["@playwright/test"] || packageJson2.devDependencies?.playwright);
6899
7450
  } catch {
6900
7451
  return false;
@@ -6904,7 +7455,7 @@ function detectPlaywright(cwd) {
6904
7455
  if (hasPlaywrightDependency(cwd)) {
6905
7456
  return true;
6906
7457
  }
6907
- if (fs14.existsSync(path13.join(cwd, "node_modules", ".bin", "playwright"))) {
7458
+ if (fs18.existsSync(path17.join(cwd, "node_modules", ".bin", "playwright"))) {
6908
7459
  return true;
6909
7460
  }
6910
7461
  try {
@@ -6920,10 +7471,10 @@ function detectPlaywright(cwd) {
6920
7471
  }
6921
7472
  }
6922
7473
  function resolvePlaywrightInstallCommand(cwd) {
6923
- if (fs14.existsSync(path13.join(cwd, "pnpm-lock.yaml"))) {
7474
+ if (fs18.existsSync(path17.join(cwd, "pnpm-lock.yaml"))) {
6924
7475
  return "pnpm add -D @playwright/test";
6925
7476
  }
6926
- if (fs14.existsSync(path13.join(cwd, "yarn.lock"))) {
7477
+ if (fs18.existsSync(path17.join(cwd, "yarn.lock"))) {
6927
7478
  return "yarn add -D @playwright/test";
6928
7479
  }
6929
7480
  return "npm install -D @playwright/test";
@@ -7042,36 +7593,36 @@ function promptProviderSelection(providers) {
7042
7593
  });
7043
7594
  }
7044
7595
  function ensureDir(dirPath) {
7045
- if (!fs14.existsSync(dirPath)) {
7046
- fs14.mkdirSync(dirPath, { recursive: true });
7596
+ if (!fs18.existsSync(dirPath)) {
7597
+ fs18.mkdirSync(dirPath, { recursive: true });
7047
7598
  }
7048
7599
  }
7049
7600
  function resolveTemplatePath(templateName, customTemplatesDir, bundledTemplatesDir) {
7050
7601
  if (customTemplatesDir !== null) {
7051
- const customPath = join13(customTemplatesDir, templateName);
7052
- if (fs14.existsSync(customPath)) {
7602
+ const customPath = join16(customTemplatesDir, templateName);
7603
+ if (fs18.existsSync(customPath)) {
7053
7604
  return { path: customPath, source: "custom" };
7054
7605
  }
7055
7606
  }
7056
- return { path: join13(bundledTemplatesDir, templateName), source: "bundled" };
7607
+ return { path: join16(bundledTemplatesDir, templateName), source: "bundled" };
7057
7608
  }
7058
7609
  function processTemplate(templateName, targetPath, replacements, force, sourcePath, source) {
7059
- if (fs14.existsSync(targetPath) && !force) {
7610
+ if (fs18.existsSync(targetPath) && !force) {
7060
7611
  console.log(` Skipped (exists): ${targetPath}`);
7061
7612
  return { created: false, source: source ?? "bundled" };
7062
7613
  }
7063
- const templatePath = sourcePath ?? join13(TEMPLATES_DIR, templateName);
7614
+ const templatePath = sourcePath ?? join16(TEMPLATES_DIR, templateName);
7064
7615
  const resolvedSource = source ?? "bundled";
7065
- let content = fs14.readFileSync(templatePath, "utf-8");
7616
+ let content = fs18.readFileSync(templatePath, "utf-8");
7066
7617
  for (const [key, value] of Object.entries(replacements)) {
7067
7618
  content = content.replaceAll(key, value);
7068
7619
  }
7069
- fs14.writeFileSync(targetPath, content);
7620
+ fs18.writeFileSync(targetPath, content);
7070
7621
  console.log(` Created: ${targetPath} (${resolvedSource})`);
7071
7622
  return { created: true, source: resolvedSource };
7072
7623
  }
7073
7624
  function addToGitignore(cwd) {
7074
- const gitignorePath = path13.join(cwd, ".gitignore");
7625
+ const gitignorePath = path17.join(cwd, ".gitignore");
7075
7626
  const entries = [
7076
7627
  {
7077
7628
  pattern: "/logs/",
@@ -7085,13 +7636,13 @@ function addToGitignore(cwd) {
7085
7636
  },
7086
7637
  { pattern: "*.claim", label: "*.claim", check: (c) => c.includes("*.claim") }
7087
7638
  ];
7088
- if (!fs14.existsSync(gitignorePath)) {
7639
+ if (!fs18.existsSync(gitignorePath)) {
7089
7640
  const lines = ["# Night Watch", ...entries.map((e) => e.pattern), ""];
7090
- fs14.writeFileSync(gitignorePath, lines.join("\n"));
7641
+ fs18.writeFileSync(gitignorePath, lines.join("\n"));
7091
7642
  console.log(` Created: ${gitignorePath} (with Night Watch entries)`);
7092
7643
  return;
7093
7644
  }
7094
- const content = fs14.readFileSync(gitignorePath, "utf-8");
7645
+ const content = fs18.readFileSync(gitignorePath, "utf-8");
7095
7646
  const missing = entries.filter((e) => !e.check(content));
7096
7647
  if (missing.length === 0) {
7097
7648
  console.log(` Skipped (exists): Night Watch entries in .gitignore`);
@@ -7099,30 +7650,15 @@ function addToGitignore(cwd) {
7099
7650
  }
7100
7651
  const additions = missing.map((e) => e.pattern).join("\n");
7101
7652
  const newContent = content.trimEnd() + "\n\n# Night Watch\n" + additions + "\n";
7102
- fs14.writeFileSync(gitignorePath, newContent);
7653
+ fs18.writeFileSync(gitignorePath, newContent);
7103
7654
  console.log(` Updated: ${gitignorePath} (added ${missing.map((e) => e.label).join(", ")})`);
7104
7655
  }
7105
- function createSummaryFile(summaryPath, force) {
7106
- if (fs14.existsSync(summaryPath) && !force) {
7107
- console.log(` Skipped (exists): ${summaryPath}`);
7108
- return;
7109
- }
7110
- const content = `# Night Watch Summary
7111
-
7112
- This file tracks the progress of PRDs executed by Night Watch.
7113
-
7114
- ---
7115
-
7116
- `;
7117
- fs14.writeFileSync(summaryPath, content);
7118
- console.log(` Created: ${summaryPath}`);
7119
- }
7120
7656
  function initCommand(program2) {
7121
7657
  program2.command("init").description("Initialize night-watch in the current project").option("-f, --force", "Overwrite existing configuration").option("-d, --prd-dir <path>", "Path to PRD directory").option("-p, --provider <name>", "AI provider to use (claude or codex)").option("--no-reviewer", "Disable reviewer cron job").action(async (options) => {
7122
7658
  const cwd = process.cwd();
7123
7659
  const force = options.force || false;
7124
7660
  const prdDir = options.prdDir || DEFAULT_PRD_DIR;
7125
- const totalSteps = 12;
7661
+ const totalSteps = 11;
7126
7662
  console.log();
7127
7663
  header("Night Watch CLI - Initializing");
7128
7664
  step(1, totalSteps, "Checking git repository...");
@@ -7203,57 +7739,54 @@ function initCommand(program2) {
7203
7739
  "${DEFAULT_BRANCH}": defaultBranch
7204
7740
  };
7205
7741
  step(5, totalSteps, "Creating PRD directory structure...");
7206
- const prdDirPath = path13.join(cwd, prdDir);
7207
- const doneDirPath = path13.join(prdDirPath, "done");
7742
+ const prdDirPath = path17.join(cwd, prdDir);
7743
+ const doneDirPath = path17.join(prdDirPath, "done");
7208
7744
  ensureDir(doneDirPath);
7209
7745
  success(`Created ${prdDirPath}/`);
7210
7746
  success(`Created ${doneDirPath}/`);
7211
- step(6, totalSteps, "Creating NIGHT-WATCH-SUMMARY.md...");
7212
- const summaryPath = path13.join(prdDirPath, "NIGHT-WATCH-SUMMARY.md");
7213
- createSummaryFile(summaryPath, force);
7214
- step(7, totalSteps, "Creating logs directory...");
7215
- const logsPath = path13.join(cwd, LOG_DIR);
7747
+ step(6, totalSteps, "Creating logs directory...");
7748
+ const logsPath = path17.join(cwd, LOG_DIR);
7216
7749
  ensureDir(logsPath);
7217
7750
  success(`Created ${logsPath}/`);
7218
7751
  addToGitignore(cwd);
7219
- step(8, totalSteps, "Creating Claude slash commands...");
7220
- const commandsDir = path13.join(cwd, ".claude", "commands");
7221
- ensureDir(commandsDir);
7222
- success(`Created ${commandsDir}/`);
7752
+ step(7, totalSteps, "Creating instructions directory...");
7753
+ const instructionsDir = path17.join(cwd, "instructions");
7754
+ ensureDir(instructionsDir);
7755
+ success(`Created ${instructionsDir}/`);
7223
7756
  const existingConfig = loadConfig(cwd);
7224
- const customTemplatesDirPath = path13.join(cwd, existingConfig.templatesDir);
7225
- const customTemplatesDir = fs14.existsSync(customTemplatesDirPath) ? customTemplatesDirPath : null;
7757
+ const customTemplatesDirPath = path17.join(cwd, existingConfig.templatesDir);
7758
+ const customTemplatesDir = fs18.existsSync(customTemplatesDirPath) ? customTemplatesDirPath : null;
7226
7759
  const templateSources = [];
7227
7760
  const nwResolution = resolveTemplatePath("night-watch.md", customTemplatesDir, TEMPLATES_DIR);
7228
- const nwResult = processTemplate("night-watch.md", path13.join(commandsDir, "night-watch.md"), replacements, force, nwResolution.path, nwResolution.source);
7761
+ const nwResult = processTemplate("night-watch.md", path17.join(instructionsDir, "night-watch.md"), replacements, force, nwResolution.path, nwResolution.source);
7229
7762
  templateSources.push({ name: "night-watch.md", source: nwResult.source });
7230
7763
  const peResolution = resolveTemplatePath("prd-executor.md", customTemplatesDir, TEMPLATES_DIR);
7231
- const peResult = processTemplate("prd-executor.md", path13.join(commandsDir, "prd-executor.md"), replacements, force, peResolution.path, peResolution.source);
7764
+ const peResult = processTemplate("prd-executor.md", path17.join(instructionsDir, "prd-executor.md"), replacements, force, peResolution.path, peResolution.source);
7232
7765
  templateSources.push({ name: "prd-executor.md", source: peResult.source });
7233
7766
  const prResolution = resolveTemplatePath("night-watch-pr-reviewer.md", customTemplatesDir, TEMPLATES_DIR);
7234
- const prResult = processTemplate("night-watch-pr-reviewer.md", path13.join(commandsDir, "night-watch-pr-reviewer.md"), replacements, force, prResolution.path, prResolution.source);
7767
+ const prResult = processTemplate("night-watch-pr-reviewer.md", path17.join(instructionsDir, "night-watch-pr-reviewer.md"), replacements, force, prResolution.path, prResolution.source);
7235
7768
  templateSources.push({ name: "night-watch-pr-reviewer.md", source: prResult.source });
7236
7769
  const qaResolution = resolveTemplatePath("night-watch-qa.md", customTemplatesDir, TEMPLATES_DIR);
7237
- const qaResult = processTemplate("night-watch-qa.md", path13.join(commandsDir, "night-watch-qa.md"), replacements, force, qaResolution.path, qaResolution.source);
7770
+ const qaResult = processTemplate("night-watch-qa.md", path17.join(instructionsDir, "night-watch-qa.md"), replacements, force, qaResolution.path, qaResolution.source);
7238
7771
  templateSources.push({ name: "night-watch-qa.md", source: qaResult.source });
7239
7772
  const auditResolution = resolveTemplatePath("night-watch-audit.md", customTemplatesDir, TEMPLATES_DIR);
7240
- const auditResult = processTemplate("night-watch-audit.md", path13.join(commandsDir, "night-watch-audit.md"), replacements, force, auditResolution.path, auditResolution.source);
7773
+ const auditResult = processTemplate("night-watch-audit.md", path17.join(instructionsDir, "night-watch-audit.md"), replacements, force, auditResolution.path, auditResolution.source);
7241
7774
  templateSources.push({ name: "night-watch-audit.md", source: auditResult.source });
7242
- step(9, totalSteps, "Creating configuration file...");
7243
- const configPath = path13.join(cwd, CONFIG_FILE_NAME);
7244
- if (fs14.existsSync(configPath) && !force) {
7775
+ step(8, totalSteps, "Creating configuration file...");
7776
+ const configPath = path17.join(cwd, CONFIG_FILE_NAME);
7777
+ if (fs18.existsSync(configPath) && !force) {
7245
7778
  console.log(` Skipped (exists): ${configPath}`);
7246
7779
  } else {
7247
- let configContent = fs14.readFileSync(join13(TEMPLATES_DIR, "night-watch.config.json"), "utf-8");
7780
+ let configContent = fs18.readFileSync(join16(TEMPLATES_DIR, "night-watch.config.json"), "utf-8");
7248
7781
  configContent = configContent.replace('"projectName": ""', `"projectName": "${projectName}"`);
7249
7782
  configContent = configContent.replace('"defaultBranch": ""', `"defaultBranch": "${defaultBranch}"`);
7250
7783
  configContent = configContent.replace(/"provider":\s*"[^"]*"/, `"provider": "${selectedProvider}"`);
7251
7784
  configContent = configContent.replace(/"reviewerEnabled":\s*(true|false)/, `"reviewerEnabled": ${reviewerEnabled}`);
7252
- fs14.writeFileSync(configPath, configContent);
7785
+ fs18.writeFileSync(configPath, configContent);
7253
7786
  success(`Created ${configPath}`);
7254
7787
  }
7255
- step(10, totalSteps, "Setting up GitHub Project board...");
7256
- const existingRaw = JSON.parse(fs14.readFileSync(configPath, "utf-8"));
7788
+ step(9, totalSteps, "Setting up GitHub Project board...");
7789
+ const existingRaw = JSON.parse(fs18.readFileSync(configPath, "utf-8"));
7257
7790
  const existingBoard = existingRaw.boardProvider;
7258
7791
  if (existingBoard?.projectNumber && !force) {
7259
7792
  info(`Board already configured (#${existingBoard.projectNumber}), skipping.`);
@@ -7275,13 +7808,13 @@ function initCommand(program2) {
7275
7808
  const provider = createBoardProvider({ enabled: true, provider: "github" }, cwd);
7276
7809
  const boardTitle = `${projectName} Night Watch`;
7277
7810
  const board = await provider.setupBoard(boardTitle);
7278
- const rawConfig = JSON.parse(fs14.readFileSync(configPath, "utf-8"));
7811
+ const rawConfig = JSON.parse(fs18.readFileSync(configPath, "utf-8"));
7279
7812
  rawConfig.boardProvider = {
7280
7813
  enabled: true,
7281
7814
  provider: "github",
7282
7815
  projectNumber: board.number
7283
7816
  };
7284
- fs14.writeFileSync(configPath, JSON.stringify(rawConfig, null, 2) + "\n");
7817
+ fs18.writeFileSync(configPath, JSON.stringify(rawConfig, null, 2) + "\n");
7285
7818
  success(`GitHub Project board "${boardTitle}" ready (#${board.number})`);
7286
7819
  } catch (boardErr) {
7287
7820
  console.warn(` Warning: Could not set up GitHub Project board: ${boardErr instanceof Error ? boardErr.message : String(boardErr)}`);
@@ -7289,7 +7822,7 @@ function initCommand(program2) {
7289
7822
  }
7290
7823
  }
7291
7824
  }
7292
- step(11, totalSteps, "Registering project in global registry...");
7825
+ step(10, totalSteps, "Registering project in global registry...");
7293
7826
  try {
7294
7827
  const { registerProject: registerProject2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
7295
7828
  const entry = registerProject2(cwd);
@@ -7297,23 +7830,22 @@ function initCommand(program2) {
7297
7830
  } catch (regErr) {
7298
7831
  console.warn(` Warning: Could not register in global registry: ${regErr instanceof Error ? regErr.message : String(regErr)}`);
7299
7832
  }
7300
- step(12, totalSteps, "Initialization complete!");
7833
+ step(11, totalSteps, "Initialization complete!");
7301
7834
  header("Initialization Complete");
7302
7835
  const filesTable = createTable({ head: ["Created Files", ""] });
7303
7836
  filesTable.push(["PRD Directory", `${prdDir}/done/`]);
7304
- filesTable.push(["Summary File", `${prdDir}/NIGHT-WATCH-SUMMARY.md`]);
7305
7837
  filesTable.push(["Logs Directory", `${LOG_DIR}/`]);
7306
7838
  filesTable.push([
7307
- "Slash Commands",
7308
- `.claude/commands/night-watch.md (${templateSources[0].source})`
7839
+ "Instructions",
7840
+ `instructions/night-watch.md (${templateSources[0].source})`
7309
7841
  ]);
7310
- filesTable.push(["", `.claude/commands/prd-executor.md (${templateSources[1].source})`]);
7842
+ filesTable.push(["", `instructions/prd-executor.md (${templateSources[1].source})`]);
7311
7843
  filesTable.push([
7312
7844
  "",
7313
- `.claude/commands/night-watch-pr-reviewer.md (${templateSources[2].source})`
7845
+ `instructions/night-watch-pr-reviewer.md (${templateSources[2].source})`
7314
7846
  ]);
7315
- filesTable.push(["", `.claude/commands/night-watch-qa.md (${templateSources[3].source})`]);
7316
- filesTable.push(["", `.claude/commands/night-watch-audit.md (${templateSources[4].source})`]);
7847
+ filesTable.push(["", `instructions/night-watch-qa.md (${templateSources[3].source})`]);
7848
+ filesTable.push(["", `instructions/night-watch-audit.md (${templateSources[4].source})`]);
7317
7849
  filesTable.push(["Config File", CONFIG_FILE_NAME]);
7318
7850
  filesTable.push(["Global Registry", "~/.night-watch/projects.json"]);
7319
7851
  console.log(filesTable.toString());
@@ -7354,12 +7886,12 @@ function shouldAttemptCrossProjectFallback(options, scriptStatus) {
7354
7886
  return scriptStatus === "skip_no_eligible_prd";
7355
7887
  }
7356
7888
  function getCrossProjectFallbackCandidates(currentProjectDir) {
7357
- const current = path14.resolve(currentProjectDir);
7889
+ const current = path18.resolve(currentProjectDir);
7358
7890
  const { valid, invalid } = validateRegistry();
7359
7891
  for (const entry of invalid) {
7360
7892
  warn(`Skipping invalid registry entry: ${entry.path}`);
7361
7893
  }
7362
- return valid.filter((entry) => path14.resolve(entry.path) !== current);
7894
+ return valid.filter((entry) => path18.resolve(entry.path) !== current);
7363
7895
  }
7364
7896
  async function sendRunCompletionNotifications(config, projectDir, options, exitCode, scriptResult) {
7365
7897
  if (isRateLimitFallbackTriggered(scriptResult?.data)) {
@@ -7367,7 +7899,7 @@ async function sendRunCompletionNotifications(config, projectDir, options, exitC
7367
7899
  if (nonTelegramWebhooks.length > 0) {
7368
7900
  const _rateLimitCtx = {
7369
7901
  event: "rate_limit_fallback",
7370
- projectName: path14.basename(projectDir),
7902
+ projectName: path18.basename(projectDir),
7371
7903
  exitCode,
7372
7904
  provider: config.provider
7373
7905
  };
@@ -7389,11 +7921,15 @@ async function sendRunCompletionNotifications(config, projectDir, options, exitC
7389
7921
  }
7390
7922
  }
7391
7923
  if (event) {
7924
+ const timeoutDuration = event === "run_timeout" ? config.maxRuntime : void 0;
7392
7925
  const _ctx = {
7393
7926
  event,
7394
- projectName: path14.basename(projectDir),
7927
+ projectName: path18.basename(projectDir),
7395
7928
  exitCode,
7396
7929
  provider: config.provider,
7930
+ prdName: scriptResult?.data.prd,
7931
+ branchName: scriptResult?.data.branch,
7932
+ duration: timeoutDuration,
7397
7933
  prUrl: prDetails?.url,
7398
7934
  prTitle: prDetails?.title,
7399
7935
  prBody: prDetails?.body,
@@ -7501,20 +8037,20 @@ function applyCliOverrides(config, options) {
7501
8037
  return overridden;
7502
8038
  }
7503
8039
  function scanPrdDirectory(projectDir, prdDir, maxRuntime) {
7504
- const absolutePrdDir = path14.join(projectDir, prdDir);
7505
- const doneDir = path14.join(absolutePrdDir, "done");
8040
+ const absolutePrdDir = path18.join(projectDir, prdDir);
8041
+ const doneDir = path18.join(absolutePrdDir, "done");
7506
8042
  const pending = [];
7507
8043
  const completed = [];
7508
- if (fs15.existsSync(absolutePrdDir)) {
7509
- const entries = fs15.readdirSync(absolutePrdDir, { withFileTypes: true });
8044
+ if (fs19.existsSync(absolutePrdDir)) {
8045
+ const entries = fs19.readdirSync(absolutePrdDir, { withFileTypes: true });
7510
8046
  for (const entry of entries) {
7511
- if (entry.isFile() && entry.name.endsWith(".md") && entry.name !== "NIGHT-WATCH-SUMMARY.md") {
7512
- const claimPath = path14.join(absolutePrdDir, entry.name + CLAIM_FILE_EXTENSION);
8047
+ if (entry.isFile() && entry.name.endsWith(".md")) {
8048
+ const claimPath = path18.join(absolutePrdDir, entry.name + CLAIM_FILE_EXTENSION);
7513
8049
  let claimed = false;
7514
8050
  let claimInfo = null;
7515
- if (fs15.existsSync(claimPath)) {
8051
+ if (fs19.existsSync(claimPath)) {
7516
8052
  try {
7517
- const content = fs15.readFileSync(claimPath, "utf-8");
8053
+ const content = fs19.readFileSync(claimPath, "utf-8");
7518
8054
  const data = JSON.parse(content);
7519
8055
  const age = Math.floor(Date.now() / 1e3) - data.timestamp;
7520
8056
  if (age < maxRuntime) {
@@ -7528,8 +8064,8 @@ function scanPrdDirectory(projectDir, prdDir, maxRuntime) {
7528
8064
  }
7529
8065
  }
7530
8066
  }
7531
- if (fs15.existsSync(doneDir)) {
7532
- const entries = fs15.readdirSync(doneDir, { withFileTypes: true });
8067
+ if (fs19.existsSync(doneDir)) {
8068
+ const entries = fs19.readdirSync(doneDir, { withFileTypes: true });
7533
8069
  for (const entry of entries) {
7534
8070
  if (entry.isFile() && entry.name.endsWith(".md")) {
7535
8071
  completed.push(entry.name);
@@ -7738,13 +8274,42 @@ function applyCliOverrides2(config, options) {
7738
8274
  }
7739
8275
  return overridden;
7740
8276
  }
8277
+ function isFailingCheck(check) {
8278
+ const bucket = (check.bucket ?? "").toLowerCase();
8279
+ const state = (check.state ?? "").toLowerCase();
8280
+ const conclusion = (check.conclusion ?? "").toLowerCase();
8281
+ return bucket === "fail" || bucket === "cancel" || state === "failure" || state === "error" || state === "cancelled" || conclusion === "failure" || conclusion === "error" || conclusion === "cancelled" || conclusion === "timed_out" || conclusion === "action_required" || conclusion === "startup_failure" || conclusion === "stale";
8282
+ }
8283
+ function getPrFailingChecks(prNumber) {
8284
+ try {
8285
+ const result = execFileSync5("gh", ["pr", "checks", String(prNumber), "--json", "name,bucket,state,conclusion"], {
8286
+ encoding: "utf-8",
8287
+ stdio: ["pipe", "pipe", "pipe"]
8288
+ });
8289
+ const checks = JSON.parse(result.trim() || "[]");
8290
+ const failing = checks.filter((check) => isFailingCheck(check)).map((check) => `${check.name ?? "unknown"} [state=${check.state ?? "unknown"}, conclusion=${check.conclusion ?? "unknown"}]`);
8291
+ if (failing.length > 0) {
8292
+ return failing;
8293
+ }
8294
+ } catch {
8295
+ }
8296
+ try {
8297
+ const result = execFileSync5("gh", ["pr", "checks", String(prNumber)], {
8298
+ encoding: "utf-8",
8299
+ stdio: ["pipe", "pipe", "pipe"]
8300
+ });
8301
+ return result.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).filter((line) => /fail|error|cancel|timed[_ -]?out|action_required|startup_failure|stale/i.test(line));
8302
+ } catch {
8303
+ return [];
8304
+ }
8305
+ }
7741
8306
  function getOpenPrsNeedingWork(branchPatterns) {
7742
8307
  try {
7743
8308
  const args = ["pr", "list", "--state", "open", "--json", "number,title,headRefName"];
7744
8309
  for (const pattern of branchPatterns) {
7745
8310
  args.push("--head", pattern);
7746
8311
  }
7747
- const result = execFileSync2("gh", args, {
8312
+ const result = execFileSync5("gh", args, {
7748
8313
  encoding: "utf-8",
7749
8314
  stdio: ["pipe", "pipe", "pipe"]
7750
8315
  });
@@ -7812,6 +8377,21 @@ function reviewCommand(program2) {
7812
8377
  console.log();
7813
8378
  process.exit(0);
7814
8379
  }
8380
+ const preflightOpenPrs = getOpenPrsNeedingWork(config.branchPatterns);
8381
+ const preflightFailures = preflightOpenPrs.map((pr) => ({
8382
+ prNumber: pr.number,
8383
+ title: pr.title,
8384
+ failingChecks: getPrFailingChecks(pr.number)
8385
+ })).filter((entry) => entry.failingChecks.length > 0);
8386
+ if (preflightFailures.length > 0) {
8387
+ header("Preflight Failing Checks");
8388
+ for (const entry of preflightFailures) {
8389
+ info(`#${entry.prNumber}: ${entry.title}`);
8390
+ for (const check of entry.failingChecks) {
8391
+ dim(` ${check}`);
8392
+ }
8393
+ }
8394
+ }
7815
8395
  const spinner = createSpinner("Running PR reviewer...");
7816
8396
  spinner.start();
7817
8397
  try {
@@ -7851,7 +8431,7 @@ ${stderr}`);
7851
8431
  const finalScore = parseFinalReviewScore(scriptResult?.data.final_score);
7852
8432
  const _reviewCtx = {
7853
8433
  event: "review_completed",
7854
- projectName: path15.basename(projectDir),
8434
+ projectName: path19.basename(projectDir),
7855
8435
  exitCode,
7856
8436
  provider: config.provider,
7857
8437
  prUrl: prDetails?.url,
@@ -7872,7 +8452,7 @@ ${stderr}`);
7872
8452
  const autoMergedPrDetails = fetchPrDetailsByNumber(autoMergedPrNumber, projectDir);
7873
8453
  const _mergeCtx = {
7874
8454
  event: "pr_auto_merged",
7875
- projectName: path15.basename(projectDir),
8455
+ projectName: path19.basename(projectDir),
7876
8456
  exitCode,
7877
8457
  provider: config.provider,
7878
8458
  prNumber: autoMergedPrDetails?.number ?? autoMergedPrNumber,
@@ -8028,7 +8608,7 @@ ${stderr}`);
8028
8608
  const fallbackPrUrl = !prDetails?.url && primaryQaPr && repo ? `https://github.com/${repo}/pull/${primaryQaPr}` : void 0;
8029
8609
  const _qaCtx = {
8030
8610
  event: "qa_completed",
8031
- projectName: path16.basename(projectDir),
8611
+ projectName: path20.basename(projectDir),
8032
8612
  exitCode,
8033
8613
  provider: config.provider,
8034
8614
  prNumber: prDetails?.number ?? primaryQaPr,
@@ -8107,7 +8687,7 @@ function auditCommand(program2) {
8107
8687
  configTable.push(["Provider", auditProvider]);
8108
8688
  configTable.push(["Provider CLI", PROVIDER_COMMANDS[auditProvider]]);
8109
8689
  configTable.push(["Max Runtime", `${config.audit.maxRuntime}s`]);
8110
- configTable.push(["Report File", path17.join(projectDir, "logs", "audit-report.md")]);
8690
+ configTable.push(["Report File", path21.join(projectDir, "logs", "audit-report.md")]);
8111
8691
  console.log(configTable.toString());
8112
8692
  header("Provider Invocation");
8113
8693
  const providerCmd = PROVIDER_COMMANDS[auditProvider];
@@ -8133,8 +8713,8 @@ ${stderr}`);
8133
8713
  } else if (scriptResult?.status?.startsWith("skip_")) {
8134
8714
  spinner.succeed("Code audit skipped");
8135
8715
  } else {
8136
- const reportPath = path17.join(projectDir, "logs", "audit-report.md");
8137
- if (!fs16.existsSync(reportPath)) {
8716
+ const reportPath = path21.join(projectDir, "logs", "audit-report.md");
8717
+ if (!fs20.existsSync(reportPath)) {
8138
8718
  spinner.fail("Code audit finished without a report file");
8139
8719
  process.exit(1);
8140
8720
  }
@@ -8145,9 +8725,9 @@ ${stderr}`);
8145
8725
  const providerExit = scriptResult?.data?.provider_exit;
8146
8726
  const exitDetail = providerExit && providerExit !== String(exitCode) ? `, provider exit ${providerExit}` : "";
8147
8727
  spinner.fail(`Code audit exited with code ${exitCode}${statusSuffix}${exitDetail}`);
8148
- const logPath = path17.join(projectDir, "logs", "audit.log");
8149
- if (fs16.existsSync(logPath)) {
8150
- const logLines = fs16.readFileSync(logPath, "utf-8").split("\n").filter((l) => l.trim()).slice(-8);
8728
+ const logPath = path21.join(projectDir, "logs", "audit.log");
8729
+ if (fs20.existsSync(logPath)) {
8730
+ const logLines = fs20.readFileSync(logPath, "utf-8").split("\n").filter((l) => l.trim()).slice(-8);
8151
8731
  if (logLines.length > 0) {
8152
8732
  process.stderr.write(logLines.join("\n") + "\n");
8153
8733
  }
@@ -8167,8 +8747,8 @@ function shellQuote(value) {
8167
8747
  function getNightWatchBinPath() {
8168
8748
  try {
8169
8749
  const npmBin = execSync4("npm bin -g", { encoding: "utf-8" }).trim();
8170
- const binPath = path18.join(npmBin, "night-watch");
8171
- if (fs17.existsSync(binPath)) {
8750
+ const binPath = path22.join(npmBin, "night-watch");
8751
+ if (fs21.existsSync(binPath)) {
8172
8752
  return binPath;
8173
8753
  }
8174
8754
  } catch {
@@ -8182,13 +8762,13 @@ function getNightWatchBinPath() {
8182
8762
  function getNodeBinDir() {
8183
8763
  try {
8184
8764
  const nodePath = execSync4("which node", { encoding: "utf-8" }).trim();
8185
- return path18.dirname(nodePath);
8765
+ return path22.dirname(nodePath);
8186
8766
  } catch {
8187
8767
  return "";
8188
8768
  }
8189
8769
  }
8190
8770
  function buildCronPathPrefix(nodeBinDir, nightWatchBin) {
8191
- const nightWatchBinDir = nightWatchBin.includes("/") || nightWatchBin.includes("\\") ? path18.dirname(nightWatchBin) : "";
8771
+ const nightWatchBinDir = nightWatchBin.includes("/") || nightWatchBin.includes("\\") ? path22.dirname(nightWatchBin) : "";
8192
8772
  const pathParts = Array.from(new Set([nodeBinDir, nightWatchBinDir].filter((part) => part.length > 0)));
8193
8773
  if (pathParts.length === 0) {
8194
8774
  return "";
@@ -8215,12 +8795,12 @@ function performInstall(projectDir, config, options) {
8215
8795
  const nightWatchBin = getNightWatchBinPath();
8216
8796
  const projectName = getProjectName(projectDir);
8217
8797
  const marker = generateMarker(projectName);
8218
- const logDir = path18.join(projectDir, LOG_DIR);
8219
- if (!fs17.existsSync(logDir)) {
8220
- fs17.mkdirSync(logDir, { recursive: true });
8798
+ const logDir = path22.join(projectDir, LOG_DIR);
8799
+ if (!fs21.existsSync(logDir)) {
8800
+ fs21.mkdirSync(logDir, { recursive: true });
8221
8801
  }
8222
- const executorLog = path18.join(logDir, "executor.log");
8223
- const reviewerLog = path18.join(logDir, "reviewer.log");
8802
+ const executorLog = path22.join(logDir, "executor.log");
8803
+ const reviewerLog = path22.join(logDir, "reviewer.log");
8224
8804
  if (!options?.force) {
8225
8805
  const existingEntries = Array.from(/* @__PURE__ */ new Set([...getEntries(marker), ...getProjectEntries(projectDir)]));
8226
8806
  if (existingEntries.length > 0) {
@@ -8253,7 +8833,7 @@ function performInstall(projectDir, config, options) {
8253
8833
  const installSlicer = options?.noSlicer === true ? false : config.roadmapScanner.enabled;
8254
8834
  if (installSlicer) {
8255
8835
  const slicerSchedule = applyScheduleOffset(config.roadmapScanner.slicerSchedule, offset);
8256
- const slicerLog = path18.join(logDir, "slicer.log");
8836
+ const slicerLog = path22.join(logDir, "slicer.log");
8257
8837
  const slicerEntry = `${slicerSchedule} ${pathPrefix}${providerEnvPrefix}${cliBinPrefix}cd ${shellQuote(projectDir)} && ${shellQuote(nightWatchBin)} planner >> ${shellQuote(slicerLog)} 2>&1 ${marker}`;
8258
8838
  entries.push(slicerEntry);
8259
8839
  }
@@ -8261,7 +8841,7 @@ function performInstall(projectDir, config, options) {
8261
8841
  const installQa = disableQa ? false : config.qa.enabled;
8262
8842
  if (installQa) {
8263
8843
  const qaSchedule = applyScheduleOffset(config.qa.schedule, offset);
8264
- const qaLog = path18.join(logDir, "qa.log");
8844
+ const qaLog = path22.join(logDir, "qa.log");
8265
8845
  const qaEntry = `${qaSchedule} ${pathPrefix}${providerEnvPrefix}${cliBinPrefix}cd ${shellQuote(projectDir)} && ${shellQuote(nightWatchBin)} qa >> ${shellQuote(qaLog)} 2>&1 ${marker}`;
8266
8846
  entries.push(qaEntry);
8267
8847
  }
@@ -8269,7 +8849,7 @@ function performInstall(projectDir, config, options) {
8269
8849
  const installAudit = disableAudit ? false : config.audit.enabled;
8270
8850
  if (installAudit) {
8271
8851
  const auditSchedule = applyScheduleOffset(config.audit.schedule, offset);
8272
- const auditLog = path18.join(logDir, "audit.log");
8852
+ const auditLog = path22.join(logDir, "audit.log");
8273
8853
  const auditEntry = `${auditSchedule} ${pathPrefix}${providerEnvPrefix}${cliBinPrefix}cd ${shellQuote(projectDir)} && ${shellQuote(nightWatchBin)} audit >> ${shellQuote(auditLog)} 2>&1 ${marker}`;
8274
8854
  entries.push(auditEntry);
8275
8855
  }
@@ -8296,12 +8876,12 @@ function installCommand(program2) {
8296
8876
  const nightWatchBin = getNightWatchBinPath();
8297
8877
  const projectName = getProjectName(projectDir);
8298
8878
  const marker = generateMarker(projectName);
8299
- const logDir = path18.join(projectDir, LOG_DIR);
8300
- if (!fs17.existsSync(logDir)) {
8301
- fs17.mkdirSync(logDir, { recursive: true });
8879
+ const logDir = path22.join(projectDir, LOG_DIR);
8880
+ if (!fs21.existsSync(logDir)) {
8881
+ fs21.mkdirSync(logDir, { recursive: true });
8302
8882
  }
8303
- const executorLog = path18.join(logDir, "executor.log");
8304
- const reviewerLog = path18.join(logDir, "reviewer.log");
8883
+ const executorLog = path22.join(logDir, "executor.log");
8884
+ const reviewerLog = path22.join(logDir, "reviewer.log");
8305
8885
  const existingEntries = Array.from(/* @__PURE__ */ new Set([...getEntries(marker), ...getProjectEntries(projectDir)]));
8306
8886
  if (existingEntries.length > 0) {
8307
8887
  warn(`Night Watch is already installed for ${projectName}.`);
@@ -8334,7 +8914,7 @@ function installCommand(program2) {
8334
8914
  const installSlicer = options.noSlicer === true ? false : config.roadmapScanner.enabled;
8335
8915
  let slicerLog;
8336
8916
  if (installSlicer) {
8337
- slicerLog = path18.join(logDir, "slicer.log");
8917
+ slicerLog = path22.join(logDir, "slicer.log");
8338
8918
  const slicerSchedule = applyScheduleOffset(config.roadmapScanner.slicerSchedule, offset);
8339
8919
  const slicerEntry = `${slicerSchedule} ${pathPrefix}${providerEnvPrefix}${cliBinPrefix}cd ${shellQuote(projectDir)} && ${shellQuote(nightWatchBin)} planner >> ${shellQuote(slicerLog)} 2>&1 ${marker}`;
8340
8920
  entries.push(slicerEntry);
@@ -8343,7 +8923,7 @@ function installCommand(program2) {
8343
8923
  const installQa = disableQa ? false : config.qa.enabled;
8344
8924
  let qaLog;
8345
8925
  if (installQa) {
8346
- qaLog = path18.join(logDir, "qa.log");
8926
+ qaLog = path22.join(logDir, "qa.log");
8347
8927
  const qaSchedule = applyScheduleOffset(config.qa.schedule, offset);
8348
8928
  const qaEntry = `${qaSchedule} ${pathPrefix}${providerEnvPrefix}${cliBinPrefix}cd ${shellQuote(projectDir)} && ${shellQuote(nightWatchBin)} qa >> ${shellQuote(qaLog)} 2>&1 ${marker}`;
8349
8929
  entries.push(qaEntry);
@@ -8352,7 +8932,7 @@ function installCommand(program2) {
8352
8932
  const installAudit = disableAudit ? false : config.audit.enabled;
8353
8933
  let auditLog;
8354
8934
  if (installAudit) {
8355
- auditLog = path18.join(logDir, "audit.log");
8935
+ auditLog = path22.join(logDir, "audit.log");
8356
8936
  const auditSchedule = applyScheduleOffset(config.audit.schedule, offset);
8357
8937
  const auditEntry = `${auditSchedule} ${pathPrefix}${providerEnvPrefix}${cliBinPrefix}cd ${shellQuote(projectDir)} && ${shellQuote(nightWatchBin)} audit >> ${shellQuote(auditLog)} 2>&1 ${marker}`;
8358
8938
  entries.push(auditEntry);
@@ -8401,19 +8981,19 @@ function performUninstall(projectDir, options) {
8401
8981
  }
8402
8982
  const removedCount = removeEntriesForProject(projectDir, marker);
8403
8983
  if (!options?.keepLogs) {
8404
- const logDir = path19.join(projectDir, "logs");
8405
- if (fs18.existsSync(logDir)) {
8984
+ const logDir = path23.join(projectDir, "logs");
8985
+ if (fs22.existsSync(logDir)) {
8406
8986
  const logFiles = ["executor.log", "reviewer.log", "slicer.log", "audit.log"];
8407
8987
  logFiles.forEach((logFile) => {
8408
- const logPath = path19.join(logDir, logFile);
8409
- if (fs18.existsSync(logPath)) {
8410
- fs18.unlinkSync(logPath);
8988
+ const logPath = path23.join(logDir, logFile);
8989
+ if (fs22.existsSync(logPath)) {
8990
+ fs22.unlinkSync(logPath);
8411
8991
  }
8412
8992
  });
8413
8993
  try {
8414
- const remainingFiles = fs18.readdirSync(logDir);
8994
+ const remainingFiles = fs22.readdirSync(logDir);
8415
8995
  if (remainingFiles.length === 0) {
8416
- fs18.rmdirSync(logDir);
8996
+ fs22.rmdirSync(logDir);
8417
8997
  }
8418
8998
  } catch {
8419
8999
  }
@@ -8444,21 +9024,21 @@ function uninstallCommand(program2) {
8444
9024
  existingEntries.forEach((entry) => dim(` ${entry}`));
8445
9025
  const removedCount = removeEntriesForProject(projectDir, marker);
8446
9026
  if (!options.keepLogs) {
8447
- const logDir = path19.join(projectDir, "logs");
8448
- if (fs18.existsSync(logDir)) {
9027
+ const logDir = path23.join(projectDir, "logs");
9028
+ if (fs22.existsSync(logDir)) {
8449
9029
  const logFiles = ["executor.log", "reviewer.log", "slicer.log", "audit.log"];
8450
9030
  let logsRemoved = 0;
8451
9031
  logFiles.forEach((logFile) => {
8452
- const logPath = path19.join(logDir, logFile);
8453
- if (fs18.existsSync(logPath)) {
8454
- fs18.unlinkSync(logPath);
9032
+ const logPath = path23.join(logDir, logFile);
9033
+ if (fs22.existsSync(logPath)) {
9034
+ fs22.unlinkSync(logPath);
8455
9035
  logsRemoved++;
8456
9036
  }
8457
9037
  });
8458
9038
  try {
8459
- const remainingFiles = fs18.readdirSync(logDir);
9039
+ const remainingFiles = fs22.readdirSync(logDir);
8460
9040
  if (remainingFiles.length === 0) {
8461
- fs18.rmdirSync(logDir);
9041
+ fs22.rmdirSync(logDir);
8462
9042
  }
8463
9043
  } catch {
8464
9044
  }
@@ -8684,11 +9264,11 @@ function statusCommand(program2) {
8684
9264
  }
8685
9265
  init_dist();
8686
9266
  function getLastLines(filePath, lineCount) {
8687
- if (!fs19.existsSync(filePath)) {
9267
+ if (!fs23.existsSync(filePath)) {
8688
9268
  return `Log file not found: ${filePath}`;
8689
9269
  }
8690
9270
  try {
8691
- const content = fs19.readFileSync(filePath, "utf-8");
9271
+ const content = fs23.readFileSync(filePath, "utf-8");
8692
9272
  const lines = content.trim().split("\n");
8693
9273
  return lines.slice(-lineCount).join("\n");
8694
9274
  } catch (error2) {
@@ -8696,7 +9276,7 @@ function getLastLines(filePath, lineCount) {
8696
9276
  }
8697
9277
  }
8698
9278
  function followLog(filePath) {
8699
- if (!fs19.existsSync(filePath)) {
9279
+ if (!fs23.existsSync(filePath)) {
8700
9280
  console.log(`Log file not found: ${filePath}`);
8701
9281
  console.log("The log file will be created when the first execution runs.");
8702
9282
  return;
@@ -8716,13 +9296,13 @@ function logsCommand(program2) {
8716
9296
  program2.command("logs").description("View night-watch log output").option("-n, --lines <count>", "Number of lines to show", "50").option("-f, --follow", "Follow log output (tail -f)").option("-t, --type <type>", "Log type to view (executor|reviewer|qa|audit|planner|all)", "all").action(async (options) => {
8717
9297
  try {
8718
9298
  const projectDir = process.cwd();
8719
- const logDir = path20.join(projectDir, LOG_DIR);
9299
+ const logDir = path24.join(projectDir, LOG_DIR);
8720
9300
  const lineCount = parseInt(options.lines || "50", 10);
8721
- const executorLog = path20.join(logDir, EXECUTOR_LOG_FILE);
8722
- const reviewerLog = path20.join(logDir, REVIEWER_LOG_FILE);
8723
- const qaLog = path20.join(logDir, `${QA_LOG_NAME}.log`);
8724
- const auditLog = path20.join(logDir, `${AUDIT_LOG_NAME}.log`);
8725
- const plannerLog = path20.join(logDir, `${PLANNER_LOG_NAME}.log`);
9301
+ const executorLog = path24.join(logDir, EXECUTOR_LOG_FILE);
9302
+ const reviewerLog = path24.join(logDir, REVIEWER_LOG_FILE);
9303
+ const qaLog = path24.join(logDir, `${QA_LOG_NAME}.log`);
9304
+ const auditLog = path24.join(logDir, `${AUDIT_LOG_NAME}.log`);
9305
+ const plannerLog = path24.join(logDir, `${PLANNER_LOG_NAME}.log`);
8726
9306
  const logType = options.type?.toLowerCase() || "all";
8727
9307
  const showExecutor = logType === "all" || logType === "run" || logType === "executor";
8728
9308
  const showReviewer = logType === "all" || logType === "review" || logType === "reviewer";
@@ -8792,9 +9372,9 @@ function slugify2(name) {
8792
9372
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
8793
9373
  }
8794
9374
  function getNextPrdNumber2(prdDir) {
8795
- if (!fs20.existsSync(prdDir))
9375
+ if (!fs24.existsSync(prdDir))
8796
9376
  return 1;
8797
- const files = fs20.readdirSync(prdDir).filter((f) => f.endsWith(".md") && f !== "NIGHT-WATCH-SUMMARY.md");
9377
+ const files = fs24.readdirSync(prdDir).filter((f) => f.endsWith(".md"));
8798
9378
  const numbers = files.map((f) => {
8799
9379
  const match = f.match(/^(\d+)-/);
8800
9380
  return match ? parseInt(match[1], 10) : 0;
@@ -8816,10 +9396,10 @@ function parseDependencies(content) {
8816
9396
  }
8817
9397
  function isClaimActive(claimPath, maxRuntime) {
8818
9398
  try {
8819
- if (!fs20.existsSync(claimPath)) {
9399
+ if (!fs24.existsSync(claimPath)) {
8820
9400
  return { active: false };
8821
9401
  }
8822
- const content = fs20.readFileSync(claimPath, "utf-8");
9402
+ const content = fs24.readFileSync(claimPath, "utf-8");
8823
9403
  const claim = JSON.parse(content);
8824
9404
  const age = Math.floor(Date.now() / 1e3) - claim.timestamp;
8825
9405
  if (age < maxRuntime) {
@@ -8835,9 +9415,9 @@ function prdCommand(program2) {
8835
9415
  prd.command("create").description("Generate a new PRD markdown file from template").argument("<name>", "PRD name (used for title and filename)").option("-i, --interactive", "Prompt for complexity, dependencies, and phase count", false).option("-t, --template <path>", "Path to a custom template file").option("--deps <files>", "Comma-separated dependency filenames").option("--phases <count>", "Number of execution phases", "3").option("--no-number", "Skip auto-numbering prefix").action(async (name, options) => {
8836
9416
  const projectDir = process.cwd();
8837
9417
  const config = loadConfig(projectDir);
8838
- const prdDir = path21.join(projectDir, config.prdDir);
8839
- if (!fs20.existsSync(prdDir)) {
8840
- fs20.mkdirSync(prdDir, { recursive: true });
9418
+ const prdDir = path25.join(projectDir, config.prdDir);
9419
+ if (!fs24.existsSync(prdDir)) {
9420
+ fs24.mkdirSync(prdDir, { recursive: true });
8841
9421
  }
8842
9422
  let complexityScore = 5;
8843
9423
  let dependsOn = [];
@@ -8893,20 +9473,20 @@ function prdCommand(program2) {
8893
9473
  } else {
8894
9474
  filename = `${slug}.md`;
8895
9475
  }
8896
- const filePath = path21.join(prdDir, filename);
8897
- if (fs20.existsSync(filePath)) {
9476
+ const filePath = path25.join(prdDir, filename);
9477
+ if (fs24.existsSync(filePath)) {
8898
9478
  error(`File already exists: ${filePath}`);
8899
9479
  dim("Use a different name or remove the existing file.");
8900
9480
  process.exit(1);
8901
9481
  }
8902
9482
  let customTemplate;
8903
9483
  if (options.template) {
8904
- const templatePath = path21.resolve(options.template);
8905
- if (!fs20.existsSync(templatePath)) {
9484
+ const templatePath = path25.resolve(options.template);
9485
+ if (!fs24.existsSync(templatePath)) {
8906
9486
  error(`Template file not found: ${templatePath}`);
8907
9487
  process.exit(1);
8908
9488
  }
8909
- customTemplate = fs20.readFileSync(templatePath, "utf-8");
9489
+ customTemplate = fs24.readFileSync(templatePath, "utf-8");
8910
9490
  }
8911
9491
  const vars = {
8912
9492
  title: name,
@@ -8917,7 +9497,7 @@ function prdCommand(program2) {
8917
9497
  phaseCount
8918
9498
  };
8919
9499
  const content = renderPrdTemplate(vars, customTemplate);
8920
- fs20.writeFileSync(filePath, content, "utf-8");
9500
+ fs24.writeFileSync(filePath, content, "utf-8");
8921
9501
  header("PRD Created");
8922
9502
  success(`Created: ${filePath}`);
8923
9503
  info(`Title: ${name}`);
@@ -8929,15 +9509,15 @@ function prdCommand(program2) {
8929
9509
  prd.command("list").description("List all PRDs with status").option("--json", "Output as JSON").action(async (options) => {
8930
9510
  const projectDir = process.cwd();
8931
9511
  const config = loadConfig(projectDir);
8932
- const absolutePrdDir = path21.join(projectDir, config.prdDir);
8933
- const doneDir = path21.join(absolutePrdDir, "done");
9512
+ const absolutePrdDir = path25.join(projectDir, config.prdDir);
9513
+ const doneDir = path25.join(absolutePrdDir, "done");
8934
9514
  const pending = [];
8935
- if (fs20.existsSync(absolutePrdDir)) {
8936
- const files = fs20.readdirSync(absolutePrdDir).filter((f) => f.endsWith(".md") && f !== "NIGHT-WATCH-SUMMARY.md");
9515
+ if (fs24.existsSync(absolutePrdDir)) {
9516
+ const files = fs24.readdirSync(absolutePrdDir).filter((f) => f.endsWith(".md"));
8937
9517
  for (const file of files) {
8938
- const content = fs20.readFileSync(path21.join(absolutePrdDir, file), "utf-8");
9518
+ const content = fs24.readFileSync(path25.join(absolutePrdDir, file), "utf-8");
8939
9519
  const deps = parseDependencies(content);
8940
- const claimPath = path21.join(absolutePrdDir, file + CLAIM_FILE_EXTENSION);
9520
+ const claimPath = path25.join(absolutePrdDir, file + CLAIM_FILE_EXTENSION);
8941
9521
  const claimStatus = isClaimActive(claimPath, config.maxRuntime);
8942
9522
  pending.push({
8943
9523
  name: file,
@@ -8948,10 +9528,10 @@ function prdCommand(program2) {
8948
9528
  }
8949
9529
  }
8950
9530
  const done = [];
8951
- if (fs20.existsSync(doneDir)) {
8952
- const files = fs20.readdirSync(doneDir).filter((f) => f.endsWith(".md"));
9531
+ if (fs24.existsSync(doneDir)) {
9532
+ const files = fs24.readdirSync(doneDir).filter((f) => f.endsWith(".md"));
8953
9533
  for (const file of files) {
8954
- const content = fs20.readFileSync(path21.join(doneDir, file), "utf-8");
9534
+ const content = fs24.readFileSync(path25.join(doneDir, file), "utf-8");
8955
9535
  const deps = parseDependencies(content);
8956
9536
  done.push({ name: file, dependencies: deps });
8957
9537
  }
@@ -8984,7 +9564,7 @@ function prdCommand(program2) {
8984
9564
  }
8985
9565
  init_dist();
8986
9566
  init_dist();
8987
- function sortPrdsByPriority(prds, priority) {
9567
+ function sortPrdsByPriority2(prds, priority) {
8988
9568
  if (priority.length === 0)
8989
9569
  return prds;
8990
9570
  const priorityMap = /* @__PURE__ */ new Map();
@@ -9003,7 +9583,7 @@ function renderPrdPane(prds, priority) {
9003
9583
  if (prds.length === 0) {
9004
9584
  return "No PRD files found";
9005
9585
  }
9006
- const sorted = priority ? sortPrdsByPriority(prds, priority) : prds;
9586
+ const sorted = priority ? sortPrdsByPriority2(prds, priority) : prds;
9007
9587
  const lines = [];
9008
9588
  for (const prd of sorted) {
9009
9589
  let indicator;
@@ -9081,7 +9661,7 @@ function renderLogPane(projectDir, logs) {
9081
9661
  let newestMtime = 0;
9082
9662
  for (const log of existingLogs) {
9083
9663
  try {
9084
- const stat = fs21.statSync(log.path);
9664
+ const stat = fs25.statSync(log.path);
9085
9665
  if (stat.mtimeMs > newestMtime) {
9086
9666
  newestMtime = stat.mtimeMs;
9087
9667
  newestLog = log;
@@ -9206,7 +9786,7 @@ function createStatusTab() {
9206
9786
  ctx.showMessage("No PRDs to reorder", "info");
9207
9787
  return;
9208
9788
  }
9209
- const sorted = sortPrdsByPriority(nonDone, ctx.config.prdPriority);
9789
+ const sorted = sortPrdsByPriority2(nonDone, ctx.config.prdPriority);
9210
9790
  reorderList = sorted.map((p) => p.name);
9211
9791
  reorderIndex = 0;
9212
9792
  reorderMode = true;
@@ -10762,7 +11342,7 @@ function createLogsTab() {
10762
11342
  let activeKeyHandlers = [];
10763
11343
  let activeCtx = null;
10764
11344
  function getLogPath(projectDir, logName) {
10765
- return path22.join(projectDir, "logs", `${logName}.log`);
11345
+ return path26.join(projectDir, "logs", `${logName}.log`);
10766
11346
  }
10767
11347
  function updateSelector() {
10768
11348
  const tabs = LOG_NAMES.map((name, idx) => {
@@ -10776,7 +11356,7 @@ function createLogsTab() {
10776
11356
  function loadLog(ctx) {
10777
11357
  const logName = LOG_NAMES[selectedLogIndex];
10778
11358
  const logPath = getLogPath(ctx.projectDir, logName);
10779
- if (!fs22.existsSync(logPath)) {
11359
+ if (!fs26.existsSync(logPath)) {
10780
11360
  logContent.setContent(`{yellow-fg}No ${logName}.log file found{/yellow-fg}
10781
11361
 
10782
11362
  Log will appear here once the ${logName} runs.`);
@@ -10784,7 +11364,7 @@ Log will appear here once the ${logName} runs.`);
10784
11364
  return;
10785
11365
  }
10786
11366
  try {
10787
- const stat = fs22.statSync(logPath);
11367
+ const stat = fs26.statSync(logPath);
10788
11368
  const sizeKB = (stat.size / 1024).toFixed(1);
10789
11369
  logContent.setLabel(`[ ${logName}.log - ${sizeKB} KB ]`);
10790
11370
  } catch {
@@ -11349,7 +11929,7 @@ function resolveProject(req, res, next) {
11349
11929
  res.status(404).json({ error: `Project not found: ${decodedId}` });
11350
11930
  return;
11351
11931
  }
11352
- if (!fs23.existsSync(entry.path) || !fs23.existsSync(path23.join(entry.path, CONFIG_FILE_NAME))) {
11932
+ if (!fs27.existsSync(entry.path) || !fs27.existsSync(path27.join(entry.path, CONFIG_FILE_NAME))) {
11353
11933
  res.status(404).json({ error: `Project path invalid or missing config: ${entry.path}` });
11354
11934
  return;
11355
11935
  }
@@ -11434,17 +12014,17 @@ function getBoardProvider(config, projectDir) {
11434
12014
  function cleanOrphanedClaims(dir) {
11435
12015
  let entries;
11436
12016
  try {
11437
- entries = fs24.readdirSync(dir, { withFileTypes: true });
12017
+ entries = fs28.readdirSync(dir, { withFileTypes: true });
11438
12018
  } catch {
11439
12019
  return;
11440
12020
  }
11441
12021
  for (const entry of entries) {
11442
- const fullPath = path24.join(dir, entry.name);
12022
+ const fullPath = path28.join(dir, entry.name);
11443
12023
  if (entry.isDirectory() && entry.name !== "done") {
11444
12024
  cleanOrphanedClaims(fullPath);
11445
12025
  } else if (entry.name.endsWith(CLAIM_FILE_EXTENSION)) {
11446
12026
  try {
11447
- fs24.unlinkSync(fullPath);
12027
+ fs28.unlinkSync(fullPath);
11448
12028
  } catch {
11449
12029
  }
11450
12030
  }
@@ -11492,7 +12072,7 @@ function spawnAction2(projectDir, command, req, res, onSpawned) {
11492
12072
  const config = loadConfig(projectDir);
11493
12073
  sendNotifications(config, {
11494
12074
  event: "run_started",
11495
- projectName: path24.basename(projectDir),
12075
+ projectName: path28.basename(projectDir),
11496
12076
  exitCode: 0,
11497
12077
  provider: config.provider
11498
12078
  }).catch(() => {
@@ -11574,19 +12154,19 @@ function createActionRouteHandlers(ctx) {
11574
12154
  res.status(400).json({ error: "Invalid PRD name" });
11575
12155
  return;
11576
12156
  }
11577
- const prdDir = path24.join(projectDir, config.prdDir);
12157
+ const prdDir = path28.join(projectDir, config.prdDir);
11578
12158
  const normalized = prdName.endsWith(".md") ? prdName : `${prdName}.md`;
11579
- const pendingPath = path24.join(prdDir, normalized);
11580
- const donePath = path24.join(prdDir, "done", normalized);
11581
- if (fs24.existsSync(pendingPath)) {
12159
+ const pendingPath = path28.join(prdDir, normalized);
12160
+ const donePath = path28.join(prdDir, "done", normalized);
12161
+ if (fs28.existsSync(pendingPath)) {
11582
12162
  res.json({ message: `"${normalized}" is already pending` });
11583
12163
  return;
11584
12164
  }
11585
- if (!fs24.existsSync(donePath)) {
12165
+ if (!fs28.existsSync(donePath)) {
11586
12166
  res.status(404).json({ error: `PRD "${normalized}" not found in done/` });
11587
12167
  return;
11588
12168
  }
11589
- fs24.renameSync(donePath, pendingPath);
12169
+ fs28.renameSync(donePath, pendingPath);
11590
12170
  res.json({ message: `Moved "${normalized}" back to pending` });
11591
12171
  } catch (error2) {
11592
12172
  res.status(500).json({
@@ -11604,11 +12184,11 @@ function createActionRouteHandlers(ctx) {
11604
12184
  res.status(409).json({ error: "Executor is actively running \u2014 use Stop instead" });
11605
12185
  return;
11606
12186
  }
11607
- if (fs24.existsSync(lockPath)) {
11608
- fs24.unlinkSync(lockPath);
12187
+ if (fs28.existsSync(lockPath)) {
12188
+ fs28.unlinkSync(lockPath);
11609
12189
  }
11610
- const prdDir = path24.join(projectDir, config.prdDir);
11611
- if (fs24.existsSync(prdDir)) {
12190
+ const prdDir = path28.join(projectDir, config.prdDir);
12191
+ if (fs28.existsSync(prdDir)) {
11612
12192
  cleanOrphanedClaims(prdDir);
11613
12193
  }
11614
12194
  broadcastSSE(ctx.getSseClients(req), "status_changed", await fetchStatusSnapshot(projectDir, config));
@@ -11745,6 +12325,7 @@ function createAgentRoutes() {
11745
12325
  return router;
11746
12326
  }
11747
12327
  init_dist();
12328
+ var ERROR_BOARD_NOT_CONFIGURED = "Board not configured";
11748
12329
  function createBoardRouteHandlers(ctx) {
11749
12330
  const router = Router3({ mergeParams: true });
11750
12331
  const p = ctx.pathPrefix;
@@ -11754,7 +12335,7 @@ function createBoardRouteHandlers(ctx) {
11754
12335
  const projectDir = ctx.getProjectDir(req);
11755
12336
  const provider = getBoardProvider(config, projectDir);
11756
12337
  if (!provider) {
11757
- res.status(404).json({ error: "Board not configured" });
12338
+ res.status(404).json({ error: ERROR_BOARD_NOT_CONFIGURED });
11758
12339
  return;
11759
12340
  }
11760
12341
  const cached = getCachedBoardData(projectDir);
@@ -11787,7 +12368,7 @@ function createBoardRouteHandlers(ctx) {
11787
12368
  const projectDir = ctx.getProjectDir(req);
11788
12369
  const provider = getBoardProvider(config, projectDir);
11789
12370
  if (!provider) {
11790
- res.status(404).json({ error: "Board not configured" });
12371
+ res.status(404).json({ error: ERROR_BOARD_NOT_CONFIGURED });
11791
12372
  return;
11792
12373
  }
11793
12374
  const issues = await provider.getAllIssues();
@@ -11802,7 +12383,7 @@ function createBoardRouteHandlers(ctx) {
11802
12383
  const projectDir = ctx.getProjectDir(req);
11803
12384
  const provider = getBoardProvider(config, projectDir);
11804
12385
  if (!provider) {
11805
- res.status(404).json({ error: "Board not configured" });
12386
+ res.status(404).json({ error: ERROR_BOARD_NOT_CONFIGURED });
11806
12387
  return;
11807
12388
  }
11808
12389
  const { title, body, column } = req.body;
@@ -11833,7 +12414,7 @@ function createBoardRouteHandlers(ctx) {
11833
12414
  const projectDir = ctx.getProjectDir(req);
11834
12415
  const provider = getBoardProvider(config, projectDir);
11835
12416
  if (!provider) {
11836
- res.status(404).json({ error: "Board not configured" });
12417
+ res.status(404).json({ error: ERROR_BOARD_NOT_CONFIGURED });
11837
12418
  return;
11838
12419
  }
11839
12420
  const issueNumber = parseInt(req.params.number, 10);
@@ -11863,7 +12444,7 @@ function createBoardRouteHandlers(ctx) {
11863
12444
  const projectDir = ctx.getProjectDir(req);
11864
12445
  const provider = getBoardProvider(config, projectDir);
11865
12446
  if (!provider) {
11866
- res.status(404).json({ error: "Board not configured" });
12447
+ res.status(404).json({ error: ERROR_BOARD_NOT_CONFIGURED });
11867
12448
  return;
11868
12449
  }
11869
12450
  const issueNumber = parseInt(req.params.number, 10);
@@ -11891,7 +12472,7 @@ function createBoardRouteHandlers(ctx) {
11891
12472
  const projectDir = ctx.getProjectDir(req);
11892
12473
  const provider = getBoardProvider(config, projectDir);
11893
12474
  if (!provider) {
11894
- res.status(404).json({ error: "Board not configured" });
12475
+ res.status(404).json({ error: ERROR_BOARD_NOT_CONFIGURED });
11895
12476
  return;
11896
12477
  }
11897
12478
  const issueNumber = parseInt(req.params.number, 10);
@@ -12179,7 +12760,7 @@ function runDoctorChecks(projectDir, config) {
12179
12760
  });
12180
12761
  }
12181
12762
  try {
12182
- const projectName = path25.basename(projectDir);
12763
+ const projectName = path29.basename(projectDir);
12183
12764
  const marker = generateMarker(projectName);
12184
12765
  const crontabEntries = [...getEntries(marker), ...getProjectEntries(projectDir)];
12185
12766
  if (crontabEntries.length > 0) {
@@ -12202,8 +12783,8 @@ function runDoctorChecks(projectDir, config) {
12202
12783
  detail: "Failed to check crontab"
12203
12784
  });
12204
12785
  }
12205
- const configPath = path25.join(projectDir, CONFIG_FILE_NAME);
12206
- if (fs25.existsSync(configPath)) {
12786
+ const configPath = path29.join(projectDir, CONFIG_FILE_NAME);
12787
+ if (fs29.existsSync(configPath)) {
12207
12788
  checks.push({ name: "config", status: "pass", detail: "Config file exists" });
12208
12789
  } else {
12209
12790
  checks.push({
@@ -12212,9 +12793,9 @@ function runDoctorChecks(projectDir, config) {
12212
12793
  detail: "Config file not found (using defaults)"
12213
12794
  });
12214
12795
  }
12215
- const prdDir = path25.join(projectDir, config.prdDir);
12216
- if (fs25.existsSync(prdDir)) {
12217
- const prds = fs25.readdirSync(prdDir).filter((f) => f.endsWith(".md") && f !== "NIGHT-WATCH-SUMMARY.md");
12796
+ const prdDir = path29.join(projectDir, config.prdDir);
12797
+ if (fs29.existsSync(prdDir)) {
12798
+ const prds = fs29.readdirSync(prdDir).filter((f) => f.endsWith(".md"));
12218
12799
  checks.push({
12219
12800
  name: "prdDir",
12220
12801
  status: "pass",
@@ -12272,7 +12853,7 @@ function createLogRoutes(deps) {
12272
12853
  const lines = typeof linesParam === "string" ? parseInt(linesParam, 10) : 200;
12273
12854
  const linesToRead = isNaN(lines) || lines < 1 ? 200 : Math.min(lines, 1e4);
12274
12855
  const fileName = LOG_FILE_NAMES[name] || name;
12275
- const logPath = path26.join(projectDir, LOG_DIR, `${fileName}.log`);
12856
+ const logPath = path30.join(projectDir, LOG_DIR, `${fileName}.log`);
12276
12857
  const logLines = getLastLogLines(logPath, linesToRead);
12277
12858
  res.json({ name, lines: logLines });
12278
12859
  } catch (error2) {
@@ -12298,7 +12879,7 @@ function createProjectLogRoutes() {
12298
12879
  const lines = typeof linesParam === "string" ? parseInt(linesParam, 10) : 200;
12299
12880
  const linesToRead = isNaN(lines) || lines < 1 ? 200 : Math.min(lines, 1e4);
12300
12881
  const fileName = LOG_FILE_NAMES[name] || name;
12301
- const logPath = path26.join(projectDir, LOG_DIR, `${fileName}.log`);
12882
+ const logPath = path30.join(projectDir, LOG_DIR, `${fileName}.log`);
12302
12883
  const logLines = getLastLogLines(logPath, linesToRead);
12303
12884
  res.json({ name, lines: logLines });
12304
12885
  } catch (error2) {
@@ -12336,7 +12917,7 @@ function createRoadmapRouteHandlers(ctx) {
12336
12917
  const config = ctx.getConfig(req);
12337
12918
  const projectDir = ctx.getProjectDir(req);
12338
12919
  const status = getRoadmapStatus(projectDir, config);
12339
- const prdDir = path27.join(projectDir, config.prdDir);
12920
+ const prdDir = path31.join(projectDir, config.prdDir);
12340
12921
  const state = loadRoadmapState(prdDir);
12341
12922
  res.json({
12342
12923
  ...status,
@@ -12593,14 +13174,14 @@ data: ${JSON.stringify(snapshot)}
12593
13174
  var __filename2 = fileURLToPath3(import.meta.url);
12594
13175
  var __dirname3 = dirname7(__filename2);
12595
13176
  function resolveWebDistPath() {
12596
- const bundled = path28.join(__dirname3, "web");
12597
- if (fs26.existsSync(path28.join(bundled, "index.html")))
13177
+ const bundled = path32.join(__dirname3, "web");
13178
+ if (fs30.existsSync(path32.join(bundled, "index.html")))
12598
13179
  return bundled;
12599
13180
  let d = __dirname3;
12600
13181
  for (let i = 0; i < 8; i++) {
12601
- if (fs26.existsSync(path28.join(d, "turbo.json"))) {
12602
- const dev = path28.join(d, "web/dist");
12603
- if (fs26.existsSync(path28.join(dev, "index.html")))
13182
+ if (fs30.existsSync(path32.join(d, "turbo.json"))) {
13183
+ const dev = path32.join(d, "web/dist");
13184
+ if (fs30.existsSync(path32.join(dev, "index.html")))
12604
13185
  return dev;
12605
13186
  break;
12606
13187
  }
@@ -12610,7 +13191,7 @@ function resolveWebDistPath() {
12610
13191
  }
12611
13192
  function setupStaticFiles(app) {
12612
13193
  const webDistPath = resolveWebDistPath();
12613
- if (fs26.existsSync(webDistPath)) {
13194
+ if (fs30.existsSync(webDistPath)) {
12614
13195
  app.use(express.static(webDistPath));
12615
13196
  }
12616
13197
  app.use((req, res, next) => {
@@ -12618,8 +13199,8 @@ function setupStaticFiles(app) {
12618
13199
  next();
12619
13200
  return;
12620
13201
  }
12621
- const indexPath = path28.resolve(webDistPath, "index.html");
12622
- if (fs26.existsSync(indexPath)) {
13202
+ const indexPath = path32.resolve(webDistPath, "index.html");
13203
+ if (fs30.existsSync(indexPath)) {
12623
13204
  res.sendFile(indexPath, (err) => {
12624
13205
  if (err)
12625
13206
  next();
@@ -12729,7 +13310,7 @@ function createGlobalApp() {
12729
13310
  return app;
12730
13311
  }
12731
13312
  function bootContainer() {
12732
- initContainer(path28.dirname(getDbPath()));
13313
+ initContainer(path32.dirname(getDbPath()));
12733
13314
  const personaRepo = container.resolve(SqliteAgentPersonaRepository);
12734
13315
  personaRepo.seedDefaultsOnFirstRun();
12735
13316
  personaRepo.patchDefaultAvatarUrls();
@@ -12783,9 +13364,9 @@ function isProcessRunning2(pid) {
12783
13364
  }
12784
13365
  function readPid(lockPath) {
12785
13366
  try {
12786
- if (!fs27.existsSync(lockPath))
13367
+ if (!fs31.existsSync(lockPath))
12787
13368
  return null;
12788
- const raw = fs27.readFileSync(lockPath, "utf-8").trim();
13369
+ const raw = fs31.readFileSync(lockPath, "utf-8").trim();
12789
13370
  const pid = parseInt(raw, 10);
12790
13371
  return Number.isFinite(pid) ? pid : null;
12791
13372
  } catch {
@@ -12797,10 +13378,10 @@ function acquireServeLock(mode, port) {
12797
13378
  let stalePidCleaned;
12798
13379
  for (let attempt = 0; attempt < 2; attempt++) {
12799
13380
  try {
12800
- const fd = fs27.openSync(lockPath, "wx");
12801
- fs27.writeFileSync(fd, `${process.pid}
13381
+ const fd = fs31.openSync(lockPath, "wx");
13382
+ fs31.writeFileSync(fd, `${process.pid}
12802
13383
  `);
12803
- fs27.closeSync(fd);
13384
+ fs31.closeSync(fd);
12804
13385
  return { acquired: true, lockPath, stalePidCleaned };
12805
13386
  } catch (error2) {
12806
13387
  const err = error2;
@@ -12821,7 +13402,7 @@ function acquireServeLock(mode, port) {
12821
13402
  };
12822
13403
  }
12823
13404
  try {
12824
- fs27.unlinkSync(lockPath);
13405
+ fs31.unlinkSync(lockPath);
12825
13406
  if (existingPid) {
12826
13407
  stalePidCleaned = existingPid;
12827
13408
  }
@@ -12844,12 +13425,12 @@ function acquireServeLock(mode, port) {
12844
13425
  }
12845
13426
  function releaseServeLock(lockPath) {
12846
13427
  try {
12847
- if (!fs27.existsSync(lockPath))
13428
+ if (!fs31.existsSync(lockPath))
12848
13429
  return;
12849
13430
  const lockPid = readPid(lockPath);
12850
13431
  if (lockPid !== null && lockPid !== process.pid)
12851
13432
  return;
12852
- fs27.unlinkSync(lockPath);
13433
+ fs31.unlinkSync(lockPath);
12853
13434
  } catch {
12854
13435
  }
12855
13436
  }
@@ -12935,7 +13516,7 @@ function parseProjectDirs(projects, cwd) {
12935
13516
  if (!projects || projects.trim().length === 0) {
12936
13517
  return [cwd];
12937
13518
  }
12938
- const dirs = projects.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0).map((entry) => path29.resolve(cwd, entry));
13519
+ const dirs = projects.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0).map((entry) => path33.resolve(cwd, entry));
12939
13520
  return Array.from(new Set(dirs));
12940
13521
  }
12941
13522
  function runCommand2(command, args, cwd) {
@@ -12974,7 +13555,7 @@ function updateCommand(program2) {
12974
13555
  }
12975
13556
  const nightWatchBin = resolveNightWatchBin();
12976
13557
  for (const projectDir of projectDirs) {
12977
- if (!fs28.existsSync(projectDir) || !fs28.statSync(projectDir).isDirectory()) {
13558
+ if (!fs32.existsSync(projectDir) || !fs32.statSync(projectDir).isDirectory()) {
12978
13559
  warn(`Skipping invalid project directory: ${projectDir}`);
12979
13560
  continue;
12980
13561
  }
@@ -13021,26 +13602,26 @@ function normalizePrdName(name) {
13021
13602
  return name;
13022
13603
  }
13023
13604
  function getDonePrds(doneDir) {
13024
- if (!fs29.existsSync(doneDir)) {
13605
+ if (!fs33.existsSync(doneDir)) {
13025
13606
  return [];
13026
13607
  }
13027
- return fs29.readdirSync(doneDir).filter((f) => f.endsWith(".md"));
13608
+ return fs33.readdirSync(doneDir).filter((f) => f.endsWith(".md"));
13028
13609
  }
13029
13610
  function retryCommand(program2) {
13030
13611
  program2.command("retry <prdName>").description("Move a completed PRD from done/ back to pending").action((prdName) => {
13031
13612
  const projectDir = process.cwd();
13032
13613
  const config = loadConfig(projectDir);
13033
- const prdDir = path30.join(projectDir, config.prdDir);
13034
- const doneDir = path30.join(prdDir, "done");
13614
+ const prdDir = path34.join(projectDir, config.prdDir);
13615
+ const doneDir = path34.join(prdDir, "done");
13035
13616
  const normalizedPrdName = normalizePrdName(prdName);
13036
- const pendingPath = path30.join(prdDir, normalizedPrdName);
13037
- if (fs29.existsSync(pendingPath)) {
13617
+ const pendingPath = path34.join(prdDir, normalizedPrdName);
13618
+ if (fs33.existsSync(pendingPath)) {
13038
13619
  info(`"${normalizedPrdName}" is already pending, nothing to retry.`);
13039
13620
  return;
13040
13621
  }
13041
- const donePath = path30.join(doneDir, normalizedPrdName);
13042
- if (fs29.existsSync(donePath)) {
13043
- fs29.renameSync(donePath, pendingPath);
13622
+ const donePath = path34.join(doneDir, normalizedPrdName);
13623
+ if (fs33.existsSync(donePath)) {
13624
+ fs33.renameSync(donePath, pendingPath);
13044
13625
  success(`Moved "${normalizedPrdName}" back to pending.`);
13045
13626
  dim(`From: ${donePath}`);
13046
13627
  dim(`To: ${pendingPath}`);
@@ -13214,7 +13795,7 @@ function prdsCommand(program2) {
13214
13795
  const config = loadConfig(projectDir);
13215
13796
  const prds = collectPrdInfo(projectDir, config.prdDir, config.maxRuntime);
13216
13797
  const openPrBranches = getOpenPrBranches(projectDir);
13217
- const filteredPrds = prds.filter((prd) => !prd.name.toLowerCase().includes("night-watch-summary"));
13798
+ const filteredPrds = prds;
13218
13799
  for (const prd of filteredPrds) {
13219
13800
  if (prd.status !== "done") {
13220
13801
  const matchingPr = findMatchingPr(prd.name, openPrBranches, config.branchPrefix);
@@ -13322,7 +13903,7 @@ async function cancelProcess2(processType, lockPath, force = false) {
13322
13903
  const pid = lockStatus.pid;
13323
13904
  if (!lockStatus.running) {
13324
13905
  try {
13325
- fs30.unlinkSync(lockPath);
13906
+ fs34.unlinkSync(lockPath);
13326
13907
  return {
13327
13908
  success: true,
13328
13909
  message: `${processType} is not running (cleaned up stale lock file for PID ${pid})`,
@@ -13360,7 +13941,7 @@ async function cancelProcess2(processType, lockPath, force = false) {
13360
13941
  await sleep3(3e3);
13361
13942
  if (!isProcessRunning3(pid)) {
13362
13943
  try {
13363
- fs30.unlinkSync(lockPath);
13944
+ fs34.unlinkSync(lockPath);
13364
13945
  } catch {
13365
13946
  }
13366
13947
  return {
@@ -13395,7 +13976,7 @@ async function cancelProcess2(processType, lockPath, force = false) {
13395
13976
  await sleep3(500);
13396
13977
  if (!isProcessRunning3(pid)) {
13397
13978
  try {
13398
- fs30.unlinkSync(lockPath);
13979
+ fs34.unlinkSync(lockPath);
13399
13980
  } catch {
13400
13981
  }
13401
13982
  return {
@@ -13462,24 +14043,24 @@ function plannerLockPath2(projectDir) {
13462
14043
  }
13463
14044
  function acquirePlannerLock(projectDir) {
13464
14045
  const lockFile = plannerLockPath2(projectDir);
13465
- if (fs31.existsSync(lockFile)) {
13466
- const pidRaw = fs31.readFileSync(lockFile, "utf-8").trim();
14046
+ if (fs35.existsSync(lockFile)) {
14047
+ const pidRaw = fs35.readFileSync(lockFile, "utf-8").trim();
13467
14048
  const pid = parseInt(pidRaw, 10);
13468
14049
  if (!Number.isNaN(pid) && isProcessRunning(pid)) {
13469
14050
  return { acquired: false, lockFile, pid };
13470
14051
  }
13471
14052
  try {
13472
- fs31.unlinkSync(lockFile);
14053
+ fs35.unlinkSync(lockFile);
13473
14054
  } catch {
13474
14055
  }
13475
14056
  }
13476
- fs31.writeFileSync(lockFile, String(process.pid));
14057
+ fs35.writeFileSync(lockFile, String(process.pid));
13477
14058
  return { acquired: true, lockFile };
13478
14059
  }
13479
14060
  function releasePlannerLock(lockFile) {
13480
14061
  try {
13481
- if (fs31.existsSync(lockFile)) {
13482
- fs31.unlinkSync(lockFile);
14062
+ if (fs35.existsSync(lockFile)) {
14063
+ fs35.unlinkSync(lockFile);
13483
14064
  }
13484
14065
  } catch {
13485
14066
  }
@@ -13601,7 +14182,7 @@ function sliceCommand(program2) {
13601
14182
  if (!options.dryRun) {
13602
14183
  await sendNotifications(config, {
13603
14184
  event: "run_started",
13604
- projectName: path31.basename(projectDir),
14185
+ projectName: path35.basename(projectDir),
13605
14186
  exitCode: 0,
13606
14187
  provider: config.provider
13607
14188
  });
@@ -13621,7 +14202,7 @@ function sliceCommand(program2) {
13621
14202
  if (!options.dryRun && result.sliced) {
13622
14203
  await sendNotifications(config, {
13623
14204
  event: "run_succeeded",
13624
- projectName: path31.basename(projectDir),
14205
+ projectName: path35.basename(projectDir),
13625
14206
  exitCode,
13626
14207
  provider: config.provider,
13627
14208
  prTitle: result.item?.title
@@ -13629,7 +14210,7 @@ function sliceCommand(program2) {
13629
14210
  } else if (!options.dryRun && !nothingPending) {
13630
14211
  await sendNotifications(config, {
13631
14212
  event: "run_failed",
13632
- projectName: path31.basename(projectDir),
14213
+ projectName: path35.basename(projectDir),
13633
14214
  exitCode,
13634
14215
  provider: config.provider
13635
14216
  });
@@ -13647,13 +14228,13 @@ function createStateCommand() {
13647
14228
  const state = new Command("state");
13648
14229
  state.description("Manage Night Watch state");
13649
14230
  state.command("migrate").description("Migrate legacy JSON state files to SQLite").option("--dry-run", "Show what would be migrated without making changes").action((opts) => {
13650
- const nightWatchHome = process.env.NIGHT_WATCH_HOME || path32.join(os5.homedir(), GLOBAL_CONFIG_DIR);
14231
+ const nightWatchHome = process.env.NIGHT_WATCH_HOME || path36.join(os6.homedir(), GLOBAL_CONFIG_DIR);
13651
14232
  if (opts.dryRun) {
13652
14233
  console.log(chalk5.cyan("Dry-run mode: no changes will be made.\n"));
13653
14234
  console.log(`Legacy JSON files that would be migrated from: ${chalk5.bold(nightWatchHome)}`);
13654
- console.log(` ${path32.join(nightWatchHome, "projects.json")}`);
13655
- console.log(` ${path32.join(nightWatchHome, "history.json")}`);
13656
- console.log(` ${path32.join(nightWatchHome, "prd-states.json")}`);
14235
+ console.log(` ${path36.join(nightWatchHome, "projects.json")}`);
14236
+ console.log(` ${path36.join(nightWatchHome, "history.json")}`);
14237
+ console.log(` ${path36.join(nightWatchHome, "prd-states.json")}`);
13657
14238
  console.log(` <project>/<prdDir>/.roadmap-state.json (per project)`);
13658
14239
  console.log(chalk5.dim("\nRun without --dry-run to apply the migration."));
13659
14240
  return;
@@ -13701,7 +14282,7 @@ function getProvider(config, cwd) {
13701
14282
  return createBoardProvider(bp, cwd);
13702
14283
  }
13703
14284
  function defaultBoardTitle(cwd) {
13704
- return `${path33.basename(cwd)} Night Watch`;
14285
+ return `${path37.basename(cwd)} Night Watch`;
13705
14286
  }
13706
14287
  async function ensureBoardConfigured(config, cwd, provider, options) {
13707
14288
  if (config.boardProvider?.projectNumber) {
@@ -13741,7 +14322,7 @@ async function confirmPrompt(question) {
13741
14322
  }
13742
14323
  async function createGitHubLabel(label2, cwd) {
13743
14324
  try {
13744
- execFileSync3("gh", ["label", "create", label2.name, "--description", label2.description, "--color", label2.color], { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
14325
+ execFileSync6("gh", ["label", "create", label2.name, "--description", label2.description, "--color", label2.color], { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
13745
14326
  return { created: true, skipped: false };
13746
14327
  } catch (err) {
13747
14328
  const output = err instanceof Error ? err.message : String(err);
@@ -13881,11 +14462,11 @@ function boardCommand(program2) {
13881
14462
  let body = options.body ?? "";
13882
14463
  if (options.bodyFile) {
13883
14464
  const filePath = options.bodyFile;
13884
- if (!fs32.existsSync(filePath)) {
14465
+ if (!fs36.existsSync(filePath)) {
13885
14466
  console.error(`File not found: ${filePath}`);
13886
14467
  process.exit(1);
13887
14468
  }
13888
- body = fs32.readFileSync(filePath, "utf-8");
14469
+ body = fs36.readFileSync(filePath, "utf-8");
13889
14470
  }
13890
14471
  const labels = [];
13891
14472
  if (options.label) {
@@ -14093,12 +14674,12 @@ function boardCommand(program2) {
14093
14674
  const config = loadConfig(cwd);
14094
14675
  const provider = getProvider(config, cwd);
14095
14676
  await ensureBoardConfigured(config, cwd, provider);
14096
- const roadmapPath = options.roadmap ?? path33.join(cwd, "ROADMAP.md");
14097
- if (!fs32.existsSync(roadmapPath)) {
14677
+ const roadmapPath = options.roadmap ?? path37.join(cwd, "ROADMAP.md");
14678
+ if (!fs36.existsSync(roadmapPath)) {
14098
14679
  console.error(`Roadmap file not found: ${roadmapPath}`);
14099
14680
  process.exit(1);
14100
14681
  }
14101
- const roadmapContent = fs32.readFileSync(roadmapPath, "utf-8");
14682
+ const roadmapContent = fs36.readFileSync(roadmapPath, "utf-8");
14102
14683
  const items = parseRoadmap(roadmapContent);
14103
14684
  const uncheckedItems = getUncheckedItems(items);
14104
14685
  if (uncheckedItems.length === 0) {
@@ -14192,7 +14773,7 @@ function boardCommand(program2) {
14192
14773
  try {
14193
14774
  const labelsToAdd = [category, horizon].filter((l) => !issue.labels.includes(l));
14194
14775
  if (labelsToAdd.length > 0) {
14195
- execFileSync3("gh", ["issue", "edit", String(issue.number), "--add-label", labelsToAdd.join(",")], { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
14776
+ execFileSync6("gh", ["issue", "edit", String(issue.number), "--add-label", labelsToAdd.join(",")], { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
14196
14777
  }
14197
14778
  updated++;
14198
14779
  success(`Updated labels on #${issue.number}: ${item.title}`);
@@ -14216,14 +14797,14 @@ var __dirname4 = dirname8(__filename3);
14216
14797
  function findPackageRoot(dir) {
14217
14798
  let d = dir;
14218
14799
  for (let i = 0; i < 5; i++) {
14219
- if (existsSync26(join30(d, "package.json")))
14800
+ if (existsSync30(join33(d, "package.json")))
14220
14801
  return d;
14221
14802
  d = dirname8(d);
14222
14803
  }
14223
14804
  return dir;
14224
14805
  }
14225
14806
  var packageRoot = findPackageRoot(__dirname4);
14226
- var packageJson = JSON.parse(readFileSync16(join30(packageRoot, "package.json"), "utf-8"));
14807
+ var packageJson = JSON.parse(readFileSync18(join33(packageRoot, "package.json"), "utf-8"));
14227
14808
  var program = new Command2();
14228
14809
  program.name("night-watch").description("Autonomous PRD execution using Claude CLI + cron").version(packageJson.version);
14229
14810
  initCommand(program);