@open-code-review/cli 1.6.0 → 1.8.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 +20 -4
- package/dist/dashboard/client/assets/{_basePickBy-BGuMbEDR.js → _basePickBy-DbLJVCA4.js} +1 -1
- package/dist/dashboard/client/assets/{_baseUniq-Bx8loabg.js → _baseUniq-IXEG0cJJ.js} +1 -1
- package/dist/dashboard/client/assets/{arc-DUgpt7nY.js → arc-lsKxmOJY.js} +1 -1
- package/dist/dashboard/client/assets/{architectureDiagram-VXUJARFQ-D25nt6Xz.js → architectureDiagram-VXUJARFQ-DfMlzFJX.js} +1 -1
- package/dist/dashboard/client/assets/{blockDiagram-VD42YOAC-D8PUF3h4.js → blockDiagram-VD42YOAC-bSpnd26J.js} +1 -1
- package/dist/dashboard/client/assets/{c4Diagram-YG6GDRKO-lorsCz-I.js → c4Diagram-YG6GDRKO-DPYmVhCZ.js} +1 -1
- package/dist/dashboard/client/assets/channel-C--wY_Wd.js +1 -0
- package/dist/dashboard/client/assets/{chunk-4BX2VUAB-8lVyfRJM.js → chunk-4BX2VUAB-CI9zC4lV.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-55IACEB6-C4SjgsZO.js → chunk-55IACEB6-BqUdJdx5.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-B4BG7PRW-BXzTPbH1.js → chunk-B4BG7PRW-DymQrTp-.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-DI55MBZ5-Bp7QllDt.js → chunk-DI55MBZ5-lZ_9LKGJ.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-FMBD7UC4-B4g9S67N.js → chunk-FMBD7UC4-DC5rgLNm.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-QN33PNHL-Dyk7Hc0J.js → chunk-QN33PNHL-BrygpHrX.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-QZHKN3VN-DTvkGdnm.js → chunk-QZHKN3VN-CWJqBdNg.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-TZMSLE5B-BAeZLvrI.js → chunk-TZMSLE5B-BACgM5pG.js} +1 -1
- package/dist/dashboard/client/assets/classDiagram-2ON5EDUG-DoxmMlnf.js +1 -0
- package/dist/dashboard/client/assets/classDiagram-v2-WZHVMYZB-DoxmMlnf.js +1 -0
- package/dist/dashboard/client/assets/clone-BgvweD4v.js +1 -0
- package/dist/dashboard/client/assets/{cose-bilkent-S5V4N54A--6-kzrdu.js → cose-bilkent-S5V4N54A-BYvGIfo0.js} +1 -1
- package/dist/dashboard/client/assets/{dagre-6UL2VRFP-D10_QE2P.js → dagre-6UL2VRFP-B1rZyiLJ.js} +1 -1
- package/dist/dashboard/client/assets/{diagram-PSM6KHXK-kS1x75Bl.js → diagram-PSM6KHXK-Dvl5dQMd.js} +1 -1
- package/dist/dashboard/client/assets/{diagram-QEK2KX5R-D_LLCPas.js → diagram-QEK2KX5R-Cmntmhht.js} +1 -1
- package/dist/dashboard/client/assets/{diagram-S2PKOQOG-Duy1t5UO.js → diagram-S2PKOQOG-BqZcpG85.js} +1 -1
- package/dist/dashboard/client/assets/{erDiagram-Q2GNP2WA-DyQXwzLf.js → erDiagram-Q2GNP2WA-Cw7BALso.js} +1 -1
- package/dist/dashboard/client/assets/{flowDiagram-NV44I4VS-D9U11XVw.js → flowDiagram-NV44I4VS-B_amTHzQ.js} +1 -1
- package/dist/dashboard/client/assets/{ganttDiagram-JELNMOA3-STy-TC-3.js → ganttDiagram-JELNMOA3-B1j2-sTo.js} +1 -1
- package/dist/dashboard/client/assets/{gitGraphDiagram-V2S2FVAM-B04PgURg.js → gitGraphDiagram-V2S2FVAM-D5BkfAMt.js} +1 -1
- package/dist/dashboard/client/assets/{graph-AiGwnT5H.js → graph-B_v15DHv.js} +1 -1
- package/dist/dashboard/client/assets/index-UkJZZdYD.js +548 -0
- package/dist/dashboard/client/assets/index-Zl---B_3.css +1 -0
- package/dist/dashboard/client/assets/{infoDiagram-HS3SLOUP-D4arwl6T.js → infoDiagram-HS3SLOUP-C4dtIkj3.js} +1 -1
- package/dist/dashboard/client/assets/{journeyDiagram-XKPGCS4Q-CsKqlKkf.js → journeyDiagram-XKPGCS4Q-hha4Am8v.js} +1 -1
- package/dist/dashboard/client/assets/{kanban-definition-3W4ZIXB7-CUFnzQE3.js → kanban-definition-3W4ZIXB7-1EY8l7Ng.js} +1 -1
- package/dist/dashboard/client/assets/{layout-BvvYJVPv.js → layout-7SmAbjFT.js} +1 -1
- package/dist/dashboard/client/assets/{linear-BiBJkzyE.js → linear-BfjSBezh.js} +1 -1
- package/dist/dashboard/client/assets/{mermaid-renderer-DGUmIWXY.js → mermaid-renderer-PPIt-kY4.js} +4 -4
- package/dist/dashboard/client/assets/{mindmap-definition-VGOIOE7T-D-Kc9Xgu.js → mindmap-definition-VGOIOE7T-BFpjN9LY.js} +1 -1
- package/dist/dashboard/client/assets/{pieDiagram-ADFJNKIX-CooPKLnX.js → pieDiagram-ADFJNKIX-GBbQtDBQ.js} +1 -1
- package/dist/dashboard/client/assets/{quadrantDiagram-AYHSOK5B-3soPtaSQ.js → quadrantDiagram-AYHSOK5B-Dm0vOhOw.js} +1 -1
- package/dist/dashboard/client/assets/{requirementDiagram-UZGBJVZJ-rE40t0IG.js → requirementDiagram-UZGBJVZJ-BrKONIV8.js} +1 -1
- package/dist/dashboard/client/assets/{sankeyDiagram-TZEHDZUN-CrgDF_jW.js → sankeyDiagram-TZEHDZUN-IOobtmDc.js} +1 -1
- package/dist/dashboard/client/assets/{sequenceDiagram-WL72ISMW-B628IlDW.js → sequenceDiagram-WL72ISMW-Dnb0bOW5.js} +1 -1
- package/dist/dashboard/client/assets/{stateDiagram-FKZM4ZOC-C4yb7S9D.js → stateDiagram-FKZM4ZOC-C9-bf7bn.js} +1 -1
- package/dist/dashboard/client/assets/stateDiagram-v2-4FDKWEC3-C8Gr4khP.js +1 -0
- package/dist/dashboard/client/assets/{timeline-definition-IT6M3QCI-5uLN4f_J.js → timeline-definition-IT6M3QCI-tJogDEHB.js} +1 -1
- package/dist/dashboard/client/assets/{treemap-GDKQZRPO-BHXME3bw.js → treemap-GDKQZRPO-DQY6HADq.js} +1 -1
- package/dist/dashboard/client/assets/{xychartDiagram-PRI3JC2R-BYTod6eI.js → xychartDiagram-PRI3JC2R-DfxeQmTO.js} +1 -1
- package/dist/dashboard/client/index.html +2 -2
- package/dist/dashboard/server.js +312 -187
- package/dist/index.js +326 -10
- package/package.json +2 -2
- package/dist/dashboard/client/assets/channel-yW2sWou_.js +0 -1
- package/dist/dashboard/client/assets/classDiagram-2ON5EDUG-1pMX5UXO.js +0 -1
- package/dist/dashboard/client/assets/classDiagram-v2-WZHVMYZB-1pMX5UXO.js +0 -1
- package/dist/dashboard/client/assets/clone-DQwdw3YR.js +0 -1
- package/dist/dashboard/client/assets/index-BzQ3i_QR.js +0 -458
- package/dist/dashboard/client/assets/index-CGGYXSm-.css +0 -1
- package/dist/dashboard/client/assets/stateDiagram-v2-4FDKWEC3-BoFeOfLI.js +0 -1
package/dist/dashboard/server.js
CHANGED
|
@@ -18413,7 +18413,7 @@ var require_view = __commonJS({
|
|
|
18413
18413
|
var dirname11 = path2.dirname;
|
|
18414
18414
|
var basename3 = path2.basename;
|
|
18415
18415
|
var extname = path2.extname;
|
|
18416
|
-
var
|
|
18416
|
+
var join14 = path2.join;
|
|
18417
18417
|
var resolve3 = path2.resolve;
|
|
18418
18418
|
module.exports = View;
|
|
18419
18419
|
function View(name, options) {
|
|
@@ -18461,12 +18461,12 @@ var require_view = __commonJS({
|
|
|
18461
18461
|
};
|
|
18462
18462
|
View.prototype.resolve = function resolve4(dir, file) {
|
|
18463
18463
|
var ext = this.ext;
|
|
18464
|
-
var path3 =
|
|
18464
|
+
var path3 = join14(dir, file);
|
|
18465
18465
|
var stat = tryStat(path3);
|
|
18466
18466
|
if (stat && stat.isFile()) {
|
|
18467
18467
|
return path3;
|
|
18468
18468
|
}
|
|
18469
|
-
path3 =
|
|
18469
|
+
path3 = join14(dir, basename3(file, ext), "index" + ext);
|
|
18470
18470
|
stat = tryStat(path3);
|
|
18471
18471
|
if (stat && stat.isFile()) {
|
|
18472
18472
|
return path3;
|
|
@@ -19099,7 +19099,7 @@ var require_send = __commonJS({
|
|
|
19099
19099
|
var Stream = __require("stream");
|
|
19100
19100
|
var util = __require("util");
|
|
19101
19101
|
var extname = path2.extname;
|
|
19102
|
-
var
|
|
19102
|
+
var join14 = path2.join;
|
|
19103
19103
|
var normalize = path2.normalize;
|
|
19104
19104
|
var resolve3 = path2.resolve;
|
|
19105
19105
|
var sep = path2.sep;
|
|
@@ -19318,7 +19318,7 @@ var require_send = __commonJS({
|
|
|
19318
19318
|
return res;
|
|
19319
19319
|
}
|
|
19320
19320
|
parts = path3.split(sep);
|
|
19321
|
-
path3 = normalize(
|
|
19321
|
+
path3 = normalize(join14(root, path3));
|
|
19322
19322
|
} else {
|
|
19323
19323
|
if (UP_PATH_REGEXP.test(path3)) {
|
|
19324
19324
|
debug('malicious path "%s"', path3);
|
|
@@ -19453,7 +19453,7 @@ var require_send = __commonJS({
|
|
|
19453
19453
|
if (err) return self.onStatError(err);
|
|
19454
19454
|
return self.error(404);
|
|
19455
19455
|
}
|
|
19456
|
-
var p =
|
|
19456
|
+
var p = join14(path3, self._index[i]);
|
|
19457
19457
|
debug('stat "%s"', p);
|
|
19458
19458
|
fs6.stat(p, function(err2, stat) {
|
|
19459
19459
|
if (err2) return next(err2);
|
|
@@ -20592,7 +20592,7 @@ var require_application = __commonJS({
|
|
|
20592
20592
|
"../../node_modules/.pnpm/express@4.22.1/node_modules/express/lib/application.js"(exports, module) {
|
|
20593
20593
|
"use strict";
|
|
20594
20594
|
var finalhandler = require_finalhandler();
|
|
20595
|
-
var
|
|
20595
|
+
var Router12 = require_router();
|
|
20596
20596
|
var methods = require_methods();
|
|
20597
20597
|
var middleware = require_init();
|
|
20598
20598
|
var query = require_query();
|
|
@@ -20657,7 +20657,7 @@ var require_application = __commonJS({
|
|
|
20657
20657
|
};
|
|
20658
20658
|
app2.lazyrouter = function lazyrouter() {
|
|
20659
20659
|
if (!this._router) {
|
|
20660
|
-
this._router = new
|
|
20660
|
+
this._router = new Router12({
|
|
20661
20661
|
caseSensitive: this.enabled("case sensitive routing"),
|
|
20662
20662
|
strict: this.enabled("strict routing")
|
|
20663
20663
|
});
|
|
@@ -22521,7 +22521,7 @@ var require_express = __commonJS({
|
|
|
22521
22521
|
var mixin = require_merge_descriptors();
|
|
22522
22522
|
var proto = require_application();
|
|
22523
22523
|
var Route = require_route();
|
|
22524
|
-
var
|
|
22524
|
+
var Router12 = require_router();
|
|
22525
22525
|
var req = require_request();
|
|
22526
22526
|
var res = require_response();
|
|
22527
22527
|
exports = module.exports = createApplication;
|
|
@@ -22544,7 +22544,7 @@ var require_express = __commonJS({
|
|
|
22544
22544
|
exports.request = req;
|
|
22545
22545
|
exports.response = res;
|
|
22546
22546
|
exports.Route = Route;
|
|
22547
|
-
exports.Router =
|
|
22547
|
+
exports.Router = Router12;
|
|
22548
22548
|
exports.json = bodyParser.json;
|
|
22549
22549
|
exports.query = require_query();
|
|
22550
22550
|
exports.raw = bodyParser.raw;
|
|
@@ -23179,10 +23179,10 @@ var init_open = __esm({
|
|
|
23179
23179
|
});
|
|
23180
23180
|
|
|
23181
23181
|
// src/server/index.ts
|
|
23182
|
-
var
|
|
23182
|
+
var import_express12 = __toESM(require_express2(), 1);
|
|
23183
23183
|
import { createServer } from "node:http";
|
|
23184
|
-
import { existsSync as
|
|
23185
|
-
import { join as
|
|
23184
|
+
import { existsSync as existsSync9, readFileSync as readFileSync10, writeFileSync as writeFileSync4, unlinkSync as unlinkSync2, mkdirSync as mkdirSync3 } from "node:fs";
|
|
23185
|
+
import { join as join13, 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";
|
|
@@ -24008,24 +24008,24 @@ function enrichSession(db, session) {
|
|
|
24008
24008
|
let reviewPhaseNumber = 0;
|
|
24009
24009
|
let reviewPhase = "";
|
|
24010
24010
|
if (hasReview) {
|
|
24011
|
+
const derived = deriveReviewPhase(db, session.id);
|
|
24011
24012
|
if (session.workflow_type === "review") {
|
|
24012
|
-
reviewPhaseNumber = session.phase_number;
|
|
24013
|
-
reviewPhase = session.current_phase;
|
|
24013
|
+
reviewPhaseNumber = Math.max(session.phase_number, derived);
|
|
24014
24014
|
} else {
|
|
24015
|
-
reviewPhaseNumber =
|
|
24016
|
-
reviewPhase = REVIEW_PHASE_NAMES[reviewPhaseNumber - 1] ?? "context";
|
|
24015
|
+
reviewPhaseNumber = derived;
|
|
24017
24016
|
}
|
|
24017
|
+
reviewPhase = REVIEW_PHASE_NAMES[reviewPhaseNumber - 1] ?? "context";
|
|
24018
24018
|
}
|
|
24019
24019
|
let mapPhaseNumber = 0;
|
|
24020
24020
|
let mapPhase = "";
|
|
24021
24021
|
if (hasMap) {
|
|
24022
|
+
const derived = deriveMapPhase(db, session.id);
|
|
24022
24023
|
if (session.workflow_type === "map") {
|
|
24023
|
-
mapPhaseNumber = session.phase_number;
|
|
24024
|
-
mapPhase = session.current_phase;
|
|
24024
|
+
mapPhaseNumber = Math.max(session.phase_number, derived);
|
|
24025
24025
|
} else {
|
|
24026
|
-
mapPhaseNumber =
|
|
24027
|
-
mapPhase = MAP_PHASE_NAMES[mapPhaseNumber - 1] ?? "map-context";
|
|
24026
|
+
mapPhaseNumber = derived;
|
|
24028
24027
|
}
|
|
24028
|
+
mapPhase = MAP_PHASE_NAMES[mapPhaseNumber - 1] ?? "map-context";
|
|
24029
24029
|
}
|
|
24030
24030
|
const latestRound = rounds.length > 0 ? rounds[rounds.length - 1] : null;
|
|
24031
24031
|
const latestVerdict = latestRound?.verdict ?? null;
|
|
@@ -25112,18 +25112,16 @@ var AiCliService = class {
|
|
|
25112
25112
|
active: this.activeAdapter?.binary ?? null,
|
|
25113
25113
|
preferred: this.preference
|
|
25114
25114
|
};
|
|
25115
|
-
|
|
25116
|
-
|
|
25117
|
-
|
|
25118
|
-
console.log(` AI CLI: ${adapter.name} v${detection.version ?? "?"} detected`);
|
|
25119
|
-
}
|
|
25115
|
+
const detected = this.entries.filter((e) => e.detection.found).map((e) => `${e.adapter.name} v${e.detection.version ?? "?"}`);
|
|
25116
|
+
if (detected.length > 0) {
|
|
25117
|
+
console.log(` AI CLI detected: ${detected.join(", ")}`);
|
|
25120
25118
|
}
|
|
25121
25119
|
if (this.preference === "off") {
|
|
25122
|
-
console.log(" AI CLI
|
|
25120
|
+
console.log(" AI CLI active: off (read-only mode)");
|
|
25123
25121
|
} else if (this.activeAdapter) {
|
|
25124
|
-
console.log(` AI CLI:
|
|
25122
|
+
console.log(` AI CLI active: ${this.activeAdapter.name} (${this.preference})`);
|
|
25125
25123
|
} else {
|
|
25126
|
-
console.log(" AI CLI:
|
|
25124
|
+
console.log(" AI CLI active: none (read-only mode)");
|
|
25127
25125
|
}
|
|
25128
25126
|
}
|
|
25129
25127
|
/** Returns the status object for the /api/config endpoint. */
|
|
@@ -25190,11 +25188,37 @@ function resolveLocalCli() {
|
|
|
25190
25188
|
}
|
|
25191
25189
|
|
|
25192
25190
|
// src/server/socket/command-runner.ts
|
|
25191
|
+
function shellSplit(str) {
|
|
25192
|
+
const tokens = [];
|
|
25193
|
+
let current = "";
|
|
25194
|
+
let quote = null;
|
|
25195
|
+
for (let i = 0; i < str.length; i++) {
|
|
25196
|
+
const ch = str[i];
|
|
25197
|
+
if (quote) {
|
|
25198
|
+
if (ch === quote) {
|
|
25199
|
+
quote = null;
|
|
25200
|
+
} else {
|
|
25201
|
+
current += ch;
|
|
25202
|
+
}
|
|
25203
|
+
} else if (ch === '"' || ch === "'") {
|
|
25204
|
+
quote = ch;
|
|
25205
|
+
} else if (/\s/.test(ch)) {
|
|
25206
|
+
if (current) {
|
|
25207
|
+
tokens.push(current);
|
|
25208
|
+
current = "";
|
|
25209
|
+
}
|
|
25210
|
+
} else {
|
|
25211
|
+
current += ch;
|
|
25212
|
+
}
|
|
25213
|
+
}
|
|
25214
|
+
if (current) tokens.push(current);
|
|
25215
|
+
return tokens;
|
|
25216
|
+
}
|
|
25193
25217
|
var ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
25194
25218
|
"progress",
|
|
25195
25219
|
"state"
|
|
25196
25220
|
]);
|
|
25197
|
-
var AI_COMMANDS = /* @__PURE__ */ new Set(["map", "review", "translate-review-to-single-human", "address"]);
|
|
25221
|
+
var AI_COMMANDS = /* @__PURE__ */ new Set(["map", "review", "translate-review-to-single-human", "address", "create-reviewer", "sync-reviewers"]);
|
|
25198
25222
|
var MAX_CONCURRENT = 3;
|
|
25199
25223
|
var activeCommands = /* @__PURE__ */ new Map();
|
|
25200
25224
|
function getActiveCommands() {
|
|
@@ -25216,7 +25240,7 @@ function registerCommandHandlers(io2, socket, db, ocrDir, aiCliService) {
|
|
|
25216
25240
|
}
|
|
25217
25241
|
const { command } = payload;
|
|
25218
25242
|
const normalized = command.replace(/^ocr\s+/, "");
|
|
25219
|
-
const parts = normalized
|
|
25243
|
+
const parts = shellSplit(normalized);
|
|
25220
25244
|
const baseCommand = parts[0] ?? "";
|
|
25221
25245
|
const subArgs = parts.slice(1);
|
|
25222
25246
|
if (!ALLOWED_COMMANDS.has(baseCommand) && !AI_COMMANDS.has(baseCommand)) {
|
|
@@ -25373,34 +25397,68 @@ function spawnAiCommand(io2, _socket, db, ocrDir, executionId, baseCommand, subA
|
|
|
25373
25397
|
finishExecution(io2, db, ocrDir, executionId, 1, content);
|
|
25374
25398
|
return;
|
|
25375
25399
|
}
|
|
25376
|
-
|
|
25377
|
-
|
|
25378
|
-
|
|
25379
|
-
|
|
25380
|
-
|
|
25381
|
-
|
|
25382
|
-
|
|
25383
|
-
|
|
25384
|
-
|
|
25385
|
-
|
|
25386
|
-
|
|
25387
|
-
|
|
25388
|
-
|
|
25389
|
-
|
|
25390
|
-
|
|
25391
|
-
|
|
25392
|
-
i
|
|
25400
|
+
const promptLines = [];
|
|
25401
|
+
if (baseCommand === "create-reviewer" || baseCommand === "sync-reviewers") {
|
|
25402
|
+
const argsStr = subArgs.length > 0 ? subArgs.join(" ") : "";
|
|
25403
|
+
promptLines.push(
|
|
25404
|
+
`Follow the instructions below to run the OCR ${baseCommand} workflow.`,
|
|
25405
|
+
"",
|
|
25406
|
+
`Arguments: ${argsStr || "none"}`
|
|
25407
|
+
);
|
|
25408
|
+
} else {
|
|
25409
|
+
let target = "staged changes";
|
|
25410
|
+
let requirements = "";
|
|
25411
|
+
let team = "";
|
|
25412
|
+
const reviewerDescriptions = [];
|
|
25413
|
+
const options = [];
|
|
25414
|
+
let i = 0;
|
|
25415
|
+
while (i < subArgs.length) {
|
|
25416
|
+
const arg = subArgs[i] ?? "";
|
|
25417
|
+
if (arg === "--fresh") {
|
|
25418
|
+
options.push("--fresh");
|
|
25419
|
+
i++;
|
|
25420
|
+
} else if (arg === "--requirements" && i + 1 < subArgs.length) {
|
|
25421
|
+
requirements = subArgs.slice(i + 1).join(" ");
|
|
25422
|
+
break;
|
|
25423
|
+
} else if (arg === "--team" && i + 1 < subArgs.length) {
|
|
25424
|
+
team = subArgs[i + 1] ?? "";
|
|
25425
|
+
i += 2;
|
|
25426
|
+
} else if (arg === "--reviewer" && i + 1 < subArgs.length) {
|
|
25427
|
+
const raw = subArgs[i + 1] ?? "";
|
|
25428
|
+
const countMatch = raw.match(/^(\d+):(.+)$/);
|
|
25429
|
+
if (countMatch) {
|
|
25430
|
+
reviewerDescriptions.push({ description: countMatch[2], count: parseInt(countMatch[1], 10) });
|
|
25431
|
+
} else {
|
|
25432
|
+
reviewerDescriptions.push({ description: raw, count: 1 });
|
|
25433
|
+
}
|
|
25434
|
+
i += 2;
|
|
25435
|
+
} else if (!arg.startsWith("--")) {
|
|
25436
|
+
target = arg;
|
|
25437
|
+
i++;
|
|
25438
|
+
} else {
|
|
25439
|
+
i++;
|
|
25440
|
+
}
|
|
25441
|
+
}
|
|
25442
|
+
const optionsStr = options.length > 0 ? options.join(" ") : "none";
|
|
25443
|
+
promptLines.push(
|
|
25444
|
+
`Follow the instructions below to run the OCR ${baseCommand} workflow.`,
|
|
25445
|
+
"",
|
|
25446
|
+
`Target: ${target}`,
|
|
25447
|
+
`Options: ${optionsStr}`
|
|
25448
|
+
);
|
|
25449
|
+
if (team) {
|
|
25450
|
+
promptLines.push(`Team: ${team}`);
|
|
25451
|
+
}
|
|
25452
|
+
for (const { description, count } of reviewerDescriptions) {
|
|
25453
|
+
if (count > 1) {
|
|
25454
|
+
promptLines.push(`Reviewer (x${count}): ${description}`);
|
|
25455
|
+
} else {
|
|
25456
|
+
promptLines.push(`Reviewer: ${description}`);
|
|
25457
|
+
}
|
|
25458
|
+
}
|
|
25459
|
+
if (requirements) {
|
|
25460
|
+
promptLines.push(`Requirements: ${requirements}`);
|
|
25393
25461
|
}
|
|
25394
|
-
}
|
|
25395
|
-
const optionsStr = options.length > 0 ? options.join(" ") : "none";
|
|
25396
|
-
const promptLines = [
|
|
25397
|
-
`Follow the instructions below to run the OCR ${baseCommand} workflow.`,
|
|
25398
|
-
"",
|
|
25399
|
-
`Target: ${target}`,
|
|
25400
|
-
`Options: ${optionsStr}`
|
|
25401
|
-
];
|
|
25402
|
-
if (requirements) {
|
|
25403
|
-
promptLines.push(`Requirements: ${requirements}`);
|
|
25404
25462
|
}
|
|
25405
25463
|
const localCli = resolveLocalCli();
|
|
25406
25464
|
if (localCli) {
|
|
@@ -25768,10 +25826,77 @@ function createChatRouter(db, ocrDir) {
|
|
|
25768
25826
|
return router;
|
|
25769
25827
|
}
|
|
25770
25828
|
|
|
25829
|
+
// src/server/routes/reviewers.ts
|
|
25830
|
+
var import_express11 = __toESM(require_express2(), 1);
|
|
25831
|
+
import { readFileSync as readFileSync5, existsSync as existsSync4, watch } from "node:fs";
|
|
25832
|
+
import { join as join9 } from "node:path";
|
|
25833
|
+
function readReviewersMeta(ocrDir) {
|
|
25834
|
+
const metaPath = join9(ocrDir, "reviewers-meta.json");
|
|
25835
|
+
if (!existsSync4(metaPath)) {
|
|
25836
|
+
return { reviewers: [], defaults: [] };
|
|
25837
|
+
}
|
|
25838
|
+
try {
|
|
25839
|
+
const raw = readFileSync5(metaPath, "utf-8");
|
|
25840
|
+
const meta = JSON.parse(raw);
|
|
25841
|
+
const reviewers = meta.reviewers ?? [];
|
|
25842
|
+
const defaults = reviewers.filter((r) => r.is_default).map((r) => r.id);
|
|
25843
|
+
return { reviewers, defaults };
|
|
25844
|
+
} catch {
|
|
25845
|
+
return { reviewers: [], defaults: [] };
|
|
25846
|
+
}
|
|
25847
|
+
}
|
|
25848
|
+
var VALID_ID_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
25849
|
+
function createReviewersRouter(ocrDir) {
|
|
25850
|
+
const router = (0, import_express11.Router)();
|
|
25851
|
+
router.get("/", (_req, res) => {
|
|
25852
|
+
res.json(readReviewersMeta(ocrDir));
|
|
25853
|
+
});
|
|
25854
|
+
router.get("/:id/prompt", (req, res) => {
|
|
25855
|
+
const { id } = req.params;
|
|
25856
|
+
if (!id || !VALID_ID_RE.test(id)) {
|
|
25857
|
+
res.status(400).json({ error: "Invalid reviewer ID" });
|
|
25858
|
+
return;
|
|
25859
|
+
}
|
|
25860
|
+
const filePath = join9(ocrDir, "skills", "references", "reviewers", `${id}.md`);
|
|
25861
|
+
if (!existsSync4(filePath)) {
|
|
25862
|
+
res.status(404).json({ error: "Reviewer not found", id });
|
|
25863
|
+
return;
|
|
25864
|
+
}
|
|
25865
|
+
try {
|
|
25866
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
25867
|
+
res.json({ id, content });
|
|
25868
|
+
} catch {
|
|
25869
|
+
res.status(500).json({ error: "Failed to read reviewer file", id });
|
|
25870
|
+
}
|
|
25871
|
+
});
|
|
25872
|
+
return router;
|
|
25873
|
+
}
|
|
25874
|
+
function watchReviewersMeta(ocrDir, io2) {
|
|
25875
|
+
const metaPath = join9(ocrDir, "reviewers-meta.json");
|
|
25876
|
+
let watcher = null;
|
|
25877
|
+
let debounce;
|
|
25878
|
+
try {
|
|
25879
|
+
watcher = watch(metaPath, () => {
|
|
25880
|
+
clearTimeout(debounce);
|
|
25881
|
+
debounce = setTimeout(() => {
|
|
25882
|
+
const data = readReviewersMeta(ocrDir);
|
|
25883
|
+
io2.emit("reviewers:updated", data);
|
|
25884
|
+
}, 200);
|
|
25885
|
+
});
|
|
25886
|
+
watcher.on("error", () => {
|
|
25887
|
+
});
|
|
25888
|
+
} catch {
|
|
25889
|
+
}
|
|
25890
|
+
return () => {
|
|
25891
|
+
clearTimeout(debounce);
|
|
25892
|
+
watcher?.close();
|
|
25893
|
+
};
|
|
25894
|
+
}
|
|
25895
|
+
|
|
25771
25896
|
// src/server/services/filesystem-sync.ts
|
|
25772
|
-
import { readdirSync, readFileSync as
|
|
25773
|
-
import { join as
|
|
25774
|
-
import { watch } from "chokidar";
|
|
25897
|
+
import { readdirSync, readFileSync as readFileSync6, statSync, existsSync as existsSync5 } from "node:fs";
|
|
25898
|
+
import { join as join10, basename as basename2, dirname as dirname7, relative } from "node:path";
|
|
25899
|
+
import { watch as watch2 } from "chokidar";
|
|
25775
25900
|
|
|
25776
25901
|
// src/server/services/parsers/reviewer-parser.ts
|
|
25777
25902
|
var FINDING_HEADING_RE = /^#{2,3}\s+(?:Finding|Issue|Suggestion)\s*(?:\d+)?\s*[:\s]*\s*(.*)/i;
|
|
@@ -25952,67 +26077,67 @@ var FilesystemSync = class {
|
|
|
25952
26077
|
onSync;
|
|
25953
26078
|
// ── 6.1: Full Scan ──
|
|
25954
26079
|
async fullScan() {
|
|
25955
|
-
if (!
|
|
26080
|
+
if (!existsSync5(this.sessionsDir)) return;
|
|
25956
26081
|
const entries = readdirSync(this.sessionsDir, { withFileTypes: true });
|
|
25957
26082
|
for (const entry of entries) {
|
|
25958
26083
|
if (!entry.isDirectory()) continue;
|
|
25959
26084
|
const sessionId = entry.name;
|
|
25960
|
-
const sessionDir =
|
|
26085
|
+
const sessionDir = join10(this.sessionsDir, sessionId);
|
|
25961
26086
|
this.syncSession(sessionId, sessionDir);
|
|
25962
26087
|
}
|
|
25963
26088
|
}
|
|
25964
26089
|
syncSession(sessionId, sessionDir) {
|
|
25965
26090
|
this.ensureSessionRow(sessionId, sessionDir);
|
|
25966
|
-
const roundsDir =
|
|
25967
|
-
if (
|
|
26091
|
+
const roundsDir = join10(sessionDir, "rounds");
|
|
26092
|
+
if (existsSync5(roundsDir)) {
|
|
25968
26093
|
const rounds = readdirSync(roundsDir, { withFileTypes: true });
|
|
25969
26094
|
for (const roundEntry of rounds) {
|
|
25970
26095
|
if (!roundEntry.isDirectory()) continue;
|
|
25971
26096
|
const roundMatch = roundEntry.name.match(/^round-(\d+)$/);
|
|
25972
26097
|
if (!roundMatch) continue;
|
|
25973
26098
|
const roundNumber = parseInt(roundMatch[1] ?? "0", 10);
|
|
25974
|
-
const roundDir =
|
|
25975
|
-
const reviewsDir =
|
|
25976
|
-
if (
|
|
26099
|
+
const roundDir = join10(roundsDir, roundEntry.name);
|
|
26100
|
+
const reviewsDir = join10(roundDir, "reviews");
|
|
26101
|
+
if (existsSync5(reviewsDir)) {
|
|
25977
26102
|
const reviewFiles = readdirSync(reviewsDir).filter((f) => f.endsWith(".md"));
|
|
25978
26103
|
for (const reviewFile of reviewFiles) {
|
|
25979
|
-
const filePath =
|
|
26104
|
+
const filePath = join10(reviewsDir, reviewFile);
|
|
25980
26105
|
this.processReviewerOutput(sessionId, roundNumber, filePath, reviewFile);
|
|
25981
26106
|
}
|
|
25982
26107
|
}
|
|
25983
|
-
const roundMetaPath =
|
|
25984
|
-
if (
|
|
26108
|
+
const roundMetaPath = join10(roundDir, "round-meta.json");
|
|
26109
|
+
if (existsSync5(roundMetaPath)) {
|
|
25985
26110
|
this.processRoundMeta(sessionId, roundNumber, roundMetaPath);
|
|
25986
26111
|
}
|
|
25987
|
-
const finalPath =
|
|
25988
|
-
if (
|
|
26112
|
+
const finalPath = join10(roundDir, "final.md");
|
|
26113
|
+
if (existsSync5(finalPath)) {
|
|
25989
26114
|
this.processFinalMd(sessionId, roundNumber, finalPath);
|
|
25990
26115
|
}
|
|
25991
|
-
const finalHumanPath =
|
|
25992
|
-
if (
|
|
26116
|
+
const finalHumanPath = join10(roundDir, "final-human.md");
|
|
26117
|
+
if (existsSync5(finalHumanPath)) {
|
|
25993
26118
|
this.processGenericArtifact(sessionId, "final-human", finalHumanPath, roundNumber);
|
|
25994
26119
|
}
|
|
25995
|
-
const discoursePath =
|
|
25996
|
-
if (
|
|
26120
|
+
const discoursePath = join10(roundDir, "discourse.md");
|
|
26121
|
+
if (existsSync5(discoursePath)) {
|
|
25997
26122
|
this.processGenericArtifact(sessionId, "discourse", discoursePath, roundNumber);
|
|
25998
26123
|
}
|
|
25999
26124
|
}
|
|
26000
26125
|
}
|
|
26001
|
-
const mapDir =
|
|
26002
|
-
if (
|
|
26126
|
+
const mapDir = join10(sessionDir, "map", "runs");
|
|
26127
|
+
if (existsSync5(mapDir)) {
|
|
26003
26128
|
const runs = readdirSync(mapDir, { withFileTypes: true });
|
|
26004
26129
|
for (const runEntry of runs) {
|
|
26005
26130
|
if (!runEntry.isDirectory()) continue;
|
|
26006
26131
|
const runMatch = runEntry.name.match(/^run-(\d+)$/);
|
|
26007
26132
|
if (!runMatch) continue;
|
|
26008
26133
|
const runNumber = parseInt(runMatch[1] ?? "0", 10);
|
|
26009
|
-
const runDir =
|
|
26010
|
-
const mapMetaPath =
|
|
26011
|
-
if (
|
|
26134
|
+
const runDir = join10(mapDir, runEntry.name);
|
|
26135
|
+
const mapMetaPath = join10(runDir, "map-meta.json");
|
|
26136
|
+
if (existsSync5(mapMetaPath)) {
|
|
26012
26137
|
this.processMapMeta(sessionId, runNumber, mapMetaPath);
|
|
26013
26138
|
}
|
|
26014
|
-
const mapPath =
|
|
26015
|
-
if (
|
|
26139
|
+
const mapPath = join10(runDir, "map.md");
|
|
26140
|
+
if (existsSync5(mapPath)) {
|
|
26016
26141
|
this.processMapMd(sessionId, runNumber, mapPath);
|
|
26017
26142
|
}
|
|
26018
26143
|
const mapArtifacts = [
|
|
@@ -26021,8 +26146,8 @@ var FilesystemSync = class {
|
|
|
26021
26146
|
["requirements-mapping.md", "requirements-mapping"]
|
|
26022
26147
|
];
|
|
26023
26148
|
for (const [fileName, artifactType] of mapArtifacts) {
|
|
26024
|
-
const filePath =
|
|
26025
|
-
if (
|
|
26149
|
+
const filePath = join10(runDir, fileName);
|
|
26150
|
+
if (existsSync5(filePath)) {
|
|
26026
26151
|
this.processGenericArtifact(sessionId, artifactType, filePath, void 0, runNumber);
|
|
26027
26152
|
}
|
|
26028
26153
|
}
|
|
@@ -26033,8 +26158,8 @@ var FilesystemSync = class {
|
|
|
26033
26158
|
["discovered-standards.md", "discovered-standards"]
|
|
26034
26159
|
];
|
|
26035
26160
|
for (const [fileName, artifactType] of sessionArtifacts) {
|
|
26036
|
-
const filePath =
|
|
26037
|
-
if (
|
|
26161
|
+
const filePath = join10(sessionDir, fileName);
|
|
26162
|
+
if (existsSync5(filePath)) {
|
|
26038
26163
|
this.processGenericArtifact(sessionId, artifactType, filePath);
|
|
26039
26164
|
}
|
|
26040
26165
|
}
|
|
@@ -26043,17 +26168,17 @@ var FilesystemSync = class {
|
|
|
26043
26168
|
ensureSessionRow(sessionId, sessionDir) {
|
|
26044
26169
|
const branchMatch = sessionId.match(/^\d{4}-\d{2}-\d{2}-(.+)$/);
|
|
26045
26170
|
const branch = branchMatch?.[1] ?? "unknown";
|
|
26046
|
-
const hasRoundsDir =
|
|
26047
|
-
const hasMapDir =
|
|
26171
|
+
const hasRoundsDir = existsSync5(join10(sessionDir, "rounds"));
|
|
26172
|
+
const hasMapDir = existsSync5(join10(sessionDir, "map"));
|
|
26048
26173
|
const workflowType = hasMapDir && !hasRoundsDir ? "map" : "review";
|
|
26049
26174
|
let currentRound = 1;
|
|
26050
26175
|
if (hasRoundsDir) {
|
|
26051
|
-
const roundDirs = readdirSync(
|
|
26176
|
+
const roundDirs = readdirSync(join10(sessionDir, "rounds")).filter((d) => d.match(/^round-\d+$/));
|
|
26052
26177
|
currentRound = Math.max(1, roundDirs.length);
|
|
26053
26178
|
}
|
|
26054
26179
|
let currentMapRun = 1;
|
|
26055
|
-
const mapRunsDir =
|
|
26056
|
-
if (
|
|
26180
|
+
const mapRunsDir = join10(sessionDir, "map", "runs");
|
|
26181
|
+
if (existsSync5(mapRunsDir)) {
|
|
26057
26182
|
const runDirs = readdirSync(mapRunsDir).filter((d) => d.match(/^run-\d+$/));
|
|
26058
26183
|
currentMapRun = Math.max(1, runDirs.length);
|
|
26059
26184
|
}
|
|
@@ -26061,40 +26186,40 @@ var FilesystemSync = class {
|
|
|
26061
26186
|
let phaseNumber = 1;
|
|
26062
26187
|
let status = "active";
|
|
26063
26188
|
if (workflowType === "review" && hasRoundsDir) {
|
|
26064
|
-
const roundDir =
|
|
26065
|
-
if (
|
|
26189
|
+
const roundDir = join10(sessionDir, "rounds", `round-${currentRound}`);
|
|
26190
|
+
if (existsSync5(join10(roundDir, "final.md"))) {
|
|
26066
26191
|
phase = "complete";
|
|
26067
26192
|
phaseNumber = 8;
|
|
26068
26193
|
status = "closed";
|
|
26069
|
-
} else if (
|
|
26194
|
+
} else if (existsSync5(join10(roundDir, "discourse.md"))) {
|
|
26070
26195
|
phase = "synthesis";
|
|
26071
26196
|
phaseNumber = 7;
|
|
26072
|
-
} else if (
|
|
26197
|
+
} else if (existsSync5(join10(roundDir, "reviews")) && readdirSync(join10(roundDir, "reviews")).filter((f) => f.endsWith(".md")).length > 0) {
|
|
26073
26198
|
phase = "reviews";
|
|
26074
26199
|
phaseNumber = 4;
|
|
26075
|
-
} else if (
|
|
26200
|
+
} else if (existsSync5(join10(sessionDir, "context.md"))) {
|
|
26076
26201
|
phase = "analysis";
|
|
26077
26202
|
phaseNumber = 3;
|
|
26078
|
-
} else if (
|
|
26203
|
+
} else if (existsSync5(join10(sessionDir, "discovered-standards.md"))) {
|
|
26079
26204
|
phase = "change-context";
|
|
26080
26205
|
phaseNumber = 2;
|
|
26081
26206
|
}
|
|
26082
26207
|
} else if (workflowType === "map" && hasMapDir) {
|
|
26083
|
-
const runDir =
|
|
26084
|
-
if (
|
|
26208
|
+
const runDir = join10(mapRunsDir, `run-${currentMapRun}`);
|
|
26209
|
+
if (existsSync5(join10(runDir, "map.md"))) {
|
|
26085
26210
|
phase = "complete";
|
|
26086
26211
|
phaseNumber = 6;
|
|
26087
26212
|
status = "closed";
|
|
26088
|
-
} else if (
|
|
26213
|
+
} else if (existsSync5(join10(runDir, "requirements-mapping.md"))) {
|
|
26089
26214
|
phase = "synthesis";
|
|
26090
26215
|
phaseNumber = 5;
|
|
26091
|
-
} else if (
|
|
26216
|
+
} else if (existsSync5(join10(runDir, "flow-analysis.md"))) {
|
|
26092
26217
|
phase = "requirements-mapping";
|
|
26093
26218
|
phaseNumber = 4;
|
|
26094
|
-
} else if (
|
|
26219
|
+
} else if (existsSync5(join10(runDir, "topology.md"))) {
|
|
26095
26220
|
phase = "flow-analysis";
|
|
26096
26221
|
phaseNumber = 3;
|
|
26097
|
-
} else if (
|
|
26222
|
+
} else if (existsSync5(join10(sessionDir, "discovered-standards.md"))) {
|
|
26098
26223
|
phase = "topology";
|
|
26099
26224
|
phaseNumber = 2;
|
|
26100
26225
|
}
|
|
@@ -26157,12 +26282,12 @@ var FilesystemSync = class {
|
|
|
26157
26282
|
);
|
|
26158
26283
|
if (existingRun && this.shouldSkip(filePath, existingRun["parsed_at"] ?? null)) return;
|
|
26159
26284
|
if (existingRun?.["source"] === "orchestrator") {
|
|
26160
|
-
const content2 =
|
|
26285
|
+
const content2 = readFileSync6(filePath, "utf-8");
|
|
26161
26286
|
const action2 = this.upsertMarkdownArtifact(sessionId, "map", filePath, content2, void 0);
|
|
26162
26287
|
this.emitArtifactEvent(action2, { sessionId, artifactType: "map", filePath });
|
|
26163
26288
|
return;
|
|
26164
26289
|
}
|
|
26165
|
-
const content =
|
|
26290
|
+
const content = readFileSync6(filePath, "utf-8");
|
|
26166
26291
|
const parsed = parseMapMd(content);
|
|
26167
26292
|
this.db.run(
|
|
26168
26293
|
`INSERT OR REPLACE INTO map_runs (session_id, run_number, file_count, map_md_path, parsed_at, source)
|
|
@@ -26244,10 +26369,10 @@ var FilesystemSync = class {
|
|
|
26244
26369
|
}
|
|
26245
26370
|
const session = queryFirst(
|
|
26246
26371
|
this.db,
|
|
26247
|
-
"SELECT current_phase, workflow_type FROM sessions WHERE id = ?",
|
|
26372
|
+
"SELECT current_phase, phase_number, workflow_type FROM sessions WHERE id = ?",
|
|
26248
26373
|
[sessionId]
|
|
26249
26374
|
);
|
|
26250
|
-
if (session && session["workflow_type"] === "map" && session["current_phase"] !== "complete") {
|
|
26375
|
+
if (session && session["workflow_type"] === "map" && (session["current_phase"] !== "complete" || session["phase_number"] < 6)) {
|
|
26251
26376
|
this.db.run(
|
|
26252
26377
|
`UPDATE sessions SET current_phase = 'complete', phase_number = 6, status = 'closed', updated_at = datetime('now')
|
|
26253
26378
|
WHERE id = ?`,
|
|
@@ -26282,7 +26407,7 @@ var FilesystemSync = class {
|
|
|
26282
26407
|
const roundId = roundRow?.["id"];
|
|
26283
26408
|
if (!roundId) return;
|
|
26284
26409
|
if (roundRow?.["source"] === "orchestrator") {
|
|
26285
|
-
const content2 =
|
|
26410
|
+
const content2 = readFileSync6(filePath, "utf-8");
|
|
26286
26411
|
const action2 = this.upsertMarkdownArtifact(sessionId, "reviewer-output", filePath, content2, roundNumber);
|
|
26287
26412
|
this.emitArtifactEvent(action2, {
|
|
26288
26413
|
sessionId,
|
|
@@ -26301,7 +26426,7 @@ var FilesystemSync = class {
|
|
|
26301
26426
|
[roundId, reviewerType, instanceNumber]
|
|
26302
26427
|
);
|
|
26303
26428
|
if (existingOutput && this.shouldSkip(filePath, existingOutput["parsed_at"] ?? null)) return;
|
|
26304
|
-
const content =
|
|
26429
|
+
const content = readFileSync6(filePath, "utf-8");
|
|
26305
26430
|
const parsed = parseReviewerOutput(content);
|
|
26306
26431
|
this.db.run(
|
|
26307
26432
|
`INSERT OR REPLACE INTO reviewer_outputs (round_id, reviewer_type, instance_number, file_path, finding_count, parsed_at)
|
|
@@ -26389,7 +26514,7 @@ var FilesystemSync = class {
|
|
|
26389
26514
|
if (existingRound?.["source"] === "orchestrator" && this.shouldSkip(filePath, existingRound["parsed_at"] ?? null)) return;
|
|
26390
26515
|
let raw;
|
|
26391
26516
|
try {
|
|
26392
|
-
raw = JSON.parse(
|
|
26517
|
+
raw = JSON.parse(readFileSync6(filePath, "utf-8"));
|
|
26393
26518
|
} catch {
|
|
26394
26519
|
console.error(`[FilesystemSync] Failed to parse ${filePath}`);
|
|
26395
26520
|
return;
|
|
@@ -26439,7 +26564,7 @@ var FilesystemSync = class {
|
|
|
26439
26564
|
const reviewerType = reviewer.type ?? "unknown";
|
|
26440
26565
|
const instanceNumber = reviewer.instance ?? 1;
|
|
26441
26566
|
const findings = reviewer.findings ?? [];
|
|
26442
|
-
const reviewerMdPath =
|
|
26567
|
+
const reviewerMdPath = join10(roundDir, "reviews", `${reviewerType}-${instanceNumber}.md`);
|
|
26443
26568
|
this.db.run(
|
|
26444
26569
|
`INSERT OR REPLACE INTO reviewer_outputs (round_id, reviewer_type, instance_number, file_path, finding_count, parsed_at)
|
|
26445
26570
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
@@ -26537,7 +26662,7 @@ var FilesystemSync = class {
|
|
|
26537
26662
|
if (existingRun?.["source"] === "orchestrator" && this.shouldSkip(filePath, existingRun["parsed_at"] ?? null)) return;
|
|
26538
26663
|
let raw;
|
|
26539
26664
|
try {
|
|
26540
|
-
raw = JSON.parse(
|
|
26665
|
+
raw = JSON.parse(readFileSync6(filePath, "utf-8"));
|
|
26541
26666
|
} catch {
|
|
26542
26667
|
console.error(`[FilesystemSync] Failed to parse ${filePath}`);
|
|
26543
26668
|
return;
|
|
@@ -26665,7 +26790,7 @@ var FilesystemSync = class {
|
|
|
26665
26790
|
);
|
|
26666
26791
|
const isOrchestratorSource = existingRound?.["source"] === "orchestrator";
|
|
26667
26792
|
if (!isOrchestratorSource && existingRound && this.shouldSkip(filePath, existingRound["parsed_at"] ?? null)) return;
|
|
26668
|
-
const content =
|
|
26793
|
+
const content = readFileSync6(filePath, "utf-8");
|
|
26669
26794
|
if (isOrchestratorSource) {
|
|
26670
26795
|
this.db.run(
|
|
26671
26796
|
`UPDATE review_rounds SET final_md_path = ?, parsed_at = ?
|
|
@@ -26708,7 +26833,7 @@ var FilesystemSync = class {
|
|
|
26708
26833
|
"SELECT current_phase, phase_number, status FROM sessions WHERE id = ?",
|
|
26709
26834
|
[sessionId]
|
|
26710
26835
|
);
|
|
26711
|
-
if (session && session["current_phase"] !== "complete") {
|
|
26836
|
+
if (session && (session["current_phase"] !== "complete" || session["phase_number"] < 8)) {
|
|
26712
26837
|
this.db.run(
|
|
26713
26838
|
`UPDATE sessions SET current_phase = 'complete', phase_number = 8, status = 'closed', updated_at = datetime('now')
|
|
26714
26839
|
WHERE id = ?`,
|
|
@@ -26738,7 +26863,7 @@ var FilesystemSync = class {
|
|
|
26738
26863
|
[sessionId, artifactType, relPath]
|
|
26739
26864
|
);
|
|
26740
26865
|
if (existing && this.shouldSkip(filePath, existing["parsed_at"] ?? null)) return;
|
|
26741
|
-
const content =
|
|
26866
|
+
const content = readFileSync6(filePath, "utf-8");
|
|
26742
26867
|
const action = this.upsertMarkdownArtifact(sessionId, artifactType, filePath, content, roundNumber);
|
|
26743
26868
|
this.emitArtifactEvent(action, {
|
|
26744
26869
|
sessionId,
|
|
@@ -26750,7 +26875,7 @@ var FilesystemSync = class {
|
|
|
26750
26875
|
// ── 6.6: Chokidar Watcher ──
|
|
26751
26876
|
startWatching() {
|
|
26752
26877
|
if (this.watcher) return;
|
|
26753
|
-
this.watcher =
|
|
26878
|
+
this.watcher = watch2(this.sessionsDir, {
|
|
26754
26879
|
persistent: true,
|
|
26755
26880
|
ignoreInitial: true,
|
|
26756
26881
|
depth: 10,
|
|
@@ -26797,7 +26922,7 @@ var FilesystemSync = class {
|
|
|
26797
26922
|
const parts = relFromSessions.split("/");
|
|
26798
26923
|
const sessionId = parts[0];
|
|
26799
26924
|
if (!sessionId) return;
|
|
26800
|
-
const sessionDir =
|
|
26925
|
+
const sessionDir = join10(this.sessionsDir, sessionId);
|
|
26801
26926
|
this.ensureSessionRow(sessionId, sessionDir);
|
|
26802
26927
|
const fileName = basename2(filePath);
|
|
26803
26928
|
const reviewerMatch = relFromSessions.match(/rounds\/round-(\d+)\/reviews\/(.+\.md)$/);
|
|
@@ -26869,8 +26994,8 @@ var FilesystemSync = class {
|
|
|
26869
26994
|
};
|
|
26870
26995
|
|
|
26871
26996
|
// src/server/services/db-sync-watcher.ts
|
|
26872
|
-
import { existsSync as
|
|
26873
|
-
import { watch as
|
|
26997
|
+
import { existsSync as existsSync6, readFileSync as readFileSync7, statSync as statSync2 } from "node:fs";
|
|
26998
|
+
import { watch as watch3 } from "chokidar";
|
|
26874
26999
|
import initSqlJs3 from "sql.js";
|
|
26875
27000
|
function col(row, key) {
|
|
26876
27001
|
return row[key] ?? null;
|
|
@@ -26891,7 +27016,7 @@ var DbSyncWatcher = class {
|
|
|
26891
27016
|
* Initialize the WASM runtime (called once at startup).
|
|
26892
27017
|
*/
|
|
26893
27018
|
async init() {
|
|
26894
|
-
const wasmBuffer =
|
|
27019
|
+
const wasmBuffer = readFileSync7(locateWasm());
|
|
26895
27020
|
this.wasmBinary = wasmBuffer.buffer.slice(
|
|
26896
27021
|
wasmBuffer.byteOffset,
|
|
26897
27022
|
wasmBuffer.byteOffset + wasmBuffer.byteLength
|
|
@@ -26902,12 +27027,12 @@ var DbSyncWatcher = class {
|
|
|
26902
27027
|
* Start watching the DB file for external changes.
|
|
26903
27028
|
*/
|
|
26904
27029
|
startWatching() {
|
|
26905
|
-
if (!
|
|
27030
|
+
if (!existsSync6(this.dbFilePath)) return;
|
|
26906
27031
|
try {
|
|
26907
27032
|
this.lastMtime = statSync2(this.dbFilePath).mtimeMs;
|
|
26908
27033
|
} catch {
|
|
26909
27034
|
}
|
|
26910
|
-
this.watcher =
|
|
27035
|
+
this.watcher = watch3(this.dbFilePath, {
|
|
26911
27036
|
// Also watch WAL/SHM files that SQLite may create
|
|
26912
27037
|
persistent: true,
|
|
26913
27038
|
ignoreInitial: true,
|
|
@@ -26953,7 +27078,7 @@ var DbSyncWatcher = class {
|
|
|
26953
27078
|
* to avoid overwriting CLI changes.
|
|
26954
27079
|
*/
|
|
26955
27080
|
syncFromDisk() {
|
|
26956
|
-
if (!this.SQL || !
|
|
27081
|
+
if (!this.SQL || !existsSync6(this.dbFilePath)) return;
|
|
26957
27082
|
let currentMtime;
|
|
26958
27083
|
try {
|
|
26959
27084
|
currentMtime = statSync2(this.dbFilePath).mtimeMs;
|
|
@@ -26964,7 +27089,7 @@ var DbSyncWatcher = class {
|
|
|
26964
27089
|
this.lastMtime = currentMtime;
|
|
26965
27090
|
let diskDb = null;
|
|
26966
27091
|
try {
|
|
26967
|
-
const fileBuffer =
|
|
27092
|
+
const fileBuffer = readFileSync7(this.dbFilePath);
|
|
26968
27093
|
diskDb = new this.SQL.Database(fileBuffer);
|
|
26969
27094
|
this.syncSessions(diskDb);
|
|
26970
27095
|
this.syncEvents(diskDb);
|
|
@@ -27221,17 +27346,17 @@ var DbSyncWatcher = class {
|
|
|
27221
27346
|
import { dirname as dirname8 } from "node:path";
|
|
27222
27347
|
|
|
27223
27348
|
// src/server/services/chat-context.ts
|
|
27224
|
-
import { readFileSync as
|
|
27225
|
-
import { join as
|
|
27349
|
+
import { readFileSync as readFileSync8, readdirSync as readdirSync2, existsSync as existsSync7 } from "node:fs";
|
|
27350
|
+
import { join as join11 } from "node:path";
|
|
27226
27351
|
function buildChatContext(ocrDir, target) {
|
|
27227
|
-
const sessionsDir =
|
|
27352
|
+
const sessionsDir = join11(ocrDir, "sessions");
|
|
27228
27353
|
if (target.type === "map_run") {
|
|
27229
27354
|
return buildMapRunContext(sessionsDir, target.sessionId, target.runNumber);
|
|
27230
27355
|
}
|
|
27231
27356
|
return buildReviewRoundContext(sessionsDir, target.sessionId, target.roundNumber);
|
|
27232
27357
|
}
|
|
27233
27358
|
function buildMapRunContext(sessionsDir, sessionId, runNumber) {
|
|
27234
|
-
const mapPath =
|
|
27359
|
+
const mapPath = join11(
|
|
27235
27360
|
sessionsDir,
|
|
27236
27361
|
sessionId,
|
|
27237
27362
|
"map",
|
|
@@ -27245,8 +27370,8 @@ function buildMapRunContext(sessionsDir, sessionId, runNumber) {
|
|
|
27245
27370
|
"",
|
|
27246
27371
|
`Below is the Code Review Map that organizes the changeset into reviewable sections:`
|
|
27247
27372
|
];
|
|
27248
|
-
if (
|
|
27249
|
-
const content =
|
|
27373
|
+
if (existsSync7(mapPath)) {
|
|
27374
|
+
const content = readFileSync8(mapPath, "utf-8");
|
|
27250
27375
|
parts.push("");
|
|
27251
27376
|
parts.push("<map>");
|
|
27252
27377
|
parts.push(content);
|
|
@@ -27258,26 +27383,26 @@ function buildMapRunContext(sessionsDir, sessionId, runNumber) {
|
|
|
27258
27383
|
return parts.join("\n");
|
|
27259
27384
|
}
|
|
27260
27385
|
function buildReviewRoundContext(sessionsDir, sessionId, roundNumber) {
|
|
27261
|
-
const roundDir =
|
|
27262
|
-
const finalPath =
|
|
27263
|
-
const reviewersDir =
|
|
27386
|
+
const roundDir = join11(sessionsDir, sessionId, "rounds", `round-${roundNumber}`);
|
|
27387
|
+
const finalPath = join11(roundDir, "final.md");
|
|
27388
|
+
const reviewersDir = join11(roundDir, "reviews");
|
|
27264
27389
|
const parts = [
|
|
27265
27390
|
`You are an expert code reviewer assisting with a code review session.`,
|
|
27266
27391
|
`You are looking at review round #${roundNumber} for session "${sessionId}".`,
|
|
27267
27392
|
"",
|
|
27268
27393
|
`Below are the review artifacts for this round:`
|
|
27269
27394
|
];
|
|
27270
|
-
if (
|
|
27271
|
-
const content =
|
|
27395
|
+
if (existsSync7(finalPath)) {
|
|
27396
|
+
const content = readFileSync8(finalPath, "utf-8");
|
|
27272
27397
|
parts.push("");
|
|
27273
27398
|
parts.push("<final-synthesis>");
|
|
27274
27399
|
parts.push(content);
|
|
27275
27400
|
parts.push("</final-synthesis>");
|
|
27276
27401
|
}
|
|
27277
|
-
if (
|
|
27402
|
+
if (existsSync7(reviewersDir)) {
|
|
27278
27403
|
const files = readdirSync2(reviewersDir).filter((f) => f.endsWith(".md")).sort();
|
|
27279
27404
|
for (const file of files) {
|
|
27280
|
-
const content =
|
|
27405
|
+
const content = readFileSync8(join11(reviewersDir, file), "utf-8");
|
|
27281
27406
|
const reviewerName = file.replace(/\.md$/, "");
|
|
27282
27407
|
parts.push("");
|
|
27283
27408
|
parts.push(`<reviewer name="${reviewerName}">`);
|
|
@@ -27285,7 +27410,7 @@ function buildReviewRoundContext(sessionsDir, sessionId, roundNumber) {
|
|
|
27285
27410
|
parts.push("</reviewer>");
|
|
27286
27411
|
}
|
|
27287
27412
|
}
|
|
27288
|
-
if (!
|
|
27413
|
+
if (!existsSync7(finalPath) && !existsSync7(reviewersDir)) {
|
|
27289
27414
|
parts.push("");
|
|
27290
27415
|
parts.push("(No review artifacts found on disk for this round.)");
|
|
27291
27416
|
}
|
|
@@ -27590,15 +27715,15 @@ function cleanupAllChats() {
|
|
|
27590
27715
|
|
|
27591
27716
|
// src/server/socket/post-handler.ts
|
|
27592
27717
|
import { execFile } from "node:child_process";
|
|
27593
|
-
import { existsSync as
|
|
27718
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync2, readFileSync as readFileSync9, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
27594
27719
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
27595
|
-
import { join as
|
|
27720
|
+
import { join as join12, dirname as dirname9, isAbsolute } from "node:path";
|
|
27596
27721
|
import { randomUUID } from "node:crypto";
|
|
27597
27722
|
import { promisify } from "node:util";
|
|
27598
27723
|
var execFileAsync = promisify(execFile);
|
|
27599
27724
|
function resolveSessionDir(sessionDir, ocrDir) {
|
|
27600
27725
|
if (isAbsolute(sessionDir)) return sessionDir;
|
|
27601
|
-
return
|
|
27726
|
+
return join12(dirname9(ocrDir), sessionDir);
|
|
27602
27727
|
}
|
|
27603
27728
|
var BRANCH_PREFIXES = [
|
|
27604
27729
|
"feat",
|
|
@@ -27768,19 +27893,19 @@ function registerPostHandlers(io2, socket, db, ocrDir, aiCliService) {
|
|
|
27768
27893
|
socket.emit("post:error", { error: "Session not found" });
|
|
27769
27894
|
return;
|
|
27770
27895
|
}
|
|
27771
|
-
const sessionDir = session.session_dir ? resolveSessionDir(session.session_dir, ocrDir) :
|
|
27772
|
-
const roundDir =
|
|
27773
|
-
const finalPath =
|
|
27774
|
-
if (!
|
|
27896
|
+
const sessionDir = session.session_dir ? resolveSessionDir(session.session_dir, ocrDir) : join12(ocrDir, "sessions", sessionId);
|
|
27897
|
+
const roundDir = join12(sessionDir, "rounds", `round-${roundNumber}`);
|
|
27898
|
+
const finalPath = join12(roundDir, "final.md");
|
|
27899
|
+
if (!existsSync8(finalPath)) {
|
|
27775
27900
|
socket.emit("post:error", { error: "final.md not found for this round" });
|
|
27776
27901
|
return;
|
|
27777
27902
|
}
|
|
27778
|
-
const humanReviewPath =
|
|
27903
|
+
const humanReviewPath = join12(roundDir, "final-human.md");
|
|
27779
27904
|
const repoRoot = dirname9(ocrDir);
|
|
27780
|
-
const commandMdPath =
|
|
27905
|
+
const commandMdPath = join12(ocrDir, "commands", "translate-review-to-single-human.md");
|
|
27781
27906
|
let commandContent;
|
|
27782
27907
|
try {
|
|
27783
|
-
commandContent =
|
|
27908
|
+
commandContent = readFileSync9(commandMdPath, "utf-8");
|
|
27784
27909
|
} catch {
|
|
27785
27910
|
socket.emit("post:error", {
|
|
27786
27911
|
error: `Command file not found: ${commandMdPath}. Run \`ocr init\` to set up.`
|
|
@@ -27856,9 +27981,9 @@ function registerPostHandlers(io2, socket, db, ocrDir, aiCliService) {
|
|
|
27856
27981
|
}
|
|
27857
27982
|
}
|
|
27858
27983
|
let generatedContent = "";
|
|
27859
|
-
if (
|
|
27984
|
+
if (existsSync8(humanReviewPath)) {
|
|
27860
27985
|
try {
|
|
27861
|
-
generatedContent =
|
|
27986
|
+
generatedContent = readFileSync9(humanReviewPath, "utf-8").trim();
|
|
27862
27987
|
} catch {
|
|
27863
27988
|
}
|
|
27864
27989
|
}
|
|
@@ -27933,10 +28058,10 @@ function registerPostHandlers(io2, socket, db, ocrDir, aiCliService) {
|
|
|
27933
28058
|
socket.emit("post:save-result", { success: false, error: "Session not found" });
|
|
27934
28059
|
return;
|
|
27935
28060
|
}
|
|
27936
|
-
const sessionDir = session.session_dir ? resolveSessionDir(session.session_dir, ocrDir) :
|
|
27937
|
-
const roundDir =
|
|
28061
|
+
const sessionDir = session.session_dir ? resolveSessionDir(session.session_dir, ocrDir) : join12(ocrDir, "sessions", sessionId);
|
|
28062
|
+
const roundDir = join12(sessionDir, "rounds", `round-${roundNumber}`);
|
|
27938
28063
|
mkdirSync2(roundDir, { recursive: true });
|
|
27939
|
-
const filePath =
|
|
28064
|
+
const filePath = join12(roundDir, "final-human.md");
|
|
27940
28065
|
writeFileSync3(filePath, content, { mode: 420 });
|
|
27941
28066
|
saveDb(db, ocrDir);
|
|
27942
28067
|
socket.emit("post:save-result", { success: true });
|
|
@@ -27964,12 +28089,12 @@ function registerPostHandlers(io2, socket, db, ocrDir, aiCliService) {
|
|
|
27964
28089
|
);
|
|
27965
28090
|
tracker.appendOutput(`\u25B8 Posting review to PR #${prNumber}...
|
|
27966
28091
|
`);
|
|
27967
|
-
const tmpDir =
|
|
28092
|
+
const tmpDir = join12(tmpdir2(), "ocr-post-comments");
|
|
27968
28093
|
try {
|
|
27969
28094
|
mkdirSync2(tmpDir, { recursive: true, mode: 448 });
|
|
27970
28095
|
} catch {
|
|
27971
28096
|
}
|
|
27972
|
-
const tmpFile =
|
|
28097
|
+
const tmpFile = join12(tmpDir, `${randomUUID()}.md`);
|
|
27973
28098
|
writeFileSync3(tmpFile, content, { mode: 384 });
|
|
27974
28099
|
const repoRoot = dirname9(ocrDir);
|
|
27975
28100
|
try {
|
|
@@ -28015,9 +28140,14 @@ function cleanupAllPostGenerations() {
|
|
|
28015
28140
|
}
|
|
28016
28141
|
|
|
28017
28142
|
// src/server/index.ts
|
|
28143
|
+
import { homedir } from "node:os";
|
|
28018
28144
|
var __dirname3 = dirname10(fileURLToPath3(import.meta.url));
|
|
28145
|
+
function shortenPath(p) {
|
|
28146
|
+
const home = homedir();
|
|
28147
|
+
return p.startsWith(home) ? "~" + p.slice(home.length) : p;
|
|
28148
|
+
}
|
|
28019
28149
|
var AUTH_TOKEN = randomBytes(32).toString("hex");
|
|
28020
|
-
var app = (0,
|
|
28150
|
+
var app = (0, import_express12.default)();
|
|
28021
28151
|
var httpServer = createServer(app);
|
|
28022
28152
|
var io = new SocketIOServer(httpServer, {
|
|
28023
28153
|
cors: {
|
|
@@ -28026,7 +28156,7 @@ var io = new SocketIOServer(httpServer, {
|
|
|
28026
28156
|
maxHttpBufferSize: 1e6
|
|
28027
28157
|
// 1 MB — explicit default; review if large payloads are needed
|
|
28028
28158
|
});
|
|
28029
|
-
app.use(
|
|
28159
|
+
app.use(import_express12.default.json());
|
|
28030
28160
|
if (process.env.NODE_ENV !== "production") {
|
|
28031
28161
|
app.use((_req, res, next) => {
|
|
28032
28162
|
const origin = _req.headers.origin;
|
|
@@ -28078,12 +28208,12 @@ async function startServer(options = {}) {
|
|
|
28078
28208
|
const ocrDir = resolveOcrDir();
|
|
28079
28209
|
const aiCliService = new AiCliService(ocrDir);
|
|
28080
28210
|
const db = await openDb(ocrDir);
|
|
28081
|
-
const dataDir =
|
|
28082
|
-
const pidFilePath =
|
|
28211
|
+
const dataDir = join13(ocrDir, "data");
|
|
28212
|
+
const pidFilePath = join13(dataDir, "dashboard.pid");
|
|
28083
28213
|
mkdirSync3(dataDir, { recursive: true });
|
|
28084
|
-
if (
|
|
28214
|
+
if (existsSync9(pidFilePath)) {
|
|
28085
28215
|
try {
|
|
28086
|
-
const oldPid = parseInt(
|
|
28216
|
+
const oldPid = parseInt(readFileSync10(pidFilePath, "utf-8").trim(), 10);
|
|
28087
28217
|
if (!isNaN(oldPid)) {
|
|
28088
28218
|
try {
|
|
28089
28219
|
process.kill(oldPid, 0);
|
|
@@ -28123,7 +28253,6 @@ async function startServer(options = {}) {
|
|
|
28123
28253
|
process.kill(pid, "SIGTERM");
|
|
28124
28254
|
}
|
|
28125
28255
|
killedCount++;
|
|
28126
|
-
console.log(`Killed orphaned process (PID ${pid})`);
|
|
28127
28256
|
setTimeout(() => {
|
|
28128
28257
|
try {
|
|
28129
28258
|
process.kill(pid, 0);
|
|
@@ -28141,7 +28270,7 @@ async function startServer(options = {}) {
|
|
|
28141
28270
|
}
|
|
28142
28271
|
}
|
|
28143
28272
|
if (killedCount > 0) {
|
|
28144
|
-
console.log(`
|
|
28273
|
+
console.log(` Cleaned up ${killedCount} orphaned process(es)`);
|
|
28145
28274
|
}
|
|
28146
28275
|
}
|
|
28147
28276
|
const staleResult = db.exec(
|
|
@@ -28158,7 +28287,7 @@ async function startServer(options = {}) {
|
|
|
28158
28287
|
WHERE finished_at IS NULL OR exit_code IS NULL`
|
|
28159
28288
|
);
|
|
28160
28289
|
saveDb(db, ocrDir);
|
|
28161
|
-
console.log(`Cleaned up ${staleCount} stale command
|
|
28290
|
+
console.log(` Cleaned up ${staleCount} stale command(s)`);
|
|
28162
28291
|
}
|
|
28163
28292
|
app.get("/api/reviews", (_req, res) => {
|
|
28164
28293
|
try {
|
|
@@ -28183,11 +28312,12 @@ async function startServer(options = {}) {
|
|
|
28183
28312
|
app.use("/api/commands", createCommandsRouter(db));
|
|
28184
28313
|
app.use("/api/config", createConfigRouter(ocrDir, aiCliService));
|
|
28185
28314
|
app.use("/api/sessions", createChatRouter(db, ocrDir));
|
|
28186
|
-
|
|
28187
|
-
|
|
28188
|
-
|
|
28189
|
-
|
|
28190
|
-
const
|
|
28315
|
+
app.use("/api/reviewers", createReviewersRouter(ocrDir));
|
|
28316
|
+
const clientDir = join13(__dirname3, "client");
|
|
28317
|
+
if (process.env.NODE_ENV === "production" && existsSync9(clientDir)) {
|
|
28318
|
+
app.use(import_express12.default.static(clientDir, { index: false }));
|
|
28319
|
+
const indexHtmlPath = join13(clientDir, "index.html");
|
|
28320
|
+
const rawIndexHtml = existsSync9(indexHtmlPath) ? readFileSync10(indexHtmlPath, "utf-8") : "";
|
|
28191
28321
|
const tokenScript = `<script>window.__OCR_TOKEN__=${JSON.stringify(AUTH_TOKEN)};</script>`;
|
|
28192
28322
|
const injectedIndexHtml = rawIndexHtml.replace(
|
|
28193
28323
|
"</head>",
|
|
@@ -28201,32 +28331,29 @@ async function startServer(options = {}) {
|
|
|
28201
28331
|
});
|
|
28202
28332
|
}
|
|
28203
28333
|
io.on("connection", (socket) => {
|
|
28204
|
-
console.log("Client connected:", socket.id);
|
|
28205
28334
|
registerSocketHandlers(io, socket);
|
|
28206
28335
|
registerCommandHandlers(io, socket, db, ocrDir, aiCliService);
|
|
28207
28336
|
registerChatHandlers(io, socket, db, ocrDir, aiCliService);
|
|
28208
28337
|
registerPostHandlers(io, socket, db, ocrDir, aiCliService);
|
|
28209
|
-
socket.on("disconnect", () => {
|
|
28210
|
-
console.log("Client disconnected:", socket.id);
|
|
28211
|
-
});
|
|
28212
28338
|
});
|
|
28213
|
-
const dbFilePath =
|
|
28339
|
+
const dbFilePath = join13(ocrDir, "data", "ocr.db");
|
|
28214
28340
|
const dbSyncWatcher = new DbSyncWatcher(db, dbFilePath, io, () => {
|
|
28215
28341
|
saveDb(db, ocrDir);
|
|
28216
28342
|
});
|
|
28217
28343
|
await dbSyncWatcher.init();
|
|
28218
28344
|
dbSyncWatcher.startWatching();
|
|
28219
|
-
console.log(`Watching DB:
|
|
28345
|
+
console.log(` Watching DB: ${shortenPath(dbFilePath)}`);
|
|
28220
28346
|
registerSaveHooks(
|
|
28221
28347
|
() => dbSyncWatcher.syncFromDisk(),
|
|
28222
28348
|
() => dbSyncWatcher.markOwnWrite()
|
|
28223
28349
|
);
|
|
28224
|
-
const sessionsDir =
|
|
28350
|
+
const sessionsDir = join13(ocrDir, "sessions");
|
|
28225
28351
|
const fsSync = new FilesystemSync(db, sessionsDir, io, () => saveDb(db, ocrDir));
|
|
28226
28352
|
await fsSync.fullScan();
|
|
28227
28353
|
saveDb(db, ocrDir);
|
|
28228
28354
|
fsSync.startWatching();
|
|
28229
|
-
console.log(`Watching sessions: ${sessionsDir}`);
|
|
28355
|
+
console.log(` Watching sessions: ${shortenPath(sessionsDir)}`);
|
|
28356
|
+
const stopReviewersWatch = watchReviewersMeta(ocrDir, io);
|
|
28230
28357
|
await new Promise((resolve3, reject) => {
|
|
28231
28358
|
httpServer.once("error", (err) => {
|
|
28232
28359
|
if (err.code === "EADDRINUSE") {
|
|
@@ -28238,14 +28365,11 @@ async function startServer(options = {}) {
|
|
|
28238
28365
|
}
|
|
28239
28366
|
});
|
|
28240
28367
|
httpServer.listen(port, "127.0.0.1", () => {
|
|
28241
|
-
console.log(`
|
|
28242
|
-
console.log(`OCR directory:
|
|
28243
|
-
console.log(
|
|
28244
|
-
console.log(
|
|
28245
|
-
console.log(
|
|
28246
|
-
console.log(` ${AUTH_TOKEN.slice(0, 8)}...[redacted]`);
|
|
28247
|
-
console.log("=".repeat(60));
|
|
28248
|
-
console.log("");
|
|
28368
|
+
console.log(` Server: http://localhost:${port}`);
|
|
28369
|
+
console.log(` OCR directory: ${shortenPath(ocrDir)}`);
|
|
28370
|
+
console.log();
|
|
28371
|
+
console.log(` Auth token: ${AUTH_TOKEN.slice(0, 8)}...[redacted]`);
|
|
28372
|
+
console.log();
|
|
28249
28373
|
resolve3();
|
|
28250
28374
|
});
|
|
28251
28375
|
});
|
|
@@ -28310,6 +28434,7 @@ async function startServer(options = {}) {
|
|
|
28310
28434
|
}
|
|
28311
28435
|
dbSyncWatcher.stopWatching();
|
|
28312
28436
|
fsSync.stopWatching();
|
|
28437
|
+
stopReviewersWatch();
|
|
28313
28438
|
io.close();
|
|
28314
28439
|
httpServer.close(() => {
|
|
28315
28440
|
try {
|