@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.
- package/dist/cli.js +685 -656
- 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
|
|
5129
|
-
import { homedir as
|
|
5130
|
-
import { basename as basename3, dirname as
|
|
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
|
|
5134
|
-
return
|
|
5133
|
+
if (override) return join10(override, ".unerr");
|
|
5134
|
+
return join10(homedir4(), ".unerr");
|
|
5135
5135
|
}
|
|
5136
5136
|
function registryPath() {
|
|
5137
|
-
return
|
|
5137
|
+
return join10(globalDir(), "repos.json");
|
|
5138
5138
|
}
|
|
5139
5139
|
function readRegistry() {
|
|
5140
5140
|
try {
|
|
5141
|
-
const raw =
|
|
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 (!
|
|
5154
|
-
|
|
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(
|
|
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 =
|
|
5210
|
-
if (!
|
|
5211
|
-
|
|
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 =
|
|
5251
|
-
const root =
|
|
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 (
|
|
5254
|
+
if (existsSync9(join10(current, ".unerr", "state", "proxy.pid"))) {
|
|
5255
5255
|
return current;
|
|
5256
5256
|
}
|
|
5257
|
-
const parent =
|
|
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 =
|
|
5270
|
-
return JSON.parse(
|
|
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 =
|
|
5277
|
-
if (!
|
|
5276
|
+
const dir = join10(repoPath, ".unerr");
|
|
5277
|
+
if (!existsSync9(dir)) mkdirSync5(dir, { recursive: true });
|
|
5278
5278
|
writeFileSync3(
|
|
5279
|
-
|
|
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 =
|
|
5294
|
+
const configPath = join10(repoPath, ".unerr", "config.json");
|
|
5295
5295
|
let config = {};
|
|
5296
5296
|
try {
|
|
5297
|
-
config = JSON.parse(
|
|
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 =
|
|
5306
|
-
if (!
|
|
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
|
|
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 (
|
|
5341
|
+
if (existsSync10("/.dockerenv")) return true;
|
|
5342
5342
|
try {
|
|
5343
|
-
const cgroup =
|
|
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
|
|
5371
|
+
import { execSync as execSync3 } from "child_process";
|
|
5372
5372
|
import {
|
|
5373
|
-
existsSync as
|
|
5374
|
-
mkdirSync as
|
|
5375
|
-
readFileSync as
|
|
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
|
|
5381
|
-
import { dirname as
|
|
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
|
|
5383
|
+
return join11(homedir5(), "Library", "LaunchAgents");
|
|
5384
5384
|
}
|
|
5385
5385
|
function plistPath() {
|
|
5386
|
-
return
|
|
5386
|
+
return join11(plistDir(), PLIST_NAME);
|
|
5387
5387
|
}
|
|
5388
5388
|
function logPath() {
|
|
5389
|
-
return
|
|
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 (
|
|
5401
|
+
if (existsSync11(resolved)) return resolved;
|
|
5402
5402
|
}
|
|
5403
5403
|
try {
|
|
5404
|
-
const shimPath =
|
|
5405
|
-
if (shimPath &&
|
|
5406
|
-
const shimContent =
|
|
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 =
|
|
5409
|
+
const basedir = dirname6(shimPath);
|
|
5410
5410
|
const abs = resolve2(basedir, jsMatch[1]);
|
|
5411
|
-
if (
|
|
5411
|
+
if (existsSync11(abs)) return abs;
|
|
5412
5412
|
}
|
|
5413
5413
|
}
|
|
5414
5414
|
} catch {
|
|
5415
5415
|
}
|
|
5416
|
-
const fallbackBase = process.argv[1] ?
|
|
5417
|
-
return
|
|
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, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
5421
5421
|
}
|
|
5422
5422
|
function generatePlist(nodeBin, cliEntry) {
|
|
5423
5423
|
const log25 = logPath();
|
|
5424
|
-
const nodeBinDir =
|
|
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
|
-
|
|
5472
|
-
const logDir =
|
|
5473
|
-
|
|
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?.() ??
|
|
5476
|
+
const uid = process.getuid?.() ?? execSync3("id -u", { encoding: "utf-8" }).trim();
|
|
5477
5477
|
try {
|
|
5478
|
-
|
|
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
|
-
|
|
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?.() ??
|
|
5499
|
+
const uid = process.getuid?.() ?? execSync3("id -u", { encoding: "utf-8" }).trim();
|
|
5500
5500
|
try {
|
|
5501
|
-
|
|
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 (
|
|
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
|
|
5520
|
+
return existsSync11(plistPath());
|
|
5521
5521
|
}
|
|
5522
5522
|
function getLaunchdStatus() {
|
|
5523
|
-
const plistExists =
|
|
5523
|
+
const plistExists = existsSync11(plistPath());
|
|
5524
5524
|
let loaded = false;
|
|
5525
5525
|
if (plistExists) {
|
|
5526
5526
|
try {
|
|
5527
|
-
const out =
|
|
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
|
|
5550
|
+
import { execSync as execSync4 } from "child_process";
|
|
5551
5551
|
import {
|
|
5552
|
-
existsSync as
|
|
5553
|
-
mkdirSync as
|
|
5554
|
-
readFileSync as
|
|
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
|
|
5560
|
-
import { dirname as
|
|
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
|
|
5562
|
+
return join12(homedir6(), ".config", "systemd", "user");
|
|
5563
5563
|
}
|
|
5564
5564
|
function unitPath() {
|
|
5565
|
-
return
|
|
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 (
|
|
5577
|
+
if (existsSync12(resolved)) return resolved;
|
|
5578
5578
|
}
|
|
5579
5579
|
try {
|
|
5580
|
-
const shimPath =
|
|
5581
|
-
if (shimPath &&
|
|
5582
|
-
const shimContent =
|
|
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 =
|
|
5585
|
+
const basedir = dirname7(shimPath);
|
|
5586
5586
|
const abs = resolve3(basedir, jsMatch[1]);
|
|
5587
|
-
if (
|
|
5587
|
+
if (existsSync12(abs)) return abs;
|
|
5588
5588
|
}
|
|
5589
5589
|
}
|
|
5590
5590
|
} catch {
|
|
5591
5591
|
}
|
|
5592
|
-
const fallbackBase = process.argv[1] ?
|
|
5593
|
-
return
|
|
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 =
|
|
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 =
|
|
5610
|
-
const home =
|
|
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
|
-
|
|
5640
|
+
mkdirSync7(dir, { recursive: true });
|
|
5641
5641
|
writeFileSync5(path7, generateUnit(nodeBin, cliEntry), "utf-8");
|
|
5642
|
-
|
|
5643
|
-
|
|
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 ||
|
|
5648
|
-
|
|
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
|
-
|
|
5664
|
+
execSync4("systemctl --user disable --now unerrd.service", {
|
|
5665
5665
|
stdio: "ignore"
|
|
5666
5666
|
});
|
|
5667
5667
|
} catch {
|
|
5668
5668
|
}
|
|
5669
|
-
if (
|
|
5669
|
+
if (existsSync12(path7)) unlinkSync2(path7);
|
|
5670
5670
|
try {
|
|
5671
|
-
|
|
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
|
|
5684
|
+
return existsSync12(unitPath());
|
|
5685
5685
|
}
|
|
5686
5686
|
function getSystemdStatus() {
|
|
5687
|
-
const unitExists =
|
|
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 =
|
|
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 =
|
|
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
|
|
5723
|
+
import { execSync as execSync5 } from "child_process";
|
|
5724
5724
|
import {
|
|
5725
|
-
existsSync as
|
|
5726
|
-
mkdirSync as
|
|
5727
|
-
readFileSync as
|
|
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
|
|
5733
|
-
import { dirname as
|
|
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
|
|
5736
|
-
process.env.APPDATA ||
|
|
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
|
|
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 (
|
|
5757
|
+
if (existsSync13(resolved)) return resolved;
|
|
5758
5758
|
}
|
|
5759
5759
|
try {
|
|
5760
|
-
const whereLine =
|
|
5761
|
-
if (whereLine &&
|
|
5762
|
-
const shimContent =
|
|
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(
|
|
5766
|
-
if (
|
|
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] ?
|
|
5772
|
-
return
|
|
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
|
-
|
|
5786
|
+
execSync5(`schtasks /Delete /TN "${TASK_NAME}" /F`, { stdio: "ignore" });
|
|
5787
5787
|
} catch {
|
|
5788
5788
|
}
|
|
5789
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
|
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
|
|
5868
|
-
import { homedir as
|
|
5869
|
-
import { join as
|
|
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
|
|
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 =
|
|
5879
|
-
|
|
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 (
|
|
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 =
|
|
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
|
|
5985
|
+
import { join as join15 } from "path";
|
|
5986
5986
|
function daemonSockPath() {
|
|
5987
|
-
return
|
|
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
|
|
6397
|
-
existsSync as
|
|
6398
|
-
mkdirSync as
|
|
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
|
|
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 (!
|
|
6412
|
-
if (i === keep &&
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
6464
|
-
import { existsSync as
|
|
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 =
|
|
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 (!
|
|
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 (
|
|
6503
|
-
const online =
|
|
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 =
|
|
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
|
|
6574
|
-
import { homedir as
|
|
6575
|
-
import { join as
|
|
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 =
|
|
6577
|
+
const configPath = join16(homedir9(), ".unerr", "config.json");
|
|
6578
6578
|
try {
|
|
6579
|
-
if (!
|
|
6580
|
-
const raw = JSON.parse(
|
|
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 =
|
|
6592
|
-
const dir =
|
|
6593
|
-
|
|
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 (
|
|
6597
|
-
existing = JSON.parse(
|
|
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 (!
|
|
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
|
|
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
|
|
6776
|
-
import { join as
|
|
6775
|
+
import { homedir as homedir10 } from "os";
|
|
6776
|
+
import { join as join17 } from "path";
|
|
6777
6777
|
function versionCachePath() {
|
|
6778
|
-
return
|
|
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 =
|
|
6784
|
-
if (
|
|
6785
|
-
const pkg = JSON.parse(
|
|
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 =
|
|
6793
|
-
const pkgPath =
|
|
6794
|
-
if (
|
|
6795
|
-
const pkg = JSON.parse(
|
|
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 (!
|
|
6814
|
+
if (!existsSync18(path7)) return defaults;
|
|
6815
6815
|
const raw = JSON.parse(
|
|
6816
|
-
|
|
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 =
|
|
6831
|
-
|
|
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
|
|
6993
|
+
import { existsSync as existsSync19, readFileSync as readFileSync16 } from "fs";
|
|
6994
6994
|
import { request as httpRequest } from "http";
|
|
6995
|
-
import { dirname as
|
|
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 =
|
|
7040
|
+
const serverJsonPath = join18(
|
|
7041
7041
|
repo.path,
|
|
7042
7042
|
".unerr",
|
|
7043
7043
|
"state",
|
|
7044
7044
|
"server.json"
|
|
7045
7045
|
);
|
|
7046
|
-
if (!
|
|
7046
|
+
if (!existsSync19(serverJsonPath)) return null;
|
|
7047
7047
|
try {
|
|
7048
7048
|
const serverInfo = JSON.parse(
|
|
7049
|
-
|
|
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 =
|
|
7158
|
-
if (!
|
|
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(
|
|
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 =
|
|
7182
|
-
const spaIndex =
|
|
7183
|
-
if (
|
|
7184
|
-
const spaHtml =
|
|
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
|
|
7297
|
-
mkdirSync as
|
|
7298
|
-
readFileSync as
|
|
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
|
|
7303
|
+
import { join as join19 } from "path";
|
|
7304
7304
|
function pidPath() {
|
|
7305
|
-
return
|
|
7305
|
+
return join19(globalDir(), "unerrd.pid");
|
|
7306
7306
|
}
|
|
7307
7307
|
function sockPath() {
|
|
7308
|
-
return
|
|
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 =
|
|
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 (!
|
|
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 (!
|
|
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 =
|
|
7476
|
-
if (!
|
|
7475
|
+
const logsDir = join19(globalDir(), "logs");
|
|
7476
|
+
if (!existsSync20(logsDir)) mkdirSync13(logsDir, { recursive: true });
|
|
7477
7477
|
installFileLogger({
|
|
7478
|
-
filePath:
|
|
7478
|
+
filePath: join19(logsDir, "unerrd.log"),
|
|
7479
7479
|
maxBytes: 1e7,
|
|
7480
7480
|
keep: 5
|
|
7481
7481
|
});
|
|
7482
7482
|
if (!acquirePidLock()) {
|
|
7483
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7546
|
+
log2.info(`Dashboard: http://localhost:${apiHandle.port}`);
|
|
7547
7547
|
}
|
|
7548
7548
|
} catch (err) {
|
|
7549
|
-
|
|
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
|
-
|
|
7557
|
+
log2.info(`warm-start: ${event.label} ready (${event.ms}ms)`);
|
|
7558
7558
|
} else if (event.status === "skipped") {
|
|
7559
|
-
|
|
7559
|
+
log2.info(`warm-start: ${event.label} skipped \u2014 ${event.reason}`);
|
|
7560
7560
|
} else if (event.status === "failed") {
|
|
7561
|
-
|
|
7561
|
+
log2.warn(`warm-start: ${event.label} failed \u2014 ${event.reason}`);
|
|
7562
7562
|
} else if (event.status === "aborted") {
|
|
7563
|
-
|
|
7563
|
+
log2.warn(`warm-start: ${event.label} aborted \u2014 ${event.reason}`);
|
|
7564
7564
|
}
|
|
7565
7565
|
});
|
|
7566
7566
|
} catch (err) {
|
|
7567
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7586
|
+
log2.info(
|
|
7587
7587
|
`Started (PID ${process.pid}), ${reg.repos.length} repos registered. Socket: ${sock}`
|
|
7588
7588
|
);
|
|
7589
7589
|
if (!opts.background) {
|
|
7590
|
-
|
|
7590
|
+
log2.info("Running in foreground. Press Ctrl+C to stop.");
|
|
7591
7591
|
}
|
|
7592
7592
|
}
|
|
7593
|
-
var
|
|
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
|
-
|
|
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
|
|
7619
|
-
mkdirSync as
|
|
7620
|
-
readFileSync as
|
|
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
|
|
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 =
|
|
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 =
|
|
7643
|
-
|
|
7644
|
-
_fileLogPath =
|
|
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
|
-
|
|
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
|
|
46879
|
-
import { join as
|
|
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 =
|
|
46882
|
-
if (!
|
|
47310
|
+
const p = join21(cwd, ".unerr", "state", "server.json");
|
|
47311
|
+
if (!existsSync21(p)) return null;
|
|
46883
47312
|
try {
|
|
46884
|
-
const raw =
|
|
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
|
|
46924
|
-
import { arch, homedir as
|
|
46925
|
-
import { join as
|
|
46926
|
-
var UNERR_DIR =
|
|
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 =
|
|
46938
|
-
if (
|
|
47366
|
+
const settingsPath = join22(UNERR_DIR, "settings.json");
|
|
47367
|
+
if (existsSync22(settingsPath)) {
|
|
46939
47368
|
try {
|
|
46940
47369
|
const settings = JSON.parse(
|
|
46941
|
-
|
|
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 =
|
|
46966
|
-
if (
|
|
47394
|
+
const configPath = join22(process.cwd(), ".unerr", "config.json");
|
|
47395
|
+
if (existsSync22(configPath)) {
|
|
46967
47396
|
try {
|
|
46968
47397
|
const config = JSON.parse(
|
|
46969
|
-
|
|
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 =
|
|
46983
|
-
if (
|
|
47411
|
+
const pidPath2 = join22(process.cwd(), ".unerr", "state", "proxy.pid");
|
|
47412
|
+
if (existsSync22(pidPath2)) {
|
|
46984
47413
|
try {
|
|
46985
47414
|
const pid = Number.parseInt(
|
|
46986
|
-
|
|
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 =
|
|
47005
|
-
if (
|
|
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 =
|
|
47013
|
-
if (
|
|
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 =
|
|
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
|
-
|
|
47030
|
-
|
|
47031
|
-
|
|
47032
|
-
|
|
47033
|
-
|
|
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 =
|
|
47473
|
+
const exists = existsSync22(loc);
|
|
47045
47474
|
sections.push(
|
|
47046
|
-
` ${exists ? "[x]" : "[ ]"} ${loc.replace(
|
|
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 =
|
|
47052
|
-
if (
|
|
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 =
|
|
47484
|
+
const logPath2 = join22(logsDir, logFiles[0]);
|
|
47056
47485
|
try {
|
|
47057
|
-
const content =
|
|
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
|
-
|
|
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(
|
|
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();
|