@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.
Files changed (2) hide show
  1. package/dist/index.js +143 -19
  2. 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.6" : createRequire(import.meta.url)("../../package.json").version;
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 dirname12 = sysPath.dirname(file);
31824
+ const dirname13 = sysPath.dirname(file);
31825
31825
  const basename9 = sysPath.basename(file);
31826
- const parent = this.fsw._getWatchedDir(dirname12);
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(dirname12, basename9);
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 ?? 15e3;
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
- await Promise.all(
37981
- promises.map(async (promise) => {
37982
- const result = await promise;
37983
- results.push(result);
37984
- if (result.exitCode !== 0) {
37985
- controller.abort();
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
- completed_at: (/* @__PURE__ */ new Date()).toISOString(),
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 dirname11 } from "node:path";
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 = dirname11(__filename);
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.6",
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.6",
40
+ "@nk070281sjv/agents": "2.3.7",
41
41
  "chalk": "^5.4.1",
42
42
  "chokidar": "^4.0.3",
43
43
  "commander": "^13.0.0",