@unerr-ai/unerr 0.1.3 → 0.1.4

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.
Files changed (2) hide show
  1. package/dist/cli.js +685 -656
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -5125,20 +5125,20 @@ __export(registry_exports, {
5125
5125
  writeNeedsInput: () => writeNeedsInput,
5126
5126
  writeRegistry: () => writeRegistry
5127
5127
  });
5128
- import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
5129
- import { homedir as homedir3 } from "os";
5130
- import { basename as basename3, dirname as dirname4, join as join9, resolve } from "path";
5128
+ import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "fs";
5129
+ import { homedir as homedir4 } from "os";
5130
+ import { basename as basename3, dirname as dirname5, join as join10, resolve } from "path";
5131
5131
  function globalDir() {
5132
5132
  const override = process.env.UNERR_HOME;
5133
- if (override) return join9(override, ".unerr");
5134
- return join9(homedir3(), ".unerr");
5133
+ if (override) return join10(override, ".unerr");
5134
+ return join10(homedir4(), ".unerr");
5135
5135
  }
5136
5136
  function registryPath() {
5137
- return join9(globalDir(), "repos.json");
5137
+ return join10(globalDir(), "repos.json");
5138
5138
  }
5139
5139
  function readRegistry() {
5140
5140
  try {
5141
- const raw = readFileSync7(registryPath(), "utf-8");
5141
+ const raw = readFileSync8(registryPath(), "utf-8");
5142
5142
  const parsed = JSON.parse(raw);
5143
5143
  if (parsed.version !== 1 || !Array.isArray(parsed.repos)) {
5144
5144
  return { version: 1, repos: [] };
@@ -5150,8 +5150,8 @@ function readRegistry() {
5150
5150
  }
5151
5151
  function writeRegistry(reg) {
5152
5152
  const dir = globalDir();
5153
- if (!existsSync8(dir)) {
5154
- mkdirSync4(dir, { recursive: true });
5153
+ if (!existsSync9(dir)) {
5154
+ mkdirSync5(dir, { recursive: true });
5155
5155
  }
5156
5156
  writeFileSync3(registryPath(), `${JSON.stringify(reg, null, 2)}
5157
5157
  `);
@@ -5160,7 +5160,7 @@ function deriveLabel(repoPath, existing) {
5160
5160
  const base = basename3(repoPath);
5161
5161
  const taken = new Set(existing.map((e) => e.label));
5162
5162
  if (!taken.has(base)) return base;
5163
- const parentBase = `${basename3(dirname4(repoPath))}-${base}`;
5163
+ const parentBase = `${basename3(dirname5(repoPath))}-${base}`;
5164
5164
  if (!taken.has(parentBase)) return parentBase;
5165
5165
  for (let i = 2; i < 100; i++) {
5166
5166
  const candidate = `${base}-${i}`;
@@ -5206,9 +5206,9 @@ function addRepo(rawPath, settings = {}, opts = {}) {
5206
5206
  };
5207
5207
  reg.repos.push(entry);
5208
5208
  writeRegistry(reg);
5209
- const unerrDir = join9(absPath, ".unerr");
5210
- if (!existsSync8(unerrDir)) {
5211
- mkdirSync4(unerrDir, { recursive: true });
5209
+ const unerrDir = join10(absPath, ".unerr");
5210
+ if (!existsSync9(unerrDir)) {
5211
+ mkdirSync5(unerrDir, { recursive: true });
5212
5212
  }
5213
5213
  mirrorSettingsToLocal(absPath, entry.settings);
5214
5214
  return { ok: true, entry, created: true };
@@ -5247,14 +5247,14 @@ function updateRepoSettings(rawPath, patch) {
5247
5247
  }
5248
5248
  function detectParentConflict(target, repos) {
5249
5249
  const registeredPaths = new Set(repos.map((r) => r.path));
5250
- let current = dirname4(target);
5251
- const root = dirname4(current) === current ? current : void 0;
5250
+ let current = dirname5(target);
5251
+ const root = dirname5(current) === current ? current : void 0;
5252
5252
  while (current !== root) {
5253
5253
  if (registeredPaths.has(current)) return current;
5254
- if (existsSync8(join9(current, ".unerr", "state", "proxy.pid"))) {
5254
+ if (existsSync9(join10(current, ".unerr", "state", "proxy.pid"))) {
5255
5255
  return current;
5256
5256
  }
5257
- const parent = dirname4(current);
5257
+ const parent = dirname5(current);
5258
5258
  if (parent === current) break;
5259
5259
  current = parent;
5260
5260
  }
@@ -5266,17 +5266,17 @@ function detectChildConflicts(target, repos) {
5266
5266
  }
5267
5267
  function readNeedsInput(repoPath) {
5268
5268
  try {
5269
- const p = join9(repoPath, ".unerr", "needs-input.json");
5270
- return JSON.parse(readFileSync7(p, "utf-8"));
5269
+ const p = join10(repoPath, ".unerr", "needs-input.json");
5270
+ return JSON.parse(readFileSync8(p, "utf-8"));
5271
5271
  } catch {
5272
5272
  return [];
5273
5273
  }
5274
5274
  }
5275
5275
  function writeNeedsInput(repoPath, signals) {
5276
- const dir = join9(repoPath, ".unerr");
5277
- if (!existsSync8(dir)) mkdirSync4(dir, { recursive: true });
5276
+ const dir = join10(repoPath, ".unerr");
5277
+ if (!existsSync9(dir)) mkdirSync5(dir, { recursive: true });
5278
5278
  writeFileSync3(
5279
- join9(dir, "needs-input.json"),
5279
+ join10(dir, "needs-input.json"),
5280
5280
  `${JSON.stringify(signals, null, 2)}
5281
5281
  `
5282
5282
  );
@@ -5291,10 +5291,10 @@ function buildSettings(partial) {
5291
5291
  return s;
5292
5292
  }
5293
5293
  function mirrorSettingsToLocal(repoPath, settings) {
5294
- const configPath = join9(repoPath, ".unerr", "config.json");
5294
+ const configPath = join10(repoPath, ".unerr", "config.json");
5295
5295
  let config = {};
5296
5296
  try {
5297
- config = JSON.parse(readFileSync7(configPath, "utf-8"));
5297
+ config = JSON.parse(readFileSync8(configPath, "utf-8"));
5298
5298
  } catch {
5299
5299
  }
5300
5300
  for (const [k, v] of Object.entries(settings)) {
@@ -5302,8 +5302,8 @@ function mirrorSettingsToLocal(repoPath, settings) {
5302
5302
  config[k] = v;
5303
5303
  }
5304
5304
  }
5305
- const dir = join9(repoPath, ".unerr");
5306
- if (!existsSync8(dir)) mkdirSync4(dir, { recursive: true });
5305
+ const dir = join10(repoPath, ".unerr");
5306
+ if (!existsSync9(dir)) mkdirSync5(dir, { recursive: true });
5307
5307
  writeFileSync3(configPath, `${JSON.stringify(config, null, 2)}
5308
5308
  `);
5309
5309
  }
@@ -5315,7 +5315,7 @@ var init_registry = __esm({
5315
5315
  });
5316
5316
 
5317
5317
  // src/daemon/detect-ci.ts
5318
- import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
5318
+ import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
5319
5319
  function isCI() {
5320
5320
  if (cachedResult !== null) return cachedResult;
5321
5321
  cachedResult = detect();
@@ -5338,9 +5338,9 @@ function detect() {
5338
5338
  if (env("WOODPECKER_CI")) return true;
5339
5339
  if (env("TEAMCITY_VERSION")) return true;
5340
5340
  if (env("HEROKU_TEST_RUN_ID")) return true;
5341
- if (existsSync9("/.dockerenv")) return true;
5341
+ if (existsSync10("/.dockerenv")) return true;
5342
5342
  try {
5343
- const cgroup = readFileSync8("/proc/1/cgroup", "utf-8");
5343
+ const cgroup = readFileSync9("/proc/1/cgroup", "utf-8");
5344
5344
  if (cgroup.includes("docker") || cgroup.includes("kubepods") || cgroup.includes("containerd")) {
5345
5345
  return true;
5346
5346
  }
@@ -5368,25 +5368,25 @@ __export(platform_macos_exports, {
5368
5368
  isLaunchdInstalled: () => isLaunchdInstalled,
5369
5369
  uninstallLaunchd: () => uninstallLaunchd
5370
5370
  });
5371
- import { execSync as execSync2 } from "child_process";
5371
+ import { execSync as execSync3 } from "child_process";
5372
5372
  import {
5373
- existsSync as existsSync10,
5374
- mkdirSync as mkdirSync5,
5375
- readFileSync as readFileSync9,
5373
+ existsSync as existsSync11,
5374
+ mkdirSync as mkdirSync6,
5375
+ readFileSync as readFileSync10,
5376
5376
  realpathSync,
5377
5377
  unlinkSync,
5378
5378
  writeFileSync as writeFileSync4
5379
5379
  } from "fs";
5380
- import { homedir as homedir4 } from "os";
5381
- import { dirname as dirname5, join as join10, resolve as resolve2 } from "path";
5380
+ import { homedir as homedir5 } from "os";
5381
+ import { dirname as dirname6, join as join11, resolve as resolve2 } from "path";
5382
5382
  function plistDir() {
5383
- return join10(homedir4(), "Library", "LaunchAgents");
5383
+ return join11(homedir5(), "Library", "LaunchAgents");
5384
5384
  }
5385
5385
  function plistPath() {
5386
- return join10(plistDir(), PLIST_NAME);
5386
+ return join11(plistDir(), PLIST_NAME);
5387
5387
  }
5388
5388
  function logPath() {
5389
- return join10(homedir4(), ".unerr", "logs", "unerrd.boot.log");
5389
+ return join11(homedir5(), ".unerr", "logs", "unerrd.boot.log");
5390
5390
  }
5391
5391
  function resolveNodeBin() {
5392
5392
  try {
@@ -5398,30 +5398,30 @@ function resolveNodeBin() {
5398
5398
  function resolveCliEntry() {
5399
5399
  if (process.argv[1]) {
5400
5400
  const resolved = resolve2(process.argv[1]);
5401
- if (existsSync10(resolved)) return resolved;
5401
+ if (existsSync11(resolved)) return resolved;
5402
5402
  }
5403
5403
  try {
5404
- const shimPath = execSync2("which unerr", { encoding: "utf-8" }).trim();
5405
- if (shimPath && existsSync10(shimPath)) {
5406
- const shimContent = readFileSync9(shimPath, "utf-8");
5404
+ const shimPath = execSync3("which unerr", { encoding: "utf-8" }).trim();
5405
+ if (shimPath && existsSync11(shimPath)) {
5406
+ const shimContent = readFileSync10(shimPath, "utf-8");
5407
5407
  const jsMatch = /"\$basedir\/((?:\.\.\/)*[^"]+\.js)"/m.exec(shimContent);
5408
5408
  if (jsMatch?.[1]) {
5409
- const basedir = dirname5(shimPath);
5409
+ const basedir = dirname6(shimPath);
5410
5410
  const abs = resolve2(basedir, jsMatch[1]);
5411
- if (existsSync10(abs)) return abs;
5411
+ if (existsSync11(abs)) return abs;
5412
5412
  }
5413
5413
  }
5414
5414
  } catch {
5415
5415
  }
5416
- const fallbackBase = process.argv[1] ? dirname5(resolve2(process.argv[1])) : process.cwd();
5417
- return join10(fallbackBase, "cli.js");
5416
+ const fallbackBase = process.argv[1] ? dirname6(resolve2(process.argv[1])) : process.cwd();
5417
+ return join11(fallbackBase, "cli.js");
5418
5418
  }
5419
5419
  function xmlEscape(s) {
5420
5420
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
5421
5421
  }
5422
5422
  function generatePlist(nodeBin, cliEntry) {
5423
5423
  const log25 = logPath();
5424
- const nodeBinDir = dirname5(nodeBin);
5424
+ const nodeBinDir = dirname6(nodeBin);
5425
5425
  const e = xmlEscape;
5426
5426
  return `<?xml version="1.0" encoding="UTF-8"?>
5427
5427
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -5468,14 +5468,14 @@ function installLaunchd() {
5468
5468
  const nodeBin = resolveNodeBin();
5469
5469
  const cliEntry = resolveCliEntry();
5470
5470
  try {
5471
- mkdirSync5(dir, { recursive: true });
5472
- const logDir = join10(homedir4(), ".unerr", "logs");
5473
- mkdirSync5(logDir, { recursive: true });
5471
+ mkdirSync6(dir, { recursive: true });
5472
+ const logDir = join11(homedir5(), ".unerr", "logs");
5473
+ mkdirSync6(logDir, { recursive: true });
5474
5474
  const plist = generatePlist(nodeBin, cliEntry);
5475
5475
  writeFileSync4(path7, plist, "utf-8");
5476
- const uid = process.getuid?.() ?? execSync2("id -u", { encoding: "utf-8" }).trim();
5476
+ const uid = process.getuid?.() ?? execSync3("id -u", { encoding: "utf-8" }).trim();
5477
5477
  try {
5478
- execSync2(
5478
+ execSync3(
5479
5479
  `launchctl bootout gui/${uid}/${PLIST_NAME.replace(".plist", "")}`,
5480
5480
  {
5481
5481
  stdio: "ignore"
@@ -5483,7 +5483,7 @@ function installLaunchd() {
5483
5483
  );
5484
5484
  } catch {
5485
5485
  }
5486
- execSync2(`launchctl bootstrap gui/${uid} "${path7}"`, { stdio: "ignore" });
5486
+ execSync3(`launchctl bootstrap gui/${uid} "${path7}"`, { stdio: "ignore" });
5487
5487
  return { installed: true, path: path7 };
5488
5488
  } catch (err) {
5489
5489
  return {
@@ -5496,9 +5496,9 @@ function installLaunchd() {
5496
5496
  function uninstallLaunchd() {
5497
5497
  const path7 = plistPath();
5498
5498
  try {
5499
- const uid = process.getuid?.() ?? execSync2("id -u", { encoding: "utf-8" }).trim();
5499
+ const uid = process.getuid?.() ?? execSync3("id -u", { encoding: "utf-8" }).trim();
5500
5500
  try {
5501
- execSync2(
5501
+ execSync3(
5502
5502
  `launchctl bootout gui/${uid}/${PLIST_NAME.replace(".plist", "")}`,
5503
5503
  {
5504
5504
  stdio: "ignore"
@@ -5506,7 +5506,7 @@ function uninstallLaunchd() {
5506
5506
  );
5507
5507
  } catch {
5508
5508
  }
5509
- if (existsSync10(path7)) unlinkSync(path7);
5509
+ if (existsSync11(path7)) unlinkSync(path7);
5510
5510
  return { installed: false, path: path7 };
5511
5511
  } catch (err) {
5512
5512
  return {
@@ -5517,14 +5517,14 @@ function uninstallLaunchd() {
5517
5517
  }
5518
5518
  }
5519
5519
  function isLaunchdInstalled() {
5520
- return existsSync10(plistPath());
5520
+ return existsSync11(plistPath());
5521
5521
  }
5522
5522
  function getLaunchdStatus() {
5523
- const plistExists = existsSync10(plistPath());
5523
+ const plistExists = existsSync11(plistPath());
5524
5524
  let loaded = false;
5525
5525
  if (plistExists) {
5526
5526
  try {
5527
- const out = execSync2("launchctl list", { encoding: "utf-8" });
5527
+ const out = execSync3("launchctl list", { encoding: "utf-8" });
5528
5528
  loaded = out.includes("com.unerr.daemon");
5529
5529
  } catch {
5530
5530
  }
@@ -5547,22 +5547,22 @@ __export(platform_linux_exports, {
5547
5547
  isSystemdInstalled: () => isSystemdInstalled,
5548
5548
  uninstallSystemd: () => uninstallSystemd
5549
5549
  });
5550
- import { execSync as execSync3 } from "child_process";
5550
+ import { execSync as execSync4 } from "child_process";
5551
5551
  import {
5552
- existsSync as existsSync11,
5553
- mkdirSync as mkdirSync6,
5554
- readFileSync as readFileSync10,
5552
+ existsSync as existsSync12,
5553
+ mkdirSync as mkdirSync7,
5554
+ readFileSync as readFileSync11,
5555
5555
  realpathSync as realpathSync2,
5556
5556
  unlinkSync as unlinkSync2,
5557
5557
  writeFileSync as writeFileSync5
5558
5558
  } from "fs";
5559
- import { homedir as homedir5 } from "os";
5560
- import { dirname as dirname6, join as join11, resolve as resolve3 } from "path";
5559
+ import { homedir as homedir6 } from "os";
5560
+ import { dirname as dirname7, join as join12, resolve as resolve3 } from "path";
5561
5561
  function unitDir() {
5562
- return join11(homedir5(), ".config", "systemd", "user");
5562
+ return join12(homedir6(), ".config", "systemd", "user");
5563
5563
  }
5564
5564
  function unitPath() {
5565
- return join11(unitDir(), UNIT_NAME);
5565
+ return join12(unitDir(), UNIT_NAME);
5566
5566
  }
5567
5567
  function resolveNodeBin2() {
5568
5568
  try {
@@ -5574,27 +5574,27 @@ function resolveNodeBin2() {
5574
5574
  function resolveCliEntry2() {
5575
5575
  if (process.argv[1]) {
5576
5576
  const resolved = resolve3(process.argv[1]);
5577
- if (existsSync11(resolved)) return resolved;
5577
+ if (existsSync12(resolved)) return resolved;
5578
5578
  }
5579
5579
  try {
5580
- const shimPath = execSync3("which unerr", { encoding: "utf-8" }).trim();
5581
- if (shimPath && existsSync11(shimPath)) {
5582
- const shimContent = readFileSync10(shimPath, "utf-8");
5580
+ const shimPath = execSync4("which unerr", { encoding: "utf-8" }).trim();
5581
+ if (shimPath && existsSync12(shimPath)) {
5582
+ const shimContent = readFileSync11(shimPath, "utf-8");
5583
5583
  const jsMatch = /"\$basedir\/((?:\.\.\/)*[^"]+\.js)"/m.exec(shimContent);
5584
5584
  if (jsMatch?.[1]) {
5585
- const basedir = dirname6(shimPath);
5585
+ const basedir = dirname7(shimPath);
5586
5586
  const abs = resolve3(basedir, jsMatch[1]);
5587
- if (existsSync11(abs)) return abs;
5587
+ if (existsSync12(abs)) return abs;
5588
5588
  }
5589
5589
  }
5590
5590
  } catch {
5591
5591
  }
5592
- const fallbackBase = process.argv[1] ? dirname6(resolve3(process.argv[1])) : process.cwd();
5593
- return join11(fallbackBase, "cli.js");
5592
+ const fallbackBase = process.argv[1] ? dirname7(resolve3(process.argv[1])) : process.cwd();
5593
+ return join12(fallbackBase, "cli.js");
5594
5594
  }
5595
5595
  function isWSL() {
5596
5596
  try {
5597
- const version = readFileSync10("/proc/version", "utf-8");
5597
+ const version = readFileSync11("/proc/version", "utf-8");
5598
5598
  return version.toLowerCase().includes("microsoft");
5599
5599
  } catch {
5600
5600
  return false;
@@ -5606,8 +5606,8 @@ function systemdQuote(s) {
5606
5606
  return s;
5607
5607
  }
5608
5608
  function generateUnit(nodeBin, cliEntry) {
5609
- const nodeBinDir = dirname6(nodeBin);
5610
- const home = homedir5();
5609
+ const nodeBinDir = dirname7(nodeBin);
5610
+ const home = homedir6();
5611
5611
  return `[Unit]
5612
5612
  Description=unerr daemon supervisor
5613
5613
  After=network.target
@@ -5637,15 +5637,15 @@ function installSystemd() {
5637
5637
  const nodeBin = resolveNodeBin2();
5638
5638
  const cliEntry = resolveCliEntry2();
5639
5639
  const dir = unitDir();
5640
- mkdirSync6(dir, { recursive: true });
5640
+ mkdirSync7(dir, { recursive: true });
5641
5641
  writeFileSync5(path7, generateUnit(nodeBin, cliEntry), "utf-8");
5642
- execSync3("systemctl --user daemon-reload", { stdio: "ignore" });
5643
- execSync3("systemctl --user enable --now unerrd.service", {
5642
+ execSync4("systemctl --user daemon-reload", { stdio: "ignore" });
5643
+ execSync4("systemctl --user enable --now unerrd.service", {
5644
5644
  stdio: "ignore"
5645
5645
  });
5646
5646
  try {
5647
- const username = process.env.USER || execSync3("whoami", { encoding: "utf-8" }).trim();
5648
- execSync3(`loginctl enable-linger ${username}`, { stdio: "ignore" });
5647
+ const username = process.env.USER || execSync4("whoami", { encoding: "utf-8" }).trim();
5648
+ execSync4(`loginctl enable-linger ${username}`, { stdio: "ignore" });
5649
5649
  } catch {
5650
5650
  }
5651
5651
  return { installed: true, path: path7 };
@@ -5661,14 +5661,14 @@ function uninstallSystemd() {
5661
5661
  const path7 = unitPath();
5662
5662
  try {
5663
5663
  try {
5664
- execSync3("systemctl --user disable --now unerrd.service", {
5664
+ execSync4("systemctl --user disable --now unerrd.service", {
5665
5665
  stdio: "ignore"
5666
5666
  });
5667
5667
  } catch {
5668
5668
  }
5669
- if (existsSync11(path7)) unlinkSync2(path7);
5669
+ if (existsSync12(path7)) unlinkSync2(path7);
5670
5670
  try {
5671
- execSync3("systemctl --user daemon-reload", { stdio: "ignore" });
5671
+ execSync4("systemctl --user daemon-reload", { stdio: "ignore" });
5672
5672
  } catch {
5673
5673
  }
5674
5674
  return { installed: false, path: path7 };
@@ -5681,22 +5681,22 @@ function uninstallSystemd() {
5681
5681
  }
5682
5682
  }
5683
5683
  function isSystemdInstalled() {
5684
- return existsSync11(unitPath());
5684
+ return existsSync12(unitPath());
5685
5685
  }
5686
5686
  function getSystemdStatus() {
5687
- const unitExists = existsSync11(unitPath());
5687
+ const unitExists = existsSync12(unitPath());
5688
5688
  let active = false;
5689
5689
  let enabled = false;
5690
5690
  if (unitExists) {
5691
5691
  try {
5692
- const out = execSync3("systemctl --user is-active unerrd.service", {
5692
+ const out = execSync4("systemctl --user is-active unerrd.service", {
5693
5693
  encoding: "utf-8"
5694
5694
  }).trim();
5695
5695
  active = out === "active";
5696
5696
  } catch {
5697
5697
  }
5698
5698
  try {
5699
- const out = execSync3("systemctl --user is-enabled unerrd.service", {
5699
+ const out = execSync4("systemctl --user is-enabled unerrd.service", {
5700
5700
  encoding: "utf-8"
5701
5701
  }).trim();
5702
5702
  enabled = out === "enabled";
@@ -5720,20 +5720,20 @@ __export(platform_windows_exports, {
5720
5720
  isWindowsInstalled: () => isWindowsInstalled,
5721
5721
  uninstallWindows: () => uninstallWindows
5722
5722
  });
5723
- import { execSync as execSync4 } from "child_process";
5723
+ import { execSync as execSync5 } from "child_process";
5724
5724
  import {
5725
- existsSync as existsSync12,
5726
- mkdirSync as mkdirSync7,
5727
- readFileSync as readFileSync11,
5725
+ existsSync as existsSync13,
5726
+ mkdirSync as mkdirSync8,
5727
+ readFileSync as readFileSync12,
5728
5728
  realpathSync as realpathSync3,
5729
5729
  unlinkSync as unlinkSync3,
5730
5730
  writeFileSync as writeFileSync6
5731
5731
  } from "fs";
5732
- import { homedir as homedir6 } from "os";
5733
- import { dirname as dirname7, join as join12, resolve as resolve4 } from "path";
5732
+ import { homedir as homedir7 } from "os";
5733
+ import { dirname as dirname8, join as join13, resolve as resolve4 } from "path";
5734
5734
  function startupDir() {
5735
- return join12(
5736
- process.env.APPDATA || join12(homedir6(), "AppData", "Roaming"),
5735
+ return join13(
5736
+ process.env.APPDATA || join13(homedir7(), "AppData", "Roaming"),
5737
5737
  "Microsoft",
5738
5738
  "Windows",
5739
5739
  "Start Menu",
@@ -5742,7 +5742,7 @@ function startupDir() {
5742
5742
  );
5743
5743
  }
5744
5744
  function startupCmdPath() {
5745
- return join12(startupDir(), STARTUP_CMD_NAME);
5745
+ return join13(startupDir(), STARTUP_CMD_NAME);
5746
5746
  }
5747
5747
  function resolveNodeBin3() {
5748
5748
  try {
@@ -5754,22 +5754,22 @@ function resolveNodeBin3() {
5754
5754
  function resolveCliEntry3() {
5755
5755
  if (process.argv[1]) {
5756
5756
  const resolved = resolve4(process.argv[1]);
5757
- if (existsSync12(resolved)) return resolved;
5757
+ if (existsSync13(resolved)) return resolved;
5758
5758
  }
5759
5759
  try {
5760
- const whereLine = execSync4("where unerr", { encoding: "utf-8" }).trim().split("\n")[0]?.trim();
5761
- if (whereLine && existsSync12(whereLine)) {
5762
- const shimContent = readFileSync11(whereLine, "utf-8");
5760
+ const whereLine = execSync5("where unerr", { encoding: "utf-8" }).trim().split("\n")[0]?.trim();
5761
+ if (whereLine && existsSync13(whereLine)) {
5762
+ const shimContent = readFileSync12(whereLine, "utf-8");
5763
5763
  const jsMatch = /"%~dp0\\([^"]+\.js)"/m.exec(shimContent);
5764
5764
  if (jsMatch?.[1]) {
5765
- const abs = resolve4(dirname7(whereLine), jsMatch[1]);
5766
- if (existsSync12(abs)) return abs;
5765
+ const abs = resolve4(dirname8(whereLine), jsMatch[1]);
5766
+ if (existsSync13(abs)) return abs;
5767
5767
  }
5768
5768
  }
5769
5769
  } catch {
5770
5770
  }
5771
- const fallbackBase = process.argv[1] ? dirname7(resolve4(process.argv[1])) : process.cwd();
5772
- return join12(fallbackBase, "cli.js");
5771
+ const fallbackBase = process.argv[1] ? dirname8(resolve4(process.argv[1])) : process.cwd();
5772
+ return join13(fallbackBase, "cli.js");
5773
5773
  }
5774
5774
  function installWindows() {
5775
5775
  const nodeBin = resolveNodeBin3();
@@ -5783,10 +5783,10 @@ function installScheduledTask(nodeBin, cliEntry) {
5783
5783
  const trArg = `"${innerCmd}"`;
5784
5784
  try {
5785
5785
  try {
5786
- execSync4(`schtasks /Delete /TN "${TASK_NAME}" /F`, { stdio: "ignore" });
5786
+ execSync5(`schtasks /Delete /TN "${TASK_NAME}" /F`, { stdio: "ignore" });
5787
5787
  } catch {
5788
5788
  }
5789
- execSync4(
5789
+ execSync5(
5790
5790
  `schtasks /Create /SC ONLOGON /TN "${TASK_NAME}" /TR ${trArg} /RL LIMITED /F`,
5791
5791
  { stdio: "ignore" }
5792
5792
  );
@@ -5803,7 +5803,7 @@ function installStartupCmd(nodeBin, cliEntry) {
5803
5803
  const path7 = startupCmdPath();
5804
5804
  try {
5805
5805
  const dir = startupDir();
5806
- mkdirSync7(dir, { recursive: true });
5806
+ mkdirSync8(dir, { recursive: true });
5807
5807
  const script = `@echo off\r
5808
5808
  "${nodeBin}" "${cliEntry}" daemon start --foreground\r
5809
5809
  `;
@@ -5820,12 +5820,12 @@ function installStartupCmd(nodeBin, cliEntry) {
5820
5820
  function uninstallWindows() {
5821
5821
  const errors = [];
5822
5822
  try {
5823
- execSync4(`schtasks /Delete /TN "${TASK_NAME}" /F`, { stdio: "ignore" });
5823
+ execSync5(`schtasks /Delete /TN "${TASK_NAME}" /F`, { stdio: "ignore" });
5824
5824
  } catch {
5825
5825
  }
5826
5826
  const cmdPath = startupCmdPath();
5827
5827
  try {
5828
- if (existsSync12(cmdPath)) unlinkSync3(cmdPath);
5828
+ if (existsSync13(cmdPath)) unlinkSync3(cmdPath);
5829
5829
  } catch (err) {
5830
5830
  errors.push(err instanceof Error ? err.message : String(err));
5831
5831
  }
@@ -5837,13 +5837,13 @@ function uninstallWindows() {
5837
5837
  }
5838
5838
  function isWindowsInstalled() {
5839
5839
  try {
5840
- execSync4(`schtasks /Query /TN "${TASK_NAME}" /FO CSV /NH`, {
5840
+ execSync5(`schtasks /Query /TN "${TASK_NAME}" /FO CSV /NH`, {
5841
5841
  stdio: "pipe"
5842
5842
  });
5843
5843
  return true;
5844
5844
  } catch {
5845
5845
  }
5846
- return existsSync12(startupCmdPath());
5846
+ return existsSync13(startupCmdPath());
5847
5847
  }
5848
5848
  var TASK_NAME, STARTUP_CMD_NAME;
5849
5849
  var init_platform_windows = __esm({
@@ -5864,19 +5864,19 @@ __export(autostart_exports, {
5864
5864
  removeSentinel: () => removeSentinel,
5865
5865
  uninstallForCurrentPlatform: () => uninstallForCurrentPlatform
5866
5866
  });
5867
- import { existsSync as existsSync13, mkdirSync as mkdirSync8, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "fs";
5868
- import { homedir as homedir7 } from "os";
5869
- import { join as join13 } from "path";
5867
+ import { existsSync as existsSync14, mkdirSync as mkdirSync9, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "fs";
5868
+ import { homedir as homedir8 } from "os";
5869
+ import { join as join14 } from "path";
5870
5870
  function isAutostartInstalled() {
5871
- return existsSync13(SENTINEL_PATH);
5871
+ return existsSync14(SENTINEL_PATH);
5872
5872
  }
5873
5873
  async function autoInstallIfNeeded() {
5874
5874
  if (isAutostartInstalled()) return null;
5875
5875
  if (isCI()) return null;
5876
5876
  const result = await installForCurrentPlatform();
5877
5877
  if (result.installed) {
5878
- const dir = join13(homedir7(), ".unerr");
5879
- mkdirSync8(dir, { recursive: true });
5878
+ const dir = join14(homedir8(), ".unerr");
5879
+ mkdirSync9(dir, { recursive: true });
5880
5880
  writeFileSync7(SENTINEL_PATH, (/* @__PURE__ */ new Date()).toISOString(), "utf-8");
5881
5881
  }
5882
5882
  return result;
@@ -5955,7 +5955,7 @@ async function getAutostartStatus() {
5955
5955
  }
5956
5956
  function removeSentinel() {
5957
5957
  try {
5958
- if (existsSync13(SENTINEL_PATH)) unlinkSync4(SENTINEL_PATH);
5958
+ if (existsSync14(SENTINEL_PATH)) unlinkSync4(SENTINEL_PATH);
5959
5959
  } catch {
5960
5960
  }
5961
5961
  }
@@ -5964,7 +5964,7 @@ var init_autostart = __esm({
5964
5964
  "src/daemon/autostart.ts"() {
5965
5965
  "use strict";
5966
5966
  init_detect_ci();
5967
- SENTINEL_PATH = join13(homedir7(), ".unerr", ".autostart-installed");
5967
+ SENTINEL_PATH = join14(homedir8(), ".unerr", ".autostart-installed");
5968
5968
  }
5969
5969
  });
5970
5970
 
@@ -5982,9 +5982,9 @@ __export(client_exports, {
5982
5982
  sendRequest: () => sendRequest
5983
5983
  });
5984
5984
  import { createConnection } from "net";
5985
- import { join as join14 } from "path";
5985
+ import { join as join15 } from "path";
5986
5986
  function daemonSockPath() {
5987
- return join14(globalDir(), "unerrd.sock");
5987
+ return join15(globalDir(), "unerrd.sock");
5988
5988
  }
5989
5989
  function sendRequest(sockPath2, request, timeoutMs = 3e4) {
5990
5990
  return new Promise((resolve9, reject) => {
@@ -6393,14 +6393,14 @@ var init_process_manager = __esm({
6393
6393
 
6394
6394
  // src/utils/file-logger.ts
6395
6395
  import {
6396
- appendFileSync as appendFileSync3,
6397
- existsSync as existsSync14,
6398
- mkdirSync as mkdirSync9,
6396
+ appendFileSync as appendFileSync4,
6397
+ existsSync as existsSync15,
6398
+ mkdirSync as mkdirSync10,
6399
6399
  renameSync,
6400
6400
  statSync as statSync2,
6401
6401
  unlinkSync as unlinkSync5
6402
6402
  } from "fs";
6403
- import { dirname as dirname8 } from "path";
6403
+ import { dirname as dirname9 } from "path";
6404
6404
  function stripAnsi(s) {
6405
6405
  return s.replace(ANSI_RE, "");
6406
6406
  }
@@ -6408,8 +6408,8 @@ function rotate(filePath, keep) {
6408
6408
  for (let i = keep; i >= 1; i--) {
6409
6409
  const cur = i === 1 ? filePath : `${filePath}.${i - 1}`;
6410
6410
  const next = `${filePath}.${i}`;
6411
- if (!existsSync14(cur)) continue;
6412
- if (i === keep && existsSync14(next)) {
6411
+ if (!existsSync15(cur)) continue;
6412
+ if (i === keep && existsSync15(next)) {
6413
6413
  try {
6414
6414
  unlinkSync5(next);
6415
6415
  } catch {
@@ -6423,7 +6423,7 @@ function rotate(filePath, keep) {
6423
6423
  }
6424
6424
  function installFileLogger(opts) {
6425
6425
  const { filePath, maxBytes = 5e6, keep = 5 } = opts;
6426
- mkdirSync9(dirname8(filePath), { recursive: true });
6426
+ mkdirSync10(dirname9(filePath), { recursive: true });
6427
6427
  let bytesWritten = 0;
6428
6428
  try {
6429
6429
  bytesWritten = statSync2(filePath).size;
@@ -6436,7 +6436,7 @@ function installFileLogger(opts) {
6436
6436
  try {
6437
6437
  const text2 = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf-8");
6438
6438
  const clean = stripAnsi(text2);
6439
- appendFileSync3(filePath, clean);
6439
+ appendFileSync4(filePath, clean);
6440
6440
  bytesWritten += clean.length;
6441
6441
  if (bytesWritten >= maxBytes) {
6442
6442
  rotate(filePath, keep);
@@ -6460,8 +6460,8 @@ var init_file_logger = __esm({
6460
6460
  });
6461
6461
 
6462
6462
  // src/daemon/system-health.ts
6463
- import { execSync as execSync5 } from "child_process";
6464
- import { existsSync as existsSync15, readFileSync as readFileSync12, readdirSync as readdirSync3 } from "fs";
6463
+ import { execSync as execSync6 } from "child_process";
6464
+ import { existsSync as existsSync16, readFileSync as readFileSync13, readdirSync as readdirSync3 } from "fs";
6465
6465
  import { cpus, loadavg, platform } from "os";
6466
6466
  function onBattery() {
6467
6467
  const now = Date.now();
@@ -6481,7 +6481,7 @@ function detectBattery() {
6481
6481
  }
6482
6482
  function detectBatteryMacOS() {
6483
6483
  try {
6484
- const out = execSync5("pmset -g batt", {
6484
+ const out = execSync6("pmset -g batt", {
6485
6485
  encoding: "utf-8",
6486
6486
  timeout: 3e3
6487
6487
  });
@@ -6494,13 +6494,13 @@ function detectBatteryMacOS() {
6494
6494
  function detectBatteryLinux() {
6495
6495
  try {
6496
6496
  const psDir = "/sys/class/power_supply";
6497
- if (!existsSync15(psDir)) return false;
6497
+ if (!existsSync16(psDir)) return false;
6498
6498
  const supplies = readdirSync3(psDir);
6499
6499
  for (const name of supplies) {
6500
6500
  if (name.startsWith("AC") || name.startsWith("ADP")) {
6501
6501
  const onlinePath = `${psDir}/${name}/online`;
6502
- if (existsSync15(onlinePath)) {
6503
- const online = readFileSync12(onlinePath, "utf-8").trim();
6502
+ if (existsSync16(onlinePath)) {
6503
+ const online = readFileSync13(onlinePath, "utf-8").trim();
6504
6504
  if (online === "0") return true;
6505
6505
  if (online === "1") return false;
6506
6506
  }
@@ -6513,7 +6513,7 @@ function detectBatteryLinux() {
6513
6513
  }
6514
6514
  function detectBatteryWindows() {
6515
6515
  try {
6516
- const out = execSync5("wmic path Win32_Battery get BatteryStatus /value", {
6516
+ const out = execSync6("wmic path Win32_Battery get BatteryStatus /value", {
6517
6517
  encoding: "utf-8",
6518
6518
  timeout: 5e3
6519
6519
  });
@@ -6570,14 +6570,14 @@ __export(warm_start_exports, {
6570
6570
  scheduleWarmStart: () => scheduleWarmStart,
6571
6571
  selectCandidates: () => selectCandidates
6572
6572
  });
6573
- import { existsSync as existsSync16, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "fs";
6574
- import { homedir as homedir8 } from "os";
6575
- import { join as join15 } from "path";
6573
+ import { existsSync as existsSync17, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync8 } from "fs";
6574
+ import { homedir as homedir9 } from "os";
6575
+ import { join as join16 } from "path";
6576
6576
  function loadWarmStartConfig() {
6577
- const configPath = join15(homedir8(), ".unerr", "config.json");
6577
+ const configPath = join16(homedir9(), ".unerr", "config.json");
6578
6578
  try {
6579
- if (!existsSync16(configPath)) return { ...DEFAULT_CONFIG };
6580
- const raw = JSON.parse(readFileSync13(configPath, "utf-8"));
6579
+ if (!existsSync17(configPath)) return { ...DEFAULT_CONFIG };
6580
+ const raw = JSON.parse(readFileSync14(configPath, "utf-8"));
6581
6581
  return {
6582
6582
  warmStartBudget: typeof raw.warmStartBudget === "number" ? raw.warmStartBudget : DEFAULT_CONFIG.warmStartBudget,
6583
6583
  warmStartIdleDays: typeof raw.warmStartIdleDays === "number" ? raw.warmStartIdleDays : DEFAULT_CONFIG.warmStartIdleDays,
@@ -6588,13 +6588,13 @@ function loadWarmStartConfig() {
6588
6588
  }
6589
6589
  }
6590
6590
  function saveWarmStartConfig(partial) {
6591
- const configPath = join15(homedir8(), ".unerr", "config.json");
6592
- const dir = join15(homedir8(), ".unerr");
6593
- mkdirSync10(dir, { recursive: true });
6591
+ const configPath = join16(homedir9(), ".unerr", "config.json");
6592
+ const dir = join16(homedir9(), ".unerr");
6593
+ mkdirSync11(dir, { recursive: true });
6594
6594
  let existing = {};
6595
6595
  try {
6596
- if (existsSync16(configPath)) {
6597
- existing = JSON.parse(readFileSync13(configPath, "utf-8"));
6596
+ if (existsSync17(configPath)) {
6597
+ existing = JSON.parse(readFileSync14(configPath, "utf-8"));
6598
6598
  }
6599
6599
  } catch {
6600
6600
  }
@@ -6612,7 +6612,7 @@ function selectCandidates(repos, config) {
6612
6612
  skipped.push({ entry, reason: "autostart=never" });
6613
6613
  continue;
6614
6614
  }
6615
- if (!existsSync16(entry.path)) {
6615
+ if (!existsSync17(entry.path)) {
6616
6616
  skipped.push({ entry, reason: "directory not found" });
6617
6617
  continue;
6618
6618
  }
@@ -6770,29 +6770,29 @@ __export(version_checker_exports, {
6770
6770
  startPeriodicCheck: () => startPeriodicCheck,
6771
6771
  writeVersionCache: () => writeVersionCache
6772
6772
  });
6773
- import { existsSync as existsSync17, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "fs";
6773
+ import { existsSync as existsSync18, mkdirSync as mkdirSync12, readFileSync as readFileSync15, writeFileSync as writeFileSync9 } from "fs";
6774
6774
  import { get as httpsGet } from "https";
6775
- import { homedir as homedir9 } from "os";
6776
- import { join as join16 } from "path";
6775
+ import { homedir as homedir10 } from "os";
6776
+ import { join as join17 } from "path";
6777
6777
  function versionCachePath() {
6778
- return join16(homedir9(), ".unerr", "version.json");
6778
+ return join17(homedir10(), ".unerr", "version.json");
6779
6779
  }
6780
6780
  function getInstalledVersion() {
6781
6781
  if (cachedInstalledVersion) return cachedInstalledVersion;
6782
6782
  try {
6783
- const pkgPath = join16(__dirname, "../../package.json");
6784
- if (existsSync17(pkgPath)) {
6785
- const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
6783
+ const pkgPath = join17(__dirname, "../../package.json");
6784
+ if (existsSync18(pkgPath)) {
6785
+ const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
6786
6786
  cachedInstalledVersion = pkg.version;
6787
6787
  return pkg.version;
6788
6788
  }
6789
6789
  } catch {
6790
6790
  }
6791
6791
  try {
6792
- const binDir = join16(process.argv[1] || "", "..");
6793
- const pkgPath = join16(binDir, "../package.json");
6794
- if (existsSync17(pkgPath)) {
6795
- const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
6792
+ const binDir = join17(process.argv[1] || "", "..");
6793
+ const pkgPath = join17(binDir, "../package.json");
6794
+ if (existsSync18(pkgPath)) {
6795
+ const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
6796
6796
  cachedInstalledVersion = pkg.version;
6797
6797
  return pkg.version;
6798
6798
  }
@@ -6811,9 +6811,9 @@ function readVersionCache() {
6811
6811
  };
6812
6812
  try {
6813
6813
  const path7 = versionCachePath();
6814
- if (!existsSync17(path7)) return defaults;
6814
+ if (!existsSync18(path7)) return defaults;
6815
6815
  const raw = JSON.parse(
6816
- readFileSync14(path7, "utf-8")
6816
+ readFileSync15(path7, "utf-8")
6817
6817
  );
6818
6818
  return {
6819
6819
  lastChecked: raw.lastChecked ?? defaults.lastChecked,
@@ -6827,8 +6827,8 @@ function readVersionCache() {
6827
6827
  }
6828
6828
  }
6829
6829
  function writeVersionCache(cache) {
6830
- const dir = join16(homedir9(), ".unerr");
6831
- mkdirSync11(dir, { recursive: true });
6830
+ const dir = join17(homedir10(), ".unerr");
6831
+ mkdirSync12(dir, { recursive: true });
6832
6832
  writeFileSync9(versionCachePath(), JSON.stringify(cache, null, 2), "utf-8");
6833
6833
  }
6834
6834
  function parseSemVer(version) {
@@ -6990,9 +6990,9 @@ var api_exports = {};
6990
6990
  __export(api_exports, {
6991
6991
  startDaemonApi: () => startDaemonApi
6992
6992
  });
6993
- import { existsSync as existsSync18, readFileSync as readFileSync15 } from "fs";
6993
+ import { existsSync as existsSync19, readFileSync as readFileSync16 } from "fs";
6994
6994
  import { request as httpRequest } from "http";
6995
- import { dirname as dirname9, join as join17 } from "path";
6995
+ import { dirname as dirname10, join as join18 } from "path";
6996
6996
  import { fileURLToPath } from "url";
6997
6997
  import { serve } from "@hono/node-server";
6998
6998
  import { serveStatic } from "@hono/node-server/serve-static";
@@ -7037,16 +7037,16 @@ function startDaemonApi(pm) {
7037
7037
  if (!repo.pid) return null;
7038
7038
  const managed = pm.getManaged(repo.path);
7039
7039
  if (!managed?.sock) return null;
7040
- const serverJsonPath = join17(
7040
+ const serverJsonPath = join18(
7041
7041
  repo.path,
7042
7042
  ".unerr",
7043
7043
  "state",
7044
7044
  "server.json"
7045
7045
  );
7046
- if (!existsSync18(serverJsonPath)) return null;
7046
+ if (!existsSync19(serverJsonPath)) return null;
7047
7047
  try {
7048
7048
  const serverInfo = JSON.parse(
7049
- readFileSync15(serverJsonPath, "utf-8")
7049
+ readFileSync16(serverJsonPath, "utf-8")
7050
7050
  );
7051
7051
  const [sessionStats, tokenFlow] = await Promise.allSettled([
7052
7052
  fetchRepoApi(serverInfo.port, "/api/session/stats"),
@@ -7154,13 +7154,13 @@ function startDaemonApi(pm) {
7154
7154
  503
7155
7155
  );
7156
7156
  }
7157
- const serverJsonPath = join17(repo.path, ".unerr", "state", "server.json");
7158
- if (!existsSync18(serverJsonPath)) {
7157
+ const serverJsonPath = join18(repo.path, ".unerr", "state", "server.json");
7158
+ if (!existsSync19(serverJsonPath)) {
7159
7159
  return c.json({ error: `Repo ${label} has no dashboard server` }, 503);
7160
7160
  }
7161
7161
  let repoPort;
7162
7162
  try {
7163
- const info2 = JSON.parse(readFileSync15(serverJsonPath, "utf-8"));
7163
+ const info2 = JSON.parse(readFileSync16(serverJsonPath, "utf-8"));
7164
7164
  repoPort = info2.port;
7165
7165
  } catch {
7166
7166
  return c.json({ error: `Cannot read server.json for ${label}` }, 500);
@@ -7178,10 +7178,10 @@ function startDaemonApi(pm) {
7178
7178
  return c.json({ error: `Proxy error: ${err.message}` }, 502);
7179
7179
  }
7180
7180
  });
7181
- const distDir = join17(dirname9(fileURLToPath(import.meta.url)), "ui");
7182
- const spaIndex = join17(distDir, "index.html");
7183
- if (existsSync18(spaIndex)) {
7184
- const spaHtml = readFileSync15(spaIndex, "utf-8");
7181
+ const distDir = join18(dirname10(fileURLToPath(import.meta.url)), "ui");
7182
+ const spaIndex = join18(distDir, "index.html");
7183
+ if (existsSync19(spaIndex)) {
7184
+ const spaHtml = readFileSync16(spaIndex, "utf-8");
7185
7185
  app.use("*", serveStatic({ root: distDir }));
7186
7186
  app.get("*", (c) => {
7187
7187
  if (c.req.path.startsWith("/api/")) return c.notFound();
@@ -7293,19 +7293,19 @@ __export(daemon_exports, {
7293
7293
  startDaemon: () => startDaemon
7294
7294
  });
7295
7295
  import {
7296
- existsSync as existsSync19,
7297
- mkdirSync as mkdirSync12,
7298
- readFileSync as readFileSync16,
7296
+ existsSync as existsSync20,
7297
+ mkdirSync as mkdirSync13,
7298
+ readFileSync as readFileSync17,
7299
7299
  unlinkSync as unlinkSync6,
7300
7300
  writeFileSync as writeFileSync10
7301
7301
  } from "fs";
7302
7302
  import { createConnection as createConnection2, createServer } from "net";
7303
- import { join as join18 } from "path";
7303
+ import { join as join19 } from "path";
7304
7304
  function pidPath() {
7305
- return join18(globalDir(), "unerrd.pid");
7305
+ return join19(globalDir(), "unerrd.pid");
7306
7306
  }
7307
7307
  function sockPath() {
7308
- return join18(globalDir(), "unerrd.sock");
7308
+ return join19(globalDir(), "unerrd.sock");
7309
7309
  }
7310
7310
  function isProcessAlive(pid) {
7311
7311
  try {
@@ -7318,7 +7318,7 @@ function isProcessAlive(pid) {
7318
7318
  function acquirePidLock() {
7319
7319
  const p = pidPath();
7320
7320
  try {
7321
- const raw = readFileSync16(p, "utf-8").trim();
7321
+ const raw = readFileSync17(p, "utf-8").trim();
7322
7322
  const existingPid = Number.parseInt(raw, 10);
7323
7323
  if (Number.isFinite(existingPid) && isProcessAlive(existingPid)) {
7324
7324
  return false;
@@ -7326,7 +7326,7 @@ function acquirePidLock() {
7326
7326
  } catch {
7327
7327
  }
7328
7328
  const dir = globalDir();
7329
- if (!existsSync19(dir)) mkdirSync12(dir, { recursive: true });
7329
+ if (!existsSync20(dir)) mkdirSync13(dir, { recursive: true });
7330
7330
  writeFileSync10(p, `${process.pid}
7331
7331
  `);
7332
7332
  return true;
@@ -7339,7 +7339,7 @@ function releasePidLock() {
7339
7339
  }
7340
7340
  function cleanStaleSocket() {
7341
7341
  const sock = sockPath();
7342
- if (!existsSync19(sock)) return;
7342
+ if (!existsSync20(sock)) return;
7343
7343
  try {
7344
7344
  const probe = createConnection2(sock);
7345
7345
  probe.on("connect", () => {
@@ -7472,21 +7472,21 @@ async function handleRequest(pm, raw) {
7472
7472
  }
7473
7473
  }
7474
7474
  async function startDaemon(opts) {
7475
- const logsDir = join18(globalDir(), "logs");
7476
- if (!existsSync19(logsDir)) mkdirSync12(logsDir, { recursive: true });
7475
+ const logsDir = join19(globalDir(), "logs");
7476
+ if (!existsSync20(logsDir)) mkdirSync13(logsDir, { recursive: true });
7477
7477
  installFileLogger({
7478
- filePath: join18(logsDir, "unerrd.log"),
7478
+ filePath: join19(logsDir, "unerrd.log"),
7479
7479
  maxBytes: 1e7,
7480
7480
  keep: 5
7481
7481
  });
7482
7482
  if (!acquirePidLock()) {
7483
- log.info("unerrd is already running. Exiting.");
7483
+ log2.info("unerrd is already running. Exiting.");
7484
7484
  process.exit(0);
7485
7485
  }
7486
7486
  cleanStaleSocket();
7487
7487
  await new Promise((r) => setTimeout(r, 100));
7488
7488
  const sock = sockPath();
7489
- if (existsSync19(sock)) {
7489
+ if (existsSync20(sock)) {
7490
7490
  try {
7491
7491
  unlinkSync6(sock);
7492
7492
  } catch {
@@ -7494,7 +7494,7 @@ async function startDaemon(opts) {
7494
7494
  }
7495
7495
  const pm = new ProcessManager();
7496
7496
  pm.setEventHandler((event, repo, detail2) => {
7497
- log.info(`[${repo.label}] ${event}${detail2 ? `: ${detail2}` : ""}`);
7497
+ log2.info(`[${repo.label}] ${event}${detail2 ? `: ${detail2}` : ""}`);
7498
7498
  });
7499
7499
  const server = createUdsServer(pm);
7500
7500
  let shutdownRequested = false;
@@ -7504,7 +7504,7 @@ async function startDaemon(opts) {
7504
7504
  const shutdown = async (reason) => {
7505
7505
  if (shutdownRequested) return;
7506
7506
  shutdownRequested = true;
7507
- log.info(`Shutting down: ${reason}`);
7507
+ log2.info(`Shutting down: ${reason}`);
7508
7508
  pm.stopIdleSweep();
7509
7509
  apiHandle?.close();
7510
7510
  server.close();
@@ -7514,7 +7514,7 @@ async function startDaemon(opts) {
7514
7514
  }
7515
7515
  await pm.shutdownAll();
7516
7516
  releasePidLock();
7517
- log.info("Shutdown complete.");
7517
+ log2.info("Shutdown complete.");
7518
7518
  process.exit(0);
7519
7519
  };
7520
7520
  process.on("SIGTERM", () => shutdown("SIGTERM"));
@@ -7529,7 +7529,7 @@ async function startDaemon(opts) {
7529
7529
  });
7530
7530
  await new Promise((resolve9, reject) => {
7531
7531
  server.on("error", (err) => {
7532
- log.error(`UDS server error: ${err.message}`);
7532
+ log2.error(`UDS server error: ${err.message}`);
7533
7533
  releasePidLock();
7534
7534
  reject(err);
7535
7535
  });
@@ -7543,10 +7543,10 @@ async function startDaemon(opts) {
7543
7543
  const { startDaemonApi: startDaemonApi2 } = await Promise.resolve().then(() => (init_api(), api_exports));
7544
7544
  apiHandle = startDaemonApi2(pm);
7545
7545
  if (apiHandle) {
7546
- log.info(`Dashboard: http://localhost:${apiHandle.port}`);
7546
+ log2.info(`Dashboard: http://localhost:${apiHandle.port}`);
7547
7547
  }
7548
7548
  } catch (err) {
7549
- log.warn(`Dashboard API failed to start: ${err.message}`);
7549
+ log2.warn(`Dashboard API failed to start: ${err.message}`);
7550
7550
  }
7551
7551
  let cancelWarmStart = null;
7552
7552
  try {
@@ -7554,24 +7554,24 @@ async function startDaemon(opts) {
7554
7554
  cancelWarmStart = scheduleWarmStart2(pm, (event) => {
7555
7555
  apiHandle?.pushWarmStartEvent(event);
7556
7556
  if (event.status === "started") {
7557
- log.info(`warm-start: ${event.label} ready (${event.ms}ms)`);
7557
+ log2.info(`warm-start: ${event.label} ready (${event.ms}ms)`);
7558
7558
  } else if (event.status === "skipped") {
7559
- log.info(`warm-start: ${event.label} skipped \u2014 ${event.reason}`);
7559
+ log2.info(`warm-start: ${event.label} skipped \u2014 ${event.reason}`);
7560
7560
  } else if (event.status === "failed") {
7561
- log.warn(`warm-start: ${event.label} failed \u2014 ${event.reason}`);
7561
+ log2.warn(`warm-start: ${event.label} failed \u2014 ${event.reason}`);
7562
7562
  } else if (event.status === "aborted") {
7563
- log.warn(`warm-start: ${event.label} aborted \u2014 ${event.reason}`);
7563
+ log2.warn(`warm-start: ${event.label} aborted \u2014 ${event.reason}`);
7564
7564
  }
7565
7565
  });
7566
7566
  } catch (err) {
7567
- log.warn(`Warm-start scheduler failed: ${err.message}`);
7567
+ log2.warn(`Warm-start scheduler failed: ${err.message}`);
7568
7568
  }
7569
7569
  let cancelVersionCheck = null;
7570
7570
  try {
7571
7571
  const { startPeriodicCheck: startPeriodicCheck2 } = await Promise.resolve().then(() => (init_version_checker(), version_checker_exports));
7572
7572
  cancelVersionCheck = startPeriodicCheck2();
7573
7573
  } catch (err) {
7574
- log.warn(`Version checker failed: ${err.message}`);
7574
+ log2.warn(`Version checker failed: ${err.message}`);
7575
7575
  }
7576
7576
  const origShutdown = shutdown;
7577
7577
  const wrappedShutdown = async (reason) => {
@@ -7583,21 +7583,21 @@ async function startDaemon(opts) {
7583
7583
  process.removeAllListeners("SIGINT");
7584
7584
  process.on("SIGTERM", () => wrappedShutdown("SIGTERM"));
7585
7585
  process.on("SIGINT", () => wrappedShutdown("SIGINT"));
7586
- log.info(
7586
+ log2.info(
7587
7587
  `Started (PID ${process.pid}), ${reg.repos.length} repos registered. Socket: ${sock}`
7588
7588
  );
7589
7589
  if (!opts.background) {
7590
- log.info("Running in foreground. Press Ctrl+C to stop.");
7590
+ log2.info("Running in foreground. Press Ctrl+C to stop.");
7591
7591
  }
7592
7592
  }
7593
- var log;
7593
+ var log2;
7594
7594
  var init_daemon = __esm({
7595
7595
  "src/entrypoints/daemon.ts"() {
7596
7596
  "use strict";
7597
7597
  init_process_manager();
7598
7598
  init_registry();
7599
7599
  init_file_logger();
7600
- log = {
7600
+ log2 = {
7601
7601
  info: (msg) => process.stderr.write(`[unerrd] ${msg}
7602
7602
  `),
7603
7603
  warn: (msg) => process.stderr.write(`[unerrd] WARN: ${msg}
@@ -7615,12 +7615,12 @@ __export(startup_log_exports, {
7615
7615
  startupLog: () => startupLog
7616
7616
  });
7617
7617
  import {
7618
- appendFileSync as appendFileSync4,
7619
- mkdirSync as mkdirSync13,
7620
- readFileSync as readFileSync17,
7618
+ appendFileSync as appendFileSync5,
7619
+ mkdirSync as mkdirSync14,
7620
+ readFileSync as readFileSync18,
7621
7621
  writeFileSync as writeFileSync11
7622
7622
  } from "fs";
7623
- import { join as join19 } from "path";
7623
+ import { join as join20 } from "path";
7624
7624
  function stripAnsi2(s) {
7625
7625
  const ESC2 = "\x1B";
7626
7626
  const CSI = new RegExp(`${ESC2}\\[[0-9;?]*[A-Za-z~]`, "g");
@@ -7629,7 +7629,7 @@ function stripAnsi2(s) {
7629
7629
  }
7630
7630
  function rotateIfNeeded(filePath, maxLines, keepLines) {
7631
7631
  try {
7632
- const content = readFileSync17(filePath, "utf-8");
7632
+ const content = readFileSync18(filePath, "utf-8");
7633
7633
  const lines = content.split("\n").filter(Boolean);
7634
7634
  if (lines.length > maxLines) {
7635
7635
  writeFileSync11(filePath, `${lines.slice(-keepLines).join("\n")}
@@ -7639,9 +7639,9 @@ function rotateIfNeeded(filePath, maxLines, keepLines) {
7639
7639
  }
7640
7640
  }
7641
7641
  function initFileLog(cwd) {
7642
- const logsDir = join19(cwd, ".unerr", "logs");
7643
- mkdirSync13(logsDir, { recursive: true });
7644
- _fileLogPath = join19(logsDir, "unerr.jsonl");
7642
+ const logsDir = join20(cwd, ".unerr", "logs");
7643
+ mkdirSync14(logsDir, { recursive: true });
7644
+ _fileLogPath = join20(logsDir, "unerr.jsonl");
7645
7645
  rotateIfNeeded(_fileLogPath, 2e3, 1e3);
7646
7646
  }
7647
7647
  function writeToFile(level, message, meta) {
@@ -7654,7 +7654,7 @@ function writeToFile(level, message, meta) {
7654
7654
  ...meta
7655
7655
  };
7656
7656
  try {
7657
- appendFileSync4(_fileLogPath, `${JSON.stringify(entry)}
7657
+ appendFileSync5(_fileLogPath, `${JSON.stringify(entry)}
7658
7658
  `);
7659
7659
  if (++_fileLogCount % 200 === 0) rotateIfNeeded(_fileLogPath, 2e3, 1e3);
7660
7660
  } catch {
@@ -42711,6 +42711,11 @@ async function startProxy(opts = {}) {
42711
42711
  }
42712
42712
  } catch {
42713
42713
  }
42714
+ needsBackgroundIndex = true;
42715
+ log22.info("Snapshot migration complete \u2014 scheduling background reindex to refresh graph");
42716
+ startupLog.step(
42717
+ `${startupLog.fmt.muted("Background reindex will refresh graph after MCP ready")}`
42718
+ );
42714
42719
  } else {
42715
42720
  needsBackgroundIndex = true;
42716
42721
  startupLog.step(
@@ -45827,9 +45832,432 @@ function registerCompressOutputCommand(program2) {
45827
45832
  init_config_verify();
45828
45833
 
45829
45834
  // src/commands/daemon.ts
45830
- init_registry();
45831
45835
  import { resolve as resolve5 } from "path";
45832
45836
 
45837
+ // src/commands/doctor.ts
45838
+ import { execSync as execSync2 } from "child_process";
45839
+ import { appendFileSync as appendFileSync3, existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync7 } from "fs";
45840
+ import { homedir as homedir3 } from "os";
45841
+ import { dirname as dirname4, join as join9, normalize } from "path";
45842
+ import { createInterface } from "readline";
45843
+ var hasTTY = !!process.stderr.isTTY;
45844
+ var W = hasTTY ? "\x1B[33m" : "";
45845
+ var G = hasTTY ? "\x1B[32m" : "";
45846
+ var B = hasTTY ? "\x1B[1m" : "";
45847
+ var D = hasTTY ? "\x1B[2m" : "";
45848
+ var R = hasTTY ? "\x1B[0m" : "";
45849
+ var C = hasTTY ? "\x1B[36m" : "";
45850
+ function log(msg) {
45851
+ process.stderr.write(msg);
45852
+ }
45853
+ var isWin = process.platform === "win32";
45854
+ function detectShell() {
45855
+ if (isWin) {
45856
+ const psModulePath = process.env.PSModulePath;
45857
+ if (psModulePath) return "powershell";
45858
+ const comspec = (process.env.ComSpec || "").toLowerCase();
45859
+ if (comspec.endsWith("cmd.exe")) return "cmd";
45860
+ return "powershell";
45861
+ }
45862
+ const shell = (process.env.SHELL || "").split("/").pop() || "unknown";
45863
+ if (shell === "zsh") return "zsh";
45864
+ if (shell === "fish") return "fish";
45865
+ if (shell === "bash") return "bash";
45866
+ return shell;
45867
+ }
45868
+ function getGlobalBin() {
45869
+ try {
45870
+ const prefix = execSync2("npm prefix -g", {
45871
+ encoding: "utf-8",
45872
+ timeout: 5e3,
45873
+ stdio: ["pipe", "pipe", "pipe"]
45874
+ }).trim();
45875
+ return isWin ? prefix : join9(prefix, "bin");
45876
+ } catch {
45877
+ return "";
45878
+ }
45879
+ }
45880
+ function isOnPath(globalBin) {
45881
+ const pathSep = isWin ? ";" : ":";
45882
+ const dirs = (process.env.PATH || "").split(pathSep);
45883
+ const normalized = normalize(globalBin).replace(/[/\\]+$/, "");
45884
+ return dirs.some((d) => {
45885
+ const nd = normalize(d).replace(/[/\\]+$/, "");
45886
+ return isWin ? nd.toLowerCase() === normalized.toLowerCase() : nd === normalized;
45887
+ });
45888
+ }
45889
+ function getRcPath(shell) {
45890
+ const home = homedir3();
45891
+ switch (shell) {
45892
+ case "zsh":
45893
+ return join9(home, ".zshrc");
45894
+ case "fish":
45895
+ return join9(home, ".config", "fish", "config.fish");
45896
+ case "bash":
45897
+ return join9(home, ".bashrc");
45898
+ case "powershell": {
45899
+ const docs = process.env.USERPROFILE ? join9(process.env.USERPROFILE, "Documents") : join9(home, "Documents");
45900
+ const ps7Profile = join9(
45901
+ docs,
45902
+ "PowerShell",
45903
+ "Microsoft.PowerShell_profile.ps1"
45904
+ );
45905
+ const ps5Profile = join9(
45906
+ docs,
45907
+ "WindowsPowerShell",
45908
+ "Microsoft.PowerShell_profile.ps1"
45909
+ );
45910
+ if (existsSync8(dirname4(ps7Profile))) return ps7Profile;
45911
+ return ps5Profile;
45912
+ }
45913
+ case "cmd":
45914
+ return join9(home, ".unerr-path.cmd");
45915
+ default:
45916
+ return join9(home, ".bashrc");
45917
+ }
45918
+ }
45919
+ function getRcDisplayName(shell) {
45920
+ const rcPath = getRcPath(shell);
45921
+ const home = homedir3();
45922
+ if (rcPath.startsWith(home)) {
45923
+ return isWin ? `%USERPROFILE%${rcPath.slice(home.length)}` : `~${rcPath.slice(home.length)}`;
45924
+ }
45925
+ return rcPath;
45926
+ }
45927
+ function getFixPayload(shell, globalBin) {
45928
+ const home = homedir3();
45929
+ const hasNvm = !!process.env.NVM_DIR;
45930
+ const hasFnm = !!process.env.FNM_MULTISHELL_PATH;
45931
+ const hasVolta = !!process.env.VOLTA_HOME;
45932
+ if (shell === "powershell") {
45933
+ if (hasVolta) {
45934
+ return {
45935
+ lines: [
45936
+ "",
45937
+ "# volta \u2014 JavaScript tool manager (added by unerr doctor)",
45938
+ '$env:VOLTA_HOME = "$env:USERPROFILE\\.volta"',
45939
+ '$env:PATH = "$env:VOLTA_HOME\\bin;$env:PATH"'
45940
+ ],
45941
+ description: "volta PATH setup for PowerShell",
45942
+ canAutoFix: true,
45943
+ reloadInstruction: ". $PROFILE"
45944
+ };
45945
+ }
45946
+ const portableBin2 = globalBin.startsWith(home) ? globalBin.replace(home, "$env:USERPROFILE") : globalBin;
45947
+ return {
45948
+ lines: [
45949
+ "",
45950
+ "# npm global bin (added by unerr doctor)",
45951
+ `$env:PATH = "${portableBin2};$env:PATH"`
45952
+ ],
45953
+ description: "PATH export for PowerShell",
45954
+ canAutoFix: true,
45955
+ reloadInstruction: ". $PROFILE"
45956
+ };
45957
+ }
45958
+ if (shell === "cmd") {
45959
+ const portableBin2 = globalBin.startsWith(home) ? globalBin.replace(home, "%USERPROFILE%") : globalBin;
45960
+ return {
45961
+ lines: [
45962
+ ":: npm global bin (added by unerr doctor)",
45963
+ `setx PATH "${portableBin2};%PATH%"`
45964
+ ],
45965
+ description: "Permanently add npm global bin to user PATH via setx",
45966
+ canAutoFix: true,
45967
+ reloadInstruction: "open a new Command Prompt"
45968
+ };
45969
+ }
45970
+ if (hasNvm) {
45971
+ if (shell === "fish") {
45972
+ return {
45973
+ lines: [
45974
+ "# nvm \u2014 install nvm.fish: https://github.com/jorgebucaran/nvm.fish"
45975
+ ],
45976
+ description: "nvm init for fish (manual \u2014 requires nvm.fish plugin)",
45977
+ canAutoFix: false,
45978
+ reloadInstruction: "source ~/.config/fish/config.fish"
45979
+ };
45980
+ }
45981
+ const nvmDir = process.env.NVM_DIR || "$HOME/.nvm";
45982
+ return {
45983
+ lines: [
45984
+ "",
45985
+ "# nvm \u2014 load Node version manager (added by unerr doctor)",
45986
+ `export NVM_DIR="${nvmDir}"`,
45987
+ `[ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh"`
45988
+ ],
45989
+ description: "nvm init block",
45990
+ canAutoFix: true,
45991
+ reloadInstruction: `source ${shell === "zsh" ? "~/.zshrc" : "~/.bashrc"}`
45992
+ };
45993
+ }
45994
+ if (hasFnm) {
45995
+ const initLine = shell === "fish" ? "fnm env | source" : 'eval "$(fnm env)"';
45996
+ return {
45997
+ lines: [
45998
+ "",
45999
+ "# fnm \u2014 fast Node manager (added by unerr doctor)",
46000
+ initLine
46001
+ ],
46002
+ description: "fnm env init",
46003
+ canAutoFix: true,
46004
+ reloadInstruction: shell === "fish" ? "source ~/.config/fish/config.fish" : `source ${shell === "zsh" ? "~/.zshrc" : "~/.bashrc"}`
46005
+ };
46006
+ }
46007
+ if (hasVolta) {
46008
+ return {
46009
+ lines: [
46010
+ "",
46011
+ "# volta \u2014 JavaScript tool manager (added by unerr doctor)",
46012
+ 'export VOLTA_HOME="$HOME/.volta"',
46013
+ 'export PATH="$VOLTA_HOME/bin:$PATH"'
46014
+ ],
46015
+ description: "volta PATH setup",
46016
+ canAutoFix: true,
46017
+ reloadInstruction: `source ${shell === "zsh" ? "~/.zshrc" : shell === "fish" ? "~/.config/fish/config.fish" : "~/.bashrc"}`
46018
+ };
46019
+ }
46020
+ const portableBin = globalBin.startsWith(home) ? globalBin.replace(home, "$HOME") : globalBin;
46021
+ const exportLine = shell === "fish" ? `set -gx PATH ${portableBin} $PATH` : `export PATH="${portableBin}:$PATH"`;
46022
+ return {
46023
+ lines: ["", "# npm global bin (added by unerr doctor)", exportLine],
46024
+ description: `PATH export for ${globalBin}`,
46025
+ canAutoFix: true,
46026
+ reloadInstruction: shell === "fish" ? "source ~/.config/fish/config.fish" : `source ${shell === "zsh" ? "~/.zshrc" : "~/.bashrc"}`
46027
+ };
46028
+ }
46029
+ function isAlreadyInRc(rcPath, fix) {
46030
+ if (!existsSync8(rcPath)) return false;
46031
+ const content = readFileSync7(rcPath, "utf-8");
46032
+ const meaningful = fix.lines.filter(
46033
+ (l) => l.trim() && !l.trim().startsWith("#") && !l.trim().startsWith("::")
46034
+ );
46035
+ return meaningful.some((line) => content.includes(line.trim()));
46036
+ }
46037
+ function askYesNo(question) {
46038
+ return new Promise((resolve9) => {
46039
+ const rl = createInterface({
46040
+ input: process.stdin,
46041
+ output: process.stderr
46042
+ });
46043
+ const timer = setTimeout(() => {
46044
+ rl.close();
46045
+ log(`
46046
+ ${D}(timed out \u2014 no changes made)${R}
46047
+ `);
46048
+ resolve9(false);
46049
+ }, 3e4);
46050
+ rl.question(question, (answer) => {
46051
+ clearTimeout(timer);
46052
+ rl.close();
46053
+ const a = answer.trim().toLowerCase();
46054
+ resolve9(a === "" || a === "y" || a === "yes");
46055
+ });
46056
+ });
46057
+ }
46058
+ function applyFix(shell, rcPath, rcName, fix, globalBin) {
46059
+ try {
46060
+ if (shell === "cmd") {
46061
+ execSync2(`setx PATH "${globalBin};%PATH%"`, {
46062
+ encoding: "utf-8",
46063
+ stdio: ["pipe", "pipe", "pipe"]
46064
+ });
46065
+ log(`
46066
+ ${G}\u2713${R} Updated user PATH via ${C}setx${R}
46067
+ `);
46068
+ log(
46069
+ ` ${G}\u2713${R} Open a new Command Prompt for the change to take effect.
46070
+
46071
+ `
46072
+ );
46073
+ } else {
46074
+ const dir = dirname4(rcPath);
46075
+ if (!existsSync8(dir)) {
46076
+ mkdirSync4(dir, { recursive: true });
46077
+ }
46078
+ appendFileSync3(rcPath, `${fix.lines.join("\n")}
46079
+ `, "utf-8");
46080
+ log(`
46081
+ ${G}\u2713${R} Updated ${C}${rcName}${R}
46082
+ `);
46083
+ log(
46084
+ ` ${G}\u2713${R} Run ${C}${fix.reloadInstruction}${R} or open a new terminal.
46085
+
46086
+ `
46087
+ );
46088
+ }
46089
+ } catch (err) {
46090
+ const msg = err instanceof Error ? err.message : String(err);
46091
+ log(`
46092
+ ${W}\u26A0 Could not apply fix: ${msg}${R}
46093
+ `);
46094
+ printManualSteps(shell, fix, rcName);
46095
+ }
46096
+ }
46097
+ function printManualSteps(shell, fix, rcName) {
46098
+ if (shell === "cmd") {
46099
+ log(`
46100
+ ${B}Run the following in an elevated Command Prompt:${R}
46101
+
46102
+ `);
46103
+ for (const line of fix.lines) {
46104
+ if (line.trim() && !line.trim().startsWith("::"))
46105
+ log(` ${C}${line}${R}
46106
+ `);
46107
+ }
46108
+ log(`
46109
+ Then ${C}${fix.reloadInstruction}${R}.
46110
+
46111
+ `);
46112
+ } else {
46113
+ log(`
46114
+ ${B}Add the following to ${rcName}:${R}
46115
+
46116
+ `);
46117
+ for (const line of fix.lines) {
46118
+ if (line.trim() && !line.trim().startsWith("#"))
46119
+ log(` ${C}${line}${R}
46120
+ `);
46121
+ }
46122
+ log(
46123
+ `
46124
+ Then reload: ${C}${fix.reloadInstruction}${R} or open a new terminal.
46125
+
46126
+ `
46127
+ );
46128
+ }
46129
+ }
46130
+ function isUnerrOnPathViaWhere() {
46131
+ try {
46132
+ const result = execSync2("where unerr", {
46133
+ encoding: "utf-8",
46134
+ timeout: 5e3,
46135
+ stdio: ["pipe", "pipe", "pipe"]
46136
+ }).trim();
46137
+ return result.length > 0;
46138
+ } catch {
46139
+ return false;
46140
+ }
46141
+ }
46142
+ function verifyUnerrOnPath() {
46143
+ const globalBin = getGlobalBin();
46144
+ if (!globalBin) return true;
46145
+ const normalizedBin = normalize(globalBin).replace(/[/\\]+$/, "");
46146
+ const onPath = isOnPath(normalizedBin) || isWin && isUnerrOnPathViaWhere();
46147
+ if (onPath) return true;
46148
+ const hasTTYLocal = !!process.stderr.isTTY;
46149
+ const w = hasTTYLocal ? "\x1B[33m" : "";
46150
+ const b = hasTTYLocal ? "\x1B[1m" : "";
46151
+ const d = hasTTYLocal ? "\x1B[2m" : "";
46152
+ const r = hasTTYLocal ? "\x1B[0m" : "";
46153
+ process.stderr.write(
46154
+ `${w}\u26A0${r} ${b}unerr${r} may not be on your PATH in new terminals.
46155
+ ${d} Run ${b}unerr doctor${r}${d} to diagnose and fix.${r}
46156
+
46157
+ `
46158
+ );
46159
+ return false;
46160
+ }
46161
+ function registerDoctorCommand(program2) {
46162
+ program2.command("doctor").description("Check environment and fix PATH issues").action(async () => {
46163
+ log(`
46164
+ ${B}unerr doctor${R}
46165
+
46166
+ `);
46167
+ const globalBin = getGlobalBin();
46168
+ if (!globalBin) {
46169
+ log(` ${W}\u26A0${R} Could not determine npm global bin directory.
46170
+ `);
46171
+ log(
46172
+ ` ${D}Run ${C}npm prefix -g${D} to verify npm is working.${R}
46173
+
46174
+ `
46175
+ );
46176
+ process.exitCode = 1;
46177
+ return;
46178
+ }
46179
+ const normalizedBin = normalize(globalBin).replace(/[/\\]+$/, "");
46180
+ const onPath = isOnPath(normalizedBin) || isWin && isUnerrOnPathViaWhere();
46181
+ if (onPath) {
46182
+ const displayBin = isWin ? normalizedBin.replace(homedir3(), "%USERPROFILE%") : normalizedBin.replace(homedir3(), "~");
46183
+ log(
46184
+ ` ${G}\u2713${R} ${B}unerr${R} is on PATH and ready to use in all terminals.
46185
+ `
46186
+ );
46187
+ log(` ${D}Global bin: ${displayBin}${R}
46188
+
46189
+ `);
46190
+ return;
46191
+ }
46192
+ const shell = detectShell();
46193
+ const rcPath = getRcPath(shell);
46194
+ const rcName = getRcDisplayName(shell);
46195
+ const fix = getFixPayload(shell, normalizedBin);
46196
+ log(
46197
+ ` ${W}\u26A0${R} npm global bin directory is ${B}not on your PATH${R}:
46198
+ `
46199
+ );
46200
+ log(` ${C}${normalizedBin}${R}
46201
+
46202
+ `);
46203
+ log(
46204
+ ` ${D}This means ${B}unerr${D} won't be found in new terminal sessions.${R}
46205
+
46206
+ `
46207
+ );
46208
+ if (isAlreadyInRc(rcPath, fix)) {
46209
+ log(
46210
+ ` ${D}The required lines already exist in ${rcName} but PATH still doesn't include the bin dir.${R}
46211
+ `
46212
+ );
46213
+ if (shell === "cmd" || shell === "powershell") {
46214
+ log(
46215
+ ` ${D}Try opening a new terminal window, or run: ${C}refreshenv${R}
46216
+
46217
+ `
46218
+ );
46219
+ } else {
46220
+ log(
46221
+ ` ${D}This may mean ${rcName} isn't being sourced by your terminal.${R}
46222
+ `
46223
+ );
46224
+ log(
46225
+ ` ${D}Check your terminal app settings, or try: ${C}${fix.reloadInstruction}${R}
46226
+
46227
+ `
46228
+ );
46229
+ }
46230
+ return;
46231
+ }
46232
+ if (!fix.canAutoFix) {
46233
+ printManualSteps(shell, fix, rcName);
46234
+ return;
46235
+ }
46236
+ const commentPrefix = shell === "cmd" ? "::" : "#";
46237
+ const preview = fix.lines.filter((l) => l.trim() && !l.trim().startsWith(commentPrefix)).join("\n ");
46238
+ log(` ${B}Fix:${R} ${fix.description}
46239
+ `);
46240
+ log(` ${D}Target: ${C}${rcName}${R}
46241
+
46242
+ `);
46243
+ log(` ${D}${preview}${R}
46244
+
46245
+ `);
46246
+ const answer = await askYesNo(` Apply this fix now? ${D}[Y/n]${R} `);
46247
+ if (answer) {
46248
+ applyFix(shell, rcPath, rcName, fix, normalizedBin);
46249
+ } else {
46250
+ log(`
46251
+ ${D}No changes made.${R}
46252
+ `);
46253
+ printManualSteps(shell, fix, rcName);
46254
+ }
46255
+ });
46256
+ }
46257
+
46258
+ // src/commands/daemon.ts
46259
+ init_registry();
46260
+
45833
46261
  // src/daemon/settings-schema.ts
45834
46262
  init_protocol();
45835
46263
  var parsePositiveInt = (raw) => {
@@ -45907,6 +46335,7 @@ function registerDaemonCommand(program2) {
45907
46335
  daemon.command("initialize").description(
45908
46336
  "One-time daemon setup: register at boot (launchd/systemd/schtasks) and start unerrd"
45909
46337
  ).action(async () => {
46338
+ verifyUnerrOnPath();
45910
46339
  const { installForCurrentPlatform: installForCurrentPlatform2 } = await Promise.resolve().then(() => (init_autostart(), autostart_exports));
45911
46340
  const { existsSync: existsSync81, mkdirSync: mkdirSync50, writeFileSync: writeFileSync43 } = await import("fs");
45912
46341
  const { homedir: homedir17 } = await import("os");
@@ -46875,13 +47304,13 @@ function toKebab(s) {
46875
47304
  init_exec();
46876
47305
  init_git();
46877
47306
  init_startup_log();
46878
- import { existsSync as existsSync20, readFileSync as readFileSync18 } from "fs";
46879
- import { join as join20 } from "path";
47307
+ import { existsSync as existsSync21, readFileSync as readFileSync19 } from "fs";
47308
+ import { join as join21 } from "path";
46880
47309
  function readServerJson(cwd) {
46881
- const p = join20(cwd, ".unerr", "state", "server.json");
46882
- if (!existsSync20(p)) return null;
47310
+ const p = join21(cwd, ".unerr", "state", "server.json");
47311
+ if (!existsSync21(p)) return null;
46883
47312
  try {
46884
- const raw = readFileSync18(p, "utf-8");
47313
+ const raw = readFileSync19(p, "utf-8");
46885
47314
  return JSON.parse(raw);
46886
47315
  } catch {
46887
47316
  return null;
@@ -46920,10 +47349,10 @@ function registerDashboardCommand(program2) {
46920
47349
 
46921
47350
  // src/commands/debug.ts
46922
47351
  init_git();
46923
- import { existsSync as existsSync21, readFileSync as readFileSync19, readdirSync as readdirSync4, statSync as statSync3 } from "fs";
46924
- import { arch, homedir as homedir10, platform as platform3, release } from "os";
46925
- import { join as join21 } from "path";
46926
- var UNERR_DIR = join21(homedir10(), ".unerr");
47352
+ import { existsSync as existsSync22, readFileSync as readFileSync20, readdirSync as readdirSync4, statSync as statSync3 } from "fs";
47353
+ import { arch, homedir as homedir11, platform as platform3, release } from "os";
47354
+ import { join as join22 } from "path";
47355
+ var UNERR_DIR = join22(homedir11(), ".unerr");
46927
47356
  function registerDebugCommand(program2) {
46928
47357
  program2.command("debug").description("Diagnostics dump for support").action(async () => {
46929
47358
  const sections = [];
@@ -46934,11 +47363,11 @@ function registerDebugCommand(program2) {
46934
47363
  sections.push(" CLI: 0.1.0");
46935
47364
  sections.push("");
46936
47365
  sections.push("## Settings");
46937
- const settingsPath = join21(UNERR_DIR, "settings.json");
46938
- if (existsSync21(settingsPath)) {
47366
+ const settingsPath = join22(UNERR_DIR, "settings.json");
47367
+ if (existsSync22(settingsPath)) {
46939
47368
  try {
46940
47369
  const settings = JSON.parse(
46941
- readFileSync19(settingsPath, "utf-8")
47370
+ readFileSync20(settingsPath, "utf-8")
46942
47371
  );
46943
47372
  for (const [key, value] of Object.entries(settings)) {
46944
47373
  if (key === "anthropicApiKey" && typeof value === "string") {
@@ -46962,11 +47391,11 @@ function registerDebugCommand(program2) {
46962
47391
  sections.push(` Branch: ${branch ?? "(detached)"}`);
46963
47392
  sections.push("");
46964
47393
  sections.push("## Project Config (.unerr/config.json)");
46965
- const configPath = join21(process.cwd(), ".unerr", "config.json");
46966
- if (existsSync21(configPath)) {
47394
+ const configPath = join22(process.cwd(), ".unerr", "config.json");
47395
+ if (existsSync22(configPath)) {
46967
47396
  try {
46968
47397
  const config = JSON.parse(
46969
- readFileSync19(configPath, "utf-8")
47398
+ readFileSync20(configPath, "utf-8")
46970
47399
  );
46971
47400
  for (const [key, value] of Object.entries(config)) {
46972
47401
  sections.push(` ${key}: ${String(value)}`);
@@ -46979,11 +47408,11 @@ function registerDebugCommand(program2) {
46979
47408
  }
46980
47409
  sections.push("");
46981
47410
  sections.push("## Proxy Status");
46982
- const pidPath2 = join21(process.cwd(), ".unerr", "state", "proxy.pid");
46983
- if (existsSync21(pidPath2)) {
47411
+ const pidPath2 = join22(process.cwd(), ".unerr", "state", "proxy.pid");
47412
+ if (existsSync22(pidPath2)) {
46984
47413
  try {
46985
47414
  const pid = Number.parseInt(
46986
- readFileSync19(pidPath2, "utf-8").trim(),
47415
+ readFileSync20(pidPath2, "utf-8").trim(),
46987
47416
  10
46988
47417
  );
46989
47418
  let alive = false;
@@ -47001,22 +47430,22 @@ function registerDebugCommand(program2) {
47001
47430
  }
47002
47431
  sections.push("");
47003
47432
  sections.push("## .unerr/ Directory (repo-local)");
47004
- const localUnerrDir = join21(process.cwd(), ".unerr");
47005
- if (existsSync21(localUnerrDir)) {
47433
+ const localUnerrDir = join22(process.cwd(), ".unerr");
47434
+ if (existsSync22(localUnerrDir)) {
47006
47435
  listDir(localUnerrDir, " ", sections, 0, 2);
47007
47436
  } else {
47008
47437
  sections.push(" (not found)");
47009
47438
  }
47010
47439
  sections.push("");
47011
47440
  sections.push("## Snapshots");
47012
- const snapshotsDir = join21(localUnerrDir, "snapshots");
47013
- if (existsSync21(snapshotsDir)) {
47441
+ const snapshotsDir = join22(localUnerrDir, "snapshots");
47442
+ if (existsSync22(snapshotsDir)) {
47014
47443
  const files = readdirSync4(snapshotsDir);
47015
47444
  if (files.length === 0) {
47016
47445
  sections.push(" (empty)");
47017
47446
  }
47018
47447
  for (const file of files) {
47019
- const filePath = join21(snapshotsDir, file);
47448
+ const filePath = join22(snapshotsDir, file);
47020
47449
  const stat2 = statSync3(filePath);
47021
47450
  sections.push(` ${file}: ${formatBytes(stat2.size)}`);
47022
47451
  }
@@ -47026,11 +47455,11 @@ function registerDebugCommand(program2) {
47026
47455
  sections.push("");
47027
47456
  sections.push("## MCP Config Locations");
47028
47457
  const mcpLocations = [
47029
- join21(process.cwd(), ".cursor", "mcp.json"),
47030
- join21(process.cwd(), ".vscode", "mcp.json"),
47031
- join21(homedir10(), ".claude", "claude_desktop_config.json"),
47032
- join21(
47033
- homedir10(),
47458
+ join22(process.cwd(), ".cursor", "mcp.json"),
47459
+ join22(process.cwd(), ".vscode", "mcp.json"),
47460
+ join22(homedir11(), ".claude", "claude_desktop_config.json"),
47461
+ join22(
47462
+ homedir11(),
47034
47463
  "Library",
47035
47464
  "Application Support",
47036
47465
  "Cursor",
@@ -47041,20 +47470,20 @@ function registerDebugCommand(program2) {
47041
47470
  )
47042
47471
  ];
47043
47472
  for (const loc of mcpLocations) {
47044
- const exists = existsSync21(loc);
47473
+ const exists = existsSync22(loc);
47045
47474
  sections.push(
47046
- ` ${exists ? "[x]" : "[ ]"} ${loc.replace(homedir10(), "~")}`
47475
+ ` ${exists ? "[x]" : "[ ]"} ${loc.replace(homedir11(), "~")}`
47047
47476
  );
47048
47477
  }
47049
47478
  sections.push("");
47050
47479
  sections.push("## Recent Log (last 20 lines)");
47051
- const logsDir = join21(process.cwd(), ".unerr", "logs");
47052
- if (existsSync21(logsDir)) {
47480
+ const logsDir = join22(process.cwd(), ".unerr", "logs");
47481
+ if (existsSync22(logsDir)) {
47053
47482
  const logFiles = readdirSync4(logsDir).filter((f) => f.endsWith(".log")).sort().reverse();
47054
47483
  if (logFiles.length > 0 && logFiles[0]) {
47055
- const logPath2 = join21(logsDir, logFiles[0]);
47484
+ const logPath2 = join22(logsDir, logFiles[0]);
47056
47485
  try {
47057
- const content = readFileSync19(logPath2, "utf-8");
47486
+ const content = readFileSync20(logPath2, "utf-8");
47058
47487
  const lines = content.split("\n").filter(Boolean);
47059
47488
  const last20 = lines.slice(-20);
47060
47489
  for (const line of last20) {
@@ -47085,14 +47514,14 @@ function listDir(dirPath, indent, out, depth, maxDepth) {
47085
47514
  if (entry.isDirectory()) {
47086
47515
  out.push(`${indent}${entry.name}/`);
47087
47516
  listDir(
47088
- join21(dirPath, entry.name),
47517
+ join22(dirPath, entry.name),
47089
47518
  `${indent} `,
47090
47519
  out,
47091
47520
  depth + 1,
47092
47521
  maxDepth
47093
47522
  );
47094
47523
  } else {
47095
- const size = formatBytes(statSync3(join21(dirPath, entry.name)).size);
47524
+ const size = formatBytes(statSync3(join22(dirPath, entry.name)).size);
47096
47525
  out.push(`${indent}${entry.name} (${size})`);
47097
47526
  }
47098
47527
  }
@@ -47101,408 +47530,6 @@ function listDir(dirPath, indent, out, depth, maxDepth) {
47101
47530
  }
47102
47531
  }
47103
47532
 
47104
- // src/commands/doctor.ts
47105
- import { execSync as execSync6 } from "child_process";
47106
- import { appendFileSync as appendFileSync5, existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync20 } from "fs";
47107
- import { homedir as homedir11 } from "os";
47108
- import { dirname as dirname10, join as join22, normalize } from "path";
47109
- import { createInterface } from "readline";
47110
- var hasTTY = !!process.stderr.isTTY;
47111
- var W = hasTTY ? "\x1B[33m" : "";
47112
- var G = hasTTY ? "\x1B[32m" : "";
47113
- var B = hasTTY ? "\x1B[1m" : "";
47114
- var D = hasTTY ? "\x1B[2m" : "";
47115
- var R = hasTTY ? "\x1B[0m" : "";
47116
- var C = hasTTY ? "\x1B[36m" : "";
47117
- function log2(msg) {
47118
- process.stderr.write(msg);
47119
- }
47120
- var isWin = process.platform === "win32";
47121
- function detectShell() {
47122
- if (isWin) {
47123
- const psModulePath = process.env.PSModulePath;
47124
- if (psModulePath) return "powershell";
47125
- const comspec = (process.env.ComSpec || "").toLowerCase();
47126
- if (comspec.endsWith("cmd.exe")) return "cmd";
47127
- return "powershell";
47128
- }
47129
- const shell = (process.env.SHELL || "").split("/").pop() || "unknown";
47130
- if (shell === "zsh") return "zsh";
47131
- if (shell === "fish") return "fish";
47132
- if (shell === "bash") return "bash";
47133
- return shell;
47134
- }
47135
- function getGlobalBin() {
47136
- try {
47137
- const prefix = execSync6("npm prefix -g", {
47138
- encoding: "utf-8",
47139
- timeout: 5e3,
47140
- stdio: ["pipe", "pipe", "pipe"]
47141
- }).trim();
47142
- return isWin ? prefix : join22(prefix, "bin");
47143
- } catch {
47144
- return "";
47145
- }
47146
- }
47147
- function isOnPath(globalBin) {
47148
- const pathSep = isWin ? ";" : ":";
47149
- const dirs = (process.env.PATH || "").split(pathSep);
47150
- const normalized = normalize(globalBin).replace(/[/\\]+$/, "");
47151
- return dirs.some((d) => {
47152
- const nd = normalize(d).replace(/[/\\]+$/, "");
47153
- return isWin ? nd.toLowerCase() === normalized.toLowerCase() : nd === normalized;
47154
- });
47155
- }
47156
- function getRcPath(shell) {
47157
- const home = homedir11();
47158
- switch (shell) {
47159
- case "zsh":
47160
- return join22(home, ".zshrc");
47161
- case "fish":
47162
- return join22(home, ".config", "fish", "config.fish");
47163
- case "bash":
47164
- return join22(home, ".bashrc");
47165
- case "powershell": {
47166
- const docs = process.env.USERPROFILE ? join22(process.env.USERPROFILE, "Documents") : join22(home, "Documents");
47167
- const ps7Profile = join22(
47168
- docs,
47169
- "PowerShell",
47170
- "Microsoft.PowerShell_profile.ps1"
47171
- );
47172
- const ps5Profile = join22(
47173
- docs,
47174
- "WindowsPowerShell",
47175
- "Microsoft.PowerShell_profile.ps1"
47176
- );
47177
- if (existsSync22(dirname10(ps7Profile))) return ps7Profile;
47178
- return ps5Profile;
47179
- }
47180
- case "cmd":
47181
- return join22(home, ".unerr-path.cmd");
47182
- default:
47183
- return join22(home, ".bashrc");
47184
- }
47185
- }
47186
- function getRcDisplayName(shell) {
47187
- const rcPath = getRcPath(shell);
47188
- const home = homedir11();
47189
- if (rcPath.startsWith(home)) {
47190
- return isWin ? `%USERPROFILE%${rcPath.slice(home.length)}` : `~${rcPath.slice(home.length)}`;
47191
- }
47192
- return rcPath;
47193
- }
47194
- function getFixPayload(shell, globalBin) {
47195
- const home = homedir11();
47196
- const hasNvm = !!process.env.NVM_DIR;
47197
- const hasFnm = !!process.env.FNM_MULTISHELL_PATH;
47198
- const hasVolta = !!process.env.VOLTA_HOME;
47199
- if (shell === "powershell") {
47200
- if (hasVolta) {
47201
- return {
47202
- lines: [
47203
- "",
47204
- "# volta \u2014 JavaScript tool manager (added by unerr doctor)",
47205
- '$env:VOLTA_HOME = "$env:USERPROFILE\\.volta"',
47206
- '$env:PATH = "$env:VOLTA_HOME\\bin;$env:PATH"'
47207
- ],
47208
- description: "volta PATH setup for PowerShell",
47209
- canAutoFix: true,
47210
- reloadInstruction: ". $PROFILE"
47211
- };
47212
- }
47213
- const portableBin2 = globalBin.startsWith(home) ? globalBin.replace(home, "$env:USERPROFILE") : globalBin;
47214
- return {
47215
- lines: [
47216
- "",
47217
- "# npm global bin (added by unerr doctor)",
47218
- `$env:PATH = "${portableBin2};$env:PATH"`
47219
- ],
47220
- description: "PATH export for PowerShell",
47221
- canAutoFix: true,
47222
- reloadInstruction: ". $PROFILE"
47223
- };
47224
- }
47225
- if (shell === "cmd") {
47226
- const portableBin2 = globalBin.startsWith(home) ? globalBin.replace(home, "%USERPROFILE%") : globalBin;
47227
- return {
47228
- lines: [
47229
- ":: npm global bin (added by unerr doctor)",
47230
- `setx PATH "${portableBin2};%PATH%"`
47231
- ],
47232
- description: "Permanently add npm global bin to user PATH via setx",
47233
- canAutoFix: true,
47234
- reloadInstruction: "open a new Command Prompt"
47235
- };
47236
- }
47237
- if (hasNvm) {
47238
- if (shell === "fish") {
47239
- return {
47240
- lines: [
47241
- "# nvm \u2014 install nvm.fish: https://github.com/jorgebucaran/nvm.fish"
47242
- ],
47243
- description: "nvm init for fish (manual \u2014 requires nvm.fish plugin)",
47244
- canAutoFix: false,
47245
- reloadInstruction: "source ~/.config/fish/config.fish"
47246
- };
47247
- }
47248
- const nvmDir = process.env.NVM_DIR || "$HOME/.nvm";
47249
- return {
47250
- lines: [
47251
- "",
47252
- "# nvm \u2014 load Node version manager (added by unerr doctor)",
47253
- `export NVM_DIR="${nvmDir}"`,
47254
- `[ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh"`
47255
- ],
47256
- description: "nvm init block",
47257
- canAutoFix: true,
47258
- reloadInstruction: `source ${shell === "zsh" ? "~/.zshrc" : "~/.bashrc"}`
47259
- };
47260
- }
47261
- if (hasFnm) {
47262
- const initLine = shell === "fish" ? "fnm env | source" : 'eval "$(fnm env)"';
47263
- return {
47264
- lines: [
47265
- "",
47266
- "# fnm \u2014 fast Node manager (added by unerr doctor)",
47267
- initLine
47268
- ],
47269
- description: "fnm env init",
47270
- canAutoFix: true,
47271
- reloadInstruction: shell === "fish" ? "source ~/.config/fish/config.fish" : `source ${shell === "zsh" ? "~/.zshrc" : "~/.bashrc"}`
47272
- };
47273
- }
47274
- if (hasVolta) {
47275
- return {
47276
- lines: [
47277
- "",
47278
- "# volta \u2014 JavaScript tool manager (added by unerr doctor)",
47279
- 'export VOLTA_HOME="$HOME/.volta"',
47280
- 'export PATH="$VOLTA_HOME/bin:$PATH"'
47281
- ],
47282
- description: "volta PATH setup",
47283
- canAutoFix: true,
47284
- reloadInstruction: `source ${shell === "zsh" ? "~/.zshrc" : shell === "fish" ? "~/.config/fish/config.fish" : "~/.bashrc"}`
47285
- };
47286
- }
47287
- const portableBin = globalBin.startsWith(home) ? globalBin.replace(home, "$HOME") : globalBin;
47288
- const exportLine = shell === "fish" ? `set -gx PATH ${portableBin} $PATH` : `export PATH="${portableBin}:$PATH"`;
47289
- return {
47290
- lines: ["", "# npm global bin (added by unerr doctor)", exportLine],
47291
- description: `PATH export for ${globalBin}`,
47292
- canAutoFix: true,
47293
- reloadInstruction: shell === "fish" ? "source ~/.config/fish/config.fish" : `source ${shell === "zsh" ? "~/.zshrc" : "~/.bashrc"}`
47294
- };
47295
- }
47296
- function isAlreadyInRc(rcPath, fix) {
47297
- if (!existsSync22(rcPath)) return false;
47298
- const content = readFileSync20(rcPath, "utf-8");
47299
- const meaningful = fix.lines.filter(
47300
- (l) => l.trim() && !l.trim().startsWith("#") && !l.trim().startsWith("::")
47301
- );
47302
- return meaningful.some((line) => content.includes(line.trim()));
47303
- }
47304
- function askYesNo(question) {
47305
- return new Promise((resolve9) => {
47306
- const rl = createInterface({
47307
- input: process.stdin,
47308
- output: process.stderr
47309
- });
47310
- const timer = setTimeout(() => {
47311
- rl.close();
47312
- log2(`
47313
- ${D}(timed out \u2014 no changes made)${R}
47314
- `);
47315
- resolve9(false);
47316
- }, 3e4);
47317
- rl.question(question, (answer) => {
47318
- clearTimeout(timer);
47319
- rl.close();
47320
- const a = answer.trim().toLowerCase();
47321
- resolve9(a === "" || a === "y" || a === "yes");
47322
- });
47323
- });
47324
- }
47325
- function applyFix(shell, rcPath, rcName, fix, globalBin) {
47326
- try {
47327
- if (shell === "cmd") {
47328
- execSync6(`setx PATH "${globalBin};%PATH%"`, {
47329
- encoding: "utf-8",
47330
- stdio: ["pipe", "pipe", "pipe"]
47331
- });
47332
- log2(`
47333
- ${G}\u2713${R} Updated user PATH via ${C}setx${R}
47334
- `);
47335
- log2(
47336
- ` ${G}\u2713${R} Open a new Command Prompt for the change to take effect.
47337
-
47338
- `
47339
- );
47340
- } else {
47341
- const dir = dirname10(rcPath);
47342
- if (!existsSync22(dir)) {
47343
- mkdirSync14(dir, { recursive: true });
47344
- }
47345
- appendFileSync5(rcPath, `${fix.lines.join("\n")}
47346
- `, "utf-8");
47347
- log2(`
47348
- ${G}\u2713${R} Updated ${C}${rcName}${R}
47349
- `);
47350
- log2(
47351
- ` ${G}\u2713${R} Run ${C}${fix.reloadInstruction}${R} or open a new terminal.
47352
-
47353
- `
47354
- );
47355
- }
47356
- } catch (err) {
47357
- const msg = err instanceof Error ? err.message : String(err);
47358
- log2(`
47359
- ${W}\u26A0 Could not apply fix: ${msg}${R}
47360
- `);
47361
- printManualSteps(shell, fix, rcName);
47362
- }
47363
- }
47364
- function printManualSteps(shell, fix, rcName) {
47365
- if (shell === "cmd") {
47366
- log2(`
47367
- ${B}Run the following in an elevated Command Prompt:${R}
47368
-
47369
- `);
47370
- for (const line of fix.lines) {
47371
- if (line.trim() && !line.trim().startsWith("::"))
47372
- log2(` ${C}${line}${R}
47373
- `);
47374
- }
47375
- log2(`
47376
- Then ${C}${fix.reloadInstruction}${R}.
47377
-
47378
- `);
47379
- } else {
47380
- log2(`
47381
- ${B}Add the following to ${rcName}:${R}
47382
-
47383
- `);
47384
- for (const line of fix.lines) {
47385
- if (line.trim() && !line.trim().startsWith("#"))
47386
- log2(` ${C}${line}${R}
47387
- `);
47388
- }
47389
- log2(
47390
- `
47391
- Then reload: ${C}${fix.reloadInstruction}${R} or open a new terminal.
47392
-
47393
- `
47394
- );
47395
- }
47396
- }
47397
- function isUnerrOnPathViaWhere() {
47398
- try {
47399
- const result = execSync6("where unerr", {
47400
- encoding: "utf-8",
47401
- timeout: 5e3,
47402
- stdio: ["pipe", "pipe", "pipe"]
47403
- }).trim();
47404
- return result.length > 0;
47405
- } catch {
47406
- return false;
47407
- }
47408
- }
47409
- function registerDoctorCommand(program2) {
47410
- program2.command("doctor").description("Check environment and fix PATH issues").action(async () => {
47411
- log2(`
47412
- ${B}unerr doctor${R}
47413
-
47414
- `);
47415
- const globalBin = getGlobalBin();
47416
- if (!globalBin) {
47417
- log2(` ${W}\u26A0${R} Could not determine npm global bin directory.
47418
- `);
47419
- log2(
47420
- ` ${D}Run ${C}npm prefix -g${D} to verify npm is working.${R}
47421
-
47422
- `
47423
- );
47424
- process.exitCode = 1;
47425
- return;
47426
- }
47427
- const normalizedBin = normalize(globalBin).replace(/[/\\]+$/, "");
47428
- const onPath = isOnPath(normalizedBin) || isWin && isUnerrOnPathViaWhere();
47429
- if (onPath) {
47430
- const displayBin = isWin ? normalizedBin.replace(homedir11(), "%USERPROFILE%") : normalizedBin.replace(homedir11(), "~");
47431
- log2(
47432
- ` ${G}\u2713${R} ${B}unerr${R} is on PATH and ready to use in all terminals.
47433
- `
47434
- );
47435
- log2(` ${D}Global bin: ${displayBin}${R}
47436
-
47437
- `);
47438
- return;
47439
- }
47440
- const shell = detectShell();
47441
- const rcPath = getRcPath(shell);
47442
- const rcName = getRcDisplayName(shell);
47443
- const fix = getFixPayload(shell, normalizedBin);
47444
- log2(
47445
- ` ${W}\u26A0${R} npm global bin directory is ${B}not on your PATH${R}:
47446
- `
47447
- );
47448
- log2(` ${C}${normalizedBin}${R}
47449
-
47450
- `);
47451
- log2(
47452
- ` ${D}This means ${B}unerr${D} won't be found in new terminal sessions.${R}
47453
-
47454
- `
47455
- );
47456
- if (isAlreadyInRc(rcPath, fix)) {
47457
- log2(
47458
- ` ${D}The required lines already exist in ${rcName} but PATH still doesn't include the bin dir.${R}
47459
- `
47460
- );
47461
- if (shell === "cmd" || shell === "powershell") {
47462
- log2(
47463
- ` ${D}Try opening a new terminal window, or run: ${C}refreshenv${R}
47464
-
47465
- `
47466
- );
47467
- } else {
47468
- log2(
47469
- ` ${D}This may mean ${rcName} isn't being sourced by your terminal.${R}
47470
- `
47471
- );
47472
- log2(
47473
- ` ${D}Check your terminal app settings, or try: ${C}${fix.reloadInstruction}${R}
47474
-
47475
- `
47476
- );
47477
- }
47478
- return;
47479
- }
47480
- if (!fix.canAutoFix) {
47481
- printManualSteps(shell, fix, rcName);
47482
- return;
47483
- }
47484
- const commentPrefix = shell === "cmd" ? "::" : "#";
47485
- const preview = fix.lines.filter((l) => l.trim() && !l.trim().startsWith(commentPrefix)).join("\n ");
47486
- log2(` ${B}Fix:${R} ${fix.description}
47487
- `);
47488
- log2(` ${D}Target: ${C}${rcName}${R}
47489
-
47490
- `);
47491
- log2(` ${D}${preview}${R}
47492
-
47493
- `);
47494
- const answer = await askYesNo(` Apply this fix now? ${D}[Y/n]${R} `);
47495
- if (answer) {
47496
- applyFix(shell, rcPath, rcName, fix, normalizedBin);
47497
- } else {
47498
- log2(`
47499
- ${D}No changes made.${R}
47500
- `);
47501
- printManualSteps(shell, fix, rcName);
47502
- }
47503
- });
47504
- }
47505
-
47506
47533
  // src/commands/enrich.ts
47507
47534
  function buildEnrichmentPrompt(entities) {
47508
47535
  const entityBlock = entities.map(
@@ -57083,6 +57110,7 @@ function readLocalConfig(cwd) {
57083
57110
  }
57084
57111
  }
57085
57112
  async function resumeBoot(config) {
57113
+ verifyUnerrOnPath();
57086
57114
  initFileLog(process.cwd());
57087
57115
  const detection = await detectProjectRoot(process.cwd());
57088
57116
  if (!detection.isProject) {
@@ -57122,6 +57150,7 @@ ${antiSignals.length > 0 ? ` Negative signals: ${antiSignals.map((s) => s.repla
57122
57150
  await startProxy2(config.repoId);
57123
57151
  }
57124
57152
  async function firstRunBoot() {
57153
+ verifyUnerrOnPath();
57125
57154
  initFileLog(process.cwd());
57126
57155
  const { initSessionLogger: initSessionLogger2, createSessionModuleLogger: createSessionModuleLogger2 } = await Promise.resolve().then(() => (init_session_logger(), session_logger_exports));
57127
57156
  initSessionLogger2();