@jonit-dev/night-watch-cli 1.7.57 → 1.7.59

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
@@ -1,5 +1,175 @@
1
1
  #!/usr/bin/env node
2
2
  import 'reflect-metadata';
3
+
4
+ // dist/cli.js
5
+ import "reflect-metadata";
6
+ import "reflect-metadata";
7
+ import "reflect-metadata";
8
+ import * as fs from "fs";
9
+ import * as path from "path";
10
+ import { fileURLToPath } from "url";
11
+ import Database from "better-sqlite3";
12
+ import { inject, injectable } from "tsyringe";
13
+ import { createCipheriv, createDecipheriv, randomBytes, randomUUID } from "crypto";
14
+ import Database2 from "better-sqlite3";
15
+ import { inject as inject2, injectable as injectable2 } from "tsyringe";
16
+ import Database3 from "better-sqlite3";
17
+ import { inject as inject3, injectable as injectable3 } from "tsyringe";
18
+ import Database4 from "better-sqlite3";
19
+ import { inject as inject4, injectable as injectable4 } from "tsyringe";
20
+ import Database5 from "better-sqlite3";
21
+ import { inject as inject5, injectable as injectable5 } from "tsyringe";
22
+ import Database6 from "better-sqlite3";
23
+ import { inject as inject6, injectable as injectable6 } from "tsyringe";
24
+ import * as fs2 from "fs";
25
+ import * as os from "os";
26
+ import * as path2 from "path";
27
+ import Database7 from "better-sqlite3";
28
+ import "reflect-metadata";
29
+ import { container } from "tsyringe";
30
+ import { execFile } from "child_process";
31
+ import { promisify } from "util";
32
+ import { execFile as execFile2 } from "child_process";
33
+ import { promisify as promisify2 } from "util";
34
+ import * as fs3 from "fs";
35
+ import * as path3 from "path";
36
+ import { execSync } from "child_process";
37
+ import * as fs4 from "fs";
38
+ import * as os2 from "os";
39
+ import * as path4 from "path";
40
+ import { createHash } from "crypto";
41
+ import { exec } from "child_process";
42
+ import { promisify as promisify3 } from "util";
43
+ import * as fs5 from "fs";
44
+ import * as path5 from "path";
45
+ import * as fs6 from "fs";
46
+ import * as fs7 from "fs";
47
+ import * as path6 from "path";
48
+ import { execSync as execSync2 } from "child_process";
49
+ import * as os3 from "os";
50
+ import * as path7 from "path";
51
+ import * as fs8 from "fs";
52
+ import * as fs9 from "fs";
53
+ import * as path8 from "path";
54
+ import * as os4 from "os";
55
+ import * as path9 from "path";
56
+ import { execFileSync } from "child_process";
57
+ import { execFileSync as execFileSync2 } from "child_process";
58
+ import * as fs10 from "fs";
59
+ import chalk from "chalk";
60
+ import ora from "ora";
61
+ import Table from "cli-table3";
62
+ import { execFileSync as execFileSync3 } from "child_process";
63
+ import * as fs11 from "fs";
64
+ import * as path10 from "path";
65
+ import * as fs12 from "fs";
66
+ import * as path11 from "path";
67
+ import * as fs13 from "fs";
68
+ import * as os5 from "os";
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";
77
+ import { spawn } from "child_process";
78
+ import { createHash as createHash3 } from "crypto";
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";
83
+ import "reflect-metadata";
84
+ import { Command as Command2 } from "commander";
85
+ import { existsSync as existsSync30, readFileSync as readFileSync18 } from "fs";
86
+ import { fileURLToPath as fileURLToPath4 } from "url";
87
+ import { dirname as dirname8, join as join34 } from "path";
88
+ import fs18 from "fs";
89
+ import path17 from "path";
90
+ import { execSync as execSync3 } from "child_process";
91
+ import { fileURLToPath as fileURLToPath2 } from "url";
92
+ import { dirname as dirname4, join as join16 } from "path";
93
+ import * as readline from "readline";
94
+ import * as fs19 from "fs";
95
+ import * as path18 from "path";
96
+ import { execFileSync as execFileSync5 } from "child_process";
97
+ import * as path19 from "path";
98
+ import * as path20 from "path";
99
+ import * as fs20 from "fs";
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";
112
+ import * as readline2 from "readline";
113
+ import blessed6 from "blessed";
114
+ import blessed from "blessed";
115
+ import * as fs25 from "fs";
116
+ import blessed2 from "blessed";
117
+ import blessed3 from "blessed";
118
+ import cronstrue from "cronstrue";
119
+ import blessed4 from "blessed";
120
+ import { spawn as spawn4 } from "child_process";
121
+ import blessed5 from "blessed";
122
+ import * as fs26 from "fs";
123
+ import * as path26 from "path";
124
+ import * as fs31 from "fs";
125
+ import * as fs30 from "fs";
126
+ import * as path32 from "path";
127
+ import { dirname as dirname7 } from "path";
128
+ import { fileURLToPath as fileURLToPath3 } from "url";
129
+ import cors from "cors";
130
+ import express from "express";
131
+ import * as fs27 from "fs";
132
+ import * as path27 from "path";
133
+ import * as fs28 from "fs";
134
+ import * as path28 from "path";
135
+ import { execSync as execSync5, spawn as spawn5 } from "child_process";
136
+ import { Router } from "express";
137
+ import { Router as Router2 } from "express";
138
+ import { Router as Router3 } from "express";
139
+ import { Router as Router4 } from "express";
140
+ import { CronExpressionParser } from "cron-parser";
141
+ import * as fs29 from "fs";
142
+ import * as path29 from "path";
143
+ import { execSync as execSync6 } from "child_process";
144
+ import { Router as Router5 } from "express";
145
+ import * as path30 from "path";
146
+ import { Router as Router6 } from "express";
147
+ import { Router as Router7 } from "express";
148
+ import * as path31 from "path";
149
+ import { Router as Router8 } from "express";
150
+ import { Router as Router9 } from "express";
151
+ import { CronExpressionParser as CronExpressionParser2 } from "cron-parser";
152
+ import { spawnSync } from "child_process";
153
+ import * as fs32 from "fs";
154
+ import * as path33 from "path";
155
+ import * as fs33 from "fs";
156
+ import * as path34 from "path";
157
+ import chalk3 from "chalk";
158
+ import chalk4 from "chalk";
159
+ import { execSync as execSync7 } from "child_process";
160
+ import * as fs34 from "fs";
161
+ import * as readline3 from "readline";
162
+ import * as fs35 from "fs";
163
+ import * as path35 from "path";
164
+ import * as os6 from "os";
165
+ import * as path36 from "path";
166
+ import chalk5 from "chalk";
167
+ import { Command } from "commander";
168
+ import { execFileSync as execFileSync6 } from "child_process";
169
+ import * as fs36 from "fs";
170
+ import * as path37 from "path";
171
+ import * as readline4 from "readline";
172
+ import chalk6 from "chalk";
3
173
  var __defProp = Object.defineProperty;
