@nk070281sjv/cli 2.3.22 → 2.3.23

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 (59) hide show
  1. package/README.md +7 -18
  2. package/dist/index.js +142 -151
  3. package/package.json +2 -3
  4. package/dist/dashboard/client/assets/_basePickBy-CZOJm2vF.js +0 -1
  5. package/dist/dashboard/client/assets/_baseUniq-BNrzwRTV.js +0 -1
  6. package/dist/dashboard/client/assets/arc-Bl8fh4M2.js +0 -1
  7. package/dist/dashboard/client/assets/architectureDiagram-VXUJARFQ-TTtHv-xF.js +0 -36
  8. package/dist/dashboard/client/assets/blockDiagram-VD42YOAC-Civ0_twg.js +0 -122
  9. package/dist/dashboard/client/assets/c4Diagram-YG6GDRKO-FpPihNtg.js +0 -10
  10. package/dist/dashboard/client/assets/channel-BXL5vtDv.js +0 -1
  11. package/dist/dashboard/client/assets/chunk-4BX2VUAB-DPa8WBIp.js +0 -1
  12. package/dist/dashboard/client/assets/chunk-55IACEB6-BxRzcpzA.js +0 -1
  13. package/dist/dashboard/client/assets/chunk-B4BG7PRW-DajTgf2c.js +0 -165
  14. package/dist/dashboard/client/assets/chunk-DI55MBZ5-iF7jh16b.js +0 -220
  15. package/dist/dashboard/client/assets/chunk-FMBD7UC4-BNfvHrjT.js +0 -15
  16. package/dist/dashboard/client/assets/chunk-QN33PNHL-DDEcP3Rr.js +0 -1
  17. package/dist/dashboard/client/assets/chunk-QZHKN3VN-CNrv8PPa.js +0 -1
  18. package/dist/dashboard/client/assets/chunk-TZMSLE5B-Cf7ruLpv.js +0 -1
  19. package/dist/dashboard/client/assets/classDiagram-2ON5EDUG-l6aRknEX.js +0 -1
  20. package/dist/dashboard/client/assets/classDiagram-v2-WZHVMYZB-l6aRknEX.js +0 -1
  21. package/dist/dashboard/client/assets/clone-DlyIkpMA.js +0 -1
  22. package/dist/dashboard/client/assets/cose-bilkent-S5V4N54A-BLdeLAXN.js +0 -1
  23. package/dist/dashboard/client/assets/cytoscape.esm-DtBltrT8.js +0 -331
  24. package/dist/dashboard/client/assets/dagre-6UL2VRFP-BJ4sOJMG.js +0 -4
  25. package/dist/dashboard/client/assets/defaultLocale-DX6XiGOO.js +0 -1
  26. package/dist/dashboard/client/assets/diagram-PSM6KHXK-6bnUwEUL.js +0 -24
  27. package/dist/dashboard/client/assets/diagram-QEK2KX5R-BVM40PZZ.js +0 -43
  28. package/dist/dashboard/client/assets/diagram-S2PKOQOG-Bymzcnfw.js +0 -24
  29. package/dist/dashboard/client/assets/erDiagram-Q2GNP2WA-BVADk0og.js +0 -60
  30. package/dist/dashboard/client/assets/flowDiagram-NV44I4VS-_eGXTmsk.js +0 -162
  31. package/dist/dashboard/client/assets/ganttDiagram-JELNMOA3-CX3MM-Kg.js +0 -267
  32. package/dist/dashboard/client/assets/gitGraphDiagram-V2S2FVAM-CkKtnGnz.js +0 -65
  33. package/dist/dashboard/client/assets/graph-DHnUlkk_.js +0 -1
  34. package/dist/dashboard/client/assets/index-Czwdh6UA.css +0 -1
  35. package/dist/dashboard/client/assets/index-D9drpDt3.js +0 -581
  36. package/dist/dashboard/client/assets/infoDiagram-HS3SLOUP-D9BnKoPB.js +0 -2
  37. package/dist/dashboard/client/assets/init-Gi6I4Gst.js +0 -1
  38. package/dist/dashboard/client/assets/journeyDiagram-XKPGCS4Q-DS_q4bTn.js +0 -139
  39. package/dist/dashboard/client/assets/kanban-definition-3W4ZIXB7-8_1dZaX4.js +0 -89
  40. package/dist/dashboard/client/assets/katex-DGN8GczM.js +0 -261
  41. package/dist/dashboard/client/assets/layout-CsLHITt3.js +0 -1
  42. package/dist/dashboard/client/assets/linear-CCtPUyi6.js +0 -1
  43. package/dist/dashboard/client/assets/mermaid-renderer-YLFCVv-z.js +0 -256
  44. package/dist/dashboard/client/assets/mindmap-definition-VGOIOE7T-DR-LlyOU.js +0 -68
  45. package/dist/dashboard/client/assets/ordinal-Cboi1Yqb.js +0 -1
  46. package/dist/dashboard/client/assets/pieDiagram-ADFJNKIX-Bb5Zk2R3.js +0 -30
  47. package/dist/dashboard/client/assets/quadrantDiagram-AYHSOK5B-jsjp4NWV.js +0 -7
  48. package/dist/dashboard/client/assets/requirementDiagram-UZGBJVZJ-fAoABRs-.js +0 -64
  49. package/dist/dashboard/client/assets/sankeyDiagram-TZEHDZUN-BTJZKbMB.js +0 -10
  50. package/dist/dashboard/client/assets/sequenceDiagram-WL72ISMW-D1CT5eZr.js +0 -145
  51. package/dist/dashboard/client/assets/stateDiagram-FKZM4ZOC-BOuyRm06.js +0 -1
  52. package/dist/dashboard/client/assets/stateDiagram-v2-4FDKWEC3-DtmMH8sN.js +0 -1
  53. package/dist/dashboard/client/assets/timeline-definition-IT6M3QCI-IT_de2GW.js +0 -61
  54. package/dist/dashboard/client/assets/treemap-GDKQZRPO-ChPy-xEn.js +0 -162
  55. package/dist/dashboard/client/assets/xychartDiagram-PRI3JC2R-CNHEwC5B.js +0 -7
  56. package/dist/dashboard/client/favicon-dark.ico +0 -0
  57. package/dist/dashboard/client/favicon-light.ico +0 -0
  58. package/dist/dashboard/client/index.html +0 -15
  59. package/dist/dashboard/server.js +0 -39726
