@jonit-dev/night-watch-cli 1.7.50 → 1.7.52
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 +393 -229
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +6 -24
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +20 -23
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/qa.d.ts.map +1 -1
- package/dist/commands/qa.js +16 -4
- package/dist/commands/qa.js.map +1 -1
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +6 -4
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/shared/env-builder.d.ts +5 -0
- package/dist/commands/shared/env-builder.d.ts.map +1 -1
- package/dist/commands/shared/env-builder.js +32 -0
- package/dist/commands/shared/env-builder.js.map +1 -1
- package/dist/commands/slice.d.ts +8 -0
- package/dist/commands/slice.d.ts.map +1 -1
- package/dist/commands/slice.js +90 -2
- package/dist/commands/slice.js.map +1 -1
- package/dist/scripts/night-watch-audit-cron.sh +17 -4
- package/dist/scripts/night-watch-cron.sh +19 -5
- package/dist/scripts/night-watch-helpers.sh +137 -0
- package/dist/scripts/night-watch-pr-reviewer-cron.sh +268 -5
- package/dist/scripts/night-watch-qa-cron.sh +427 -22
- package/dist/scripts/night-watch-slicer-cron.sh +14 -3
- package/dist/templates/audit.md +87 -0
- package/dist/templates/executor.md +67 -0
- package/dist/templates/night-watch-pr-reviewer.md +33 -0
- package/dist/templates/night-watch.config.json +31 -1
- package/dist/templates/night-watch.md +31 -0
- package/dist/templates/pr-reviewer.md +203 -0
- package/dist/templates/qa.md +157 -0
- package/dist/templates/slicer.md +234 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,6 @@ import 'reflect-metadata';
|
|
|
4
4
|
// dist/cli.js
|
|
5
5
|
import "reflect-metadata";
|
|
6
6
|
import "reflect-metadata";
|
|
7
|
-
import "reflect-metadata";
|
|
8
7
|
import * as fs from "fs";
|
|
9
8
|
import * as path from "path";
|
|
10
9
|
import { fileURLToPath } from "url";
|
|
@@ -84,7 +83,7 @@ import "reflect-metadata";
|
|
|
84
83
|
import { Command as Command2 } from "commander";
|
|
85
84
|
import { existsSync as existsSync30, readFileSync as readFileSync18 } from "fs";
|
|
86
85
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
87
|
-
import { dirname as dirname8, join as
|
|
86
|
+
import { dirname as dirname8, join as join34 } from "path";
|
|
88
87
|
import fs18 from "fs";
|
|
89
88
|
import path17 from "path";
|
|
90
89
|
import { execSync as execSync3 } from "child_process";
|
|
@@ -286,7 +285,9 @@ var init_constants = __esm({
|
|
|
286
285
|
roadmapPath: "ROADMAP.md",
|
|
287
286
|
autoScanInterval: 300,
|
|
288
287
|
slicerSchedule: DEFAULT_SLICER_SCHEDULE,
|
|
289
|
-
slicerMaxRuntime: DEFAULT_SLICER_MAX_RUNTIME
|
|
288
|
+
slicerMaxRuntime: DEFAULT_SLICER_MAX_RUNTIME,
|
|
289
|
+
priorityMode: "roadmap-first",
|
|
290
|
+
issueColumn: "Draft"
|
|
290
291
|
};
|
|
291
292
|
DEFAULT_TEMPLATES_DIR = ".night-watch/templates";
|
|
292
293
|
DEFAULT_BOARD_PROVIDER = {
|
|
@@ -441,6 +442,10 @@ function normalizeConfig(rawConfig) {
|
|
|
441
442
|
normalized.provider = validateProvider(String(rawConfig.provider ?? "")) ?? void 0;
|
|
442
443
|
normalized.executorEnabled = readBoolean(rawConfig.executorEnabled);
|
|
443
444
|
normalized.reviewerEnabled = readBoolean(rawConfig.reviewerEnabled);
|
|
445
|
+
const providerLabelVal = readString(rawConfig.providerLabel);
|
|
446
|
+
if (providerLabelVal) {
|
|
447
|
+
normalized.providerLabel = providerLabelVal;
|
|
448
|
+
}
|
|
444
449
|
const rawProviderEnv = readObject(rawConfig.providerEnv);
|
|
445
450
|
if (rawProviderEnv) {
|
|
446
451
|
const env = {};
|
|
@@ -474,12 +479,18 @@ function normalizeConfig(rawConfig) {
|
|
|
474
479
|
normalized.prdPriority = readStringArray(rawConfig.prdPriority);
|
|
475
480
|
const rawRoadmapScanner = readObject(rawConfig.roadmapScanner);
|
|
476
481
|
if (rawRoadmapScanner) {
|
|
482
|
+
const priorityModeRaw = readString(rawRoadmapScanner.priorityMode);
|
|
483
|
+
const priorityMode = priorityModeRaw === "roadmap-first" || priorityModeRaw === "audit-first" ? priorityModeRaw : DEFAULT_ROADMAP_SCANNER.priorityMode;
|
|
484
|
+
const issueColumnRaw = readString(rawRoadmapScanner.issueColumn);
|
|
485
|
+
const issueColumn = issueColumnRaw === "Draft" || issueColumnRaw === "Ready" ? issueColumnRaw : DEFAULT_ROADMAP_SCANNER.issueColumn;
|
|
477
486
|
const roadmapScanner = {
|
|
478
487
|
enabled: readBoolean(rawRoadmapScanner.enabled) ?? DEFAULT_ROADMAP_SCANNER.enabled,
|
|
479
488
|
roadmapPath: readString(rawRoadmapScanner.roadmapPath) ?? DEFAULT_ROADMAP_SCANNER.roadmapPath,
|
|
480
489
|
autoScanInterval: readNumber(rawRoadmapScanner.autoScanInterval) ?? DEFAULT_ROADMAP_SCANNER.autoScanInterval,
|
|
481
490
|
slicerSchedule: readString(rawRoadmapScanner.slicerSchedule) ?? DEFAULT_ROADMAP_SCANNER.slicerSchedule,
|
|
482
|
-
slicerMaxRuntime: readNumber(rawRoadmapScanner.slicerMaxRuntime) ?? DEFAULT_ROADMAP_SCANNER.slicerMaxRuntime
|
|
491
|
+
slicerMaxRuntime: readNumber(rawRoadmapScanner.slicerMaxRuntime) ?? DEFAULT_ROADMAP_SCANNER.slicerMaxRuntime,
|
|
492
|
+
priorityMode,
|
|
493
|
+
issueColumn
|
|
483
494
|
};
|
|
484
495
|
if (roadmapScanner.autoScanInterval < 30) {
|
|
485
496
|
roadmapScanner.autoScanInterval = 30;
|
|
@@ -601,130 +612,30 @@ function sanitizeReviewerRetryDelay(value, fallback) {
|
|
|
601
612
|
return 300;
|
|
602
613
|
return normalized;
|
|
603
614
|
}
|
|
615
|
+
function mergeConfigLayer(base, layer) {
|
|
616
|
+
for (const _key of Object.keys(layer)) {
|
|
617
|
+
const value = layer[_key];
|
|
618
|
+
if (value === void 0)
|
|
619
|
+
continue;
|
|
620
|
+
if (_key === "providerEnv" || _key === "boardProvider" || _key === "qa" || _key === "audit") {
|
|
621
|
+
base[_key] = {
|
|
622
|
+
...base[_key],
|
|
623
|
+
...value
|
|
624
|
+
};
|
|
625
|
+
} else if (_key === "roadmapScanner" || _key === "jobProviders") {
|
|
626
|
+
base[_key] = { ...value };
|
|
627
|
+
} else if (_key === "branchPatterns" || _key === "prdPriority") {
|
|
628
|
+
base[_key] = [...value];
|
|
629
|
+
} else {
|
|
630
|
+
base[_key] = value;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
604
634
|
function mergeConfigs(base, fileConfig, envConfig) {
|
|
605
635
|
const merged = { ...base };
|
|
606
|
-
if (fileConfig)
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
if (fileConfig.prdDir !== void 0)
|
|
610
|
-
merged.prdDir = fileConfig.prdDir;
|
|
611
|
-
if (fileConfig.maxRuntime !== void 0)
|
|
612
|
-
merged.maxRuntime = fileConfig.maxRuntime;
|
|
613
|
-
if (fileConfig.reviewerMaxRuntime !== void 0)
|
|
614
|
-
merged.reviewerMaxRuntime = fileConfig.reviewerMaxRuntime;
|
|
615
|
-
if (fileConfig.branchPrefix !== void 0)
|
|
616
|
-
merged.branchPrefix = fileConfig.branchPrefix;
|
|
617
|
-
if (fileConfig.branchPatterns !== void 0)
|
|
618
|
-
merged.branchPatterns = [...fileConfig.branchPatterns];
|
|
619
|
-
if (fileConfig.minReviewScore !== void 0)
|
|
620
|
-
merged.minReviewScore = fileConfig.minReviewScore;
|
|
621
|
-
if (fileConfig.maxLogSize !== void 0)
|
|
622
|
-
merged.maxLogSize = fileConfig.maxLogSize;
|
|
623
|
-
if (fileConfig.cronSchedule !== void 0)
|
|
624
|
-
merged.cronSchedule = fileConfig.cronSchedule;
|
|
625
|
-
if (fileConfig.reviewerSchedule !== void 0)
|
|
626
|
-
merged.reviewerSchedule = fileConfig.reviewerSchedule;
|
|
627
|
-
if (fileConfig.cronScheduleOffset !== void 0)
|
|
628
|
-
merged.cronScheduleOffset = fileConfig.cronScheduleOffset;
|
|
629
|
-
if (fileConfig.maxRetries !== void 0)
|
|
630
|
-
merged.maxRetries = fileConfig.maxRetries;
|
|
631
|
-
if (fileConfig.reviewerMaxRetries !== void 0)
|
|
632
|
-
merged.reviewerMaxRetries = fileConfig.reviewerMaxRetries;
|
|
633
|
-
if (fileConfig.reviewerRetryDelay !== void 0)
|
|
634
|
-
merged.reviewerRetryDelay = fileConfig.reviewerRetryDelay;
|
|
635
|
-
if (fileConfig.provider !== void 0)
|
|
636
|
-
merged.provider = fileConfig.provider;
|
|
637
|
-
if (fileConfig.executorEnabled !== void 0)
|
|
638
|
-
merged.executorEnabled = fileConfig.executorEnabled;
|
|
639
|
-
if (fileConfig.reviewerEnabled !== void 0)
|
|
640
|
-
merged.reviewerEnabled = fileConfig.reviewerEnabled;
|
|
641
|
-
if (fileConfig.providerEnv !== void 0)
|
|
642
|
-
merged.providerEnv = { ...merged.providerEnv, ...fileConfig.providerEnv };
|
|
643
|
-
if (fileConfig.notifications !== void 0)
|
|
644
|
-
merged.notifications = fileConfig.notifications;
|
|
645
|
-
if (fileConfig.prdPriority !== void 0)
|
|
646
|
-
merged.prdPriority = [...fileConfig.prdPriority];
|
|
647
|
-
if (fileConfig.roadmapScanner !== void 0)
|
|
648
|
-
merged.roadmapScanner = { ...fileConfig.roadmapScanner };
|
|
649
|
-
if (fileConfig.templatesDir !== void 0)
|
|
650
|
-
merged.templatesDir = fileConfig.templatesDir;
|
|
651
|
-
if (fileConfig.boardProvider !== void 0)
|
|
652
|
-
merged.boardProvider = { ...merged.boardProvider, ...fileConfig.boardProvider };
|
|
653
|
-
if (fileConfig.autoMerge !== void 0)
|
|
654
|
-
merged.autoMerge = fileConfig.autoMerge;
|
|
655
|
-
if (fileConfig.autoMergeMethod !== void 0)
|
|
656
|
-
merged.autoMergeMethod = fileConfig.autoMergeMethod;
|
|
657
|
-
if (fileConfig.fallbackOnRateLimit !== void 0)
|
|
658
|
-
merged.fallbackOnRateLimit = fileConfig.fallbackOnRateLimit;
|
|
659
|
-
if (fileConfig.claudeModel !== void 0)
|
|
660
|
-
merged.claudeModel = fileConfig.claudeModel;
|
|
661
|
-
if (fileConfig.qa !== void 0)
|
|
662
|
-
merged.qa = { ...merged.qa, ...fileConfig.qa };
|
|
663
|
-
if (fileConfig.audit !== void 0)
|
|
664
|
-
merged.audit = { ...merged.audit, ...fileConfig.audit };
|
|
665
|
-
if (fileConfig.jobProviders !== void 0)
|
|
666
|
-
merged.jobProviders = { ...fileConfig.jobProviders };
|
|
667
|
-
}
|
|
668
|
-
if (envConfig.defaultBranch !== void 0)
|
|
669
|
-
merged.defaultBranch = envConfig.defaultBranch;
|
|
670
|
-
if (envConfig.prdDir !== void 0)
|
|
671
|
-
merged.prdDir = envConfig.prdDir;
|
|
672
|
-
if (envConfig.maxRuntime !== void 0)
|
|
673
|
-
merged.maxRuntime = envConfig.maxRuntime;
|
|
674
|
-
if (envConfig.reviewerMaxRuntime !== void 0)
|
|
675
|
-
merged.reviewerMaxRuntime = envConfig.reviewerMaxRuntime;
|
|
676
|
-
if (envConfig.branchPrefix !== void 0)
|
|
677
|
-
merged.branchPrefix = envConfig.branchPrefix;
|
|
678
|
-
if (envConfig.branchPatterns !== void 0)
|
|
679
|
-
merged.branchPatterns = [...envConfig.branchPatterns];
|
|
680
|
-
if (envConfig.minReviewScore !== void 0)
|
|
681
|
-
merged.minReviewScore = envConfig.minReviewScore;
|
|
682
|
-
if (envConfig.maxLogSize !== void 0)
|
|
683
|
-
merged.maxLogSize = envConfig.maxLogSize;
|
|
684
|
-
if (envConfig.cronSchedule !== void 0)
|
|
685
|
-
merged.cronSchedule = envConfig.cronSchedule;
|
|
686
|
-
if (envConfig.reviewerSchedule !== void 0)
|
|
687
|
-
merged.reviewerSchedule = envConfig.reviewerSchedule;
|
|
688
|
-
if (envConfig.cronScheduleOffset !== void 0)
|
|
689
|
-
merged.cronScheduleOffset = envConfig.cronScheduleOffset;
|
|
690
|
-
if (envConfig.maxRetries !== void 0)
|
|
691
|
-
merged.maxRetries = envConfig.maxRetries;
|
|
692
|
-
if (envConfig.reviewerMaxRetries !== void 0)
|
|
693
|
-
merged.reviewerMaxRetries = envConfig.reviewerMaxRetries;
|
|
694
|
-
if (envConfig.reviewerRetryDelay !== void 0)
|
|
695
|
-
merged.reviewerRetryDelay = envConfig.reviewerRetryDelay;
|
|
696
|
-
if (envConfig.provider !== void 0)
|
|
697
|
-
merged.provider = envConfig.provider;
|
|
698
|
-
if (envConfig.executorEnabled !== void 0)
|
|
699
|
-
merged.executorEnabled = envConfig.executorEnabled;
|
|
700
|
-
if (envConfig.reviewerEnabled !== void 0)
|
|
701
|
-
merged.reviewerEnabled = envConfig.reviewerEnabled;
|
|
702
|
-
if (envConfig.providerEnv !== void 0)
|
|
703
|
-
merged.providerEnv = { ...merged.providerEnv, ...envConfig.providerEnv };
|
|
704
|
-
if (envConfig.notifications !== void 0)
|
|
705
|
-
merged.notifications = envConfig.notifications;
|
|
706
|
-
if (envConfig.prdPriority !== void 0)
|
|
707
|
-
merged.prdPriority = [...envConfig.prdPriority];
|
|
708
|
-
if (envConfig.roadmapScanner !== void 0)
|
|
709
|
-
merged.roadmapScanner = { ...envConfig.roadmapScanner };
|
|
710
|
-
if (envConfig.templatesDir !== void 0)
|
|
711
|
-
merged.templatesDir = envConfig.templatesDir;
|
|
712
|
-
if (envConfig.boardProvider !== void 0)
|
|
713
|
-
merged.boardProvider = { ...merged.boardProvider, ...envConfig.boardProvider };
|
|
714
|
-
if (envConfig.autoMerge !== void 0)
|
|
715
|
-
merged.autoMerge = envConfig.autoMerge;
|
|
716
|
-
if (envConfig.autoMergeMethod !== void 0)
|
|
717
|
-
merged.autoMergeMethod = envConfig.autoMergeMethod;
|
|
718
|
-
if (envConfig.fallbackOnRateLimit !== void 0)
|
|
719
|
-
merged.fallbackOnRateLimit = envConfig.fallbackOnRateLimit;
|
|
720
|
-
if (envConfig.claudeModel !== void 0)
|
|
721
|
-
merged.claudeModel = envConfig.claudeModel;
|
|
722
|
-
if (envConfig.qa !== void 0)
|
|
723
|
-
merged.qa = { ...merged.qa, ...envConfig.qa };
|
|
724
|
-
if (envConfig.audit !== void 0)
|
|
725
|
-
merged.audit = { ...merged.audit, ...envConfig.audit };
|
|
726
|
-
if (envConfig.jobProviders !== void 0)
|
|
727
|
-
merged.jobProviders = { ...envConfig.jobProviders };
|
|
636
|
+
if (fileConfig)
|
|
637
|
+
mergeConfigLayer(merged, fileConfig);
|
|
638
|
+
mergeConfigLayer(merged, envConfig);
|
|
728
639
|
merged.maxRetries = sanitizeMaxRetries(merged.maxRetries, DEFAULT_MAX_RETRIES);
|
|
729
640
|
merged.reviewerMaxRetries = sanitizeReviewerMaxRetries(merged.reviewerMaxRetries, DEFAULT_REVIEWER_MAX_RETRIES);
|
|
730
641
|
merged.reviewerRetryDelay = sanitizeReviewerRetryDelay(merged.reviewerRetryDelay, DEFAULT_REVIEWER_RETRY_DELAY);
|
|
@@ -859,6 +770,24 @@ function loadConfig(projectDir) {
|
|
|
859
770
|
};
|
|
860
771
|
}
|
|
861
772
|
}
|
|
773
|
+
if (process.env.NW_PLANNER_ISSUE_COLUMN) {
|
|
774
|
+
const issueColumn = process.env.NW_PLANNER_ISSUE_COLUMN;
|
|
775
|
+
if (issueColumn === "Draft" || issueColumn === "Ready") {
|
|
776
|
+
envConfig.roadmapScanner = {
|
|
777
|
+
...envConfig.roadmapScanner ?? DEFAULT_ROADMAP_SCANNER,
|
|
778
|
+
issueColumn
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
if (process.env.NW_PLANNER_PRIORITY_MODE) {
|
|
783
|
+
const priorityMode = process.env.NW_PLANNER_PRIORITY_MODE;
|
|
784
|
+
if (priorityMode === "roadmap-first" || priorityMode === "audit-first") {
|
|
785
|
+
envConfig.roadmapScanner = {
|
|
786
|
+
...envConfig.roadmapScanner ?? DEFAULT_ROADMAP_SCANNER,
|
|
787
|
+
priorityMode
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
}
|
|
862
791
|
if (process.env.NW_AUTO_MERGE) {
|
|
863
792
|
const autoMerge = parseBoolean(process.env.NW_AUTO_MERGE);
|
|
864
793
|
if (autoMerge !== null) {
|
|
@@ -5258,7 +5187,8 @@ function parsePrDetails(raw) {
|
|
|
5258
5187
|
body: details.body ?? "",
|
|
5259
5188
|
additions: details.additions ?? 0,
|
|
5260
5189
|
deletions: details.deletions ?? 0,
|
|
5261
|
-
changedFiles: details.changedFiles ?? 0
|
|
5190
|
+
changedFiles: details.changedFiles ?? 0,
|
|
5191
|
+
headRefName: details.headRefName ?? ""
|
|
5262
5192
|
};
|
|
5263
5193
|
} catch {
|
|
5264
5194
|
return null;
|
|
@@ -5266,12 +5196,60 @@ function parsePrDetails(raw) {
|
|
|
5266
5196
|
}
|
|
5267
5197
|
function fetchPrBySelector(selector, cwd) {
|
|
5268
5198
|
try {
|
|
5269
|
-
const output = execFileSync2("gh", [
|
|
5199
|
+
const output = execFileSync2("gh", [
|
|
5200
|
+
"pr",
|
|
5201
|
+
"view",
|
|
5202
|
+
selector,
|
|
5203
|
+
"--json",
|
|
5204
|
+
"number,title,url,body,additions,deletions,changedFiles,headRefName"
|
|
5205
|
+
], { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
|
|
5270
5206
|
return parsePrDetails(output);
|
|
5271
5207
|
} catch {
|
|
5272
5208
|
return null;
|
|
5273
5209
|
}
|
|
5274
5210
|
}
|
|
5211
|
+
function decodeBase64Value(value) {
|
|
5212
|
+
try {
|
|
5213
|
+
return Buffer.from(value, "base64").toString("utf-8");
|
|
5214
|
+
} catch {
|
|
5215
|
+
return "";
|
|
5216
|
+
}
|
|
5217
|
+
}
|
|
5218
|
+
function splitNonEmptyLines(value) {
|
|
5219
|
+
return value.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
5220
|
+
}
|
|
5221
|
+
function getQaCommentBodiesBase64(prNumber, cwd, repo) {
|
|
5222
|
+
const bodies = [];
|
|
5223
|
+
try {
|
|
5224
|
+
const ghPrOutput = execFileSync2("gh", ["pr", "view", String(prNumber), "--json", "comments", "--jq", ".comments[]?.body | @base64"], { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
|
|
5225
|
+
bodies.push(...splitNonEmptyLines(ghPrOutput));
|
|
5226
|
+
} catch {
|
|
5227
|
+
}
|
|
5228
|
+
if (repo) {
|
|
5229
|
+
try {
|
|
5230
|
+
const issueCommentsOutput = execFileSync2("gh", ["api", `repos/${repo}/issues/${prNumber}/comments`, "--jq", ".[].body | @base64"], { cwd, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
|
|
5231
|
+
bodies.push(...splitNonEmptyLines(issueCommentsOutput));
|
|
5232
|
+
} catch {
|
|
5233
|
+
}
|
|
5234
|
+
}
|
|
5235
|
+
return bodies;
|
|
5236
|
+
}
|
|
5237
|
+
function normalizeQaScreenshotUrl(rawUrl, repo) {
|
|
5238
|
+
const url = rawUrl.trim();
|
|
5239
|
+
if (url.length === 0) {
|
|
5240
|
+
return "";
|
|
5241
|
+
}
|
|
5242
|
+
if (/^https?:\/\//i.test(url)) {
|
|
5243
|
+
return url;
|
|
5244
|
+
}
|
|
5245
|
+
if (repo && url.startsWith("../blob/")) {
|
|
5246
|
+
return `https://github.com/${repo}/${url.replace(/^\.\.\//, "")}`;
|
|
5247
|
+
}
|
|
5248
|
+
if (repo && url.startsWith("blob/")) {
|
|
5249
|
+
return `https://github.com/${repo}/${url}`;
|
|
5250
|
+
}
|
|
5251
|
+
return url;
|
|
5252
|
+
}
|
|
5275
5253
|
function fetchPrDetailsForBranch(branchName, cwd) {
|
|
5276
5254
|
return fetchPrBySelector(branchName, cwd);
|
|
5277
5255
|
}
|
|
@@ -5306,6 +5284,44 @@ function fetchReviewedPrDetails(branchPatterns, cwd) {
|
|
|
5306
5284
|
return null;
|
|
5307
5285
|
}
|
|
5308
5286
|
}
|
|
5287
|
+
function fetchLatestQaCommentBody(prNumber, cwd, repo) {
|
|
5288
|
+
const encodedBodies = getQaCommentBodiesBase64(prNumber, cwd, repo);
|
|
5289
|
+
let latestQaComment = null;
|
|
5290
|
+
for (const encoded of encodedBodies) {
|
|
5291
|
+
const decoded = decodeBase64Value(encoded);
|
|
5292
|
+
if (decoded.includes(QA_COMMENT_MARKER)) {
|
|
5293
|
+
latestQaComment = decoded;
|
|
5294
|
+
}
|
|
5295
|
+
}
|
|
5296
|
+
return latestQaComment;
|
|
5297
|
+
}
|
|
5298
|
+
function extractQaScreenshotUrls(commentBody, repo) {
|
|
5299
|
+
if (!commentBody || commentBody.trim().length === 0) {
|
|
5300
|
+
return [];
|
|
5301
|
+
}
|
|
5302
|
+
const regex = new RegExp(QA_SCREENSHOT_REGEX);
|
|
5303
|
+
const screenshots = [];
|
|
5304
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5305
|
+
let match;
|
|
5306
|
+
match = regex.exec(commentBody);
|
|
5307
|
+
while (match !== null) {
|
|
5308
|
+
const rawUrl = match[1] ?? "";
|
|
5309
|
+
const normalizedUrl = normalizeQaScreenshotUrl(rawUrl, repo);
|
|
5310
|
+
if (normalizedUrl.length > 0 && !seen.has(normalizedUrl)) {
|
|
5311
|
+
seen.add(normalizedUrl);
|
|
5312
|
+
screenshots.push(normalizedUrl);
|
|
5313
|
+
}
|
|
5314
|
+
match = regex.exec(commentBody);
|
|
5315
|
+
}
|
|
5316
|
+
return screenshots;
|
|
5317
|
+
}
|
|
5318
|
+
function fetchQaScreenshotUrlsForPr(prNumber, cwd, repo) {
|
|
5319
|
+
const qaComment = fetchLatestQaCommentBody(prNumber, cwd, repo);
|
|
5320
|
+
if (!qaComment) {
|
|
5321
|
+
return [];
|
|
5322
|
+
}
|
|
5323
|
+
return extractQaScreenshotUrls(qaComment, repo);
|
|
5324
|
+
}
|
|
5309
5325
|
function extractSummary(body, maxLength = 500) {
|
|
5310
5326
|
if (!body || body.trim().length === 0) {
|
|
5311
5327
|
return "";
|
|
@@ -5330,9 +5346,13 @@ function extractSummary(body, maxLength = 500) {
|
|
|
5330
5346
|
const lastSpace = truncated.lastIndexOf(" ");
|
|
5331
5347
|
return (lastSpace > 0 ? truncated.slice(0, lastSpace) : truncated) + "...";
|
|
5332
5348
|
}
|
|
5349
|
+
var QA_COMMENT_MARKER;
|
|
5350
|
+
var QA_SCREENSHOT_REGEX;
|
|
5333
5351
|
var init_github = __esm({
|
|
5334
5352
|
"../core/dist/utils/github.js"() {
|
|
5335
5353
|
"use strict";
|
|
5354
|
+
QA_COMMENT_MARKER = "<!-- night-watch-qa-marker -->";
|
|
5355
|
+
QA_SCREENSHOT_REGEX = /!\[[^\]]*]\(([^)\n]*qa-artifacts\/[^)\n]+)\)/g;
|
|
5336
5356
|
}
|
|
5337
5357
|
});
|
|
5338
5358
|
function rotateLog(logFile, maxSize = DEFAULT_MAX_LOG_SIZE) {
|
|
@@ -5546,6 +5566,16 @@ function buildDescription(ctx) {
|
|
|
5546
5566
|
lines.push(retryInfo);
|
|
5547
5567
|
}
|
|
5548
5568
|
}
|
|
5569
|
+
if (ctx.event === "qa_completed" && (ctx.qaScreenshotUrls?.length ?? 0) > 0) {
|
|
5570
|
+
const screenshotUrls = ctx.qaScreenshotUrls ?? [];
|
|
5571
|
+
lines.push(`QA screenshots: ${screenshotUrls.length}`);
|
|
5572
|
+
for (const [index, screenshotUrl] of screenshotUrls.slice(0, MAX_QA_SCREENSHOTS_IN_NOTIFICATION).entries()) {
|
|
5573
|
+
lines.push(`Screenshot ${index + 1}: ${screenshotUrl}`);
|
|
5574
|
+
}
|
|
5575
|
+
if (screenshotUrls.length > MAX_QA_SCREENSHOTS_IN_NOTIFICATION) {
|
|
5576
|
+
lines.push(`Additional screenshots: ${screenshotUrls.length - MAX_QA_SCREENSHOTS_IN_NOTIFICATION}`);
|
|
5577
|
+
}
|
|
5578
|
+
}
|
|
5549
5579
|
return lines.join("\n");
|
|
5550
5580
|
}
|
|
5551
5581
|
function escapeMarkdownV2(text) {
|
|
@@ -5635,6 +5665,17 @@ function formatTelegramPayload(ctx) {
|
|
|
5635
5665
|
lines.push(escapeMarkdownV2(`\u{1F501} Attempts: ${ctx.attempts}`));
|
|
5636
5666
|
}
|
|
5637
5667
|
}
|
|
5668
|
+
if (ctx.event === "qa_completed" && (ctx.qaScreenshotUrls?.length ?? 0) > 0) {
|
|
5669
|
+
const screenshotUrls = ctx.qaScreenshotUrls ?? [];
|
|
5670
|
+
lines.push("");
|
|
5671
|
+
lines.push(escapeMarkdownV2("\u{1F5BC} Screenshots"));
|
|
5672
|
+
for (const screenshotUrl of screenshotUrls.slice(0, MAX_QA_SCREENSHOTS_IN_NOTIFICATION)) {
|
|
5673
|
+
lines.push(escapeMarkdownV2(screenshotUrl));
|
|
5674
|
+
}
|
|
5675
|
+
if (screenshotUrls.length > MAX_QA_SCREENSHOTS_IN_NOTIFICATION) {
|
|
5676
|
+
lines.push(escapeMarkdownV2(`...and ${screenshotUrls.length - MAX_QA_SCREENSHOTS_IN_NOTIFICATION} more`));
|
|
5677
|
+
}
|
|
5678
|
+
}
|
|
5638
5679
|
lines.push("");
|
|
5639
5680
|
lines.push(escapeMarkdownV2(`\u2699\uFE0F Project: ${ctx.projectName} | Provider: ${ctx.provider}`));
|
|
5640
5681
|
return {
|
|
@@ -5702,11 +5743,13 @@ async function sendNotifications(config, ctx) {
|
|
|
5702
5743
|
const total = results.length;
|
|
5703
5744
|
info(`Sent ${sent}/${total} notifications`);
|
|
5704
5745
|
}
|
|
5746
|
+
var MAX_QA_SCREENSHOTS_IN_NOTIFICATION;
|
|
5705
5747
|
var init_notify = __esm({
|
|
5706
5748
|
"../core/dist/utils/notify.js"() {
|
|
5707
5749
|
"use strict";
|
|
5708
5750
|
init_ui();
|
|
5709
5751
|
init_github();
|
|
5752
|
+
MAX_QA_SCREENSHOTS_IN_NOTIFICATION = 3;
|
|
5710
5753
|
}
|
|
5711
5754
|
});
|
|
5712
5755
|
function getOpenBranches(projectDir) {
|
|
@@ -6171,7 +6214,7 @@ function loadSlicerTemplate(templateDir) {
|
|
|
6171
6214
|
if (cachedTemplate) {
|
|
6172
6215
|
return cachedTemplate;
|
|
6173
6216
|
}
|
|
6174
|
-
const templatePath = templateDir ? path14.join(templateDir, "
|
|
6217
|
+
const templatePath = templateDir ? path14.join(templateDir, "slicer.md") : path14.resolve(__dirname, "..", "..", "templates", "slicer.md");
|
|
6175
6218
|
try {
|
|
6176
6219
|
cachedTemplate = fs15.readFileSync(templatePath, "utf-8");
|
|
6177
6220
|
return cachedTemplate;
|
|
@@ -6600,7 +6643,8 @@ async function sliceNextItem(projectDir, config) {
|
|
|
6600
6643
|
}
|
|
6601
6644
|
return void 0;
|
|
6602
6645
|
};
|
|
6603
|
-
const
|
|
6646
|
+
const roadmapFirst = config.roadmapScanner.priorityMode !== "audit-first";
|
|
6647
|
+
const targetItem = roadmapFirst ? pickEligibleItem(roadmapItems) ?? pickEligibleItem(auditItems) : pickEligibleItem(auditItems) ?? pickEligibleItem(roadmapItems);
|
|
6604
6648
|
if (!targetItem) {
|
|
6605
6649
|
return {
|
|
6606
6650
|
sliced: false,
|
|
@@ -7255,10 +7299,13 @@ __export(dist_exports, {
|
|
|
7255
7299
|
extractCategory: () => extractCategory,
|
|
7256
7300
|
extractHorizon: () => extractHorizon,
|
|
7257
7301
|
extractPriority: () => extractPriority,
|
|
7302
|
+
extractQaScreenshotUrls: () => extractQaScreenshotUrls,
|
|
7258
7303
|
extractSummary: () => extractSummary,
|
|
7304
|
+
fetchLatestQaCommentBody: () => fetchLatestQaCommentBody,
|
|
7259
7305
|
fetchPrDetails: () => fetchPrDetails,
|
|
7260
7306
|
fetchPrDetailsByNumber: () => fetchPrDetailsByNumber,
|
|
7261
7307
|
fetchPrDetailsForBranch: () => fetchPrDetailsForBranch,
|
|
7308
|
+
fetchQaScreenshotUrlsForPr: () => fetchQaScreenshotUrlsForPr,
|
|
7262
7309
|
fetchReviewedPrDetails: () => fetchReviewedPrDetails,
|
|
7263
7310
|
fetchStatusSnapshot: () => fetchStatusSnapshot,
|
|
7264
7311
|
findEligibleBoardIssue: () => findEligibleBoardIssue,
|
|
@@ -7757,21 +7804,21 @@ function initCommand(program2) {
|
|
|
7757
7804
|
const customTemplatesDirPath = path17.join(cwd, existingConfig.templatesDir);
|
|
7758
7805
|
const customTemplatesDir = fs18.existsSync(customTemplatesDirPath) ? customTemplatesDirPath : null;
|
|
7759
7806
|
const templateSources = [];
|
|
7760
|
-
const nwResolution = resolveTemplatePath("
|
|
7761
|
-
const nwResult = processTemplate("
|
|
7762
|
-
templateSources.push({ name: "
|
|
7807
|
+
const nwResolution = resolveTemplatePath("executor.md", customTemplatesDir, TEMPLATES_DIR);
|
|
7808
|
+
const nwResult = processTemplate("executor.md", path17.join(instructionsDir, "executor.md"), replacements, force, nwResolution.path, nwResolution.source);
|
|
7809
|
+
templateSources.push({ name: "executor.md", source: nwResult.source });
|
|
7763
7810
|
const peResolution = resolveTemplatePath("prd-executor.md", customTemplatesDir, TEMPLATES_DIR);
|
|
7764
7811
|
const peResult = processTemplate("prd-executor.md", path17.join(instructionsDir, "prd-executor.md"), replacements, force, peResolution.path, peResolution.source);
|
|
7765
7812
|
templateSources.push({ name: "prd-executor.md", source: peResult.source });
|
|
7766
|
-
const prResolution = resolveTemplatePath("
|
|
7767
|
-
const prResult = processTemplate("
|
|
7768
|
-
templateSources.push({ name: "
|
|
7769
|
-
const qaResolution = resolveTemplatePath("
|
|
7770
|
-
const qaResult = processTemplate("
|
|
7771
|
-
templateSources.push({ name: "
|
|
7772
|
-
const auditResolution = resolveTemplatePath("
|
|
7773
|
-
const auditResult = processTemplate("
|
|
7774
|
-
templateSources.push({ name: "
|
|
7813
|
+
const prResolution = resolveTemplatePath("pr-reviewer.md", customTemplatesDir, TEMPLATES_DIR);
|
|
7814
|
+
const prResult = processTemplate("pr-reviewer.md", path17.join(instructionsDir, "pr-reviewer.md"), replacements, force, prResolution.path, prResolution.source);
|
|
7815
|
+
templateSources.push({ name: "pr-reviewer.md", source: prResult.source });
|
|
7816
|
+
const qaResolution = resolveTemplatePath("qa.md", customTemplatesDir, TEMPLATES_DIR);
|
|
7817
|
+
const qaResult = processTemplate("qa.md", path17.join(instructionsDir, "qa.md"), replacements, force, qaResolution.path, qaResolution.source);
|
|
7818
|
+
templateSources.push({ name: "qa.md", source: qaResult.source });
|
|
7819
|
+
const auditResolution = resolveTemplatePath("audit.md", customTemplatesDir, TEMPLATES_DIR);
|
|
7820
|
+
const auditResult = processTemplate("audit.md", path17.join(instructionsDir, "audit.md"), replacements, force, auditResolution.path, auditResolution.source);
|
|
7821
|
+
templateSources.push({ name: "audit.md", source: auditResult.source });
|
|
7775
7822
|
step(8, totalSteps, "Creating configuration file...");
|
|
7776
7823
|
const configPath = path17.join(cwd, CONFIG_FILE_NAME);
|
|
7777
7824
|
if (fs18.existsSync(configPath) && !force) {
|
|
@@ -7837,15 +7884,12 @@ function initCommand(program2) {
|
|
|
7837
7884
|
filesTable.push(["Logs Directory", `${LOG_DIR}/`]);
|
|
7838
7885
|
filesTable.push([
|
|
7839
7886
|
"Instructions",
|
|
7840
|
-
`instructions/
|
|
7887
|
+
`instructions/executor.md (${templateSources[0].source})`
|
|
7841
7888
|
]);
|
|
7842
7889
|
filesTable.push(["", `instructions/prd-executor.md (${templateSources[1].source})`]);
|
|
7843
|
-
filesTable.push([
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
]);
|
|
7847
|
-
filesTable.push(["", `instructions/night-watch-qa.md (${templateSources[3].source})`]);
|
|
7848
|
-
filesTable.push(["", `instructions/night-watch-audit.md (${templateSources[4].source})`]);
|
|
7890
|
+
filesTable.push(["", `instructions/pr-reviewer.md (${templateSources[2].source})`]);
|
|
7891
|
+
filesTable.push(["", `instructions/qa.md (${templateSources[3].source})`]);
|
|
7892
|
+
filesTable.push(["", `instructions/audit.md (${templateSources[4].source})`]);
|
|
7849
7893
|
filesTable.push(["Config File", CONFIG_FILE_NAME]);
|
|
7850
7894
|
filesTable.push(["Global Registry", "~/.night-watch/projects.json"]);
|
|
7851
7895
|
console.log(filesTable.toString());
|
|
@@ -7861,6 +7905,47 @@ function initCommand(program2) {
|
|
|
7861
7905
|
});
|
|
7862
7906
|
}
|
|
7863
7907
|
init_dist();
|
|
7908
|
+
init_dist();
|
|
7909
|
+
function deriveProviderLabel(config, jobType) {
|
|
7910
|
+
if (config.providerLabel)
|
|
7911
|
+
return config.providerLabel;
|
|
7912
|
+
const provider = resolveJobProvider(config, jobType);
|
|
7913
|
+
if (provider === "codex")
|
|
7914
|
+
return "Codex";
|
|
7915
|
+
if (config.providerEnv?.ANTHROPIC_BASE_URL)
|
|
7916
|
+
return "Claude (proxy)";
|
|
7917
|
+
return "Claude";
|
|
7918
|
+
}
|
|
7919
|
+
function buildBaseEnvVars(config, jobType, isDryRun) {
|
|
7920
|
+
const env = {};
|
|
7921
|
+
env.NW_PROVIDER_CMD = PROVIDER_COMMANDS[resolveJobProvider(config, jobType)];
|
|
7922
|
+
env.NW_PROVIDER_LABEL = deriveProviderLabel(config, jobType);
|
|
7923
|
+
if (config.defaultBranch) {
|
|
7924
|
+
env.NW_DEFAULT_BRANCH = config.defaultBranch;
|
|
7925
|
+
}
|
|
7926
|
+
if (config.providerEnv) {
|
|
7927
|
+
Object.assign(env, config.providerEnv);
|
|
7928
|
+
}
|
|
7929
|
+
if (isDryRun) {
|
|
7930
|
+
env.NW_DRY_RUN = "1";
|
|
7931
|
+
}
|
|
7932
|
+
env.NW_EXECUTION_CONTEXT = "agent";
|
|
7933
|
+
return env;
|
|
7934
|
+
}
|
|
7935
|
+
function formatProviderDisplay(providerCmd, providerLabel) {
|
|
7936
|
+
const cmd = providerCmd?.trim();
|
|
7937
|
+
if (!cmd)
|
|
7938
|
+
return "unknown";
|
|
7939
|
+
const label2 = providerLabel?.trim();
|
|
7940
|
+
if (!label2)
|
|
7941
|
+
return cmd;
|
|
7942
|
+
if (label2.toLowerCase() === cmd.toLowerCase())
|
|
7943
|
+
return cmd;
|
|
7944
|
+
return `${cmd} (${label2})`;
|
|
7945
|
+
}
|
|
7946
|
+
function getTelegramStatusWebhooks(config) {
|
|
7947
|
+
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 }));
|
|
7948
|
+
}
|
|
7864
7949
|
function resolveRunNotificationEvent(exitCode, scriptStatus) {
|
|
7865
7950
|
if (exitCode === 124) {
|
|
7866
7951
|
return "run_timeout";
|
|
@@ -7984,25 +8069,13 @@ function isRateLimitFallbackTriggered(resultData) {
|
|
|
7984
8069
|
return resultData?.rate_limit_fallback === "1";
|
|
7985
8070
|
}
|
|
7986
8071
|
function buildEnvVars(config, options) {
|
|
7987
|
-
const env =
|
|
7988
|
-
const executorProvider = resolveJobProvider(config, "executor");
|
|
7989
|
-
env.NW_PROVIDER_CMD = PROVIDER_COMMANDS[executorProvider];
|
|
7990
|
-
if (config.defaultBranch) {
|
|
7991
|
-
env.NW_DEFAULT_BRANCH = config.defaultBranch;
|
|
7992
|
-
}
|
|
8072
|
+
const env = buildBaseEnvVars(config, "executor", options.dryRun);
|
|
7993
8073
|
env.NW_MAX_RUNTIME = String(config.maxRuntime);
|
|
7994
8074
|
env.NW_PRD_DIR = config.prdDir;
|
|
7995
8075
|
env.NW_BRANCH_PREFIX = config.branchPrefix;
|
|
7996
|
-
if (config.providerEnv) {
|
|
7997
|
-
Object.assign(env, config.providerEnv);
|
|
7998
|
-
}
|
|
7999
8076
|
if (config.prdPriority && config.prdPriority.length > 0) {
|
|
8000
8077
|
env.NW_PRD_PRIORITY = config.prdPriority.join(":");
|
|
8001
8078
|
}
|
|
8002
|
-
if (options.dryRun) {
|
|
8003
|
-
env.NW_DRY_RUN = "1";
|
|
8004
|
-
}
|
|
8005
|
-
env.NW_EXECUTION_CONTEXT = "agent";
|
|
8006
8079
|
const maxRetries = Number.isFinite(config.maxRetries) ? Math.max(1, Math.floor(config.maxRetries)) : 3;
|
|
8007
8080
|
env.NW_MAX_RETRIES = String(maxRetries);
|
|
8008
8081
|
if (process.argv[1]) {
|
|
@@ -8234,28 +8307,18 @@ function parseFinalReviewScore(raw) {
|
|
|
8234
8307
|
return parsed;
|
|
8235
8308
|
}
|
|
8236
8309
|
function buildEnvVars2(config, options) {
|
|
8237
|
-
const env =
|
|
8238
|
-
const reviewerProvider = resolveJobProvider(config, "reviewer");
|
|
8239
|
-
env.NW_PROVIDER_CMD = PROVIDER_COMMANDS[reviewerProvider];
|
|
8240
|
-
if (config.defaultBranch) {
|
|
8241
|
-
env.NW_DEFAULT_BRANCH = config.defaultBranch;
|
|
8242
|
-
}
|
|
8310
|
+
const env = buildBaseEnvVars(config, "reviewer", options.dryRun);
|
|
8243
8311
|
env.NW_REVIEWER_MAX_RUNTIME = String(config.reviewerMaxRuntime);
|
|
8244
8312
|
env.NW_REVIEWER_MAX_RETRIES = String(config.reviewerMaxRetries);
|
|
8245
8313
|
env.NW_REVIEWER_RETRY_DELAY = String(config.reviewerRetryDelay);
|
|
8246
8314
|
env.NW_MIN_REVIEW_SCORE = String(config.minReviewScore);
|
|
8247
8315
|
env.NW_BRANCH_PATTERNS = config.branchPatterns.join(",");
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
}
|
|
8316
|
+
env.NW_PRD_DIR = config.prdDir;
|
|
8317
|
+
env.NW_CLAUDE_MODEL_ID = CLAUDE_MODEL_IDS[config.claudeModel ?? "sonnet"];
|
|
8251
8318
|
if (config.autoMerge) {
|
|
8252
8319
|
env.NW_AUTO_MERGE = "1";
|
|
8253
8320
|
}
|
|
8254
8321
|
env.NW_AUTO_MERGE_METHOD = config.autoMergeMethod;
|
|
8255
|
-
if (options.dryRun) {
|
|
8256
|
-
env.NW_DRY_RUN = "1";
|
|
8257
|
-
}
|
|
8258
|
-
env.NW_EXECUTION_CONTEXT = "agent";
|
|
8259
8322
|
return env;
|
|
8260
8323
|
}
|
|
8261
8324
|
function applyCliOverrides2(config, options) {
|
|
@@ -8433,7 +8496,7 @@ ${stderr}`);
|
|
|
8433
8496
|
event: "review_completed",
|
|
8434
8497
|
projectName: path19.basename(projectDir),
|
|
8435
8498
|
exitCode,
|
|
8436
|
-
provider:
|
|
8499
|
+
provider: formatProviderDisplay(envVars.NW_PROVIDER_CMD, envVars.NW_PROVIDER_LABEL),
|
|
8437
8500
|
prUrl: prDetails?.url,
|
|
8438
8501
|
prTitle: prDetails?.title,
|
|
8439
8502
|
prBody: prDetails?.body,
|
|
@@ -8454,7 +8517,7 @@ ${stderr}`);
|
|
|
8454
8517
|
event: "pr_auto_merged",
|
|
8455
8518
|
projectName: path19.basename(projectDir),
|
|
8456
8519
|
exitCode,
|
|
8457
|
-
provider:
|
|
8520
|
+
provider: formatProviderDisplay(envVars.NW_PROVIDER_CMD, envVars.NW_PROVIDER_LABEL),
|
|
8458
8521
|
prNumber: autoMergedPrDetails?.number ?? autoMergedPrNumber,
|
|
8459
8522
|
prUrl: autoMergedPrDetails?.url,
|
|
8460
8523
|
prTitle: autoMergedPrDetails?.title,
|
|
@@ -8496,35 +8559,28 @@ function parseQaPrNumbers(prsRaw) {
|
|
|
8496
8559
|
}
|
|
8497
8560
|
return numbers;
|
|
8498
8561
|
}
|
|
8499
|
-
function
|
|
8500
|
-
|
|
8562
|
+
function parseRepoFromPrUrl(prUrl) {
|
|
8563
|
+
if (!prUrl) {
|
|
8564
|
+
return void 0;
|
|
8565
|
+
}
|
|
8566
|
+
const match = prUrl.match(/^https?:\/\/github\.com\/([^/]+\/[^/]+)\/pull\/\d+/i);
|
|
8567
|
+
return match?.[1];
|
|
8501
8568
|
}
|
|
8502
8569
|
function buildEnvVars3(config, options) {
|
|
8503
|
-
const env =
|
|
8504
|
-
const qaProvider = resolveJobProvider(config, "qa");
|
|
8505
|
-
env.NW_PROVIDER_CMD = PROVIDER_COMMANDS[qaProvider];
|
|
8506
|
-
if (config.defaultBranch) {
|
|
8507
|
-
env.NW_DEFAULT_BRANCH = config.defaultBranch;
|
|
8508
|
-
}
|
|
8570
|
+
const env = buildBaseEnvVars(config, "qa", options.dryRun);
|
|
8509
8571
|
env.NW_QA_MAX_RUNTIME = String(config.qa.maxRuntime);
|
|
8510
8572
|
const branchPatterns = config.qa.branchPatterns.length > 0 ? config.qa.branchPatterns : config.branchPatterns;
|
|
8511
8573
|
env.NW_BRANCH_PATTERNS = branchPatterns.join(",");
|
|
8512
8574
|
env.NW_QA_SKIP_LABEL = config.qa.skipLabel;
|
|
8513
8575
|
env.NW_QA_ARTIFACTS = config.qa.artifacts;
|
|
8514
8576
|
env.NW_QA_AUTO_INSTALL_PLAYWRIGHT = config.qa.autoInstallPlaywright ? "1" : "0";
|
|
8515
|
-
|
|
8516
|
-
Object.assign(env, config.providerEnv);
|
|
8517
|
-
}
|
|
8577
|
+
env.NW_CLAUDE_MODEL_ID = CLAUDE_MODEL_IDS[config.claudeModel ?? "sonnet"];
|
|
8518
8578
|
const telegramWebhooks = getTelegramStatusWebhooks(config);
|
|
8519
8579
|
if (telegramWebhooks.length > 0) {
|
|
8520
8580
|
env.NW_TELEGRAM_STATUS_WEBHOOKS = JSON.stringify(telegramWebhooks);
|
|
8521
8581
|
env.NW_TELEGRAM_BOT_TOKEN = telegramWebhooks[0].botToken;
|
|
8522
8582
|
env.NW_TELEGRAM_CHAT_ID = telegramWebhooks[0].chatId;
|
|
8523
8583
|
}
|
|
8524
|
-
if (options.dryRun) {
|
|
8525
|
-
env.NW_DRY_RUN = "1";
|
|
8526
|
-
}
|
|
8527
|
-
env.NW_EXECUTION_CONTEXT = "agent";
|
|
8528
8584
|
return env;
|
|
8529
8585
|
}
|
|
8530
8586
|
function applyCliOverrides3(config, options) {
|
|
@@ -8604,20 +8660,22 @@ ${stderr}`);
|
|
|
8604
8660
|
const qaPrNumbers = parseQaPrNumbers(scriptResult?.data.prs);
|
|
8605
8661
|
const primaryQaPr = qaPrNumbers[0];
|
|
8606
8662
|
const prDetails = primaryQaPr ? fetchPrDetailsByNumber(primaryQaPr, projectDir) : null;
|
|
8607
|
-
const repo = scriptResult?.data.repo;
|
|
8663
|
+
const repo = scriptResult?.data.repo ?? parseRepoFromPrUrl(prDetails?.url);
|
|
8608
8664
|
const fallbackPrUrl = !prDetails?.url && primaryQaPr && repo ? `https://github.com/${repo}/pull/${primaryQaPr}` : void 0;
|
|
8665
|
+
const qaScreenshotUrls = primaryQaPr !== void 0 ? fetchQaScreenshotUrlsForPr(primaryQaPr, projectDir, repo) : [];
|
|
8609
8666
|
const _qaCtx = {
|
|
8610
8667
|
event: "qa_completed",
|
|
8611
8668
|
projectName: path20.basename(projectDir),
|
|
8612
8669
|
exitCode,
|
|
8613
|
-
provider:
|
|
8670
|
+
provider: formatProviderDisplay(envVars.NW_PROVIDER_CMD, envVars.NW_PROVIDER_LABEL),
|
|
8614
8671
|
prNumber: prDetails?.number ?? primaryQaPr,
|
|
8615
8672
|
prUrl: prDetails?.url ?? fallbackPrUrl,
|
|
8616
8673
|
prTitle: prDetails?.title,
|
|
8617
8674
|
prBody: prDetails?.body,
|
|
8618
8675
|
filesChanged: prDetails?.changedFiles,
|
|
8619
8676
|
additions: prDetails?.additions,
|
|
8620
|
-
deletions: prDetails?.deletions
|
|
8677
|
+
deletions: prDetails?.deletions,
|
|
8678
|
+
qaScreenshotUrls
|
|
8621
8679
|
};
|
|
8622
8680
|
await sendNotifications(config, _qaCtx);
|
|
8623
8681
|
}
|
|
@@ -8631,30 +8689,16 @@ ${stderr}`);
|
|
|
8631
8689
|
});
|
|
8632
8690
|
}
|
|
8633
8691
|
init_dist();
|
|
8634
|
-
function getTelegramStatusWebhooks2(config) {
|
|
8635
|
-
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 }));
|
|
8636
|
-
}
|
|
8637
8692
|
function buildEnvVars4(config, options) {
|
|
8638
|
-
const env =
|
|
8639
|
-
const auditProvider = resolveJobProvider(config, "audit");
|
|
8640
|
-
env.NW_PROVIDER_CMD = PROVIDER_COMMANDS[auditProvider];
|
|
8693
|
+
const env = buildBaseEnvVars(config, "audit", options.dryRun);
|
|
8641
8694
|
env.NW_AUDIT_MAX_RUNTIME = String(config.audit.maxRuntime);
|
|
8642
|
-
|
|
8643
|
-
|
|
8644
|
-
}
|
|
8645
|
-
if (config.providerEnv) {
|
|
8646
|
-
Object.assign(env, config.providerEnv);
|
|
8647
|
-
}
|
|
8648
|
-
const telegramWebhooks = getTelegramStatusWebhooks2(config);
|
|
8695
|
+
env.NW_CLAUDE_MODEL_ID = CLAUDE_MODEL_IDS[config.claudeModel ?? "sonnet"];
|
|
8696
|
+
const telegramWebhooks = getTelegramStatusWebhooks(config);
|
|
8649
8697
|
if (telegramWebhooks.length > 0) {
|
|
8650
8698
|
env.NW_TELEGRAM_STATUS_WEBHOOKS = JSON.stringify(telegramWebhooks);
|
|
8651
8699
|
env.NW_TELEGRAM_BOT_TOKEN = telegramWebhooks[0].botToken;
|
|
8652
8700
|
env.NW_TELEGRAM_CHAT_ID = telegramWebhooks[0].chatId;
|
|
8653
8701
|
}
|
|
8654
|
-
if (options.dryRun) {
|
|
8655
|
-
env.NW_DRY_RUN = "1";
|
|
8656
|
-
}
|
|
8657
|
-
env.NW_EXECUTION_CONTEXT = "agent";
|
|
8658
8702
|
return env;
|
|
8659
8703
|
}
|
|
8660
8704
|
function auditCommand(program2) {
|
|
@@ -12516,6 +12560,15 @@ function validateConfigChanges(changes) {
|
|
|
12516
12560
|
return `Invalid provider. Must be one of: ${validProviders.join(", ")}`;
|
|
12517
12561
|
}
|
|
12518
12562
|
}
|
|
12563
|
+
if (changes.providerLabel !== void 0 && typeof changes.providerLabel !== "string") {
|
|
12564
|
+
return "providerLabel must be a string";
|
|
12565
|
+
}
|
|
12566
|
+
if (changes.defaultBranch !== void 0 && typeof changes.defaultBranch !== "string") {
|
|
12567
|
+
return "defaultBranch must be a string";
|
|
12568
|
+
}
|
|
12569
|
+
if (changes.branchPrefix !== void 0 && (typeof changes.branchPrefix !== "string" || changes.branchPrefix.trim().length === 0)) {
|
|
12570
|
+
return "branchPrefix must be a non-empty string";
|
|
12571
|
+
}
|
|
12519
12572
|
if (changes.reviewerEnabled !== void 0 && typeof changes.reviewerEnabled !== "boolean") {
|
|
12520
12573
|
return "reviewerEnabled must be a boolean";
|
|
12521
12574
|
}
|
|
@@ -12534,6 +12587,15 @@ function validateConfigChanges(changes) {
|
|
|
12534
12587
|
if (changes.maxLogSize !== void 0 && (typeof changes.maxLogSize !== "number" || changes.maxLogSize < 0)) {
|
|
12535
12588
|
return "maxLogSize must be a positive number";
|
|
12536
12589
|
}
|
|
12590
|
+
if (changes.maxRetries !== void 0 && (typeof changes.maxRetries !== "number" || !Number.isInteger(changes.maxRetries) || changes.maxRetries < 1)) {
|
|
12591
|
+
return "maxRetries must be an integer >= 1";
|
|
12592
|
+
}
|
|
12593
|
+
if (changes.reviewerMaxRetries !== void 0 && (typeof changes.reviewerMaxRetries !== "number" || !Number.isInteger(changes.reviewerMaxRetries) || changes.reviewerMaxRetries < 0 || changes.reviewerMaxRetries > 10)) {
|
|
12594
|
+
return "reviewerMaxRetries must be an integer between 0 and 10";
|
|
12595
|
+
}
|
|
12596
|
+
if (changes.reviewerRetryDelay !== void 0 && (typeof changes.reviewerRetryDelay !== "number" || !Number.isInteger(changes.reviewerRetryDelay) || changes.reviewerRetryDelay < 0 || changes.reviewerRetryDelay > 300)) {
|
|
12597
|
+
return "reviewerRetryDelay must be an integer between 0 and 300";
|
|
12598
|
+
}
|
|
12537
12599
|
if (changes.branchPatterns !== void 0 && (!Array.isArray(changes.branchPatterns) || !changes.branchPatterns.every((p) => typeof p === "string"))) {
|
|
12538
12600
|
return "branchPatterns must be an array of strings";
|
|
12539
12601
|
}
|
|
@@ -12572,6 +12634,19 @@ function validateConfigChanges(changes) {
|
|
|
12572
12634
|
return "roadmapScanner.autoScanInterval must be a number >= 30";
|
|
12573
12635
|
}
|
|
12574
12636
|
}
|
|
12637
|
+
if (changes.providerEnv !== void 0) {
|
|
12638
|
+
if (typeof changes.providerEnv !== "object" || changes.providerEnv === null) {
|
|
12639
|
+
return "providerEnv must be an object";
|
|
12640
|
+
}
|
|
12641
|
+
for (const [key, value] of Object.entries(changes.providerEnv)) {
|
|
12642
|
+
if (key.trim().length === 0) {
|
|
12643
|
+
return "providerEnv keys must be non-empty strings";
|
|
12644
|
+
}
|
|
12645
|
+
if (typeof value !== "string") {
|
|
12646
|
+
return "providerEnv values must be strings";
|
|
12647
|
+
}
|
|
12648
|
+
}
|
|
12649
|
+
}
|
|
12575
12650
|
if (changes.autoMerge !== void 0 && typeof changes.autoMerge !== "boolean") {
|
|
12576
12651
|
return "autoMerge must be a boolean";
|
|
12577
12652
|
}
|
|
@@ -12597,6 +12672,9 @@ function validateConfigChanges(changes) {
|
|
|
12597
12672
|
if (changes.prdDir !== void 0 && (typeof changes.prdDir !== "string" || changes.prdDir.trim().length === 0)) {
|
|
12598
12673
|
return "prdDir must be a non-empty string";
|
|
12599
12674
|
}
|
|
12675
|
+
if (changes.templatesDir !== void 0 && (typeof changes.templatesDir !== "string" || changes.templatesDir.trim().length === 0)) {
|
|
12676
|
+
return "templatesDir must be a non-empty string";
|
|
12677
|
+
}
|
|
12600
12678
|
if (changes.cronScheduleOffset !== void 0 && (typeof changes.cronScheduleOffset !== "number" || changes.cronScheduleOffset < 0 || changes.cronScheduleOffset > 59)) {
|
|
12601
12679
|
return "cronScheduleOffset must be a number between 0 and 59";
|
|
12602
12680
|
}
|
|
@@ -12661,11 +12739,26 @@ function validateConfigChanges(changes) {
|
|
|
12661
12739
|
if (rs.slicerMaxRuntime !== void 0 && (typeof rs.slicerMaxRuntime !== "number" || rs.slicerMaxRuntime < 60)) {
|
|
12662
12740
|
return "roadmapScanner.slicerMaxRuntime must be a number >= 60";
|
|
12663
12741
|
}
|
|
12742
|
+
if (rs.priorityMode !== void 0 && rs.priorityMode !== "roadmap-first" && rs.priorityMode !== "audit-first") {
|
|
12743
|
+
return "roadmapScanner.priorityMode must be one of: roadmap-first, audit-first";
|
|
12744
|
+
}
|
|
12745
|
+
if (rs.issueColumn !== void 0 && rs.issueColumn !== "Draft" && rs.issueColumn !== "Ready") {
|
|
12746
|
+
return "roadmapScanner.issueColumn must be one of: Draft, Ready";
|
|
12747
|
+
}
|
|
12664
12748
|
}
|
|
12665
12749
|
if (changes.boardProvider !== void 0) {
|
|
12666
12750
|
if (typeof changes.boardProvider !== "object" || changes.boardProvider === null) {
|
|
12667
12751
|
return "boardProvider must be an object";
|
|
12668
12752
|
}
|
|
12753
|
+
if (changes.boardProvider.provider !== void 0 && !["github", "jira", "linear", "local"].includes(changes.boardProvider.provider)) {
|
|
12754
|
+
return "boardProvider.provider must be one of: github, jira, linear, local";
|
|
12755
|
+
}
|
|
12756
|
+
if (changes.boardProvider.projectNumber !== void 0 && (typeof changes.boardProvider.projectNumber !== "number" || !Number.isInteger(changes.boardProvider.projectNumber) || changes.boardProvider.projectNumber <= 0)) {
|
|
12757
|
+
return "boardProvider.projectNumber must be an integer > 0";
|
|
12758
|
+
}
|
|
12759
|
+
if (changes.boardProvider.repo !== void 0 && (typeof changes.boardProvider.repo !== "string" || changes.boardProvider.repo.trim().length === 0)) {
|
|
12760
|
+
return "boardProvider.repo must be a non-empty string";
|
|
12761
|
+
}
|
|
12669
12762
|
if (changes.boardProvider.enabled !== void 0 && typeof changes.boardProvider.enabled !== "boolean") {
|
|
12670
12763
|
return "boardProvider.enabled must be a boolean";
|
|
12671
12764
|
}
|
|
@@ -14035,9 +14128,6 @@ function cancelCommand(program2) {
|
|
|
14035
14128
|
});
|
|
14036
14129
|
}
|
|
14037
14130
|
init_dist();
|
|
14038
|
-
function getTelegramStatusWebhooks3(config) {
|
|
14039
|
-
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 }));
|
|
14040
|
-
}
|
|
14041
14131
|
function plannerLockPath2(projectDir) {
|
|
14042
14132
|
return `${LOCK_FILE_PREFIX}slicer-${projectRuntimeKey(projectDir)}.lock`;
|
|
14043
14133
|
}
|
|
@@ -14065,26 +14155,85 @@ function releasePlannerLock(lockFile) {
|
|
|
14065
14155
|
} catch {
|
|
14066
14156
|
}
|
|
14067
14157
|
}
|
|
14158
|
+
function resolvePlannerIssueColumn(config) {
|
|
14159
|
+
return config.roadmapScanner.issueColumn === "Ready" ? "Ready" : "Draft";
|
|
14160
|
+
}
|
|
14161
|
+
function buildPlannerIssueBody(projectDir, config, result) {
|
|
14162
|
+
const relativePrdPath = path35.join(config.prdDir, result.file ?? "").replace(/\\/g, "/");
|
|
14163
|
+
const absolutePrdPath = path35.join(projectDir, config.prdDir, result.file ?? "");
|
|
14164
|
+
const sourceItem = result.item;
|
|
14165
|
+
let prdContent = "";
|
|
14166
|
+
try {
|
|
14167
|
+
prdContent = fs35.readFileSync(absolutePrdPath, "utf-8");
|
|
14168
|
+
} catch {
|
|
14169
|
+
prdContent = `Unable to read generated PRD file at \`${relativePrdPath}\`.`;
|
|
14170
|
+
}
|
|
14171
|
+
const maxBodyChars = 6e4;
|
|
14172
|
+
const truncated = prdContent.length > maxBodyChars;
|
|
14173
|
+
const prdPreview = truncated ? `${prdContent.slice(0, maxBodyChars)}
|
|
14174
|
+
|
|
14175
|
+
...[truncated]` : prdContent;
|
|
14176
|
+
const sourceLines = sourceItem ? [
|
|
14177
|
+
`- Source section: ${sourceItem.section}`,
|
|
14178
|
+
`- Source item: ${sourceItem.title}`,
|
|
14179
|
+
sourceItem.description ? `- Source summary: ${sourceItem.description}` : ""
|
|
14180
|
+
].filter((line) => line.length > 0) : [];
|
|
14181
|
+
return [
|
|
14182
|
+
"## Planner Generated PRD",
|
|
14183
|
+
"",
|
|
14184
|
+
`- PRD file: \`${relativePrdPath}\``,
|
|
14185
|
+
...sourceLines,
|
|
14186
|
+
"",
|
|
14187
|
+
"---",
|
|
14188
|
+
"",
|
|
14189
|
+
prdPreview
|
|
14190
|
+
].join("\n");
|
|
14191
|
+
}
|
|
14192
|
+
async function createPlannerIssue(projectDir, config, result) {
|
|
14193
|
+
if (!result.sliced || !result.file || !result.item) {
|
|
14194
|
+
return { created: false, skippedReason: "nothing-created" };
|
|
14195
|
+
}
|
|
14196
|
+
if (!config.boardProvider?.enabled) {
|
|
14197
|
+
return { created: false, skippedReason: "board-disabled" };
|
|
14198
|
+
}
|
|
14199
|
+
const provider = createBoardProvider(config.boardProvider, projectDir);
|
|
14200
|
+
const board = await provider.getBoard();
|
|
14201
|
+
if (!board) {
|
|
14202
|
+
return { created: false, skippedReason: "board-not-configured" };
|
|
14203
|
+
}
|
|
14204
|
+
const existingIssues = await provider.getAllIssues();
|
|
14205
|
+
const existing = existingIssues.find((issue2) => issue2.title.trim().toLowerCase() === result.item.title.trim().toLowerCase());
|
|
14206
|
+
if (existing) {
|
|
14207
|
+
return {
|
|
14208
|
+
created: false,
|
|
14209
|
+
skippedReason: "already-exists",
|
|
14210
|
+
issueNumber: existing.number,
|
|
14211
|
+
issueUrl: existing.url
|
|
14212
|
+
};
|
|
14213
|
+
}
|
|
14214
|
+
const issue = await provider.createIssue({
|
|
14215
|
+
title: result.item.title,
|
|
14216
|
+
body: buildPlannerIssueBody(projectDir, config, result),
|
|
14217
|
+
column: resolvePlannerIssueColumn(config)
|
|
14218
|
+
});
|
|
14219
|
+
return {
|
|
14220
|
+
created: true,
|
|
14221
|
+
issueNumber: issue.number,
|
|
14222
|
+
issueUrl: issue.url
|
|
14223
|
+
};
|
|
14224
|
+
}
|
|
14068
14225
|
function buildEnvVars5(config, options) {
|
|
14069
|
-
const env =
|
|
14070
|
-
const slicerProvider = resolveJobProvider(config, "slicer");
|
|
14071
|
-
env.NW_PROVIDER_CMD = PROVIDER_COMMANDS[slicerProvider];
|
|
14226
|
+
const env = buildBaseEnvVars(config, "slicer", options.dryRun);
|
|
14072
14227
|
env.NW_SLICER_MAX_RUNTIME = String(config.roadmapScanner.slicerMaxRuntime);
|
|
14073
14228
|
env.NW_PRD_DIR = config.prdDir;
|
|
14074
14229
|
env.NW_ROADMAP_PATH = config.roadmapScanner.roadmapPath;
|
|
14075
|
-
|
|
14076
|
-
|
|
14077
|
-
}
|
|
14078
|
-
const telegramWebhooks = getTelegramStatusWebhooks3(config);
|
|
14230
|
+
env.NW_CLAUDE_MODEL_ID = CLAUDE_MODEL_IDS[config.claudeModel ?? "sonnet"];
|
|
14231
|
+
const telegramWebhooks = getTelegramStatusWebhooks(config);
|
|
14079
14232
|
if (telegramWebhooks.length > 0) {
|
|
14080
14233
|
env.NW_TELEGRAM_STATUS_WEBHOOKS = JSON.stringify(telegramWebhooks);
|
|
14081
14234
|
env.NW_TELEGRAM_BOT_TOKEN = telegramWebhooks[0].botToken;
|
|
14082
14235
|
env.NW_TELEGRAM_CHAT_ID = telegramWebhooks[0].chatId;
|
|
14083
14236
|
}
|
|
14084
|
-
if (options.dryRun) {
|
|
14085
|
-
env.NW_DRY_RUN = "1";
|
|
14086
|
-
}
|
|
14087
|
-
env.NW_EXECUTION_CONTEXT = "agent";
|
|
14088
14237
|
return env;
|
|
14089
14238
|
}
|
|
14090
14239
|
function applyCliOverrides4(config, options) {
|
|
@@ -14130,6 +14279,8 @@ function sliceCommand(program2) {
|
|
|
14130
14279
|
`${config.roadmapScanner.slicerMaxRuntime}s (${Math.floor(config.roadmapScanner.slicerMaxRuntime / 60)}min)`
|
|
14131
14280
|
]);
|
|
14132
14281
|
configTable.push(["Planner Schedule", config.roadmapScanner.slicerSchedule]);
|
|
14282
|
+
configTable.push(["Planner Priority Mode", config.roadmapScanner.priorityMode]);
|
|
14283
|
+
configTable.push(["Planner Issue Column", resolvePlannerIssueColumn(config)]);
|
|
14133
14284
|
configTable.push(["Scanner Enabled", config.roadmapScanner.enabled ? "Yes" : "No"]);
|
|
14134
14285
|
console.log(configTable.toString());
|
|
14135
14286
|
header("Roadmap Status");
|
|
@@ -14188,8 +14339,21 @@ function sliceCommand(program2) {
|
|
|
14188
14339
|
});
|
|
14189
14340
|
}
|
|
14190
14341
|
const result = await sliceNextItem(projectDir, config);
|
|
14342
|
+
let issueSummary = "";
|
|
14343
|
+
if (result.sliced) {
|
|
14344
|
+
try {
|
|
14345
|
+
const issueResult = await createPlannerIssue(projectDir, config, result);
|
|
14346
|
+
if (issueResult.created && issueResult.issueNumber) {
|
|
14347
|
+
issueSummary = `; issue #${issueResult.issueNumber} (${resolvePlannerIssueColumn(config)})`;
|
|
14348
|
+
} else if (issueResult.skippedReason === "already-exists" && issueResult.issueNumber) {
|
|
14349
|
+
issueSummary = `; existing issue #${issueResult.issueNumber}`;
|
|
14350
|
+
}
|
|
14351
|
+
} catch (issueError) {
|
|
14352
|
+
warn(`Planner created ${result.file} but failed to create board issue: ${issueError instanceof Error ? issueError.message : String(issueError)}`);
|
|
14353
|
+
}
|
|
14354
|
+
}
|
|
14191
14355
|
if (result.sliced) {
|
|
14192
|
-
spinner.succeed(`Planner completed successfully: Created ${result.file}`);
|
|
14356
|
+
spinner.succeed(`Planner completed successfully: Created ${result.file}${issueSummary}`);
|
|
14193
14357
|
} else if (result.error) {
|
|
14194
14358
|
if (result.error === "No pending items to process") {
|
|
14195
14359
|
spinner.succeed("No pending items to process");
|
|
@@ -14797,14 +14961,14 @@ var __dirname4 = dirname8(__filename3);
|
|
|
14797
14961
|
function findPackageRoot(dir) {
|
|
14798
14962
|
let d = dir;
|
|
14799
14963
|
for (let i = 0; i < 5; i++) {
|
|
14800
|
-
if (existsSync30(
|
|
14964
|
+
if (existsSync30(join34(d, "package.json")))
|
|
14801
14965
|
return d;
|
|
14802
14966
|
d = dirname8(d);
|
|
14803
14967
|
}
|
|
14804
14968
|
return dir;
|
|
14805
14969
|
}
|
|
14806
14970
|
var packageRoot = findPackageRoot(__dirname4);
|
|
14807
|
-
var packageJson = JSON.parse(readFileSync18(
|
|
14971
|
+
var packageJson = JSON.parse(readFileSync18(join34(packageRoot, "package.json"), "utf-8"));
|
|
14808
14972
|
var program = new Command2();
|
|
14809
14973
|
program.name("night-watch").description("Autonomous PRD execution using Claude CLI + cron").version(packageJson.version);
|
|
14810
14974
|
initCommand(program);
|