4
174
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
175
  var __esm = (fn, res) => function __init() {
@@ -9,16 +179,77 @@ var __export = (target, all) => {
9
179
  for (var name in all)
10
180
  __defProp(target, name, { get: all[name], enumerable: true });
11
181
  };
12
-
13
- // ../core/dist/types.js
14
182
  var init_types = __esm({
15
183
  "../core/dist/types.js"() {
16
184
  "use strict";
17
185
  }
18
186
  });
19
-
20
- // ../core/dist/constants.js
21
- var DEFAULT_DEFAULT_BRANCH, DEFAULT_PRD_DIR, DEFAULT_MAX_RUNTIME, DEFAULT_REVIEWER_MAX_RUNTIME, DEFAULT_CRON_SCHEDULE, DEFAULT_REVIEWER_SCHEDULE, DEFAULT_CRON_SCHEDULE_OFFSET, DEFAULT_MAX_RETRIES, DEFAULT_REVIEWER_MAX_RETRIES, DEFAULT_REVIEWER_RETRY_DELAY, DEFAULT_BRANCH_PREFIX, DEFAULT_BRANCH_PATTERNS, DEFAULT_MIN_REVIEW_SCORE, DEFAULT_MAX_LOG_SIZE, DEFAULT_PROVIDER, DEFAULT_EXECUTOR_ENABLED, DEFAULT_REVIEWER_ENABLED, DEFAULT_PROVIDER_ENV, DEFAULT_FALLBACK_ON_RATE_LIMIT, DEFAULT_CLAUDE_MODEL, VALID_CLAUDE_MODELS, CLAUDE_MODEL_IDS, DEFAULT_NOTIFICATIONS, DEFAULT_PRD_PRIORITY, DEFAULT_SLICER_SCHEDULE, DEFAULT_SLICER_MAX_RUNTIME, DEFAULT_ROADMAP_SCANNER, DEFAULT_TEMPLATES_DIR, DEFAULT_BOARD_PROVIDER, DEFAULT_LOCAL_BOARD_INFO, DEFAULT_AUTO_MERGE, DEFAULT_AUTO_MERGE_METHOD, VALID_MERGE_METHODS, DEFAULT_QA_ENABLED, DEFAULT_QA_SCHEDULE, DEFAULT_QA_MAX_RUNTIME, DEFAULT_QA_ARTIFACTS, DEFAULT_QA_SKIP_LABEL, DEFAULT_QA_AUTO_INSTALL_PLAYWRIGHT, DEFAULT_QA, QA_LOG_NAME, DEFAULT_AUDIT_ENABLED, DEFAULT_AUDIT_SCHEDULE, DEFAULT_AUDIT_MAX_RUNTIME, DEFAULT_AUDIT, AUDIT_LOG_NAME, PLANNER_LOG_NAME, VALID_PROVIDERS, VALID_JOB_TYPES, DEFAULT_JOB_PROVIDERS, PROVIDER_COMMANDS, CONFIG_FILE_NAME, LOCK_FILE_PREFIX, LOG_DIR, CLAIM_FILE_EXTENSION, EXECUTOR_LOG_NAME, REVIEWER_LOG_NAME, EXECUTOR_LOG_FILE, REVIEWER_LOG_FILE, LOG_FILE_NAMES, GLOBAL_CONFIG_DIR, REGISTRY_FILE_NAME, HISTORY_FILE_NAME, PRD_STATES_FILE_NAME, STATE_DB_FILE_NAME, MAX_HISTORY_RECORDS_PER_PRD;
187
+ var DEFAULT_DEFAULT_BRANCH;
188
+ var DEFAULT_PRD_DIR;
189
+ var DEFAULT_MAX_RUNTIME;
190
+ var DEFAULT_REVIEWER_MAX_RUNTIME;
191
+ var DEFAULT_CRON_SCHEDULE;
192
+ var DEFAULT_REVIEWER_SCHEDULE;
193
+ var DEFAULT_CRON_SCHEDULE_OFFSET;
194
+ var DEFAULT_MAX_RETRIES;
195
+ var DEFAULT_REVIEWER_MAX_RETRIES;
196
+ var DEFAULT_REVIEWER_RETRY_DELAY;
197
+ var DEFAULT_BRANCH_PREFIX;
198
+ var DEFAULT_BRANCH_PATTERNS;
199
+ var DEFAULT_MIN_REVIEW_SCORE;
200
+ var DEFAULT_MAX_LOG_SIZE;
201
+ var DEFAULT_PROVIDER;
202
+ var DEFAULT_EXECUTOR_ENABLED;
203
+ var DEFAULT_REVIEWER_ENABLED;
204
+ var DEFAULT_PROVIDER_ENV;
205
+ var DEFAULT_FALLBACK_ON_RATE_LIMIT;
206
+ var DEFAULT_CLAUDE_MODEL;
207
+ var VALID_CLAUDE_MODELS;
208
+ var CLAUDE_MODEL_IDS;
209
+ var DEFAULT_NOTIFICATIONS;
210
+ var DEFAULT_PRD_PRIORITY;
211
+ var DEFAULT_SLICER_SCHEDULE;
212
+ var DEFAULT_SLICER_MAX_RUNTIME;
213
+ var DEFAULT_ROADMAP_SCANNER;
214
+ var DEFAULT_TEMPLATES_DIR;
215
+ var DEFAULT_BOARD_PROVIDER;
216
+ var DEFAULT_LOCAL_BOARD_INFO;
217
+ var DEFAULT_AUTO_MERGE;
218
+ var DEFAULT_AUTO_MERGE_METHOD;
219
+ var VALID_MERGE_METHODS;
220
+ var DEFAULT_QA_ENABLED;
221
+ var DEFAULT_QA_SCHEDULE;
222
+ var DEFAULT_QA_MAX_RUNTIME;
223
+ var DEFAULT_QA_ARTIFACTS;
224
+ var DEFAULT_QA_SKIP_LABEL;
225
+ var DEFAULT_QA_AUTO_INSTALL_PLAYWRIGHT;
226
+ var DEFAULT_QA;
227
+ var QA_LOG_NAME;
228
+ var DEFAULT_AUDIT_ENABLED;
229
+ var DEFAULT_AUDIT_SCHEDULE;
230
+ var DEFAULT_AUDIT_MAX_RUNTIME;
231
+ var DEFAULT_AUDIT;
232
+ var AUDIT_LOG_NAME;
233
+ var PLANNER_LOG_NAME;
234
+ var VALID_PROVIDERS;
235
+ var VALID_JOB_TYPES;
236
+ var DEFAULT_JOB_PROVIDERS;
237
+ var PROVIDER_COMMANDS;
238
+ var CONFIG_FILE_NAME;
239
+ var LOCK_FILE_PREFIX;
240
+ var LOG_DIR;
241
+ var CLAIM_FILE_EXTENSION;
242
+ var EXECUTOR_LOG_NAME;
243
+ var REVIEWER_LOG_NAME;
244
+ var EXECUTOR_LOG_FILE;
245
+ var REVIEWER_LOG_FILE;
246
+ var LOG_FILE_NAMES;
247
+ var GLOBAL_CONFIG_DIR;
248
+ var REGISTRY_FILE_NAME;
249
+ var HISTORY_FILE_NAME;
250
+ var PRD_STATES_FILE_NAME;
251
+ var STATE_DB_FILE_NAME;
252
+ var MAX_HISTORY_RECORDS_PER_PRD;
22
253
  var init_constants = __esm({
23
254
  "../core/dist/constants.js"() {
24
255
  "use strict";
@@ -125,11 +356,6 @@ var init_constants = __esm({
125
356
  MAX_HISTORY_RECORDS_PER_PRD = 10;
126
357
  }
127
358
  });
128
-
129
- // ../core/dist/config.js
130
- import * as fs from "fs";
131
- import * as path from "path";
132
- import { fileURLToPath } from "url";
133
359
  function getDefaultConfig() {
134
360
  return {
135
361
  // PRD execution
@@ -144,6 +370,7 @@ function getDefaultConfig() {
144
370
  // Cron scheduling
145
371
  cronSchedule: DEFAULT_CRON_SCHEDULE,
146
372
  reviewerSchedule: DEFAULT_REVIEWER_SCHEDULE,
373
+ scheduleBundleId: null,
147
374
  cronScheduleOffset: DEFAULT_CRON_SCHEDULE_OFFSET,
148
375
  maxRetries: DEFAULT_MAX_RETRIES,
149
376
  // Reviewer retry configuration
@@ -211,6 +438,13 @@ function normalizeConfig(rawConfig) {
211
438
  normalized.maxLogSize = readNumber(rawConfig.maxLogSize) ?? readNumber(logging?.maxLogSize);
212
439
  normalized.cronSchedule = readString(rawConfig.cronSchedule) ?? readString(cron?.executorSchedule);
213
440
  normalized.reviewerSchedule = readString(rawConfig.reviewerSchedule) ?? readString(cron?.reviewerSchedule);
441
+ const rawScheduleBundleId = rawConfig.scheduleBundleId;
442
+ if (typeof rawScheduleBundleId === "string") {
443
+ const trimmed = rawScheduleBundleId.trim();
444
+ normalized.scheduleBundleId = trimmed.length > 0 ? trimmed : null;
445
+ } else if (rawScheduleBundleId === null) {
446
+ normalized.scheduleBundleId = null;
447
+ }
214
448
  normalized.cronScheduleOffset = readNumber(rawConfig.cronScheduleOffset);
215
449
  normalized.maxRetries = readNumber(rawConfig.maxRetries);
216
450
  normalized.reviewerMaxRetries = readNumber(rawConfig.reviewerMaxRetries);
@@ -725,8 +959,6 @@ var init_config = __esm({
725
959
  init_constants();
726
960
  }
727
961
  });
728
-
729
- // ../core/dist/board/types.js
730
962
  var BOARD_COLUMNS;
731
963
  var init_types2 = __esm({
732
964
  "../core/dist/board/types.js"() {
@@ -734,9 +966,9 @@ var init_types2 = __esm({
734
966
  BOARD_COLUMNS = ["Draft", "Ready", "In Progress", "Review", "Done"];
735
967
  }
736
968
  });
737
-
738
- // ../core/dist/storage/repositories/sqlite/agent-persona.defaults.js
739
- var GITHUB_RAW_BASE, DEFAULT_AVATAR_URLS, DEFAULT_PERSONAS;
969
+ var GITHUB_RAW_BASE;
970
+ var DEFAULT_AVATAR_URLS;
971
+ var DEFAULT_PERSONAS;
740
972
  var init_agent_persona_defaults = __esm({
741
973
  "../core/dist/storage/repositories/sqlite/agent-persona.defaults.js"() {
742
974
  "use strict";
@@ -1310,11 +1542,6 @@ var init_agent_persona_defaults = __esm({
1310
1542
  ];
1311
1543
  }
1312
1544
  });
1313
-
1314
- // ../core/dist/storage/repositories/sqlite/agent-persona.repository.js
1315
- import Database from "better-sqlite3";
1316
- import { inject, injectable } from "tsyringe";
1317
- import { createCipheriv, createDecipheriv, randomBytes, randomUUID } from "crypto";
1318
1545
  function defaultSoul() {
1319
1546
  return {
1320
1547
  whoIAm: "",
@@ -1392,7 +1619,12 @@ function rowToPersona(row, modelConfig) {
1392
1619
  updatedAt: row.updated_at
1393
1620
  };
1394
1621
  }
1395
- var __decorate, __metadata, __param, ENV_KEY_META_KEY, ENV_SEEDED_META_KEY, SqliteAgentPersonaRepository;
1622
+ var __decorate;
1623
+ var __metadata;
1624
+ var __param;
1625
+ var ENV_KEY_META_KEY;
1626
+ var ENV_SEEDED_META_KEY;
1627
+ var SqliteAgentPersonaRepository;
1396
1628
  var init_agent_persona_repository = __esm({
1397
1629
  "../core/dist/storage/repositories/sqlite/agent-persona.repository.js"() {
1398
1630
  "use strict";
@@ -1585,11 +1817,10 @@ var init_agent_persona_repository = __esm({
1585
1817
  ], SqliteAgentPersonaRepository);
1586
1818
  }
1587
1819
  });
1588
-
1589
- // ../core/dist/storage/repositories/sqlite/execution-history.repository.js
1590
- import Database2 from "better-sqlite3";
1591
- import { inject as inject2, injectable as injectable2 } from "tsyringe";
1592
- var __decorate2, __metadata2, __param2, SqliteExecutionHistoryRepository;
1820
+ var __decorate2;
1821
+ var __metadata2;
1822
+ var __param2;
1823
+ var SqliteExecutionHistoryRepository;
1593
1824
  var init_execution_history_repository = __esm({
1594
1825
  "../core/dist/storage/repositories/sqlite/execution-history.repository.js"() {
1595
1826
  "use strict";
@@ -1691,10 +1922,6 @@ var init_execution_history_repository = __esm({
1691
1922
  ], SqliteExecutionHistoryRepository);
1692
1923
  }
1693
1924
  });
1694
-
1695
- // ../core/dist/storage/repositories/sqlite/kanban-issue.repository.js
1696
- import Database3 from "better-sqlite3";
1697
- import { inject as inject3, injectable as injectable3 } from "tsyringe";
1698
1925
  function rowToIssue(row) {
1699
1926
  return {
1700
1927
  number: row.number,
@@ -1708,7 +1935,10 @@ function rowToIssue(row) {
1708
1935
  updatedAt: row.updated_at
1709
1936
  };
1710
1937
  }
1711
- var __decorate3, __metadata3, __param3, SqliteKanbanIssueRepository;
1938
+ var __decorate3;
1939
+ var __metadata3;
1940
+ var __param3;
1941
+ var SqliteKanbanIssueRepository;
1712
1942
  var init_kanban_issue_repository = __esm({
1713
1943
  "../core/dist/storage/repositories/sqlite/kanban-issue.repository.js"() {
1714
1944
  "use strict";
@@ -1775,11 +2005,10 @@ var init_kanban_issue_repository = __esm({
1775
2005
  ], SqliteKanbanIssueRepository);
1776
2006
  }
1777
2007
  });
1778
-
1779
- // ../core/dist/storage/repositories/sqlite/prd-state.repository.js
1780
- import Database4 from "better-sqlite3";
1781
- import { inject as inject4, injectable as injectable4 } from "tsyringe";
1782
- var __decorate4, __metadata4, __param4, SqlitePrdStateRepository;
2008
+ var __decorate4;
2009
+ var __metadata4;
2010
+ var __param4;
2011
+ var SqlitePrdStateRepository;
1783
2012
  var init_prd_state_repository = __esm({
1784
2013
  "../core/dist/storage/repositories/sqlite/prd-state.repository.js"() {
1785
2014
  "use strict";
@@ -1863,11 +2092,10 @@ var init_prd_state_repository = __esm({
1863
2092
  ], SqlitePrdStateRepository);
1864
2093
  }
1865
2094
  });
1866
-
1867
- // ../core/dist/storage/repositories/sqlite/project-registry.repository.js
1868
- import Database5 from "better-sqlite3";
1869
- import { inject as inject5, injectable as injectable5 } from "tsyringe";
1870
- var __decorate5, __metadata5, __param5, SqliteProjectRegistryRepository;
2095
+ var __decorate5;
2096
+ var __metadata5;
2097
+ var __param5;
2098
+ var SqliteProjectRegistryRepository;
1871
2099
  var init_project_registry_repository = __esm({
1872
2100
  "../core/dist/storage/repositories/sqlite/project-registry.repository.js"() {
1873
2101
  "use strict";
@@ -1918,11 +2146,10 @@ var init_project_registry_repository = __esm({
1918
2146
  ], SqliteProjectRegistryRepository);
1919
2147
  }
1920
2148
  });
1921
-
1922
- // ../core/dist/storage/repositories/sqlite/roadmap-state.repository.js
1923
- import Database6 from "better-sqlite3";
1924
- import { inject as inject6, injectable as injectable6 } from "tsyringe";
1925
- var __decorate6, __metadata6, __param6, SqliteRoadmapStateRepository;
2149
+ var __decorate6;
2150
+ var __metadata6;
2151
+ var __param6;
2152
+ var SqliteRoadmapStateRepository;
1926
2153
  var init_roadmap_state_repository = __esm({
1927
2154
  "../core/dist/storage/repositories/sqlite/roadmap-state.repository.js"() {
1928
2155
  "use strict";
@@ -1984,12 +2211,6 @@ var init_roadmap_state_repository = __esm({
1984
2211
  ], SqliteRoadmapStateRepository);
1985
2212
  }
1986
2213
  });
1987
-
1988
- // ../core/dist/storage/sqlite/client.js
1989
- import * as fs2 from "fs";
1990
- import * as os from "os";
1991
- import * as path2 from "path";
1992
- import Database7 from "better-sqlite3";
1993
2214
  function getDbPath() {
1994
2215
  const base = process.env.NIGHT_WATCH_HOME || path2.join(os.homedir(), GLOBAL_CONFIG_DIR);
1995
2216
  return path2.join(base, STATE_DB_FILE_NAME);
@@ -2028,8 +2249,6 @@ var init_client = __esm({
2028
2249
  _db = null;
2029
2250
  }
2030
2251
  });
2031
-
2032
- // ../core/dist/storage/sqlite/migrations.js
2033
2252
  function runMigrations(db) {
2034
2253
  db.exec(`
2035
2254
  CREATE TABLE IF NOT EXISTS projects (
@@ -2134,10 +2353,6 @@ var init_migrations = __esm({
2134
2353
  SCHEMA_VERSION = "1";
2135
2354
  }
2136
2355
  });
2137
-
2138
- // ../core/dist/di/container.js
2139
- import "reflect-metadata";
2140
- import { container } from "tsyringe";
2141
2356
  function initContainer(projectDir) {
2142
2357
  if (container.isRegistered(DATABASE_TOKEN)) {
2143
2358
  return;
@@ -2170,10 +2385,6 @@ var init_container = __esm({
2170
2385
  DATABASE_TOKEN = "Database";
2171
2386
  }
2172
2387
  });
2173
-
2174
- // ../core/dist/board/providers/github-graphql.js
2175
- import { execFile } from "child_process";
2176
- import { promisify } from "util";
2177
2388
  async function graphql(query, variables, cwd) {
2178
2389
  const args = ["api", "graphql", "-f", `query=${query}`];
2179
2390
  for (const [key, value] of Object.entries(variables)) {
@@ -2208,11 +2419,8 @@ var init_github_graphql = __esm({
2208
2419
  execFileAsync = promisify(execFile);
2209
2420
  }
2210
2421
  });
2211
-
2212
- // ../core/dist/board/providers/github-projects.js
2213
- import { execFile as execFile2 } from "child_process";
2214
- import { promisify as promisify2 } from "util";
2215
- var execFileAsync2, GitHubProjectsProvider;
2422
+ var execFileAsync2;
2423
+ var GitHubProjectsProvider;
2216
2424
  var init_github_projects = __esm({
2217
2425
  "../core/dist/board/providers/github-projects.js"() {
2218
2426
  "use strict";
@@ -2908,8 +3116,6 @@ var init_github_projects = __esm({
2908
3116
  };
2909
3117
  }
2910
3118
  });
2911
-
2912
- // ../core/dist/board/providers/local-kanban.js
2913
3119
  function toIBoardIssue(row) {
2914
3120
  return {
2915
3121
  id: String(row.number),
@@ -2973,8 +3179,6 @@ var init_local_kanban = __esm({
2973
3179
  };
2974
3180
  }
2975
3181
  });
2976
-
2977
- // ../core/dist/board/factory.js
2978
3182
  function createBoardProvider(config, cwd) {
2979
3183
  switch (config.provider) {
2980
3184
  case "github":
@@ -2996,8 +3200,6 @@ var init_factory = __esm({
2996
3200
  init_local_kanban();
2997
3201
  }
2998
3202
  });
2999
-
3000
- // ../core/dist/board/labels.js
3001
3203
  function isValidPriority(value) {
3002
3204
  return PRIORITY_LABELS.includes(value);
3003
3205
  }
@@ -3047,7 +3249,14 @@ function sortByPriority(issues) {
3047
3249
  return aOrder - bOrder;
3048
3250
  });
3049
3251
  }
3050
- var PRIORITY_LABELS, PRIORITY_LABEL_INFO, CATEGORY_LABELS, CATEGORY_LABEL_INFO, HORIZON_LABELS, HORIZON_LABEL_INFO, PRIORITY_COLORS, NIGHT_WATCH_LABELS;
3252
+ var PRIORITY_LABELS;
3253
+ var PRIORITY_LABEL_INFO;
3254
+ var CATEGORY_LABELS;
3255
+ var CATEGORY_LABEL_INFO;
3256
+ var HORIZON_LABELS;
3257
+ var HORIZON_LABEL_INFO;
3258
+ var PRIORITY_COLORS;
3259
+ var NIGHT_WATCH_LABELS;
3051
3260
  var init_labels = __esm({
3052
3261
  "../core/dist/board/labels.js"() {
3053
3262
  "use strict";
@@ -3148,8 +3357,6 @@ var init_labels = __esm({
3148
3357
  ];
3149
3358
  }
3150
3359
  });
3151
-
3152
- // ../core/dist/board/roadmap-mapping.js
3153
3360
  function getLabelsForSection(sectionName) {
3154
3361
  for (const mapping of ROADMAP_SECTION_MAPPINGS) {
3155
3362
  if (mapping.sectionPattern.test(sectionName)) {
@@ -3197,7 +3404,10 @@ function findMatchingIssue(targetTitle, issues, threshold = 0.8) {
3197
3404
  }
3198
3405
  return bestMatch;
3199
3406
  }
3200
- var HORIZON_SHORT_TERM, HORIZON_MEDIUM_TERM, HORIZON_LONG_TERM, ROADMAP_SECTION_MAPPINGS;
3407
+ var HORIZON_SHORT_TERM;
3408
+ var HORIZON_MEDIUM_TERM;
3409
+ var HORIZON_LONG_TERM;
3410
+ var ROADMAP_SECTION_MAPPINGS;
3201
3411
  var init_roadmap_mapping = __esm({
3202
3412
  "../core/dist/board/roadmap-mapping.js"() {
3203
3413
  "use strict";
@@ -3299,15 +3509,11 @@ var init_roadmap_mapping = __esm({
3299
3509
  ];
3300
3510
  }
3301
3511
  });
3302
-
3303
- // ../core/dist/storage/repositories/interfaces.js
3304
3512
  var init_interfaces = __esm({
3305
3513
  "../core/dist/storage/repositories/interfaces.js"() {
3306
3514
  "use strict";
3307
3515
  }
3308
3516
  });
3309
-
3310
- // ../core/dist/storage/repositories/index.js
3311
3517
  function getRepositories() {
3312
3518
  if (isContainerInitialized()) {
3313
3519
  return {
@@ -3352,10 +3558,6 @@ var init_repositories = __esm({
3352
3558
  _initialized = false;
3353
3559
  }
3354
3560
  });
3355
-
3356
- // ../core/dist/storage/json-state-migrator.js
3357
- import * as fs3 from "fs";
3358
- import * as path3 from "path";
3359
3561
  function tryReadJson(filePath) {
3360
3562
  if (!fs3.existsSync(filePath)) {
3361
3563
  return null;
@@ -3504,8 +3706,6 @@ var init_json_state_migrator = __esm({
3504
3706
  init_repositories();
3505
3707
  }
3506
3708
  });
3507
-
3508
- // ../core/dist/agents/soul-compiler.js
3509
3709
  function compileSoul(persona, memory) {
3510
3710
  if (persona.systemPromptOverride) {
3511
3711
  return persona.systemPromptOverride;
@@ -3639,7 +3839,8 @@ function compileSoul(persona, memory) {
3639
3839
  }
3640
3840
  return lines.join("\n");
3641
3841
  }
3642
- var AIISH_WORDS_TO_AVOID, CANNED_CHATBOT_PHRASES;
3842
+ var AIISH_WORDS_TO_AVOID;
3843
+ var CANNED_CHATBOT_PHRASES;
3643
3844
  var init_soul_compiler = __esm({
3644
3845
  "../core/dist/agents/soul-compiler.js"() {
3645
3846
  "use strict";
@@ -3664,8 +3865,6 @@ var init_soul_compiler = __esm({
3664
3865
  ];
3665
3866
  }
3666
3867
  });
3667
-
3668
- // ../core/dist/utils/avatar-generator.js
3669
3868
  function extractOutputUrl(output) {
3670
3869
  if (!output)
3671
3870
  return null;
@@ -3746,7 +3945,10 @@ async function generatePersonaAvatar(personaName, personaRole, apiToken) {
3746
3945
  }
3747
3946
  throw new Error("Replicate avatar generation timed out after 3 minutes");
3748
3947
  }
3749
- var REPLICATE_MODEL, POLL_INTERVAL_MS, MAX_POLLS, PERSONA_PORTRAITS;
3948
+ var REPLICATE_MODEL;
3949
+ var POLL_INTERVAL_MS;
3950
+ var MAX_POLLS;
3951
+ var PERSONA_PORTRAITS;
3750
3952
  var init_avatar_generator = __esm({
3751
3953
  "../core/dist/utils/avatar-generator.js"() {
3752
3954
  "use strict";
@@ -3781,8 +3983,6 @@ var init_avatar_generator = __esm({
3781
3983
  };
3782
3984
  }
3783
3985
  });
3784
-
3785
- // ../core/dist/utils/logger.js
3786
3986
  function colorize(color, text) {
3787
3987
  return NO_COLOR ? text : `${color}${text}${ANSI.reset}`;
3788
3988
  }
@@ -3802,7 +4002,10 @@ function formatMeta(meta) {
3802
4002
  function createLogger(context) {
3803
4003
  return new Logger(context);
3804
4004
  }
3805
- var ANSI, NO_COLOR, LEVEL_STYLES, Logger;
4005
+ var ANSI;
4006
+ var NO_COLOR;
4007
+ var LEVEL_STYLES;
4008
+ var Logger;
3806
4009
  var init_logger = __esm({
3807
4010
  "../core/dist/utils/logger.js"() {
3808
4011
  "use strict";
@@ -3859,8 +4062,6 @@ var init_logger = __esm({
3859
4062
  };
3860
4063
  }
3861
4064
  });
3862
-
3863
- // ../core/dist/utils/prd-states.js
3864
4065
  function readPrdStates() {
3865
4066
  const { prdState } = getRepositories();
3866
4067
  return prdState.readAll();
@@ -3887,12 +4088,6 @@ var init_prd_states = __esm({
3887
4088
  init_repositories();
3888
4089
  }
3889
4090
  });
3890
-
3891
- // ../core/dist/utils/crontab.js
3892
- import { execSync } from "child_process";
3893
- import * as fs4 from "fs";
3894
- import * as os2 from "os";
3895
- import * as path4 from "path";
3896
4091
  function isNightWatchEntry(line) {
3897
4092
  if (line.includes(CRONTAB_MARKER_PREFIX)) {
3898
4093
  return true;
@@ -4020,7 +4215,8 @@ function removeEntriesForProject(projectDir, marker) {
4020
4215
  }
4021
4216
  return removedCount;
4022
4217
  }
4023
- var CRONTAB_MARKER_PREFIX, LEGACY_SCRIPT_NAMES;
4218
+ var CRONTAB_MARKER_PREFIX;
4219
+ var LEGACY_SCRIPT_NAMES;
4024
4220
  var init_crontab = __esm({
4025
4221
  "../core/dist/utils/crontab.js"() {
4026
4222
  "use strict";
@@ -4035,13 +4231,6 @@ var init_crontab = __esm({
4035
4231
  ];
4036
4232
  }
4037
4233
  });
4038
-
4039
- // ../core/dist/utils/status-data.js
4040
- import { createHash } from "crypto";
4041
- import { exec } from "child_process";
4042
- import { promisify as promisify3 } from "util";
4043
- import * as fs5 from "fs";
4044
- import * as path5 from "path";
4045
4234
  function getProjectName(projectDir) {
4046
4235
  const packageJsonPath = path5.join(projectDir, "package.json");
4047
4236
  if (fs5.existsSync(packageJsonPath)) {
@@ -4497,9 +4686,6 @@ var init_status_data = __esm({
4497
4686
  execAsync = promisify3(exec);
4498
4687
  }
4499
4688
  });
4500
-
4501
- // ../core/dist/utils/cancel.js
4502
- import * as fs6 from "fs";
4503
4689
  function getLockFilePaths(projectDir) {
4504
4690
  const runtimeKey = projectRuntimeKey(projectDir);
4505
4691
  return {
@@ -4606,11 +4792,6 @@ var init_cancel = __esm({
4606
4792
  init_status_data();
4607
4793
  }
4608
4794
  });
4609
-
4610
- // ../core/dist/utils/checks.js
4611
- import * as fs7 from "fs";
4612
- import * as path6 from "path";
4613
- import { execSync as execSync2 } from "child_process";
4614
4795
  function checkGitRepo(cwd) {
4615
4796
  const isRepo = fs7.existsSync(path6.join(cwd, ".git"));
4616
4797
  return {
@@ -4801,11 +4982,6 @@ var init_checks = __esm({
4801
4982
  init_constants();
4802
4983
  }
4803
4984
  });
4804
-
4805
- // ../core/dist/utils/claim-manager.js
4806
- import * as os3 from "os";
4807
- import * as path7 from "path";
4808
- import * as fs8 from "fs";
4809
4985
  function claimPrd(prdDir, prdFile, pid) {
4810
4986
  const claimPath = path7.join(prdDir, prdFile + CLAIM_FILE_EXTENSION);
4811
4987
  const claimData = {
@@ -4884,10 +5060,9 @@ var init_claim_manager = __esm({
4884
5060
  init_constants();
4885
5061
  }
4886
5062
  });
4887
-
4888
- // ../core/dist/utils/config-writer.js
4889
- import * as fs9 from "fs";
4890
- import * as path8 from "path";
5063
+ function isPlainObject(value) {
5064
+ return value !== null && typeof value === "object" && !Array.isArray(value);
5065
+ }
4891
5066
  function saveConfig(projectDir, changes) {
4892
5067
  const configPath = path8.join(projectDir, CONFIG_FILE_NAME);
4893
5068
  try {
@@ -4899,8 +5074,8 @@ function saveConfig(projectDir, changes) {
4899
5074
  const merged = { ...existing };
4900
5075
  for (const [key, value] of Object.entries(changes)) {
4901
5076
  if (value !== void 0) {
4902
- if (key === "notifications" && existing.notifications && typeof existing.notifications === "object") {
4903
- merged.notifications = { ...existing.notifications, ...value };
5077
+ if (PARTIAL_MERGE_KEYS.has(key) && isPlainObject(existing[key]) && isPlainObject(value)) {
5078
+ merged[key] = { ...existing[key], ...value };
4904
5079
  } else {
4905
5080
  merged[key] = value;
4906
5081
  }
@@ -4915,16 +5090,14 @@ function saveConfig(projectDir, changes) {
4915
5090
  };
4916
5091
  }
4917
5092
  }
5093
+ var PARTIAL_MERGE_KEYS;
4918
5094
  var init_config_writer = __esm({
4919
5095
  "../core/dist/utils/config-writer.js"() {
4920
5096
  "use strict";
4921
5097
  init_constants();
5098
+ PARTIAL_MERGE_KEYS = /* @__PURE__ */ new Set(["notifications", "qa", "audit", "roadmapScanner"]);
4922
5099
  }
4923
5100
  });
4924
-
4925
- // ../core/dist/utils/execution-history.js
4926
- import * as os4 from "os";
4927
- import * as path9 from "path";
4928
5101
  function getHistoryPath() {
4929
5102
  const base = process.env.NIGHT_WATCH_HOME || path9.join(os4.homedir(), GLOBAL_CONFIG_DIR);
4930
5103
  return path9.join(base, HISTORY_FILE_NAME);
@@ -4975,9 +5148,6 @@ var init_execution_history = __esm({
4975
5148
  init_client();
4976
5149
  }
4977
5150
  });
4978
-
4979
- // ../core/dist/utils/git-utils.js
4980
- import { execFileSync } from "child_process";
4981
5151
  function getBranchTipTimestamp(projectDir, branch) {
4982
5152
  let remoteTs = null;
4983
5153
  let localTs = null;
@@ -5066,9 +5236,6 @@ var init_git_utils = __esm({
5066
5236
  "use strict";
5067
5237
  }
5068
5238
  });
5069
-
5070
- // ../core/dist/utils/github.js
5071
- import { execFileSync as execFileSync2 } from "child_process";
5072
5239
  function parsePrDetails(raw) {
5073
5240
  try {
5074
5241
  const details = JSON.parse(raw);
@@ -5241,7 +5408,8 @@ function extractSummary(body, maxLength = 500) {
5241
5408
  const lastSpace = truncated.lastIndexOf(" ");
5242
5409
  return (lastSpace > 0 ? truncated.slice(0, lastSpace) : truncated) + "...";
5243
5410
  }
5244
- var QA_COMMENT_MARKER, QA_SCREENSHOT_REGEX;
5411
+ var QA_COMMENT_MARKER;
5412
+ var QA_SCREENSHOT_REGEX;
5245
5413
  var init_github = __esm({
5246
5414
  "../core/dist/utils/github.js"() {
5247
5415
  "use strict";
@@ -5249,9 +5417,6 @@ var init_github = __esm({
5249
5417
  QA_SCREENSHOT_REGEX = /!\[[^\]]*]\(([^)\n]*qa-artifacts\/[^)\n]+)\)/g;
5250
5418
  }
5251
5419
  });
5252
-
5253
- // ../core/dist/utils/log-utils.js
5254
- import * as fs10 from "fs";
5255
5420
  function rotateLog(logFile, maxSize = DEFAULT_MAX_LOG_SIZE) {
5256
5421
  if (!fs10.existsSync(logFile)) {
5257
5422
  return false;
@@ -5291,11 +5456,6 @@ var init_log_utils = __esm({
5291
5456
  init_constants();
5292
5457
  }
5293
5458
  });
5294
-
5295
- // ../core/dist/utils/ui.js
5296
- import chalk from "chalk";
5297
- import ora from "ora";
5298
- import Table from "cli-table3";
5299
5459
  function success(msg) {
5300
5460
  console.log(chalk.green("\u2714"), msg);
5301
5461
  }
@@ -5378,8 +5538,6 @@ var init_ui = __esm({
5378
5538
  "use strict";
5379
5539
  }
5380
5540
  });
5381
-
5382
- // ../core/dist/utils/notify.js
5383
5541
  function getEventEmoji(event) {
5384
5542
  switch (event) {
5385
5543
  case "run_started":
@@ -5656,11 +5814,6 @@ var init_notify = __esm({
5656
5814
  MAX_QA_SCREENSHOTS_IN_NOTIFICATION = 3;
5657
5815
  }
5658
5816
  });
5659
-
5660
- // ../core/dist/utils/prd-discovery.js
5661
- import { execFileSync as execFileSync3 } from "child_process";
5662
- import * as fs11 from "fs";
5663
- import * as path10 from "path";
5664
5817
  function getOpenBranches(projectDir) {
5665
5818
  try {
5666
5819
  const output = execFileSync3("gh", ["pr", "list", "--state", "open", "--json", "headRefName", "--jq", ".[].headRefName"], { cwd: projectDir, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
@@ -5766,10 +5919,6 @@ var init_prd_discovery = __esm({
5766
5919
  init_status_data();
5767
5920
  }
5768
5921
  });
5769
-
5770
- // ../core/dist/utils/prd-utils.js
5771
- import * as fs12 from "fs";
5772
- import * as path11 from "path";
5773
5922
  function slugify(name) {
5774
5923
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
5775
5924
  }
@@ -5801,11 +5950,6 @@ var init_prd_utils = __esm({
5801
5950
  "use strict";
5802
5951
  }
5803
5952
  });
5804
-
5805
- // ../core/dist/utils/registry.js
5806
- import * as fs13 from "fs";
5807
- import * as os5 from "os";
5808
- import * as path12 from "path";
5809
5953
  function getRegistryPath() {
5810
5954
  const base = process.env.NIGHT_WATCH_HOME || path12.join(os5.homedir(), GLOBAL_CONFIG_DIR);
5811
5955
  return path12.join(base, REGISTRY_FILE_NAME);
@@ -5863,8 +6007,6 @@ var init_registry = __esm({
5863
6007
  init_status_data();
5864
6008
  }
5865
6009
  });
5866
-
5867
- // ../core/dist/utils/roadmap-context-compiler.js
5868
6010
  function isLeadRole(role) {
5869
6011
  const lower = role.toLowerCase();
5870
6012
  return LEAD_KEYWORDS.some((kw) => lower.includes(kw));
@@ -5933,7 +6075,10 @@ function buildSmartProgress(status) {
5933
6075
  }
5934
6076
  return result;
5935
6077
  }
5936
- var RAW_CONTENT_MAX, PROGRESS_MAX_FULL, PROGRESS_MAX_SUMMARY, LEAD_KEYWORDS;
6078
+ var RAW_CONTENT_MAX;
6079
+ var PROGRESS_MAX_FULL;
6080
+ var PROGRESS_MAX_SUMMARY;
6081
+ var LEAD_KEYWORDS;
5937
6082
  var init_roadmap_context_compiler = __esm({
5938
6083
  "../core/dist/utils/roadmap-context-compiler.js"() {
5939
6084
  "use strict";
@@ -5943,9 +6088,6 @@ var init_roadmap_context_compiler = __esm({
5943
6088
  LEAD_KEYWORDS = ["lead", "architect", "product", "manager", "pm", "director"];
5944
6089
  }
5945
6090
  });
5946
-
5947
- // ../core/dist/utils/roadmap-parser.js
5948
- import * as crypto from "crypto";
5949
6091
  function generateItemHash(title) {
5950
6092
  const normalizedTitle = title.toLowerCase().trim();
5951
6093
  return crypto.createHash("sha256").update(normalizedTitle).digest("hex").slice(0, 8);
@@ -6040,10 +6182,6 @@ var init_roadmap_parser = __esm({
6040
6182
  "use strict";
6041
6183
  }
6042
6184
  });
6043
-
6044
- // ../core/dist/utils/roadmap-state.js
6045
- import * as fs14 from "fs";
6046
- import * as path13 from "path";
6047
6185
  function getStateFilePath(prdDir) {
6048
6186
  return path13.join(prdDir, STATE_FILE_NAME);
6049
6187
  }
@@ -6124,7 +6262,8 @@ function getProcessedHashes(state) {
6124
6262
  function getStateItem(state, hash) {
6125
6263
  return state.items[hash];
6126
6264
  }
6127
- var STATE_VERSION, STATE_FILE_NAME;
6265
+ var STATE_VERSION;
6266
+ var STATE_FILE_NAME;
6128
6267
  var init_roadmap_state = __esm({
6129
6268
  "../core/dist/utils/roadmap-state.js"() {
6130
6269
  "use strict";
@@ -6133,10 +6272,6 @@ var init_roadmap_state = __esm({
6133
6272
  STATE_FILE_NAME = ".roadmap-state.json";
6134
6273
  }
6135
6274
  });
6136
-
6137
- // ../core/dist/templates/slicer-prompt.js
6138
- import * as fs15 from "fs";
6139
- import * as path14 from "path";
6140
6275
  function loadSlicerTemplate(templateDir) {
6141
6276
  if (cachedTemplate) {
6142
6277
  return cachedTemplate;
@@ -6172,7 +6307,8 @@ function createSlicerPromptVars(title, section, description, prdDir, prdFilename
6172
6307
  prdDir
6173
6308
  };
6174
6309
  }
6175
- var DEFAULT_SLICER_TEMPLATE, cachedTemplate;
6310
+ var DEFAULT_SLICER_TEMPLATE;
6311
+ var cachedTemplate;
6176
6312
  var init_slicer_prompt = __esm({
6177
6313
  "../core/dist/templates/slicer-prompt.js"() {
6178
6314
  "use strict";
@@ -6260,12 +6396,6 @@ DO NOT forget to write the file.
6260
6396
  cachedTemplate = null;
6261
6397
  }
6262
6398
  });
6263
-
6264
- // ../core/dist/utils/roadmap-scanner.js
6265
- import * as fs16 from "fs";
6266
- import * as path15 from "path";
6267
- import { spawn } from "child_process";
6268
- import { createHash as createHash3 } from "crypto";
6269
6399
  function normalizeAuditSeverity(raw) {
6270
6400
  const normalized = raw.trim().toLowerCase();
6271
6401
  if (normalized === "critical")
@@ -6631,8 +6761,6 @@ var init_roadmap_scanner = __esm({
6631
6761
  init_slicer_prompt();
6632
6762
  }
6633
6763
  });
6634
-
6635
- // ../core/dist/utils/script-result.js
6636
6764
  function parseScriptResult(output) {
6637
6765
  if (!output || output.trim().length === 0) {
6638
6766
  return null;
@@ -6677,9 +6805,6 @@ var init_script_result = __esm({
6677
6805
  RESULT_PREFIX = "NIGHT_WATCH_RESULT:";
6678
6806
  }
6679
6807
  });
6680
-
6681
- // ../core/dist/utils/shell.js
6682
- import { spawn as spawn2 } from "child_process";
6683
6808
  async function executeScript(scriptPath, args = [], env = {}, options = {}) {
6684
6809
  const result = await executeScriptWithOutput(scriptPath, args, env, options);
6685
6810
  return result.exitCode;
@@ -6724,8 +6849,6 @@ var init_shell = __esm({
6724
6849
  "use strict";
6725
6850
  }
6726
6851
  });
6727
-
6728
- // ../core/dist/utils/webhook-validator.js
6729
6852
  function validateWebhook(webhook) {
6730
6853
  const issues = [];
6731
6854
  if (!webhook.events || webhook.events.length === 0) {
@@ -6780,11 +6903,6 @@ var init_webhook_validator = __esm({
6780
6903
  "use strict";
6781
6904
  }
6782
6905
  });
6783
-
6784
- // ../core/dist/utils/worktree-manager.js
6785
- import { execFileSync as execFileSync4 } from "child_process";
6786
- import * as fs17 from "fs";
6787
- import * as path16 from "path";
6788
6906
  function gitExec(args, cwd, logFile) {
6789
6907
  try {
6790
6908
  const result = execFileSync4("git", args, {
@@ -6941,8 +7059,6 @@ var init_worktree_manager = __esm({
6941
7059
  init_git_utils();
6942
7060
  }
6943
7061
  });
6944
-
6945
- // ../core/dist/templates/prd-template.js
6946
7062
  function renderDependsOn(deps) {
6947
7063
  if (deps.length === 0) {
6948
7064
  return "";
@@ -7114,8 +7230,6 @@ sequenceDiagram
7114
7230
  `;
7115
7231
  }
7116
7232
  });
7117
-
7118
- // ../core/dist/index.js
7119
7233
  var dist_exports = {};
7120
7234
  __export(dist_exports, {
7121
7235
  AUDIT_LOG_NAME: () => AUDIT_LOG_NAME,
@@ -7419,22 +7533,7 @@ var init_dist = __esm({
7419
7533
  init_slicer_prompt();
7420
7534
  }
7421
7535
  });
7422
-
7423
- // dist/cli.js
7424
- import "reflect-metadata";
7425
- import { Command as Command2 } from "commander";
7426
- import { existsSync as existsSync30, readFileSync as readFileSync18 } from "fs";
7427
- import { fileURLToPath as fileURLToPath4 } from "url";
7428
- import { dirname as dirname8, join as join34 } from "path";
7429
-
7430
- // dist/commands/init.js
7431
7536
  init_dist();
7432
- import fs18 from "fs";
7433
- import path17 from "path";
7434
- import { execSync as execSync3 } from "child_process";
7435
- import { fileURLToPath as fileURLToPath2 } from "url";
7436
- import { dirname as dirname4, join as join16 } from "path";
7437
- import * as readline from "readline";
7438
7537
  var __filename = fileURLToPath2(import.meta.url);
7439
7538
  var __dirname2 = dirname4(__filename);
7440
7539
  function findTemplatesDir(startDir) {
@@ -7867,11 +7966,7 @@ function initCommand(program2) {
7867
7966
  console.log();
7868
7967
  });
7869
7968
  }
7870
-
7871
- // dist/commands/run.js
7872
7969
  init_dist();
7873
-
7874
- // dist/commands/shared/env-builder.js
7875
7970
  init_dist();
7876
7971
  function deriveProviderLabel(config, jobType) {
7877
7972
  if (config.providerLabel)
@@ -7913,10 +8008,6 @@ function formatProviderDisplay(providerCmd, providerLabel) {
7913
8008
  function getTelegramStatusWebhooks(config) {
7914
8009
  return (config.notifications?.webhooks ?? []).filter((wh) => wh.type === "telegram" && typeof wh.botToken === "string" && wh.botToken.trim().length > 0 && typeof wh.chatId === "string" && wh.chatId.trim().length > 0).map((wh) => ({ botToken: wh.botToken, chatId: wh.chatId }));
7915
8010
  }
7916
-
7917
- // dist/commands/run.js
7918
- import * as fs19 from "fs";
7919
- import * as path18 from "path";
7920
8011
  function resolveRunNotificationEvent(exitCode, scriptStatus) {
7921
8012
  if (exitCode === 124) {
7922
8013
  return "run_timeout";
@@ -8247,11 +8338,7 @@ ${stderr}`);
8247
8338
  }
8248
8339
  });
8249
8340
  }
8250
-
8251
- // dist/commands/review.js
8252
8341
  init_dist();
8253
- import { execFileSync as execFileSync5 } from "child_process";
8254
- import * as path19 from "path";
8255
8342
  function shouldSendReviewNotification(scriptStatus) {
8256
8343
  if (!scriptStatus) {
8257
8344
  return true;
@@ -8512,10 +8599,7 @@ ${stderr}`);
8512
8599
  }
8513
8600
  });
8514
8601
  }
8515
-
8516
- // dist/commands/qa.js
8517
8602
  init_dist();
8518
- import * as path20 from "path";
8519
8603
  function shouldSendQaNotification(scriptStatus) {
8520
8604
  if (!scriptStatus) {
8521
8605
  return true;
@@ -8666,11 +8750,7 @@ ${stderr}`);
8666
8750
  }
8667
8751
  });
8668
8752
  }
8669
-
8670
- // dist/commands/audit.js
8671
8753
  init_dist();
8672
- import * as fs20 from "fs";
8673
- import * as path21 from "path";
8674
8754
  function buildEnvVars4(config, options) {
8675
8755
  const env = buildBaseEnvVars(config, "audit", options.dryRun);
8676
8756
  env.NW_AUDIT_MAX_RUNTIME = String(config.audit.maxRuntime);
@@ -8766,12 +8846,7 @@ ${stderr}`);
8766
8846
  }
8767
8847
  });
8768
8848
  }
8769
-
8770
- // dist/commands/install.js
8771
8849
  init_dist();
8772
- import { execSync as execSync4 } from "child_process";
8773
- import * as path22 from "path";
8774
- import * as fs21 from "fs";
8775
8850
  function shellQuote(value) {
8776
8851
  return `'${value.replace(/'/g, `'"'"'`)}'`;
8777
8852
  }
@@ -8833,11 +8908,11 @@ function performInstall(projectDir, config, options) {
8833
8908
  const executorLog = path22.join(logDir, "executor.log");
8834
8909
  const reviewerLog = path22.join(logDir, "reviewer.log");
8835
8910
  if (!options?.force) {
8836
- const existingEntries = Array.from(/* @__PURE__ */ new Set([...getEntries(marker), ...getProjectEntries(projectDir)]));
8837
- if (existingEntries.length > 0) {
8911
+ const existingEntries2 = Array.from(/* @__PURE__ */ new Set([...getEntries(marker), ...getProjectEntries(projectDir)]));
8912
+ if (existingEntries2.length > 0) {
8838
8913
  return {
8839
8914
  success: false,
8840
- entries: existingEntries,
8915
+ entries: existingEntries2,
8841
8916
  error: "Already installed. Uninstall first or use force."
8842
8917
  };
8843
8918
  }
@@ -8884,8 +8959,10 @@ function performInstall(projectDir, config, options) {
8884
8959
  const auditEntry = `${auditSchedule} ${pathPrefix}${providerEnvPrefix}${cliBinPrefix}cd ${shellQuote(projectDir)} && ${shellQuote(nightWatchBin)} audit >> ${shellQuote(auditLog)} 2>&1 ${marker}`;
8885
8960
  entries.push(auditEntry);
8886
8961
  }
8962
+ const existingEntries = new Set(Array.from(/* @__PURE__ */ new Set([...getEntries(marker), ...getProjectEntries(projectDir)])));
8887
8963
  const currentCrontab = readCrontab();
8888
- const newCrontab = [...currentCrontab, ...entries];
8964
+ const baseCrontab = options?.force ? currentCrontab.filter((line) => !existingEntries.has(line) && !line.includes(marker)) : currentCrontab;
8965
+ const newCrontab = [...baseCrontab, ...entries];
8889
8966
  writeCrontab(newCrontab);
8890
8967
  return { success: true, entries };
8891
8968
  } catch (err) {
@@ -8897,7 +8974,7 @@ function performInstall(projectDir, config, options) {
8897
8974
  }
8898
8975
  }
8899
8976
  function installCommand(program2) {
8900
- program2.command("install").description("Add crontab entries for automated execution").option("-s, --schedule <cron>", "Cron schedule for PRD executor").option("--reviewer-schedule <cron>", "Cron schedule for reviewer").option("--no-reviewer", "Skip installing reviewer cron").option("--no-slicer", "Skip installing slicer cron").option("--no-qa", "Skip installing QA cron").option("--no-audit", "Skip installing audit cron").action(async (options) => {
8977
+ program2.command("install").description("Add crontab entries for automated execution").option("-s, --schedule <cron>", "Cron schedule for PRD executor").option("--reviewer-schedule <cron>", "Cron schedule for reviewer").option("--no-reviewer", "Skip installing reviewer cron").option("--no-slicer", "Skip installing slicer cron").option("--no-qa", "Skip installing QA cron").option("--no-audit", "Skip installing audit cron").option("-f, --force", "Replace existing cron entries for this project").action(async (options) => {
8901
8978
  try {
8902
8979
  const projectDir = process.cwd();
8903
8980
  const config = loadConfig(projectDir);
@@ -8914,13 +8991,13 @@ function installCommand(program2) {
8914
8991
  const executorLog = path22.join(logDir, "executor.log");
8915
8992
  const reviewerLog = path22.join(logDir, "reviewer.log");
8916
8993
  const existingEntries = Array.from(/* @__PURE__ */ new Set([...getEntries(marker), ...getProjectEntries(projectDir)]));
8917
- if (existingEntries.length > 0) {
8994
+ if (existingEntries.length > 0 && !options.force) {
8918
8995
  warn(`Night Watch is already installed for ${projectName}.`);
8919
8996
  console.log();
8920
8997
  dim("Existing crontab entries:");
8921
8998
  existingEntries.forEach((entry) => dim(` ${entry}`));
8922
8999
  console.log();
8923
- dim("Run 'night-watch uninstall' first to reinstall.");
9000
+ dim("Run 'night-watch install --force' to replace them.");
8924
9001
  return;
8925
9002
  }
8926
9003
  const entries = [];
@@ -8968,8 +9045,10 @@ function installCommand(program2) {
8968
9045
  const auditEntry = `${auditSchedule} ${pathPrefix}${providerEnvPrefix}${cliBinPrefix}cd ${shellQuote(projectDir)} && ${shellQuote(nightWatchBin)} audit >> ${shellQuote(auditLog)} 2>&1 ${marker}`;
8969
9046
  entries.push(auditEntry);
8970
9047
  }
9048
+ const existingEntrySet = new Set(existingEntries);
8971
9049
  const currentCrontab = readCrontab();
8972
- const newCrontab = [...currentCrontab, ...entries];
9050
+ const baseCrontab = options.force ? currentCrontab.filter((line) => !existingEntrySet.has(line) && !line.includes(marker)) : currentCrontab;
9051
+ const newCrontab = [...baseCrontab, ...entries];
8973
9052
  writeCrontab(newCrontab);
8974
9053
  success(`Night Watch installed successfully for ${projectName}!`);
8975
9054
  console.log();
@@ -9001,11 +9080,7 @@ function installCommand(program2) {
9001
9080
  }
9002
9081
  });
9003
9082
  }
9004
-
9005
- // dist/commands/uninstall.js
9006
9083
  init_dist();
9007
- import * as path23 from "path";
9008
- import * as fs22 from "fs";
9009
9084
  function performUninstall(projectDir, options) {
9010
9085
  try {
9011
9086
  const projectName = getProjectName(projectDir);
@@ -9093,10 +9168,7 @@ function uninstallCommand(program2) {
9093
9168
  }
9094
9169
  });
9095
9170
  }
9096
-
9097
- // dist/commands/status.js
9098
9171
  init_dist();
9099
- import chalk2 from "chalk";
9100
9172
  function formatBytes(bytes) {
9101
9173
  if (bytes === 0)
9102
9174
  return "0 B";
@@ -9300,12 +9372,7 @@ function statusCommand(program2) {
9300
9372
  }
9301
9373
  });
9302
9374
  }
9303
-
9304
- // dist/commands/logs.js
9305
9375
  init_dist();
9306
- import { spawn as spawn3 } from "child_process";
9307
- import * as path24 from "path";
9308
- import * as fs23 from "fs";
9309
9376
  function getLastLines(filePath, lineCount) {
9310
9377
  if (!fs23.existsSync(filePath)) {
9311
9378
  return `Log file not found: ${filePath}`;
@@ -9410,12 +9477,7 @@ function logsCommand(program2) {
9410
9477
  }
9411
9478
  });
9412
9479
  }
9413
-
9414
- // dist/commands/prd.js
9415
9480
  init_dist();
9416
- import * as fs24 from "fs";
9417
- import * as path25 from "path";
9418
- import * as readline2 from "readline";
9419
9481
  function slugify2(name) {
9420
9482
  return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
9421
9483
  }
@@ -9610,15 +9672,8 @@ function prdCommand(program2) {
9610
9672
  info(`${pendingCount} pending, ${claimedCount} claimed, ${done.length} done`);
9611
9673
  });
9612
9674
  }
9613
-
9614
- // dist/commands/dashboard.js
9615
9675
  init_dist();
9616
- import blessed6 from "blessed";
9617
-
9618
- // dist/commands/dashboard/tab-status.js
9619
9676
  init_dist();
9620
- import blessed from "blessed";
9621
- import * as fs25 from "fs";
9622
9677
  function sortPrdsByPriority2(prds, priority) {
9623
9678
  if (priority.length === 0)
9624
9679
  return prds;
@@ -10004,10 +10059,7 @@ function createStatusTab() {
10004
10059
  }
10005
10060
  };
10006
10061
  }
10007
-
10008
- // dist/commands/dashboard/tab-config.js
10009
10062
  init_dist();
10010
- import blessed2 from "blessed";
10011
10063
  var SENSITIVE_PATTERNS = /TOKEN|KEY|SECRET|PASSWORD/i;
10012
10064
  function promptTextbox(screen, label2, initialValue, cb) {
10013
10065
  const input = blessed2.textbox({
@@ -10826,10 +10878,6 @@ function createConfigTab() {
10826
10878
  }
10827
10879
  };
10828
10880
  }
10829
-
10830
- // dist/commands/dashboard/tab-schedules.js
10831
- import blessed3 from "blessed";
10832
- import cronstrue from "cronstrue";
10833
10881
  init_dist();
10834
10882
  function cronToHuman(cron) {
10835
10883
  const trimmed = cron.trim();
@@ -11126,10 +11174,6 @@ function createSchedulesTab() {
11126
11174
  }
11127
11175
  };
11128
11176
  }
11129
-
11130
- // dist/commands/dashboard/tab-actions.js
11131
- import blessed4 from "blessed";
11132
- import { spawn as spawn4 } from "child_process";
11133
11177
  function spawnAction(args, ctx, outputBox, onDone) {
11134
11178
  outputBox.setContent("{cyan-fg}Starting...{/cyan-fg}\n");
11135
11179
  ctx.screen.render();
@@ -11367,12 +11411,7 @@ function createActionsTab() {
11367
11411
  }
11368
11412
  };
11369
11413
  }
11370
-
11371
- // dist/commands/dashboard/tab-logs.js
11372
11414
  init_dist();
11373
- import blessed5 from "blessed";
11374
- import * as fs26 from "fs";
11375
- import * as path26 from "path";
11376
11415
  var LOG_NAMES = ["executor", "reviewer"];
11377
11416
  var LOG_LINES = 200;
11378
11417
  function createLogsTab() {
@@ -11562,8 +11601,6 @@ Log will appear here once the ${logName} runs.`);
11562
11601
  }
11563
11602
  };
11564
11603
  }
11565
-
11566
- // dist/commands/dashboard.js
11567
11604
  function showMessage(screen, text, type, durationMs = 2e3) {
11568
11605
  const colors = { success: "green", error: "red", info: "cyan" };
11569
11606
  const msgBox = blessed6.box({
@@ -11759,8 +11796,6 @@ function dashboardCommand(program2) {
11759
11796
  screen.render();
11760
11797
  });
11761
11798
  }
11762
-
11763
- // dist/commands/doctor.js
11764
11799
  init_dist();
11765
11800
  function validateWebhook2(webhook) {
11766
11801
  const issues = [];
@@ -11919,27 +11954,12 @@ function doctorCommand(program2) {
11919
11954
  }
11920
11955
  });
11921
11956
  }
11922
-
11923
- // dist/commands/serve.js
11924
11957
  init_dist();
11925
- import * as fs31 from "fs";
11926
-
11927
- // ../server/dist/index.js
11928
11958
  init_dist();
11929
- import * as fs30 from "fs";
11930
- import * as path32 from "path";
11931
- import { dirname as dirname7 } from "path";
11932
- import { fileURLToPath as fileURLToPath3 } from "url";
11933
- import cors from "cors";
11934
- import express from "express";
11935
-
11936
- // ../server/dist/middleware/error-handler.middleware.js
11937
11959
  function errorHandler(err, _req, res, _next) {
11938
11960
  console.error("API Error:", err);
11939
11961
  res.status(500).json({ error: err.message });
11940
11962
  }
11941
-
11942
- // ../server/dist/middleware/graceful-shutdown.middleware.js
11943
11963
  var PRE_SHUTDOWN_TIMEOUT_MS = 5e3;
11944
11964
  var GRACEFUL_SHUTDOWN_TIMEOUT_MS = 12e3;
11945
11965
  function withTimeout(promise, timeoutMs, label2) {
@@ -12009,11 +12029,7 @@ function setupGracefulShutdown(server, beforeClose) {
12009
12029
  process.on("SIGTERM", () => shutdown("SIGTERM"));
12010
12030
  process.on("SIGINT", () => shutdown("SIGINT"));
12011
12031
  }
12012
-
12013
- // ../server/dist/middleware/project-resolver.middleware.js
12014
12032
  init_dist();
12015
- import * as fs27 from "fs";
12016
- import * as path27 from "path";
12017
12033
  function resolveProject(req, res, next) {
12018
12034
  const projectId = req.params.projectId;
12019
12035
  const decodedId = decodeURIComponent(projectId).replace(/~/g, "/");
@@ -12031,8 +12047,6 @@ function resolveProject(req, res, next) {
12031
12047
  req.projectConfig = loadConfig(entry.path);
12032
12048
  next();
12033
12049
  }
12034
-
12035
- // ../server/dist/middleware/sse.middleware.js
12036
12050
  init_dist();
12037
12051
  function broadcastSSE(clients, event, data) {
12038
12052
  const msg = `event: ${event}
@@ -12065,15 +12079,7 @@ function startSseStatusWatcher(clients, projectDir, getConfig) {
12065
12079
  });
12066
12080
  }, 2e3);
12067
12081
  }
12068
-
12069
- // ../server/dist/routes/action.routes.js
12070
12082
  init_dist();
12071
- import * as fs28 from "fs";
12072
- import * as path28 from "path";
12073
- import { execSync as execSync5, spawn as spawn5 } from "child_process";
12074
- import { Router } from "express";
12075
-
12076
- // ../server/dist/helpers.js
12077
12083
  init_dist();
12078
12084
  function validatePrdName(name) {
12079
12085
  return /^[a-zA-Z0-9_-]+(\.md)?$/.test(name) && !name.includes("..");
@@ -12115,8 +12121,6 @@ function getBoardProvider(config, projectDir) {
12115
12121
  }
12116
12122
  return createBoardProvider(config.boardProvider, projectDir);
12117
12123
  }
12118
-
12119
- // ../server/dist/routes/action.routes.js
12120
12124
  function cleanOrphanedClaims(dir) {
12121
12125
  let entries;
12122
12126
  try {
@@ -12239,8 +12243,7 @@ function createActionRouteHandlers(ctx) {
12239
12243
  router.post(`/${p}install-cron`, (req, res) => {
12240
12244
  const projectDir = ctx.getProjectDir(req);
12241
12245
  try {
12242
- runCliCommand(projectDir, ["uninstall", "--keep-logs"]);
12243
- runCliCommand(projectDir, ["install"]);
12246
+ runCliCommand(projectDir, ["install", "--force"]);
12244
12247
  res.json({ started: true });
12245
12248
  } catch (error2) {
12246
12249
  res.status(500).json({ error: formatCommandError(error2) });
@@ -12361,10 +12364,7 @@ function createProjectActionRoutes(deps) {
12361
12364
  pathPrefix: "actions/"
12362
12365
  });
12363
12366
  }
12364
-
12365
- // ../server/dist/routes/agent.routes.js
12366
12367
  init_dist();
12367
- import { Router as Router2 } from "express";
12368
12368
  function createAgentRoutes() {
12369
12369
  const router = Router2();
12370
12370
  router.post("/seed-defaults", (_req, res) => {
@@ -12464,10 +12464,7 @@ function createAgentRoutes() {
12464
12464
  });
12465
12465
  return router;
12466
12466
  }
12467
-
12468
- // ../server/dist/routes/board.routes.js
12469
12467
  init_dist();
12470
- import { Router as Router3 } from "express";
12471
12468
  var ERROR_BOARD_NOT_CONFIGURED = "Board not configured";
12472
12469
  function createBoardRouteHandlers(ctx) {
12473
12470
  const router = Router3({ mergeParams: true });
@@ -12648,10 +12645,27 @@ function createProjectBoardRoutes() {
12648
12645
  pathPrefix: "board/"
12649
12646
  });
12650
12647
  }
12651
-
12652
- // ../server/dist/routes/config.routes.js
12653
12648
  init_dist();
12654
- import { Router as Router4 } from "express";
12649
+ function isValidCronExpression(value) {
12650
+ try {
12651
+ CronExpressionParser.parse(value.trim());
12652
+ return true;
12653
+ } catch {
12654
+ return false;
12655
+ }
12656
+ }
12657
+ function validateCronField(fieldName, value) {
12658
+ if (value === void 0) {
12659
+ return null;
12660
+ }
12661
+ if (typeof value !== "string" || value.trim().length === 0) {
12662
+ return `${fieldName} must be a non-empty string`;
12663
+ }
12664
+ if (!isValidCronExpression(value)) {
12665
+ return `${fieldName} must be a valid cron expression`;
12666
+ }
12667
+ return null;
12668
+ }
12655
12669
  function validateConfigChanges(changes) {
12656
12670
  if (typeof changes !== "object" || changes === null) {
12657
12671
  return "Invalid request body";
@@ -12704,11 +12718,18 @@ function validateConfigChanges(changes) {
12704
12718
  if (changes.prdPriority !== void 0 && (!Array.isArray(changes.prdPriority) || !changes.prdPriority.every((p) => typeof p === "string"))) {
12705
12719
  return "prdPriority must be an array of strings";
12706
12720
  }
12707
- if (changes.cronSchedule !== void 0 && (typeof changes.cronSchedule !== "string" || changes.cronSchedule.trim().length === 0)) {
12708
- return "cronSchedule must be a non-empty string";
12721
+ const rootCronFields = [
12722
+ ["cronSchedule", changes.cronSchedule],
12723
+ ["reviewerSchedule", changes.reviewerSchedule]
12724
+ ];
12725
+ for (const [fieldName, value] of rootCronFields) {
12726
+ const cronError = validateCronField(fieldName, value);
12727
+ if (cronError) {
12728
+ return cronError;
12729
+ }
12709
12730
  }
12710
- if (changes.reviewerSchedule !== void 0 && (typeof changes.reviewerSchedule !== "string" || changes.reviewerSchedule.trim().length === 0)) {
12711
- return "reviewerSchedule must be a non-empty string";
12731
+ if (changes.scheduleBundleId !== void 0 && changes.scheduleBundleId !== null && (typeof changes.scheduleBundleId !== "string" || changes.scheduleBundleId.trim().length === 0)) {
12732
+ return "scheduleBundleId must be a non-empty string or null";
12712
12733
  }
12713
12734
  if (changes.notifications?.webhooks !== void 0) {
12714
12735
  if (!Array.isArray(changes.notifications.webhooks)) {
@@ -12735,6 +12756,19 @@ function validateConfigChanges(changes) {
12735
12756
  if (rs.autoScanInterval !== void 0 && (typeof rs.autoScanInterval !== "number" || rs.autoScanInterval < 30)) {
12736
12757
  return "roadmapScanner.autoScanInterval must be a number >= 30";
12737
12758
  }
12759
+ const slicerScheduleError = validateCronField("roadmapScanner.slicerSchedule", rs.slicerSchedule);
12760
+ if (slicerScheduleError) {
12761
+ return slicerScheduleError;
12762
+ }
12763
+ if (rs.slicerMaxRuntime !== void 0 && (typeof rs.slicerMaxRuntime !== "number" || rs.slicerMaxRuntime < 60)) {
12764
+ return "roadmapScanner.slicerMaxRuntime must be a number >= 60";
12765
+ }
12766
+ if (rs.priorityMode !== void 0 && rs.priorityMode !== "roadmap-first" && rs.priorityMode !== "audit-first") {
12767
+ return "roadmapScanner.priorityMode must be one of: roadmap-first, audit-first";
12768
+ }
12769
+ if (rs.issueColumn !== void 0 && rs.issueColumn !== "Draft" && rs.issueColumn !== "Ready") {
12770
+ return "roadmapScanner.issueColumn must be one of: Draft, Ready";
12771
+ }
12738
12772
  }
12739
12773
  if (changes.providerEnv !== void 0) {
12740
12774
  if (typeof changes.providerEnv !== "object" || changes.providerEnv === null) {
@@ -12794,8 +12828,9 @@ function validateConfigChanges(changes) {
12794
12828
  if (qa.enabled !== void 0 && typeof qa.enabled !== "boolean") {
12795
12829
  return "qa.enabled must be a boolean";
12796
12830
  }
12797
- if (qa.schedule !== void 0 && (typeof qa.schedule !== "string" || qa.schedule.trim().length === 0)) {
12798
- return "qa.schedule must be a non-empty string";
12831
+ const qaScheduleError = validateCronField("qa.schedule", qa.schedule);
12832
+ if (qaScheduleError) {
12833
+ return qaScheduleError;
12799
12834
  }
12800
12835
  if (qa.maxRuntime !== void 0 && (typeof qa.maxRuntime !== "number" || qa.maxRuntime < 60)) {
12801
12836
  return "qa.maxRuntime must be a number >= 60";
@@ -12826,28 +12861,14 @@ function validateConfigChanges(changes) {
12826
12861
  if (audit.enabled !== void 0 && typeof audit.enabled !== "boolean") {
12827
12862
  return "audit.enabled must be a boolean";
12828
12863
  }
12829
- if (audit.schedule !== void 0 && (typeof audit.schedule !== "string" || audit.schedule.trim().length === 0)) {
12830
- return "audit.schedule must be a non-empty string";
12864
+ const auditScheduleError = validateCronField("audit.schedule", audit.schedule);
12865
+ if (auditScheduleError) {
12866
+ return auditScheduleError;
12831
12867
  }
12832
12868
  if (audit.maxRuntime !== void 0 && (typeof audit.maxRuntime !== "number" || audit.maxRuntime < 60)) {
12833
12869
  return "audit.maxRuntime must be a number >= 60";
12834
12870
  }
12835
12871
  }
12836
- if (changes.roadmapScanner !== void 0) {
12837
- const rs = changes.roadmapScanner;
12838
- if (rs.slicerSchedule !== void 0 && (typeof rs.slicerSchedule !== "string" || rs.slicerSchedule.trim().length === 0)) {
12839
- return "roadmapScanner.slicerSchedule must be a non-empty string";
12840
- }
12841
- if (rs.slicerMaxRuntime !== void 0 && (typeof rs.slicerMaxRuntime !== "number" || rs.slicerMaxRuntime < 60)) {
12842
- return "roadmapScanner.slicerMaxRuntime must be a number >= 60";
12843
- }
12844
- if (rs.priorityMode !== void 0 && rs.priorityMode !== "roadmap-first" && rs.priorityMode !== "audit-first") {
12845
- return "roadmapScanner.priorityMode must be one of: roadmap-first, audit-first";
12846
- }
12847
- if (rs.issueColumn !== void 0 && rs.issueColumn !== "Draft" && rs.issueColumn !== "Ready") {
12848
- return "roadmapScanner.issueColumn must be one of: Draft, Ready";
12849
- }
12850
- }
12851
12872
  if (changes.boardProvider !== void 0) {
12852
12873
  if (typeof changes.boardProvider !== "object" || changes.boardProvider === null) {
12853
12874
  return "boardProvider must be an object";
@@ -12928,13 +12949,7 @@ function createProjectConfigRoutes() {
12928
12949
  });
12929
12950
  return router;
12930
12951
  }
12931
-
12932
- // ../server/dist/routes/doctor.routes.js
12933
12952
  init_dist();
12934
- import * as fs29 from "fs";
12935
- import * as path29 from "path";
12936
- import { execSync as execSync6 } from "child_process";
12937
- import { Router as Router5 } from "express";
12938
12953
  function runDoctorChecks(projectDir, config) {
12939
12954
  const checks = [];
12940
12955
  try {
@@ -13036,11 +13051,7 @@ function createProjectDoctorRoutes() {
13036
13051
  });
13037
13052
  return router;
13038
13053
  }
13039
-
13040
- // ../server/dist/routes/log.routes.js
13041
13054
  init_dist();
13042
- import * as path30 from "path";
13043
- import { Router as Router6 } from "express";
13044
13055
  function createLogRoutes(deps) {
13045
13056
  const { projectDir } = deps;
13046
13057
  const router = Router6();
@@ -13093,9 +13104,6 @@ function createProjectLogRoutes() {
13093
13104
  });
13094
13105
  return router;
13095
13106
  }
13096
-
13097
- // ../server/dist/routes/prd.routes.js
13098
- import { Router as Router7 } from "express";
13099
13107
  function createPrdRoutes(_deps) {
13100
13108
  const router = Router7();
13101
13109
  router.get("/", (_req, res) => {
@@ -13116,11 +13124,7 @@ function createProjectPrdRoutes() {
13116
13124
  });
13117
13125
  return router;
13118
13126
  }
13119
-
13120
- // ../server/dist/routes/roadmap.routes.js
13121
13127
  init_dist();
13122
- import * as path31 from "path";
13123
- import { Router as Router8 } from "express";
13124
13128
  function createRoadmapRouteHandlers(ctx) {
13125
13129
  const router = Router8({ mergeParams: true });
13126
13130
  const p = ctx.pathPrefix;
@@ -13200,11 +13204,7 @@ function createProjectRoadmapRoutes() {
13200
13204
  pathPrefix: "roadmap/"
13201
13205
  });
13202
13206
  }
13203
-
13204
- // ../server/dist/routes/status.routes.js
13205
13207
  init_dist();
13206
- import { Router as Router9 } from "express";
13207
- import { CronExpressionParser } from "cron-parser";
13208
13208
  function createStatusRoutes(deps) {
13209
13209
  const { projectDir, getConfig, sseClients } = deps;
13210
13210
  const router = Router9();
@@ -13235,9 +13235,20 @@ data: ${JSON.stringify(snapshot)}
13235
13235
  });
13236
13236
  return router;
13237
13237
  }
13238
+ function applyScheduleOffset2(schedule, offset) {
13239
+ if (offset === 0) {
13240
+ return schedule;
13241
+ }
13242
+ const parts = schedule.trim().split(/\s+/);
13243
+ if (parts.length < 5 || !/^\d+$/.test(parts[0])) {
13244
+ return schedule.trim();
13245
+ }
13246
+ parts[0] = String(offset);
13247
+ return parts.join(" ");
13248
+ }
13238
13249
  function computeNextRun(cronExpr) {
13239
13250
  try {
13240
- const interval = CronExpressionParser.parse(cronExpr);
13251
+ const interval = CronExpressionParser2.parse(cronExpr);
13241
13252
  return interval.next().toISOString();
13242
13253
  } catch {
13243
13254
  return null;
@@ -13247,6 +13258,48 @@ function hasScheduledCommand(entries, command) {
13247
13258
  const commandPattern = new RegExp(`\\s${command}\\s+>>`);
13248
13259
  return entries.some((entry) => commandPattern.test(entry));
13249
13260
  }
13261
+ function buildScheduleInfoResponse(config, entries, installed) {
13262
+ const offset = config.cronScheduleOffset ?? 0;
13263
+ const executorSchedule = applyScheduleOffset2(config.cronSchedule, offset);
13264
+ const reviewerSchedule = applyScheduleOffset2(config.reviewerSchedule, offset);
13265
+ const qaSchedule = applyScheduleOffset2(config.qa.schedule, offset);
13266
+ const auditSchedule = applyScheduleOffset2(config.audit.schedule, offset);
13267
+ const plannerSchedule = applyScheduleOffset2(config.roadmapScanner.slicerSchedule, offset);
13268
+ const executorInstalled = installed && config.executorEnabled !== false && hasScheduledCommand(entries, "run");
13269
+ const reviewerInstalled = installed && config.reviewerEnabled && hasScheduledCommand(entries, "review");
13270
+ const qaInstalled = installed && config.qa.enabled && hasScheduledCommand(entries, "qa");
13271
+ const auditInstalled = installed && config.audit.enabled && hasScheduledCommand(entries, "audit");
13272
+ const plannerInstalled = installed && config.roadmapScanner.enabled && (hasScheduledCommand(entries, "planner") || hasScheduledCommand(entries, "slice"));
13273
+ return {
13274
+ executor: {
13275
+ schedule: executorSchedule,
13276
+ installed: executorInstalled,
13277
+ nextRun: executorInstalled ? computeNextRun(executorSchedule) : null
13278
+ },
13279
+ reviewer: {
13280
+ schedule: reviewerSchedule,
13281
+ installed: reviewerInstalled,
13282
+ nextRun: reviewerInstalled ? computeNextRun(reviewerSchedule) : null
13283
+ },
13284
+ qa: {
13285
+ schedule: qaSchedule,
13286
+ installed: qaInstalled,
13287
+ nextRun: qaInstalled ? computeNextRun(qaSchedule) : null
13288
+ },
13289
+ audit: {
13290
+ schedule: auditSchedule,
13291
+ installed: auditInstalled,
13292
+ nextRun: auditInstalled ? computeNextRun(auditSchedule) : null
13293
+ },
13294
+ planner: {
13295
+ schedule: plannerSchedule,
13296
+ installed: plannerInstalled,
13297
+ nextRun: plannerInstalled ? computeNextRun(plannerSchedule) : null
13298
+ },
13299
+ paused: !installed,
13300
+ entries
13301
+ };
13302
+ }
13250
13303
  function createScheduleInfoRoutes(deps) {
13251
13304
  const { projectDir, getConfig } = deps;
13252
13305
  const router = Router9();
@@ -13254,42 +13307,7 @@ function createScheduleInfoRoutes(deps) {
13254
13307
  try {
13255
13308
  const config = getConfig();
13256
13309
  const snapshot = await fetchStatusSnapshot(projectDir, config);
13257
- const installed = snapshot.crontab.installed;
13258
- const entries = snapshot.crontab.entries;
13259
- const executorInstalled = installed && config.executorEnabled !== false && hasScheduledCommand(entries, "run");
13260
- const reviewerInstalled = installed && config.reviewerEnabled && hasScheduledCommand(entries, "review");
13261
- const qaInstalled = installed && config.qa.enabled && hasScheduledCommand(entries, "qa");
13262
- const auditInstalled = installed && config.audit.enabled && hasScheduledCommand(entries, "audit");
13263
- const plannerInstalled = installed && config.roadmapScanner.enabled && (hasScheduledCommand(entries, "planner") || hasScheduledCommand(entries, "slice"));
13264
- res.json({
13265
- executor: {
13266
- schedule: config.cronSchedule,
13267
- installed: executorInstalled,
13268
- nextRun: executorInstalled ? computeNextRun(config.cronSchedule) : null
13269
- },
13270
- reviewer: {
13271
- schedule: config.reviewerSchedule,
13272
- installed: reviewerInstalled,
13273
- nextRun: reviewerInstalled ? computeNextRun(config.reviewerSchedule) : null
13274
- },
13275
- qa: {
13276
- schedule: config.qa.schedule,
13277
- installed: qaInstalled,
13278
- nextRun: qaInstalled ? computeNextRun(config.qa.schedule) : null
13279
- },
13280
- audit: {
13281
- schedule: config.audit.schedule,
13282
- installed: auditInstalled,
13283
- nextRun: auditInstalled ? computeNextRun(config.audit.schedule) : null
13284
- },
13285
- planner: {
13286
- schedule: config.roadmapScanner.slicerSchedule,
13287
- installed: plannerInstalled,
13288
- nextRun: plannerInstalled ? computeNextRun(config.roadmapScanner.slicerSchedule) : null
13289
- },
13290
- paused: !installed,
13291
- entries
13292
- });
13310
+ res.json(buildScheduleInfoResponse(config, snapshot.crontab.entries, snapshot.crontab.installed));
13293
13311
  } catch (error2) {
13294
13312
  res.status(500).json({ error: error2 instanceof Error ? error2.message : String(error2) });
13295
13313
  }
@@ -13345,50 +13363,13 @@ data: ${JSON.stringify(snapshot)}
13345
13363
  const config = req.projectConfig;
13346
13364
  const projectDir = req.projectDir;
13347
13365
  const snapshot = await fetchStatusSnapshot(projectDir, config);
13348
- const installed = snapshot.crontab.installed;
13349
- const entries = snapshot.crontab.entries;
13350
- const executorInstalled = installed && config.executorEnabled !== false && hasScheduledCommand(entries, "run");
13351
- const reviewerInstalled = installed && config.reviewerEnabled && hasScheduledCommand(entries, "review");
13352
- const qaInstalled = installed && config.qa.enabled && hasScheduledCommand(entries, "qa");
13353
- const auditInstalled = installed && config.audit.enabled && hasScheduledCommand(entries, "audit");
13354
- const plannerInstalled = installed && config.roadmapScanner.enabled && (hasScheduledCommand(entries, "planner") || hasScheduledCommand(entries, "slice"));
13355
- res.json({
13356
- executor: {
13357
- schedule: config.cronSchedule,
13358
- installed: executorInstalled,
13359
- nextRun: executorInstalled ? computeNextRun(config.cronSchedule) : null
13360
- },
13361
- reviewer: {
13362
- schedule: config.reviewerSchedule,
13363
- installed: reviewerInstalled,
13364
- nextRun: reviewerInstalled ? computeNextRun(config.reviewerSchedule) : null
13365
- },
13366
- qa: {
13367
- schedule: config.qa.schedule,
13368
- installed: qaInstalled,
13369
- nextRun: qaInstalled ? computeNextRun(config.qa.schedule) : null
13370
- },
13371
- audit: {
13372
- schedule: config.audit.schedule,
13373
- installed: auditInstalled,
13374
- nextRun: auditInstalled ? computeNextRun(config.audit.schedule) : null
13375
- },
13376
- planner: {
13377
- schedule: config.roadmapScanner.slicerSchedule,
13378
- installed: plannerInstalled,
13379
- nextRun: plannerInstalled ? computeNextRun(config.roadmapScanner.slicerSchedule) : null
13380
- },
13381
- paused: !installed,
13382
- entries
13383
- });
13366
+ res.json(buildScheduleInfoResponse(config, snapshot.crontab.entries, snapshot.crontab.installed));
13384
13367
  } catch (error2) {
13385
13368
  res.status(500).json({ error: error2 instanceof Error ? error2.message : String(error2) });
13386
13369
  }
13387
13370
  });
13388
13371
  return router;
13389
13372
  }
13390
-
13391
- // ../server/dist/index.js
13392
13373
  var __filename2 = fileURLToPath3(import.meta.url);
13393
13374
  var __dirname3 = dirname7(__filename2);
13394
13375
  function resolveWebDistPath() {
@@ -13569,8 +13550,6 @@ Night Watch Global UI`);
13569
13550
  });
13570
13551
  setupGracefulShutdown(server);
13571
13552
  }
13572
-
13573
- // dist/commands/serve.js
13574
13553
  function getServeLockPath(mode, port) {
13575
13554
  return `${LOCK_FILE_PREFIX}serve-${mode}-${port}.lock`;
13576
13555
  }
@@ -13692,8 +13671,6 @@ function serveCommand(program2) {
13692
13671
  }
13693
13672
  });
13694
13673
  }
13695
-
13696
- // dist/commands/history.js
13697
13674
  init_dist();
13698
13675
  var VALID_OUTCOMES = ["success", "failure", "timeout", "rate_limited"];
13699
13676
  function historyCommand(program2) {
@@ -13732,12 +13709,7 @@ function historyCommand(program2) {
13732
13709
  }
13733
13710
  });
13734
13711
  }
13735
-
13736
- // dist/commands/update.js
13737
13712
  init_dist();
13738
- import { spawnSync } from "child_process";
13739
- import * as fs32 from "fs";
13740
- import * as path33 from "path";
13741
13713
  var DEFAULT_GLOBAL_SPEC = "@jonit-dev/night-watch-cli@latest";
13742
13714
  function parseProjectDirs(projects, cwd) {
13743
13715
  if (!projects || projects.trim().length === 0) {
@@ -13801,8 +13773,6 @@ function updateCommand(program2) {
13801
13773
  }
13802
13774
  });
13803
13775
  }
13804
-
13805
- // dist/commands/prd-state.js
13806
13776
  init_dist();
13807
13777
  function prdStateCommand(program2) {
13808
13778
  const prdState = program2.command("prd-state").description("Manage PRD state entries in ~/.night-watch/prd-states.json");
@@ -13826,11 +13796,7 @@ function prdStateCommand(program2) {
13826
13796
  }
13827
13797
  });
13828
13798
  }
13829
-
13830
- // dist/commands/retry.js
13831
13799
  init_dist();
13832
- import * as fs33 from "fs";
13833
- import * as path34 from "path";
13834
13800
  function normalizePrdName(name) {
13835
13801
  if (!name.endsWith(".md")) {
13836
13802
  return `${name}.md`;
@@ -13876,10 +13842,7 @@ function retryCommand(program2) {
13876
13842
  process.exit(1);
13877
13843
  });
13878
13844
  }
13879
-
13880
- // dist/commands/prs.js
13881
13845
  init_dist();
13882
- import chalk3 from "chalk";
13883
13846
  function formatCiStatus(status) {
13884
13847
  switch (status) {
13885
13848
  case "pass":
@@ -13956,11 +13919,7 @@ function prsCommand(program2) {
13956
13919
  }
13957
13920
  });
13958
13921
  }
13959
-
13960
- // dist/commands/prds.js
13961
13922
  init_dist();
13962
- import chalk4 from "chalk";
13963
- import { execSync as execSync7 } from "child_process";
13964
13923
  function getOpenPrBranches(projectDir) {
13965
13924
  try {
13966
13925
  execSync7("git rev-parse --git-dir", {
@@ -14100,11 +14059,7 @@ function prdsCommand(program2) {
14100
14059
  }
14101
14060
  });
14102
14061
  }
14103
-
14104
- // dist/commands/cancel.js
14105
14062
  init_dist();
14106
- import * as fs34 from "fs";
14107
- import * as readline3 from "readline";
14108
14063
  function getLockFilePaths2(projectDir) {
14109
14064
  const runtimeKey = projectRuntimeKey(projectDir);
14110
14065
  return {
@@ -14281,11 +14236,7 @@ function cancelCommand(program2) {
14281
14236
  }
14282
14237
  });
14283
14238
  }
14284
-
14285
- // dist/commands/slice.js
14286
14239
  init_dist();
14287
- import * as fs35 from "fs";
14288
- import * as path35 from "path";
14289
14240
  function plannerLockPath2(projectDir) {
14290
14241
  return `${LOCK_FILE_PREFIX}slicer-${projectRuntimeKey(projectDir)}.lock`;
14291
14242
  }
@@ -14545,13 +14496,7 @@ function sliceCommand(program2) {
14545
14496
  }
14546
14497
  });
14547
14498
  }
14548
-
14549
- // dist/commands/state.js
14550
14499
  init_dist();
14551
- import * as os6 from "os";
14552
- import * as path36 from "path";
14553
- import chalk5 from "chalk";
14554
- import { Command } from "commander";
14555
14500
  function createStateCommand() {
14556
14501
  const state = new Command("state");
14557
14502
  state.description("Manage Night Watch state");
@@ -14591,15 +14536,8 @@ function createStateCommand() {
14591
14536
  });
14592
14537
  return state;
14593
14538
  }
14594
-
14595
- // dist/commands/board.js
14596
14539
  init_dist();
14597
14540
  init_dist();
14598
- import { execFileSync as execFileSync6 } from "child_process";
14599
- import * as fs36 from "fs";
14600
- import * as path37 from "path";
14601
- import * as readline4 from "readline";
14602
- import chalk6 from "chalk";
14603
14541
  async function run(fn) {
14604
14542
  try {
14605
14543
  await fn();
@@ -15127,8 +15065,6 @@ function boardCommand(program2) {
15127
15065
  }
15128
15066
  }));
15129
15067
  }
15130
-
15131
- // dist/cli.js
15132
15068
  var __filename3 = fileURLToPath4(import.meta.url);
15133
15069
  var __dirname4 = dirname8(__filename3);
15134
15070
  function findPackageRoot(dir) {