package/dist/index.js CHANGED
@@ -16686,10 +16686,6 @@ var init_counts = __esm({
16686
16686
  });
16687
16687
 
16688
16688
  // ../shared/platform/src/index.ts
16689
- import { pathToFileURL } from "node:url";
16690
- async function importModule(absolutePath) {
16691
- return import(pathToFileURL(absolutePath).href);
16692
- }
16693
16689
  function killErrorMeansDead(err) {
16694
16690
  return err instanceof Error && "code" in err && err.code === "ESRCH";
16695
16691
  }
@@ -30779,7 +30775,7 @@ ${hint}
30779
30775
  }
30780
30776
 
30781
30777
  // src/lib/version.ts
30782
- var CLI_VERSION = true ? "2.3.22" : createRequire(import.meta.url)("../../package.json").version;
30778
+ var CLI_VERSION = true ? "2.3.23" : createRequire(import.meta.url)("../../package.json").version;
30783
30779
 
30784
30780
  // src/lib/deps.ts
30785
30781
  init_src();
@@ -30788,7 +30784,7 @@ var CATEGORY_INFO = {
30788
30784
  core: { label: "Core", hint: "" },
30789
30785
  "ai-cli": {
30790
30786
  label: "AI CLI",
30791
- hint: "powers dashboard commands + chat"
30787
+ hint: "powers CLI/OpenCode review commands"
30792
30788
  },
30793
30789
  github: {
30794
30790
  label: "GitHub Integration",
@@ -30925,13 +30921,13 @@ function printCapabilities(result) {
30925
30921
  },
30926
30922
  {
30927
30923
  ok: true,
30928
- label: "Dashboard viewer",
30929
- detail: "ocr dashboard \u2014 browse sessions, reviews, maps"
30924
+ label: "CLI artifacts",
30925
+ detail: "browse .ocr/sessions and use review status/watch"
30930
30926
  },
30931
30927
  {
30932
30928
  ok: caps.dashboardAi,
30933
- label: "Dashboard commands",
30934
- detail: caps.dashboardAi ? "Command Center, Ask the Team chat" : "Install Claude Code or OpenCode to enable"
30929
+ label: "AI review commands",
30930
+ detail: caps.dashboardAi ? "/ocr-review and process-agent reviews" : "Install Claude Code or OpenCode to enable"
30935
30931
  },
30936
30932
  {
30937
30933
  ok: caps.githubPost,
@@ -31076,16 +31072,16 @@ var initCommand = new Command("init").description("Set up OCR for AI coding envi
31076
31072
  );
31077
31073
  console.log();
31078
31074
  console.log(
31079
- ` ${source_default.cyan("3.")} Run ${source_default.yellow("ocr dashboard")} to open the web dashboard.`
31075
+ ` ${source_default.cyan("3.")} Run ${source_default.yellow("ocr review run-agents --fresh")} from your project or use the installed /ocr-review command.`
31080
31076
  );
31081
31077
  if (depResult.capabilities.dashboardAi) {
31082
31078
  console.log(
31083
- source_default.dim(" Command Center and Ask the Team are ready.")
31079
+ source_default.dim(" AI review commands are ready.")
31084
31080
  );
31085
31081
  } else {
31086
31082
  console.log(
31087
31083
  source_default.dim(
31088
- " Read-only mode \u2014 install Claude Code or OpenCode for full features."
31084
+ " Install Claude Code or OpenCode for AI review execution."
31089
31085
  )
31090
31086
  );
31091
31087
  }
@@ -31821,9 +31817,9 @@ var NodeFsHandler = class {
31821
31817
  if (this.fsw.closed) {
31822
31818
  return;
31823
31819
  }
31824
- const dirname13 = sysPath.dirname(file);
31820
+ const dirname12 = sysPath.dirname(file);
31825
31821
  const basename9 = sysPath.basename(file);
31826
- const parent = this.fsw._getWatchedDir(dirname13);
31822
+ const parent = this.fsw._getWatchedDir(dirname12);
31827
31823
  let prevStats = stats;
31828
31824
  if (parent.has(basename9))
31829
31825
  return;
@@ -31850,7 +31846,7 @@ var NodeFsHandler = class {
31850
31846
  prevStats = newStats2;
31851
31847
  }
31852
31848
  } catch (error) {
31853
- this.fsw._remove(dirname13, basename9);
31849
+ this.fsw._remove(dirname12, basename9);
31854
31850
  }
31855
31851
  } else if (parent.has(basename9)) {
31856
31852
  const at = newStats.atimeMs;
@@ -34983,6 +34979,12 @@ var VALID_SEVERITIES2 = /* @__PURE__ */ new Set([
34983
34979
  "low",
34984
34980
  "info"
34985
34981
  ]);
34982
+ var VALID_AGGREGATION_SEVERITIES = /* @__PURE__ */ new Set([
34983
+ "critical",
34984
+ "high",
34985
+ "medium",
34986
+ "low"
34987
+ ]);
34986
34988
  var VALID_CATEGORIES2 = /* @__PURE__ */ new Set([
34987
34989
  "blocker",
34988
34990
  "should_fix",
@@ -35025,15 +35027,15 @@ function validateAggregationJson(value) {
35025
35027
  if (!f) return;
35026
35028
  expectString(f.id, `findings[${index}].id`, errors);
35027
35029
  expectString(f.title, `findings[${index}].title`, errors);
35028
- expectStringArray(f.source_findings, `findings[${index}].source_findings`, errors);
35030
+ expectStringArray(f.src, `findings[${index}].src`, errors);
35029
35031
  expectEnum(f.signal, VALID_SIGNALS, `findings[${index}].signal`, errors);
35030
- expectEnum(f.severity, VALID_SEVERITIES2, `findings[${index}].severity`, errors);
35031
- expectStringArray(f.file_refs, `findings[${index}].file_refs`, errors);
35032
+ expectEnum(f.severity, VALID_AGGREGATION_SEVERITIES, `findings[${index}].severity`, errors);
35033
+ expectStringArray(f.files, `findings[${index}].files`, errors);
35032
35034
  expectString(f.claim, `findings[${index}].claim`, errors);
35033
35035
  expectString(f.evidence, `findings[${index}].evidence`, errors);
35034
- expectString(f.developer_impact, `findings[${index}].developer_impact`, errors);
35035
- expectStringArray(f.validation_steps, `findings[${index}].validation_steps`, errors);
35036
- expectString(f.fix_direction, `findings[${index}].fix_direction`, errors);
35036
+ expectString(f.impact, `findings[${index}].impact`, errors);
35037
+ expectStringArray(f.validate, `findings[${index}].validate`, errors);
35038
+ expectString(f.fix, `findings[${index}].fix`, errors);
35037
35039
  });
35038
35040
  }
35039
35041
  const dropped = expectArray(obj.dropped, "dropped", errors);
@@ -35041,7 +35043,7 @@ function validateAggregationJson(value) {
35041
35043
  dropped.forEach((drop, index) => {
35042
35044
  const d = expectObject(drop, `dropped[${index}]`, errors);
35043
35045
  if (!d) return;
35044
- expectStringArray(d.source_findings, `dropped[${index}].source_findings`, errors);
35046
+ expectStringArray(d.src, `dropped[${index}].src`, errors);
35045
35047
  expectString(d.reason, `dropped[${index}].reason`, errors);
35046
35048
  });
35047
35049
  }
@@ -36322,7 +36324,7 @@ function readDashboardSpawnMarker(ocrDir) {
36322
36324
  if (live.length > 1) {
36323
36325
  console.error(
36324
36326
  source_default.gray(
36325
- `[state] ${live.length} concurrent dashboard spawns live; marker fallback is ambiguous \u2014 pass --dashboard-uid for linkage`
36327
+ `[state] ${live.length} concurrent external launches live; marker fallback is ambiguous \u2014 pass --dashboard-uid for linkage`
36326
36328
  )
36327
36329
  );
36328
36330
  return null;
@@ -36346,7 +36348,7 @@ async function linkDashboardInvocation(ocrDir, sessionId, explicitUid, label) {
36346
36348
  if (!dashboardUid) {
36347
36349
  console.error(
36348
36350
  source_default.gray(
36349
- `[state ${label}] no dashboard linkage available (flag, env var, and marker file all absent \u2014 CLI-only invocation)`
36351
+ `[state ${label}] no external-launch linkage available (flag, env var, and marker file all absent \u2014 CLI-only invocation)`
36350
36352
  )
36351
36353
  );
36352
36354
  return;
@@ -36356,13 +36358,13 @@ async function linkDashboardInvocation(ocrDir, sessionId, explicitUid, label) {
36356
36358
  linkDashboardInvocationToWorkflow(db, dashboardUid, sessionId);
36357
36359
  console.error(
36358
36360
  source_default.gray(
36359
- `[state ${label}] linked workflow_id=${sessionId} \u2192 dashboard uid=${dashboardUid}`
36361
+ `[state ${label}] linked workflow_id=${sessionId} \u2192 launcher uid=${dashboardUid}`
36360
36362
  )
36361
36363
  );
36362
36364
  } catch (linkErr) {
36363
36365
  console.error(
36364
36366
  source_default.yellow(
36365
- `Warning: failed to link dashboard command_execution to session: ${linkErr instanceof Error ? linkErr.message : String(linkErr)}`
36367
+ `Warning: failed to link launcher command_execution to session: ${linkErr instanceof Error ? linkErr.message : String(linkErr)}`
36366
36368
  )
36367
36369
  );
36368
36370
  }
@@ -36520,7 +36522,7 @@ var beginSubcommand = new Command("begin").description("Start or resume a workfl
36520
36522
  return v;
36521
36523
  }).option("--session-dir <dir>", "Session directory path (auto-resolved if omitted)").option(
36522
36524
  "--dashboard-uid <uid>",
36523
- "Dashboard command_executions uid to link this workflow to (takes precedence over OCR_DASHBOARD_EXECUTION_UID)"
36525
+ "External launcher command_executions uid to link this workflow to (takes precedence over OCR_DASHBOARD_EXECUTION_UID)"
36524
36526
  ).option("--json", "Output the result as JSON").action(
36525
36527
  async (options) => {
36526
36528
  const targetDir = process.cwd();
@@ -37428,12 +37430,10 @@ async function writeRoundArtifact(roundDir, relativePath, content) {
37428
37430
  }
37429
37431
 
37430
37432
  // src/lib/agent-orchestrator/context-prep.ts
37433
+ init_src();
37431
37434
  import { mkdir as mkdir2, readFile, writeFile as writeFile2 } from "node:fs/promises";
37432
37435
  import { existsSync as existsSync21 } from "node:fs";
37433
37436
  import { dirname as dirname10, join as join25 } from "node:path";
37434
- import { execFile } from "node:child_process";
37435
- import { promisify } from "node:util";
37436
- var execFileAsync = promisify(execFile);
37437
37437
  var GIT_SUMMARY_LIMIT = 2e4;
37438
37438
  var REVIEW_SNAPSHOT_EXCLUDES = [".ocr", ".opencode"];
37439
37439
  async function prepareReviewContext(input) {
@@ -37625,9 +37625,10 @@ async function resolveDefaultRemoteBase(cwd) {
37625
37625
  }
37626
37626
  async function runGit(cwd, args, limit = GIT_SUMMARY_LIMIT) {
37627
37627
  try {
37628
- const { stdout, stderr } = await execFileAsync("git", args, {
37628
+ const { stdout, stderr } = await execBinaryAsync("git", args, {
37629
37629
  cwd,
37630
- maxBuffer: limit * 2
37630
+ maxBuffer: limit * 2,
37631
+ encoding: "utf8"
37631
37632
  });
37632
37633
  return truncate(`${stdout}${stderr ? `
37633
37634
  ${stderr}` : ""}`.trim(), limit);
@@ -38037,14 +38038,41 @@ async function reviewerPrompt(context, reviewer, promptPath, reviewPath, sharedP
38037
38038
  "- Apply the reviewer persona file as your primary review lens.",
38038
38039
  "- Use the review brief as the source of truth for changed files and scope.",
38039
38040
  "- Inspect surrounding source code only when needed to validate a finding.",
38041
+ "- Rank by concrete risk: data loss, wrong persisted state, broken public contract, security, production performance, then testability.",
38040
38042
  "",
38041
38043
  "Output contract:",
38042
38044
  `- Return review markdown through stdout for ${reviewPath}.`,
38045
+ "- Return only one fenced ```ocr-json block and no prose outside it.",
38046
+ "- Include maximum 10 findings, sorted by severity and production impact.",
38047
+ "- No introductions, no progress narration, no endpoint tables, no code snippets, no broad summaries.",
38048
+ "- Include critical, high, and medium findings. Include low only when it has concrete runtime/user impact. Exclude info/style/theoretical-only items.",
38049
+ "- Do not include fix instructions; aggregation and synthesis will produce fix direction after deduplication and validation.",
38050
+ "- Exclude any item that does not have concrete `files` and `evidence`.",
38043
38051
  "- Do not write files directly.",
38044
38052
  "- Do not claim skipped agents ran.",
38045
38053
  "",
38046
38054
  "Required ocr-json schema:",
38047
- "- Reviewer findings may be prose today; pipeline stages own strict ocr-json.",
38055
+ "- Output exactly this compact JSON shape inside the fenced block:",
38056
+ "",
38057
+ "```json",
38058
+ "{",
38059
+ ' "findings": [',
38060
+ " {",
38061
+ ' "sev": "high",',
38062
+ ' "title": "Short finding title",',
38063
+ ' "files": ["src/main/java/example/File.java:42"],',
38064
+ ' "claim": "What may be wrong.",',
38065
+ ' "evidence": "Concrete code evidence.",',
38066
+ ' "impact": "Runtime/user/system impact if confirmed.",',
38067
+ ' "confidence": "high"',
38068
+ " }",
38069
+ " ]",
38070
+ "}",
38071
+ "```",
38072
+ "",
38073
+ '- `sev` must be one of: "critical", "high", "medium", "low".',
38074
+ '- `confidence` must be one of: "high", "medium", "low".',
38075
+ "- Keep every string under roughly 240 characters.",
38048
38076
  "",
38049
38077
  "Forbidden behavior:",
38050
38078
  `- Do not modify ${promptPath} or ${reviewPath}.`,
@@ -38157,7 +38185,8 @@ function pipelinePrompt(context, stage, agent, promptPath, artifactPath) {
38157
38185
  ] : stage === "aggregation" ? [
38158
38186
  "- Return only one fenced ```ocr-json block and no prose outside it.",
38159
38187
  "- Keep the output compact: at most 8 findings and at most 12 dropped entries.",
38160
- "- Do not include code snippets, long quotes, markdown tables, or reviewer narrative."
38188
+ "- Do not include code snippets, long quotes, markdown tables, or reviewer narrative.",
38189
+ "- Read the original reviewer files, but aggregate only their structured findings and concrete evidence."
38161
38190
  ] : ["- Include exactly one fenced ```ocr-json block."],
38162
38191
  "- Do not write files directly.",
38163
38192
  "",
@@ -38183,7 +38212,11 @@ function schemaHint(stage) {
38183
38212
  "- Output exactly this compact JSON shape inside one fenced ```ocr-json block.",
38184
38213
  "- Do not rename fields. Do not use markdown tables inside the JSON block.",
38185
38214
  "- Keep only high-signal findings that a developer or validation agent can act on.",
38186
- "- Merge duplicates across reviewers into one finding with multiple `source_findings`.",
38215
+ "- Merge duplicates across reviewers into one finding with multiple `src` references.",
38216
+ "- Severity gate:",
38217
+ " - Keep critical, high, and medium findings.",
38218
+ " - Keep low only when duplicated by 2+ reviewers or when it has concrete production/runtime impact.",
38219
+ " - Drop info, style, theoretical-only, and future-extensibility-only items.",
38187
38220
  "",
38188
38221
  "```json",
38189
38222
  "{",
@@ -38191,20 +38224,20 @@ function schemaHint(stage) {
38191
38224
  " {",
38192
38225
  ' "id": "agg-1",',
38193
38226
  ' "title": "Short finding title",',
38194
- ' "source_findings": ["architect-1:finding-or-heading"],',
38227
+ ' "src": ["architect-1:finding-or-heading"],',
38195
38228
  ' "signal": "keep",',
38196
38229
  ' "severity": "high",',
38197
- ' "file_refs": ["src/main/java/example/File.java:42"],',
38230
+ ' "files": ["src/main/java/example/File.java:42"],',
38198
38231
  ' "claim": "What may be wrong, stated as a verifiable hypothesis.",',
38199
38232
  ' "evidence": "Why reviewers believe this may be wrong.",',
38200
- ' "developer_impact": "What user/system behavior would be affected if confirmed.",',
38201
- ' "validation_steps": ["Check the write path for a uniqueness boundary."],',
38202
- ' "fix_direction": "Concrete direction for the fix."',
38233
+ ' "impact": "What user/system behavior would be affected if confirmed.",',
38234
+ ' "validate": ["Check the write path for a uniqueness boundary."],',
38235
+ ' "fix": "Concrete direction for the fix."',
38203
38236
  " }",
38204
38237
  " ],",
38205
38238
  ' "dropped": [',
38206
38239
  " {",
38207
- ' "source_findings": ["performance-1:finding-or-heading"],',
38240
+ ' "src": ["performance-1:finding-or-heading"],',
38208
38241
  ' "reason": "Why this reviewer finding is noise or duplicate."',
38209
38242
  " }",
38210
38243
  " ]",
@@ -38212,8 +38245,8 @@ function schemaHint(stage) {
38212
38245
  "```",
38213
38246
  "",
38214
38247
  '- `signal` must be one of: "keep", "merge", "needs_validation", "likely_noise", "false_positive_candidate".',
38215
- '- `severity` must be one of: "critical", "high", "medium", "low", "info".',
38216
- "- `source_findings`, `file_refs`, and `validation_steps` must always be arrays of non-empty strings.",
38248
+ '- `severity` must be one of: "critical", "high", "medium", "low".',
38249
+ "- `src`, `files`, and `validate` must always be arrays of non-empty strings.",
38217
38250
  "- Limit each string field to roughly 320 characters. Limit arrays to the most relevant entries.",
38218
38251
  "- Prefer dropping low/info/style-only noise over producing an overlong aggregation."
38219
38252
  ].join("\n");
@@ -38223,7 +38256,7 @@ function schemaHint(stage) {
38223
38256
  "ValidationJson:",
38224
38257
  "- Output exactly this JSON shape inside one fenced ```ocr-json block.",
38225
38258
  "- Do not rename fields. Do not use markdown tables inside the JSON block.",
38226
- "- Use aggregation `claim`, `evidence`, `file_refs`, and `validation_steps` as the checklist for each finding.",
38259
+ "- Use aggregation `claim`, `evidence`, `files`, and `validate` as the checklist for each finding.",
38227
38260
  "- Verify claims against the actual code before confirming. Do not trust reviewer text without code evidence.",
38228
38261
  "- Put every aggregation finding into exactly one of `confirmed`, `downgraded`, or `rejected`.",
38229
38262
  "",
@@ -38363,7 +38396,7 @@ async function runReviewerPhase(input) {
38363
38396
  prompt_path: request.promptPath,
38364
38397
  meta_log: startLogPaths.meta
38365
38398
  });
38366
- const result = await input.runner.run(request, controller.signal);
38399
+ const result = normalizeProcessResult(await input.runner.run(request, controller.signal));
38367
38400
  const logPaths = await writeProcessLogs(input.context.roundDir, request, result);
38368
38401
  running.delete(request.id);
38369
38402
  completed.add(request.id);
@@ -38380,7 +38413,7 @@ async function runReviewerPhase(input) {
38380
38413
  if (vendorId) await journal.bindVendorId(agentSessionId, vendorId);
38381
38414
  await journal.endInstance(agentSessionId, {
38382
38415
  exitCode: result.exitCode,
38383
- note: result.stderr.trim() || void 0
38416
+ note: result.stderr.trim() || failureNoteForResult(result)
38384
38417
  });
38385
38418
  return result;
38386
38419
  });
@@ -38600,7 +38633,7 @@ async function runPipelineStages(input) {
38600
38633
  progressTimer.unref?.();
38601
38634
  let result;
38602
38635
  try {
38603
- result = await input.runner.run(request, new AbortController().signal);
38636
+ result = normalizeProcessResult(await input.runner.run(request, new AbortController().signal));
38604
38637
  } finally {
38605
38638
  clearInterval(progressTimer);
38606
38639
  }
@@ -38701,7 +38734,7 @@ async function runUkrainianTranslation(input) {
38701
38734
  progressTimer.unref?.();
38702
38735
  let result;
38703
38736
  try {
38704
- result = await input.runner.run(request, new AbortController().signal);
38737
+ result = normalizeProcessResult(await input.runner.run(request, new AbortController().signal));
38705
38738
  } finally {
38706
38739
  clearInterval(progressTimer);
38707
38740
  }
@@ -38921,6 +38954,24 @@ function readStartedAt(path2) {
38921
38954
  function processOutput(result) {
38922
38955
  return result.outputText ?? result.stdout;
38923
38956
  }
38957
+ function normalizeProcessResult(result) {
38958
+ if (!hasOpenCodeLengthFinish(result.ndjsonEvents)) return result;
38959
+ return {
38960
+ ...result,
38961
+ exitCode: result.exitCode === 0 ? 1 : result.exitCode
38962
+ };
38963
+ }
38964
+ function failureNoteForResult(result) {
38965
+ return hasOpenCodeLengthFinish(result.ndjsonEvents) ? "OpenCode stopped because the model hit the output limit." : void 0;
38966
+ }
38967
+ function hasOpenCodeLengthFinish(events) {
38968
+ return events.some((event) => {
38969
+ if (!isRecord2(event)) return false;
38970
+ const part = event.part;
38971
+ if (!isRecord2(part)) return false;
38972
+ return part.type === "step-finish" && part.reason === "length";
38973
+ });
38974
+ }
38924
38975
  function extractUniqueSessionIds(events) {
38925
38976
  const ids = /* @__PURE__ */ new Set();
38926
38977
  for (const event of events) {
@@ -38959,6 +39010,14 @@ function buildFailureDiagnostic(result, request) {
38959
39010
  const stdoutError = extractOpenCodeErrorMessage(result.ndjsonEvents);
38960
39011
  const combined = [stderr, stdoutError].filter(Boolean).join("\n");
38961
39012
  const model = request?.model ?? "";
39013
+ if (hasOpenCodeLengthFinish(result.ndjsonEvents)) {
39014
+ return {
39015
+ summary: "OpenCode stopped because the model hit the output limit (`step_finish.reason=length`). OCR treats this as failed because the review artifact may be truncated or missing.",
39016
+ hint: "Reduce agent output, keep only structured findings, or use a model/configuration that can complete the saved prompt without truncation.",
39017
+ stderr_excerpt: excerpt(stderr),
39018
+ stdout_excerpt: excerpt(result.stdout)
39019
+ };
39020
+ }
38962
39021
  if (/session not found/i.test(combined)) {
38963
39022
  return {
38964
39023
  summary: 'OpenCode reported "Session not found" while running this process agent. This is an OpenCode subprocess/session error, not an OCR decision to simulate or skip reviewers.',
@@ -39056,7 +39115,7 @@ function newSessionId() {
39056
39115
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
39057
39116
  return `${date}-opencode-process-review-${Date.now()}`;
39058
39117
  }
39059
- 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").option("--background", "Detach and return immediately; not for normal OpenCode UI progress").addOption(new Option("--worker", "Internal detached worker mode").hideHelp()).action(
39118
+ var runAgentsSubcommand = new Command("run-agents").description("Run OCR review through OpenCode process agents").argument("[target]", "Target path for fresh review 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").option("--background", "Detach and return immediately; not for normal OpenCode UI progress").addOption(new Option("--worker", "Internal detached worker mode").hideHelp()).action(
39060
39119
  async (target, options) => {
39061
39120
  const targetDir = process.cwd();
39062
39121
  requireOcrSetup(targetDir);
@@ -39452,7 +39511,7 @@ var reviewCommand = new Command("review").description("Run or resume an OCR revi
39452
39511
  if (!options.resume) {
39453
39512
  console.error(
39454
39513
  source_default.yellow(
39455
- "Running a fresh review from the CLI is not yet supported \u2014 start one from your AI CLI's `/ocr-review` slash command or from the dashboard."
39514
+ "Running a fresh review from this wrapper is not yet supported \u2014 use your AI CLI's `/ocr-review` slash command or run `ocr review run-agents --fresh`."
39456
39515
  )
39457
39516
  );
39458
39517
  console.error(
@@ -39729,76 +39788,9 @@ var updateCommand = new Command("update").description("Update OCR assets after p
39729
39788
  console.log();
39730
39789
  });
39731
39790
 
39732
- // src/commands/dashboard.ts
39733
- import { existsSync as existsSync25 } from "node:fs";
39734
- import { join as join30, dirname as dirname12 } from "node:path";
39735
- import { fileURLToPath } from "node:url";
39736
- init_src();
39737
- init_db();
39738
- var __filename = fileURLToPath(import.meta.url);
39739
- var __dirname = dirname12(__filename);
39740
- function resolveServerPath() {
39741
- return join30(__dirname, "dashboard", "server.js");
39742
- }
39743
- var dashboardCommand = new Command("dashboard").description("Start the OCR dashboard web interface").option("-p, --port <port>", "Port to run the server on", "4173").option("--no-open", "Don't open the browser automatically").action(
39744
- async (options) => {
39745
- const targetDir = process.cwd();
39746
- requireOcrSetup(targetDir);
39747
- const port = parseInt(options.port, 10);
39748
- if (isNaN(port) || port < 1 || port > 65535) {
39749
- console.error(source_default.red(`Error: Invalid port "${options.port}". Must be 1-65535.`));
39750
- process.exit(1);
39751
- }
39752
- const ocrDir = join30(targetDir, ".ocr");
39753
- try {
39754
- await ensureDatabase(ocrDir);
39755
- closeAllDatabases();
39756
- } catch (err) {
39757
- console.error(source_default.red("Error: Failed to initialize database."));
39758
- console.error(
39759
- source_default.dim(
39760
- ` ${err instanceof Error ? err.message : String(err)}`
39761
- )
39762
- );
39763
- process.exit(1);
39764
- }
39765
- const serverPath = resolveServerPath();
39766
- if (!existsSync25(serverPath)) {
39767
- console.error(source_default.red("Error: Dashboard server bundle not found."));
39768
- console.error(
39769
- source_default.dim(` Expected at: ${serverPath}`)
39770
- );
39771
- console.error(
39772
- source_default.dim(" This may indicate a broken installation. Try reinstalling:")
39773
- );
39774
- console.error(source_default.white(" npm install -g @open-code-review/cli"));
39775
- process.exit(1);
39776
- }
39777
- process.env.NODE_ENV = "production";
39778
- console.log();
39779
- console.log(source_default.bold(" OCR Dashboard"));
39780
- console.log();
39781
- try {
39782
- const { startServer } = await importModule(serverPath);
39783
- await startServer({ port, open: options.open });
39784
- } catch (err) {
39785
- console.error(source_default.red("Error: Failed to start dashboard server."));
39786
- console.error(
39787
- source_default.dim(
39788
- ` ${err instanceof Error ? err.message : String(err)}`
39789
- )
39790
- );
39791
- process.exit(1);
39792
- }
39793
- console.log();
39794
- console.log(source_default.dim(" Press Ctrl+C to stop"));
39795
- console.log();
39796
- }
39797
- );
39798
-
39799
39791
  // src/commands/doctor.ts
39800
- import { existsSync as existsSync26 } from "node:fs";
39801
- import { join as join31 } from "node:path";
39792
+ import { existsSync as existsSync25 } from "node:fs";
39793
+ import { join as join30 } from "node:path";
39802
39794
  init_db();
39803
39795
  function printStorageEngine(probeWriteEnabled) {
39804
39796
  console.log();
@@ -39855,10 +39847,10 @@ var doctorCommand = new Command("doctor").description("Check OCR installation an
39855
39847
  console.log(source_default.bold(" OCR Installation"));
39856
39848
  console.log();
39857
39849
  const ocrStatus = checkOcrSetup(targetDir);
39858
- const configPath = join31(targetDir, ".ocr", "config.yaml");
39859
- const dbPath = join31(targetDir, ".ocr", "data", "ocr.db");
39860
- const hasConfig = existsSync26(configPath);
39861
- const hasDb = existsSync26(dbPath);
39850
+ const configPath = join30(targetDir, ".ocr", "config.yaml");
39851
+ const dbPath = join30(targetDir, ".ocr", "data", "ocr.db");
39852
+ const hasConfig = existsSync25(configPath);
39853
+ const hasDb = existsSync25(dbPath);
39862
39854
  const ocrChecks = [
39863
39855
  { label: ".ocr/skills/", ok: ocrStatus.hasSkills },
39864
39856
  { label: ".ocr/sessions/", ok: ocrStatus.hasSessions },
@@ -39927,7 +39919,7 @@ var doctorCommand = new Command("doctor").description("Check OCR installation an
39927
39919
  console.log(source_default.green(" \u2713 Ready for code review"));
39928
39920
  console.log(
39929
39921
  source_default.dim(
39930
- " Install Claude Code or OpenCode for dashboard commands"
39922
+ " Install Claude Code or OpenCode for AI review commands"
39931
39923
  )
39932
39924
  );
39933
39925
  }
@@ -39935,8 +39927,8 @@ var doctorCommand = new Command("doctor").description("Check OCR installation an
39935
39927
  });
39936
39928
 
39937
39929
  // src/commands/db.ts
39938
- import { existsSync as existsSync27, readFileSync as readFileSync18 } from "node:fs";
39939
- import { join as join32 } from "node:path";
39930
+ import { existsSync as existsSync26, readFileSync as readFileSync18 } from "node:fs";
39931
+ import { join as join31 } from "node:path";
39940
39932
  init_src();
39941
39933
  init_db();
39942
39934
  function fail4(message) {
@@ -39946,10 +39938,10 @@ function fail4(message) {
39946
39938
  function resolveOcrDir() {
39947
39939
  const targetDir = process.cwd();
39948
39940
  requireOcrSetup(targetDir);
39949
- return join32(targetDir, ".ocr");
39941
+ return join31(targetDir, ".ocr");
39950
39942
  }
39951
39943
  function dbPathFor(ocrDir) {
39952
- return join32(ocrDir, "data", "ocr.db");
39944
+ return join31(ocrDir, "data", "ocr.db");
39953
39945
  }
39954
39946
  function formatBytes(n) {
39955
39947
  if (n < 1024) return `${n} B`;
@@ -39962,9 +39954,9 @@ function formatBytes(n) {
39962
39954
  }
39963
39955
  return `${v.toFixed(v >= 100 ? 0 : 1)} ${units[i]}`;
39964
39956
  }
39965
- function liveDashboardPid(ocrDir) {
39966
- const pidFile = join32(ocrDir, "data", "dashboard.pid");
39967
- if (!existsSync27(pidFile)) return null;
39957
+ function liveOcrOwnerPid(ocrDir) {
39958
+ const pidFile = join31(ocrDir, "data", "dashboard.pid");
39959
+ if (!existsSync26(pidFile)) return null;
39968
39960
  try {
39969
39961
  const pid = parseInt(readFileSync18(pidFile, "utf-8").trim(), 10);
39970
39962
  if (!Number.isNaN(pid) && isProcessAlive(pid)) return pid;
@@ -39973,10 +39965,10 @@ function liveDashboardPid(ocrDir) {
39973
39965
  return null;
39974
39966
  }
39975
39967
  function guardExclusive(ocrDir, force, op) {
39976
- const pid = liveDashboardPid(ocrDir);
39968
+ const pid = liveOcrOwnerPid(ocrDir);
39977
39969
  if (pid !== null && !force) {
39978
39970
  fail4(
39979
- `a dashboard appears to be running (PID ${pid}); ${op} needs exclusive access to the database.
39971
+ `another OCR process appears to be running (PID ${pid}); ${op} needs exclusive access to the database.
39980
39972
  Stop it first, or pass --force to proceed anyway.`
39981
39973
  );
39982
39974
  }
@@ -40044,7 +40036,7 @@ function printHealth(report) {
40044
40036
  function needsFix(report) {
40045
40037
  return !report.integrityOk || report.fkViolations.length > 0 || report.markdownDuplicateRows > 0 || report.orphanTempFiles.some((f) => f.reapable) || report.reclaimableBytes > 0;
40046
40038
  }
40047
- var doctorSubcommand = new Command("doctor").description("Report database health; --fix repairs orphans/dupes and VACUUMs").option("--fix", "apply repairs: FK-orphan sweep, dedup, temp reap, VACUUM").option("--no-snapshot", "skip the pre-fix snapshot (with --fix)").option("--force", "proceed even if a live dashboard owns the database").option("--json", "emit the health report as JSON (implies no --fix)").action(
40039
+ var doctorSubcommand = new Command("doctor").description("Report database health; --fix repairs orphans/dupes and VACUUMs").option("--fix", "apply repairs: FK-orphan sweep, dedup, temp reap, VACUUM").option("--no-snapshot", "skip the pre-fix snapshot (with --fix)").option("--force", "proceed even if another live OCR process owns the database").option("--json", "emit the health report as JSON (implies no --fix)").action(
40048
40040
  async (options) => {
40049
40041
  const ocrDir = resolveOcrDir();
40050
40042
  const dbPath = dbPathFor(ocrDir);
@@ -40123,7 +40115,7 @@ var doctorSubcommand = new Command("doctor").description("Report database health
40123
40115
  console.log();
40124
40116
  }
40125
40117
  );
40126
- var vacuumSubcommand = new Command("vacuum").description("Checkpoint the WAL and VACUUM the database (snapshot-first)").option("--no-snapshot", "skip the pre-vacuum snapshot").option("--force", "proceed even if a live dashboard owns the database").action(async (options) => {
40118
+ var vacuumSubcommand = new Command("vacuum").description("Checkpoint the WAL and VACUUM the database (snapshot-first)").option("--no-snapshot", "skip the pre-vacuum snapshot").option("--force", "proceed even if another live OCR process owns the database").action(async (options) => {
40127
40119
  const ocrDir = resolveOcrDir();
40128
40120
  const dbPath = dbPathFor(ocrDir);
40129
40121
  guardExclusive(ocrDir, options.force ?? false, "vacuum");
@@ -40148,7 +40140,7 @@ var pruneSubcommand = new Command("prune").description(
40148
40140
  "--older-than <days>",
40149
40141
  "only prune closed sessions quiet for more than D days",
40150
40142
  (v) => parseInt(v, 10)
40151
- ).option("--dry-run", "show what would be pruned without deleting").option("--force", "proceed even if a live dashboard owns the database").action(
40143
+ ).option("--dry-run", "show what would be pruned without deleting").option("--force", "proceed even if another live OCR process owns the database").action(
40152
40144
  async (options) => {
40153
40145
  const ocrDir = resolveOcrDir();
40154
40146
  const dbPath = dbPathFor(ocrDir);
@@ -40220,7 +40212,7 @@ var pruneBackupsSubcommand = new Command("prune-backups").description("Delete ol
40220
40212
  1
40221
40213
  ).option("--force", "permit --keep 0 (removing the last backup / safety net)").option("--dry-run", "show what would be deleted without deleting").action(async (options) => {
40222
40214
  const ocrDir = resolveOcrDir();
40223
- const dataDir = join32(ocrDir, "data");
40215
+ const dataDir = join31(ocrDir, "data");
40224
40216
  const invalid = validatePruneBackupsOptions(options);
40225
40217
  if (invalid !== null) {
40226
40218
  fail4(invalid);
@@ -40257,7 +40249,7 @@ var dbCommand = new Command("db").description("Inspect and maintain the OCR SQLi
40257
40249
 
40258
40250
  // src/commands/reviewers.ts
40259
40251
  import { writeFileSync as writeFileSync10, renameSync as renameSync2 } from "node:fs";
40260
- import { join as join33 } from "node:path";
40252
+ import { join as join32 } from "node:path";
40261
40253
  init_src();
40262
40254
  async function readStdin3() {
40263
40255
  const chunks = [];
@@ -40353,17 +40345,17 @@ function validateReviewersMeta(data) {
40353
40345
  var syncSubcommand2 = new Command("sync").description("Sync reviewers-meta.json from reviewer markdown files or structured JSON").option("--stdin", "Read reviewers JSON from stdin (for AI-invoked sync)").action(async (options) => {
40354
40346
  const targetDir = process.cwd();
40355
40347
  requireOcrSetup(targetDir);
40356
- const ocrDir = join33(targetDir, ".ocr");
40348
+ const ocrDir = join32(targetDir, ".ocr");
40357
40349
  if (!options.stdin) {
40358
40350
  try {
40359
- const reviewersDir = join33(ocrDir, "skills", "references", "reviewers");
40360
- const configPath = join33(ocrDir, "config.yaml");
40351
+ const reviewersDir = join32(ocrDir, "skills", "references", "reviewers");
40352
+ const configPath = join32(ocrDir, "config.yaml");
40361
40353
  const meta = generateReviewersMeta(reviewersDir, configPath);
40362
40354
  if (!meta || meta.reviewers.length === 0) {
40363
40355
  console.error(source_default.yellow("No reviewer files found in .ocr/skills/references/reviewers/"));
40364
40356
  process.exit(1);
40365
40357
  }
40366
- const metaPath = join33(ocrDir, "reviewers-meta.json");
40358
+ const metaPath = join32(ocrDir, "reviewers-meta.json");
40367
40359
  const tmpPath = metaPath + ".tmp";
40368
40360
  writeFileSync10(tmpPath, JSON.stringify(meta, null, 2) + "\n");
40369
40361
  renameSync2(tmpPath, metaPath);
@@ -40393,7 +40385,7 @@ var syncSubcommand2 = new Command("sync").description("Sync reviewers-meta.json
40393
40385
  throw new Error("Invalid JSON on stdin");
40394
40386
  }
40395
40387
  const meta = validateReviewersMeta(parsed);
40396
- const metaPath = join33(ocrDir, "reviewers-meta.json");
40388
+ const metaPath = join32(ocrDir, "reviewers-meta.json");
40397
40389
  const tmpPath = metaPath + ".tmp";
40398
40390
  writeFileSync10(tmpPath, JSON.stringify(meta, null, 2) + "\n");
40399
40391
  renameSync2(tmpPath, metaPath);
@@ -40469,12 +40461,12 @@ var hostCommand = new Command("host").description("Inspect host (AI CLI) capabil
40469
40461
 
40470
40462
  // src/lib/update-check.ts
40471
40463
  import { homedir } from "node:os";
40472
- import { join as join34 } from "node:path";
40464
+ import { join as join33 } from "node:path";
40473
40465
  import { readFileSync as readFileSync19, writeFileSync as writeFileSync11, mkdirSync as mkdirSync9 } from "node:fs";
40474
40466
  var PACKAGE_NAME = "@open-code-review/cli";
40475
40467
  var REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
40476
- var CACHE_DIR2 = join34(homedir(), ".ocr");
40477
- var CACHE_FILE = join34(CACHE_DIR2, "update-check.json");
40468
+ var CACHE_DIR2 = join33(homedir(), ".ocr");
40469
+ var CACHE_FILE = join33(CACHE_DIR2, "update-check.json");
40478
40470
  var CHECK_INTERVAL_MS = 4 * 60 * 60 * 1e3;
40479
40471
  var FETCH_TIMEOUT_MS = 3e3;
40480
40472
  function readCache(cacheFile) {
@@ -40486,7 +40478,7 @@ function readCache(cacheFile) {
40486
40478
  }
40487
40479
  function writeCache(cacheFile, cache2) {
40488
40480
  try {
40489
- mkdirSync9(join34(cacheFile, ".."), { recursive: true });
40481
+ mkdirSync9(join33(cacheFile, ".."), { recursive: true });
40490
40482
  writeFileSync11(cacheFile, JSON.stringify(cache2));
40491
40483
  } catch {
40492
40484
  }
@@ -40507,7 +40499,7 @@ async function checkForUpdate(currentVersion, options) {
40507
40499
  if (process.env.CI || process.env.OCR_NO_UPDATE_CHECK) {
40508
40500
  return null;
40509
40501
  }
40510
- const cacheFile = join34(options?.cacheDir ?? CACHE_DIR2, "update-check.json");
40502
+ const cacheFile = join33(options?.cacheDir ?? CACHE_DIR2, "update-check.json");
40511
40503
  try {
40512
40504
  const cache2 = readCache(cacheFile);
40513
40505
  if (cache2 && Date.now() - cache2.lastCheck < CHECK_INTERVAL_MS) {
@@ -40551,7 +40543,7 @@ ${line2}
40551
40543
  }
40552
40544
 
40553
40545
  // src/index.ts
40554
- var HUMAN_COMMANDS = /* @__PURE__ */ new Set(["init", "update", "doctor", "dashboard", "progress"]);
40546
+ var HUMAN_COMMANDS = /* @__PURE__ */ new Set(["init", "update", "doctor", "progress"]);
40555
40547
  var subcommand = process.argv[2];
40556
40548
  var updateCheck = subcommand && HUMAN_COMMANDS.has(subcommand) ? checkForUpdate(CLI_VERSION) : null;
40557
40549
  var program2 = new Command();
@@ -40564,7 +40556,6 @@ program2.addCommand(modelsCommand);
40564
40556
  program2.addCommand(teamCommand);
40565
40557
  program2.addCommand(reviewCommand);
40566
40558
  program2.addCommand(updateCommand);
40567
- program2.addCommand(dashboardCommand);
40568
40559
  program2.addCommand(doctorCommand);
40569
40560
  program2.addCommand(dbCommand);
40570
40561
  program2.addCommand(reviewersCommand);