@jonit-dev/night-watch-cli 1.8.4-beta.0 → 1.8.4-beta.1
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 +307 -164
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +5 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/plan.d.ts +19 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/plan.js +88 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/prd.d.ts +8 -14
- package/dist/commands/prd.d.ts.map +1 -1
- package/dist/commands/prd.js +238 -145
- package/dist/commands/prd.js.map +1 -1
- package/dist/scripts/night-watch-plan-cron.sh +130 -0
- package/dist/templates/pr-reviewer.md +1 -1
- package/dist/templates/prd-creator.md +330 -0
- package/dist/templates/qa.md +8 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3792,7 +3792,7 @@ function getLockFilePaths(projectDir) {
|
|
|
3792
3792
|
};
|
|
3793
3793
|
}
|
|
3794
3794
|
function sleep(ms) {
|
|
3795
|
-
return new Promise((
|
|
3795
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
3796
3796
|
}
|
|
3797
3797
|
async function cancelProcess(processType, lockPath, force = false) {
|
|
3798
3798
|
const lockStatus = checkLockFile(lockPath);
|
|
@@ -5390,6 +5390,7 @@ var init_roadmap_state = __esm({
|
|
|
5390
5390
|
// ../core/dist/templates/slicer-prompt.js
|
|
5391
5391
|
import * as fs15 from "fs";
|
|
5392
5392
|
import * as path14 from "path";
|
|
5393
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5393
5394
|
function loadSlicerTemplate(templateDir) {
|
|
5394
5395
|
if (cachedTemplate) {
|
|
5395
5396
|
return cachedTemplate;
|
|
@@ -5425,10 +5426,12 @@ function createSlicerPromptVars(title, section, description, prdDir, prdFilename
|
|
|
5425
5426
|
prdDir
|
|
5426
5427
|
};
|
|
5427
5428
|
}
|
|
5428
|
-
var DEFAULT_SLICER_TEMPLATE, cachedTemplate;
|
|
5429
|
+
var __filename, __dirname, DEFAULT_SLICER_TEMPLATE, cachedTemplate;
|
|
5429
5430
|
var init_slicer_prompt = __esm({
|
|
5430
5431
|
"../core/dist/templates/slicer-prompt.js"() {
|
|
5431
5432
|
"use strict";
|
|
5433
|
+
__filename = fileURLToPath2(import.meta.url);
|
|
5434
|
+
__dirname = path14.dirname(__filename);
|
|
5432
5435
|
DEFAULT_SLICER_TEMPLATE = `You are a **PRD Creator Agent**. Your job: analyze the codebase and write a complete Product Requirements Document (PRD) for a feature.
|
|
5433
5436
|
|
|
5434
5437
|
When this activates: \`PRD Creator: Initializing\`
|
|
@@ -5702,11 +5705,11 @@ function scanExistingPrdSlugs(prdDir) {
|
|
|
5702
5705
|
}
|
|
5703
5706
|
return slugs;
|
|
5704
5707
|
}
|
|
5705
|
-
function buildProviderArgs(provider,
|
|
5708
|
+
function buildProviderArgs(provider, prompt, workingDir) {
|
|
5706
5709
|
if (provider === "codex") {
|
|
5707
|
-
return ["exec", "-C", workingDir, "--yolo",
|
|
5710
|
+
return ["exec", "-C", workingDir, "--yolo", prompt];
|
|
5708
5711
|
}
|
|
5709
|
-
return ["-p",
|
|
5712
|
+
return ["-p", prompt, "--dangerously-skip-permissions"];
|
|
5710
5713
|
}
|
|
5711
5714
|
async function sliceRoadmapItem(projectDir, prdDir, item, config) {
|
|
5712
5715
|
const itemSlug = slugify(item.title);
|
|
@@ -5726,9 +5729,9 @@ async function sliceRoadmapItem(projectDir, prdDir, item, config) {
|
|
|
5726
5729
|
fs16.mkdirSync(prdDir, { recursive: true });
|
|
5727
5730
|
}
|
|
5728
5731
|
const promptVars = createSlicerPromptVars(item.title, item.section, item.description, prdDir, filename);
|
|
5729
|
-
const
|
|
5732
|
+
const prompt = renderSlicerPrompt(promptVars);
|
|
5730
5733
|
const provider = resolveJobProvider(config, "slicer");
|
|
5731
|
-
const providerArgs = buildProviderArgs(provider,
|
|
5734
|
+
const providerArgs = buildProviderArgs(provider, prompt, projectDir);
|
|
5732
5735
|
const logDir = path15.join(projectDir, "logs");
|
|
5733
5736
|
if (!fs16.existsSync(logDir)) {
|
|
5734
5737
|
fs16.mkdirSync(logDir, { recursive: true });
|
|
@@ -5737,7 +5740,7 @@ async function sliceRoadmapItem(projectDir, prdDir, item, config) {
|
|
|
5737
5740
|
const logStream = fs16.createWriteStream(logFile, { flags: "w" });
|
|
5738
5741
|
logStream.on("error", () => {
|
|
5739
5742
|
});
|
|
5740
|
-
return new Promise((
|
|
5743
|
+
return new Promise((resolve9) => {
|
|
5741
5744
|
const childEnv = {
|
|
5742
5745
|
...process.env,
|
|
5743
5746
|
...config.providerEnv
|
|
@@ -5755,7 +5758,7 @@ async function sliceRoadmapItem(projectDir, prdDir, item, config) {
|
|
|
5755
5758
|
});
|
|
5756
5759
|
child.on("error", (error2) => {
|
|
5757
5760
|
logStream.end();
|
|
5758
|
-
|
|
5761
|
+
resolve9({
|
|
5759
5762
|
sliced: false,
|
|
5760
5763
|
error: `Failed to spawn provider: ${error2.message}`,
|
|
5761
5764
|
item
|
|
@@ -5764,7 +5767,7 @@ async function sliceRoadmapItem(projectDir, prdDir, item, config) {
|
|
|
5764
5767
|
child.on("close", (code) => {
|
|
5765
5768
|
logStream.end();
|
|
5766
5769
|
if (code !== 0) {
|
|
5767
|
-
|
|
5770
|
+
resolve9({
|
|
5768
5771
|
sliced: false,
|
|
5769
5772
|
error: `Provider exited with code ${code ?? 1}`,
|
|
5770
5773
|
item
|
|
@@ -5772,14 +5775,14 @@ async function sliceRoadmapItem(projectDir, prdDir, item, config) {
|
|
|
5772
5775
|
return;
|
|
5773
5776
|
}
|
|
5774
5777
|
if (!fs16.existsSync(filePath)) {
|
|
5775
|
-
|
|
5778
|
+
resolve9({
|
|
5776
5779
|
sliced: false,
|
|
5777
5780
|
error: `Provider did not create expected file: ${filePath}`,
|
|
5778
5781
|
item
|
|
5779
5782
|
});
|
|
5780
5783
|
return;
|
|
5781
5784
|
}
|
|
5782
|
-
|
|
5785
|
+
resolve9({
|
|
5783
5786
|
sliced: true,
|
|
5784
5787
|
file: filename,
|
|
5785
5788
|
item
|
|
@@ -5940,7 +5943,7 @@ async function executeScript(scriptPath, args = [], env = {}, options = {}) {
|
|
|
5940
5943
|
return result.exitCode;
|
|
5941
5944
|
}
|
|
5942
5945
|
async function executeScriptWithOutput(scriptPath, args = [], env = {}, options = {}) {
|
|
5943
|
-
return new Promise((
|
|
5946
|
+
return new Promise((resolve9, reject) => {
|
|
5944
5947
|
const childEnv = {
|
|
5945
5948
|
...process.env,
|
|
5946
5949
|
...env
|
|
@@ -5966,7 +5969,7 @@ async function executeScriptWithOutput(scriptPath, args = [], env = {}, options
|
|
|
5966
5969
|
reject(error2);
|
|
5967
5970
|
});
|
|
5968
5971
|
child.on("close", (code) => {
|
|
5969
|
-
|
|
5972
|
+
resolve9({
|
|
5970
5973
|
exitCode: code ?? 1,
|
|
5971
5974
|
stdout: stdoutChunks.join(""),
|
|
5972
5975
|
stderr: stderrChunks.join("")
|
|
@@ -6361,6 +6364,7 @@ function getLockPathForJob(projectPath, jobType) {
|
|
|
6361
6364
|
case "audit":
|
|
6362
6365
|
return auditLockPath(projectPath);
|
|
6363
6366
|
case "slicer":
|
|
6367
|
+
case "planner":
|
|
6364
6368
|
return plannerLockPath(projectPath);
|
|
6365
6369
|
case "analytics":
|
|
6366
6370
|
return analyticsLockPath(projectPath);
|
|
@@ -6917,13 +6921,13 @@ async function runAnalytics(config, projectDir) {
|
|
|
6917
6921
|
logger3.info("Fetching Amplitude data", { lookbackDays: config.analytics.lookbackDays });
|
|
6918
6922
|
const data = await fetchAmplitudeData(apiKey, secretKey, config.analytics.lookbackDays);
|
|
6919
6923
|
const systemPrompt = config.analytics.analysisPrompt?.trim() || DEFAULT_ANALYTICS_PROMPT;
|
|
6920
|
-
const
|
|
6924
|
+
const prompt = `${systemPrompt}
|
|
6921
6925
|
|
|
6922
6926
|
--- AMPLITUDE DATA ---
|
|
6923
6927
|
${JSON.stringify(data, null, 2)}`;
|
|
6924
6928
|
const tmpDir = fs19.mkdtempSync(path19.join(os8.tmpdir(), "nw-analytics-"));
|
|
6925
6929
|
const promptFile = path19.join(tmpDir, "analytics-prompt.md");
|
|
6926
|
-
fs19.writeFileSync(promptFile,
|
|
6930
|
+
fs19.writeFileSync(promptFile, prompt, "utf-8");
|
|
6927
6931
|
try {
|
|
6928
6932
|
const provider = resolveJobProvider(config, "analytics");
|
|
6929
6933
|
const providerCmd = PROVIDER_COMMANDS[provider];
|
|
@@ -7553,19 +7557,19 @@ var init_dist = __esm({
|
|
|
7553
7557
|
import "reflect-metadata";
|
|
7554
7558
|
import { Command as Command3 } from "commander";
|
|
7555
7559
|
import { existsSync as existsSync30, readFileSync as readFileSync19 } from "fs";
|
|
7556
|
-
import { fileURLToPath as
|
|
7557
|
-
import { dirname as
|
|
7560
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
7561
|
+
import { dirname as dirname12, join as join36 } from "path";
|
|
7558
7562
|
|
|
7559
7563
|
// src/commands/init.ts
|
|
7560
7564
|
init_dist();
|
|
7561
7565
|
import fs20 from "fs";
|
|
7562
7566
|
import path20 from "path";
|
|
7563
7567
|
import { execSync as execSync3 } from "child_process";
|
|
7564
|
-
import { fileURLToPath as
|
|
7565
|
-
import { dirname as
|
|
7568
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7569
|
+
import { dirname as dirname6, join as join18 } from "path";
|
|
7566
7570
|
import * as readline from "readline";
|
|
7567
|
-
var
|
|
7568
|
-
var __dirname2 =
|
|
7571
|
+
var __filename2 = fileURLToPath3(import.meta.url);
|
|
7572
|
+
var __dirname2 = dirname6(__filename2);
|
|
7569
7573
|
function findTemplatesDir(startDir) {
|
|
7570
7574
|
let d = startDir;
|
|
7571
7575
|
for (let i = 0; i < 8; i++) {
|
|
@@ -7573,7 +7577,7 @@ function findTemplatesDir(startDir) {
|
|
|
7573
7577
|
if (fs20.existsSync(candidate) && fs20.statSync(candidate).isDirectory()) {
|
|
7574
7578
|
return candidate;
|
|
7575
7579
|
}
|
|
7576
|
-
d =
|
|
7580
|
+
d = dirname6(d);
|
|
7577
7581
|
}
|
|
7578
7582
|
return join18(startDir, "templates");
|
|
7579
7583
|
}
|
|
@@ -7632,7 +7636,7 @@ function promptYesNo(question, defaultNo = true) {
|
|
|
7632
7636
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
7633
7637
|
return Promise.resolve(false);
|
|
7634
7638
|
}
|
|
7635
|
-
return new Promise((
|
|
7639
|
+
return new Promise((resolve9) => {
|
|
7636
7640
|
const rl = readline.createInterface({
|
|
7637
7641
|
input: process.stdin,
|
|
7638
7642
|
output: process.stdout
|
|
@@ -7642,10 +7646,10 @@ function promptYesNo(question, defaultNo = true) {
|
|
|
7642
7646
|
rl.close();
|
|
7643
7647
|
const normalized = answer.trim().toLowerCase();
|
|
7644
7648
|
if (normalized === "") {
|
|
7645
|
-
|
|
7649
|
+
resolve9(!defaultNo);
|
|
7646
7650
|
return;
|
|
7647
7651
|
}
|
|
7648
|
-
|
|
7652
|
+
resolve9(normalized === "y" || normalized === "yes");
|
|
7649
7653
|
});
|
|
7650
7654
|
});
|
|
7651
7655
|
}
|
|
@@ -7748,7 +7752,7 @@ function getDefaultBranch(cwd) {
|
|
|
7748
7752
|
}
|
|
7749
7753
|
}
|
|
7750
7754
|
function promptProviderSelection(providers) {
|
|
7751
|
-
return new Promise((
|
|
7755
|
+
return new Promise((resolve9, reject) => {
|
|
7752
7756
|
const rl = readline.createInterface({
|
|
7753
7757
|
input: process.stdin,
|
|
7754
7758
|
output: process.stdout
|
|
@@ -7764,7 +7768,7 @@ function promptProviderSelection(providers) {
|
|
|
7764
7768
|
reject(new Error("Invalid selection. Please run init again and select a valid number."));
|
|
7765
7769
|
return;
|
|
7766
7770
|
}
|
|
7767
|
-
|
|
7771
|
+
resolve9(providers[selection - 1]);
|
|
7768
7772
|
});
|
|
7769
7773
|
});
|
|
7770
7774
|
}
|
|
@@ -8126,6 +8130,20 @@ function initCommand(program2) {
|
|
|
8126
8130
|
auditResolution.source
|
|
8127
8131
|
);
|
|
8128
8132
|
templateSources.push({ name: "audit.md", source: auditResult.source });
|
|
8133
|
+
const plannerResolution = resolveTemplatePath(
|
|
8134
|
+
"prd-creator.md",
|
|
8135
|
+
customTemplatesDir,
|
|
8136
|
+
TEMPLATES_DIR
|
|
8137
|
+
);
|
|
8138
|
+
const plannerResult = processTemplate(
|
|
8139
|
+
"prd-creator.md",
|
|
8140
|
+
path20.join(instructionsDir, "prd-creator.md"),
|
|
8141
|
+
replacements,
|
|
8142
|
+
force,
|
|
8143
|
+
plannerResolution.path,
|
|
8144
|
+
plannerResolution.source
|
|
8145
|
+
);
|
|
8146
|
+
templateSources.push({ name: "prd-creator.md", source: plannerResult.source });
|
|
8129
8147
|
step(9, totalSteps, "Creating configuration file...");
|
|
8130
8148
|
const configPath = path20.join(cwd, CONFIG_FILE_NAME);
|
|
8131
8149
|
if (fs20.existsSync(configPath) && !force) {
|
|
@@ -8214,6 +8232,7 @@ function initCommand(program2) {
|
|
|
8214
8232
|
filesTable.push(["", `instructions/pr-reviewer.md (${templateSources[2].source})`]);
|
|
8215
8233
|
filesTable.push(["", `instructions/qa.md (${templateSources[3].source})`]);
|
|
8216
8234
|
filesTable.push(["", `instructions/audit.md (${templateSources[4].source})`]);
|
|
8235
|
+
filesTable.push(["", `instructions/prd-creator.md (${templateSources[5].source})`]);
|
|
8217
8236
|
filesTable.push(["Config File", CONFIG_FILE_NAME]);
|
|
8218
8237
|
filesTable.push(["Board Setup", boardSetupStatus]);
|
|
8219
8238
|
filesTable.push(["Global Registry", "~/.night-watch/projects.json"]);
|
|
@@ -8295,7 +8314,7 @@ async function maybeApplyCronSchedulingDelay(config, jobType, projectDir) {
|
|
|
8295
8314
|
return plan;
|
|
8296
8315
|
}
|
|
8297
8316
|
if (plan.totalDelayMinutes > 0) {
|
|
8298
|
-
await new Promise((
|
|
8317
|
+
await new Promise((resolve9) => setTimeout(resolve9, plan.totalDelayMinutes * 6e4));
|
|
8299
8318
|
}
|
|
8300
8319
|
return getSchedulingPlan(projectDir, config, jobType);
|
|
8301
8320
|
}
|
|
@@ -10038,9 +10057,25 @@ function logsCommand(program2) {
|
|
|
10038
10057
|
|
|
10039
10058
|
// src/commands/prd.ts
|
|
10040
10059
|
init_dist();
|
|
10060
|
+
import { execSync as execSync5, spawn as spawn4, spawnSync } from "child_process";
|
|
10041
10061
|
import * as fs26 from "fs";
|
|
10042
10062
|
import * as path28 from "path";
|
|
10043
|
-
import
|
|
10063
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
10064
|
+
import { dirname as dirname9 } from "path";
|
|
10065
|
+
var __filename3 = fileURLToPath4(import.meta.url);
|
|
10066
|
+
var __dirname3 = dirname9(__filename3);
|
|
10067
|
+
function findTemplatesDir2(startDir) {
|
|
10068
|
+
let current = startDir;
|
|
10069
|
+
for (let i = 0; i < 8; i++) {
|
|
10070
|
+
const candidate = path28.join(current, "templates");
|
|
10071
|
+
if (fs26.existsSync(candidate) && fs26.statSync(candidate).isDirectory()) {
|
|
10072
|
+
return candidate;
|
|
10073
|
+
}
|
|
10074
|
+
current = path28.dirname(current);
|
|
10075
|
+
}
|
|
10076
|
+
return path28.join(startDir, "templates");
|
|
10077
|
+
}
|
|
10078
|
+
var TEMPLATES_DIR2 = findTemplatesDir2(__dirname3);
|
|
10044
10079
|
function slugify2(name) {
|
|
10045
10080
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
10046
10081
|
}
|
|
@@ -10053,13 +10088,186 @@ function getNextPrdNumber2(prdDir) {
|
|
|
10053
10088
|
});
|
|
10054
10089
|
return Math.max(0, ...numbers) + 1;
|
|
10055
10090
|
}
|
|
10056
|
-
function
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
|
|
10091
|
+
function extractPrdMarkdown(response) {
|
|
10092
|
+
const match = response.match(/(^#\s+[\s\S]*)/m);
|
|
10093
|
+
return match ? match[1].trim() : response.trim();
|
|
10094
|
+
}
|
|
10095
|
+
function extractPrdTitle(markdown) {
|
|
10096
|
+
const match = markdown.match(/^#\s+PRD:\s*(.+)/m);
|
|
10097
|
+
return match ? match[1].trim() : null;
|
|
10098
|
+
}
|
|
10099
|
+
function buildPrdPrompt(description, projectDir, planningPrinciples) {
|
|
10100
|
+
return `You are generating a PRD markdown file for Night Watch.
|
|
10101
|
+
|
|
10102
|
+
Return only the final PRD markdown.
|
|
10103
|
+
|
|
10104
|
+
Hard requirements:
|
|
10105
|
+
- Start with: # PRD: <title>
|
|
10106
|
+
- Do not ask follow-up questions
|
|
10107
|
+
- Do not add any preamble, commentary, or code fences
|
|
10108
|
+
- Do not describe what you are going to do
|
|
10109
|
+
- Do not mention these instructions
|
|
10110
|
+
- Treat the planning guide below as mandatory instructions, not background context
|
|
10111
|
+
|
|
10112
|
+
Project directory: ${projectDir}
|
|
10113
|
+
|
|
10114
|
+
Planning guide:
|
|
10115
|
+
${planningPrinciples}
|
|
10116
|
+
|
|
10117
|
+
User request:
|
|
10118
|
+
${description}
|
|
10119
|
+
|
|
10120
|
+
Now write the complete PRD markdown file.`;
|
|
10121
|
+
}
|
|
10122
|
+
function buildNativeClaudeEnv(baseEnv = process.env) {
|
|
10123
|
+
const env = { ...baseEnv };
|
|
10124
|
+
delete env.ANTHROPIC_BASE_URL;
|
|
10125
|
+
delete env.ANTHROPIC_API_KEY;
|
|
10126
|
+
delete env.ANTHROPIC_AUTH_TOKEN;
|
|
10127
|
+
delete env.ANTHROPIC_DEFAULT_SONNET_MODEL;
|
|
10128
|
+
delete env.ANTHROPIC_DEFAULT_OPUS_MODEL;
|
|
10129
|
+
delete env.API_TIMEOUT_MS;
|
|
10130
|
+
delete env.CLAUDE_CODE_SSE_PORT;
|
|
10131
|
+
delete env.CLAUDE_NIGHTS_WATCH_DIR;
|
|
10132
|
+
delete env.NW_CLAUDE_MODEL_ID;
|
|
10133
|
+
delete env.NW_CLAUDE_PRIMARY_MODEL_ID;
|
|
10134
|
+
delete env.NW_CLAUDE_SECONDARY_MODEL_ID;
|
|
10135
|
+
delete env.NW_PROVIDER_CMD;
|
|
10136
|
+
delete env.NW_PROVIDER_SUBCOMMAND;
|
|
10137
|
+
delete env.NW_PROVIDER_PROMPT_FLAG;
|
|
10138
|
+
delete env.NW_PROVIDER_APPROVE_FLAG;
|
|
10139
|
+
delete env.NW_PROVIDER_WORKDIR_FLAG;
|
|
10140
|
+
delete env.NW_PROVIDER_MODEL_FLAG;
|
|
10141
|
+
delete env.NW_PROVIDER_MODEL;
|
|
10142
|
+
delete env.NW_PROVIDER_LABEL;
|
|
10143
|
+
return env;
|
|
10144
|
+
}
|
|
10145
|
+
function resolvePrdCreateDir() {
|
|
10146
|
+
return "docs/PRDs";
|
|
10147
|
+
}
|
|
10148
|
+
function resolveGitHubBlobUrl(projectDir, relPath) {
|
|
10149
|
+
try {
|
|
10150
|
+
const remoteUrl = execSync5("git remote get-url origin", {
|
|
10151
|
+
cwd: projectDir,
|
|
10152
|
+
encoding: "utf-8",
|
|
10153
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
10154
|
+
}).trim();
|
|
10155
|
+
const branch = execSync5("git rev-parse --abbrev-ref HEAD", {
|
|
10156
|
+
cwd: projectDir,
|
|
10157
|
+
encoding: "utf-8",
|
|
10158
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
10159
|
+
}).trim();
|
|
10160
|
+
const httpsBase = remoteUrl.replace(/^git@github\.com:/, "https://github.com/").replace(/^ssh:\/\/git@github\.com\//, "https://github.com/").replace(/\.git$/, "");
|
|
10161
|
+
if (!httpsBase.startsWith("https://github.com/")) {
|
|
10162
|
+
return null;
|
|
10163
|
+
}
|
|
10164
|
+
const ref = branch && branch !== "HEAD" ? branch : "main";
|
|
10165
|
+
return `${httpsBase}/blob/${encodeURIComponent(ref).replace(/%2F/g, "/")}/${relPath.split(path28.sep).map((segment) => encodeURIComponent(segment)).join("/")}`;
|
|
10166
|
+
} catch {
|
|
10167
|
+
return null;
|
|
10168
|
+
}
|
|
10169
|
+
}
|
|
10170
|
+
function buildGithubIssueBody(prdPath, projectDir, prdContent) {
|
|
10171
|
+
const relPath = path28.relative(projectDir, prdPath);
|
|
10172
|
+
const blobUrl = resolveGitHubBlobUrl(projectDir, relPath);
|
|
10173
|
+
const fileLine = blobUrl ? `PRD file: [\`${relPath}\`](${blobUrl})` : `PRD file: \`${relPath}\``;
|
|
10174
|
+
return `${fileLine}
|
|
10175
|
+
|
|
10176
|
+
${prdContent}
|
|
10177
|
+
|
|
10178
|
+
---
|
|
10179
|
+
Created via \`night-watch prd create\`.`;
|
|
10180
|
+
}
|
|
10181
|
+
async function generatePrdWithClaude(description, projectDir, model) {
|
|
10182
|
+
const bundledTemplatePath = path28.join(TEMPLATES_DIR2, "prd-creator.md");
|
|
10183
|
+
const installedTemplatePath = path28.join(projectDir, "instructions", "prd-creator.md");
|
|
10184
|
+
const templatePath = fs26.existsSync(installedTemplatePath) ? installedTemplatePath : bundledTemplatePath;
|
|
10185
|
+
if (!fs26.existsSync(templatePath)) {
|
|
10186
|
+
return null;
|
|
10187
|
+
}
|
|
10188
|
+
const planningPrinciples = fs26.readFileSync(templatePath, "utf-8");
|
|
10189
|
+
const prompt = buildPrdPrompt(description, projectDir, planningPrinciples);
|
|
10190
|
+
const modelId = model ?? CLAUDE_MODEL_IDS.opus;
|
|
10191
|
+
const env = buildNativeClaudeEnv(process.env);
|
|
10192
|
+
return await new Promise((resolve9) => {
|
|
10193
|
+
const child = spawn4(
|
|
10194
|
+
"claude",
|
|
10195
|
+
[
|
|
10196
|
+
"-p",
|
|
10197
|
+
"--verbose",
|
|
10198
|
+
"--output-format",
|
|
10199
|
+
"stream-json",
|
|
10200
|
+
"--include-partial-messages",
|
|
10201
|
+
"--model",
|
|
10202
|
+
modelId,
|
|
10203
|
+
prompt
|
|
10204
|
+
],
|
|
10205
|
+
{ env, stdio: ["ignore", "pipe", "pipe"] }
|
|
10206
|
+
);
|
|
10207
|
+
let stdoutBuffer = "";
|
|
10208
|
+
let finalResult = "";
|
|
10209
|
+
child.stdout.on("data", (chunk) => {
|
|
10210
|
+
stdoutBuffer += chunk.toString("utf-8");
|
|
10211
|
+
while (stdoutBuffer.includes("\n")) {
|
|
10212
|
+
const newlineIndex = stdoutBuffer.indexOf("\n");
|
|
10213
|
+
const line = stdoutBuffer.slice(0, newlineIndex).trim();
|
|
10214
|
+
stdoutBuffer = stdoutBuffer.slice(newlineIndex + 1);
|
|
10215
|
+
if (!line) continue;
|
|
10216
|
+
try {
|
|
10217
|
+
const payload = JSON.parse(line);
|
|
10218
|
+
if (payload.type === "stream_event") {
|
|
10219
|
+
const event = payload.event;
|
|
10220
|
+
const delta = event?.delta;
|
|
10221
|
+
if (delta?.type === "text_delta" && typeof delta.text === "string") {
|
|
10222
|
+
process.stdout.write(delta.text);
|
|
10223
|
+
}
|
|
10224
|
+
continue;
|
|
10225
|
+
}
|
|
10226
|
+
if (payload.type === "result" && typeof payload.result === "string") {
|
|
10227
|
+
finalResult = payload.result;
|
|
10228
|
+
}
|
|
10229
|
+
} catch {
|
|
10230
|
+
}
|
|
10231
|
+
}
|
|
10232
|
+
});
|
|
10233
|
+
child.stderr.on("data", (chunk) => process.stderr.write(chunk));
|
|
10234
|
+
child.on("close", (code) => {
|
|
10235
|
+
if (stdoutBuffer.trim().length > 0) {
|
|
10236
|
+
try {
|
|
10237
|
+
const payload = JSON.parse(stdoutBuffer.trim());
|
|
10238
|
+
if (payload.type === "result" && typeof payload.result === "string") {
|
|
10239
|
+
finalResult = payload.result;
|
|
10240
|
+
}
|
|
10241
|
+
} catch {
|
|
10242
|
+
}
|
|
10243
|
+
}
|
|
10244
|
+
process.stdout.write("\n");
|
|
10245
|
+
resolve9(code === 0 && finalResult ? extractPrdMarkdown(finalResult) : null);
|
|
10060
10246
|
});
|
|
10247
|
+
child.on("error", () => resolve9(null));
|
|
10061
10248
|
});
|
|
10062
10249
|
}
|
|
10250
|
+
function runGh(args, cwd) {
|
|
10251
|
+
const result = spawnSync("gh", args, { cwd, encoding: "utf-8" });
|
|
10252
|
+
if (result.status === 0) return (result.stdout ?? "").trim();
|
|
10253
|
+
return null;
|
|
10254
|
+
}
|
|
10255
|
+
function createGithubIssue(title, prdPath, projectDir, prdContent) {
|
|
10256
|
+
const tmpFile = path28.join(projectDir, `.prd-issue-body-${Date.now()}.tmp`);
|
|
10257
|
+
try {
|
|
10258
|
+
const body = buildGithubIssueBody(prdPath, projectDir, prdContent);
|
|
10259
|
+
fs26.writeFileSync(tmpFile, body, "utf-8");
|
|
10260
|
+
const baseArgs = ["issue", "create", "--title", `PRD: ${title}`, "--body-file", tmpFile];
|
|
10261
|
+
return runGh([...baseArgs, "--label", "prd"], projectDir) ?? runGh(baseArgs, projectDir);
|
|
10262
|
+
} catch {
|
|
10263
|
+
return null;
|
|
10264
|
+
} finally {
|
|
10265
|
+
try {
|
|
10266
|
+
fs26.unlinkSync(tmpFile);
|
|
10267
|
+
} catch {
|
|
10268
|
+
}
|
|
10269
|
+
}
|
|
10270
|
+
}
|
|
10063
10271
|
function parseDependencies(content) {
|
|
10064
10272
|
const match = content.match(/\*\*Depends on:\*\*\s*(.+)/i) || content.match(/Depends on:\s*(.+)/i);
|
|
10065
10273
|
if (!match) return [];
|
|
@@ -10083,101 +10291,38 @@ function isClaimActive(claimPath, maxRuntime) {
|
|
|
10083
10291
|
}
|
|
10084
10292
|
function prdCommand(program2) {
|
|
10085
10293
|
const prd = program2.command("prd").description("Manage PRD files");
|
|
10086
|
-
prd.command("create").description("Generate a new PRD markdown file
|
|
10294
|
+
prd.command("create").description("Generate a new PRD markdown file using Claude").argument("<name>", "PRD description").option("--number", "Add auto-numbering prefix to the filename", false).option("--model <model>", "Claude model to use (e.g. sonnet, opus, or a full model ID)").action(async (name, options) => {
|
|
10087
10295
|
const projectDir = process.cwd();
|
|
10088
|
-
const
|
|
10089
|
-
const prdDir = path28.join(projectDir, config.prdDir);
|
|
10296
|
+
const prdDir = path28.join(projectDir, resolvePrdCreateDir());
|
|
10090
10297
|
if (!fs26.existsSync(prdDir)) {
|
|
10091
10298
|
fs26.mkdirSync(prdDir, { recursive: true });
|
|
10092
10299
|
}
|
|
10093
|
-
|
|
10094
|
-
|
|
10095
|
-
|
|
10096
|
-
|
|
10097
|
-
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
}
|
|
10102
|
-
if (options.interactive) {
|
|
10103
|
-
const rl = readline2.createInterface({
|
|
10104
|
-
input: process.stdin,
|
|
10105
|
-
output: process.stdout
|
|
10106
|
-
});
|
|
10107
|
-
try {
|
|
10108
|
-
const complexityInput = await prompt(rl, "Complexity score (1-10, default 5): ");
|
|
10109
|
-
if (complexityInput) {
|
|
10110
|
-
const parsed = parseInt(complexityInput, 10);
|
|
10111
|
-
if (!isNaN(parsed) && parsed >= 1 && parsed <= 10) {
|
|
10112
|
-
complexityScore = parsed;
|
|
10113
|
-
}
|
|
10114
|
-
}
|
|
10115
|
-
const depsInput = await prompt(
|
|
10116
|
-
rl,
|
|
10117
|
-
"Dependencies (comma-separated filenames, or empty): "
|
|
10118
|
-
);
|
|
10119
|
-
if (depsInput) {
|
|
10120
|
-
dependsOn = depsInput.split(",").map((d) => d.trim()).filter((d) => d.length > 0);
|
|
10121
|
-
}
|
|
10122
|
-
const phasesInput = await prompt(rl, `Number of phases (default ${phaseCount}): `);
|
|
10123
|
-
if (phasesInput) {
|
|
10124
|
-
const parsed = parseInt(phasesInput, 10);
|
|
10125
|
-
if (!isNaN(parsed) && parsed >= 1) {
|
|
10126
|
-
phaseCount = parsed;
|
|
10127
|
-
}
|
|
10128
|
-
}
|
|
10129
|
-
} finally {
|
|
10130
|
-
rl.close();
|
|
10131
|
-
}
|
|
10132
|
-
}
|
|
10133
|
-
let complexityLevel;
|
|
10134
|
-
if (complexityScore <= 3) {
|
|
10135
|
-
complexityLevel = "LOW";
|
|
10136
|
-
} else if (complexityScore <= 7) {
|
|
10137
|
-
complexityLevel = "MEDIUM";
|
|
10138
|
-
} else {
|
|
10139
|
-
complexityLevel = "HIGH";
|
|
10140
|
-
}
|
|
10141
|
-
const slug = slugify2(name);
|
|
10142
|
-
let filename;
|
|
10143
|
-
if (options.number) {
|
|
10144
|
-
const nextNum = getNextPrdNumber2(prdDir);
|
|
10145
|
-
const padded = String(nextNum).padStart(2, "0");
|
|
10146
|
-
filename = `${padded}-${slug}.md`;
|
|
10147
|
-
} else {
|
|
10148
|
-
filename = `${slug}.md`;
|
|
10300
|
+
const resolvedModel = options.model ? CLAUDE_MODEL_IDS[options.model] ?? options.model : void 0;
|
|
10301
|
+
const modelLabel = resolvedModel ?? CLAUDE_MODEL_IDS.opus;
|
|
10302
|
+
dim(`Calling Claude (${modelLabel}) to generate the PRD. It can take several minutes, please hang on!
|
|
10303
|
+
`);
|
|
10304
|
+
const generated = await generatePrdWithClaude(name, projectDir, resolvedModel);
|
|
10305
|
+
if (!generated) {
|
|
10306
|
+
error("Claude generation failed. Is the provider configured and available?");
|
|
10307
|
+
process.exit(1);
|
|
10149
10308
|
}
|
|
10309
|
+
const prdTitle = extractPrdTitle(generated) ?? name;
|
|
10310
|
+
const slug = slugify2(prdTitle);
|
|
10311
|
+
const filename = options.number ? `${String(getNextPrdNumber2(prdDir)).padStart(2, "0")}-${slug}.md` : `${slug}.md`;
|
|
10150
10312
|
const filePath = path28.join(prdDir, filename);
|
|
10151
10313
|
if (fs26.existsSync(filePath)) {
|
|
10152
10314
|
error(`File already exists: ${filePath}`);
|
|
10153
10315
|
dim("Use a different name or remove the existing file.");
|
|
10154
10316
|
process.exit(1);
|
|
10155
10317
|
}
|
|
10156
|
-
|
|
10157
|
-
if (options.template) {
|
|
10158
|
-
const templatePath = path28.resolve(options.template);
|
|
10159
|
-
if (!fs26.existsSync(templatePath)) {
|
|
10160
|
-
error(`Template file not found: ${templatePath}`);
|
|
10161
|
-
process.exit(1);
|
|
10162
|
-
}
|
|
10163
|
-
customTemplate = fs26.readFileSync(templatePath, "utf-8");
|
|
10164
|
-
}
|
|
10165
|
-
const vars = {
|
|
10166
|
-
title: name,
|
|
10167
|
-
dependsOn,
|
|
10168
|
-
complexityScore,
|
|
10169
|
-
complexityLevel,
|
|
10170
|
-
complexityBreakdown: [],
|
|
10171
|
-
phaseCount
|
|
10172
|
-
};
|
|
10173
|
-
const content = renderPrdTemplate(vars, customTemplate);
|
|
10174
|
-
fs26.writeFileSync(filePath, content, "utf-8");
|
|
10318
|
+
fs26.writeFileSync(filePath, generated, "utf-8");
|
|
10175
10319
|
header("PRD Created");
|
|
10176
10320
|
success(`Created: ${filePath}`);
|
|
10177
|
-
|
|
10178
|
-
|
|
10179
|
-
|
|
10180
|
-
|
|
10321
|
+
const issueUrl = createGithubIssue(prdTitle, filePath, projectDir, generated);
|
|
10322
|
+
if (issueUrl) {
|
|
10323
|
+
info(`Issue: ${issueUrl}`);
|
|
10324
|
+
} else {
|
|
10325
|
+
dim("GitHub issue creation skipped (gh not available or not in a GitHub repo).");
|
|
10181
10326
|
}
|
|
10182
10327
|
});
|
|
10183
10328
|
prd.command("list").description("List all PRDs with status").option("--json", "Output as JSON").action(async (options) => {
|
|
@@ -10219,16 +10364,14 @@ function prdCommand(program2) {
|
|
|
10219
10364
|
dim(" No PRDs found.");
|
|
10220
10365
|
return;
|
|
10221
10366
|
}
|
|
10222
|
-
const table = createTable({
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
const statusDisplay = prd2.claimed && prd2.claimInfo ? `claimed (${prd2.claimInfo.hostname}:${prd2.claimInfo.pid})` : status;
|
|
10228
|
-
table.push([prd2.name, statusDisplay, prd2.dependencies.join(", ") || "-"]);
|
|
10367
|
+
const table = createTable({ head: ["Name", "Status", "Dependencies"] });
|
|
10368
|
+
for (const prdEntry of pending) {
|
|
10369
|
+
const status = prdEntry.claimed ? "claimed" : "pending";
|
|
10370
|
+
const statusDisplay = prdEntry.claimed && prdEntry.claimInfo ? `claimed (${prdEntry.claimInfo.hostname}:${prdEntry.claimInfo.pid})` : status;
|
|
10371
|
+
table.push([prdEntry.name, statusDisplay, prdEntry.dependencies.join(", ") || "-"]);
|
|
10229
10372
|
}
|
|
10230
|
-
for (const
|
|
10231
|
-
table.push([
|
|
10373
|
+
for (const prdEntry of done) {
|
|
10374
|
+
table.push([prdEntry.name, "done", prdEntry.dependencies.join(", ") || "-"]);
|
|
10232
10375
|
}
|
|
10233
10376
|
console.log(table.toString());
|
|
10234
10377
|
const claimedCount = pending.filter((p) => p.claimed).length;
|
|
@@ -11748,11 +11891,11 @@ function createSchedulesTab() {
|
|
|
11748
11891
|
|
|
11749
11892
|
// src/commands/dashboard/tab-actions.ts
|
|
11750
11893
|
import blessed4 from "blessed";
|
|
11751
|
-
import { spawn as
|
|
11894
|
+
import { spawn as spawn5 } from "child_process";
|
|
11752
11895
|
function spawnAction(args, ctx, outputBox, onDone) {
|
|
11753
11896
|
outputBox.setContent("{cyan-fg}Starting...{/cyan-fg}\n");
|
|
11754
11897
|
ctx.screen.render();
|
|
11755
|
-
const child =
|
|
11898
|
+
const child = spawn5("npx", ["tsx", "src/cli.ts", ...args], {
|
|
11756
11899
|
cwd: ctx.projectDir,
|
|
11757
11900
|
stdio: ["ignore", "pipe", "pipe"],
|
|
11758
11901
|
env: { ...process.env }
|
|
@@ -12565,8 +12708,8 @@ import * as fs33 from "fs";
|
|
|
12565
12708
|
init_dist();
|
|
12566
12709
|
import * as fs32 from "fs";
|
|
12567
12710
|
import * as path35 from "path";
|
|
12568
|
-
import { dirname as
|
|
12569
|
-
import { fileURLToPath as
|
|
12711
|
+
import { dirname as dirname11 } from "path";
|
|
12712
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
12570
12713
|
import cors from "cors";
|
|
12571
12714
|
import express from "express";
|
|
12572
12715
|
|
|
@@ -12707,7 +12850,7 @@ function startSseStatusWatcher(clients, projectDir, getConfig) {
|
|
|
12707
12850
|
init_dist();
|
|
12708
12851
|
import * as fs30 from "fs";
|
|
12709
12852
|
import * as path31 from "path";
|
|
12710
|
-
import { execSync as
|
|
12853
|
+
import { execSync as execSync6, spawn as spawn6 } from "child_process";
|
|
12711
12854
|
import { Router } from "express";
|
|
12712
12855
|
|
|
12713
12856
|
// ../server/dist/helpers.js
|
|
@@ -12794,7 +12937,7 @@ function spawnAction2(projectDir, command, req, res, onSpawned) {
|
|
|
12794
12937
|
if (prdName) {
|
|
12795
12938
|
extraEnv.NW_PRD_PRIORITY = prdName;
|
|
12796
12939
|
}
|
|
12797
|
-
const child =
|
|
12940
|
+
const child = spawn6("night-watch", command, {
|
|
12798
12941
|
detached: true,
|
|
12799
12942
|
stdio: "ignore",
|
|
12800
12943
|
cwd: projectDir,
|
|
@@ -12826,7 +12969,7 @@ function formatCommandError(error2) {
|
|
|
12826
12969
|
return output || error2.message;
|
|
12827
12970
|
}
|
|
12828
12971
|
function runCliCommand(projectDir, args) {
|
|
12829
|
-
|
|
12972
|
+
execSync6(`night-watch ${args.join(" ")}`, {
|
|
12830
12973
|
cwd: projectDir,
|
|
12831
12974
|
encoding: "utf-8",
|
|
12832
12975
|
stdio: "pipe",
|
|
@@ -13657,12 +13800,12 @@ function createProjectConfigRoutes() {
|
|
|
13657
13800
|
init_dist();
|
|
13658
13801
|
import * as fs31 from "fs";
|
|
13659
13802
|
import * as path32 from "path";
|
|
13660
|
-
import { execSync as
|
|
13803
|
+
import { execSync as execSync7 } from "child_process";
|
|
13661
13804
|
import { Router as Router4 } from "express";
|
|
13662
13805
|
function runDoctorChecks(projectDir, config) {
|
|
13663
13806
|
const checks = [];
|
|
13664
13807
|
try {
|
|
13665
|
-
|
|
13808
|
+
execSync7("git rev-parse --is-inside-work-tree", {
|
|
13666
13809
|
cwd: projectDir,
|
|
13667
13810
|
stdio: "pipe"
|
|
13668
13811
|
});
|
|
@@ -13673,7 +13816,7 @@ function runDoctorChecks(projectDir, config) {
|
|
|
13673
13816
|
try {
|
|
13674
13817
|
const preset = resolvePreset(config, config.provider);
|
|
13675
13818
|
const command = preset?.command ?? config.provider;
|
|
13676
|
-
|
|
13819
|
+
execSync7(`which ${command}`, { stdio: "pipe" });
|
|
13677
13820
|
checks.push({
|
|
13678
13821
|
name: "provider",
|
|
13679
13822
|
status: "pass",
|
|
@@ -14188,13 +14331,13 @@ function createQueueRoutes(deps) {
|
|
|
14188
14331
|
}
|
|
14189
14332
|
|
|
14190
14333
|
// ../server/dist/index.js
|
|
14191
|
-
var
|
|
14192
|
-
var
|
|
14334
|
+
var __filename4 = fileURLToPath5(import.meta.url);
|
|
14335
|
+
var __dirname4 = dirname11(__filename4);
|
|
14193
14336
|
function resolveWebDistPath() {
|
|
14194
|
-
const bundled = path35.join(
|
|
14337
|
+
const bundled = path35.join(__dirname4, "web");
|
|
14195
14338
|
if (fs32.existsSync(path35.join(bundled, "index.html")))
|
|
14196
14339
|
return bundled;
|
|
14197
|
-
let d =
|
|
14340
|
+
let d = __dirname4;
|
|
14198
14341
|
for (let i = 0; i < 8; i++) {
|
|
14199
14342
|
if (fs32.existsSync(path35.join(d, "turbo.json"))) {
|
|
14200
14343
|
const dev = path35.join(d, "web/dist");
|
|
@@ -14202,7 +14345,7 @@ function resolveWebDistPath() {
|
|
|
14202
14345
|
return dev;
|
|
14203
14346
|
break;
|
|
14204
14347
|
}
|
|
14205
|
-
d =
|
|
14348
|
+
d = dirname11(d);
|
|
14206
14349
|
}
|
|
14207
14350
|
return bundled;
|
|
14208
14351
|
}
|
|
@@ -14561,7 +14704,7 @@ function historyCommand(program2) {
|
|
|
14561
14704
|
|
|
14562
14705
|
// src/commands/update.ts
|
|
14563
14706
|
init_dist();
|
|
14564
|
-
import { spawnSync } from "child_process";
|
|
14707
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
14565
14708
|
import * as fs34 from "fs";
|
|
14566
14709
|
import * as path36 from "path";
|
|
14567
14710
|
var DEFAULT_GLOBAL_SPEC = "@jonit-dev/night-watch-cli@latest";
|
|
@@ -14576,7 +14719,7 @@ function shouldInstallGlobal(options) {
|
|
|
14576
14719
|
return options.global !== false;
|
|
14577
14720
|
}
|
|
14578
14721
|
function runCommand2(command, args, cwd) {
|
|
14579
|
-
const result =
|
|
14722
|
+
const result = spawnSync2(command, args, {
|
|
14580
14723
|
cwd,
|
|
14581
14724
|
env: process.env,
|
|
14582
14725
|
stdio: "inherit"
|
|
@@ -14590,7 +14733,7 @@ function runCommand2(command, args, cwd) {
|
|
|
14590
14733
|
}
|
|
14591
14734
|
}
|
|
14592
14735
|
function resolveNightWatchBin() {
|
|
14593
|
-
const result =
|
|
14736
|
+
const result = spawnSync2("which", ["night-watch"], {
|
|
14594
14737
|
encoding: "utf-8",
|
|
14595
14738
|
env: process.env
|
|
14596
14739
|
});
|
|
@@ -14788,10 +14931,10 @@ function prsCommand(program2) {
|
|
|
14788
14931
|
// src/commands/prds.ts
|
|
14789
14932
|
init_dist();
|
|
14790
14933
|
import chalk4 from "chalk";
|
|
14791
|
-
import { execSync as
|
|
14934
|
+
import { execSync as execSync8 } from "child_process";
|
|
14792
14935
|
function getOpenPrBranches(projectDir) {
|
|
14793
14936
|
try {
|
|
14794
|
-
|
|
14937
|
+
execSync8("git rev-parse --git-dir", {
|
|
14795
14938
|
cwd: projectDir,
|
|
14796
14939
|
encoding: "utf-8",
|
|
14797
14940
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -14800,12 +14943,12 @@ function getOpenPrBranches(projectDir) {
|
|
|
14800
14943
|
return /* @__PURE__ */ new Set();
|
|
14801
14944
|
}
|
|
14802
14945
|
try {
|
|
14803
|
-
|
|
14946
|
+
execSync8("which gh", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
|
|
14804
14947
|
} catch {
|
|
14805
14948
|
return /* @__PURE__ */ new Set();
|
|
14806
14949
|
}
|
|
14807
14950
|
try {
|
|
14808
|
-
const output =
|
|
14951
|
+
const output = execSync8("gh pr list --state open --json headRefName", {
|
|
14809
14952
|
cwd: projectDir,
|
|
14810
14953
|
encoding: "utf-8",
|
|
14811
14954
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -14936,7 +15079,7 @@ function prdsCommand(program2) {
|
|
|
14936
15079
|
// src/commands/cancel.ts
|
|
14937
15080
|
init_dist();
|
|
14938
15081
|
import * as fs36 from "fs";
|
|
14939
|
-
import * as
|
|
15082
|
+
import * as readline2 from "readline";
|
|
14940
15083
|
function getLockFilePaths2(projectDir) {
|
|
14941
15084
|
const runtimeKey = projectRuntimeKey(projectDir);
|
|
14942
15085
|
return {
|
|
@@ -14944,24 +15087,24 @@ function getLockFilePaths2(projectDir) {
|
|
|
14944
15087
|
reviewer: `${LOCK_FILE_PREFIX}pr-reviewer-${runtimeKey}.lock`
|
|
14945
15088
|
};
|
|
14946
15089
|
}
|
|
14947
|
-
async function promptConfirmation(
|
|
15090
|
+
async function promptConfirmation(prompt) {
|
|
14948
15091
|
if (!process.stdin.isTTY) {
|
|
14949
15092
|
return false;
|
|
14950
15093
|
}
|
|
14951
|
-
const rl =
|
|
15094
|
+
const rl = readline2.createInterface({
|
|
14952
15095
|
input: process.stdin,
|
|
14953
15096
|
output: process.stdout
|
|
14954
15097
|
});
|
|
14955
|
-
return new Promise((
|
|
14956
|
-
rl.question(`${
|
|
15098
|
+
return new Promise((resolve9) => {
|
|
15099
|
+
rl.question(`${prompt} `, (answer) => {
|
|
14957
15100
|
rl.close();
|
|
14958
15101
|
const normalized = answer.toLowerCase().trim();
|
|
14959
|
-
|
|
15102
|
+
resolve9(normalized === "y" || normalized === "yes");
|
|
14960
15103
|
});
|
|
14961
15104
|
});
|
|
14962
15105
|
}
|
|
14963
15106
|
function sleep2(ms) {
|
|
14964
|
-
return new Promise((
|
|
15107
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
14965
15108
|
}
|
|
14966
15109
|
function isProcessRunning3(pid) {
|
|
14967
15110
|
try {
|
|
@@ -15443,7 +15586,7 @@ init_dist();
|
|
|
15443
15586
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
15444
15587
|
import * as fs38 from "fs";
|
|
15445
15588
|
import * as path40 from "path";
|
|
15446
|
-
import * as
|
|
15589
|
+
import * as readline3 from "readline";
|
|
15447
15590
|
import chalk6 from "chalk";
|
|
15448
15591
|
async function run(fn) {
|
|
15449
15592
|
try {
|
|
@@ -15491,14 +15634,14 @@ async function ensureBoardConfigured(config, cwd, provider, options) {
|
|
|
15491
15634
|
}
|
|
15492
15635
|
}
|
|
15493
15636
|
async function confirmPrompt(question) {
|
|
15494
|
-
const rl =
|
|
15637
|
+
const rl = readline3.createInterface({
|
|
15495
15638
|
input: process.stdin,
|
|
15496
15639
|
output: process.stdout
|
|
15497
15640
|
});
|
|
15498
|
-
return new Promise((
|
|
15641
|
+
return new Promise((resolve9) => {
|
|
15499
15642
|
rl.question(question, (answer) => {
|
|
15500
15643
|
rl.close();
|
|
15501
|
-
|
|
15644
|
+
resolve9(answer.trim().toLowerCase() === "y");
|
|
15502
15645
|
});
|
|
15503
15646
|
});
|
|
15504
15647
|
}
|
|
@@ -16038,7 +16181,7 @@ function boardCommand(program2) {
|
|
|
16038
16181
|
init_dist();
|
|
16039
16182
|
init_dist();
|
|
16040
16183
|
import * as path41 from "path";
|
|
16041
|
-
import { spawn as
|
|
16184
|
+
import { spawn as spawn7 } from "child_process";
|
|
16042
16185
|
import chalk7 from "chalk";
|
|
16043
16186
|
import { Command as Command2 } from "commander";
|
|
16044
16187
|
var logger4 = createLogger("queue");
|
|
@@ -16192,7 +16335,7 @@ function createQueueCommand() {
|
|
|
16192
16335
|
const scriptPath = getScriptPath(scriptName);
|
|
16193
16336
|
logger4.info(`Spawning: ${scriptPath} ${entry.projectPath}`);
|
|
16194
16337
|
try {
|
|
16195
|
-
const child =
|
|
16338
|
+
const child = spawn7("bash", [scriptPath, entry.projectPath], {
|
|
16196
16339
|
detached: true,
|
|
16197
16340
|
stdio: "ignore",
|
|
16198
16341
|
env,
|
|
@@ -16312,17 +16455,17 @@ function notifyCommand(program2) {
|
|
|
16312
16455
|
}
|
|
16313
16456
|
|
|
16314
16457
|
// src/cli.ts
|
|
16315
|
-
var
|
|
16316
|
-
var
|
|
16458
|
+
var __filename5 = fileURLToPath6(import.meta.url);
|
|
16459
|
+
var __dirname5 = dirname12(__filename5);
|
|
16317
16460
|
function findPackageRoot(dir) {
|
|
16318
16461
|
let d = dir;
|
|
16319
16462
|
for (let i = 0; i < 5; i++) {
|
|
16320
16463
|
if (existsSync30(join36(d, "package.json"))) return d;
|
|
16321
|
-
d =
|
|
16464
|
+
d = dirname12(d);
|
|
16322
16465
|
}
|
|
16323
16466
|
return dir;
|
|
16324
16467
|
}
|
|
16325
|
-
var packageRoot = findPackageRoot(
|
|
16468
|
+
var packageRoot = findPackageRoot(__dirname5);
|
|
16326
16469
|
var packageJson = JSON.parse(readFileSync19(join36(packageRoot, "package.json"), "utf-8"));
|
|
16327
16470
|
var program = new Command3();
|
|
16328
16471
|
program.name("night-watch").description("Autonomous PRD execution using Claude CLI + cron").version(packageJson.version);
|