@open-code-review/cli 1.10.0 → 1.10.2

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.
@@ -22752,7 +22752,7 @@ async function defaultBrowserId() {
22752
22752
  if (process4.platform !== "darwin") {
22753
22753
  throw new Error("macOS only");
22754
22754
  }
22755
- const { stdout } = await execFileAsync2("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
22755
+ const { stdout } = await execFileAsync("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
22756
22756
  const match = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
22757
22757
  const browserId = match?.groups.id ?? "com.apple.Safari";
22758
22758
  if (browserId === "com.apple.safari") {
@@ -22760,17 +22760,17 @@ async function defaultBrowserId() {
22760
22760
  }
22761
22761
  return browserId;
22762
22762
  }
22763
- var execFileAsync2;
22763
+ var execFileAsync;
22764
22764
  var init_default_browser_id = __esm({
22765
22765
  "../../node_modules/.pnpm/default-browser-id@5.0.1/node_modules/default-browser-id/index.js"() {
22766
- execFileAsync2 = promisify2(execFile2);
22766
+ execFileAsync = promisify2(execFile2);
22767
22767
  }
22768
22768
  });
22769
22769
 
22770
22770
  // ../../node_modules/.pnpm/run-applescript@7.1.0/node_modules/run-applescript/index.js
22771
22771
  import process5 from "node:process";
22772
22772
  import { promisify as promisify3 } from "node:util";
22773
- import { execFile as execFile3, execFileSync as execFileSync4 } from "node:child_process";
22773
+ import { execFile as execFile3, execFileSync as execFileSync2 } from "node:child_process";
22774
22774
  async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
22775
22775
  if (process5.platform !== "darwin") {
22776
22776
  throw new Error("macOS only");
@@ -22780,13 +22780,13 @@ async function runAppleScript(script, { humanReadableOutput = true, signal } = {
22780
22780
  if (signal) {
22781
22781
  execOptions.signal = signal;
22782
22782
  }
22783
- const { stdout } = await execFileAsync3("osascript", ["-e", script, outputArguments], execOptions);
22783
+ const { stdout } = await execFileAsync2("osascript", ["-e", script, outputArguments], execOptions);
22784
22784
  return stdout.trim();
22785
22785
  }
22786
- var execFileAsync3;
22786
+ var execFileAsync2;
22787
22787
  var init_run_applescript = __esm({
22788
22788
  "../../node_modules/.pnpm/run-applescript@7.1.0/node_modules/run-applescript/index.js"() {
22789
- execFileAsync3 = promisify3(execFile3);
22789
+ execFileAsync2 = promisify3(execFile3);
22790
22790
  }
22791
22791
  });
22792
22792
 
@@ -22804,7 +22804,7 @@ var init_bundle_name = __esm({
22804
22804
  // ../../node_modules/.pnpm/default-browser@5.5.0/node_modules/default-browser/windows.js
22805
22805
  import { promisify as promisify4 } from "node:util";
22806
22806
  import { execFile as execFile4 } from "node:child_process";
22807
- async function defaultBrowser(_execFileAsync = execFileAsync4) {
22807
+ async function defaultBrowser(_execFileAsync = execFileAsync3) {
22808
22808
  const { stdout } = await _execFileAsync("reg", [
22809
22809
  "QUERY",
22810
22810
  " HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
@@ -22822,10 +22822,10 @@ async function defaultBrowser(_execFileAsync = execFileAsync4) {
22822
22822
  const baseIdByHyphen = hyphenIndex === -1 ? void 0 : id.slice(0, hyphenIndex);
22823
22823
  return windowsBrowserProgIds[id] ?? windowsBrowserProgIds[baseIdByDot] ?? windowsBrowserProgIds[baseIdByHyphen] ?? { name: id, id };
22824
22824
  }
22825
- var execFileAsync4, windowsBrowserProgIds, _windowsBrowserProgIdMap, UnknownBrowserError;
22825
+ var execFileAsync3, windowsBrowserProgIds, _windowsBrowserProgIdMap, UnknownBrowserError;
22826
22826
  var init_windows = __esm({
22827
22827
  "../../node_modules/.pnpm/default-browser@5.5.0/node_modules/default-browser/windows.js"() {
22828
- execFileAsync4 = promisify4(execFile4);
22828
+ execFileAsync3 = promisify4(execFile4);
22829
22829
  windowsBrowserProgIds = {
22830
22830
  MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
22831
22831
  // The missing `L` is correct.
@@ -22862,7 +22862,7 @@ async function defaultBrowser2() {
22862
22862
  return { name, id };
22863
22863
  }
22864
22864
  if (process6.platform === "linux") {
22865
- const { stdout } = await execFileAsync5("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
22865
+ const { stdout } = await execFileAsync4("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
22866
22866
  const id = stdout.trim();
22867
22867
  const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
22868
22868
  return { name, id };
@@ -22872,13 +22872,13 @@ async function defaultBrowser2() {
22872
22872
  }
22873
22873
  throw new Error("Only macOS, Linux, and Windows are supported");
22874
22874
  }
22875
- var execFileAsync5, titleize;
22875
+ var execFileAsync4, titleize;
22876
22876
  var init_default_browser = __esm({
22877
22877
  "../../node_modules/.pnpm/default-browser@5.5.0/node_modules/default-browser/index.js"() {
22878
22878
  init_default_browser_id();
22879
22879
  init_bundle_name();
22880
22880
  init_windows();
22881
- execFileAsync5 = promisify5(execFile5);
22881
+ execFileAsync4 = promisify5(execFile5);
22882
22882
  titleize = (string) => string.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
22883
22883
  }
22884
22884
  });
@@ -24901,8 +24901,35 @@ function createStatsRouter(db) {
24901
24901
  // src/server/routes/commands.ts
24902
24902
  var import_express8 = __toESM(require_express2(), 1);
24903
24903
 
24904
+ // ../shared/platform/src/index.ts
24905
+ import {
24906
+ execFile,
24907
+ execFileSync,
24908
+ spawn
24909
+ } from "node:child_process";
24910
+ import { promisify } from "node:util";
24911
+ var execFilePromise = promisify(execFile);
24912
+ var isWindows = process.platform === "win32";
24913
+ function execBinary(binary, args, opts) {
24914
+ return execFileSync(binary, args, {
24915
+ ...opts,
24916
+ shell: isWindows
24917
+ });
24918
+ }
24919
+ async function execBinaryAsync(binary, args, opts) {
24920
+ return execFilePromise(binary, args, {
24921
+ ...opts,
24922
+ shell: isWindows
24923
+ });
24924
+ }
24925
+ function spawnBinary(binary, args, opts) {
24926
+ return spawn(binary, args, {
24927
+ ...opts,
24928
+ ...isWindows && { shell: true, windowsHide: true }
24929
+ });
24930
+ }
24931
+
24904
24932
  // src/server/socket/command-runner.ts
24905
- import { spawn as spawn3 } from "node:child_process";
24906
24933
  import { readFileSync as readFileSync4 } from "node:fs";
24907
24934
  import { dirname as dirname6, join as join8 } from "node:path";
24908
24935
 
@@ -24910,10 +24937,6 @@ import { dirname as dirname6, join as join8 } from "node:path";
24910
24937
  import { readFileSync as readFileSync3 } from "node:fs";
24911
24938
  import { join as join6 } from "node:path";
24912
24939
 
24913
- // src/server/services/ai-cli/claude-adapter.ts
24914
- import { execFileSync } from "node:child_process";
24915
- import { spawn } from "node:child_process";
24916
-
24917
24940
  // src/server/services/ai-cli/helpers.ts
24918
24941
  import { tmpdir } from "node:os";
24919
24942
  import { join as join5 } from "node:path";
@@ -24992,7 +25015,7 @@ var ClaudeCodeAdapter = class {
24992
25015
  binary = "claude";
24993
25016
  detect() {
24994
25017
  try {
24995
- const output = execFileSync("claude", ["--version"], {
25018
+ const output = execBinary("claude", ["--version"], {
24996
25019
  encoding: "utf-8",
24997
25020
  timeout: 5e3,
24998
25021
  stdio: ["ignore", "pipe", "pipe"]
@@ -25021,7 +25044,7 @@ var ClaudeCodeAdapter = class {
25021
25044
  if (opts.resumeSessionId) {
25022
25045
  flags.push("--resume", opts.resumeSessionId);
25023
25046
  }
25024
- const proc = spawn("claude", flags, {
25047
+ const proc = spawnBinary("claude", flags, {
25025
25048
  cwd: opts.cwd,
25026
25049
  env: cleanEnv(),
25027
25050
  detached: isWorkflow,
@@ -25091,7 +25114,6 @@ var ClaudeCodeAdapter = class {
25091
25114
  };
25092
25115
 
25093
25116
  // src/server/services/ai-cli/opencode-adapter.ts
25094
- import { execFileSync as execFileSync2, spawn as spawn2 } from "node:child_process";
25095
25117
  function capitalize(s) {
25096
25118
  return s.charAt(0).toUpperCase() + s.slice(1);
25097
25119
  }
@@ -25100,7 +25122,7 @@ var OpenCodeAdapter = class {
25100
25122
  binary = "opencode";
25101
25123
  detect() {
25102
25124
  try {
25103
- const output = execFileSync2("opencode", ["--version"], {
25125
+ const output = execBinary("opencode", ["--version"], {
25104
25126
  encoding: "utf-8",
25105
25127
  timeout: 5e3,
25106
25128
  stdio: ["ignore", "pipe", "pipe"]
@@ -25126,7 +25148,7 @@ var OpenCodeAdapter = class {
25126
25148
  if (opts.resumeSessionId) {
25127
25149
  args.push("--session", opts.resumeSessionId, "--continue");
25128
25150
  }
25129
- const proc = spawn2("opencode", args, {
25151
+ const proc = spawnBinary("opencode", args, {
25130
25152
  cwd: opts.cwd,
25131
25153
  env: cleanEnv(),
25132
25154
  detached: isWorkflow,
@@ -25467,10 +25489,10 @@ function registerCommandHandlers(io2, socket, db, ocrDir, aiCliService) {
25467
25489
  function spawnCliCommand(io2, db, ocrDir, executionId, baseCommand, subArgs, entry) {
25468
25490
  const localCli = resolveLocalCli();
25469
25491
  const repoRoot = dirname6(ocrDir);
25470
- const proc = localCli ? spawn3("node", [localCli, baseCommand, ...subArgs], {
25492
+ const proc = localCli ? spawnBinary("node", [localCli, baseCommand, ...subArgs], {
25471
25493
  cwd: repoRoot,
25472
25494
  env: cleanEnv()
25473
- }) : spawn3("ocr", [baseCommand, ...subArgs], {
25495
+ }) : spawnBinary("ocr", [baseCommand, ...subArgs], {
25474
25496
  cwd: repoRoot,
25475
25497
  env: cleanEnv()
25476
25498
  });
@@ -25811,7 +25833,6 @@ function createCommandsRouter(db) {
25811
25833
  // src/server/routes/config.ts
25812
25834
  var import_express9 = __toESM(require_express2(), 1);
25813
25835
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
25814
- import { execFileSync as execFileSync3 } from "node:child_process";
25815
25836
  import { join as join9, dirname as dirname7, basename } from "node:path";
25816
25837
  var VALID_IDES = ["vscode", "cursor", "windsurf", "jetbrains", "sublime"];
25817
25838
  function detectIde() {
@@ -25846,7 +25867,7 @@ function resolveIde(ocrDir) {
25846
25867
  }
25847
25868
  function detectGitBranch(cwd) {
25848
25869
  try {
25849
- return execFileSync3("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
25870
+ return execBinary("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
25850
25871
  cwd,
25851
25872
  timeout: 3e3,
25852
25873
  encoding: "utf-8"
@@ -26322,7 +26343,7 @@ var FilesystemSync = class {
26322
26343
  }
26323
26344
  let phase = "context";
26324
26345
  let phaseNumber = 1;
26325
- let status = "active";
26346
+ let status = "closed";
26326
26347
  if (workflowType === "review" && hasRoundsDir) {
26327
26348
  const roundDir = join11(sessionDir, "rounds", `round-${currentRound}`);
26328
26349
  if (existsSync6(join11(roundDir, "final.md"))) {
@@ -26370,6 +26391,7 @@ var FilesystemSync = class {
26370
26391
  [currentRound, currentMapRun, sessionId]
26371
26392
  );
26372
26393
  } else {
26394
+ if (!this.hasArtifacts(sessionDir)) return;
26373
26395
  this.db.run(
26374
26396
  `INSERT INTO sessions (id, branch, workflow_type, current_phase, phase_number, current_round, current_map_run, session_dir, status)
26375
26397
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
@@ -26379,6 +26401,21 @@ var FilesystemSync = class {
26379
26401
  }
26380
26402
  this.onSync?.();
26381
26403
  }
26404
+ // ── Artifact Check ──
26405
+ /** Returns true if the directory contains at least one .md or .json file (recursively). */
26406
+ hasArtifacts(dir) {
26407
+ try {
26408
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
26409
+ if (entry.isDirectory()) {
26410
+ if (this.hasArtifacts(join11(dir, entry.name))) return true;
26411
+ } else if (/\.(md|json)$/.test(entry.name)) {
26412
+ return true;
26413
+ }
26414
+ }
26415
+ } catch {
26416
+ }
26417
+ return false;
26418
+ }
26382
26419
  // ── Mtime Skip Check ──
26383
26420
  shouldSkip(filePath, existingParsedAt) {
26384
26421
  if (!existingParsedAt) return false;
@@ -27875,13 +27912,10 @@ function cleanupAllChats() {
27875
27912
  }
27876
27913
 
27877
27914
  // src/server/socket/post-handler.ts
27878
- import { execFile } from "node:child_process";
27879
27915
  import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync10, unlinkSync, writeFileSync as writeFileSync4 } from "node:fs";
27880
27916
  import { tmpdir as tmpdir2 } from "node:os";
27881
27917
  import { join as join13, dirname as dirname10, isAbsolute } from "node:path";
27882
27918
  import { randomUUID as randomUUID2 } from "node:crypto";
27883
- import { promisify } from "node:util";
27884
- var execFileAsync = promisify(execFile);
27885
27919
  function resolveSessionDir(sessionDir, ocrDir) {
27886
27920
  if (isAbsolute(sessionDir)) return sessionDir;
27887
27921
  return join13(dirname10(ocrDir), sessionDir);
@@ -27912,10 +27946,10 @@ async function findPrForBranch(branch, env, cwd) {
27912
27946
  }
27913
27947
  for (const candidate of candidates) {
27914
27948
  try {
27915
- const { stdout } = await execFileAsync(
27949
+ const { stdout } = await execBinaryAsync(
27916
27950
  "gh",
27917
27951
  ["pr", "list", "--head", candidate, "--json", "number,url", "--limit", "1"],
27918
- { env, cwd }
27952
+ { env, cwd, encoding: "utf-8" }
27919
27953
  );
27920
27954
  const prs = JSON.parse(stdout);
27921
27955
  if (prs.length > 0 && prs[0]) {
@@ -27955,7 +27989,7 @@ function registerPostHandlers(io2, socket, db, ocrDir, aiCliService) {
27955
27989
  const branch = session.branch;
27956
27990
  const repoRoot = dirname10(ocrDir);
27957
27991
  try {
27958
- await execFileAsync("gh", ["auth", "status"], { env: cleanEnv(), cwd: repoRoot });
27992
+ await execBinaryAsync("gh", ["auth", "status"], { env: cleanEnv(), cwd: repoRoot, encoding: "utf-8" });
27959
27993
  } catch {
27960
27994
  socket.emit("post:gh-result", {
27961
27995
  authenticated: false,
@@ -28259,10 +28293,10 @@ function registerPostHandlers(io2, socket, db, ocrDir, aiCliService) {
28259
28293
  writeFileSync4(tmpFile, content, { mode: 384 });
28260
28294
  const repoRoot = dirname10(ocrDir);
28261
28295
  try {
28262
- const { stdout } = await execFileAsync(
28296
+ const { stdout } = await execBinaryAsync(
28263
28297
  "gh",
28264
28298
  ["pr", "comment", String(prNumber), "--body-file", tmpFile],
28265
- { env: cleanEnv(), cwd: repoRoot }
28299
+ { env: cleanEnv(), cwd: repoRoot, encoding: "utf-8" }
28266
28300
  );
28267
28301
  const urlMatch = stdout.match(/(https:\/\/github\.com\S+)/)?.[0] ?? null;
28268
28302
  tracker.appendOutput(`\u2713 Posted to PR #${prNumber}${urlMatch ? ` \u2014 ${urlMatch}` : ""}
@@ -28337,6 +28371,9 @@ if (process.env.NODE_ENV !== "production") {
28337
28371
  next();
28338
28372
  });
28339
28373
  }
28374
+ app.get("/api/health", (_req, res) => {
28375
+ res.json({ status: "ok" });
28376
+ });
28340
28377
  app.use("/api", (req, res, next) => {
28341
28378
  const authHeader = req.headers.authorization;
28342
28379
  if (!authHeader || !authHeader.startsWith("Bearer ") || authHeader.slice(7) !== AUTH_TOKEN) {
@@ -28363,9 +28400,6 @@ if (process.env.NODE_ENV !== "production") {
28363
28400
  res.json({ token: AUTH_TOKEN });
28364
28401
  });
28365
28402
  }
28366
- app.get("/api/health", (_req, res) => {
28367
- res.json({ status: "ok" });
28368
- });
28369
28403
  async function startServer(options = {}) {
28370
28404
  const port = options.port ?? parseInt(process.env.PORT ?? "4173", 10);
28371
28405
  const ocrDir = resolveOcrDir();
@@ -28373,7 +28407,12 @@ async function startServer(options = {}) {
28373
28407
  const db = await openDb(ocrDir);
28374
28408
  const dataDir = join14(ocrDir, "data");
28375
28409
  const pidFilePath = join14(dataDir, "dashboard.pid");
28410
+ const portFilePath = join14(dataDir, "server-port");
28376
28411
  mkdirSync4(dataDir, { recursive: true });
28412
+ try {
28413
+ unlinkSync2(portFilePath);
28414
+ } catch {
28415
+ }
28377
28416
  if (existsSync10(pidFilePath)) {
28378
28417
  try {
28379
28418
  const oldPid = parseInt(readFileSync11(pidFilePath, "utf-8").trim(), 10);
@@ -28559,7 +28598,6 @@ async function startServer(options = {}) {
28559
28598
  if (actualPort !== port) {
28560
28599
  console.log(` Note: using port ${actualPort} (${port} was in use)`);
28561
28600
  }
28562
- const portFilePath = join14(dataDir, "server-port");
28563
28601
  writeFileSync5(portFilePath, String(actualPort), { mode: 384 });
28564
28602
  console.log(` Server: http://localhost:${actualPort}`);
28565
28603
  console.log(` OCR directory: ${shortenPath(ocrDir)}`);
package/dist/index.js CHANGED
@@ -20894,10 +20894,29 @@ ${hint}
20894
20894
  }
20895
20895
 
20896
20896
  // src/lib/version.ts
20897
- var CLI_VERSION = true ? "1.10.0" : createRequire(import.meta.url)("../../package.json").version;
20897
+ var CLI_VERSION = true ? "1.10.2" : createRequire(import.meta.url)("../../package.json").version;
20898
+
20899
+ // ../shared/platform/src/index.ts
20900
+ import { pathToFileURL } from "node:url";
20901
+ import {
20902
+ execFile,
20903
+ execFileSync,
20904
+ spawn as spawn2
20905
+ } from "node:child_process";
20906
+ import { promisify } from "node:util";
20907
+ var execFilePromise = promisify(execFile);
20908
+ var isWindows = process.platform === "win32";
20909
+ async function importModule(absolutePath) {
20910
+ return import(pathToFileURL(absolutePath).href);
20911
+ }
20912
+ function execBinary(binary, args, opts) {
20913
+ return execFileSync(binary, args, {
20914
+ ...opts,
20915
+ shell: isWindows
20916
+ });
20917
+ }
20898
20918
 
20899
20919
  // src/lib/deps.ts
20900
- import { execFileSync } from "node:child_process";
20901
20920
  var CATEGORY_ORDER = ["core", "ai-cli", "github"];
20902
20921
  var CATEGORY_INFO = {
20903
20922
  core: { label: "Core", hint: "" },
@@ -20946,7 +20965,7 @@ function parseVersion(output) {
20946
20965
  }
20947
20966
  function checkBinary(spec) {
20948
20967
  try {
20949
- const output = execFileSync(spec.binary, ["--version"], {
20968
+ const output = execBinary(spec.binary, ["--version"], {
20950
20969
  encoding: "utf-8",
20951
20970
  timeout: 5e3,
20952
20971
  stdio: ["ignore", "pipe", "pipe"]
@@ -21441,7 +21460,7 @@ var STR_CLOSE = "close";
21441
21460
  var EMPTY_FN = () => {
21442
21461
  };
21443
21462
  var pl = process.platform;
21444
- var isWindows = pl === "win32";
21463
+ var isWindows2 = pl === "win32";
21445
21464
  var isMacos = pl === "darwin";
21446
21465
  var isLinux = pl === "linux";
21447
21466
  var isFreeBSD = pl === "freebsd";
@@ -21814,7 +21833,7 @@ var setFsWatchListener = (path2, fullPath, options, handlers) => {
21814
21833
  const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR);
21815
21834
  if (cont)
21816
21835
  cont.watcherUnusable = true;
21817
- if (isWindows && error.code === "EPERM") {
21836
+ if (isWindows2 && error.code === "EPERM") {
21818
21837
  try {
21819
21838
  const fd = await open(path2, "r");
21820
21839
  await fd.close();
@@ -22587,7 +22606,7 @@ var FSWatcher = class extends EventEmitter {
22587
22606
  if (this.closed)
22588
22607
  return;
22589
22608
  const opts = this.options;
22590
- if (isWindows)
22609
+ if (isWindows2)
22591
22610
  path2 = sysPath2.normalize(path2);
22592
22611
  if (opts.cwd)
22593
22612
  path2 = sysPath2.relative(opts.cwd, path2);
@@ -22956,7 +22975,7 @@ var isSharedWorker = typeof SharedWorkerGlobalScope !== "undefined" && globalThi
22956
22975
  var isServiceWorker = typeof ServiceWorkerGlobalScope !== "undefined" && globalThis instanceof ServiceWorkerGlobalScope;
22957
22976
  var platform = globalThis.navigator?.userAgentData?.platform;
22958
22977
  var isMacOs = platform === "macOS" || globalThis.navigator?.platform === "MacIntel" || globalThis.navigator?.userAgent?.includes(" Mac ") === true || globalThis.process?.platform === "darwin";
22959
- var isWindows2 = platform === "Windows" || globalThis.navigator?.platform === "Win32" || globalThis.process?.platform === "win32";
22978
+ var isWindows3 = platform === "Windows" || globalThis.navigator?.platform === "Win32" || globalThis.process?.platform === "win32";
22960
22979
  var isLinux2 = platform === "Linux" || globalThis.navigator?.platform?.startsWith("Linux") === true || globalThis.navigator?.userAgent?.includes(" Linux ") === true || globalThis.process?.platform === "linux";
22961
22980
  var isIos = platform === "iOS" || globalThis.navigator?.platform === "MacIntel" && globalThis.navigator?.maxTouchPoints > 1 || /iPad|iPhone|iPod/.test(globalThis.navigator?.platform);
22962
22981
  var isAndroid = platform === "Android" || globalThis.navigator?.platform === "Android" || globalThis.navigator?.userAgent?.includes(" Android ") === true || globalThis.process?.platform === "android";
@@ -22967,7 +22986,7 @@ var OSC = "\x1B]";
22967
22986
  var BEL = "\x07";
22968
22987
  var SEP = ";";
22969
22988
  var isTerminalApp = !isBrowser && process11.env.TERM_PROGRAM === "Apple_Terminal";
22970
- var isWindows3 = !isBrowser && process11.platform === "win32";
22989
+ var isWindows4 = !isBrowser && process11.platform === "win32";
22971
22990
  var isTmux = !isBrowser && (process11.env.TERM?.startsWith("screen") || process11.env.TERM?.startsWith("tmux") || process11.env.TMUX !== void 0);
22972
22991
  var cwdFunction = isBrowser ? () => {
22973
22992
  throw new Error("`process.cwd()` only works in Node.js, not the browser.");
@@ -23037,7 +23056,7 @@ var scrollDown = ESC2 + "T";
23037
23056
  var clearScreen = "\x1Bc";
23038
23057
  var clearViewport = `${eraseScreen}${ESC2}H`;
23039
23058
  var isOldWindows = () => {
23040
- if (isBrowser || !isWindows3) {
23059
+ if (isBrowser || !isWindows4) {
23041
23060
  return false;
23042
23061
  }
23043
23062
  const parts = os3.release().split(".");
@@ -24850,6 +24869,19 @@ import {
24850
24869
  writeFileSync as writeFileSync8
24851
24870
  } from "node:fs";
24852
24871
  import { join as join14 } from "node:path";
24872
+ function hasArtifacts(dir) {
24873
+ try {
24874
+ for (const entry of readdirSync6(dir, { withFileTypes: true })) {
24875
+ if (entry.isDirectory()) {
24876
+ if (hasArtifacts(join14(dir, entry.name))) return true;
24877
+ } else if (/\.(md|json)$/.test(entry.name)) {
24878
+ return true;
24879
+ }
24880
+ }
24881
+ } catch {
24882
+ }
24883
+ return false;
24884
+ }
24853
24885
  async function stateInit(params) {
24854
24886
  const { sessionId, branch, workflowType, sessionDir, ocrDir } = params;
24855
24887
  const db = await ensureDatabase(ocrDir);
@@ -25286,25 +25318,49 @@ async function stateSync(ocrDir) {
25286
25318
  if (existing) {
25287
25319
  continue;
25288
25320
  }
25321
+ if (!hasArtifacts(dirPath)) {
25322
+ continue;
25323
+ }
25289
25324
  const hasRoundsDir = existsSync12(join14(dirPath, "rounds"));
25290
25325
  const hasMapDir = existsSync12(join14(dirPath, "map"));
25291
25326
  const workflowType = hasMapDir && !hasRoundsDir ? "map" : "review";
25292
25327
  const branchMatch = dirName.match(/^\d{4}-\d{2}-\d{2}-(.+)$/);
25293
25328
  const branch = branchMatch?.[1] ?? dirName;
25329
+ let inferredPhase = "context";
25330
+ if (workflowType === "review") {
25331
+ const roundsDir = join14(dirPath, "rounds");
25332
+ if (existsSync12(roundsDir)) {
25333
+ const roundDirs = readdirSync6(roundsDir).filter((d) => /^round-\d+$/.test(d)).sort((a, b) => parseInt(a.replace(/^\D+-/, ""), 10) - parseInt(b.replace(/^\D+-/, ""), 10));
25334
+ const latestRound = roundDirs[roundDirs.length - 1];
25335
+ if (latestRound && existsSync12(join14(roundsDir, latestRound, "final.md"))) {
25336
+ inferredPhase = "complete";
25337
+ }
25338
+ }
25339
+ } else if (workflowType === "map") {
25340
+ const runsDir = join14(dirPath, "map", "runs");
25341
+ if (existsSync12(runsDir)) {
25342
+ const runDirs = readdirSync6(runsDir).filter((d) => /^run-\d+$/.test(d)).sort((a, b) => parseInt(a.replace(/^\D+-/, ""), 10) - parseInt(b.replace(/^\D+-/, ""), 10));
25343
+ const latestRun = runDirs[runDirs.length - 1];
25344
+ if (latestRun && existsSync12(join14(runsDir, latestRun, "map.md"))) {
25345
+ inferredPhase = "complete";
25346
+ }
25347
+ }
25348
+ }
25294
25349
  insertSession(db, {
25295
25350
  id: dirName,
25296
25351
  branch,
25297
25352
  workflow_type: workflowType,
25298
- current_phase: "context",
25353
+ current_phase: inferredPhase,
25299
25354
  phase_number: 1,
25300
25355
  current_round: 1,
25301
25356
  current_map_run: 1,
25302
25357
  session_dir: dirPath
25303
25358
  });
25359
+ updateSession(db, dirName, { status: "closed" });
25304
25360
  insertEvent(db, {
25305
25361
  session_id: dirName,
25306
25362
  event_type: "session_synced",
25307
- phase: "context",
25363
+ phase: inferredPhase,
25308
25364
  phase_number: 1,
25309
25365
  metadata: JSON.stringify({ source: "filesystem_backfill" })
25310
25366
  });
@@ -25832,7 +25888,7 @@ var dashboardCommand = new Command("dashboard").description("Start the OCR dashb
25832
25888
  console.log(source_default.bold(" OCR Dashboard"));
25833
25889
  console.log();
25834
25890
  try {
25835
- const { startServer } = await import(serverPath);
25891
+ const { startServer } = await importModule(serverPath);
25836
25892
  await startServer({ port, open: options.open });
25837
25893
  } catch (err) {
25838
25894
  console.error(source_default.red("Error: Failed to start dashboard server."));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-code-review/cli",
3
- "version": "1.10.0",
3
+ "version": "1.10.2",
4
4
  "description": "CLI for Open Code Review - Multi-environment setup and progress tracking",
5
5
  "type": "module",
6
6
  "bin": {
@@ -50,7 +50,8 @@
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.10.0"
53
+ "@open-code-review/agents": "1.10.2",
54
+ "@open-code-review/platform": "0.0.0"
54
55
  },
55
56
  "publishConfig": {
56
57
  "access": "public"