@jonit-dev/night-watch-cli 1.8.11 → 1.8.12-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.d.ts +3 -0
- package/dist/cli.js +2363 -1382
- package/dist/cli.js.map +1 -0
- package/dist/commands/analytics.d.ts +14 -0
- package/dist/commands/analytics.js +69 -0
- package/dist/commands/analytics.js.map +1 -0
- package/dist/commands/audit.d.ts +19 -0
- package/dist/commands/audit.js +144 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/board.d.ts +9 -0
- package/dist/commands/board.js +702 -0
- package/dist/commands/board.js.map +1 -0
- package/dist/commands/cancel.d.ts +46 -0
- package/dist/commands/cancel.js +239 -0
- package/dist/commands/cancel.js.map +1 -0
- package/dist/commands/cron.d.ts +8 -0
- package/dist/commands/cron.js +134 -0
- package/dist/commands/cron.js.map +1 -0
- package/dist/commands/dashboard/tab-actions.d.ts +10 -0
- package/dist/commands/dashboard/tab-actions.js +247 -0
- package/dist/commands/dashboard/tab-actions.js.map +1 -0
- package/dist/commands/dashboard/tab-config.d.ts +21 -0
- package/dist/commands/dashboard/tab-config.js +874 -0
- package/dist/commands/dashboard/tab-config.js.map +1 -0
- package/dist/commands/dashboard/tab-logs.d.ts +10 -0
- package/dist/commands/dashboard/tab-logs.js +202 -0
- package/dist/commands/dashboard/tab-logs.js.map +1 -0
- package/dist/commands/dashboard/tab-schedules.d.ts +21 -0
- package/dist/commands/dashboard/tab-schedules.js +320 -0
- package/dist/commands/dashboard/tab-schedules.js.map +1 -0
- package/dist/commands/dashboard/tab-status.d.ts +32 -0
- package/dist/commands/dashboard/tab-status.js +424 -0
- package/dist/commands/dashboard/tab-status.js.map +1 -0
- package/dist/commands/dashboard/types.d.ts +42 -0
- package/dist/commands/dashboard/types.js +5 -0
- package/dist/commands/dashboard/types.js.map +1 -0
- package/dist/commands/dashboard.d.ts +11 -0
- package/dist/commands/dashboard.js +242 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/doctor.d.ts +16 -0
- package/dist/commands/doctor.js +195 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/history.d.ts +7 -0
- package/dist/commands/history.js +49 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/init.d.ts +45 -0
- package/dist/commands/install.d.ts +65 -0
- package/dist/commands/install.js +405 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/logs.d.ts +15 -0
- package/dist/commands/logs.js +155 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/merge.d.ts +26 -0
- package/dist/commands/merge.js +159 -0
- package/dist/commands/merge.js.map +1 -0
- package/dist/commands/notify.d.ts +7 -0
- package/dist/commands/notify.js +43 -0
- package/dist/commands/notify.js.map +1 -0
- package/dist/commands/plan.d.ts +19 -0
- package/dist/commands/plan.js +88 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/prd-state.d.ts +12 -0
- package/dist/commands/prd-state.js +47 -0
- package/dist/commands/prd-state.js.map +1 -0
- package/dist/commands/prd.d.ts +18 -0
- package/dist/commands/prd.js +363 -0
- package/dist/commands/prd.js.map +1 -0
- package/dist/commands/prds.d.ts +13 -0
- package/dist/commands/prds.js +194 -0
- package/dist/commands/prds.js.map +1 -0
- package/dist/commands/prs.d.ts +14 -0
- package/dist/commands/prs.js +104 -0
- package/dist/commands/prs.js.map +1 -0
- package/dist/commands/qa.d.ts +34 -0
- package/dist/commands/qa.js +214 -0
- package/dist/commands/qa.js.map +1 -0
- package/dist/commands/queue.d.ts +8 -0
- package/dist/commands/queue.js +378 -0
- package/dist/commands/queue.js.map +1 -0
- package/dist/commands/resolve.d.ts +26 -0
- package/dist/commands/resolve.js +186 -0
- package/dist/commands/resolve.js.map +1 -0
- package/dist/commands/retry.d.ts +9 -0
- package/dist/commands/retry.js +71 -0
- package/dist/commands/retry.js.map +1 -0
- package/dist/commands/review.d.ts +77 -0
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +447 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/run.d.ts +73 -0
- package/dist/commands/serve.d.ts +19 -0
- package/dist/commands/serve.js +142 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/shared/env-builder.d.ts +49 -0
- package/dist/commands/shared/env-builder.js +151 -0
- package/dist/commands/shared/env-builder.js.map +1 -0
- package/dist/commands/slice.d.ts +35 -0
- package/dist/commands/slice.js +316 -0
- package/dist/commands/slice.js.map +1 -0
- package/dist/commands/state.d.ts +8 -0
- package/dist/commands/state.js +54 -0
- package/dist/commands/state.js.map +1 -0
- package/dist/commands/status.d.ts +14 -0
- package/dist/commands/status.js +297 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/summary.d.ts +14 -0
- package/dist/commands/summary.js +193 -0
- package/dist/commands/summary.js.map +1 -0
- package/dist/commands/uninstall.d.ts +25 -0
- package/dist/commands/uninstall.js +134 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/update.d.ts +22 -0
- package/dist/commands/update.js +90 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/scripts/night-watch-pr-reviewer-cron.sh +146 -32
- package/dist/templates/night-watch.config.json +1 -21
- package/package.json +1 -1
- package/dist/web/assets/index-B6E6kOoR.js +0 -406
- package/dist/web/assets/index-DIMUXIP8.css +0 -1
- package/dist/web/assets/index-NR27JE3b.js +0 -406
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Uninstall command for Night Watch CLI
|
|
3
|
+
* Removes crontab entries for the current project
|
|
4
|
+
*/
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import { dim, generateMarker, getEntries, getProjectEntries, getProjectName, removeEntriesForProject, success, error as uiError, unregisterProject, warn, } from '@night-watch/core';
|
|
8
|
+
/**
|
|
9
|
+
* Core uninstall logic, reusable from dashboard.
|
|
10
|
+
* Returns result without printing to console.
|
|
11
|
+
*/
|
|
12
|
+
export function performUninstall(projectDir, options) {
|
|
13
|
+
try {
|
|
14
|
+
const projectName = getProjectName(projectDir);
|
|
15
|
+
const marker = generateMarker(projectName);
|
|
16
|
+
const existingEntries = Array.from(new Set([...getEntries(marker), ...getProjectEntries(projectDir)]));
|
|
17
|
+
if (existingEntries.length === 0) {
|
|
18
|
+
unregisterProject(projectDir);
|
|
19
|
+
return { success: true, removedCount: 0 };
|
|
20
|
+
}
|
|
21
|
+
const removedCount = removeEntriesForProject(projectDir, marker);
|
|
22
|
+
unregisterProject(projectDir);
|
|
23
|
+
if (!options?.keepLogs) {
|
|
24
|
+
const logDir = path.join(projectDir, 'logs');
|
|
25
|
+
if (fs.existsSync(logDir)) {
|
|
26
|
+
const logFiles = [
|
|
27
|
+
'executor.log',
|
|
28
|
+
'reviewer.log',
|
|
29
|
+
'slicer.log',
|
|
30
|
+
'audit.log',
|
|
31
|
+
'pr-resolver.log',
|
|
32
|
+
];
|
|
33
|
+
logFiles.forEach((logFile) => {
|
|
34
|
+
const logPath = path.join(logDir, logFile);
|
|
35
|
+
if (fs.existsSync(logPath)) {
|
|
36
|
+
fs.unlinkSync(logPath);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
try {
|
|
40
|
+
const remainingFiles = fs.readdirSync(logDir);
|
|
41
|
+
if (remainingFiles.length === 0) {
|
|
42
|
+
fs.rmdirSync(logDir);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Ignore errors removing directory
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { success: true, removedCount };
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return {
|
|
54
|
+
success: false,
|
|
55
|
+
removedCount: 0,
|
|
56
|
+
error: err instanceof Error ? err.message : String(err),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Uninstall crontab entries for night-watch
|
|
62
|
+
*/
|
|
63
|
+
export function uninstallCommand(program) {
|
|
64
|
+
program
|
|
65
|
+
.command('uninstall')
|
|
66
|
+
.description('Remove crontab entries')
|
|
67
|
+
.option('--keep-logs', 'Preserve log files')
|
|
68
|
+
.action(async (options) => {
|
|
69
|
+
try {
|
|
70
|
+
// Get project directory
|
|
71
|
+
const projectDir = process.cwd();
|
|
72
|
+
// Get project name
|
|
73
|
+
const projectName = getProjectName(projectDir);
|
|
74
|
+
const marker = generateMarker(projectName);
|
|
75
|
+
// Check if there are entries to remove
|
|
76
|
+
const existingEntries = Array.from(new Set([...getEntries(marker), ...getProjectEntries(projectDir)]));
|
|
77
|
+
if (existingEntries.length === 0) {
|
|
78
|
+
warn(`No Night Watch crontab entries found for ${projectName}.`);
|
|
79
|
+
dim('Nothing to uninstall.');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// Show entries that will be removed
|
|
83
|
+
dim(`Removing Night Watch crontab entries for ${projectName}:`);
|
|
84
|
+
existingEntries.forEach((entry) => dim(` ${entry}`));
|
|
85
|
+
// Remove entries
|
|
86
|
+
const removedCount = removeEntriesForProject(projectDir, marker);
|
|
87
|
+
// Handle log files
|
|
88
|
+
if (!options.keepLogs) {
|
|
89
|
+
const logDir = path.join(projectDir, 'logs');
|
|
90
|
+
if (fs.existsSync(logDir)) {
|
|
91
|
+
const logFiles = [
|
|
92
|
+
'executor.log',
|
|
93
|
+
'reviewer.log',
|
|
94
|
+
'slicer.log',
|
|
95
|
+
'audit.log',
|
|
96
|
+
'pr-resolver.log',
|
|
97
|
+
];
|
|
98
|
+
let logsRemoved = 0;
|
|
99
|
+
logFiles.forEach((logFile) => {
|
|
100
|
+
const logPath = path.join(logDir, logFile);
|
|
101
|
+
if (fs.existsSync(logPath)) {
|
|
102
|
+
fs.unlinkSync(logPath);
|
|
103
|
+
logsRemoved++;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
// Try to remove log directory if empty
|
|
107
|
+
try {
|
|
108
|
+
const remainingFiles = fs.readdirSync(logDir);
|
|
109
|
+
if (remainingFiles.length === 0) {
|
|
110
|
+
fs.rmdirSync(logDir);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Ignore errors removing directory
|
|
115
|
+
}
|
|
116
|
+
if (logsRemoved > 0) {
|
|
117
|
+
console.log();
|
|
118
|
+
dim(`Removed ${logsRemoved} log file(s).`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
console.log();
|
|
124
|
+
dim('Log files preserved.');
|
|
125
|
+
}
|
|
126
|
+
success(`Successfully removed ${removedCount} crontab entry/entries.`);
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
uiError(`Error uninstalling Night Watch: ${err instanceof Error ? err.message : String(err)}`);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=uninstall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uninstall.js","sourceRoot":"","sources":["../../src/commands/uninstall.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update command for Night Watch CLI
|
|
3
|
+
* Reinstalls global CLI and refreshes cron entries for one or more projects.
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
export declare const DEFAULT_GLOBAL_SPEC = "@jonit-dev/night-watch-cli@latest";
|
|
7
|
+
export interface IUpdateOptions {
|
|
8
|
+
projects?: string;
|
|
9
|
+
globalSpec: string;
|
|
10
|
+
global?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Parse project directories from a comma-separated CLI option.
|
|
14
|
+
* Defaults to current working directory when option is omitted.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseProjectDirs(projects: string | undefined, cwd: string): string[];
|
|
17
|
+
export declare function shouldInstallGlobal(options: Pick<IUpdateOptions, 'global'>): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Register update command.
|
|
20
|
+
*/
|
|
21
|
+
export declare function updateCommand(program: Command): void;
|
|
22
|
+
//# sourceMappingURL=update.d.ts.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update command for Night Watch CLI
|
|
3
|
+
* Reinstalls global CLI and refreshes cron entries for one or more projects.
|
|
4
|
+
*/
|
|
5
|
+
import { spawnSync } from 'child_process';
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import { dim, success, error as uiError, warn } from '@night-watch/core';
|
|
9
|
+
export const DEFAULT_GLOBAL_SPEC = '@jonit-dev/night-watch-cli@latest';
|
|
10
|
+
/**
|
|
11
|
+
* Parse project directories from a comma-separated CLI option.
|
|
12
|
+
* Defaults to current working directory when option is omitted.
|
|
13
|
+
*/
|
|
14
|
+
export function parseProjectDirs(projects, cwd) {
|
|
15
|
+
if (!projects || projects.trim().length === 0) {
|
|
16
|
+
return [cwd];
|
|
17
|
+
}
|
|
18
|
+
const dirs = projects
|
|
19
|
+
.split(',')
|
|
20
|
+
.map((entry) => entry.trim())
|
|
21
|
+
.filter((entry) => entry.length > 0)
|
|
22
|
+
.map((entry) => path.resolve(cwd, entry));
|
|
23
|
+
return Array.from(new Set(dirs));
|
|
24
|
+
}
|
|
25
|
+
export function shouldInstallGlobal(options) {
|
|
26
|
+
return options.global !== false;
|
|
27
|
+
}
|
|
28
|
+
function runCommand(command, args, cwd) {
|
|
29
|
+
const result = spawnSync(command, args, {
|
|
30
|
+
cwd,
|
|
31
|
+
env: process.env,
|
|
32
|
+
stdio: 'inherit',
|
|
33
|
+
});
|
|
34
|
+
if (result.error) {
|
|
35
|
+
throw result.error;
|
|
36
|
+
}
|
|
37
|
+
if ((result.status ?? 1) !== 0) {
|
|
38
|
+
const location = cwd ? ` in ${cwd}` : '';
|
|
39
|
+
throw new Error(`Command failed${location}: ${command} ${args.join(' ')}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function resolveNightWatchBin() {
|
|
43
|
+
const result = spawnSync('which', ['night-watch'], {
|
|
44
|
+
encoding: 'utf-8',
|
|
45
|
+
env: process.env,
|
|
46
|
+
});
|
|
47
|
+
if (result.status === 0 && typeof result.stdout === 'string' && result.stdout.trim().length > 0) {
|
|
48
|
+
return result.stdout.trim();
|
|
49
|
+
}
|
|
50
|
+
return 'night-watch';
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Register update command.
|
|
54
|
+
*/
|
|
55
|
+
export function updateCommand(program) {
|
|
56
|
+
program
|
|
57
|
+
.command('update')
|
|
58
|
+
.description('Update global CLI and refresh cron for project(s)')
|
|
59
|
+
.option('--projects <dirs>', 'Comma-separated project directories (default: current directory)')
|
|
60
|
+
.option('--global-spec <spec>', 'npm package spec used for global install', DEFAULT_GLOBAL_SPEC)
|
|
61
|
+
.option('--no-global', 'Skip global npm install and only refresh project cron')
|
|
62
|
+
.action(async (options) => {
|
|
63
|
+
try {
|
|
64
|
+
const cwd = process.cwd();
|
|
65
|
+
const projectDirs = parseProjectDirs(options.projects, cwd);
|
|
66
|
+
if (shouldInstallGlobal(options)) {
|
|
67
|
+
dim(`Updating global install: npm install -g ${options.globalSpec}`);
|
|
68
|
+
runCommand('npm', ['install', '-g', options.globalSpec]);
|
|
69
|
+
success('Global CLI update completed.');
|
|
70
|
+
}
|
|
71
|
+
const nightWatchBin = resolveNightWatchBin();
|
|
72
|
+
for (const projectDir of projectDirs) {
|
|
73
|
+
if (!fs.existsSync(projectDir) || !fs.statSync(projectDir).isDirectory()) {
|
|
74
|
+
warn(`Skipping invalid project directory: ${projectDir}`);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
dim(`Refreshing cron in ${projectDir}`);
|
|
78
|
+
runCommand(nightWatchBin, ['uninstall'], projectDir);
|
|
79
|
+
runCommand(nightWatchBin, ['install'], projectDir);
|
|
80
|
+
success(`Refreshed project: ${projectDir}`);
|
|
81
|
+
}
|
|
82
|
+
success('Update completed.');
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
uiError(`Update failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
|
|
@@ -79,6 +79,9 @@ else
|
|
|
79
79
|
fi
|
|
80
80
|
|
|
81
81
|
SCRIPT_TYPE="reviewer"
|
|
82
|
+
READY_FOR_REVIEW_LABEL="${NW_READY_FOR_REVIEW_LABEL:-ready-for-review}"
|
|
83
|
+
READY_FOR_REVIEW_MARKER_NAME="night-watch-ready-for-review"
|
|
84
|
+
READY_TO_MERGE_LABEL="${NW_PR_RESOLVER_READY_LABEL:-ready-to-merge}"
|
|
82
85
|
|
|
83
86
|
emit_result() {
|
|
84
87
|
local status="${1:?status required}"
|
|
@@ -98,6 +101,80 @@ extract_review_score_from_text() {
|
|
|
98
101
|
| grep -oP '\d+(?=/100)' || echo ""
|
|
99
102
|
}
|
|
100
103
|
|
|
104
|
+
build_ready_for_review_marker() {
|
|
105
|
+
local head_sha="${1:-}"
|
|
106
|
+
[ -z "${head_sha}" ] && return 1
|
|
107
|
+
printf '<!-- %s headRefOid:%s -->' "${READY_FOR_REVIEW_MARKER_NAME}" "${head_sha}"
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
has_ready_for_human_review_marker() {
|
|
111
|
+
local comments_text="${1:-}"
|
|
112
|
+
local head_sha="${2:-}"
|
|
113
|
+
local marker=""
|
|
114
|
+
|
|
115
|
+
marker=$(build_ready_for_review_marker "${head_sha}" || true)
|
|
116
|
+
[ -z "${marker}" ] && return 1
|
|
117
|
+
|
|
118
|
+
printf '%s\n' "${comments_text}" | grep -Fq "${marker}"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
get_pr_comments() {
|
|
122
|
+
local pr_number="${1:?PR number required}"
|
|
123
|
+
|
|
124
|
+
{
|
|
125
|
+
gh pr view "${pr_number}" --json comments --jq '.comments[].body' 2>/dev/null || true
|
|
126
|
+
if [ -n "${REPO:-}" ]; then
|
|
127
|
+
gh api "repos/${REPO}/issues/${pr_number}/comments" --jq '.[].body' 2>/dev/null || true
|
|
128
|
+
fi
|
|
129
|
+
} | awk '!seen[$0]++'
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
get_pr_head_ref_oid() {
|
|
133
|
+
local pr_number="${1:?PR number required}"
|
|
134
|
+
gh pr view "${pr_number}" --json headRefOid --jq '.headRefOid' 2>/dev/null || echo ""
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
clear_ready_for_human_review_label() {
|
|
138
|
+
local pr_number="${1:?PR number required}"
|
|
139
|
+
gh pr edit "${pr_number}" --remove-label "${READY_FOR_REVIEW_LABEL}" 2>/dev/null || true
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
ensure_ready_for_human_review_comment() {
|
|
143
|
+
local pr_number="${1:?PR number required}"
|
|
144
|
+
local final_score="${2:-}"
|
|
145
|
+
local head_sha="${3:-}"
|
|
146
|
+
local comments_text=""
|
|
147
|
+
local marker=""
|
|
148
|
+
local score_note=""
|
|
149
|
+
local short_sha=""
|
|
150
|
+
local body=""
|
|
151
|
+
|
|
152
|
+
[ -z "${head_sha}" ] && return 0
|
|
153
|
+
|
|
154
|
+
comments_text=$(get_pr_comments "${pr_number}")
|
|
155
|
+
if has_ready_for_human_review_marker "${comments_text}" "${head_sha}"; then
|
|
156
|
+
gh pr edit "${pr_number}" --add-label "${READY_FOR_REVIEW_LABEL}" 2>/dev/null || true
|
|
157
|
+
return 0
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
marker=$(build_ready_for_review_marker "${head_sha}" || true)
|
|
161
|
+
short_sha=$(printf '%s' "${head_sha}" | cut -c1-12)
|
|
162
|
+
if [ -n "${final_score}" ]; then
|
|
163
|
+
score_note=" (score: ${final_score}/100)"
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
body="${marker}
|
|
167
|
+
|
|
168
|
+
## ✅ Ready for Human Review
|
|
169
|
+
|
|
170
|
+
Night Watch reviewed this PR${score_note} at commit \`${short_sha}\` and found no automated fixes to apply for the current head.
|
|
171
|
+
|
|
172
|
+
This PR is ready for human review and merge."
|
|
173
|
+
|
|
174
|
+
gh pr comment "${pr_number}" --body "${body}" 2>/dev/null || true
|
|
175
|
+
gh pr edit "${pr_number}" --add-label "${READY_FOR_REVIEW_LABEL}" 2>/dev/null || true
|
|
176
|
+
}
|
|
177
|
+
|
|
101
178
|
# ── Global Job Queue Gate ────────────────────────────────────────────────────
|
|
102
179
|
# Atomically claim a DB slot or enqueue for later dispatch — no flock needed.
|
|
103
180
|
if [ "${NW_QUEUE_ENABLED:-0}" = "1" ]; then
|
|
@@ -399,14 +476,7 @@ build_prd_context_prompt() {
|
|
|
399
476
|
get_pr_score() {
|
|
400
477
|
local pr_number="${1:?PR number required}"
|
|
401
478
|
local all_comments
|
|
402
|
-
all_comments=$(
|
|
403
|
-
{
|
|
404
|
-
gh pr view "${pr_number}" --json comments --jq '.comments[].body' 2>/dev/null || true
|
|
405
|
-
if [ -n "${REPO:-}" ]; then
|
|
406
|
-
gh api "repos/${REPO}/issues/${pr_number}/comments" --jq '.[].body' 2>/dev/null || true
|
|
407
|
-
fi
|
|
408
|
-
} | awk '!seen[$0]++'
|
|
409
|
-
)
|
|
479
|
+
all_comments=$(get_pr_comments "${pr_number}")
|
|
410
480
|
extract_review_score_from_text "${all_comments}"
|
|
411
481
|
}
|
|
412
482
|
|
|
@@ -612,8 +682,14 @@ fi
|
|
|
612
682
|
NEEDS_WORK=0
|
|
613
683
|
REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner' 2>/dev/null || echo "")
|
|
614
684
|
PRS_NEEDING_WORK=""
|
|
685
|
+
SKIPPED_ALREADY_REVIEWED_CURRENT_HEAD=0
|
|
615
686
|
|
|
616
687
|
while IFS=$'\t' read -r pr_number pr_branch pr_labels; do
|
|
688
|
+
local_ready_for_review_label_present=0
|
|
689
|
+
current_head_sha=""
|
|
690
|
+
all_comments=""
|
|
691
|
+
latest_score=""
|
|
692
|
+
|
|
617
693
|
if [ -z "${pr_number}" ] || [ -z "${pr_branch}" ]; then
|
|
618
694
|
continue
|
|
619
695
|
fi
|
|
@@ -626,6 +702,11 @@ while IFS=$'\t' read -r pr_number pr_branch pr_labels; do
|
|
|
626
702
|
continue
|
|
627
703
|
fi
|
|
628
704
|
|
|
705
|
+
if csv_has_label "${pr_labels:-}" "${READY_TO_MERGE_LABEL}"; then
|
|
706
|
+
log "INFO: PR #${pr_number} (${pr_branch}) is labeled ${READY_TO_MERGE_LABEL}; skipping automated review"
|
|
707
|
+
continue
|
|
708
|
+
fi
|
|
709
|
+
|
|
629
710
|
if printf '%s\n' "${pr_labels:-}" | tr ',' '\n' | grep -Fxq 'needs-human-review'; then
|
|
630
711
|
log "INFO: PR #${pr_number} (${pr_branch}) is labeled needs-human-review; skipping automated review"
|
|
631
712
|
continue
|
|
@@ -636,17 +717,58 @@ while IFS=$'\t' read -r pr_number pr_branch pr_labels; do
|
|
|
636
717
|
continue
|
|
637
718
|
fi
|
|
638
719
|
|
|
720
|
+
if csv_has_label "${pr_labels:-}" "${READY_FOR_REVIEW_LABEL}"; then
|
|
721
|
+
local_ready_for_review_label_present=1
|
|
722
|
+
fi
|
|
723
|
+
|
|
639
724
|
# Merge-conflict signal: this PR needs action even if CI and score look fine.
|
|
640
725
|
MERGE_STATE=$(gh pr view "${pr_number}" --json mergeStateStatus --jq '.mergeStateStatus' 2>/dev/null || echo "")
|
|
641
726
|
if [ "${MERGE_STATE}" = "DIRTY" ] || [ "${MERGE_STATE}" = "CONFLICTING" ]; then
|
|
727
|
+
if [ "${local_ready_for_review_label_present}" -eq 1 ]; then
|
|
728
|
+
log "INFO: PR #${pr_number} (${pr_branch}) is actionable again; removing stale ${READY_FOR_REVIEW_LABEL} label"
|
|
729
|
+
clear_ready_for_human_review_label "${pr_number}"
|
|
730
|
+
fi
|
|
642
731
|
log "INFO: PR #${pr_number} (${pr_branch}) has merge conflicts (${MERGE_STATE})"
|
|
643
732
|
NEEDS_WORK=1
|
|
644
733
|
PRS_NEEDING_WORK="${PRS_NEEDING_WORK} #${pr_number}"
|
|
645
734
|
continue
|
|
646
735
|
fi
|
|
647
736
|
|
|
737
|
+
current_head_sha=$(get_pr_head_ref_oid "${pr_number}")
|
|
738
|
+
all_comments=$(get_pr_comments "${pr_number}")
|
|
739
|
+
latest_score=$(extract_review_score_from_text "${all_comments}")
|
|
740
|
+
if [ -z "${latest_score}" ]; then
|
|
741
|
+
if [ "${local_ready_for_review_label_present}" -eq 1 ]; then
|
|
742
|
+
log "INFO: PR #${pr_number} (${pr_branch}) needs a fresh review; removing stale ${READY_FOR_REVIEW_LABEL} label"
|
|
743
|
+
clear_ready_for_human_review_label "${pr_number}"
|
|
744
|
+
fi
|
|
745
|
+
log "INFO: PR #${pr_number} (${pr_branch}) has no review score yet — needs initial review"
|
|
746
|
+
NEEDS_WORK=1
|
|
747
|
+
PRS_NEEDING_WORK="${PRS_NEEDING_WORK} #${pr_number}"
|
|
748
|
+
continue
|
|
749
|
+
elif [ "${latest_score}" -lt "${MIN_REVIEW_SCORE}" ]; then
|
|
750
|
+
if [ "${local_ready_for_review_label_present}" -eq 1 ]; then
|
|
751
|
+
log "INFO: PR #${pr_number} (${pr_branch}) fell below review threshold; removing stale ${READY_FOR_REVIEW_LABEL} label"
|
|
752
|
+
clear_ready_for_human_review_label "${pr_number}"
|
|
753
|
+
fi
|
|
754
|
+
log "INFO: PR #${pr_number} (${pr_branch}) has review score ${latest_score}/100 (threshold: ${MIN_REVIEW_SCORE})"
|
|
755
|
+
NEEDS_WORK=1
|
|
756
|
+
PRS_NEEDING_WORK="${PRS_NEEDING_WORK} #${pr_number}"
|
|
757
|
+
continue
|
|
758
|
+
fi
|
|
759
|
+
|
|
760
|
+
if has_ready_for_human_review_marker "${all_comments}" "${current_head_sha}"; then
|
|
761
|
+
SKIPPED_ALREADY_REVIEWED_CURRENT_HEAD=1
|
|
762
|
+
log "INFO: PR #${pr_number} (${pr_branch}) is already marked ready for human review at head ${current_head_sha:0:12}; skipping repeat automated review"
|
|
763
|
+
continue
|
|
764
|
+
fi
|
|
765
|
+
|
|
648
766
|
FAILED_CHECKS=$(get_pr_failed_ci_checks "${pr_number}")
|
|
649
767
|
if [ "${FAILED_CHECKS}" -gt 0 ]; then
|
|
768
|
+
if [ "${local_ready_for_review_label_present}" -eq 1 ]; then
|
|
769
|
+
log "INFO: PR #${pr_number} (${pr_branch}) is actionable again; removing stale ${READY_FOR_REVIEW_LABEL} label"
|
|
770
|
+
clear_ready_for_human_review_label "${pr_number}"
|
|
771
|
+
fi
|
|
650
772
|
FAILED_SUMMARY=$(get_pr_failed_ci_summary "${pr_number}")
|
|
651
773
|
if [ -n "${FAILED_SUMMARY}" ]; then
|
|
652
774
|
log "INFO: PR #${pr_number} (${pr_branch}) has ${FAILED_CHECKS} failed CI check(s): ${FAILED_SUMMARY}"
|
|
@@ -655,26 +777,6 @@ while IFS=$'\t' read -r pr_number pr_branch pr_labels; do
|
|
|
655
777
|
fi
|
|
656
778
|
NEEDS_WORK=1
|
|
657
779
|
PRS_NEEDING_WORK="${PRS_NEEDING_WORK} #${pr_number}"
|
|
658
|
-
continue
|
|
659
|
-
fi
|
|
660
|
-
|
|
661
|
-
ALL_COMMENTS=$(
|
|
662
|
-
{
|
|
663
|
-
gh pr view "${pr_number}" --json comments --jq '.comments[].body' 2>/dev/null || true
|
|
664
|
-
if [ -n "${REPO}" ]; then
|
|
665
|
-
gh api "repos/${REPO}/issues/${pr_number}/comments" --jq '.[].body' 2>/dev/null || true
|
|
666
|
-
fi
|
|
667
|
-
} | awk '!seen[$0]++'
|
|
668
|
-
)
|
|
669
|
-
LATEST_SCORE=$(extract_review_score_from_text "${ALL_COMMENTS}")
|
|
670
|
-
if [ -z "${LATEST_SCORE}" ]; then
|
|
671
|
-
log "INFO: PR #${pr_number} (${pr_branch}) has no review score yet — needs initial review"
|
|
672
|
-
NEEDS_WORK=1
|
|
673
|
-
PRS_NEEDING_WORK="${PRS_NEEDING_WORK} #${pr_number}"
|
|
674
|
-
elif [ "${LATEST_SCORE}" -lt "${MIN_REVIEW_SCORE}" ]; then
|
|
675
|
-
log "INFO: PR #${pr_number} (${pr_branch}) has review score ${LATEST_SCORE}/100 (threshold: ${MIN_REVIEW_SCORE})"
|
|
676
|
-
NEEDS_WORK=1
|
|
677
|
-
PRS_NEEDING_WORK="${PRS_NEEDING_WORK} #${pr_number}"
|
|
678
780
|
fi
|
|
679
781
|
done < <(
|
|
680
782
|
gh pr list --state open --json number,headRefName,labels \
|
|
@@ -682,14 +784,25 @@ done < <(
|
|
|
682
784
|
)
|
|
683
785
|
|
|
684
786
|
if [ "${NEEDS_WORK}" -eq 0 ]; then
|
|
685
|
-
|
|
787
|
+
if [ "${SKIPPED_ALREADY_REVIEWED_CURRENT_HEAD}" -eq 1 ]; then
|
|
788
|
+
log "SKIP: All ${OPEN_PRS} open PR(s) already pass review threshold or have already been reviewed for their current head"
|
|
686
789
|
|
|
687
|
-
|
|
688
|
-
|
|
790
|
+
if [ "${WORKER_MODE}" != "1" ]; then
|
|
791
|
+
send_telegram_status_message "🔍 Night Watch Reviewer: nothing actionable" "Project: ${PROJECT_NAME}
|
|
792
|
+
Provider (model): ${PROVIDER_MODEL_DISPLAY}
|
|
793
|
+
Result: all ${OPEN_PRS} matching PRs either already pass review threshold or were already reviewed for their current head."
|
|
794
|
+
fi
|
|
795
|
+
emit_result "skip_no_actionable_prs"
|
|
796
|
+
else
|
|
797
|
+
log "SKIP: All ${OPEN_PRS} open PR(s) have passing CI and review score >= ${MIN_REVIEW_SCORE}"
|
|
798
|
+
|
|
799
|
+
if [ "${WORKER_MODE}" != "1" ]; then
|
|
800
|
+
send_telegram_status_message "🔍 Night Watch Reviewer: nothing to do" "Project: ${PROJECT_NAME}
|
|
689
801
|
Provider (model): ${PROVIDER_MODEL_DISPLAY}
|
|
690
802
|
Result: all ${OPEN_PRS} matching PRs already pass CI and review threshold (${MIN_REVIEW_SCORE})."
|
|
803
|
+
fi
|
|
804
|
+
emit_result "skip_all_passing"
|
|
691
805
|
fi
|
|
692
|
-
emit_result "skip_all_passing"
|
|
693
806
|
exit 0
|
|
694
807
|
fi
|
|
695
808
|
|
|
@@ -1215,6 +1328,7 @@ if [ "${EXIT_CODE}" -eq 0 ] && [ -n "${TARGET_PR}" ] && [ -n "${PR_BRANCH_HEAD_B
|
|
|
1215
1328
|
NO_CHANGES_NEEDED=1
|
|
1216
1329
|
NO_CHANGES_PRS="#${TARGET_PR}"
|
|
1217
1330
|
log "INFO: PR #${TARGET_PR} — reviewer made no commits; marking as ready for human review"
|
|
1331
|
+
ensure_ready_for_human_review_comment "${TARGET_PR}" "${FINAL_SCORE}" "${PR_BRANCH_HEAD_AFTER}"
|
|
1218
1332
|
fi
|
|
1219
1333
|
fi
|
|
1220
1334
|
|
|
@@ -55,9 +55,7 @@
|
|
|
55
55
|
"audit": 10
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
|
-
"jobProviders": {
|
|
59
|
-
"reviewer": "g51claude"
|
|
60
|
-
},
|
|
58
|
+
"jobProviders": {},
|
|
61
59
|
"autoMerge": false,
|
|
62
60
|
"autoMergeMethod": "squash",
|
|
63
61
|
"fallbackOnRateLimit": true,
|
|
@@ -75,23 +73,5 @@
|
|
|
75
73
|
"enabled": true,
|
|
76
74
|
"schedule": "50 3 * * 1",
|
|
77
75
|
"maxRuntime": 1800
|
|
78
|
-
},
|
|
79
|
-
"providerPresets": {
|
|
80
|
-
"g51claude": {
|
|
81
|
-
"name": "GLM-5.1 Claude",
|
|
82
|
-
"command": "claude",
|
|
83
|
-
"promptFlag": "-p",
|
|
84
|
-
"autoApproveFlag": "--dangerously-skip-permissions",
|
|
85
|
-
"modelFlag": "--model",
|
|
86
|
-
"model": "glm-5.1",
|
|
87
|
-
"envVars": {
|
|
88
|
-
"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
|
|
89
|
-
"API_TIMEOUT_MS": "3000000",
|
|
90
|
-
"ANTHROPIC_DEFAULT_OPUS_MODEL": "glm-5.1",
|
|
91
|
-
"ANTHROPIC_DEFAULT_SONNET_MODEL": "glm-5.1",
|
|
92
|
-
"ANTHROPIC_AUTH_TOKEN": "efaeca456dab4ae69cb9ce1fa8d99a1a.KSTifNTWPS6NgC6L",
|
|
93
|
-
"ANTHROPIC_API_KEY": "efaeca456dab4ae69cb9ce1fa8d99a1a.KSTifNTWPS6NgC6L"
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
76
|
}
|
|
97
77
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jonit-dev/night-watch-cli",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.12-beta.1",
|
|
4
4
|
"description": "AI agent that implements your specs, opens PRs, and reviews code overnight. Queue GitHub issues or PRDs, wake up to pull requests.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|