@open-code-review/cli 1.5.1 → 1.6.0

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 +57 -127
  2. package/dist/dashboard/client/assets/{_basePickBy-BJKCdvle.js → _basePickBy-BGuMbEDR.js} +1 -1
  3. package/dist/dashboard/client/assets/{_baseUniq-L_sxIO0r.js → _baseUniq-Bx8loabg.js} +1 -1
  4. package/dist/dashboard/client/assets/{arc-tqAEcLt5.js → arc-DUgpt7nY.js} +1 -1
  5. package/dist/dashboard/client/assets/{architectureDiagram-VXUJARFQ-CrKQo6Ye.js → architectureDiagram-VXUJARFQ-D25nt6Xz.js} +1 -1
  6. package/dist/dashboard/client/assets/{blockDiagram-VD42YOAC-DXOc89nw.js → blockDiagram-VD42YOAC-D8PUF3h4.js} +1 -1
  7. package/dist/dashboard/client/assets/{c4Diagram-YG6GDRKO-Ba-jYbw0.js → c4Diagram-YG6GDRKO-lorsCz-I.js} +1 -1
  8. package/dist/dashboard/client/assets/channel-yW2sWou_.js +1 -0
  9. package/dist/dashboard/client/assets/{chunk-4BX2VUAB-D1G3HCqL.js → chunk-4BX2VUAB-8lVyfRJM.js} +1 -1
  10. package/dist/dashboard/client/assets/{chunk-55IACEB6-FI7g4AjR.js → chunk-55IACEB6-C4SjgsZO.js} +1 -1
  11. package/dist/dashboard/client/assets/{chunk-B4BG7PRW-DhEGFGWs.js → chunk-B4BG7PRW-BXzTPbH1.js} +1 -1
  12. package/dist/dashboard/client/assets/{chunk-DI55MBZ5-Da3-6ZE4.js → chunk-DI55MBZ5-Bp7QllDt.js} +1 -1
  13. package/dist/dashboard/client/assets/{chunk-FMBD7UC4-D0QLOjiy.js → chunk-FMBD7UC4-B4g9S67N.js} +1 -1
  14. package/dist/dashboard/client/assets/{chunk-QN33PNHL-WkfgpbLo.js → chunk-QN33PNHL-Dyk7Hc0J.js} +1 -1
  15. package/dist/dashboard/client/assets/{chunk-QZHKN3VN-Bqn0IO1w.js → chunk-QZHKN3VN-DTvkGdnm.js} +1 -1
  16. package/dist/dashboard/client/assets/{chunk-TZMSLE5B-CC_K_BeL.js → chunk-TZMSLE5B-BAeZLvrI.js} +1 -1
  17. package/dist/dashboard/client/assets/classDiagram-2ON5EDUG-1pMX5UXO.js +1 -0
  18. package/dist/dashboard/client/assets/classDiagram-v2-WZHVMYZB-1pMX5UXO.js +1 -0
  19. package/dist/dashboard/client/assets/clone-DQwdw3YR.js +1 -0
  20. package/dist/dashboard/client/assets/{cose-bilkent-S5V4N54A-D8urqxIF.js → cose-bilkent-S5V4N54A--6-kzrdu.js} +1 -1
  21. package/dist/dashboard/client/assets/{dagre-6UL2VRFP-w2xS0ztU.js → dagre-6UL2VRFP-D10_QE2P.js} +1 -1
  22. package/dist/dashboard/client/assets/{diagram-PSM6KHXK-DlOtv6zO.js → diagram-PSM6KHXK-kS1x75Bl.js} +1 -1
  23. package/dist/dashboard/client/assets/{diagram-QEK2KX5R-EpxsVLZY.js → diagram-QEK2KX5R-D_LLCPas.js} +1 -1
  24. package/dist/dashboard/client/assets/{diagram-S2PKOQOG-kmITzl42.js → diagram-S2PKOQOG-Duy1t5UO.js} +1 -1
  25. package/dist/dashboard/client/assets/{erDiagram-Q2GNP2WA-Bvyepu_Z.js → erDiagram-Q2GNP2WA-DyQXwzLf.js} +1 -1
  26. package/dist/dashboard/client/assets/{flowDiagram-NV44I4VS-BokLAZN0.js → flowDiagram-NV44I4VS-D9U11XVw.js} +1 -1
  27. package/dist/dashboard/client/assets/{ganttDiagram-JELNMOA3-i5ZSGuTN.js → ganttDiagram-JELNMOA3-STy-TC-3.js} +1 -1
  28. package/dist/dashboard/client/assets/{gitGraphDiagram-V2S2FVAM-CIayQ8P9.js → gitGraphDiagram-V2S2FVAM-B04PgURg.js} +1 -1
  29. package/dist/dashboard/client/assets/{graph-C3ouLF2F.js → graph-AiGwnT5H.js} +1 -1
  30. package/dist/dashboard/client/assets/{index-icxlpW-l.js → index-BzQ3i_QR.js} +109 -107
  31. package/dist/dashboard/client/assets/index-CGGYXSm-.css +1 -0
  32. package/dist/dashboard/client/assets/{infoDiagram-HS3SLOUP-wxe8NO00.js → infoDiagram-HS3SLOUP-D4arwl6T.js} +1 -1
  33. package/dist/dashboard/client/assets/{journeyDiagram-XKPGCS4Q-BeHCbOFN.js → journeyDiagram-XKPGCS4Q-CsKqlKkf.js} +1 -1
  34. package/dist/dashboard/client/assets/{kanban-definition-3W4ZIXB7-DxUlb4wo.js → kanban-definition-3W4ZIXB7-CUFnzQE3.js} +1 -1
  35. package/dist/dashboard/client/assets/{layout-CYsQ5kjv.js → layout-BvvYJVPv.js} +1 -1
  36. package/dist/dashboard/client/assets/{linear-ByuMiLUn.js → linear-BiBJkzyE.js} +1 -1
  37. package/dist/dashboard/client/assets/{mermaid-renderer-cx-n1jFM.js → mermaid-renderer-DGUmIWXY.js} +4 -4
  38. package/dist/dashboard/client/assets/{mindmap-definition-VGOIOE7T-CI5zvW3G.js → mindmap-definition-VGOIOE7T-D-Kc9Xgu.js} +1 -1
  39. package/dist/dashboard/client/assets/{pieDiagram-ADFJNKIX-lC7QV-4L.js → pieDiagram-ADFJNKIX-CooPKLnX.js} +1 -1
  40. package/dist/dashboard/client/assets/{quadrantDiagram-AYHSOK5B-DI7Bn_fF.js → quadrantDiagram-AYHSOK5B-3soPtaSQ.js} +1 -1
  41. package/dist/dashboard/client/assets/{requirementDiagram-UZGBJVZJ-BVuFGUp6.js → requirementDiagram-UZGBJVZJ-rE40t0IG.js} +1 -1
  42. package/dist/dashboard/client/assets/{sankeyDiagram-TZEHDZUN-C-3hBPRk.js → sankeyDiagram-TZEHDZUN-CrgDF_jW.js} +1 -1
  43. package/dist/dashboard/client/assets/{sequenceDiagram-WL72ISMW-CLS6xCbv.js → sequenceDiagram-WL72ISMW-B628IlDW.js} +1 -1
  44. package/dist/dashboard/client/assets/{stateDiagram-FKZM4ZOC-XOLrkoEE.js → stateDiagram-FKZM4ZOC-C4yb7S9D.js} +1 -1
  45. package/dist/dashboard/client/assets/stateDiagram-v2-4FDKWEC3-BoFeOfLI.js +1 -0
  46. package/dist/dashboard/client/assets/{timeline-definition-IT6M3QCI-N9m6IkH5.js → timeline-definition-IT6M3QCI-5uLN4f_J.js} +1 -1
  47. package/dist/dashboard/client/assets/{treemap-GDKQZRPO-ayvdfxB1.js → treemap-GDKQZRPO-BHXME3bw.js} +1 -1
  48. package/dist/dashboard/client/assets/{xychartDiagram-PRI3JC2R-CUmVEVIH.js → xychartDiagram-PRI3JC2R-BYTod6eI.js} +1 -1
  49. package/dist/dashboard/client/index.html +2 -2
  50. package/dist/dashboard/server.js +532 -58
  51. package/dist/index.js +523 -15
  52. package/dist/lib/db/index.js +522 -0
  53. package/package.json +2 -2
  54. package/dist/dashboard/client/assets/channel-OmrThJE3.js +0 -1
  55. package/dist/dashboard/client/assets/classDiagram-2ON5EDUG-Dg5ffKNR.js +0 -1
  56. package/dist/dashboard/client/assets/classDiagram-v2-WZHVMYZB-Dg5ffKNR.js +0 -1
  57. package/dist/dashboard/client/assets/clone-CKI4Qu1i.js +0 -1
  58. package/dist/dashboard/client/assets/index-CPEavIIM.css +0 -1
  59. package/dist/dashboard/client/assets/stateDiagram-v2-4FDKWEC3-Cy33HZ1p.js +0 -1
