@nk070281sjv/cli 2.3.7 → 2.3.10
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/index.js +363 -20
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -30779,7 +30779,7 @@ ${hint}
|
|
|
30779
30779
|
}
|
|
30780
30780
|
|
|
30781
30781
|
// src/lib/version.ts
|
|
30782
|
-
var CLI_VERSION = true ? "2.3.
|
|
30782
|
+
var CLI_VERSION = true ? "2.3.10" : createRequire(import.meta.url)("../../package.json").version;
|
|
30783
30783
|
|
|
30784
30784
|
// src/lib/deps.ts
|
|
30785
30785
|
init_src();
|
|
@@ -37218,7 +37218,15 @@ var teamCommand = new Command("team").description("Resolve and persist team comp
|
|
|
37218
37218
|
// src/commands/review.ts
|
|
37219
37219
|
init_src();
|
|
37220
37220
|
import { join as join28 } from "node:path";
|
|
37221
|
-
import {
|
|
37221
|
+
import {
|
|
37222
|
+
closeSync,
|
|
37223
|
+
existsSync as existsSync23,
|
|
37224
|
+
mkdirSync as mkdirSync8,
|
|
37225
|
+
openSync,
|
|
37226
|
+
readdirSync as readdirSync9,
|
|
37227
|
+
readFileSync as readFileSync17,
|
|
37228
|
+
writeFileSync as writeFileSync9
|
|
37229
|
+
} from "node:fs";
|
|
37222
37230
|
init_db();
|
|
37223
37231
|
|
|
37224
37232
|
// ../shared/config/src/pipeline-config.ts
|
|
@@ -37413,6 +37421,7 @@ import { execFile } from "node:child_process";
|
|
|
37413
37421
|
import { promisify } from "node:util";
|
|
37414
37422
|
var execFileAsync = promisify(execFile);
|
|
37415
37423
|
var GIT_SNAPSHOT_LIMIT = 2e4;
|
|
37424
|
+
var REVIEW_SNAPSHOT_EXCLUDES = [".ocr", ".opencode"];
|
|
37416
37425
|
async function prepareReviewContext(input) {
|
|
37417
37426
|
const roundDir = join25(input.sessionDir, "rounds", `round-${input.round}`);
|
|
37418
37427
|
await mkdir2(roundDir, { recursive: true });
|
|
@@ -37444,7 +37453,7 @@ async function prepareReviewContext(input) {
|
|
|
37444
37453
|
"## Scope",
|
|
37445
37454
|
"",
|
|
37446
37455
|
"Review the current working tree changes. Focus on changed files and the unchanged code needed to validate those changes.",
|
|
37447
|
-
"
|
|
37456
|
+
"Ignore local AI tooling/config churn under `.ocr/` and `.opencode/` unless the user explicitly asks to review OCR/OpenCode setup changes.",
|
|
37448
37457
|
"",
|
|
37449
37458
|
...gitSnapshot ? [
|
|
37450
37459
|
"## Git Status",
|
|
@@ -37517,17 +37526,20 @@ async function prepareReviewContext(input) {
|
|
|
37517
37526
|
async function collectGitSnapshot(cwd) {
|
|
37518
37527
|
const [status, cachedFiles, worktreeFiles, diffStat] = await Promise.all([
|
|
37519
37528
|
runGit(cwd, ["status", "--short"]),
|
|
37520
|
-
runGit(cwd, ["diff", "--cached", "--name-only"]),
|
|
37521
|
-
runGit(cwd, ["diff", "--name-only", "HEAD"]),
|
|
37522
|
-
runGit(cwd, ["diff", "--stat", "HEAD"])
|
|
37529
|
+
runGit(cwd, ["diff", "--cached", "--name-only", "--", ...gitReviewPathspec()]),
|
|
37530
|
+
runGit(cwd, ["diff", "--name-only", "HEAD", "--", ...gitReviewPathspec()]),
|
|
37531
|
+
runGit(cwd, ["diff", "--stat", "HEAD", "--", ...gitReviewPathspec()])
|
|
37523
37532
|
]);
|
|
37524
37533
|
return {
|
|
37525
|
-
status,
|
|
37526
|
-
changedFiles: uniqueLines(`${cachedFiles}
|
|
37527
|
-
${worktreeFiles}`),
|
|
37534
|
+
status: filterIgnoredStatusLines(status),
|
|
37535
|
+
changedFiles: filterIgnoredPaths(uniqueLines(`${cachedFiles}
|
|
37536
|
+
${worktreeFiles}`)),
|
|
37528
37537
|
diffStat
|
|
37529
37538
|
};
|
|
37530
37539
|
}
|
|
37540
|
+
function gitReviewPathspec() {
|
|
37541
|
+
return [".", ...REVIEW_SNAPSHOT_EXCLUDES.map((path2) => `:(exclude)${path2}`)];
|
|
37542
|
+
}
|
|
37531
37543
|
async function runGit(cwd, args) {
|
|
37532
37544
|
try {
|
|
37533
37545
|
const { stdout, stderr } = await execFileAsync("git", args, {
|
|
@@ -37547,6 +37559,21 @@ function uniqueLines(value) {
|
|
|
37547
37559
|
const lines = value.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
37548
37560
|
return [...new Set(lines)].join("\n");
|
|
37549
37561
|
}
|
|
37562
|
+
function filterIgnoredStatusLines(value) {
|
|
37563
|
+
return value.split(/\r?\n/).filter((line) => {
|
|
37564
|
+
const pathPart = line.slice(3).trim();
|
|
37565
|
+
return !isIgnoredReviewPath(pathPart);
|
|
37566
|
+
}).join("\n");
|
|
37567
|
+
}
|
|
37568
|
+
function filterIgnoredPaths(value) {
|
|
37569
|
+
return value.split(/\r?\n/).filter((line) => !isIgnoredReviewPath(line.trim())).join("\n");
|
|
37570
|
+
}
|
|
37571
|
+
function isIgnoredReviewPath(path2) {
|
|
37572
|
+
const normalized = path2.replace(/^"|"$/g, "");
|
|
37573
|
+
return REVIEW_SNAPSHOT_EXCLUDES.some(
|
|
37574
|
+
(ignored) => normalized === ignored || normalized.startsWith(`${ignored}/`)
|
|
37575
|
+
);
|
|
37576
|
+
}
|
|
37550
37577
|
function truncate(value) {
|
|
37551
37578
|
if (value.length <= GIT_SNAPSHOT_LIMIT) return value;
|
|
37552
37579
|
return `${value.slice(0, GIT_SNAPSHOT_LIMIT)}
|
|
@@ -38038,7 +38065,7 @@ async function runReviewerPhase(input) {
|
|
|
38038
38065
|
total: requests.length,
|
|
38039
38066
|
running: [...running].sort()
|
|
38040
38067
|
});
|
|
38041
|
-
},
|
|
38068
|
+
}, 15e3);
|
|
38042
38069
|
progressTimer.unref?.();
|
|
38043
38070
|
const promises = reviewerRequests.map(async ({ reviewer, request }) => {
|
|
38044
38071
|
const agentSessionId = await journal.startInstance({
|
|
@@ -38174,7 +38201,12 @@ async function runOpenCodeProcessAgentReview(input) {
|
|
|
38174
38201
|
round: input.round,
|
|
38175
38202
|
reviewers: snapshot.resolvedTeam.reviewers.length
|
|
38176
38203
|
});
|
|
38177
|
-
emit({
|
|
38204
|
+
emit({
|
|
38205
|
+
event: "reviews:start",
|
|
38206
|
+
session_id: input.sessionId,
|
|
38207
|
+
round: input.round,
|
|
38208
|
+
reviewers: snapshot.resolvedTeam.reviewers.length
|
|
38209
|
+
});
|
|
38178
38210
|
const reviewerResult = await runReviewerPhase({
|
|
38179
38211
|
context,
|
|
38180
38212
|
resolvedTeam: snapshot.resolvedTeam,
|
|
@@ -38268,7 +38300,21 @@ async function runPipelineStages(input) {
|
|
|
38268
38300
|
prompt_path: request.promptPath,
|
|
38269
38301
|
meta_log: startLogPaths.meta
|
|
38270
38302
|
});
|
|
38271
|
-
const
|
|
38303
|
+
const progressTimer = setInterval(() => {
|
|
38304
|
+
emit({
|
|
38305
|
+
event: "agent:progress",
|
|
38306
|
+
phase: stage,
|
|
38307
|
+
id: request.id,
|
|
38308
|
+
status: "running"
|
|
38309
|
+
});
|
|
38310
|
+
}, 15e3);
|
|
38311
|
+
progressTimer.unref?.();
|
|
38312
|
+
let result;
|
|
38313
|
+
try {
|
|
38314
|
+
result = await input.runner.run(request, new AbortController().signal);
|
|
38315
|
+
} finally {
|
|
38316
|
+
clearInterval(progressTimer);
|
|
38317
|
+
}
|
|
38272
38318
|
const logPaths = await writeProcessLogs(input.context.roundDir, request, result);
|
|
38273
38319
|
emit({
|
|
38274
38320
|
event: "agent:complete",
|
|
@@ -38542,12 +38588,15 @@ function newSessionId() {
|
|
|
38542
38588
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
38543
38589
|
return `${date}-opencode-process-review-${Date.now()}`;
|
|
38544
38590
|
}
|
|
38545
|
-
var runAgentsSubcommand = new Command("run-agents").description("Run OCR review through OpenCode process agents").argument("[target]", "Target path for fresh dashboard mode", ".").option("--session-id <workflow-session-id>", "Prepared workflow session id").option("--round <n>", "Prepared round number", (value) => Number.parseInt(value, 10)).option("--fresh", "Create a fresh workflow session before running process agents").option("--requirements <text-or-path>", "Inline requirements text or path to a requirements file").option("--team <json>", "JSON ReviewerInstance[] override for this run").action(
|
|
38591
|
+
var runAgentsSubcommand = new Command("run-agents").description("Run OCR review through OpenCode process agents").argument("[target]", "Target path for fresh dashboard mode", ".").option("--session-id <workflow-session-id>", "Prepared workflow session id").option("--round <n>", "Prepared round number", (value) => Number.parseInt(value, 10)).option("--fresh", "Create a fresh workflow session before running process agents").option("--requirements <text-or-path>", "Inline requirements text or path to a requirements file").option("--team <json>", "JSON ReviewerInstance[] override for this run").option("--foreground", "Run in the current process instead of detaching a background worker").addOption(new Option("--worker", "Internal detached worker mode").hideHelp()).action(
|
|
38546
38592
|
async (target, options) => {
|
|
38547
38593
|
const targetDir = process.cwd();
|
|
38548
38594
|
requireOcrSetup(targetDir);
|
|
38549
38595
|
const ocrDir = join28(targetDir, ".ocr");
|
|
38550
38596
|
const db = await ensureDatabase(ocrDir);
|
|
38597
|
+
let sessionDirForMeta;
|
|
38598
|
+
let roundForMeta;
|
|
38599
|
+
const modeForMeta = options.worker ? "worker" : options.foreground ? "foreground" : "detached";
|
|
38551
38600
|
try {
|
|
38552
38601
|
let sessionId = options.sessionId;
|
|
38553
38602
|
let round = options.round;
|
|
@@ -38578,6 +38627,35 @@ var runAgentsSubcommand = new Command("run-agents").description("Run OCR review
|
|
|
38578
38627
|
round = round ?? session.current_round;
|
|
38579
38628
|
sessionDir = session.session_dir;
|
|
38580
38629
|
}
|
|
38630
|
+
sessionDirForMeta = sessionDir;
|
|
38631
|
+
roundForMeta = round;
|
|
38632
|
+
if (!options.foreground && !options.worker) {
|
|
38633
|
+
const spawned = spawnDetachedRunAgents({
|
|
38634
|
+
targetDir,
|
|
38635
|
+
target,
|
|
38636
|
+
sessionId,
|
|
38637
|
+
sessionDir,
|
|
38638
|
+
round,
|
|
38639
|
+
requirements: options.requirements,
|
|
38640
|
+
team: options.team
|
|
38641
|
+
});
|
|
38642
|
+
console.log(`OCR review started in background.`);
|
|
38643
|
+
console.log(`Session: ${sessionId}`);
|
|
38644
|
+
console.log(`Round: ${round}`);
|
|
38645
|
+
console.log(`PID: ${spawned.pid}`);
|
|
38646
|
+
console.log(`Progress: ocr review watch --session-id ${sessionId}`);
|
|
38647
|
+
console.log(`Status: ocr review status --session-id ${sessionId}`);
|
|
38648
|
+
console.log(`Artifacts: ${sessionDir}`);
|
|
38649
|
+
console.log("Monitoring background review until it finishes. If OpenCode stops waiting, the background review continues.");
|
|
38650
|
+
const exitCode = await waitForDetachedRun(sessionDir, round);
|
|
38651
|
+
process.exit(exitCode);
|
|
38652
|
+
}
|
|
38653
|
+
writeRunMeta(sessionDir, round, {
|
|
38654
|
+
status: "running",
|
|
38655
|
+
mode: options.worker ? "worker" : "foreground",
|
|
38656
|
+
pid: process.pid,
|
|
38657
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
38658
|
+
});
|
|
38581
38659
|
const { team } = loadTeamConfig(ocrDir);
|
|
38582
38660
|
const override = options.team ? parseTeamOverride(options.team) : void 0;
|
|
38583
38661
|
const reviewers = resolveTeamComposition(team, override);
|
|
@@ -38591,18 +38669,281 @@ var runAgentsSubcommand = new Command("run-agents").description("Run OCR review
|
|
|
38591
38669
|
pipelineAgents,
|
|
38592
38670
|
requirements: readRequirements(options.requirements),
|
|
38593
38671
|
journal: new PersistenceAgentLifecycleJournal(ocrDir),
|
|
38594
|
-
emit: (event) =>
|
|
38672
|
+
emit: (event) => {
|
|
38673
|
+
console.log(JSON.stringify(event));
|
|
38674
|
+
renderRunAgentsProgress(event);
|
|
38675
|
+
}
|
|
38595
38676
|
});
|
|
38596
38677
|
if (!result.ok) {
|
|
38678
|
+
writeRunMeta(sessionDir, round, {
|
|
38679
|
+
status: "failed",
|
|
38680
|
+
mode: options.worker ? "worker" : "foreground",
|
|
38681
|
+
pid: process.pid,
|
|
38682
|
+
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
38683
|
+
errors: result.errors
|
|
38684
|
+
});
|
|
38597
38685
|
for (const error of result.errors) console.error(source_default.red(error));
|
|
38598
38686
|
process.exit(1);
|
|
38599
38687
|
}
|
|
38688
|
+
writeRunMeta(sessionDir, round, {
|
|
38689
|
+
status: "completed",
|
|
38690
|
+
mode: options.worker ? "worker" : "foreground",
|
|
38691
|
+
pid: process.pid,
|
|
38692
|
+
completed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
38693
|
+
});
|
|
38600
38694
|
console.log(JSON.stringify({ event: "review:complete", session_id: sessionId, round }));
|
|
38601
38695
|
} catch (error) {
|
|
38696
|
+
if (sessionDirForMeta && roundForMeta) {
|
|
38697
|
+
writeRunMeta(sessionDirForMeta, roundForMeta, {
|
|
38698
|
+
status: "failed",
|
|
38699
|
+
mode: modeForMeta,
|
|
38700
|
+
pid: process.pid,
|
|
38701
|
+
completed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
38702
|
+
errors: [error instanceof Error ? error.message : "Failed to run OpenCode process-agent review"]
|
|
38703
|
+
});
|
|
38704
|
+
}
|
|
38602
38705
|
fail3(error instanceof Error ? error.message : "Failed to run OpenCode process-agent review");
|
|
38603
38706
|
}
|
|
38604
38707
|
}
|
|
38605
38708
|
);
|
|
38709
|
+
var statusSubcommand2 = new Command("status").description("Show process-agent review status").requiredOption("--session-id <workflow-session-id>", "Workflow session id").option("--round <n>", "Round number", (value) => Number.parseInt(value, 10)).action(async (options) => {
|
|
38710
|
+
const targetDir = process.cwd();
|
|
38711
|
+
requireOcrSetup(targetDir);
|
|
38712
|
+
const ocrDir = join28(targetDir, ".ocr");
|
|
38713
|
+
const db = await ensureDatabase(ocrDir);
|
|
38714
|
+
const session = getSession(db, options.sessionId);
|
|
38715
|
+
if (!session) fail3(`Workflow session not found: ${options.sessionId}`);
|
|
38716
|
+
renderReviewStatus(session.session_dir, options.round ?? session.current_round);
|
|
38717
|
+
});
|
|
38718
|
+
var watchSubcommand = new Command("watch").description("Watch process-agent review progress").requiredOption("--session-id <workflow-session-id>", "Workflow session id").option("--round <n>", "Round number", (value) => Number.parseInt(value, 10)).option("--interval <seconds>", "Refresh interval", (value) => Number.parseInt(value, 10), 2).action(async (options) => {
|
|
38719
|
+
const targetDir = process.cwd();
|
|
38720
|
+
requireOcrSetup(targetDir);
|
|
38721
|
+
const ocrDir = join28(targetDir, ".ocr");
|
|
38722
|
+
const db = await ensureDatabase(ocrDir);
|
|
38723
|
+
const session = getSession(db, options.sessionId);
|
|
38724
|
+
if (!session) fail3(`Workflow session not found: ${options.sessionId}`);
|
|
38725
|
+
const round = options.round ?? session.current_round;
|
|
38726
|
+
renderReviewStatus(session.session_dir, round);
|
|
38727
|
+
setInterval(() => {
|
|
38728
|
+
process.stdout.write("\x1Bc");
|
|
38729
|
+
renderReviewStatus(session.session_dir, round);
|
|
38730
|
+
}, Math.max(1, options.interval) * 1e3);
|
|
38731
|
+
});
|
|
38732
|
+
function spawnDetachedRunAgents(input) {
|
|
38733
|
+
const roundDir = join28(input.sessionDir, "rounds", `round-${input.round}`);
|
|
38734
|
+
mkdirSync8(join28(roundDir, "process-logs"), { recursive: true });
|
|
38735
|
+
const stdoutPath = join28(roundDir, "process-logs", "run-agents-worker.stdout.log");
|
|
38736
|
+
const stderrPath = join28(roundDir, "process-logs", "run-agents-worker.stderr.log");
|
|
38737
|
+
const outFd = openSync(stdoutPath, "a");
|
|
38738
|
+
const errFd = openSync(stderrPath, "a");
|
|
38739
|
+
const entrypoint = process.argv[1];
|
|
38740
|
+
if (!entrypoint) fail3("Cannot locate OCR CLI entrypoint for background worker.");
|
|
38741
|
+
const args = [
|
|
38742
|
+
entrypoint,
|
|
38743
|
+
"review",
|
|
38744
|
+
"run-agents",
|
|
38745
|
+
input.target,
|
|
38746
|
+
"--session-id",
|
|
38747
|
+
input.sessionId,
|
|
38748
|
+
"--round",
|
|
38749
|
+
String(input.round),
|
|
38750
|
+
"--worker",
|
|
38751
|
+
"--foreground",
|
|
38752
|
+
...input.requirements ? ["--requirements", input.requirements] : [],
|
|
38753
|
+
...input.team ? ["--team", input.team] : []
|
|
38754
|
+
];
|
|
38755
|
+
const child = spawnBinary(process.execPath, args, {
|
|
38756
|
+
cwd: input.targetDir,
|
|
38757
|
+
detached: true,
|
|
38758
|
+
stdio: ["ignore", outFd, errFd]
|
|
38759
|
+
});
|
|
38760
|
+
child.unref();
|
|
38761
|
+
closeSync(outFd);
|
|
38762
|
+
closeSync(errFd);
|
|
38763
|
+
writeRunMeta(input.sessionDir, input.round, {
|
|
38764
|
+
status: "spawned",
|
|
38765
|
+
mode: "detached",
|
|
38766
|
+
pid: child.pid,
|
|
38767
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
38768
|
+
stdout_log: stdoutPath,
|
|
38769
|
+
stderr_log: stderrPath
|
|
38770
|
+
});
|
|
38771
|
+
return { pid: child.pid };
|
|
38772
|
+
}
|
|
38773
|
+
function writeRunMeta(sessionDir, round, patch) {
|
|
38774
|
+
const roundDir = join28(sessionDir, "rounds", `round-${round}`);
|
|
38775
|
+
mkdirSync8(roundDir, { recursive: true });
|
|
38776
|
+
const path2 = join28(roundDir, "run-meta.json");
|
|
38777
|
+
let current = { schema_version: 1 };
|
|
38778
|
+
if (existsSync23(path2)) {
|
|
38779
|
+
try {
|
|
38780
|
+
const parsed = JSON.parse(readFileSync17(path2, "utf-8"));
|
|
38781
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
38782
|
+
current = parsed;
|
|
38783
|
+
}
|
|
38784
|
+
} catch {
|
|
38785
|
+
current = { schema_version: 1 };
|
|
38786
|
+
}
|
|
38787
|
+
}
|
|
38788
|
+
writeFileSync9(path2, JSON.stringify({ ...current, ...patch }, null, 2), "utf-8");
|
|
38789
|
+
}
|
|
38790
|
+
function renderReviewStatus(sessionDir, round) {
|
|
38791
|
+
const roundDir = join28(sessionDir, "rounds", `round-${round}`);
|
|
38792
|
+
const processLogsDir = join28(roundDir, "process-logs");
|
|
38793
|
+
const runMeta = readJson(join28(roundDir, "run-meta.json"));
|
|
38794
|
+
console.log(source_default.bold(`OCR review status: ${sessionDir}`));
|
|
38795
|
+
console.log(`Round: ${round}`);
|
|
38796
|
+
if (runMeta) {
|
|
38797
|
+
const pid = typeof runMeta.pid === "number" ? runMeta.pid : void 0;
|
|
38798
|
+
console.log(
|
|
38799
|
+
`Runner: ${String(runMeta.status ?? "unknown")}${pid ? ` pid=${pid} live=${isPidLive(pid) ? "yes" : "no"}` : ""}`
|
|
38800
|
+
);
|
|
38801
|
+
}
|
|
38802
|
+
const metas = existsSync23(processLogsDir) ? readdirMetaFiles(processLogsDir).map((path2) => readJson(path2)).filter(isRecord3) : [];
|
|
38803
|
+
const reviewers = metas.filter((meta) => meta.phase === "reviews");
|
|
38804
|
+
const completedReviewers = reviewers.filter((meta) => meta.status === "completed");
|
|
38805
|
+
const runningReviewers = reviewers.filter((meta) => meta.status === "running");
|
|
38806
|
+
console.log(`Reviews: ${completedReviewers.length}/${reviewers.length || "?"} complete`);
|
|
38807
|
+
if (runningReviewers.length > 0) {
|
|
38808
|
+
console.log(`Running reviewers: ${runningReviewers.map((meta) => meta.id).join(", ")}`);
|
|
38809
|
+
}
|
|
38810
|
+
for (const phase of ["aggregation", "validation", "synthesis"]) {
|
|
38811
|
+
const meta = metas.find((item) => item.id === phase);
|
|
38812
|
+
console.log(`Pipeline ${phase}: ${String(meta?.status ?? "pending")}`);
|
|
38813
|
+
}
|
|
38814
|
+
if (existsSync23(join28(roundDir, "final.md"))) {
|
|
38815
|
+
console.log(source_default.green(`Final: ${join28(roundDir, "final.md")}`));
|
|
38816
|
+
}
|
|
38817
|
+
}
|
|
38818
|
+
function readdirMetaFiles(dir) {
|
|
38819
|
+
return existsSync23(dir) ? Array.from(new Set(readdirSync9(dir))).filter((name) => name.endsWith(".meta.json")).sort().map((name) => join28(dir, name)) : [];
|
|
38820
|
+
}
|
|
38821
|
+
function readJson(path2) {
|
|
38822
|
+
if (!existsSync23(path2)) return void 0;
|
|
38823
|
+
try {
|
|
38824
|
+
const parsed = JSON.parse(readFileSync17(path2, "utf-8"));
|
|
38825
|
+
return isRecord3(parsed) ? parsed : void 0;
|
|
38826
|
+
} catch {
|
|
38827
|
+
return void 0;
|
|
38828
|
+
}
|
|
38829
|
+
}
|
|
38830
|
+
function isPidLive(pid) {
|
|
38831
|
+
try {
|
|
38832
|
+
process.kill(pid, 0);
|
|
38833
|
+
return true;
|
|
38834
|
+
} catch {
|
|
38835
|
+
return false;
|
|
38836
|
+
}
|
|
38837
|
+
}
|
|
38838
|
+
function isRecord3(value) {
|
|
38839
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
38840
|
+
}
|
|
38841
|
+
function renderRunAgentsProgress(event) {
|
|
38842
|
+
const name = typeof event.event === "string" ? event.event : "";
|
|
38843
|
+
if (name === "reviews:start") {
|
|
38844
|
+
console.error(
|
|
38845
|
+
source_default.cyan(
|
|
38846
|
+
`OCR reviewers started: ${String(event.reviewers ?? "?")} agents running in parallel.`
|
|
38847
|
+
)
|
|
38848
|
+
);
|
|
38849
|
+
return;
|
|
38850
|
+
}
|
|
38851
|
+
if (name === "agent:start") {
|
|
38852
|
+
console.error(
|
|
38853
|
+
source_default.dim(
|
|
38854
|
+
`OCR agent started: ${String(event.id ?? "?")} (${String(event.phase ?? "?")}, ${String(event.model ?? "?")})`
|
|
38855
|
+
)
|
|
38856
|
+
);
|
|
38857
|
+
return;
|
|
38858
|
+
}
|
|
38859
|
+
if (name === "reviews:progress") {
|
|
38860
|
+
const running = Array.isArray(event.running) ? event.running.join(", ") : "?";
|
|
38861
|
+
console.error(
|
|
38862
|
+
source_default.cyan(
|
|
38863
|
+
`OCR reviews progress: ${String(event.completed ?? "?")}/${String(event.total ?? "?")} complete; running: ${running || "none"}`
|
|
38864
|
+
)
|
|
38865
|
+
);
|
|
38866
|
+
return;
|
|
38867
|
+
}
|
|
38868
|
+
if (name === "agent:complete") {
|
|
38869
|
+
console.error(
|
|
38870
|
+
source_default.green(
|
|
38871
|
+
`OCR agent completed: ${String(event.id ?? "?")} exit=${String(event.exit_code ?? "?")}`
|
|
38872
|
+
)
|
|
38873
|
+
);
|
|
38874
|
+
return;
|
|
38875
|
+
}
|
|
38876
|
+
if (name === "agent:progress") {
|
|
38877
|
+
console.error(
|
|
38878
|
+
source_default.cyan(
|
|
38879
|
+
`OCR agent still running: ${String(event.id ?? "?")} (${String(event.phase ?? "?")})`
|
|
38880
|
+
)
|
|
38881
|
+
);
|
|
38882
|
+
return;
|
|
38883
|
+
}
|
|
38884
|
+
if (name === "pipeline:start") {
|
|
38885
|
+
console.error(source_default.cyan("OCR pipeline started: aggregation -> validation -> synthesis."));
|
|
38886
|
+
return;
|
|
38887
|
+
}
|
|
38888
|
+
if (name === "pipeline:complete") {
|
|
38889
|
+
console.error(source_default.green("OCR pipeline complete."));
|
|
38890
|
+
}
|
|
38891
|
+
}
|
|
38892
|
+
async function waitForDetachedRun(sessionDir, round) {
|
|
38893
|
+
let lastLine2 = "";
|
|
38894
|
+
while (true) {
|
|
38895
|
+
const snapshot = readDetachedSnapshot(sessionDir, round);
|
|
38896
|
+
const line = formatDetachedProgress(snapshot);
|
|
38897
|
+
if (line !== lastLine2) {
|
|
38898
|
+
console.log(line);
|
|
38899
|
+
lastLine2 = line;
|
|
38900
|
+
}
|
|
38901
|
+
if (snapshot.status === "completed") {
|
|
38902
|
+
console.log(source_default.green(`OCR review complete: ${join28(sessionDir, "rounds", `round-${round}`, "final.md")}`));
|
|
38903
|
+
return 0;
|
|
38904
|
+
}
|
|
38905
|
+
if (snapshot.status === "failed") {
|
|
38906
|
+
console.error(source_default.red("OCR review failed. Inspect worker stderr and failure-summary.json if present."));
|
|
38907
|
+
return 1;
|
|
38908
|
+
}
|
|
38909
|
+
if (snapshot.pid && !snapshot.live && snapshot.status !== "completed") {
|
|
38910
|
+
console.error(source_default.red("OCR background worker is not running and did not mark the review complete."));
|
|
38911
|
+
return 1;
|
|
38912
|
+
}
|
|
38913
|
+
await new Promise((resolve4) => setTimeout(resolve4, 15e3));
|
|
38914
|
+
}
|
|
38915
|
+
}
|
|
38916
|
+
function readDetachedSnapshot(sessionDir, round) {
|
|
38917
|
+
const roundDir = join28(sessionDir, "rounds", `round-${round}`);
|
|
38918
|
+
const runMeta = readJson(join28(roundDir, "run-meta.json"));
|
|
38919
|
+
const processLogsDir = join28(roundDir, "process-logs");
|
|
38920
|
+
const metas = existsSync23(processLogsDir) ? readdirMetaFiles(processLogsDir).map((path2) => readJson(path2)).filter(isRecord3) : [];
|
|
38921
|
+
const reviewers = metas.filter((meta) => meta.phase === "reviews");
|
|
38922
|
+
const pid = typeof runMeta?.pid === "number" ? runMeta.pid : void 0;
|
|
38923
|
+
return {
|
|
38924
|
+
status: String(runMeta?.status ?? "unknown"),
|
|
38925
|
+
pid,
|
|
38926
|
+
live: pid ? isPidLive(pid) : void 0,
|
|
38927
|
+
completedReviews: reviewers.filter((meta) => meta.status === "completed").length,
|
|
38928
|
+
totalReviews: reviewers.length,
|
|
38929
|
+
runningReviews: reviewers.filter((meta) => meta.status === "running").map((meta) => String(meta.id)).sort(),
|
|
38930
|
+
pipeline: Object.fromEntries(
|
|
38931
|
+
["aggregation", "validation", "synthesis"].map((phase) => [
|
|
38932
|
+
phase,
|
|
38933
|
+
String(metas.find((meta) => meta.id === phase)?.status ?? "pending")
|
|
38934
|
+
])
|
|
38935
|
+
)
|
|
38936
|
+
};
|
|
38937
|
+
}
|
|
38938
|
+
function formatDetachedProgress(snapshot) {
|
|
38939
|
+
const running = snapshot.runningReviews.length > 0 ? snapshot.runningReviews.join(", ") : "none";
|
|
38940
|
+
return [
|
|
38941
|
+
`OCR background status: ${snapshot.status}${snapshot.pid ? ` pid=${snapshot.pid} live=${snapshot.live ? "yes" : "no"}` : ""}`,
|
|
38942
|
+
`reviews ${snapshot.completedReviews}/${snapshot.totalReviews || "?"} complete`,
|
|
38943
|
+
`running: ${running}`,
|
|
38944
|
+
`pipeline: aggregation=${snapshot.pipeline.aggregation}, validation=${snapshot.pipeline.validation}, synthesis=${snapshot.pipeline.synthesis}`
|
|
38945
|
+
].join(" | ");
|
|
38946
|
+
}
|
|
38606
38947
|
var CONTROL_PROMPT = "Resume this OCR review: run `ocr state status --json` and act on `next_action`, continuing forward from `current_phase` without redoing completed phases.";
|
|
38607
38948
|
var reviewCommand = new Command("review").description("Run or resume an OCR review").option("--resume <workflow-id>", "Resume a prior review by its workflow session id").action(async (options) => {
|
|
38608
38949
|
if (!options.resume) {
|
|
@@ -38723,6 +39064,8 @@ var reviewCommand = new Command("review").description("Run or resume an OCR revi
|
|
|
38723
39064
|
});
|
|
38724
39065
|
});
|
|
38725
39066
|
reviewCommand.addCommand(runAgentsSubcommand);
|
|
39067
|
+
reviewCommand.addCommand(statusSubcommand2);
|
|
39068
|
+
reviewCommand.addCommand(watchSubcommand);
|
|
38726
39069
|
|
|
38727
39070
|
// src/commands/update.ts
|
|
38728
39071
|
import { existsSync as existsSync24 } from "node:fs";
|
|
@@ -39409,7 +39752,7 @@ var pruneBackupsSubcommand = new Command("prune-backups").description("Delete ol
|
|
|
39409
39752
|
var dbCommand = new Command("db").description("Inspect and maintain the OCR SQLite database").addCommand(doctorSubcommand).addCommand(vacuumSubcommand).addCommand(pruneSubcommand).addCommand(pruneBackupsSubcommand);
|
|
39410
39753
|
|
|
39411
39754
|
// src/commands/reviewers.ts
|
|
39412
|
-
import { writeFileSync as
|
|
39755
|
+
import { writeFileSync as writeFileSync10, renameSync as renameSync2 } from "node:fs";
|
|
39413
39756
|
import { join as join33 } from "node:path";
|
|
39414
39757
|
init_src();
|
|
39415
39758
|
async function readStdin3() {
|
|
@@ -39518,7 +39861,7 @@ var syncSubcommand2 = new Command("sync").description("Sync reviewers-meta.json
|
|
|
39518
39861
|
}
|
|
39519
39862
|
const metaPath = join33(ocrDir, "reviewers-meta.json");
|
|
39520
39863
|
const tmpPath = metaPath + ".tmp";
|
|
39521
|
-
|
|
39864
|
+
writeFileSync10(tmpPath, JSON.stringify(meta, null, 2) + "\n");
|
|
39522
39865
|
renameSync2(tmpPath, metaPath);
|
|
39523
39866
|
const tierCounts = meta.reviewers.reduce(
|
|
39524
39867
|
(acc, r) => {
|
|
@@ -39548,7 +39891,7 @@ var syncSubcommand2 = new Command("sync").description("Sync reviewers-meta.json
|
|
|
39548
39891
|
const meta = validateReviewersMeta(parsed);
|
|
39549
39892
|
const metaPath = join33(ocrDir, "reviewers-meta.json");
|
|
39550
39893
|
const tmpPath = metaPath + ".tmp";
|
|
39551
|
-
|
|
39894
|
+
writeFileSync10(tmpPath, JSON.stringify(meta, null, 2) + "\n");
|
|
39552
39895
|
renameSync2(tmpPath, metaPath);
|
|
39553
39896
|
const tierCounts = meta.reviewers.reduce(
|
|
39554
39897
|
(acc, r) => {
|
|
@@ -39623,7 +39966,7 @@ var hostCommand = new Command("host").description("Inspect host (AI CLI) capabil
|
|
|
39623
39966
|
// src/lib/update-check.ts
|
|
39624
39967
|
import { homedir } from "node:os";
|
|
39625
39968
|
import { join as join34 } from "node:path";
|
|
39626
|
-
import { readFileSync as readFileSync19, writeFileSync as
|
|
39969
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync11, mkdirSync as mkdirSync9 } from "node:fs";
|
|
39627
39970
|
var PACKAGE_NAME = "@open-code-review/cli";
|
|
39628
39971
|
var REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
39629
39972
|
var CACHE_DIR2 = join34(homedir(), ".ocr");
|
|
@@ -39639,8 +39982,8 @@ function readCache(cacheFile) {
|
|
|
39639
39982
|
}
|
|
39640
39983
|
function writeCache(cacheFile, cache2) {
|
|
39641
39984
|
try {
|
|
39642
|
-
|
|
39643
|
-
|
|
39985
|
+
mkdirSync9(join34(cacheFile, ".."), { recursive: true });
|
|
39986
|
+
writeFileSync11(cacheFile, JSON.stringify(cache2));
|
|
39644
39987
|
} catch {
|
|
39645
39988
|
}
|
|
39646
39989
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nk070281sjv/cli",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.10",
|
|
4
4
|
"description": "CLI for Open Code Review - Multi-environment setup and progress tracking",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@inquirer/prompts": "^7.2.0",
|
|
40
|
-
"@nk070281sjv/agents": "2.3.
|
|
40
|
+
"@nk070281sjv/agents": "2.3.10",
|
|
41
41
|
"chalk": "^5.4.1",
|
|
42
42
|
"chokidar": "^4.0.3",
|
|
43
43
|
"commander": "^13.0.0",
|