@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.
- package/README.md +57 -127
- package/dist/dashboard/client/assets/{_basePickBy-BJKCdvle.js → _basePickBy-BGuMbEDR.js} +1 -1
- package/dist/dashboard/client/assets/{_baseUniq-L_sxIO0r.js → _baseUniq-Bx8loabg.js} +1 -1
- package/dist/dashboard/client/assets/{arc-tqAEcLt5.js → arc-DUgpt7nY.js} +1 -1
- package/dist/dashboard/client/assets/{architectureDiagram-VXUJARFQ-CrKQo6Ye.js → architectureDiagram-VXUJARFQ-D25nt6Xz.js} +1 -1
- package/dist/dashboard/client/assets/{blockDiagram-VD42YOAC-DXOc89nw.js → blockDiagram-VD42YOAC-D8PUF3h4.js} +1 -1
- package/dist/dashboard/client/assets/{c4Diagram-YG6GDRKO-Ba-jYbw0.js → c4Diagram-YG6GDRKO-lorsCz-I.js} +1 -1
- package/dist/dashboard/client/assets/channel-yW2sWou_.js +1 -0
- package/dist/dashboard/client/assets/{chunk-4BX2VUAB-D1G3HCqL.js → chunk-4BX2VUAB-8lVyfRJM.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-55IACEB6-FI7g4AjR.js → chunk-55IACEB6-C4SjgsZO.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-B4BG7PRW-DhEGFGWs.js → chunk-B4BG7PRW-BXzTPbH1.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-DI55MBZ5-Da3-6ZE4.js → chunk-DI55MBZ5-Bp7QllDt.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-FMBD7UC4-D0QLOjiy.js → chunk-FMBD7UC4-B4g9S67N.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-QN33PNHL-WkfgpbLo.js → chunk-QN33PNHL-Dyk7Hc0J.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-QZHKN3VN-Bqn0IO1w.js → chunk-QZHKN3VN-DTvkGdnm.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-TZMSLE5B-CC_K_BeL.js → chunk-TZMSLE5B-BAeZLvrI.js} +1 -1
- package/dist/dashboard/client/assets/classDiagram-2ON5EDUG-1pMX5UXO.js +1 -0
- package/dist/dashboard/client/assets/classDiagram-v2-WZHVMYZB-1pMX5UXO.js +1 -0
- package/dist/dashboard/client/assets/clone-DQwdw3YR.js +1 -0
- package/dist/dashboard/client/assets/{cose-bilkent-S5V4N54A-D8urqxIF.js → cose-bilkent-S5V4N54A--6-kzrdu.js} +1 -1
- package/dist/dashboard/client/assets/{dagre-6UL2VRFP-w2xS0ztU.js → dagre-6UL2VRFP-D10_QE2P.js} +1 -1
- package/dist/dashboard/client/assets/{diagram-PSM6KHXK-DlOtv6zO.js → diagram-PSM6KHXK-kS1x75Bl.js} +1 -1
- package/dist/dashboard/client/assets/{diagram-QEK2KX5R-EpxsVLZY.js → diagram-QEK2KX5R-D_LLCPas.js} +1 -1
- package/dist/dashboard/client/assets/{diagram-S2PKOQOG-kmITzl42.js → diagram-S2PKOQOG-Duy1t5UO.js} +1 -1
- package/dist/dashboard/client/assets/{erDiagram-Q2GNP2WA-Bvyepu_Z.js → erDiagram-Q2GNP2WA-DyQXwzLf.js} +1 -1
- package/dist/dashboard/client/assets/{flowDiagram-NV44I4VS-BokLAZN0.js → flowDiagram-NV44I4VS-D9U11XVw.js} +1 -1
- package/dist/dashboard/client/assets/{ganttDiagram-JELNMOA3-i5ZSGuTN.js → ganttDiagram-JELNMOA3-STy-TC-3.js} +1 -1
- package/dist/dashboard/client/assets/{gitGraphDiagram-V2S2FVAM-CIayQ8P9.js → gitGraphDiagram-V2S2FVAM-B04PgURg.js} +1 -1
- package/dist/dashboard/client/assets/{graph-C3ouLF2F.js → graph-AiGwnT5H.js} +1 -1
- package/dist/dashboard/client/assets/{index-icxlpW-l.js → index-BzQ3i_QR.js} +109 -107
- package/dist/dashboard/client/assets/index-CGGYXSm-.css +1 -0
- package/dist/dashboard/client/assets/{infoDiagram-HS3SLOUP-wxe8NO00.js → infoDiagram-HS3SLOUP-D4arwl6T.js} +1 -1
- package/dist/dashboard/client/assets/{journeyDiagram-XKPGCS4Q-BeHCbOFN.js → journeyDiagram-XKPGCS4Q-CsKqlKkf.js} +1 -1
- package/dist/dashboard/client/assets/{kanban-definition-3W4ZIXB7-DxUlb4wo.js → kanban-definition-3W4ZIXB7-CUFnzQE3.js} +1 -1
- package/dist/dashboard/client/assets/{layout-CYsQ5kjv.js → layout-BvvYJVPv.js} +1 -1
- package/dist/dashboard/client/assets/{linear-ByuMiLUn.js → linear-BiBJkzyE.js} +1 -1
- package/dist/dashboard/client/assets/{mermaid-renderer-cx-n1jFM.js → mermaid-renderer-DGUmIWXY.js} +4 -4
- package/dist/dashboard/client/assets/{mindmap-definition-VGOIOE7T-CI5zvW3G.js → mindmap-definition-VGOIOE7T-D-Kc9Xgu.js} +1 -1
- package/dist/dashboard/client/assets/{pieDiagram-ADFJNKIX-lC7QV-4L.js → pieDiagram-ADFJNKIX-CooPKLnX.js} +1 -1
- package/dist/dashboard/client/assets/{quadrantDiagram-AYHSOK5B-DI7Bn_fF.js → quadrantDiagram-AYHSOK5B-3soPtaSQ.js} +1 -1
- package/dist/dashboard/client/assets/{requirementDiagram-UZGBJVZJ-BVuFGUp6.js → requirementDiagram-UZGBJVZJ-rE40t0IG.js} +1 -1
- package/dist/dashboard/client/assets/{sankeyDiagram-TZEHDZUN-C-3hBPRk.js → sankeyDiagram-TZEHDZUN-CrgDF_jW.js} +1 -1
- package/dist/dashboard/client/assets/{sequenceDiagram-WL72ISMW-CLS6xCbv.js → sequenceDiagram-WL72ISMW-B628IlDW.js} +1 -1
- package/dist/dashboard/client/assets/{stateDiagram-FKZM4ZOC-XOLrkoEE.js → stateDiagram-FKZM4ZOC-C4yb7S9D.js} +1 -1
- package/dist/dashboard/client/assets/stateDiagram-v2-4FDKWEC3-BoFeOfLI.js +1 -0
- package/dist/dashboard/client/assets/{timeline-definition-IT6M3QCI-N9m6IkH5.js → timeline-definition-IT6M3QCI-5uLN4f_J.js} +1 -1
- package/dist/dashboard/client/assets/{treemap-GDKQZRPO-ayvdfxB1.js → treemap-GDKQZRPO-BHXME3bw.js} +1 -1
- package/dist/dashboard/client/assets/{xychartDiagram-PRI3JC2R-CUmVEVIH.js → xychartDiagram-PRI3JC2R-BYTod6eI.js} +1 -1
- package/dist/dashboard/client/index.html +2 -2
- package/dist/dashboard/server.js +532 -58
- package/dist/index.js +523 -15
- package/dist/lib/db/index.js +522 -0
- package/package.json +2 -2
- package/dist/dashboard/client/assets/channel-OmrThJE3.js +0 -1
- package/dist/dashboard/client/assets/classDiagram-2ON5EDUG-Dg5ffKNR.js +0 -1
- package/dist/dashboard/client/assets/classDiagram-v2-WZHVMYZB-Dg5ffKNR.js +0 -1
- package/dist/dashboard/client/assets/clone-CKI4Qu1i.js +0 -1
- package/dist/dashboard/client/assets/index-CPEavIIM.css +0 -1
- package/dist/dashboard/client/assets/stateDiagram-v2-4FDKWEC3-Cy33HZ1p.js +0 -1
package/dist/dashboard/server.js
CHANGED
|
@@ -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
|
|
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 =
|
|
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
|
|
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 =
|
|
25842
|
-
var SHOULD_FIX_RE =
|
|
25843
|
-
var SUGGESTIONS_RE =
|
|
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 =
|
|
25881
|
+
blockerCount = countSectionItems(content, /^##\s+Blockers?\b/im);
|
|
25858
25882
|
}
|
|
25859
25883
|
if (!shouldFixMatch) {
|
|
25860
|
-
shouldFixCount =
|
|
25884
|
+
shouldFixCount = countSectionItems(content, /^##\s+Should\s*Fix\b/im);
|
|
25861
25885
|
}
|
|
25862
25886
|
if (!suggestionsMatch) {
|
|
25863
|
-
suggestionCount =
|
|
25887
|
+
suggestionCount = countSectionItems(content, /^##\s+Suggestions?\b/im);
|
|
25864
25888
|
}
|
|
25865
25889
|
return { verdict, blockerCount, shouldFixCount, suggestionCount };
|
|
25866
25890
|
}
|
|
25867
|
-
function
|
|
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
|
-
|
|
25875
|
-
if (
|
|
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.
|
|
26315
|
-
|
|
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
|
-
|
|
26328
|
-
|
|
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
|
-
`
|
|
26331
|
-
|
|
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
|
|
26532
|
+
const existingRun = queryFirst(
|
|
26344
26533
|
this.db,
|
|
26345
|
-
|
|
26346
|
-
|
|
26347
|
-
|
|
26348
|
-
|
|
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
|
-
|
|
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
|
-
|
|
26354
|
-
|
|
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
|
-
|
|
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
|
-
|
|
27086
|
+
newEvents.push(row);
|
|
26726
27087
|
affectedSessions.add(sessionId);
|
|
26727
27088
|
}
|
|
26728
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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);
|