@open-code-review/cli 1.8.4 → 1.10.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.
@@ -1,8 +1,8 @@
1
1
  import { createRequire as _cjsReq } from "module"; const require = _cjsReq(import.meta.url);
2
2
 
3
3
  // src/lib/db/index.ts
4
- import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
5
- import { dirname, join } from "node:path";
4
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
5
+ import { dirname as dirname2, join as join2 } from "node:path";
6
6
  import { createRequire } from "node:module";
7
7
  import initSqlJs from "sql.js";
8
8
 
@@ -253,6 +253,14 @@ var MIGRATIONS = [
253
253
  ALTER TABLE map_runs ADD COLUMN source TEXT DEFAULT NULL;
254
254
  ALTER TABLE map_runs ADD COLUMN section_count INTEGER DEFAULT 0;
255
255
  `
256
+ },
257
+ {
258
+ version: 9,
259
+ description: "Add uid column to command_executions for JSONL-backed recovery",
260
+ sql: `
261
+ ALTER TABLE command_executions ADD COLUMN uid TEXT;
262
+ CREATE UNIQUE INDEX idx_command_executions_uid ON command_executions(uid);
263
+ `
256
264
  }
257
265
  ];
258
266
  function ensureSchemaVersionTable(db) {
@@ -424,12 +432,109 @@ function getLatestEventId(db) {
424
432
  return typeof val === "number" ? val : 0;
425
433
  }
426
434
 
435
+ // src/lib/db/command-log.ts
436
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
437
+ import { dirname, join } from "node:path";
438
+ import { randomUUID } from "node:crypto";
439
+ var CACHE_DIR = ".cache";
440
+ var FILENAME = "command-history.jsonl";
441
+ var MAX_LINES = 5e3;
442
+ var KEEP_LINES = 4e3;
443
+ var approxLineCount = -1;
444
+ function generateCommandUid() {
445
+ return randomUUID();
446
+ }
447
+ function cacheDir(ocrDir) {
448
+ return join(ocrDir, "data", CACHE_DIR);
449
+ }
450
+ function commandLogPath(ocrDir) {
451
+ return join(cacheDir(ocrDir), FILENAME);
452
+ }
453
+ function appendCommandLog(ocrDir, entry) {
454
+ try {
455
+ const filePath = commandLogPath(ocrDir);
456
+ const dir = dirname(filePath);
457
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
458
+ const line = JSON.stringify(entry) + "\n";
459
+ appendFileSync(filePath, line, { encoding: "utf-8" });
460
+ if (approxLineCount >= 0) approxLineCount++;
461
+ rotateIfNeeded(filePath);
462
+ } catch {
463
+ }
464
+ }
465
+ function readCommandLog(ocrDir) {
466
+ const filePath = commandLogPath(ocrDir);
467
+ if (!existsSync(filePath)) return [];
468
+ const content = readFileSync(filePath, "utf-8");
469
+ const entries = [];
470
+ for (const line of content.split("\n")) {
471
+ if (!line.trim()) continue;
472
+ try {
473
+ entries.push(JSON.parse(line));
474
+ } catch {
475
+ }
476
+ }
477
+ return entries;
478
+ }
479
+ function replayCommandLog(db, ocrDir) {
480
+ const entries = readCommandLog(ocrDir);
481
+ if (entries.length === 0) return 0;
482
+ const latest = /* @__PURE__ */ new Map();
483
+ for (const entry of entries) {
484
+ if (!entry.uid || !entry.command || !entry.started_at) continue;
485
+ const existing = latest.get(entry.uid);
486
+ if (!existing || entry.event !== "start") {
487
+ latest.set(entry.uid, entry);
488
+ }
489
+ }
490
+ let imported = 0;
491
+ for (const entry of latest.values()) {
492
+ if (entry.event === "start" && !entry.finished_at) continue;
493
+ const existing = db.exec(
494
+ "SELECT COUNT(*) as c FROM command_executions WHERE uid = ?",
495
+ [entry.uid]
496
+ );
497
+ if ((existing[0]?.values[0]?.[0] ?? 0) > 0) continue;
498
+ db.run(
499
+ `INSERT INTO command_executions
500
+ (uid, command, args, exit_code, started_at, finished_at, pid, is_detached)
501
+ VALUES (?, ?, ?, ?, ?, ?, NULL, ?)`,
502
+ [
503
+ entry.uid,
504
+ entry.command,
505
+ entry.args,
506
+ entry.exit_code,
507
+ entry.started_at,
508
+ entry.finished_at,
509
+ entry.is_detached
510
+ ]
511
+ );
512
+ imported++;
513
+ }
514
+ return imported;
515
+ }
516
+ function rotateIfNeeded(filePath) {
517
+ try {
518
+ if (approxLineCount >= 0 && approxLineCount <= MAX_LINES) return;
519
+ const content = readFileSync(filePath, "utf-8");
520
+ const lines = content.split("\n").filter((l) => l.trim());
521
+ approxLineCount = lines.length;
522
+ if (approxLineCount <= MAX_LINES) return;
523
+ const kept = lines.slice(lines.length - KEEP_LINES);
524
+ const tmpPath = `${filePath}.${process.pid}.tmp`;
525
+ writeFileSync(tmpPath, kept.join("\n") + "\n", { encoding: "utf-8" });
526
+ renameSync(tmpPath, filePath);
527
+ approxLineCount = KEEP_LINES;
528
+ } catch {
529
+ }
530
+ }
531
+
427
532
  // src/lib/db/index.ts
428
533
  var connections = /* @__PURE__ */ new Map();
429
534
  function locateWasm() {
430
535
  const require2 = createRequire(import.meta.url);
431
536
  const sqlJsPath = require2.resolve("sql.js");
432
- return join(dirname(sqlJsPath), "sql-wasm.wasm");
537
+ return join2(dirname2(sqlJsPath), "sql-wasm.wasm");
433
538
  }
434
539
  function applyPragmas(db) {
435
540
  db.run("PRAGMA foreign_keys = ON;");
@@ -441,7 +546,7 @@ async function openDatabase(dbPath) {
441
546
  if (cached) {
442
547
  return cached;
443
548
  }
444
- const wasmBuffer = readFileSync(locateWasm());
549
+ const wasmBuffer = readFileSync2(locateWasm());
445
550
  const wasmBinary = wasmBuffer.buffer.slice(
446
551
  wasmBuffer.byteOffset,
447
552
  wasmBuffer.byteOffset + wasmBuffer.byteLength
@@ -450,8 +555,8 @@ async function openDatabase(dbPath) {
450
555
  wasmBinary
451
556
  });
452
557
  let db;
453
- if (existsSync(dbPath)) {
454
- const fileBuffer = readFileSync(dbPath);
558
+ if (existsSync2(dbPath)) {
559
+ const fileBuffer = readFileSync2(dbPath);
455
560
  db = new SQL.Database(fileBuffer);
456
561
  } else {
457
562
  db = new SQL.Database();
@@ -462,24 +567,24 @@ async function openDatabase(dbPath) {
462
567
  }
463
568
  function saveDatabase(db, dbPath) {
464
569
  const data = db.export();
465
- const dir = dirname(dbPath);
466
- if (!existsSync(dir)) {
467
- mkdirSync(dir, { recursive: true });
570
+ const dir = dirname2(dbPath);
571
+ if (!existsSync2(dir)) {
572
+ mkdirSync2(dir, { recursive: true });
468
573
  }
469
- const tmpPath = dbPath + ".tmp";
470
- writeFileSync(tmpPath, Buffer.from(data));
471
- renameSync(tmpPath, dbPath);
574
+ const tmpPath = `${dbPath}.${process.pid}.tmp`;
575
+ writeFileSync2(tmpPath, Buffer.from(data));
576
+ renameSync2(tmpPath, dbPath);
472
577
  }
473
578
  async function getDb(ocrDir) {
474
- const dbPath = join(ocrDir, "data", "ocr.db");
579
+ const dbPath = join2(ocrDir, "data", "ocr.db");
475
580
  return openDatabase(dbPath);
476
581
  }
477
582
  async function ensureDatabase(ocrDir) {
478
- const dataDir = join(ocrDir, "data");
479
- if (!existsSync(dataDir)) {
480
- mkdirSync(dataDir, { recursive: true });
583
+ const dataDir = join2(ocrDir, "data");
584
+ if (!existsSync2(dataDir)) {
585
+ mkdirSync2(dataDir, { recursive: true });
481
586
  }
482
- const dbPath = join(dataDir, "ocr.db");
587
+ const dbPath = join2(dataDir, "ocr.db");
483
588
  const db = await openDatabase(dbPath);
484
589
  runMigrations(db);
485
590
  saveDatabase(db, dbPath);
@@ -500,10 +605,14 @@ function closeAllDatabases() {
500
605
  }
501
606
  export {
502
607
  MIGRATIONS,
608
+ appendCommandLog,
503
609
  applyPragmas,
610
+ cacheDir,
504
611
  closeAllDatabases,
505
612
  closeDatabase,
613
+ commandLogPath,
506
614
  ensureDatabase,
615
+ generateCommandUid,
507
616
  getAllSessions,
508
617
  getDb,
509
618
  getEventsForSession,
@@ -514,6 +623,8 @@ export {
514
623
  insertSession,
515
624
  locateWasm,
516
625
  openDatabase,
626
+ readCommandLog,
627
+ replayCommandLog,
517
628
  resultToRow,
518
629
  resultToRows,
519
630
  runMigrations,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-code-review/cli",
3
- "version": "1.8.4",
3
+ "version": "1.10.0",
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.8.4"
53
+ "@open-code-review/agents": "1.10.0"
54
54
  },
55
55
  "publishConfig": {
56
56
  "access": "public"