@jonit-dev/night-watch-cli 1.7.83 → 1.7.85
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 +46 -5
- package/dist/scripts/night-watch-pr-reviewer-cron.sh +19 -18
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4792,13 +4792,52 @@ var init_prd_utils = __esm({
|
|
|
4792
4792
|
import * as fs12 from "fs";
|
|
4793
4793
|
import * as os5 from "os";
|
|
4794
4794
|
import * as path11 from "path";
|
|
4795
|
+
function readLegacyRegistryEntries() {
|
|
4796
|
+
const registryPath = getRegistryPath();
|
|
4797
|
+
if (!fs12.existsSync(registryPath)) {
|
|
4798
|
+
return [];
|
|
4799
|
+
}
|
|
4800
|
+
try {
|
|
4801
|
+
const raw = fs12.readFileSync(registryPath, "utf-8");
|
|
4802
|
+
const parsed = JSON.parse(raw);
|
|
4803
|
+
if (!Array.isArray(parsed)) {
|
|
4804
|
+
return [];
|
|
4805
|
+
}
|
|
4806
|
+
return parsed.filter((entry) => typeof entry === "object" && entry !== null && typeof entry.name === "string" && entry.name.length > 0 && typeof entry.path === "string" && entry.path.length > 0);
|
|
4807
|
+
} catch {
|
|
4808
|
+
return [];
|
|
4809
|
+
}
|
|
4810
|
+
}
|
|
4811
|
+
function loadRegistryEntriesWithLegacyFallback() {
|
|
4812
|
+
const { projectRegistry } = getRepositories();
|
|
4813
|
+
const entries = projectRegistry.getAll();
|
|
4814
|
+
if (entries.length > 0) {
|
|
4815
|
+
return entries;
|
|
4816
|
+
}
|
|
4817
|
+
const db = getDb();
|
|
4818
|
+
const alreadyHydrated = db.prepare("SELECT value FROM schema_meta WHERE key = 'legacy_projects_json_hydrated'").get();
|
|
4819
|
+
if (alreadyHydrated) {
|
|
4820
|
+
return [];
|
|
4821
|
+
}
|
|
4822
|
+
const legacyEntries = readLegacyRegistryEntries();
|
|
4823
|
+
if (legacyEntries.length === 0) {
|
|
4824
|
+
return [];
|
|
4825
|
+
}
|
|
4826
|
+
db.transaction(() => {
|
|
4827
|
+
for (const entry of legacyEntries) {
|
|
4828
|
+
projectRegistry.upsert(entry);
|
|
4829
|
+
}
|
|
4830
|
+
db.prepare(`INSERT INTO schema_meta (key, value) VALUES ('legacy_projects_json_hydrated', ?)
|
|
4831
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run((/* @__PURE__ */ new Date()).toISOString());
|
|
4832
|
+
})();
|
|
4833
|
+
return projectRegistry.getAll();
|
|
4834
|
+
}
|
|
4795
4835
|
function getRegistryPath() {
|
|
4796
4836
|
const base = process.env.NIGHT_WATCH_HOME || path11.join(os5.homedir(), GLOBAL_CONFIG_DIR);
|
|
4797
4837
|
return path11.join(base, REGISTRY_FILE_NAME);
|
|
4798
4838
|
}
|
|
4799
4839
|
function loadRegistry() {
|
|
4800
|
-
|
|
4801
|
-
return projectRegistry.getAll();
|
|
4840
|
+
return loadRegistryEntriesWithLegacyFallback();
|
|
4802
4841
|
}
|
|
4803
4842
|
function saveRegistry(entries) {
|
|
4804
4843
|
const { projectRegistry } = getRepositories();
|
|
@@ -4810,7 +4849,7 @@ function saveRegistry(entries) {
|
|
|
4810
4849
|
function registerProject(projectDir) {
|
|
4811
4850
|
const resolvedPath = path11.resolve(projectDir);
|
|
4812
4851
|
const { projectRegistry } = getRepositories();
|
|
4813
|
-
const entries =
|
|
4852
|
+
const entries = loadRegistryEntriesWithLegacyFallback();
|
|
4814
4853
|
const existing = entries.find((e) => e.path === resolvedPath);
|
|
4815
4854
|
if (existing) {
|
|
4816
4855
|
return existing;
|
|
@@ -4824,6 +4863,7 @@ function registerProject(projectDir) {
|
|
|
4824
4863
|
}
|
|
4825
4864
|
function unregisterProject(projectDir) {
|
|
4826
4865
|
const resolvedPath = path11.resolve(projectDir);
|
|
4866
|
+
loadRegistryEntriesWithLegacyFallback();
|
|
4827
4867
|
const { projectRegistry } = getRepositories();
|
|
4828
4868
|
return projectRegistry.remove(resolvedPath);
|
|
4829
4869
|
}
|
|
@@ -4846,6 +4886,7 @@ var init_registry = __esm({
|
|
|
4846
4886
|
init_constants();
|
|
4847
4887
|
init_repositories();
|
|
4848
4888
|
init_client();
|
|
4889
|
+
init_client();
|
|
4849
4890
|
init_status_data();
|
|
4850
4891
|
}
|
|
4851
4892
|
});
|
|
@@ -7026,7 +7067,7 @@ var init_dist = __esm({
|
|
|
7026
7067
|
// src/cli.ts
|
|
7027
7068
|
import "reflect-metadata";
|
|
7028
7069
|
import { Command as Command3 } from "commander";
|
|
7029
|
-
import { existsSync as existsSync29, readFileSync as
|
|
7070
|
+
import { existsSync as existsSync29, readFileSync as readFileSync18 } from "fs";
|
|
7030
7071
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
7031
7072
|
import { dirname as dirname8, join as join34 } from "path";
|
|
7032
7073
|
|
|
@@ -15335,7 +15376,7 @@ function findPackageRoot(dir) {
|
|
|
15335
15376
|
return dir;
|
|
15336
15377
|
}
|
|
15337
15378
|
var packageRoot = findPackageRoot(__dirname4);
|
|
15338
|
-
var packageJson = JSON.parse(
|
|
15379
|
+
var packageJson = JSON.parse(readFileSync18(join34(packageRoot, "package.json"), "utf-8"));
|
|
15339
15380
|
var program = new Command3();
|
|
15340
15381
|
program.name("night-watch").description("Autonomous PRD execution using Claude CLI + cron").version(packageJson.version);
|
|
15341
15382
|
initCommand(program);
|
|
@@ -90,6 +90,14 @@ emit_result() {
|
|
|
90
90
|
fi
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
extract_review_score_from_text() {
|
|
94
|
+
local review_text="${1:-}"
|
|
95
|
+
printf '%s' "${review_text}" \
|
|
96
|
+
| grep -oP '(?:Overall\s+)?Score:\*?\*?\s*\d+/100' \
|
|
97
|
+
| tail -1 \
|
|
98
|
+
| grep -oP '\d+(?=/100)' || echo ""
|
|
99
|
+
}
|
|
100
|
+
|
|
93
101
|
# ── Global Job Queue Gate ────────────────────────────────────────────────────
|
|
94
102
|
# Acquire global gate before per-project lock to serialize jobs across projects.
|
|
95
103
|
# When gate is busy, enqueue the job and exit cleanly.
|
|
@@ -393,10 +401,7 @@ get_pr_score() {
|
|
|
393
401
|
fi
|
|
394
402
|
} | sort -u
|
|
395
403
|
)
|
|
396
|
-
|
|
397
|
-
| grep -oP 'Overall Score:\*?\*?\s*(\d+)/100' \
|
|
398
|
-
| tail -1 \
|
|
399
|
-
| grep -oP '\d+(?=/100)' || echo ""
|
|
404
|
+
extract_review_score_from_text "${all_comments}"
|
|
400
405
|
}
|
|
401
406
|
|
|
402
407
|
# Count failed CI checks for a PR.
|
|
@@ -645,10 +650,7 @@ while IFS=$'\t' read -r pr_number pr_branch; do
|
|
|
645
650
|
fi
|
|
646
651
|
} | sort -u
|
|
647
652
|
)
|
|
648
|
-
LATEST_SCORE=$(
|
|
649
|
-
| grep -oP 'Overall Score:\*?\*?\s*(\d+)/100' \
|
|
650
|
-
| tail -1 \
|
|
651
|
-
| grep -oP '\d+(?=/100)' || echo "")
|
|
653
|
+
LATEST_SCORE=$(extract_review_score_from_text "${ALL_COMMENTS}")
|
|
652
654
|
if [ -n "${LATEST_SCORE}" ] && [ "${LATEST_SCORE}" -lt "${MIN_REVIEW_SCORE}" ]; then
|
|
653
655
|
log "INFO: PR #${pr_number} (${pr_branch}) has review score ${LATEST_SCORE}/100 (threshold: ${MIN_REVIEW_SCORE})"
|
|
654
656
|
NEEDS_WORK=1
|
|
@@ -686,10 +688,7 @@ if [ "${NEEDS_WORK}" -eq 0 ]; then
|
|
|
686
688
|
fi
|
|
687
689
|
} | sort -u
|
|
688
690
|
)
|
|
689
|
-
PR_SCORE=$(
|
|
690
|
-
| grep -oP 'Overall Score:\*?\*?\s*(\d+)/100' \
|
|
691
|
-
| tail -1 \
|
|
692
|
-
| grep -oP '\d+(?=/100)' || echo "")
|
|
691
|
+
PR_SCORE=$(extract_review_score_from_text "${PR_COMMENTS}")
|
|
693
692
|
|
|
694
693
|
# Skip PRs without a score or with score below threshold
|
|
695
694
|
[ -z "${PR_SCORE}" ] && continue
|
|
@@ -915,9 +914,14 @@ if ! assert_isolated_worktree "${PROJECT_DIR}" "${REVIEW_WORKTREE_DIR}" "reviewe
|
|
|
915
914
|
exit 1
|
|
916
915
|
fi
|
|
917
916
|
|
|
918
|
-
|
|
917
|
+
SHARED_REVIEW_PROMPT_PATH="${REVIEW_WORKTREE_DIR}/.github/prompts/pr-review.md"
|
|
918
|
+
if [ -f "${SHARED_REVIEW_PROMPT_PATH}" ]; then
|
|
919
|
+
REVIEWER_PROMPT_PATH="${SHARED_REVIEW_PROMPT_PATH}"
|
|
920
|
+
else
|
|
921
|
+
REVIEWER_PROMPT_PATH=$(resolve_instruction_path_with_fallback "${REVIEW_WORKTREE_DIR}" "pr-reviewer.md" "night-watch-pr-reviewer.md" || true)
|
|
922
|
+
fi
|
|
919
923
|
if [ -z "${REVIEWER_PROMPT_PATH}" ]; then
|
|
920
|
-
log "FAIL: Missing reviewer prompt file. Checked pr-reviewer.md/night-watch-pr-reviewer.md in instructions/, .claude/commands/, and bundled templates/"
|
|
924
|
+
log "FAIL: Missing reviewer prompt file. Checked .github/prompts/pr-review.md plus pr-reviewer.md/night-watch-pr-reviewer.md in instructions/, .claude/commands/, and bundled templates/"
|
|
921
925
|
emit_result "failure" "reason=missing_reviewer_prompt"
|
|
922
926
|
exit 1
|
|
923
927
|
fi
|
|
@@ -1225,10 +1229,7 @@ if [ "${AUTO_MERGE}" = "1" ] && [ ${EXIT_CODE} -eq 0 ]; then
|
|
|
1225
1229
|
fi
|
|
1226
1230
|
} | sort -u
|
|
1227
1231
|
)
|
|
1228
|
-
LATEST_SCORE=$(
|
|
1229
|
-
| grep -oP 'Overall Score:\*?\*?\s*(\d+)/100' \
|
|
1230
|
-
| tail -1 \
|
|
1231
|
-
| grep -oP '\d+(?=/100)' || echo "")
|
|
1232
|
+
LATEST_SCORE=$(extract_review_score_from_text "${ALL_COMMENTS}")
|
|
1232
1233
|
|
|
1233
1234
|
# Skip PRs without a score
|
|
1234
1235
|
if [ -z "${LATEST_SCORE}" ]; then
|