@open-code-review/cli 1.5.0 → 1.5.1
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/dist/index.js +245 -210
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -16428,14 +16428,14 @@ __export(db_exports, {
|
|
|
16428
16428
|
saveDatabase: () => saveDatabase,
|
|
16429
16429
|
updateSession: () => updateSession
|
|
16430
16430
|
});
|
|
16431
|
-
import { existsSync as
|
|
16432
|
-
import { dirname as dirname4, join as
|
|
16431
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync8, renameSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
16432
|
+
import { dirname as dirname4, join as join11 } from "node:path";
|
|
16433
16433
|
import { createRequire as createRequire2 } from "node:module";
|
|
16434
16434
|
import initSqlJs from "sql.js";
|
|
16435
16435
|
function locateWasm() {
|
|
16436
16436
|
const require3 = createRequire2(import.meta.url);
|
|
16437
16437
|
const sqlJsPath = require3.resolve("sql.js");
|
|
16438
|
-
return
|
|
16438
|
+
return join11(dirname4(sqlJsPath), "sql-wasm.wasm");
|
|
16439
16439
|
}
|
|
16440
16440
|
function applyPragmas(db) {
|
|
16441
16441
|
db.run("PRAGMA foreign_keys = ON;");
|
|
@@ -16447,7 +16447,7 @@ async function openDatabase(dbPath) {
|
|
|
16447
16447
|
if (cached) {
|
|
16448
16448
|
return cached;
|
|
16449
16449
|
}
|
|
16450
|
-
const wasmBuffer =
|
|
16450
|
+
const wasmBuffer = readFileSync8(locateWasm());
|
|
16451
16451
|
const wasmBinary = wasmBuffer.buffer.slice(
|
|
16452
16452
|
wasmBuffer.byteOffset,
|
|
16453
16453
|
wasmBuffer.byteOffset + wasmBuffer.byteLength
|
|
@@ -16456,8 +16456,8 @@ async function openDatabase(dbPath) {
|
|
|
16456
16456
|
wasmBinary
|
|
16457
16457
|
});
|
|
16458
16458
|
let db;
|
|
16459
|
-
if (
|
|
16460
|
-
const fileBuffer =
|
|
16459
|
+
if (existsSync9(dbPath)) {
|
|
16460
|
+
const fileBuffer = readFileSync8(dbPath);
|
|
16461
16461
|
db = new SQL.Database(fileBuffer);
|
|
16462
16462
|
} else {
|
|
16463
16463
|
db = new SQL.Database();
|
|
@@ -16469,23 +16469,23 @@ async function openDatabase(dbPath) {
|
|
|
16469
16469
|
function saveDatabase(db, dbPath) {
|
|
16470
16470
|
const data = db.export();
|
|
16471
16471
|
const dir = dirname4(dbPath);
|
|
16472
|
-
if (!
|
|
16472
|
+
if (!existsSync9(dir)) {
|
|
16473
16473
|
mkdirSync3(dir, { recursive: true });
|
|
16474
16474
|
}
|
|
16475
16475
|
const tmpPath = dbPath + ".tmp";
|
|
16476
|
-
|
|
16476
|
+
writeFileSync6(tmpPath, Buffer.from(data));
|
|
16477
16477
|
renameSync(tmpPath, dbPath);
|
|
16478
16478
|
}
|
|
16479
16479
|
async function getDb(ocrDir) {
|
|
16480
|
-
const dbPath =
|
|
16480
|
+
const dbPath = join11(ocrDir, "data", "ocr.db");
|
|
16481
16481
|
return openDatabase(dbPath);
|
|
16482
16482
|
}
|
|
16483
16483
|
async function ensureDatabase(ocrDir) {
|
|
16484
|
-
const dataDir =
|
|
16485
|
-
if (!
|
|
16484
|
+
const dataDir = join11(ocrDir, "data");
|
|
16485
|
+
if (!existsSync9(dataDir)) {
|
|
16486
16486
|
mkdirSync3(dataDir, { recursive: true });
|
|
16487
16487
|
}
|
|
16488
|
-
const dbPath =
|
|
16488
|
+
const dbPath = join11(dataDir, "ocr.db");
|
|
16489
16489
|
const db = await openDatabase(dbPath);
|
|
16490
16490
|
runMigrations(db);
|
|
16491
16491
|
saveDatabase(db, dbPath);
|
|
@@ -20170,19 +20170,59 @@ function parseToolsArg(toolsArg) {
|
|
|
20170
20170
|
|
|
20171
20171
|
// src/lib/installer.ts
|
|
20172
20172
|
import {
|
|
20173
|
-
existsSync,
|
|
20173
|
+
existsSync as existsSync2,
|
|
20174
20174
|
mkdirSync,
|
|
20175
20175
|
cpSync,
|
|
20176
|
-
writeFileSync as
|
|
20176
|
+
writeFileSync as writeFileSync3,
|
|
20177
20177
|
readdirSync,
|
|
20178
|
-
readFileSync as
|
|
20178
|
+
readFileSync as readFileSync3,
|
|
20179
20179
|
unlinkSync as unlinkSync2
|
|
20180
20180
|
} from "node:fs";
|
|
20181
|
-
import { join, dirname } from "node:path";
|
|
20181
|
+
import { join as join2, dirname } from "node:path";
|
|
20182
20182
|
import { createRequire } from "node:module";
|
|
20183
|
+
|
|
20184
|
+
// src/lib/gitignore.ts
|
|
20185
|
+
import { existsSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
20186
|
+
import { join } from "node:path";
|
|
20187
|
+
var START_MARKER = "# OCR:START \u2014 managed by open-code-review (do not edit this block)";
|
|
20188
|
+
var END_MARKER = "# OCR:END";
|
|
20189
|
+
var MANAGED_ENTRIES = ["sessions/", "data/", "*.db-shm", "*.db-wal"];
|
|
20190
|
+
function buildManagedBlock() {
|
|
20191
|
+
return [START_MARKER, ...MANAGED_ENTRIES, END_MARKER].join("\n");
|
|
20192
|
+
}
|
|
20193
|
+
function escapeRegex(str) {
|
|
20194
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
20195
|
+
}
|
|
20196
|
+
function ensureGitignore(ocrDir) {
|
|
20197
|
+
const gitignorePath = join(ocrDir, ".gitignore");
|
|
20198
|
+
const block = buildManagedBlock();
|
|
20199
|
+
let content = existsSync(gitignorePath) ? readFileSync2(gitignorePath, "utf-8") : "";
|
|
20200
|
+
const regex2 = new RegExp(
|
|
20201
|
+
`${escapeRegex(START_MARKER)}[\\s\\S]*?${escapeRegex(END_MARKER)}\\n?`,
|
|
20202
|
+
"g"
|
|
20203
|
+
);
|
|
20204
|
+
if (regex2.test(content)) {
|
|
20205
|
+
content = content.replace(
|
|
20206
|
+
new RegExp(
|
|
20207
|
+
`${escapeRegex(START_MARKER)}[\\s\\S]*?${escapeRegex(END_MARKER)}\\n?`,
|
|
20208
|
+
"g"
|
|
20209
|
+
),
|
|
20210
|
+
block + "\n"
|
|
20211
|
+
);
|
|
20212
|
+
} else {
|
|
20213
|
+
content = content.trimEnd();
|
|
20214
|
+
if (content.length > 0) {
|
|
20215
|
+
content += "\n\n";
|
|
20216
|
+
}
|
|
20217
|
+
content += block + "\n";
|
|
20218
|
+
}
|
|
20219
|
+
writeFileSync2(gitignorePath, content);
|
|
20220
|
+
}
|
|
20221
|
+
|
|
20222
|
+
// src/lib/installer.ts
|
|
20183
20223
|
var require2 = createRequire(import.meta.url);
|
|
20184
20224
|
function ensureDir(dir) {
|
|
20185
|
-
if (!
|
|
20225
|
+
if (!existsSync2(dir)) {
|
|
20186
20226
|
mkdirSync(dir, { recursive: true });
|
|
20187
20227
|
}
|
|
20188
20228
|
}
|
|
@@ -20191,8 +20231,8 @@ function getAgentsPackagePath() {
|
|
|
20191
20231
|
const agentsPath = require2.resolve("@open-code-review/agents/package.json");
|
|
20192
20232
|
return dirname(agentsPath);
|
|
20193
20233
|
} catch {
|
|
20194
|
-
const localPath =
|
|
20195
|
-
if (
|
|
20234
|
+
const localPath = join2(process.cwd(), "packages", "agents");
|
|
20235
|
+
if (existsSync2(localPath)) {
|
|
20196
20236
|
return localPath;
|
|
20197
20237
|
}
|
|
20198
20238
|
throw new Error(
|
|
@@ -20212,8 +20252,8 @@ function copyDirSafe(src, dest) {
|
|
|
20212
20252
|
function copyFileSafe(src, dest) {
|
|
20213
20253
|
try {
|
|
20214
20254
|
ensureDir(dirname(dest));
|
|
20215
|
-
const content =
|
|
20216
|
-
|
|
20255
|
+
const content = readFileSync3(src);
|
|
20256
|
+
writeFileSync3(dest, content);
|
|
20217
20257
|
return true;
|
|
20218
20258
|
} catch {
|
|
20219
20259
|
return false;
|
|
@@ -20237,8 +20277,8 @@ function extractDescription(content) {
|
|
|
20237
20277
|
return match?.[1]?.trim() ?? "OCR command";
|
|
20238
20278
|
}
|
|
20239
20279
|
function installCommandsForTool(tool, commandsSource, targetDir) {
|
|
20240
|
-
const toolCommandsDir =
|
|
20241
|
-
const centralCommandsDir =
|
|
20280
|
+
const toolCommandsDir = join2(targetDir, tool.commandsDir);
|
|
20281
|
+
const centralCommandsDir = join2(targetDir, ".ocr", "commands");
|
|
20242
20282
|
ensureDir(toolCommandsDir);
|
|
20243
20283
|
ensureDir(centralCommandsDir);
|
|
20244
20284
|
try {
|
|
@@ -20246,32 +20286,32 @@ function installCommandsForTool(tool, commandsSource, targetDir) {
|
|
|
20246
20286
|
(f) => f.endsWith(".md")
|
|
20247
20287
|
);
|
|
20248
20288
|
for (const file of commandFiles) {
|
|
20249
|
-
const srcPath =
|
|
20289
|
+
const srcPath = join2(commandsSource, file);
|
|
20250
20290
|
const normalizedName = file.replace(/^ocr-/, "");
|
|
20251
|
-
const centralPath =
|
|
20291
|
+
const centralPath = join2(centralCommandsDir, normalizedName);
|
|
20252
20292
|
if (!copyFileSafe(srcPath, centralPath)) {
|
|
20253
20293
|
return false;
|
|
20254
20294
|
}
|
|
20255
20295
|
}
|
|
20256
20296
|
if (tool.commandStrategy === "subdirectory") {
|
|
20257
|
-
const ocrSubdir =
|
|
20297
|
+
const ocrSubdir = join2(toolCommandsDir, "ocr");
|
|
20258
20298
|
ensureDir(ocrSubdir);
|
|
20259
20299
|
for (const file of commandFiles) {
|
|
20260
|
-
const srcPath =
|
|
20261
|
-
const content =
|
|
20300
|
+
const srcPath = join2(commandsSource, file);
|
|
20301
|
+
const content = readFileSync3(srcPath, "utf-8");
|
|
20262
20302
|
const description = extractDescription(content);
|
|
20263
20303
|
const normalizedName = file.replace(/^ocr-/, "");
|
|
20264
20304
|
const refContent = generateCommandReference(
|
|
20265
20305
|
normalizedName,
|
|
20266
20306
|
description
|
|
20267
20307
|
);
|
|
20268
|
-
const destPath =
|
|
20269
|
-
|
|
20308
|
+
const destPath = join2(ocrSubdir, normalizedName);
|
|
20309
|
+
writeFileSync3(destPath, refContent);
|
|
20270
20310
|
}
|
|
20271
20311
|
} else {
|
|
20272
20312
|
for (const file of commandFiles) {
|
|
20273
|
-
const srcPath =
|
|
20274
|
-
const content =
|
|
20313
|
+
const srcPath = join2(commandsSource, file);
|
|
20314
|
+
const content = readFileSync3(srcPath, "utf-8");
|
|
20275
20315
|
const description = extractDescription(content);
|
|
20276
20316
|
const normalizedName = file.replace(/^ocr-/, "");
|
|
20277
20317
|
const destName = `ocr-${normalizedName}`;
|
|
@@ -20279,8 +20319,8 @@ function installCommandsForTool(tool, commandsSource, targetDir) {
|
|
|
20279
20319
|
normalizedName,
|
|
20280
20320
|
description
|
|
20281
20321
|
);
|
|
20282
|
-
const destPath =
|
|
20283
|
-
|
|
20322
|
+
const destPath = join2(toolCommandsDir, destName);
|
|
20323
|
+
writeFileSync3(destPath, refContent);
|
|
20284
20324
|
}
|
|
20285
20325
|
}
|
|
20286
20326
|
return true;
|
|
@@ -20290,39 +20330,33 @@ function installCommandsForTool(tool, commandsSource, targetDir) {
|
|
|
20290
20330
|
}
|
|
20291
20331
|
function installForTool(tool, targetDir) {
|
|
20292
20332
|
const agentsPath = getAgentsPackagePath();
|
|
20293
|
-
const ocrSkillsSource =
|
|
20294
|
-
const commandsSource =
|
|
20295
|
-
const ocrDir =
|
|
20296
|
-
const ocrSkillsDest =
|
|
20333
|
+
const ocrSkillsSource = join2(agentsPath, "skills", "ocr");
|
|
20334
|
+
const commandsSource = join2(agentsPath, "commands");
|
|
20335
|
+
const ocrDir = join2(targetDir, ".ocr");
|
|
20336
|
+
const ocrSkillsDest = join2(ocrDir, "skills");
|
|
20297
20337
|
ensureDir(ocrDir);
|
|
20298
|
-
ensureDir(
|
|
20299
|
-
|
|
20300
|
-
|
|
20301
|
-
`;
|
|
20302
|
-
const gitignorePath = join(ocrDir, ".gitignore");
|
|
20303
|
-
if (!existsSync(gitignorePath)) {
|
|
20304
|
-
writeFileSync2(gitignorePath, gitignoreContent);
|
|
20305
|
-
}
|
|
20306
|
-
const configPath = join(ocrDir, "config.yaml");
|
|
20338
|
+
ensureDir(join2(ocrDir, "sessions"));
|
|
20339
|
+
ensureGitignore(ocrDir);
|
|
20340
|
+
const configPath = join2(ocrDir, "config.yaml");
|
|
20307
20341
|
let existingConfig = null;
|
|
20308
|
-
if (
|
|
20342
|
+
if (existsSync2(configPath)) {
|
|
20309
20343
|
try {
|
|
20310
|
-
existingConfig =
|
|
20344
|
+
existingConfig = readFileSync3(configPath);
|
|
20311
20345
|
} catch {
|
|
20312
20346
|
}
|
|
20313
20347
|
}
|
|
20314
|
-
const reviewersDir =
|
|
20348
|
+
const reviewersDir = join2(ocrSkillsDest, "references", "reviewers");
|
|
20315
20349
|
const existingReviewers = /* @__PURE__ */ new Map();
|
|
20316
20350
|
const warnings = [];
|
|
20317
|
-
if (
|
|
20351
|
+
if (existsSync2(reviewersDir)) {
|
|
20318
20352
|
try {
|
|
20319
20353
|
const reviewerFiles = readdirSync(reviewersDir).filter(
|
|
20320
20354
|
(f) => f.endsWith(".md")
|
|
20321
20355
|
);
|
|
20322
20356
|
for (const file of reviewerFiles) {
|
|
20323
|
-
const filePath =
|
|
20357
|
+
const filePath = join2(reviewersDir, file);
|
|
20324
20358
|
try {
|
|
20325
|
-
existingReviewers.set(file,
|
|
20359
|
+
existingReviewers.set(file, readFileSync3(filePath));
|
|
20326
20360
|
} catch (err) {
|
|
20327
20361
|
const msg = err instanceof Error ? err.message : "unknown error";
|
|
20328
20362
|
warnings.push(`Could not read reviewer ${file}: ${msg}`);
|
|
@@ -20341,17 +20375,17 @@ sessions/
|
|
|
20341
20375
|
error: "Failed to install OCR skills to .ocr/"
|
|
20342
20376
|
};
|
|
20343
20377
|
}
|
|
20344
|
-
const configSource =
|
|
20378
|
+
const configSource = join2(ocrSkillsSource, "assets", "config.yaml");
|
|
20345
20379
|
if (existingConfig) {
|
|
20346
20380
|
try {
|
|
20347
|
-
|
|
20381
|
+
writeFileSync3(configPath, existingConfig);
|
|
20348
20382
|
} catch {
|
|
20349
20383
|
}
|
|
20350
|
-
} else if (
|
|
20384
|
+
} else if (existsSync2(configSource)) {
|
|
20351
20385
|
copyFileSafe(configSource, configPath);
|
|
20352
20386
|
}
|
|
20353
|
-
const duplicateConfig =
|
|
20354
|
-
if (
|
|
20387
|
+
const duplicateConfig = join2(ocrSkillsDest, "assets", "config.yaml");
|
|
20388
|
+
if (existsSync2(duplicateConfig)) {
|
|
20355
20389
|
try {
|
|
20356
20390
|
unlinkSync2(duplicateConfig);
|
|
20357
20391
|
} catch {
|
|
@@ -20361,7 +20395,7 @@ sessions/
|
|
|
20361
20395
|
ensureDir(reviewersDir);
|
|
20362
20396
|
for (const [file, content] of existingReviewers) {
|
|
20363
20397
|
try {
|
|
20364
|
-
|
|
20398
|
+
writeFileSync3(join2(reviewersDir, file), content);
|
|
20365
20399
|
} catch (err) {
|
|
20366
20400
|
const msg = err instanceof Error ? err.message : "unknown error";
|
|
20367
20401
|
warnings.push(`Could not restore reviewer ${file}: ${msg}`);
|
|
@@ -20384,27 +20418,27 @@ sessions/
|
|
|
20384
20418
|
}
|
|
20385
20419
|
function detectInstalledTools(targetDir, tools) {
|
|
20386
20420
|
return tools.filter((tool) => {
|
|
20387
|
-
const configPath =
|
|
20421
|
+
const configPath = join2(targetDir, tool.configDir);
|
|
20388
20422
|
if (tool.id === "github-copilot") {
|
|
20389
|
-
const copilotInstructions =
|
|
20423
|
+
const copilotInstructions = join2(
|
|
20390
20424
|
targetDir,
|
|
20391
20425
|
".github",
|
|
20392
20426
|
"copilot-instructions.md"
|
|
20393
20427
|
);
|
|
20394
|
-
const copilotDir =
|
|
20395
|
-
const copilotCommands =
|
|
20396
|
-
return
|
|
20428
|
+
const copilotDir = join2(targetDir, ".github", "copilot");
|
|
20429
|
+
const copilotCommands = join2(targetDir, ".github", "commands");
|
|
20430
|
+
return existsSync2(copilotInstructions) || existsSync2(copilotDir) || existsSync2(copilotCommands);
|
|
20397
20431
|
}
|
|
20398
|
-
return
|
|
20432
|
+
return existsSync2(configPath);
|
|
20399
20433
|
});
|
|
20400
20434
|
}
|
|
20401
20435
|
|
|
20402
20436
|
// src/lib/injector.ts
|
|
20403
|
-
import { existsSync as
|
|
20404
|
-
import { join as
|
|
20405
|
-
var
|
|
20406
|
-
var
|
|
20407
|
-
var OCR_INSTRUCTION_BLOCK = `${
|
|
20437
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
20438
|
+
import { join as join3 } from "node:path";
|
|
20439
|
+
var START_MARKER2 = "<!-- OCR:START -->";
|
|
20440
|
+
var END_MARKER2 = "<!-- OCR:END -->";
|
|
20441
|
+
var OCR_INSTRUCTION_BLOCK = `${START_MARKER2}
|
|
20408
20442
|
# Open Code Review Instructions
|
|
20409
20443
|
|
|
20410
20444
|
These instructions are for AI assistants handling code review in this project.
|
|
@@ -20423,12 +20457,12 @@ Use \`.ocr/skills/SKILL.md\` to learn:
|
|
|
20423
20457
|
|
|
20424
20458
|
Keep this managed block so 'ocr init' can refresh the instructions.
|
|
20425
20459
|
|
|
20426
|
-
${
|
|
20460
|
+
${END_MARKER2}`;
|
|
20427
20461
|
function injectOcrInstructions(filePath) {
|
|
20428
20462
|
try {
|
|
20429
|
-
let content =
|
|
20463
|
+
let content = existsSync3(filePath) ? readFileSync4(filePath, "utf-8") : "";
|
|
20430
20464
|
const regex2 = new RegExp(
|
|
20431
|
-
`${
|
|
20465
|
+
`${escapeRegex2(START_MARKER2)}[\\s\\S]*?${escapeRegex2(END_MARKER2)}\\n?`,
|
|
20432
20466
|
"g"
|
|
20433
20467
|
);
|
|
20434
20468
|
content = content.replace(regex2, "");
|
|
@@ -20437,18 +20471,18 @@ function injectOcrInstructions(filePath) {
|
|
|
20437
20471
|
content += "\n\n";
|
|
20438
20472
|
}
|
|
20439
20473
|
content += OCR_INSTRUCTION_BLOCK + "\n";
|
|
20440
|
-
|
|
20474
|
+
writeFileSync4(filePath, content);
|
|
20441
20475
|
return true;
|
|
20442
20476
|
} catch {
|
|
20443
20477
|
return false;
|
|
20444
20478
|
}
|
|
20445
20479
|
}
|
|
20446
|
-
function
|
|
20480
|
+
function escapeRegex2(str) {
|
|
20447
20481
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
20448
20482
|
}
|
|
20449
20483
|
function injectIntoProjectFiles(targetDir) {
|
|
20450
|
-
const agentsMdPath =
|
|
20451
|
-
const claudeMdPath =
|
|
20484
|
+
const agentsMdPath = join3(targetDir, "AGENTS.md");
|
|
20485
|
+
const claudeMdPath = join3(targetDir, "CLAUDE.md");
|
|
20452
20486
|
const agentsMd = injectOcrInstructions(agentsMdPath);
|
|
20453
20487
|
const claudeMd = injectOcrInstructions(claudeMdPath);
|
|
20454
20488
|
return { agentsMd, claudeMd };
|
|
@@ -20491,19 +20525,19 @@ function printHeader() {
|
|
|
20491
20525
|
}
|
|
20492
20526
|
|
|
20493
20527
|
// src/lib/cli-config.ts
|
|
20494
|
-
import { existsSync as
|
|
20495
|
-
import { join as
|
|
20528
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
20529
|
+
import { join as join4 } from "node:path";
|
|
20496
20530
|
var CLI_CONFIG_FILE = "cli-config.json";
|
|
20497
20531
|
function getCliConfigPath(targetDir) {
|
|
20498
|
-
return
|
|
20532
|
+
return join4(targetDir, ".ocr", CLI_CONFIG_FILE);
|
|
20499
20533
|
}
|
|
20500
20534
|
function loadCliConfig(targetDir) {
|
|
20501
20535
|
const configPath = getCliConfigPath(targetDir);
|
|
20502
|
-
if (!
|
|
20536
|
+
if (!existsSync4(configPath)) {
|
|
20503
20537
|
return null;
|
|
20504
20538
|
}
|
|
20505
20539
|
try {
|
|
20506
|
-
const content =
|
|
20540
|
+
const content = readFileSync5(configPath, "utf-8");
|
|
20507
20541
|
return JSON.parse(content);
|
|
20508
20542
|
} catch {
|
|
20509
20543
|
return null;
|
|
@@ -20516,7 +20550,7 @@ function saveCliConfig(targetDir, config) {
|
|
|
20516
20550
|
...config,
|
|
20517
20551
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
20518
20552
|
};
|
|
20519
|
-
|
|
20553
|
+
writeFileSync5(configPath, JSON.stringify(configWithMeta, null, 2) + "\n");
|
|
20520
20554
|
return true;
|
|
20521
20555
|
} catch {
|
|
20522
20556
|
return false;
|
|
@@ -22533,8 +22567,8 @@ function watch(paths, options = {}) {
|
|
|
22533
22567
|
}
|
|
22534
22568
|
|
|
22535
22569
|
// src/commands/progress.ts
|
|
22536
|
-
import { existsSync as
|
|
22537
|
-
import { join as
|
|
22570
|
+
import { existsSync as existsSync10, readdirSync as readdirSync5, statSync } from "node:fs";
|
|
22571
|
+
import { join as join12, basename as basename7 } from "node:path";
|
|
22538
22572
|
|
|
22539
22573
|
// ../../node_modules/.pnpm/log-update@7.0.2/node_modules/log-update/index.js
|
|
22540
22574
|
import process12 from "node:process";
|
|
@@ -23402,15 +23436,15 @@ var log_update_default = logUpdate;
|
|
|
23402
23436
|
var logUpdateStderr = createLogUpdate(process12.stderr);
|
|
23403
23437
|
|
|
23404
23438
|
// src/lib/guards.ts
|
|
23405
|
-
import { existsSync as
|
|
23406
|
-
import { join as
|
|
23439
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync2 } from "node:fs";
|
|
23440
|
+
import { join as join7 } from "node:path";
|
|
23407
23441
|
function checkOcrSetup(targetDir) {
|
|
23408
|
-
const ocrDir =
|
|
23409
|
-
const skillsDir =
|
|
23410
|
-
const sessionsDir =
|
|
23411
|
-
const hasOcrDir =
|
|
23412
|
-
const hasSkills =
|
|
23413
|
-
const hasSessions =
|
|
23442
|
+
const ocrDir = join7(targetDir, ".ocr");
|
|
23443
|
+
const skillsDir = join7(ocrDir, "skills");
|
|
23444
|
+
const sessionsDir = join7(ocrDir, "sessions");
|
|
23445
|
+
const hasOcrDir = existsSync5(ocrDir);
|
|
23446
|
+
const hasSkills = existsSync5(skillsDir);
|
|
23447
|
+
const hasSessions = existsSync5(sessionsDir);
|
|
23414
23448
|
return {
|
|
23415
23449
|
valid: hasOcrDir && hasSkills,
|
|
23416
23450
|
ocrDir,
|
|
@@ -23426,7 +23460,7 @@ function requireOcrSetup(targetDir) {
|
|
|
23426
23460
|
console.error();
|
|
23427
23461
|
console.error(source_default.red.bold(" \u2717 OCR is not set up in this directory"));
|
|
23428
23462
|
console.error();
|
|
23429
|
-
if (!
|
|
23463
|
+
if (!existsSync5(status.ocrDir)) {
|
|
23430
23464
|
console.error(source_default.dim(" The .ocr directory was not found."));
|
|
23431
23465
|
} else if (!status.hasSkills) {
|
|
23432
23466
|
console.error(source_default.dim(" The .ocr/skills directory is missing."));
|
|
@@ -23446,8 +23480,8 @@ function requireOcrSetup(targetDir) {
|
|
|
23446
23480
|
return status;
|
|
23447
23481
|
}
|
|
23448
23482
|
function ensureSessionsDir(targetDir) {
|
|
23449
|
-
const sessionsDir =
|
|
23450
|
-
if (!
|
|
23483
|
+
const sessionsDir = join7(targetDir, ".ocr", "sessions");
|
|
23484
|
+
if (!existsSync5(sessionsDir)) {
|
|
23451
23485
|
mkdirSync2(sessionsDir, { recursive: true });
|
|
23452
23486
|
}
|
|
23453
23487
|
return sessionsDir;
|
|
@@ -23463,8 +23497,8 @@ function getStrategy(workflowType) {
|
|
|
23463
23497
|
}
|
|
23464
23498
|
|
|
23465
23499
|
// src/lib/progress/detector.ts
|
|
23466
|
-
import { existsSync as
|
|
23467
|
-
import { join as
|
|
23500
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2 } from "node:fs";
|
|
23501
|
+
import { join as join8, basename as basename4 } from "node:path";
|
|
23468
23502
|
|
|
23469
23503
|
// src/lib/progress/session-reader.ts
|
|
23470
23504
|
init_result_mapper();
|
|
@@ -23535,8 +23569,8 @@ function detectWorkflowType(sessionPath, explicitType) {
|
|
|
23535
23569
|
} catch {
|
|
23536
23570
|
}
|
|
23537
23571
|
}
|
|
23538
|
-
const hasMapDir =
|
|
23539
|
-
const hasRoundsDir =
|
|
23572
|
+
const hasMapDir = existsSync6(join8(sessionPath, "map"));
|
|
23573
|
+
const hasRoundsDir = existsSync6(join8(sessionPath, "rounds"));
|
|
23540
23574
|
if (hasMapDir && !hasRoundsDir) {
|
|
23541
23575
|
return "map";
|
|
23542
23576
|
}
|
|
@@ -23592,28 +23626,28 @@ function isSessionActive(sessionPath) {
|
|
|
23592
23626
|
}
|
|
23593
23627
|
function detectActiveWorkflows(sessionPath) {
|
|
23594
23628
|
const activeWorkflows = [];
|
|
23595
|
-
const hasRoundsDir =
|
|
23629
|
+
const hasRoundsDir = existsSync6(join8(sessionPath, "rounds"));
|
|
23596
23630
|
if (hasRoundsDir) {
|
|
23597
|
-
const roundsDir =
|
|
23598
|
-
const rounds =
|
|
23631
|
+
const roundsDir = join8(sessionPath, "rounds");
|
|
23632
|
+
const rounds = existsSync6(roundsDir) ? readdirSync2(roundsDir).filter((d) => d.match(/^round-\d+$/)).sort() : [];
|
|
23599
23633
|
if (rounds.length > 0) {
|
|
23600
23634
|
const latestRound = rounds[rounds.length - 1];
|
|
23601
|
-
const finalPath =
|
|
23602
|
-
if (!
|
|
23635
|
+
const finalPath = join8(roundsDir, latestRound, "final.md");
|
|
23636
|
+
if (!existsSync6(finalPath)) {
|
|
23603
23637
|
activeWorkflows.push("review");
|
|
23604
23638
|
}
|
|
23605
23639
|
} else {
|
|
23606
23640
|
activeWorkflows.push("review");
|
|
23607
23641
|
}
|
|
23608
23642
|
}
|
|
23609
|
-
const hasMapDir =
|
|
23643
|
+
const hasMapDir = existsSync6(join8(sessionPath, "map"));
|
|
23610
23644
|
if (hasMapDir) {
|
|
23611
|
-
const runsDir =
|
|
23612
|
-
const runs =
|
|
23645
|
+
const runsDir = join8(sessionPath, "map", "runs");
|
|
23646
|
+
const runs = existsSync6(runsDir) ? readdirSync2(runsDir).filter((d) => d.match(/^run-\d+$/)).sort() : [];
|
|
23613
23647
|
if (runs.length > 0) {
|
|
23614
23648
|
const latestRun = runs[runs.length - 1];
|
|
23615
|
-
const mapPath =
|
|
23616
|
-
if (!
|
|
23649
|
+
const mapPath = join8(runsDir, latestRun, "map.md");
|
|
23650
|
+
if (!existsSync6(mapPath)) {
|
|
23617
23651
|
activeWorkflows.push("map");
|
|
23618
23652
|
}
|
|
23619
23653
|
} else {
|
|
@@ -23692,8 +23726,8 @@ function padLines(lines) {
|
|
|
23692
23726
|
}
|
|
23693
23727
|
|
|
23694
23728
|
// src/lib/progress/review-strategy.ts
|
|
23695
|
-
import { existsSync as
|
|
23696
|
-
import { join as
|
|
23729
|
+
import { existsSync as existsSync7, readdirSync as readdirSync3, readFileSync as readFileSync6 } from "node:fs";
|
|
23730
|
+
import { join as join9, basename as basename5 } from "node:path";
|
|
23697
23731
|
var REVIEW_PHASES = [
|
|
23698
23732
|
{ key: "context", label: "Context Discovery" },
|
|
23699
23733
|
{ key: "change-context", label: "Change Context" },
|
|
@@ -23705,10 +23739,10 @@ var REVIEW_PHASES = [
|
|
|
23705
23739
|
{ key: "complete", label: "Complete" }
|
|
23706
23740
|
];
|
|
23707
23741
|
function countFindings(filePath) {
|
|
23708
|
-
if (!
|
|
23742
|
+
if (!existsSync7(filePath)) {
|
|
23709
23743
|
return 0;
|
|
23710
23744
|
}
|
|
23711
|
-
const content =
|
|
23745
|
+
const content = readFileSync6(filePath, "utf-8");
|
|
23712
23746
|
const findingMatches = content.match(/^##\s+(Finding|Issue|Suggestion)/gm);
|
|
23713
23747
|
return findingMatches?.length ?? 0;
|
|
23714
23748
|
}
|
|
@@ -23722,7 +23756,7 @@ function formatReviewerName(filename) {
|
|
|
23722
23756
|
return base.charAt(0).toUpperCase() + base.slice(1);
|
|
23723
23757
|
}
|
|
23724
23758
|
function deriveRoundsFromFilesystem(roundsDir) {
|
|
23725
|
-
if (!
|
|
23759
|
+
if (!existsSync7(roundsDir)) {
|
|
23726
23760
|
return [];
|
|
23727
23761
|
}
|
|
23728
23762
|
const roundDirs = readdirSync3(roundsDir).filter((d) => d.match(/^round-\d+$/)).sort((a, b) => {
|
|
@@ -23732,17 +23766,17 @@ function deriveRoundsFromFilesystem(roundsDir) {
|
|
|
23732
23766
|
});
|
|
23733
23767
|
return roundDirs.map((dir) => {
|
|
23734
23768
|
const roundNum = parseInt(dir.replace("round-", ""));
|
|
23735
|
-
const roundPath =
|
|
23736
|
-
const reviewsPath =
|
|
23737
|
-
const finalPath =
|
|
23769
|
+
const roundPath = join9(roundsDir, dir);
|
|
23770
|
+
const reviewsPath = join9(roundPath, "reviews");
|
|
23771
|
+
const finalPath = join9(roundPath, "final.md");
|
|
23738
23772
|
const reviewers = [];
|
|
23739
|
-
if (
|
|
23773
|
+
if (existsSync7(reviewsPath)) {
|
|
23740
23774
|
const files = readdirSync3(reviewsPath).filter((f) => f.endsWith(".md"));
|
|
23741
23775
|
reviewers.push(...files.map((f) => f.replace(".md", "")));
|
|
23742
23776
|
}
|
|
23743
23777
|
return {
|
|
23744
23778
|
round: roundNum,
|
|
23745
|
-
isComplete:
|
|
23779
|
+
isComplete: existsSync7(finalPath),
|
|
23746
23780
|
reviewers
|
|
23747
23781
|
};
|
|
23748
23782
|
});
|
|
@@ -23771,19 +23805,19 @@ var ReviewProgressStrategy = class {
|
|
|
23771
23805
|
parseFromState(session, state, sessionPath, preservedStartTime) {
|
|
23772
23806
|
const effectiveStartTime = state.round_started_at ?? state.started_at;
|
|
23773
23807
|
const startTime = preservedStartTime ?? (effectiveStartTime ? new Date(effectiveStartTime).getTime() : Date.now());
|
|
23774
|
-
const roundsDir =
|
|
23808
|
+
const roundsDir = join9(sessionPath, "rounds");
|
|
23775
23809
|
const rounds = deriveRoundsFromFilesystem(roundsDir);
|
|
23776
23810
|
const highestExistingRound = rounds.length > 0 ? Math.max(...rounds.map((r) => r.round)) : 1;
|
|
23777
23811
|
const stateRound = state.current_round ?? 1;
|
|
23778
23812
|
const currentRound = Math.min(stateRound, highestExistingRound);
|
|
23779
|
-
const currentRoundDir =
|
|
23780
|
-
const reviewsDir =
|
|
23813
|
+
const currentRoundDir = join9(roundsDir, `round-${currentRound}`);
|
|
23814
|
+
const reviewsDir = join9(currentRoundDir, "reviews");
|
|
23781
23815
|
const reviewers = [];
|
|
23782
|
-
if (
|
|
23816
|
+
if (existsSync7(reviewsDir)) {
|
|
23783
23817
|
const entries = readdirSync3(reviewsDir);
|
|
23784
23818
|
const reviewFiles = entries.filter((f) => f.endsWith(".md"));
|
|
23785
23819
|
for (const file of reviewFiles) {
|
|
23786
|
-
const reviewPath =
|
|
23820
|
+
const reviewPath = join9(reviewsDir, file);
|
|
23787
23821
|
const findings = countFindings(reviewPath);
|
|
23788
23822
|
reviewers.push({
|
|
23789
23823
|
name: file.replace(".md", ""),
|
|
@@ -23793,14 +23827,14 @@ var ReviewProgressStrategy = class {
|
|
|
23793
23827
|
});
|
|
23794
23828
|
}
|
|
23795
23829
|
}
|
|
23796
|
-
const contextComplete =
|
|
23797
|
-
|
|
23830
|
+
const contextComplete = existsSync7(
|
|
23831
|
+
join9(sessionPath, "discovered-standards.md")
|
|
23798
23832
|
);
|
|
23799
|
-
const changeContextComplete =
|
|
23833
|
+
const changeContextComplete = existsSync7(join9(sessionPath, "context.md"));
|
|
23800
23834
|
const analysisComplete = changeContextComplete;
|
|
23801
23835
|
const reviewsComplete = state.phase_number > 4;
|
|
23802
|
-
const discourseComplete =
|
|
23803
|
-
const synthesisComplete =
|
|
23836
|
+
const discourseComplete = existsSync7(join9(currentRoundDir, "discourse.md"));
|
|
23837
|
+
const synthesisComplete = existsSync7(join9(currentRoundDir, "final.md"));
|
|
23804
23838
|
return {
|
|
23805
23839
|
workflowType: "review",
|
|
23806
23840
|
session,
|
|
@@ -23932,8 +23966,8 @@ var ReviewProgressStrategy = class {
|
|
|
23932
23966
|
var reviewStrategy = new ReviewProgressStrategy();
|
|
23933
23967
|
|
|
23934
23968
|
// src/lib/progress/map-strategy.ts
|
|
23935
|
-
import { existsSync as
|
|
23936
|
-
import { join as
|
|
23969
|
+
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync7 } from "node:fs";
|
|
23970
|
+
import { join as join10, basename as basename6 } from "node:path";
|
|
23937
23971
|
var MAP_PHASES = [
|
|
23938
23972
|
{ key: "map-context", label: "Context Discovery" },
|
|
23939
23973
|
{ key: "topology", label: "Topology Analysis" },
|
|
@@ -23943,8 +23977,8 @@ var MAP_PHASES = [
|
|
|
23943
23977
|
{ key: "complete", label: "Complete" }
|
|
23944
23978
|
];
|
|
23945
23979
|
function deriveRunsFromFilesystem(mapDir) {
|
|
23946
|
-
const runsDir =
|
|
23947
|
-
if (!
|
|
23980
|
+
const runsDir = join10(mapDir, "runs");
|
|
23981
|
+
if (!existsSync8(runsDir)) {
|
|
23948
23982
|
return [];
|
|
23949
23983
|
}
|
|
23950
23984
|
const runDirs = readdirSync4(runsDir).filter((d) => d.match(/^run-\d+$/)).sort((a, b) => {
|
|
@@ -23954,12 +23988,12 @@ function deriveRunsFromFilesystem(mapDir) {
|
|
|
23954
23988
|
});
|
|
23955
23989
|
return runDirs.map((dir) => {
|
|
23956
23990
|
const runNum = parseInt(dir.replace("run-", ""));
|
|
23957
|
-
const runPath =
|
|
23958
|
-
const mapPath =
|
|
23991
|
+
const runPath = join10(runsDir, dir);
|
|
23992
|
+
const mapPath = join10(runPath, "map.md");
|
|
23959
23993
|
let fileCount = 0;
|
|
23960
|
-
const topologyPath =
|
|
23961
|
-
if (
|
|
23962
|
-
const content =
|
|
23994
|
+
const topologyPath = join10(runPath, "topology.md");
|
|
23995
|
+
if (existsSync8(topologyPath)) {
|
|
23996
|
+
const content = readFileSync7(topologyPath, "utf-8");
|
|
23963
23997
|
const fileListMatch = content.match(
|
|
23964
23998
|
/## Canonical File List[\s\S]*?```([\s\S]*?)```/
|
|
23965
23999
|
);
|
|
@@ -23969,7 +24003,7 @@ function deriveRunsFromFilesystem(mapDir) {
|
|
|
23969
24003
|
}
|
|
23970
24004
|
return {
|
|
23971
24005
|
run: runNum,
|
|
23972
|
-
isComplete:
|
|
24006
|
+
isComplete: existsSync8(mapPath),
|
|
23973
24007
|
fileCount
|
|
23974
24008
|
};
|
|
23975
24009
|
});
|
|
@@ -24001,24 +24035,24 @@ var MapProgressStrategy = class {
|
|
|
24001
24035
|
parseFromState(session, state, sessionPath, preservedStartTime) {
|
|
24002
24036
|
const effectiveStartTime = state.map_started_at ?? state.started_at;
|
|
24003
24037
|
const startTime = preservedStartTime ?? (effectiveStartTime ? new Date(effectiveStartTime).getTime() : Date.now());
|
|
24004
|
-
const mapDir =
|
|
24038
|
+
const mapDir = join10(sessionPath, "map");
|
|
24005
24039
|
const runs = deriveRunsFromFilesystem(mapDir);
|
|
24006
24040
|
const highestExistingRun = runs.length > 0 ? Math.max(...runs.map((r) => r.run)) : 1;
|
|
24007
24041
|
const stateRun = state.current_map_run ?? 1;
|
|
24008
24042
|
const currentRun = Math.min(stateRun, highestExistingRun);
|
|
24009
|
-
const currentRunDir =
|
|
24010
|
-
const contextComplete =
|
|
24011
|
-
|
|
24043
|
+
const currentRunDir = join10(mapDir, "runs", `run-${currentRun}`);
|
|
24044
|
+
const contextComplete = existsSync8(
|
|
24045
|
+
join10(sessionPath, "discovered-standards.md")
|
|
24012
24046
|
);
|
|
24013
|
-
const topologyComplete =
|
|
24014
|
-
const flowAnalysisComplete =
|
|
24015
|
-
|
|
24047
|
+
const topologyComplete = existsSync8(join10(currentRunDir, "topology.md"));
|
|
24048
|
+
const flowAnalysisComplete = existsSync8(
|
|
24049
|
+
join10(currentRunDir, "flow-analysis.md")
|
|
24016
24050
|
);
|
|
24017
|
-
const requirementsMappingComplete =
|
|
24018
|
-
|
|
24051
|
+
const requirementsMappingComplete = existsSync8(
|
|
24052
|
+
join10(currentRunDir, "requirements-mapping.md")
|
|
24019
24053
|
);
|
|
24020
|
-
const synthesisComplete =
|
|
24021
|
-
const hasRequirements =
|
|
24054
|
+
const synthesisComplete = existsSync8(join10(currentRunDir, "map.md"));
|
|
24055
|
+
const hasRequirements = existsSync8(join10(sessionPath, "requirements.md"));
|
|
24022
24056
|
const flowAnalysts = flowAnalysisComplete ? [
|
|
24023
24057
|
{
|
|
24024
24058
|
name: "flow-analyst",
|
|
@@ -24170,15 +24204,15 @@ function debounce(fn, delay) {
|
|
|
24170
24204
|
};
|
|
24171
24205
|
}
|
|
24172
24206
|
function findLatestActiveSession(sessionsDir) {
|
|
24173
|
-
if (!
|
|
24207
|
+
if (!existsSync10(sessionsDir)) {
|
|
24174
24208
|
return null;
|
|
24175
24209
|
}
|
|
24176
24210
|
const sessions = readdirSync5(sessionsDir).filter((name) => {
|
|
24177
|
-
const sessionPath =
|
|
24211
|
+
const sessionPath = join12(sessionsDir, name);
|
|
24178
24212
|
return statSync(sessionPath).isDirectory();
|
|
24179
24213
|
}).sort().reverse();
|
|
24180
24214
|
for (const session of sessions) {
|
|
24181
|
-
const sessionPath =
|
|
24215
|
+
const sessionPath = join12(sessionsDir, session);
|
|
24182
24216
|
if (isSessionActive(sessionPath)) {
|
|
24183
24217
|
return session;
|
|
24184
24218
|
}
|
|
@@ -24193,8 +24227,8 @@ function getStrategyForSession(sessionPath, explicitWorkflow) {
|
|
|
24193
24227
|
return getStrategy(workflowType) ?? null;
|
|
24194
24228
|
}
|
|
24195
24229
|
async function initProgressDb(ocrDir) {
|
|
24196
|
-
const dbPath =
|
|
24197
|
-
if (!
|
|
24230
|
+
const dbPath = join12(ocrDir, "data", "ocr.db");
|
|
24231
|
+
if (!existsSync10(dbPath)) {
|
|
24198
24232
|
return;
|
|
24199
24233
|
}
|
|
24200
24234
|
try {
|
|
@@ -24219,11 +24253,11 @@ var progressCommand = new Command("progress").description("Watch real-time progr
|
|
|
24219
24253
|
const targetDir = process.cwd();
|
|
24220
24254
|
requireOcrSetup(targetDir);
|
|
24221
24255
|
const sessionsDir = ensureSessionsDir(targetDir);
|
|
24222
|
-
const ocrDir =
|
|
24256
|
+
const ocrDir = join12(targetDir, ".ocr");
|
|
24223
24257
|
await initProgressDb(ocrDir);
|
|
24224
24258
|
if (options.session) {
|
|
24225
|
-
const sessionPath =
|
|
24226
|
-
if (!
|
|
24259
|
+
const sessionPath = join12(sessionsDir, options.session);
|
|
24260
|
+
if (!existsSync10(sessionPath)) {
|
|
24227
24261
|
console.error(source_default.red(`Session not found: ${options.session}`));
|
|
24228
24262
|
process.exit(1);
|
|
24229
24263
|
}
|
|
@@ -24284,7 +24318,7 @@ var progressCommand = new Command("progress").description("Watch real-time progr
|
|
|
24284
24318
|
return;
|
|
24285
24319
|
}
|
|
24286
24320
|
let currentSession = findLatestActiveSession(sessionsDir);
|
|
24287
|
-
let currentSessionPath = currentSession ?
|
|
24321
|
+
let currentSessionPath = currentSession ? join12(sessionsDir, currentSession) : null;
|
|
24288
24322
|
let sessionWatcher = null;
|
|
24289
24323
|
const preservedStartTimes = {
|
|
24290
24324
|
review: void 0,
|
|
@@ -24292,11 +24326,11 @@ var progressCommand = new Command("progress").description("Watch real-time progr
|
|
|
24292
24326
|
};
|
|
24293
24327
|
let currentStrategy = null;
|
|
24294
24328
|
const updateDisplayImpl = () => {
|
|
24295
|
-
if (!currentSessionPath || !
|
|
24329
|
+
if (!currentSessionPath || !existsSync10(currentSessionPath) || !isSessionActive(currentSessionPath)) {
|
|
24296
24330
|
const latestActive = findLatestActiveSession(sessionsDir);
|
|
24297
24331
|
if (latestActive && latestActive !== currentSession) {
|
|
24298
24332
|
currentSession = latestActive;
|
|
24299
|
-
currentSessionPath =
|
|
24333
|
+
currentSessionPath = join12(sessionsDir, latestActive);
|
|
24300
24334
|
preservedStartTimes.review = void 0;
|
|
24301
24335
|
preservedStartTimes.map = void 0;
|
|
24302
24336
|
currentStrategy = null;
|
|
@@ -24309,7 +24343,7 @@ var progressCommand = new Command("progress").description("Watch real-time progr
|
|
|
24309
24343
|
currentStrategy = null;
|
|
24310
24344
|
}
|
|
24311
24345
|
}
|
|
24312
|
-
if (currentSessionPath &&
|
|
24346
|
+
if (currentSessionPath && existsSync10(currentSessionPath)) {
|
|
24313
24347
|
if (!options.workflow) {
|
|
24314
24348
|
const activeWorkflows = detectActiveWorkflows(currentSessionPath);
|
|
24315
24349
|
if (activeWorkflows.length > 1) {
|
|
@@ -24363,15 +24397,15 @@ var progressCommand = new Command("progress").description("Watch real-time progr
|
|
|
24363
24397
|
watchSession(currentSessionPath);
|
|
24364
24398
|
}
|
|
24365
24399
|
const timerInterval = setInterval(updateDisplay, 1e3);
|
|
24366
|
-
const watchDir =
|
|
24400
|
+
const watchDir = existsSync10(ocrDir) ? ocrDir : targetDir;
|
|
24367
24401
|
const dirWatcher = watch(watchDir, {
|
|
24368
24402
|
persistent: true,
|
|
24369
24403
|
ignoreInitial: true,
|
|
24370
24404
|
depth: 3
|
|
24371
24405
|
});
|
|
24372
24406
|
dirWatcher.on("addDir", (dirPath) => {
|
|
24373
|
-
const parentDir =
|
|
24374
|
-
const isDirectChild = parentDir.endsWith("sessions") || parentDir.endsWith(
|
|
24407
|
+
const parentDir = join12(dirPath, "..");
|
|
24408
|
+
const isDirectChild = parentDir.endsWith("sessions") || parentDir.endsWith(join12(".ocr", "sessions"));
|
|
24375
24409
|
if (isDirectChild && !dirPath.endsWith("sessions")) {
|
|
24376
24410
|
const newSession = basename7(dirPath);
|
|
24377
24411
|
currentSession = newSession;
|
|
@@ -24473,27 +24507,27 @@ function renderCombinedProgress(sessionPath, preservedStartTimes, ocrDir) {
|
|
|
24473
24507
|
}
|
|
24474
24508
|
|
|
24475
24509
|
// src/commands/state.ts
|
|
24476
|
-
import { existsSync as
|
|
24477
|
-
import { join as
|
|
24510
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync4 } from "node:fs";
|
|
24511
|
+
import { join as join14 } from "node:path";
|
|
24478
24512
|
|
|
24479
24513
|
// src/lib/state/index.ts
|
|
24480
24514
|
init_db();
|
|
24481
|
-
import { existsSync as
|
|
24482
|
-
import { join as
|
|
24515
|
+
import { existsSync as existsSync11, readdirSync as readdirSync6, statSync as statSync2 } from "node:fs";
|
|
24516
|
+
import { join as join13 } from "node:path";
|
|
24483
24517
|
async function stateInit(params) {
|
|
24484
24518
|
const { sessionId, branch, workflowType, sessionDir, ocrDir } = params;
|
|
24485
24519
|
const db = await ensureDatabase(ocrDir);
|
|
24486
|
-
const dbPath =
|
|
24520
|
+
const dbPath = join13(ocrDir, "data", "ocr.db");
|
|
24487
24521
|
const existing = getSession(db, sessionId);
|
|
24488
24522
|
if (existing) {
|
|
24489
|
-
const roundsDir =
|
|
24523
|
+
const roundsDir = join13(sessionDir, "rounds");
|
|
24490
24524
|
let nextRound = 1;
|
|
24491
|
-
if (
|
|
24525
|
+
if (existsSync11(roundsDir)) {
|
|
24492
24526
|
const roundDirs = readdirSync6(roundsDir).filter((d) => /^round-\d+$/.test(d)).map((d) => parseInt(d.replace("round-", ""), 10)).sort((a, b) => a - b);
|
|
24493
24527
|
if (roundDirs.length > 0) {
|
|
24494
24528
|
const highest = roundDirs[roundDirs.length - 1];
|
|
24495
|
-
const hasFinal =
|
|
24496
|
-
|
|
24529
|
+
const hasFinal = existsSync11(
|
|
24530
|
+
join13(roundsDir, `round-${highest}`, "final.md")
|
|
24497
24531
|
);
|
|
24498
24532
|
nextRound = hasFinal ? highest + 1 : highest;
|
|
24499
24533
|
}
|
|
@@ -24537,7 +24571,7 @@ async function stateInit(params) {
|
|
|
24537
24571
|
async function stateTransition(params) {
|
|
24538
24572
|
const { sessionId, phase, phaseNumber, round, mapRun, ocrDir } = params;
|
|
24539
24573
|
const db = await ensureDatabase(ocrDir);
|
|
24540
|
-
const dbPath =
|
|
24574
|
+
const dbPath = join13(ocrDir, "data", "ocr.db");
|
|
24541
24575
|
const existing = getSession(db, sessionId);
|
|
24542
24576
|
if (!existing) {
|
|
24543
24577
|
throw new Error(`Session not found: ${sessionId}`);
|
|
@@ -24570,7 +24604,7 @@ async function stateTransition(params) {
|
|
|
24570
24604
|
async function stateClose(params) {
|
|
24571
24605
|
const { sessionId, ocrDir } = params;
|
|
24572
24606
|
const db = await ensureDatabase(ocrDir);
|
|
24573
|
-
const dbPath =
|
|
24607
|
+
const dbPath = join13(ocrDir, "data", "ocr.db");
|
|
24574
24608
|
const existing = getSession(db, sessionId);
|
|
24575
24609
|
if (!existing) {
|
|
24576
24610
|
throw new Error(`Session not found: ${sessionId}`);
|
|
@@ -24637,24 +24671,24 @@ async function resolveActiveSession(ocrDir) {
|
|
|
24637
24671
|
}
|
|
24638
24672
|
async function stateSync(ocrDir) {
|
|
24639
24673
|
const db = await ensureDatabase(ocrDir);
|
|
24640
|
-
const dbPath =
|
|
24641
|
-
const sessionsRoot =
|
|
24642
|
-
if (!
|
|
24674
|
+
const dbPath = join13(ocrDir, "data", "ocr.db");
|
|
24675
|
+
const sessionsRoot = join13(ocrDir, "sessions");
|
|
24676
|
+
if (!existsSync11(sessionsRoot)) {
|
|
24643
24677
|
return 0;
|
|
24644
24678
|
}
|
|
24645
24679
|
const entries = readdirSync6(sessionsRoot).filter((name) => {
|
|
24646
|
-
const fullPath =
|
|
24680
|
+
const fullPath = join13(sessionsRoot, name);
|
|
24647
24681
|
return statSync2(fullPath).isDirectory();
|
|
24648
24682
|
});
|
|
24649
24683
|
let synced = 0;
|
|
24650
24684
|
for (const dirName of entries) {
|
|
24651
|
-
const dirPath =
|
|
24685
|
+
const dirPath = join13(sessionsRoot, dirName);
|
|
24652
24686
|
const existing = getSession(db, dirName);
|
|
24653
24687
|
if (existing) {
|
|
24654
24688
|
continue;
|
|
24655
24689
|
}
|
|
24656
|
-
const hasRoundsDir =
|
|
24657
|
-
const hasMapDir =
|
|
24690
|
+
const hasRoundsDir = existsSync11(join13(dirPath, "rounds"));
|
|
24691
|
+
const hasMapDir = existsSync11(join13(dirPath, "map"));
|
|
24658
24692
|
const workflowType = hasMapDir && !hasRoundsDir ? "map" : "review";
|
|
24659
24693
|
const branchMatch = dirName.match(/^\d{4}-\d{2}-\d{2}-(.+)$/);
|
|
24660
24694
|
const branch = branchMatch?.[1] ?? dirName;
|
|
@@ -24699,9 +24733,9 @@ var initSubcommand = new Command("init").description("Initialize a new OCR sessi
|
|
|
24699
24733
|
async (options) => {
|
|
24700
24734
|
const targetDir = process.cwd();
|
|
24701
24735
|
requireOcrSetup(targetDir);
|
|
24702
|
-
const ocrDir =
|
|
24703
|
-
const sessionDir = options.sessionDir ??
|
|
24704
|
-
if (!
|
|
24736
|
+
const ocrDir = join14(targetDir, ".ocr");
|
|
24737
|
+
const sessionDir = options.sessionDir ?? join14(ocrDir, "sessions", options.sessionId);
|
|
24738
|
+
if (!existsSync12(sessionDir)) {
|
|
24705
24739
|
mkdirSync4(sessionDir, { recursive: true });
|
|
24706
24740
|
}
|
|
24707
24741
|
try {
|
|
@@ -24727,7 +24761,7 @@ var transitionSubcommand = new Command("transition").description("Transition ses
|
|
|
24727
24761
|
async (options) => {
|
|
24728
24762
|
const targetDir = process.cwd();
|
|
24729
24763
|
requireOcrSetup(targetDir);
|
|
24730
|
-
const ocrDir =
|
|
24764
|
+
const ocrDir = join14(targetDir, ".ocr");
|
|
24731
24765
|
try {
|
|
24732
24766
|
const sessionId = options.sessionId ?? (await resolveActiveSession(ocrDir)).id;
|
|
24733
24767
|
await stateTransition({
|
|
@@ -24754,7 +24788,7 @@ var transitionSubcommand = new Command("transition").description("Transition ses
|
|
|
24754
24788
|
var closeSubcommand = new Command("close").description("Close a session").option("--session-id <id>", "Session ID (auto-detects latest active if omitted)").action(async (options) => {
|
|
24755
24789
|
const targetDir = process.cwd();
|
|
24756
24790
|
requireOcrSetup(targetDir);
|
|
24757
|
-
const ocrDir =
|
|
24791
|
+
const ocrDir = join14(targetDir, ".ocr");
|
|
24758
24792
|
try {
|
|
24759
24793
|
const sessionId = options.sessionId ?? (await resolveActiveSession(ocrDir)).id;
|
|
24760
24794
|
await stateClose({
|
|
@@ -24774,7 +24808,7 @@ var closeSubcommand = new Command("close").description("Close a session").option
|
|
|
24774
24808
|
var showSubcommand = new Command("show").description("Show current session state").option("--session-id <id>", "Session ID (defaults to latest active)").option("--json", "Output as JSON").action(async (options) => {
|
|
24775
24809
|
const targetDir = process.cwd();
|
|
24776
24810
|
requireOcrSetup(targetDir);
|
|
24777
|
-
const ocrDir =
|
|
24811
|
+
const ocrDir = join14(targetDir, ".ocr");
|
|
24778
24812
|
try {
|
|
24779
24813
|
const result = await stateShow(ocrDir, options.sessionId);
|
|
24780
24814
|
if (!result) {
|
|
@@ -24843,7 +24877,7 @@ var showSubcommand = new Command("show").description("Show current session state
|
|
|
24843
24877
|
var syncSubcommand = new Command("sync").description("Rebuild session state from filesystem artifacts").action(async () => {
|
|
24844
24878
|
const targetDir = process.cwd();
|
|
24845
24879
|
requireOcrSetup(targetDir);
|
|
24846
|
-
const ocrDir =
|
|
24880
|
+
const ocrDir = join14(targetDir, ".ocr");
|
|
24847
24881
|
try {
|
|
24848
24882
|
const synced = await stateSync(ocrDir);
|
|
24849
24883
|
console.log(`Synced ${synced} session${synced !== 1 ? "s" : ""} from filesystem.`);
|
|
@@ -24859,16 +24893,16 @@ var syncSubcommand = new Command("sync").description("Rebuild session state from
|
|
|
24859
24893
|
var stateCommand = new Command("state").description("Manage OCR session state").addCommand(initSubcommand).addCommand(transitionSubcommand).addCommand(closeSubcommand).addCommand(showSubcommand).addCommand(syncSubcommand);
|
|
24860
24894
|
|
|
24861
24895
|
// src/commands/update.ts
|
|
24862
|
-
import { existsSync as
|
|
24863
|
-
import { join as
|
|
24896
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
24897
|
+
import { join as join15 } from "node:path";
|
|
24864
24898
|
function detectConfiguredTools(targetDir) {
|
|
24865
24899
|
return AI_TOOLS.filter((tool) => {
|
|
24866
24900
|
if (tool.commandStrategy === "subdirectory") {
|
|
24867
|
-
const ocrDir =
|
|
24868
|
-
return
|
|
24901
|
+
const ocrDir = join15(targetDir, tool.commandsDir, "ocr");
|
|
24902
|
+
return existsSync13(ocrDir);
|
|
24869
24903
|
} else {
|
|
24870
|
-
const reviewCmd =
|
|
24871
|
-
return
|
|
24904
|
+
const reviewCmd = join15(targetDir, tool.commandsDir, "ocr-review.md");
|
|
24905
|
+
return existsSync13(reviewCmd);
|
|
24872
24906
|
}
|
|
24873
24907
|
});
|
|
24874
24908
|
}
|
|
@@ -24942,6 +24976,7 @@ var updateCommand = new Command("update").description("Update OCR assets after p
|
|
|
24942
24976
|
const result = installForTool(tool, targetDir);
|
|
24943
24977
|
results.push(result);
|
|
24944
24978
|
}
|
|
24979
|
+
ensureGitignore(join15(targetDir, ".ocr"));
|
|
24945
24980
|
spinner.stop();
|
|
24946
24981
|
const successful = results.filter((r) => r.success);
|
|
24947
24982
|
const failed = results.filter((r) => !r.success);
|
|
@@ -24977,10 +25012,10 @@ var updateCommand = new Command("update").description("Update OCR assets after p
|
|
|
24977
25012
|
if (updateInject) {
|
|
24978
25013
|
if (options.dryRun) {
|
|
24979
25014
|
console.log(source_default.dim(" Would update:"));
|
|
24980
|
-
if (
|
|
25015
|
+
if (existsSync13(join15(targetDir, "AGENTS.md"))) {
|
|
24981
25016
|
console.log(source_default.dim(" \u2022 AGENTS.md (OCR managed block)"));
|
|
24982
25017
|
}
|
|
24983
|
-
if (
|
|
25018
|
+
if (existsSync13(join15(targetDir, "CLAUDE.md"))) {
|
|
24984
25019
|
console.log(source_default.dim(" \u2022 CLAUDE.md (OCR managed block)"));
|
|
24985
25020
|
}
|
|
24986
25021
|
console.log();
|
|
@@ -25011,14 +25046,14 @@ var updateCommand = new Command("update").description("Update OCR assets after p
|
|
|
25011
25046
|
});
|
|
25012
25047
|
|
|
25013
25048
|
// src/commands/dashboard.ts
|
|
25014
|
-
import { existsSync as
|
|
25015
|
-
import { join as
|
|
25049
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
25050
|
+
import { join as join16, dirname as dirname5 } from "node:path";
|
|
25016
25051
|
import { fileURLToPath } from "node:url";
|
|
25017
25052
|
init_db();
|
|
25018
25053
|
var __filename = fileURLToPath(import.meta.url);
|
|
25019
25054
|
var __dirname = dirname5(__filename);
|
|
25020
25055
|
function resolveServerPath() {
|
|
25021
|
-
return
|
|
25056
|
+
return join16(__dirname, "dashboard", "server.js");
|
|
25022
25057
|
}
|
|
25023
25058
|
var dashboardCommand = new Command("dashboard").description("Start the OCR dashboard web interface").option("-p, --port <port>", "Port to run the server on", "4173").option("--no-open", "Don't open the browser automatically").action(
|
|
25024
25059
|
async (options) => {
|
|
@@ -25029,7 +25064,7 @@ var dashboardCommand = new Command("dashboard").description("Start the OCR dashb
|
|
|
25029
25064
|
console.error(source_default.red(`Error: Invalid port "${options.port}". Must be 1-65535.`));
|
|
25030
25065
|
process.exit(1);
|
|
25031
25066
|
}
|
|
25032
|
-
const ocrDir =
|
|
25067
|
+
const ocrDir = join16(targetDir, ".ocr");
|
|
25033
25068
|
try {
|
|
25034
25069
|
await ensureDatabase(ocrDir);
|
|
25035
25070
|
closeAllDatabases();
|
|
@@ -25043,7 +25078,7 @@ var dashboardCommand = new Command("dashboard").description("Start the OCR dashb
|
|
|
25043
25078
|
process.exit(1);
|
|
25044
25079
|
}
|
|
25045
25080
|
const serverPath = resolveServerPath();
|
|
25046
|
-
if (!
|
|
25081
|
+
if (!existsSync14(serverPath)) {
|
|
25047
25082
|
console.error(source_default.red("Error: Dashboard server bundle not found."));
|
|
25048
25083
|
console.error(
|
|
25049
25084
|
source_default.dim(` Expected at: ${serverPath}`)
|
|
@@ -25077,8 +25112,8 @@ var dashboardCommand = new Command("dashboard").description("Start the OCR dashb
|
|
|
25077
25112
|
);
|
|
25078
25113
|
|
|
25079
25114
|
// src/commands/doctor.ts
|
|
25080
|
-
import { existsSync as
|
|
25081
|
-
import { join as
|
|
25115
|
+
import { existsSync as existsSync15 } from "node:fs";
|
|
25116
|
+
import { join as join17 } from "node:path";
|
|
25082
25117
|
var doctorCommand = new Command("doctor").description("Check OCR installation and verify all dependencies").action(() => {
|
|
25083
25118
|
printHeader();
|
|
25084
25119
|
const targetDir = process.cwd();
|
|
@@ -25092,10 +25127,10 @@ var doctorCommand = new Command("doctor").description("Check OCR installation an
|
|
|
25092
25127
|
console.log(source_default.bold(" OCR Installation"));
|
|
25093
25128
|
console.log();
|
|
25094
25129
|
const ocrStatus = checkOcrSetup(targetDir);
|
|
25095
|
-
const configPath =
|
|
25096
|
-
const dbPath =
|
|
25097
|
-
const hasConfig =
|
|
25098
|
-
const hasDb =
|
|
25130
|
+
const configPath = join17(targetDir, ".ocr", "config.yaml");
|
|
25131
|
+
const dbPath = join17(targetDir, ".ocr", "data", "ocr.db");
|
|
25132
|
+
const hasConfig = existsSync15(configPath);
|
|
25133
|
+
const hasDb = existsSync15(dbPath);
|
|
25099
25134
|
const ocrChecks = [
|
|
25100
25135
|
{ label: ".ocr/skills/", ok: ocrStatus.hasSkills },
|
|
25101
25136
|
{ label: ".ocr/sessions/", ok: ocrStatus.hasSessions },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-code-review/cli",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "CLI for Open Code Review - Multi-environment setup and progress tracking",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"ora": "^8.1.1",
|
|
51
51
|
"socket.io": "^4.8",
|
|
52
52
|
"sql.js": "^1.14.1",
|
|
53
|
-
"@open-code-review/agents": "1.5.
|
|
53
|
+
"@open-code-review/agents": "1.5.1"
|
|
54
54
|
},
|
|
55
55
|
"publishConfig": {
|
|
56
56
|
"access": "public"
|