@@ -18410,7 +18410,7 @@ var require_view = __commonJS({
18410
18410
  var debug = require_src()("express:view");
18411
18411
  var path2 = __require("path");
18412
18412
  var fs6 = __require("fs");
18413
- var dirname10 = path2.dirname;
18413
+ var dirname11 = path2.dirname;
18414
18414
  var basename3 = path2.basename;
18415
18415
  var extname = path2.extname;
18416
18416
  var join13 = path2.join;
@@ -18449,7 +18449,7 @@ var require_view = __commonJS({
18449
18449
  for (var i = 0; i < roots.length && !path3; i++) {
18450
18450
  var root = roots[i];
18451
18451
  var loc = resolve3(root, name);
18452
- var dir = dirname10(loc);
18452
+ var dir = dirname11(loc);
18453
18453
  var file = basename3(loc);
18454
18454
  path3 = this.resolve(dir, file);
18455
18455
  }
@@ -23182,7 +23182,7 @@ var init_open = __esm({
23182
23182
  var import_express11 = __toESM(require_express2(), 1);
23183
23183
  import { createServer } from "node:http";
23184
23184
  import { existsSync as existsSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync4, unlinkSync as unlinkSync2, mkdirSync as mkdirSync3 } from "node:fs";
23185
- import { join as join12, dirname as dirname9, resolve as resolve2 } from "node:path";
23185
+ import { join as join12, dirname as dirname10, resolve as resolve2 } from "node:path";
23186
23186
  import { fileURLToPath as fileURLToPath3 } from "node:url";
23187
23187
  import { randomBytes } from "node:crypto";
23188
23188
  import { Server as SocketIOServer } from "socket.io";
@@ -23440,6 +23440,30 @@ var MIGRATIONS = [
23440
23440
  CREATE INDEX idx_events_session ON orchestration_events(session_id);
23441
23441
  CREATE INDEX idx_events_type ON orchestration_events(event_type);
23442
23442
  `
23443
+ },
23444
+ {
23445
+ version: 6,
23446
+ description: "Add orchestrator-first columns to review_rounds for round-meta.json support",
23447
+ sql: `
23448
+ ALTER TABLE review_rounds ADD COLUMN source TEXT DEFAULT NULL;
23449
+ ALTER TABLE review_rounds ADD COLUMN reviewer_count INTEGER DEFAULT 0;
23450
+ ALTER TABLE review_rounds ADD COLUMN total_finding_count INTEGER DEFAULT 0;
23451
+ `
23452
+ },
23453
+ {
23454
+ version: 7,
23455
+ description: "Add category column to review_findings for blocker/should_fix/suggestion classification",
23456
+ sql: `
23457
+ ALTER TABLE review_findings ADD COLUMN category TEXT DEFAULT NULL;
23458
+ `
23459
+ },
23460
+ {
23461
+ version: 8,
23462
+ description: "Add orchestrator-first columns to map_runs for map-meta.json support",
23463
+ sql: `
23464
+ ALTER TABLE map_runs ADD COLUMN source TEXT DEFAULT NULL;
23465
+ ALTER TABLE map_runs ADD COLUMN section_count INTEGER DEFAULT 0;
23466
+ `
23443
23467
  }
23444
23468
  ];
23445
23469
  function ensureSchemaVersionTable(db) {
@@ -25746,7 +25770,7 @@ function createChatRouter(db, ocrDir) {
25746
25770
 
25747
25771
  // src/server/services/filesystem-sync.ts
25748
25772
  import { readdirSync, readFileSync as readFileSync5, statSync, existsSync as existsSync4 } from "node:fs";
25749
- import { join as join9, basename as basename2, relative } from "node:path";
25773
+ import { join as join9, basename as basename2, dirname as dirname7, relative } from "node:path";
25750
25774
  import { watch } from "chokidar";
25751
25775
 
25752
25776
  // src/server/services/parsers/reviewer-parser.ts
@@ -25838,9 +25862,9 @@ function finalizeFinding(partial, summaryLines) {
25838
25862
 
25839
25863
  // src/server/services/parsers/final-parser.ts
25840
25864
  var VERDICT_RE = /^\*?\*?\s*(?:##\s*)?Verdict\s*\*?\*?\s*:?\s*\*?\*?\s*(.*)/im;
25841
- var BLOCKERS_RE = /\*?\*?Blockers?\*?\*?\s*:?\s*(\d+)/i;
25842
- var SHOULD_FIX_RE = /\*?\*?Should\s*Fix\*?\*?\s*:?\s*(\d+)/i;
25843
- var SUGGESTIONS_RE = /\*?\*?Suggestions?\*?\*?\s*:?\s*(\d+)/i;
25865
+ var BLOCKERS_RE = /^\*\*Blockers?\*\*\s*:?\s*(\d+)/im;
25866
+ var SHOULD_FIX_RE = /^\*\*Should\s*Fix\*\*\s*:?\s*(\d+)/im;
25867
+ var SUGGESTIONS_RE = /^\*\*Suggestions?\*\*\s*:?\s*(\d+)/im;
25844
25868
  function parseFinalMd(content) {
25845
25869
  let verdict = null;
25846
25870
  const verdictMatch = content.match(VERDICT_RE);
@@ -25854,25 +25878,39 @@ function parseFinalMd(content) {
25854
25878
  let shouldFixCount = shouldFixMatch ? parseInt(shouldFixMatch[1] ?? "0", 10) : 0;
25855
25879
  let suggestionCount = suggestionsMatch ? parseInt(suggestionsMatch[1] ?? "0", 10) : 0;
25856
25880
  if (!blockerMatch) {
25857
- blockerCount = countSectionHeaders(content, /^##\s+Blockers?\b/im);
25881
+ blockerCount = countSectionItems(content, /^##\s+Blockers?\b/im);
25858
25882
  }
25859
25883
  if (!shouldFixMatch) {
25860
- shouldFixCount = countSectionHeaders(content, /^##\s+Should\s*Fix\b/im);
25884
+ shouldFixCount = countSectionItems(content, /^##\s+Should\s*Fix\b/im);
25861
25885
  }
25862
25886
  if (!suggestionsMatch) {
25863
- suggestionCount = countSectionHeaders(content, /^##\s+Suggestions?\b/im);
25887
+ suggestionCount = countSectionItems(content, /^##\s+Suggestions?\b/im);
25864
25888
  }
25865
25889
  return { verdict, blockerCount, shouldFixCount, suggestionCount };
25866
25890
  }
25867
- function countSectionHeaders(content, sectionRe) {
25891
+ function countSectionItems(content, sectionRe) {
25868
25892
  const match = content.match(sectionRe);
25869
- if (!match?.index) return 0;
25893
+ if (!match?.index && match?.index !== 0) return 0;
25870
25894
  const afterSection = content.slice(match.index + (match[0]?.length ?? 0));
25871
25895
  const lines = afterSection.split("\n");
25872
25896
  let count = 0;
25873
25897
  for (const line of lines) {
25874
- if (line.match(/^##\s+[^#]/) && !line.match(/^###/)) break;
25875
- if (line.match(/^###\s+\d+\./)) count++;
25898
+ const trimmed = line.trim();
25899
+ if (/^##\s+[^#]/.test(trimmed)) break;
25900
+ if (/^---+\s*$/.test(trimmed)) break;
25901
+ if (/^###\s+\d+\./.test(trimmed)) {
25902
+ count++;
25903
+ continue;
25904
+ }
25905
+ if (/^###\s+[^\w\s#]/.test(trimmed)) {
25906
+ count++;
25907
+ continue;
25908
+ }
25909
+ if (/^-\s+\S/.test(trimmed)) {
25910
+ if (/^-\s+(?:none\b|no\s|n\/a\b)/i.test(trimmed)) continue;
25911
+ count++;
25912
+ continue;
25913
+ }
25876
25914
  }
25877
25915
  return count;
25878
25916
  }
@@ -25913,7 +25951,7 @@ var FilesystemSync = class {
25913
25951
  debounceTimers = /* @__PURE__ */ new Map();
25914
25952
  onSync;
25915
25953
  // ── 6.1: Full Scan ──
25916
- fullScan() {
25954
+ async fullScan() {
25917
25955
  if (!existsSync4(this.sessionsDir)) return;
25918
25956
  const entries = readdirSync(this.sessionsDir, { withFileTypes: true });
25919
25957
  for (const entry of entries) {
@@ -25942,6 +25980,10 @@ var FilesystemSync = class {
25942
25980
  this.processReviewerOutput(sessionId, roundNumber, filePath, reviewFile);
25943
25981
  }
25944
25982
  }
25983
+ const roundMetaPath = join9(roundDir, "round-meta.json");
25984
+ if (existsSync4(roundMetaPath)) {
25985
+ this.processRoundMeta(sessionId, roundNumber, roundMetaPath);
25986
+ }
25945
25987
  const finalPath = join9(roundDir, "final.md");
25946
25988
  if (existsSync4(finalPath)) {
25947
25989
  this.processFinalMd(sessionId, roundNumber, finalPath);
@@ -25965,6 +26007,10 @@ var FilesystemSync = class {
25965
26007
  if (!runMatch) continue;
25966
26008
  const runNumber = parseInt(runMatch[1] ?? "0", 10);
25967
26009
  const runDir = join9(mapDir, runEntry.name);
26010
+ const mapMetaPath = join9(runDir, "map-meta.json");
26011
+ if (existsSync4(mapMetaPath)) {
26012
+ this.processMapMeta(sessionId, runNumber, mapMetaPath);
26013
+ }
25968
26014
  const mapPath = join9(runDir, "map.md");
25969
26015
  if (existsSync4(mapPath)) {
25970
26016
  this.processMapMd(sessionId, runNumber, mapPath);
@@ -26106,15 +26152,21 @@ var FilesystemSync = class {
26106
26152
  processMapMd(sessionId, runNumber, filePath) {
26107
26153
  const existingRun = queryFirst(
26108
26154
  this.db,
26109
- "SELECT id, parsed_at FROM map_runs WHERE session_id = ? AND run_number = ?",
26155
+ "SELECT id, parsed_at, source FROM map_runs WHERE session_id = ? AND run_number = ?",
26110
26156
  [sessionId, runNumber]
26111
26157
  );
26112
26158
  if (existingRun && this.shouldSkip(filePath, existingRun["parsed_at"] ?? null)) return;
26159
+ if (existingRun?.["source"] === "orchestrator") {
26160
+ const content2 = readFileSync5(filePath, "utf-8");
26161
+ const action2 = this.upsertMarkdownArtifact(sessionId, "map", filePath, content2, void 0);
26162
+ this.emitArtifactEvent(action2, { sessionId, artifactType: "map", filePath });
26163
+ return;
26164
+ }
26113
26165
  const content = readFileSync5(filePath, "utf-8");
26114
26166
  const parsed = parseMapMd(content);
26115
26167
  this.db.run(
26116
- `INSERT OR REPLACE INTO map_runs (session_id, run_number, file_count, map_md_path, parsed_at)
26117
- VALUES (?, ?, ?, ?, ?)`,
26168
+ `INSERT OR REPLACE INTO map_runs (session_id, run_number, file_count, map_md_path, parsed_at, source)
26169
+ VALUES (?, ?, ?, ?, ?, 'parser')`,
26118
26170
  [sessionId, runNumber, parsed.sections.reduce((sum, s) => sum + s.files.length, 0), filePath, sqlNow()]
26119
26171
  );
26120
26172
  const runRow = queryFirst(
@@ -26224,11 +26276,22 @@ var FilesystemSync = class {
26224
26276
  );
26225
26277
  const roundRow = queryFirst(
26226
26278
  this.db,
26227
- "SELECT id FROM review_rounds WHERE session_id = ? AND round_number = ?",
26279
+ "SELECT id, source FROM review_rounds WHERE session_id = ? AND round_number = ?",
26228
26280
  [sessionId, roundNumber]
26229
26281
  );
26230
26282
  const roundId = roundRow?.["id"];
26231
26283
  if (!roundId) return;
26284
+ if (roundRow?.["source"] === "orchestrator") {
26285
+ const content2 = readFileSync5(filePath, "utf-8");
26286
+ const action2 = this.upsertMarkdownArtifact(sessionId, "reviewer-output", filePath, content2, roundNumber);
26287
+ this.emitArtifactEvent(action2, {
26288
+ sessionId,
26289
+ artifactType: "reviewer-output",
26290
+ roundNumber,
26291
+ filePath
26292
+ });
26293
+ return;
26294
+ }
26232
26295
  const nameMatch = fileName.replace(/\.md$/, "").match(/^(.+?)-(\d+)$/);
26233
26296
  const reviewerType = nameMatch?.[1] ?? fileName.replace(/\.md$/, "");
26234
26297
  const instanceNumber = nameMatch?.[2] ? parseInt(nameMatch[2], 10) : 1;
@@ -26311,8 +26374,8 @@ var FilesystemSync = class {
26311
26374
  filePath
26312
26375
  });
26313
26376
  }
26314
- // ── 6.4: Final.md Integration ──
26315
- processFinalMd(sessionId, roundNumber, filePath) {
26377
+ // ── 6.3b: Round Meta (Orchestrator-First) ──
26378
+ processRoundMeta(sessionId, roundNumber, filePath) {
26316
26379
  this.db.run(
26317
26380
  `INSERT OR IGNORE INTO review_rounds (session_id, round_number)
26318
26381
  VALUES (?, ?)`,
@@ -26320,39 +26383,325 @@ var FilesystemSync = class {
26320
26383
  );
26321
26384
  const existingRound = queryFirst(
26322
26385
  this.db,
26323
- "SELECT parsed_at FROM review_rounds WHERE session_id = ? AND round_number = ?",
26386
+ "SELECT parsed_at, source FROM review_rounds WHERE session_id = ? AND round_number = ?",
26324
26387
  [sessionId, roundNumber]
26325
26388
  );
26326
- if (existingRound && this.shouldSkip(filePath, existingRound["parsed_at"] ?? null)) return;
26327
- const content = readFileSync5(filePath, "utf-8");
26328
- const parsed = parseFinalMd(content);
26389
+ if (existingRound?.["source"] === "orchestrator" && this.shouldSkip(filePath, existingRound["parsed_at"] ?? null)) return;
26390
+ let raw;
26391
+ try {
26392
+ raw = JSON.parse(readFileSync5(filePath, "utf-8"));
26393
+ } catch {
26394
+ console.error(`[FilesystemSync] Failed to parse ${filePath}`);
26395
+ return;
26396
+ }
26397
+ const meta = raw;
26398
+ if (meta.schema_version !== 1 || !meta.verdict || !Array.isArray(meta.reviewers)) {
26399
+ console.error(`[FilesystemSync] Invalid round-meta.json at ${filePath}`);
26400
+ return;
26401
+ }
26402
+ const allFindings = meta.reviewers.flatMap((r) => r.findings ?? []);
26403
+ const blockerCount = allFindings.filter((f) => f.category === "blocker").length;
26404
+ const shouldFixCount = allFindings.filter((f) => f.category === "should_fix").length;
26405
+ const suggestionCount = allFindings.filter((f) => f.category === "suggestion").length;
26406
+ const reviewerCount = meta.reviewers.length;
26407
+ const totalFindingCount = allFindings.length;
26408
+ this.db.run("BEGIN TRANSACTION");
26409
+ try {
26410
+ this.db.run(
26411
+ `UPDATE review_rounds
26412
+ SET verdict = ?, blocker_count = ?, suggestion_count = ?, should_fix_count = ?,
26413
+ reviewer_count = ?, total_finding_count = ?, source = 'orchestrator', parsed_at = ?
26414
+ WHERE session_id = ? AND round_number = ?`,
26415
+ [
26416
+ meta.verdict,
26417
+ blockerCount,
26418
+ suggestionCount,
26419
+ shouldFixCount,
26420
+ reviewerCount,
26421
+ totalFindingCount,
26422
+ sqlNow(),
26423
+ sessionId,
26424
+ roundNumber
26425
+ ]
26426
+ );
26427
+ const roundRow = queryFirst(
26428
+ this.db,
26429
+ "SELECT id FROM review_rounds WHERE session_id = ? AND round_number = ?",
26430
+ [sessionId, roundNumber]
26431
+ );
26432
+ const roundId = roundRow?.["id"];
26433
+ if (!roundId) {
26434
+ this.db.run("COMMIT");
26435
+ return;
26436
+ }
26437
+ const roundDir = dirname7(filePath);
26438
+ for (const reviewer of meta.reviewers) {
26439
+ const reviewerType = reviewer.type ?? "unknown";
26440
+ const instanceNumber = reviewer.instance ?? 1;
26441
+ const findings = reviewer.findings ?? [];
26442
+ const reviewerMdPath = join9(roundDir, "reviews", `${reviewerType}-${instanceNumber}.md`);
26443
+ this.db.run(
26444
+ `INSERT OR REPLACE INTO reviewer_outputs (round_id, reviewer_type, instance_number, file_path, finding_count, parsed_at)
26445
+ VALUES (?, ?, ?, ?, ?, ?)`,
26446
+ [roundId, reviewerType, instanceNumber, reviewerMdPath, findings.length, sqlNow()]
26447
+ );
26448
+ const outputRow = queryFirst(
26449
+ this.db,
26450
+ "SELECT id FROM reviewer_outputs WHERE round_id = ? AND reviewer_type = ? AND instance_number = ?",
26451
+ [roundId, reviewerType, instanceNumber]
26452
+ );
26453
+ const outputId = outputRow?.["id"];
26454
+ if (!outputId) continue;
26455
+ const stashedFindingProgress = /* @__PURE__ */ new Map();
26456
+ const findingProgressResult = this.db.exec(
26457
+ `SELECT rf.title, rf.severity, rf.file_path, ufp.status, ufp.updated_at
26458
+ FROM user_finding_progress ufp
26459
+ JOIN review_findings rf ON rf.id = ufp.finding_id
26460
+ WHERE rf.reviewer_output_id = ?`,
26461
+ [outputId]
26462
+ );
26463
+ if (findingProgressResult[0]) {
26464
+ for (const row of findingProgressResult[0].values) {
26465
+ const key = `${row[0]}|${row[1]}|${row[2]}`;
26466
+ stashedFindingProgress.set(key, {
26467
+ status: row[3],
26468
+ updatedAt: row[4]
26469
+ });
26470
+ }
26471
+ }
26472
+ this.db.run("DELETE FROM review_findings WHERE reviewer_output_id = ?", [outputId]);
26473
+ for (const finding of findings) {
26474
+ this.db.run(
26475
+ `INSERT INTO review_findings (reviewer_output_id, title, severity, file_path, line_start, line_end, summary, is_blocker, parsed_at)
26476
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
26477
+ [
26478
+ outputId,
26479
+ finding.title ?? "",
26480
+ finding.severity ?? "info",
26481
+ finding.file_path ?? null,
26482
+ finding.line_start ?? null,
26483
+ finding.line_end ?? null,
26484
+ finding.summary ?? null,
26485
+ finding.category === "blocker" ? 1 : 0,
26486
+ sqlNow()
26487
+ ]
26488
+ );
26489
+ const key = `${finding.title ?? ""}|${finding.severity ?? "info"}|${finding.file_path ?? ""}`;
26490
+ const stashed = stashedFindingProgress.get(key);
26491
+ if (stashed) {
26492
+ const newFindingRow = queryFirst(
26493
+ this.db,
26494
+ "SELECT id FROM review_findings WHERE reviewer_output_id = ? AND title = ? AND severity = ? AND file_path IS ?",
26495
+ [outputId, finding.title ?? "", finding.severity ?? "info", finding.file_path ?? null]
26496
+ );
26497
+ if (newFindingRow) {
26498
+ this.db.run(
26499
+ `INSERT OR REPLACE INTO user_finding_progress (finding_id, status, updated_at)
26500
+ VALUES (?, ?, ?)`,
26501
+ [newFindingRow["id"], stashed.status, stashed.updatedAt]
26502
+ );
26503
+ }
26504
+ }
26505
+ }
26506
+ }
26507
+ this.db.run("COMMIT");
26508
+ } catch (err) {
26509
+ this.db.run("ROLLBACK");
26510
+ console.error(`[FilesystemSync] Error in processRoundMeta for ${filePath}:`, err);
26511
+ return;
26512
+ }
26513
+ this.io?.to(`session:${sessionId}`).emit("round:updated", {
26514
+ sessionId,
26515
+ roundNumber,
26516
+ verdict: meta.verdict,
26517
+ blockerCount,
26518
+ shouldFixCount,
26519
+ suggestionCount,
26520
+ reviewerCount,
26521
+ totalFindingCount,
26522
+ source: "orchestrator"
26523
+ });
26524
+ }
26525
+ // ── 6.2b: Map-meta.json Integration ──
26526
+ processMapMeta(sessionId, runNumber, filePath) {
26329
26527
  this.db.run(
26330
- `UPDATE review_rounds SET verdict = ?, blocker_count = ?, suggestion_count = ?, should_fix_count = ?, final_md_path = ?, parsed_at = ?
26331
- WHERE session_id = ? AND round_number = ?`,
26332
- [
26333
- parsed.verdict,
26334
- parsed.blockerCount,
26335
- parsed.suggestionCount,
26336
- parsed.shouldFixCount,
26337
- filePath,
26338
- sqlNow(),
26339
- sessionId,
26340
- roundNumber
26341
- ]
26528
+ `INSERT OR IGNORE INTO map_runs (session_id, run_number)
26529
+ VALUES (?, ?)`,
26530
+ [sessionId, runNumber]
26342
26531
  );
26343
- const actualBlockers = queryScalar(
26532
+ const existingRun = queryFirst(
26344
26533
  this.db,
26345
- `SELECT COUNT(*) FROM review_findings rf
26346
- JOIN reviewer_outputs ro ON rf.reviewer_output_id = ro.id
26347
- WHERE ro.round_id = (SELECT id FROM review_rounds WHERE session_id = ? AND round_number = ?)
26348
- AND rf.is_blocker = 1`,
26534
+ "SELECT id, parsed_at, source FROM map_runs WHERE session_id = ? AND run_number = ?",
26535
+ [sessionId, runNumber]
26536
+ );
26537
+ if (existingRun?.["source"] === "orchestrator" && this.shouldSkip(filePath, existingRun["parsed_at"] ?? null)) return;
26538
+ let raw;
26539
+ try {
26540
+ raw = JSON.parse(readFileSync5(filePath, "utf-8"));
26541
+ } catch {
26542
+ console.error(`[FilesystemSync] Failed to parse ${filePath}`);
26543
+ return;
26544
+ }
26545
+ const meta = raw;
26546
+ if (meta.schema_version !== 1 || !Array.isArray(meta.sections)) {
26547
+ console.error(`[FilesystemSync] Invalid map-meta.json at ${filePath}`);
26548
+ return;
26549
+ }
26550
+ const sectionCount = meta.sections.length;
26551
+ const fileCount = meta.sections.reduce((sum, s) => sum + (s.files?.length ?? 0), 0);
26552
+ this.db.run("BEGIN TRANSACTION");
26553
+ try {
26554
+ this.db.run(
26555
+ `UPDATE map_runs
26556
+ SET file_count = ?, section_count = ?, source = 'orchestrator', parsed_at = ?
26557
+ WHERE session_id = ? AND run_number = ?`,
26558
+ [fileCount, sectionCount, sqlNow(), sessionId, runNumber]
26559
+ );
26560
+ const runRow = queryFirst(
26561
+ this.db,
26562
+ "SELECT id FROM map_runs WHERE session_id = ? AND run_number = ?",
26563
+ [sessionId, runNumber]
26564
+ );
26565
+ const mapRunId = runRow?.["id"];
26566
+ if (!mapRunId) {
26567
+ this.db.run("COMMIT");
26568
+ return;
26569
+ }
26570
+ const stashedFileProgress = /* @__PURE__ */ new Map();
26571
+ const progressResult = this.db.exec(
26572
+ `SELECT mf.file_path, ufp.is_reviewed, ufp.reviewed_at
26573
+ FROM user_file_progress ufp
26574
+ JOIN map_files mf ON mf.id = ufp.map_file_id
26575
+ JOIN map_sections ms ON ms.id = mf.section_id
26576
+ WHERE ms.map_run_id = ?`,
26577
+ [mapRunId]
26578
+ );
26579
+ if (progressResult[0]) {
26580
+ for (const row of progressResult[0].values) {
26581
+ const fp = row[0];
26582
+ stashedFileProgress.set(fp, {
26583
+ isReviewed: row[1],
26584
+ reviewedAt: row[2]
26585
+ });
26586
+ }
26587
+ }
26588
+ const oldSections = this.db.exec(
26589
+ "SELECT id FROM map_sections WHERE map_run_id = ?",
26590
+ [mapRunId]
26591
+ );
26592
+ if (oldSections[0]) {
26593
+ for (const row of oldSections[0].values) {
26594
+ this.db.run("DELETE FROM map_files WHERE section_id = ?", [row[0]]);
26595
+ }
26596
+ }
26597
+ this.db.run("DELETE FROM map_sections WHERE map_run_id = ?", [mapRunId]);
26598
+ for (const section of meta.sections) {
26599
+ const sectionNumber = section.section_number ?? 0;
26600
+ const title = section.title ?? "Untitled";
26601
+ const description = section.description ?? null;
26602
+ const files = section.files ?? [];
26603
+ this.db.run(
26604
+ `INSERT OR REPLACE INTO map_sections (map_run_id, section_number, title, description, file_count, display_order)
26605
+ VALUES (?, ?, ?, ?, ?, ?)`,
26606
+ [mapRunId, sectionNumber, title, description, files.length, sectionNumber]
26607
+ );
26608
+ const sectionRow = queryFirst(
26609
+ this.db,
26610
+ "SELECT id FROM map_sections WHERE map_run_id = ? AND section_number = ?",
26611
+ [mapRunId, sectionNumber]
26612
+ );
26613
+ const sectionId = sectionRow?.["id"];
26614
+ if (!sectionId) continue;
26615
+ for (let fi = 0; fi < files.length; fi++) {
26616
+ const file = files[fi];
26617
+ if (!file) continue;
26618
+ this.db.run(
26619
+ `INSERT OR REPLACE INTO map_files (section_id, file_path, role, lines_added, lines_deleted, display_order)
26620
+ VALUES (?, ?, ?, ?, ?, ?)`,
26621
+ [sectionId, file.file_path ?? "", file.role ?? null, file.lines_added ?? 0, file.lines_deleted ?? 0, fi]
26622
+ );
26623
+ const stashed = stashedFileProgress.get(file.file_path ?? "");
26624
+ if (stashed) {
26625
+ const newFileRow = queryFirst(
26626
+ this.db,
26627
+ "SELECT id FROM map_files WHERE section_id = ? AND file_path = ?",
26628
+ [sectionId, file.file_path ?? ""]
26629
+ );
26630
+ if (newFileRow) {
26631
+ this.db.run(
26632
+ `INSERT OR REPLACE INTO user_file_progress (map_file_id, is_reviewed, reviewed_at)
26633
+ VALUES (?, ?, ?)`,
26634
+ [newFileRow["id"], stashed.isReviewed, stashed.reviewedAt]
26635
+ );
26636
+ }
26637
+ }
26638
+ }
26639
+ }
26640
+ this.db.run("COMMIT");
26641
+ } catch (err) {
26642
+ this.db.run("ROLLBACK");
26643
+ console.error(`[FilesystemSync] Error in processMapMeta for ${filePath}:`, err);
26644
+ return;
26645
+ }
26646
+ this.io?.to(`session:${sessionId}`).emit("map:updated", {
26647
+ sessionId,
26648
+ runNumber,
26649
+ fileCount,
26650
+ sectionCount,
26651
+ source: "orchestrator"
26652
+ });
26653
+ }
26654
+ // ── 6.4: Final.md Integration ──
26655
+ processFinalMd(sessionId, roundNumber, filePath) {
26656
+ this.db.run(
26657
+ `INSERT OR IGNORE INTO review_rounds (session_id, round_number)
26658
+ VALUES (?, ?)`,
26659
+ [sessionId, roundNumber]
26660
+ );
26661
+ const existingRound = queryFirst(
26662
+ this.db,
26663
+ "SELECT parsed_at, source FROM review_rounds WHERE session_id = ? AND round_number = ?",
26349
26664
  [sessionId, roundNumber]
26350
26665
  );
26351
- if (actualBlockers !== null && actualBlockers !== parsed.blockerCount) {
26666
+ const isOrchestratorSource = existingRound?.["source"] === "orchestrator";
26667
+ if (!isOrchestratorSource && existingRound && this.shouldSkip(filePath, existingRound["parsed_at"] ?? null)) return;
26668
+ const content = readFileSync5(filePath, "utf-8");
26669
+ if (isOrchestratorSource) {
26352
26670
  this.db.run(
26353
- "UPDATE review_rounds SET blocker_count = ? WHERE session_id = ? AND round_number = ?",
26354
- [actualBlockers, sessionId, roundNumber]
26671
+ `UPDATE review_rounds SET final_md_path = ?, parsed_at = ?
26672
+ WHERE session_id = ? AND round_number = ?`,
26673
+ [filePath, sqlNow(), sessionId, roundNumber]
26355
26674
  );
26675
+ } else {
26676
+ const parsed = parseFinalMd(content);
26677
+ this.db.run(
26678
+ `UPDATE review_rounds SET verdict = ?, blocker_count = ?, suggestion_count = ?, should_fix_count = ?, final_md_path = ?, parsed_at = ?, source = 'parser'
26679
+ WHERE session_id = ? AND round_number = ?`,
26680
+ [
26681
+ parsed.verdict,
26682
+ parsed.blockerCount,
26683
+ parsed.suggestionCount,
26684
+ parsed.shouldFixCount,
26685
+ filePath,
26686
+ sqlNow(),
26687
+ sessionId,
26688
+ roundNumber
26689
+ ]
26690
+ );
26691
+ const actualBlockers = queryScalar(
26692
+ this.db,
26693
+ `SELECT COUNT(*) FROM review_findings rf
26694
+ JOIN reviewer_outputs ro ON rf.reviewer_output_id = ro.id
26695
+ WHERE ro.round_id = (SELECT id FROM review_rounds WHERE session_id = ? AND round_number = ?)
26696
+ AND rf.is_blocker = 1`,
26697
+ [sessionId, roundNumber]
26698
+ );
26699
+ if (actualBlockers !== null && actualBlockers !== parsed.blockerCount) {
26700
+ this.db.run(
26701
+ "UPDATE review_rounds SET blocker_count = ? WHERE session_id = ? AND round_number = ?",
26702
+ [actualBlockers, sessionId, roundNumber]
26703
+ );
26704
+ }
26356
26705
  }
26357
26706
  const session = queryFirst(
26358
26707
  this.db,
@@ -26427,7 +26776,7 @@ var FilesystemSync = class {
26427
26776
  this.debounceTimers.clear();
26428
26777
  }
26429
26778
  handleFileChange(filePath) {
26430
- if (!filePath.endsWith(".md")) return;
26779
+ if (!filePath.endsWith(".md") && !filePath.endsWith(".json")) return;
26431
26780
  const existing = this.debounceTimers.get(filePath);
26432
26781
  if (existing) clearTimeout(existing);
26433
26782
  this.debounceTimers.set(
@@ -26457,6 +26806,12 @@ var FilesystemSync = class {
26457
26806
  this.processReviewerOutput(sessionId, roundNumber, filePath, reviewerMatch[2] ?? "");
26458
26807
  return;
26459
26808
  }
26809
+ const roundMetaMatch = relFromSessions.match(/rounds\/round-(\d+)\/round-meta\.json$/);
26810
+ if (roundMetaMatch) {
26811
+ const roundNumber = parseInt(roundMetaMatch[1] ?? "0", 10);
26812
+ this.processRoundMeta(sessionId, roundNumber, filePath);
26813
+ return;
26814
+ }
26460
26815
  const finalMatch = relFromSessions.match(/rounds\/round-(\d+)\/final\.md$/);
26461
26816
  if (finalMatch) {
26462
26817
  const roundNumber = parseInt(finalMatch[1] ?? "0", 10);
@@ -26475,6 +26830,12 @@ var FilesystemSync = class {
26475
26830
  this.processGenericArtifact(sessionId, "discourse", filePath, roundNumber);
26476
26831
  return;
26477
26832
  }
26833
+ const mapMetaMatch = relFromSessions.match(/map\/runs\/run-(\d+)\/map-meta\.json$/);
26834
+ if (mapMetaMatch) {
26835
+ const runNumber = parseInt(mapMetaMatch[1] ?? "0", 10);
26836
+ this.processMapMeta(sessionId, runNumber, filePath);
26837
+ return;
26838
+ }
26478
26839
  const mapMatch = relFromSessions.match(/map\/runs\/run-(\d+)\/map\.md$/);
26479
26840
  if (mapMatch) {
26480
26841
  const runNumber = parseInt(mapMatch[1] ?? "0", 10);
@@ -26698,7 +27059,7 @@ var DbSyncWatcher = class {
26698
27059
  const diskEvents = resultToRows(
26699
27060
  diskDb.exec("SELECT * FROM orchestration_events ORDER BY id ASC")
26700
27061
  );
26701
- let insertedCount = 0;
27062
+ const newEvents = [];
26702
27063
  const affectedSessions = /* @__PURE__ */ new Set();
26703
27064
  for (const row of diskEvents) {
26704
27065
  const eventId = col(row, "id");
@@ -26722,15 +27083,128 @@ var DbSyncWatcher = class {
26722
27083
  col(row, "created_at")
26723
27084
  ]
26724
27085
  );
26725
- insertedCount++;
27086
+ newEvents.push(row);
26726
27087
  affectedSessions.add(sessionId);
26727
27088
  }
26728
- if (insertedCount > 0) {
27089
+ for (const row of newEvents) {
27090
+ const eventType = col(row, "event_type");
27091
+ const sessionId = col(row, "session_id");
27092
+ const metadataStr = col(row, "metadata");
27093
+ if (eventType === "round_completed") {
27094
+ const roundNumber = col(row, "round");
27095
+ if (sessionId && roundNumber && metadataStr) {
27096
+ this.processRoundCompletedEvent(sessionId, roundNumber, metadataStr);
27097
+ }
27098
+ } else if (eventType === "map_completed") {
27099
+ const runNumber = col(row, "round");
27100
+ if (sessionId && runNumber && metadataStr) {
27101
+ this.processMapCompletedEvent(sessionId, runNumber, metadataStr);
27102
+ }
27103
+ }
27104
+ }
27105
+ if (newEvents.length > 0) {
26729
27106
  for (const sessionId of affectedSessions) {
26730
- this.io.emit("session:events", { session_id: sessionId });
27107
+ this.io.to(`session:${sessionId}`).emit("session:events", { session_id: sessionId });
26731
27108
  }
26732
27109
  }
26733
27110
  }
27111
+ /**
27112
+ * Process a `round_completed` orchestration event.
27113
+ * Upserts review_rounds with orchestrator data for real-time dashboard updates.
27114
+ * Idempotent — skips if round already has source='orchestrator'.
27115
+ */
27116
+ processRoundCompletedEvent(sessionId, roundNumber, metadataStr) {
27117
+ let metadata;
27118
+ try {
27119
+ metadata = JSON.parse(metadataStr);
27120
+ } catch {
27121
+ return;
27122
+ }
27123
+ const existing = this.db.exec(
27124
+ "SELECT source FROM review_rounds WHERE session_id = ? AND round_number = ?",
27125
+ [sessionId, roundNumber]
27126
+ );
27127
+ const rows = resultToRows(existing);
27128
+ if (rows.length > 0 && col(rows[0], "source") === "orchestrator") {
27129
+ return;
27130
+ }
27131
+ this.db.run(
27132
+ `INSERT OR IGNORE INTO review_rounds (session_id, round_number)
27133
+ VALUES (?, ?)`,
27134
+ [sessionId, roundNumber]
27135
+ );
27136
+ this.db.run(
27137
+ `UPDATE review_rounds
27138
+ SET verdict = ?, blocker_count = ?, suggestion_count = ?, should_fix_count = ?,
27139
+ reviewer_count = ?, total_finding_count = ?, source = 'orchestrator',
27140
+ parsed_at = datetime('now')
27141
+ WHERE session_id = ? AND round_number = ?`,
27142
+ [
27143
+ metadata.verdict ?? null,
27144
+ metadata.blocker_count ?? 0,
27145
+ metadata.suggestion_count ?? 0,
27146
+ metadata.should_fix_count ?? 0,
27147
+ metadata.reviewer_count ?? 0,
27148
+ metadata.total_finding_count ?? 0,
27149
+ sessionId,
27150
+ roundNumber
27151
+ ]
27152
+ );
27153
+ this.io.to(`session:${sessionId}`).emit("round:updated", {
27154
+ sessionId,
27155
+ roundNumber,
27156
+ verdict: metadata.verdict,
27157
+ blockerCount: metadata.blocker_count,
27158
+ shouldFixCount: metadata.should_fix_count,
27159
+ suggestionCount: metadata.suggestion_count,
27160
+ source: "orchestrator"
27161
+ });
27162
+ }
27163
+ /**
27164
+ * Process a `map_completed` orchestration event.
27165
+ * Upserts map_runs with orchestrator data for real-time dashboard updates.
27166
+ * Idempotent — skips if run already has source='orchestrator'.
27167
+ */
27168
+ processMapCompletedEvent(sessionId, runNumber, metadataStr) {
27169
+ let metadata;
27170
+ try {
27171
+ metadata = JSON.parse(metadataStr);
27172
+ } catch {
27173
+ return;
27174
+ }
27175
+ const existing = this.db.exec(
27176
+ "SELECT source FROM map_runs WHERE session_id = ? AND run_number = ?",
27177
+ [sessionId, runNumber]
27178
+ );
27179
+ const rows = resultToRows(existing);
27180
+ if (rows.length > 0 && col(rows[0], "source") === "orchestrator") {
27181
+ return;
27182
+ }
27183
+ this.db.run(
27184
+ `INSERT OR IGNORE INTO map_runs (session_id, run_number)
27185
+ VALUES (?, ?)`,
27186
+ [sessionId, runNumber]
27187
+ );
27188
+ this.db.run(
27189
+ `UPDATE map_runs
27190
+ SET file_count = ?, section_count = ?, source = 'orchestrator',
27191
+ parsed_at = datetime('now')
27192
+ WHERE session_id = ? AND run_number = ?`,
27193
+ [
27194
+ metadata.file_count ?? 0,
27195
+ metadata.section_count ?? 0,
27196
+ sessionId,
27197
+ runNumber
27198
+ ]
27199
+ );
27200
+ this.io.to(`session:${sessionId}`).emit("map:updated", {
27201
+ sessionId,
27202
+ runNumber,
27203
+ fileCount: metadata.file_count,
27204
+ sectionCount: metadata.section_count,
27205
+ source: "orchestrator"
27206
+ });
27207
+ }
26734
27208
  /**
26735
27209
  * Record current mtime after the dashboard writes to disk.
26736
27210
  * Called automatically via registered save hooks after saveDb().
@@ -26744,7 +27218,7 @@ var DbSyncWatcher = class {
26744
27218
  };
26745
27219
 
26746
27220
  // src/server/socket/chat-handler.ts
26747
- import { dirname as dirname7 } from "node:path";
27221
+ import { dirname as dirname8 } from "node:path";
26748
27222
 
26749
27223
  // src/server/services/chat-context.ts
26750
27224
  import { readFileSync as readFileSync7, readdirSync as readdirSync2, existsSync as existsSync6 } from "node:fs";
@@ -26939,7 +27413,7 @@ User: ${message}`;
26939
27413
  });
26940
27414
  return;
26941
27415
  }
26942
- const repoRoot = dirname7(ocrDir);
27416
+ const repoRoot = dirname8(ocrDir);
26943
27417
  const spawnResult = adapter.spawn({
26944
27418
  prompt,
26945
27419
  cwd: repoRoot,
@@ -27118,13 +27592,13 @@ function cleanupAllChats() {
27118
27592
  import { execFile } from "node:child_process";
27119
27593
  import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync8, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
27120
27594
  import { tmpdir as tmpdir2 } from "node:os";
27121
- import { join as join11, dirname as dirname8, isAbsolute } from "node:path";
27595
+ import { join as join11, dirname as dirname9, isAbsolute } from "node:path";
27122
27596
  import { randomUUID } from "node:crypto";
27123
27597
  import { promisify } from "node:util";
27124
27598
  var execFileAsync = promisify(execFile);
27125
27599
  function resolveSessionDir(sessionDir, ocrDir) {
27126
27600
  if (isAbsolute(sessionDir)) return sessionDir;
27127
- return join11(dirname8(ocrDir), sessionDir);
27601
+ return join11(dirname9(ocrDir), sessionDir);
27128
27602
  }
27129
27603
  var BRANCH_PREFIXES = [
27130
27604
  "feat",
@@ -27193,7 +27667,7 @@ function registerPostHandlers(io2, socket, db, ocrDir, aiCliService) {
27193
27667
  return;
27194
27668
  }
27195
27669
  const branch = session.branch;
27196
- const repoRoot = dirname8(ocrDir);
27670
+ const repoRoot = dirname9(ocrDir);
27197
27671
  try {
27198
27672
  await execFileAsync("gh", ["auth", "status"], { env: cleanEnv(), cwd: repoRoot });
27199
27673
  } catch {
@@ -27302,7 +27776,7 @@ function registerPostHandlers(io2, socket, db, ocrDir, aiCliService) {
27302
27776
  return;
27303
27777
  }
27304
27778
  const humanReviewPath = join11(roundDir, "final-human.md");
27305
- const repoRoot = dirname8(ocrDir);
27779
+ const repoRoot = dirname9(ocrDir);
27306
27780
  const commandMdPath = join11(ocrDir, "commands", "translate-review-to-single-human.md");
27307
27781
  let commandContent;
27308
27782
  try {
@@ -27497,7 +27971,7 @@ function registerPostHandlers(io2, socket, db, ocrDir, aiCliService) {
27497
27971
  }
27498
27972
  const tmpFile = join11(tmpDir, `${randomUUID()}.md`);
27499
27973
  writeFileSync3(tmpFile, content, { mode: 384 });
27500
- const repoRoot = dirname8(ocrDir);
27974
+ const repoRoot = dirname9(ocrDir);
27501
27975
  try {
27502
27976
  const { stdout } = await execFileAsync(
27503
27977
  "gh",
@@ -27541,7 +28015,7 @@ function cleanupAllPostGenerations() {
27541
28015
  }
27542
28016
 
27543
28017
  // src/server/index.ts
27544
- var __dirname3 = dirname9(fileURLToPath3(import.meta.url));
28018
+ var __dirname3 = dirname10(fileURLToPath3(import.meta.url));
27545
28019
  var AUTH_TOKEN = randomBytes(32).toString("hex");
27546
28020
  var app = (0, import_express11.default)();
27547
28021
  var httpServer = createServer(app);