@nk070281sjv/cli 2.3.6 → 2.3.7
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 +143 -19
- 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.7" : createRequire(import.meta.url)("../../package.json").version;
|
|
30783
30783
|
|
|
30784
30784
|
// src/lib/deps.ts
|
|
30785
30785
|
init_src();
|
|
@@ -31821,9 +31821,9 @@ var NodeFsHandler = class {
|
|
|
31821
31821
|
if (this.fsw.closed) {
|
|
31822
31822
|
return;
|
|
31823
31823
|
}
|
|
31824
|
-
const
|
|
31824
|
+
const dirname13 = sysPath.dirname(file);
|
|
31825
31825
|
const basename9 = sysPath.basename(file);
|
|
31826
|
-
const parent = this.fsw._getWatchedDir(
|
|
31826
|
+
const parent = this.fsw._getWatchedDir(dirname13);
|
|
31827
31827
|
let prevStats = stats;
|
|
31828
31828
|
if (parent.has(basename9))
|
|
31829
31829
|
return;
|
|
@@ -31850,7 +31850,7 @@ var NodeFsHandler = class {
|
|
|
31850
31850
|
prevStats = newStats2;
|
|
31851
31851
|
}
|
|
31852
31852
|
} catch (error) {
|
|
31853
|
-
this.fsw._remove(
|
|
31853
|
+
this.fsw._remove(dirname13, basename9);
|
|
31854
31854
|
}
|
|
31855
31855
|
} else if (parent.has(basename9)) {
|
|
31856
31856
|
const at = newStats.atimeMs;
|
|
@@ -37409,6 +37409,10 @@ async function writeRoundArtifact(roundDir, relativePath, content) {
|
|
|
37409
37409
|
import { mkdir as mkdir2, readFile, writeFile as writeFile2 } from "node:fs/promises";
|
|
37410
37410
|
import { existsSync as existsSync21 } from "node:fs";
|
|
37411
37411
|
import { dirname as dirname10, join as join25 } from "node:path";
|
|
37412
|
+
import { execFile } from "node:child_process";
|
|
37413
|
+
import { promisify } from "node:util";
|
|
37414
|
+
var execFileAsync = promisify(execFile);
|
|
37415
|
+
var GIT_SNAPSHOT_LIMIT = 2e4;
|
|
37412
37416
|
async function prepareReviewContext(input) {
|
|
37413
37417
|
const roundDir = join25(input.sessionDir, "rounds", `round-${input.round}`);
|
|
37414
37418
|
await mkdir2(roundDir, { recursive: true });
|
|
@@ -37425,6 +37429,7 @@ async function prepareReviewContext(input) {
|
|
|
37425
37429
|
"# Review Context\n\nNo shared review context has been recorded yet.\n"
|
|
37426
37430
|
);
|
|
37427
37431
|
const reviewBriefPath = join25(roundDir, "review-brief.md");
|
|
37432
|
+
const gitSnapshot = input.cwd ? await collectGitSnapshot(input.cwd) : void 0;
|
|
37428
37433
|
await writeFile2(
|
|
37429
37434
|
reviewBriefPath,
|
|
37430
37435
|
[
|
|
@@ -37434,6 +37439,37 @@ async function prepareReviewContext(input) {
|
|
|
37434
37439
|
`Round: ${input.round}`,
|
|
37435
37440
|
`Discovered standards: ${discoveredStandardsPath}`,
|
|
37436
37441
|
`Shared context: ${contextPath}`,
|
|
37442
|
+
...input.cwd ? [`Repository root: ${input.cwd}`] : [],
|
|
37443
|
+
"",
|
|
37444
|
+
"## Scope",
|
|
37445
|
+
"",
|
|
37446
|
+
"Review the current working tree changes. Focus on changed files and the unchanged code needed to validate those changes.",
|
|
37447
|
+
"Do not review generated OCR session artifacts under `.ocr/sessions/` unless they are explicitly part of the requested change.",
|
|
37448
|
+
"",
|
|
37449
|
+
...gitSnapshot ? [
|
|
37450
|
+
"## Git Status",
|
|
37451
|
+
"",
|
|
37452
|
+
fenced("text", gitSnapshot.status || "No working tree changes reported."),
|
|
37453
|
+
"",
|
|
37454
|
+
"## Changed Files",
|
|
37455
|
+
"",
|
|
37456
|
+
fenced("text", gitSnapshot.changedFiles || "No changed files reported."),
|
|
37457
|
+
"",
|
|
37458
|
+
"## Diff Stat",
|
|
37459
|
+
"",
|
|
37460
|
+
fenced("text", gitSnapshot.diffStat || "No diff stat available."),
|
|
37461
|
+
""
|
|
37462
|
+
] : [
|
|
37463
|
+
"## Git Snapshot",
|
|
37464
|
+
"",
|
|
37465
|
+
"No repository snapshot was captured by the CLI.",
|
|
37466
|
+
""
|
|
37467
|
+
],
|
|
37468
|
+
"## Reviewer Guidance",
|
|
37469
|
+
"",
|
|
37470
|
+
"- Read this brief first, then inspect relevant changed files and surrounding code as needed.",
|
|
37471
|
+
"- Prefer targeted `git diff -- <path>` and file reads over broad repository scans.",
|
|
37472
|
+
"- Report only findings supported by code evidence and concrete file references.",
|
|
37437
37473
|
""
|
|
37438
37474
|
].join("\n"),
|
|
37439
37475
|
"utf-8"
|
|
@@ -37478,6 +37514,49 @@ async function prepareReviewContext(input) {
|
|
|
37478
37514
|
requirementsExpected: Boolean(requirementsPath)
|
|
37479
37515
|
};
|
|
37480
37516
|
}
|
|
37517
|
+
async function collectGitSnapshot(cwd) {
|
|
37518
|
+
const [status, cachedFiles, worktreeFiles, diffStat] = await Promise.all([
|
|
37519
|
+
runGit(cwd, ["status", "--short"]),
|
|
37520
|
+
runGit(cwd, ["diff", "--cached", "--name-only"]),
|
|
37521
|
+
runGit(cwd, ["diff", "--name-only", "HEAD"]),
|
|
37522
|
+
runGit(cwd, ["diff", "--stat", "HEAD"])
|
|
37523
|
+
]);
|
|
37524
|
+
return {
|
|
37525
|
+
status,
|
|
37526
|
+
changedFiles: uniqueLines(`${cachedFiles}
|
|
37527
|
+
${worktreeFiles}`),
|
|
37528
|
+
diffStat
|
|
37529
|
+
};
|
|
37530
|
+
}
|
|
37531
|
+
async function runGit(cwd, args) {
|
|
37532
|
+
try {
|
|
37533
|
+
const { stdout, stderr } = await execFileAsync("git", args, {
|
|
37534
|
+
cwd,
|
|
37535
|
+
maxBuffer: GIT_SNAPSHOT_LIMIT * 2
|
|
37536
|
+
});
|
|
37537
|
+
return truncate(`${stdout}${stderr ? `
|
|
37538
|
+
${stderr}` : ""}`.trim());
|
|
37539
|
+
} catch (error) {
|
|
37540
|
+
if (error && typeof error === "object" && "stdout" in error && typeof error.stdout === "string") {
|
|
37541
|
+
return truncate(error.stdout.trim());
|
|
37542
|
+
}
|
|
37543
|
+
return "";
|
|
37544
|
+
}
|
|
37545
|
+
}
|
|
37546
|
+
function uniqueLines(value) {
|
|
37547
|
+
const lines = value.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
37548
|
+
return [...new Set(lines)].join("\n");
|
|
37549
|
+
}
|
|
37550
|
+
function truncate(value) {
|
|
37551
|
+
if (value.length <= GIT_SNAPSHOT_LIMIT) return value;
|
|
37552
|
+
return `${value.slice(0, GIT_SNAPSHOT_LIMIT)}
|
|
37553
|
+
[truncated by OCR CLI]`;
|
|
37554
|
+
}
|
|
37555
|
+
function fenced(language, value) {
|
|
37556
|
+
return `\`\`\`${language}
|
|
37557
|
+
${value}
|
|
37558
|
+
\`\`\``;
|
|
37559
|
+
}
|
|
37481
37560
|
async function ensureMarkdownFile(path2, fallbackContent) {
|
|
37482
37561
|
if (existsSync21(path2)) {
|
|
37483
37562
|
await readFile(path2, "utf-8");
|
|
@@ -37554,7 +37633,7 @@ var OpenCodeProcessRunner = class {
|
|
|
37554
37633
|
constructor(options = {}) {
|
|
37555
37634
|
this.spawn = options.spawn ?? spawnBinary;
|
|
37556
37635
|
this.promptArgvLimit = options.promptArgvLimit ?? DEFAULT_PROMPT_ARGV_LIMIT;
|
|
37557
|
-
this.serveReadyTimeoutMs = options.serveReadyTimeoutMs ??
|
|
37636
|
+
this.serveReadyTimeoutMs = options.serveReadyTimeoutMs ?? 12e4;
|
|
37558
37637
|
this.pure = options.pure ?? true;
|
|
37559
37638
|
}
|
|
37560
37639
|
async run(request, signal) {
|
|
@@ -37764,7 +37843,7 @@ function isRecord(value) {
|
|
|
37764
37843
|
|
|
37765
37844
|
// src/lib/agent-orchestrator/prompt-writer.ts
|
|
37766
37845
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
37767
|
-
import { join as join26, relative as relative3 } from "node:path";
|
|
37846
|
+
import { dirname as dirname11, join as join26, relative as relative3 } from "node:path";
|
|
37768
37847
|
async function writePromptSnapshots(input) {
|
|
37769
37848
|
const promptsDir = join26(input.context.roundDir, "prompts");
|
|
37770
37849
|
const reviewsDir = join26(input.context.roundDir, "reviews");
|
|
@@ -37833,6 +37912,7 @@ function reviewerPrompt(context, reviewer, promptPath, reviewPath) {
|
|
|
37833
37912
|
"Phase: reviews",
|
|
37834
37913
|
"",
|
|
37835
37914
|
"Input files to read before reviewing:",
|
|
37915
|
+
`- ${reviewerPersonaPath(context, reviewer)}`,
|
|
37836
37916
|
`- ${context.discoveredStandardsPath}`,
|
|
37837
37917
|
`- ${context.contextPath}`,
|
|
37838
37918
|
`- ${context.reviewBriefPath}`,
|
|
@@ -37846,8 +37926,14 @@ function reviewerPrompt(context, reviewer, promptPath, reviewPath) {
|
|
|
37846
37926
|
` - ${relative3(context.roundDir, context.discoveredStandardsPath)}`,
|
|
37847
37927
|
` - ${relative3(context.roundDir, context.contextPath)}`,
|
|
37848
37928
|
` - ${relative3(context.roundDir, context.reviewBriefPath)}`,
|
|
37929
|
+
` - ${relative3(context.roundDir, reviewerPersonaPath(context, reviewer))}`,
|
|
37849
37930
|
...context.requirementsPath ? [` - ${relative3(context.roundDir, context.requirementsPath)}`] : [],
|
|
37850
37931
|
"",
|
|
37932
|
+
"Review focus:",
|
|
37933
|
+
"- Apply the reviewer persona file as your primary review lens.",
|
|
37934
|
+
"- Use the review brief as the source of truth for changed files and scope.",
|
|
37935
|
+
"- Inspect surrounding source code only when needed to validate a finding.",
|
|
37936
|
+
"",
|
|
37851
37937
|
"Output contract:",
|
|
37852
37938
|
`- Return review markdown through stdout for ${reviewPath}.`,
|
|
37853
37939
|
"- Do not write files directly.",
|
|
@@ -37862,6 +37948,10 @@ function reviewerPrompt(context, reviewer, promptPath, reviewPath) {
|
|
|
37862
37948
|
""
|
|
37863
37949
|
].join("\n");
|
|
37864
37950
|
}
|
|
37951
|
+
function reviewerPersonaPath(context, reviewer) {
|
|
37952
|
+
const ocrDir = dirname11(dirname11(context.sessionDir));
|
|
37953
|
+
return join26(ocrDir, "skills", "references", "reviewers", `${reviewer.persona}.md`);
|
|
37954
|
+
}
|
|
37865
37955
|
function pipelinePrompt(context, stage, agent, promptPath, artifactPath) {
|
|
37866
37956
|
return [
|
|
37867
37957
|
`# Pipeline Agent: ${stage}`,
|
|
@@ -37938,6 +38028,18 @@ async function runReviewerPhase(input) {
|
|
|
37938
38028
|
};
|
|
37939
38029
|
});
|
|
37940
38030
|
const requests = reviewerRequests.map((item) => item.request);
|
|
38031
|
+
const running = new Set(requests.map((request) => request.id));
|
|
38032
|
+
const completed = /* @__PURE__ */ new Set();
|
|
38033
|
+
const progressTimer = setInterval(() => {
|
|
38034
|
+
emit({
|
|
38035
|
+
event: "reviews:progress",
|
|
38036
|
+
phase: "reviews",
|
|
38037
|
+
completed: completed.size,
|
|
38038
|
+
total: requests.length,
|
|
38039
|
+
running: [...running].sort()
|
|
38040
|
+
});
|
|
38041
|
+
}, 3e4);
|
|
38042
|
+
progressTimer.unref?.();
|
|
37941
38043
|
const promises = reviewerRequests.map(async ({ reviewer, request }) => {
|
|
37942
38044
|
const agentSessionId = await journal.startInstance({
|
|
37943
38045
|
workflowId: input.context.sessionId,
|
|
@@ -37959,6 +38061,8 @@ async function runReviewerPhase(input) {
|
|
|
37959
38061
|
});
|
|
37960
38062
|
const result = await input.runner.run(request, controller.signal);
|
|
37961
38063
|
const logPaths = await writeProcessLogs(input.context.roundDir, request, result);
|
|
38064
|
+
running.delete(request.id);
|
|
38065
|
+
completed.add(request.id);
|
|
37962
38066
|
emit({
|
|
37963
38067
|
event: "agent:complete",
|
|
37964
38068
|
phase: "reviews",
|
|
@@ -37977,15 +38081,19 @@ async function runReviewerPhase(input) {
|
|
|
37977
38081
|
return result;
|
|
37978
38082
|
});
|
|
37979
38083
|
const results = [];
|
|
37980
|
-
|
|
37981
|
-
|
|
37982
|
-
|
|
37983
|
-
|
|
37984
|
-
|
|
37985
|
-
|
|
37986
|
-
|
|
37987
|
-
|
|
37988
|
-
|
|
38084
|
+
try {
|
|
38085
|
+
await Promise.all(
|
|
38086
|
+
promises.map(async (promise) => {
|
|
38087
|
+
const result = await promise;
|
|
38088
|
+
results.push(result);
|
|
38089
|
+
if (result.exitCode !== 0) {
|
|
38090
|
+
controller.abort();
|
|
38091
|
+
}
|
|
38092
|
+
})
|
|
38093
|
+
);
|
|
38094
|
+
} finally {
|
|
38095
|
+
clearInterval(progressTimer);
|
|
38096
|
+
}
|
|
37989
38097
|
const failed = results.find((result) => result.exitCode !== 0);
|
|
37990
38098
|
if (failed) {
|
|
37991
38099
|
const failedRequest = requests.find((request) => request.id === failed.id);
|
|
@@ -38052,7 +38160,8 @@ async function runOpenCodeProcessAgentReview(input) {
|
|
|
38052
38160
|
sessionId: input.sessionId,
|
|
38053
38161
|
sessionDir: input.sessionDir,
|
|
38054
38162
|
round: input.round,
|
|
38055
|
-
requirements: input.requirements
|
|
38163
|
+
requirements: input.requirements,
|
|
38164
|
+
cwd: input.cwd
|
|
38056
38165
|
});
|
|
38057
38166
|
const snapshot = await writePromptSnapshots({
|
|
38058
38167
|
context,
|
|
@@ -38254,6 +38363,9 @@ async function writeProcessLogs(roundDir, request, result) {
|
|
|
38254
38363
|
const stdoutPath = `${prefix}.stdout.ndjson`;
|
|
38255
38364
|
const stderrPath = `${prefix}.stderr.log`;
|
|
38256
38365
|
const metaPath = `${prefix}.meta.json`;
|
|
38366
|
+
const absoluteMetaPath = join27(roundDir, metaPath);
|
|
38367
|
+
const startedAt = readStartedAt(absoluteMetaPath) ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
38368
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
38257
38369
|
await writeRoundArtifact(roundDir, stdoutPath, result.stdout);
|
|
38258
38370
|
await writeRoundArtifact(roundDir, stderrPath, result.stderr);
|
|
38259
38371
|
await writeRoundArtifact(
|
|
@@ -38267,7 +38379,9 @@ async function writeProcessLogs(roundDir, request, result) {
|
|
|
38267
38379
|
model: request.model,
|
|
38268
38380
|
prompt_path: request.promptPath,
|
|
38269
38381
|
status: "completed",
|
|
38270
|
-
|
|
38382
|
+
started_at: startedAt,
|
|
38383
|
+
completed_at: completedAt,
|
|
38384
|
+
duration_ms: Math.max(0, Date.parse(completedAt) - Date.parse(startedAt)),
|
|
38271
38385
|
exit_code: result.exitCode,
|
|
38272
38386
|
output_text_bytes: Buffer.byteLength(processOutput(result), "utf-8"),
|
|
38273
38387
|
stdout_bytes: Buffer.byteLength(result.stdout, "utf-8"),
|
|
@@ -38280,6 +38394,16 @@ async function writeProcessLogs(roundDir, request, result) {
|
|
|
38280
38394
|
);
|
|
38281
38395
|
return { stdout: stdoutPath, stderr: stderrPath, meta: metaPath };
|
|
38282
38396
|
}
|
|
38397
|
+
function readStartedAt(path2) {
|
|
38398
|
+
if (!existsSync22(path2)) return void 0;
|
|
38399
|
+
try {
|
|
38400
|
+
const parsed = JSON.parse(readFileSync16(path2, "utf-8"));
|
|
38401
|
+
if (!isRecord2(parsed)) return void 0;
|
|
38402
|
+
return typeof parsed.started_at === "string" ? parsed.started_at : void 0;
|
|
38403
|
+
} catch {
|
|
38404
|
+
return void 0;
|
|
38405
|
+
}
|
|
38406
|
+
}
|
|
38283
38407
|
function processOutput(result) {
|
|
38284
38408
|
return result.outputText ?? result.stdout;
|
|
38285
38409
|
}
|
|
@@ -38760,12 +38884,12 @@ var updateCommand = new Command("update").description("Update OCR assets after p
|
|
|
38760
38884
|
|
|
38761
38885
|
// src/commands/dashboard.ts
|
|
38762
38886
|
import { existsSync as existsSync25 } from "node:fs";
|
|
38763
|
-
import { join as join30, dirname as
|
|
38887
|
+
import { join as join30, dirname as dirname12 } from "node:path";
|
|
38764
38888
|
import { fileURLToPath } from "node:url";
|
|
38765
38889
|
init_src();
|
|
38766
38890
|
init_db();
|
|
38767
38891
|
var __filename = fileURLToPath(import.meta.url);
|
|
38768
|
-
var __dirname =
|
|
38892
|
+
var __dirname = dirname12(__filename);
|
|
38769
38893
|
function resolveServerPath() {
|
|
38770
38894
|
return join30(__dirname, "dashboard", "server.js");
|
|
38771
38895
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nk070281sjv/cli",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.7",
|
|
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.7",
|
|
41
41
|
"chalk": "^5.4.1",
|
|
42
42
|
"chokidar": "^4.0.3",
|
|
43
43
|
"commander": "^13.0.0",
|