@inerrata-corporation/errata 2.0.18 → 2.0.19-dev.3624
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/errata.mjs +156 -56
- package/package.json +1 -1
package/errata.mjs
CHANGED
|
@@ -27795,8 +27795,8 @@ var init_config = __esm({
|
|
|
27795
27795
|
"use strict";
|
|
27796
27796
|
init_paths();
|
|
27797
27797
|
LEGACY_CLOUD_URL = "https://inerrata-gateway.onrender.com";
|
|
27798
|
-
DEFAULT_CLOUD_URL = true ? "https://inerrata.dev" : DEV_CLOUD_URL;
|
|
27799
|
-
DEFAULT_UPDATE_CHANNEL =
|
|
27798
|
+
DEFAULT_CLOUD_URL = true ? "https://dev.inerrata.dev" : DEV_CLOUD_URL;
|
|
27799
|
+
DEFAULT_UPDATE_CHANNEL = false ? "latest" : "dev";
|
|
27800
27800
|
}
|
|
27801
27801
|
});
|
|
27802
27802
|
|
|
@@ -33461,6 +33461,13 @@ function foreignDaemonNote(lock, selfEntry) {
|
|
|
33461
33461
|
];
|
|
33462
33462
|
return runningInstalled ? [...head2, "this CLI is a different bundle from the daemon it is talking to \u2014 its view may not match what the daemon runs."] : [...head2, "`errata update` does not replace it. To move onto the installed package: errata stop, then errata dash."];
|
|
33463
33463
|
}
|
|
33464
|
+
function daemonVersionNote(lock, selfVersion) {
|
|
33465
|
+
if (!lock.version || lock.version === selfVersion) return null;
|
|
33466
|
+
return [
|
|
33467
|
+
`the running daemon is ${lock.version}, but this CLI is ${selfVersion} \u2014 it was started before the update.`,
|
|
33468
|
+
`restart it onto ${selfVersion}: errata stop, then errata start`
|
|
33469
|
+
];
|
|
33470
|
+
}
|
|
33464
33471
|
function isProcessAlive(pid) {
|
|
33465
33472
|
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
|
|
33466
33473
|
try {
|
|
@@ -33500,6 +33507,20 @@ function isDaemonAlive(lockPath) {
|
|
|
33500
33507
|
function daemonLockBlocksStartup(lockPath) {
|
|
33501
33508
|
return daemonLockState(readDaemonLock(lockPath), true) !== "stale";
|
|
33502
33509
|
}
|
|
33510
|
+
async function waitForDaemonExit(lock, timeoutMs, pollMs = 200) {
|
|
33511
|
+
const deadline = Date.now() + timeoutMs;
|
|
33512
|
+
for (; ; ) {
|
|
33513
|
+
if (daemonLockState(lock, true) === "stale") return true;
|
|
33514
|
+
if (Date.now() >= deadline) return false;
|
|
33515
|
+
await new Promise((resolve10) => setTimeout(resolve10, pollMs));
|
|
33516
|
+
}
|
|
33517
|
+
}
|
|
33518
|
+
function releaseOwnLock(lockPath) {
|
|
33519
|
+
try {
|
|
33520
|
+
if (parseDaemonLock(readFileSync12(lockPath, "utf8"))?.pid === process.pid) unlinkSync2(lockPath);
|
|
33521
|
+
} catch {
|
|
33522
|
+
}
|
|
33523
|
+
}
|
|
33503
33524
|
function stopLockedDaemon(lockPath) {
|
|
33504
33525
|
let original;
|
|
33505
33526
|
try {
|
|
@@ -73598,7 +73619,7 @@ var init_report_render = __esm({
|
|
|
73598
73619
|
|
|
73599
73620
|
// src/cli.ts
|
|
73600
73621
|
init_src6();
|
|
73601
|
-
import { closeSync as closeSync2, existsSync as existsSync39, openSync as openSync2, readFileSync as
|
|
73622
|
+
import { closeSync as closeSync2, existsSync as existsSync39, openSync as openSync2, readFileSync as readFileSync41, renameSync as renameSync6, statSync as statSync12 } from "node:fs";
|
|
73602
73623
|
import { join as join48, resolve as pathResolve2 } from "node:path";
|
|
73603
73624
|
import { spawn as spawn5 } from "node:child_process";
|
|
73604
73625
|
|
|
@@ -82685,7 +82706,7 @@ function createWatchBreaker(deps) {
|
|
|
82685
82706
|
}
|
|
82686
82707
|
|
|
82687
82708
|
// src/engine.ts
|
|
82688
|
-
var DAEMON_VERSION = true ? "2.0.
|
|
82709
|
+
var DAEMON_VERSION = true ? "2.0.19-dev.3624" : "2.0.0-alpha.0";
|
|
82689
82710
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
82690
82711
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
82691
82712
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -85407,10 +85428,20 @@ async function startDaemon(opts) {
|
|
|
85407
85428
|
};
|
|
85408
85429
|
}
|
|
85409
85430
|
async function listenServer(fetchFn, port) {
|
|
85410
|
-
return new Promise((resolve10) => {
|
|
85431
|
+
return new Promise((resolve10, reject) => {
|
|
85411
85432
|
const server = serve({ fetch: fetchFn, hostname: "127.0.0.1", port }, (info2) => {
|
|
85412
85433
|
resolve10({ server, port: info2.port });
|
|
85413
85434
|
});
|
|
85435
|
+
server.once(
|
|
85436
|
+
"error",
|
|
85437
|
+
(err2) => {
|
|
85438
|
+
reject(
|
|
85439
|
+
err2.code === "EADDRINUSE" ? new Error(
|
|
85440
|
+
`port ${port} is still held by another process \u2014 usually a previous errata daemon that has not finished shutting down. Wait for it to exit (errata stop waits for it), then start again.`
|
|
85441
|
+
) : err2
|
|
85442
|
+
);
|
|
85443
|
+
}
|
|
85444
|
+
);
|
|
85414
85445
|
});
|
|
85415
85446
|
}
|
|
85416
85447
|
|
|
@@ -85715,7 +85746,7 @@ function invalidateInstanceReceipt(current, destination, failedId, mirrorLegacy)
|
|
|
85715
85746
|
// src/multi.ts
|
|
85716
85747
|
init_dist();
|
|
85717
85748
|
init_src5();
|
|
85718
|
-
import { existsSync as existsSync34,
|
|
85749
|
+
import { existsSync as existsSync34, writeFileSync as writeFileSync26 } from "node:fs";
|
|
85719
85750
|
import { resolve as pathResolve } from "node:path";
|
|
85720
85751
|
|
|
85721
85752
|
// src/principle-sync.ts
|
|
@@ -89657,6 +89688,7 @@ var SessionAffinity = class {
|
|
|
89657
89688
|
// src/multi.ts
|
|
89658
89689
|
init_checkout_root();
|
|
89659
89690
|
var PROCESS_STARTED_AT = Date.now();
|
|
89691
|
+
var SHUTDOWN_CONNECTION_GRACE_MS = 2e3;
|
|
89660
89692
|
var SELF_ENTRY = process.argv[1] ? pathResolve(process.argv[1]) : "";
|
|
89661
89693
|
var LOCAL_BUILD_ENTRY = SELF_ENTRY && !isInstalledEntry(SELF_ENTRY) ? SELF_ENTRY : void 0;
|
|
89662
89694
|
function withLaunchOrigin(pending) {
|
|
@@ -91479,21 +91511,23 @@ async function startMultiDaemon(opts = {}) {
|
|
|
91479
91511
|
clearInterval(historyRetry);
|
|
91480
91512
|
clearTimeout(codexWakeBoot);
|
|
91481
91513
|
try {
|
|
91482
|
-
const
|
|
91483
|
-
|
|
91484
|
-
|
|
91485
|
-
|
|
91486
|
-
|
|
91487
|
-
(
|
|
91488
|
-
|
|
91489
|
-
|
|
91490
|
-
|
|
91491
|
-
|
|
91492
|
-
|
|
91493
|
-
|
|
91494
|
-
|
|
91495
|
-
|
|
91496
|
-
|
|
91514
|
+
const http = server;
|
|
91515
|
+
const closed = new Promise((res) => http.close(res));
|
|
91516
|
+
http.closeIdleConnections?.();
|
|
91517
|
+
const force = setTimeout(() => http.closeAllConnections?.(), SHUTDOWN_CONNECTION_GRACE_MS);
|
|
91518
|
+
await closed;
|
|
91519
|
+
clearTimeout(force);
|
|
91520
|
+
updatePoller?.stop();
|
|
91521
|
+
healthSentinel.stop();
|
|
91522
|
+
await Promise.allSettled(attaching.values());
|
|
91523
|
+
for (const r of records) await r.engine.stop();
|
|
91524
|
+
if (consolidateWorker) await consolidateWorker.stop();
|
|
91525
|
+
try {
|
|
91526
|
+
sharedStore.close();
|
|
91527
|
+
} catch {
|
|
91528
|
+
}
|
|
91529
|
+
} finally {
|
|
91530
|
+
releaseOwnLock(lockPath);
|
|
91497
91531
|
}
|
|
91498
91532
|
}
|
|
91499
91533
|
};
|
|
@@ -91943,8 +91977,31 @@ function installedHarnessVersion(bin) {
|
|
|
91943
91977
|
return null;
|
|
91944
91978
|
}
|
|
91945
91979
|
}
|
|
91980
|
+
function daemonDoctorCheck(input) {
|
|
91981
|
+
const { lock, state, selfVersion, lockPath } = input;
|
|
91982
|
+
if (!lock || state === "stale") {
|
|
91983
|
+
return { id: "daemon", status: "warn", detail: "Daemon is not running \u2014 start it: errata start" };
|
|
91984
|
+
}
|
|
91985
|
+
if (state === "unknown") {
|
|
91986
|
+
return {
|
|
91987
|
+
id: "daemon",
|
|
91988
|
+
status: "fail",
|
|
91989
|
+
detail: `${lockPath} names pid ${lock.pid}, but that process's identity cannot be verified. If \`ps -p ${lock.pid}\` shows no errata process, delete the lock; otherwise run errata stop.`
|
|
91990
|
+
};
|
|
91991
|
+
}
|
|
91992
|
+
const where = `pid ${lock.pid}${lock.webUiUrl ? ` \xB7 ${lock.webUiUrl}` : ""}`;
|
|
91993
|
+
if (lock.version && lock.version !== selfVersion) {
|
|
91994
|
+
return {
|
|
91995
|
+
id: "daemon",
|
|
91996
|
+
status: "warn",
|
|
91997
|
+
detail: `Running ${lock.version} (${where}), but this CLI is ${selfVersion} \u2014 restart it: errata stop, then errata start`
|
|
91998
|
+
};
|
|
91999
|
+
}
|
|
92000
|
+
return { id: "daemon", status: "pass", detail: `Running${lock.version ? ` ${lock.version}` : ""} \xB7 ${where}` };
|
|
92001
|
+
}
|
|
91946
92002
|
async function diagnoseInstallation(cfg, dependencies) {
|
|
91947
92003
|
const checks = [];
|
|
92004
|
+
if (dependencies.daemon) checks.push(dependencies.daemon());
|
|
91948
92005
|
if (dependencies.codexHooks) checks.push(...await dependencies.codexHooks());
|
|
91949
92006
|
const profileName = cfg.activeInstallationProfile;
|
|
91950
92007
|
const profile = profileName ? cfg.installationProfiles[profileName] : void 0;
|
|
@@ -92041,12 +92098,12 @@ async function diagnoseInstallation(cfg, dependencies) {
|
|
|
92041
92098
|
|
|
92042
92099
|
// src/codex-doctor.ts
|
|
92043
92100
|
import { spawn as spawn4 } from "node:child_process";
|
|
92044
|
-
import { readFileSync as
|
|
92101
|
+
import { readFileSync as readFileSync37, statSync as statSync10 } from "node:fs";
|
|
92045
92102
|
import { join as join44 } from "node:path";
|
|
92046
92103
|
import { createInterface } from "node:readline";
|
|
92047
92104
|
|
|
92048
92105
|
// src/codex-hooks.ts
|
|
92049
|
-
import { existsSync as existsSync35, mkdirSync as mkdirSync9, readFileSync as
|
|
92106
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync9, readFileSync as readFileSync36, renameSync as renameSync5, unlinkSync as unlinkSync5, writeFileSync as writeFileSync27 } from "node:fs";
|
|
92050
92107
|
import { homedir as homedir7 } from "node:os";
|
|
92051
92108
|
import { join as join43 } from "node:path";
|
|
92052
92109
|
|
|
@@ -92217,23 +92274,23 @@ function buildCodexRelaySource(workspaceRoot) {
|
|
|
92217
92274
|
init_checkout_root();
|
|
92218
92275
|
var CODEX_HOOK_REVIEW_HELP = "Codex desktop: Settings > Hooks, select this project, expand each event and Trust the Errata hook. CLI users can use /hooks.";
|
|
92219
92276
|
function writeRelay(file2, source) {
|
|
92220
|
-
if (existsSync35(file2) &&
|
|
92277
|
+
if (existsSync35(file2) && readFileSync36(file2, "utf8") === source) return;
|
|
92221
92278
|
const temp = `${file2}.${process.pid}.tmp`;
|
|
92222
92279
|
try {
|
|
92223
92280
|
writeFileSync27(temp, source, { encoding: "utf8", mode: 384 });
|
|
92224
92281
|
renameSync5(temp, file2);
|
|
92225
92282
|
} finally {
|
|
92226
|
-
if (existsSync35(temp))
|
|
92283
|
+
if (existsSync35(temp)) unlinkSync5(temp);
|
|
92227
92284
|
}
|
|
92228
92285
|
}
|
|
92229
92286
|
function refreshCodexRelay(root) {
|
|
92230
92287
|
const config2 = join43(root, ".codex", "config.toml");
|
|
92231
92288
|
if (!existsSync35(config2)) return "absent";
|
|
92232
|
-
const existing =
|
|
92289
|
+
const existing = readFileSync36(config2, "utf8");
|
|
92233
92290
|
if (!existing.includes(CODEX_HOOKS_BEGIN) && !existing.includes(CODEX_HOOKS_END)) return "absent";
|
|
92234
92291
|
replaceCodexHooks(existing, "");
|
|
92235
92292
|
const relay = join43(root, ".codex", "hooks", "errata-relay.mjs");
|
|
92236
|
-
const prior = existsSync35(relay) ?
|
|
92293
|
+
const prior = existsSync35(relay) ? readFileSync36(relay, "utf8") : "";
|
|
92237
92294
|
if (prior && !prior.startsWith("// errata-managed: regenerated by errata install-hooks codex")) {
|
|
92238
92295
|
throw new Error("Codex relay is not Errata-managed; preserved it. Run errata install-hooks codex to explicitly replace it.");
|
|
92239
92296
|
}
|
|
@@ -92264,10 +92321,10 @@ function writeCodexHooks(root, port, nodePath = process.execPath) {
|
|
|
92264
92321
|
const file2 = join43(dir, "config.toml");
|
|
92265
92322
|
const relay = join43(dir, "hooks", "errata-relay.mjs");
|
|
92266
92323
|
const block = buildCodexHooksToml(port, { nodePath, relayPath: relay });
|
|
92267
|
-
const final = replaceCodexHooks(existsSync35(file2) ?
|
|
92324
|
+
const final = replaceCodexHooks(existsSync35(file2) ? readFileSync36(file2, "utf8") : "", block);
|
|
92268
92325
|
mkdirSync9(join43(dir, "hooks"), { recursive: true });
|
|
92269
92326
|
writeRelay(relay, buildCodexRelaySource(checkoutRootOf(root)));
|
|
92270
|
-
if (!existsSync35(file2) ||
|
|
92327
|
+
if (!existsSync35(file2) || readFileSync36(file2, "utf8") !== final) writeFileSync27(file2, final, "utf8");
|
|
92271
92328
|
return file2;
|
|
92272
92329
|
}
|
|
92273
92330
|
|
|
@@ -92276,7 +92333,7 @@ init_checkout_root();
|
|
|
92276
92333
|
function inspectCodexRelay(cwd) {
|
|
92277
92334
|
const root = nearestGitRoot(cwd) ?? cwd;
|
|
92278
92335
|
try {
|
|
92279
|
-
const source =
|
|
92336
|
+
const source = readFileSync37(join44(root, ".codex", "hooks", "errata-relay.mjs"), "utf8");
|
|
92280
92337
|
if (source === buildCodexRelaySource(checkoutRootOf(root))) {
|
|
92281
92338
|
return { id: "codex_relay", status: "pass", detail: "Installed Codex relay matches this Errata version" };
|
|
92282
92339
|
}
|
|
@@ -92288,7 +92345,7 @@ function inspectCodexContext(cwd) {
|
|
|
92288
92345
|
const root = checkoutRootOf(nearestGitRoot(cwd) ?? cwd);
|
|
92289
92346
|
try {
|
|
92290
92347
|
const file2 = join44(root, ".errata", "context.md");
|
|
92291
|
-
if (statSync10(file2).size <= 128 * 1024 &&
|
|
92348
|
+
if (statSync10(file2).size <= 128 * 1024 && readFileSync37(file2, "utf8").trim()) {
|
|
92292
92349
|
return { id: "codex_context", status: "pass", detail: "Saved workspace context is readable by the relay; this does not prove live daemon freshness" };
|
|
92293
92350
|
}
|
|
92294
92351
|
} catch {
|
|
@@ -92464,7 +92521,7 @@ function consolidationGapMs(lastPassMs, policy) {
|
|
|
92464
92521
|
|
|
92465
92522
|
// src/codex-hook-refresh.ts
|
|
92466
92523
|
init_checkout_root();
|
|
92467
|
-
import { existsSync as existsSync36, readdirSync as readdirSync13, readFileSync as
|
|
92524
|
+
import { existsSync as existsSync36, readdirSync as readdirSync13, readFileSync as readFileSync38 } from "node:fs";
|
|
92468
92525
|
import { dirname as dirname13, join as join45, resolve as resolve8 } from "node:path";
|
|
92469
92526
|
init_registry();
|
|
92470
92527
|
function codexHookRoots(roots) {
|
|
@@ -92482,7 +92539,7 @@ function codexHookRoots(roots) {
|
|
|
92482
92539
|
}
|
|
92483
92540
|
for (const name2 of names) {
|
|
92484
92541
|
try {
|
|
92485
|
-
const checkout = dirname13(
|
|
92542
|
+
const checkout = dirname13(readFileSync38(join45(dir, name2, "gitdir"), "utf8").trim());
|
|
92486
92543
|
if (mainCheckoutOfWorktree(checkout) === main2) found.add(checkout);
|
|
92487
92544
|
} catch {
|
|
92488
92545
|
}
|
|
@@ -92504,7 +92561,7 @@ function refreshInstalledCodexRelays(roots = listWorkspaceEntries().map((entry)
|
|
|
92504
92561
|
}
|
|
92505
92562
|
|
|
92506
92563
|
// src/claude-statusline.ts
|
|
92507
|
-
import { existsSync as existsSync37, mkdirSync as mkdirSync10, readFileSync as
|
|
92564
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync10, readFileSync as readFileSync39, writeFileSync as writeFileSync28 } from "node:fs";
|
|
92508
92565
|
import { homedir as homedir8 } from "node:os";
|
|
92509
92566
|
import { dirname as dirname14, join as join46 } from "node:path";
|
|
92510
92567
|
var STATUSLINE_RELAY_SOURCE = String.raw`// errata-managed: regenerated by errata init / install-hooks claude
|
|
@@ -92565,7 +92622,7 @@ function ensureUserStatusLine(opts) {
|
|
|
92565
92622
|
let settings = {};
|
|
92566
92623
|
if (existsSync37(settingsPath)) {
|
|
92567
92624
|
try {
|
|
92568
|
-
const parsed = JSON.parse(
|
|
92625
|
+
const parsed = JSON.parse(readFileSync39(settingsPath, "utf8"));
|
|
92569
92626
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return "unreadable";
|
|
92570
92627
|
settings = parsed;
|
|
92571
92628
|
} catch {
|
|
@@ -92578,7 +92635,7 @@ function ensureUserStatusLine(opts) {
|
|
|
92578
92635
|
const ownRows = keep(settings["subagentStatusLine"]);
|
|
92579
92636
|
if (ownMain && ownRows) return "kept-own";
|
|
92580
92637
|
mkdirSync10(opts.relayDir, { recursive: true });
|
|
92581
|
-
if (!existsSync37(relay) ||
|
|
92638
|
+
if (!existsSync37(relay) || readFileSync39(relay, "utf8") !== STATUSLINE_RELAY_SOURCE) {
|
|
92582
92639
|
writeFileSync28(relay, STATUSLINE_RELAY_SOURCE, "utf8");
|
|
92583
92640
|
}
|
|
92584
92641
|
const nodePath = opts.nodePath ?? process.execPath;
|
|
@@ -92611,7 +92668,7 @@ function describeStatusLineOutcome(outcome) {
|
|
|
92611
92668
|
|
|
92612
92669
|
// src/claude-mods.ts
|
|
92613
92670
|
import { createHash as createHash20 } from "node:crypto";
|
|
92614
|
-
import { cpSync as cpSync2, existsSync as existsSync38, mkdirSync as mkdirSync11, readFileSync as
|
|
92671
|
+
import { cpSync as cpSync2, existsSync as existsSync38, mkdirSync as mkdirSync11, readFileSync as readFileSync40, readdirSync as readdirSync14, rmSync as rmSync4, statSync as statSync11, writeFileSync as writeFileSync29 } from "node:fs";
|
|
92615
92672
|
import { delimiter as delimiter2, dirname as dirname15, join as join47, relative as relative7, resolve as resolve9, sep as sep5 } from "node:path";
|
|
92616
92673
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
92617
92674
|
var CLAUDE_PLUGIN_DIRS_ENV = "CLAUDE_CODE_PLUGIN_DIRS";
|
|
@@ -92639,7 +92696,7 @@ function modHash(dir) {
|
|
|
92639
92696
|
for (const abs of listFiles(dir).sort()) {
|
|
92640
92697
|
h.update(relative7(dir, abs).split(sep5).join("/"));
|
|
92641
92698
|
h.update("\0");
|
|
92642
|
-
h.update(
|
|
92699
|
+
h.update(readFileSync40(abs));
|
|
92643
92700
|
h.update("\0");
|
|
92644
92701
|
}
|
|
92645
92702
|
return h.digest("hex");
|
|
@@ -92663,7 +92720,7 @@ function off(env2) {
|
|
|
92663
92720
|
function readSettings(path2) {
|
|
92664
92721
|
if (!existsSync38(path2)) return {};
|
|
92665
92722
|
try {
|
|
92666
|
-
const parsed = JSON.parse(
|
|
92723
|
+
const parsed = JSON.parse(readFileSync40(path2, "utf8"));
|
|
92667
92724
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
92668
92725
|
return parsed;
|
|
92669
92726
|
} catch {
|
|
@@ -92714,7 +92771,7 @@ function ensureClaudeMods(opts) {
|
|
|
92714
92771
|
const dest = join47(modsRoot, name2);
|
|
92715
92772
|
const hash2 = modHash(src);
|
|
92716
92773
|
const hashFile = join47(dest, HASH_FILE);
|
|
92717
|
-
if (!existsSync38(hashFile) ||
|
|
92774
|
+
if (!existsSync38(hashFile) || readFileSync40(hashFile, "utf8") !== hash2) {
|
|
92718
92775
|
rmSync4(dest, { recursive: true, force: true });
|
|
92719
92776
|
cpSync2(src, dest, { recursive: true, filter: (p) => !isEngineOwned(relative7(src, p)) });
|
|
92720
92777
|
writeFileSync29(hashFile, hash2, "utf8");
|
|
@@ -92886,6 +92943,8 @@ export const InerrataPlugin = async (input) => {
|
|
|
92886
92943
|
}
|
|
92887
92944
|
|
|
92888
92945
|
// src/cli.ts
|
|
92946
|
+
var STOP_WAIT_MS = 3e4;
|
|
92947
|
+
var SHUTDOWN_DEADLINE_MS = 2e4;
|
|
92889
92948
|
var exitCleanOnEpipe = (err2) => {
|
|
92890
92949
|
if (err2.code === "EPIPE") process.exit(0);
|
|
92891
92950
|
throw err2;
|
|
@@ -93138,7 +93197,7 @@ function resolveHookPort(explicit) {
|
|
|
93138
93197
|
}
|
|
93139
93198
|
const settingsPath = join48(ROOT, ".claude", "settings.json");
|
|
93140
93199
|
try {
|
|
93141
|
-
if (existsSync39(settingsPath)) return installedHookPort(
|
|
93200
|
+
if (existsSync39(settingsPath)) return installedHookPort(readFileSync41(settingsPath, "utf8")) ?? 7891;
|
|
93142
93201
|
} catch {
|
|
93143
93202
|
}
|
|
93144
93203
|
return 7891;
|
|
@@ -93303,6 +93362,8 @@ async function cmdStart() {
|
|
|
93303
93362
|
console.log(`errata: workspace registered; attached to the running daemon`);
|
|
93304
93363
|
console.log(` workspace: ${where}`);
|
|
93305
93364
|
console.log(` daemon: ${running.webUiUrl ?? "(running)"} \xB7 pid ${running.pid}`);
|
|
93365
|
+
const versionNote = daemonVersionNote(running, DAEMON_VERSION);
|
|
93366
|
+
if (versionNote) for (const l of versionNote) console.log(` \u26A0 ${l}`);
|
|
93306
93367
|
let watching = "on the daemon's next restart";
|
|
93307
93368
|
if (running.webUiUrl) {
|
|
93308
93369
|
try {
|
|
@@ -93326,7 +93387,7 @@ async function cmdStart() {
|
|
|
93326
93387
|
if (up) {
|
|
93327
93388
|
console.log(` daemon: running \xB7 pid ${up.pid} \xB7 ${up.webUiUrl ?? "(running)"}`);
|
|
93328
93389
|
console.log(` logs: ${daemonLogPath()}`);
|
|
93329
|
-
console.log(`
|
|
93390
|
+
console.log(` follow it: ${followLogHint()} \xB7 check it: errata status`);
|
|
93330
93391
|
} else {
|
|
93331
93392
|
console.log(` \u26A0 daemon did not come up within 12s.`);
|
|
93332
93393
|
console.log(` run \`errata dash\` in the foreground to see the error.`);
|
|
@@ -93438,8 +93499,10 @@ async function cmdStatus() {
|
|
|
93438
93499
|
const lockPath = globalDaemonLock();
|
|
93439
93500
|
const running = isDaemonAlive(lockPath) ? readDaemonLock(lockPath) : null;
|
|
93440
93501
|
console.log(
|
|
93441
|
-
` daemon: ${running ? `running \xB7 pid ${running.pid} \xB7 ${running.webUiUrl ?? "(running)"}` : "not running (run: errata start)"}`
|
|
93502
|
+
` daemon: ${running ? `running \xB7 pid ${running.pid}${running.version ? ` \xB7 ${running.version}` : ""} \xB7 ${running.webUiUrl ?? "(running)"}` : "not running (run: errata start)"}`
|
|
93442
93503
|
);
|
|
93504
|
+
const versionNote = running ? daemonVersionNote(running, DAEMON_VERSION) : null;
|
|
93505
|
+
if (versionNote) for (const l of versionNote) console.log(` \u26A0 ${l}`);
|
|
93443
93506
|
if (running && process.argv[1]) {
|
|
93444
93507
|
const note = foreignDaemonNote(running, pathResolve2(process.argv[1]));
|
|
93445
93508
|
if (note) for (const l of note) console.log(` \u26A0 ${l}`);
|
|
@@ -93656,6 +93719,11 @@ async function cmdDoctor(args2) {
|
|
|
93656
93719
|
const cfg = loadConfig();
|
|
93657
93720
|
const report = await diagnoseInstallation(cfg, {
|
|
93658
93721
|
...hasCodexConfig(process.cwd()) ? { codexHooks: () => diagnoseCodexHooks(process.cwd()) } : {},
|
|
93722
|
+
daemon: () => {
|
|
93723
|
+
const lockPath = globalDaemonLock();
|
|
93724
|
+
const lock = readDaemonLock(lockPath);
|
|
93725
|
+
return daemonDoctorCheck({ lock, state: daemonLockState(lock, true), selfVersion: DAEMON_VERSION, lockPath });
|
|
93726
|
+
},
|
|
93659
93727
|
inspect: () => inspectCloudEndpoint(cfg.cloudUrl),
|
|
93660
93728
|
authenticate: async () => {
|
|
93661
93729
|
const me = await authedCloudClient(cfg).me();
|
|
@@ -93672,7 +93740,7 @@ async function cmdDoctor(args2) {
|
|
|
93672
93740
|
const marker = check2.status === "pass" ? "\u2713" : check2.status === "warn" ? "!" : "\u2717";
|
|
93673
93741
|
console.log(` ${marker} ${check2.id}: ${check2.detail}`);
|
|
93674
93742
|
}
|
|
93675
|
-
if (
|
|
93743
|
+
if (report.checks.some((check2) => check2.status === "fail" && check2.id !== "daemon")) {
|
|
93676
93744
|
console.log(
|
|
93677
93745
|
" recovery: `errata profile list`, then `errata profile use <name>`; re-login if authentication still fails."
|
|
93678
93746
|
);
|
|
@@ -93738,7 +93806,8 @@ async function cmdUpdate(args2) {
|
|
|
93738
93806
|
}
|
|
93739
93807
|
console.log(`
|
|
93740
93808
|
[OK] updated to ${status.latest}. Restart the daemon to run it:`);
|
|
93741
|
-
console.log(` errata stop (
|
|
93809
|
+
console.log(` errata stop (waits for the old daemon to exit)`);
|
|
93810
|
+
console.log(` errata start (starts the updated one; autostart also relaunches it at next logon)`);
|
|
93742
93811
|
} else {
|
|
93743
93812
|
console.log(`
|
|
93744
93813
|
[X] npm install failed (exit ${code}). Try manually:`);
|
|
@@ -94375,7 +94444,7 @@ async function cmdReview() {
|
|
|
94375
94444
|
console.log("(review queue empty)");
|
|
94376
94445
|
return;
|
|
94377
94446
|
}
|
|
94378
|
-
const queue = JSON.parse(
|
|
94447
|
+
const queue = JSON.parse(readFileSync41(paths.reviewQueue, "utf8"));
|
|
94379
94448
|
if (queue.length === 0) {
|
|
94380
94449
|
console.log("(review queue empty)");
|
|
94381
94450
|
return;
|
|
@@ -95113,8 +95182,20 @@ async function cmdStop() {
|
|
|
95113
95182
|
return;
|
|
95114
95183
|
}
|
|
95115
95184
|
try {
|
|
95185
|
+
const lock = readDaemonLock(lockPath);
|
|
95116
95186
|
const result = stopLockedDaemon(lockPath);
|
|
95117
|
-
if (result === "signaled"
|
|
95187
|
+
if (result === "signaled" && lock) {
|
|
95188
|
+
console.log(`sent SIGTERM to the daemon (pid ${lock.pid}); waiting for it to exit\u2026`);
|
|
95189
|
+
if (await waitForDaemonExit(lock, STOP_WAIT_MS)) {
|
|
95190
|
+
stopLockedDaemon(lockPath);
|
|
95191
|
+
console.log(`daemon stopped \u2014 safe to start it again`);
|
|
95192
|
+
} else {
|
|
95193
|
+
console.warn(
|
|
95194
|
+
`daemon (pid ${lock.pid}) has not exited after ${STOP_WAIT_MS / 1e3}s; it may still hold port 7891 and its stores. Check it with \`ps -p ${lock.pid}\` (Windows: \`Get-Process -Id ${lock.pid}\`) before starting again.`
|
|
95195
|
+
);
|
|
95196
|
+
process.exitCode = 1;
|
|
95197
|
+
}
|
|
95198
|
+
} else if (result === "signaled") console.log(`sent SIGTERM to the verified daemon process`);
|
|
95118
95199
|
else if (result === "stale") console.log(`removed stale daemon lock; no process was signaled`);
|
|
95119
95200
|
else if (result === "missing") console.log(`no daemon lock found \u2014 nothing to stop`);
|
|
95120
95201
|
else throw new Error(`daemon lock ownership is ${result}; no process was signaled and the lock was preserved`);
|
|
@@ -95212,13 +95293,13 @@ async function cmdInstallHooks(args2) {
|
|
|
95212
95293
|
}
|
|
95213
95294
|
}
|
|
95214
95295
|
async function installOpencodePlugin(port) {
|
|
95215
|
-
const { mkdirSync: mkdirSync12, existsSync: existsSync40, readFileSync:
|
|
95296
|
+
const { mkdirSync: mkdirSync12, existsSync: existsSync40, readFileSync: readFileSync42, writeFileSync: writeFileSync30 } = await import("node:fs");
|
|
95216
95297
|
const { join: join49 } = await import("node:path");
|
|
95217
95298
|
const dir = join49(ROOT, ".opencode", "plugin");
|
|
95218
95299
|
if (!existsSync40(dir)) mkdirSync12(dir, { recursive: true });
|
|
95219
95300
|
const file2 = join49(dir, "inerrata.js");
|
|
95220
95301
|
if (existsSync40(file2)) {
|
|
95221
|
-
const head2 =
|
|
95302
|
+
const head2 = readFileSync42(file2, "utf8").split("\n")[0] ?? "";
|
|
95222
95303
|
if (head2.trim() !== OPENCODE_PLUGIN_MARKER) {
|
|
95223
95304
|
console.error(`refusing to overwrite ${file2}: not an errata-managed plugin (line 1 lacks the marker)`);
|
|
95224
95305
|
process.exit(2);
|
|
@@ -95229,7 +95310,7 @@ async function installOpencodePlugin(port) {
|
|
|
95229
95310
|
let cfg = { $schema: "https://opencode.ai/config.json" };
|
|
95230
95311
|
if (existsSync40(cfgFile)) {
|
|
95231
95312
|
try {
|
|
95232
|
-
cfg = JSON.parse(
|
|
95313
|
+
cfg = JSON.parse(readFileSync42(cfgFile, "utf8"));
|
|
95233
95314
|
} catch {
|
|
95234
95315
|
console.error(`refusing to touch invalid JSON at ${cfgFile} \u2014 fix it and re-run`);
|
|
95235
95316
|
process.exit(2);
|
|
@@ -95275,7 +95356,7 @@ function installClaudeMods() {
|
|
|
95275
95356
|
}
|
|
95276
95357
|
}
|
|
95277
95358
|
async function installClaudeHooks(port) {
|
|
95278
|
-
const { mkdirSync: mkdirSync12, existsSync: existsSync40, readFileSync:
|
|
95359
|
+
const { mkdirSync: mkdirSync12, existsSync: existsSync40, readFileSync: readFileSync42, writeFileSync: writeFileSync30 } = await import("node:fs");
|
|
95279
95360
|
const { join: join49 } = await import("node:path");
|
|
95280
95361
|
const dir = join49(ROOT, ".claude");
|
|
95281
95362
|
if (!existsSync40(dir)) mkdirSync12(dir, { recursive: true });
|
|
@@ -95283,7 +95364,7 @@ async function installClaudeHooks(port) {
|
|
|
95283
95364
|
let settings = {};
|
|
95284
95365
|
if (existsSync40(file2)) {
|
|
95285
95366
|
try {
|
|
95286
|
-
settings = JSON.parse(
|
|
95367
|
+
settings = JSON.parse(readFileSync42(file2, "utf8"));
|
|
95287
95368
|
} catch {
|
|
95288
95369
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
95289
95370
|
process.exit(2);
|
|
@@ -95349,7 +95430,7 @@ async function installClaudeHooks(port) {
|
|
|
95349
95430
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
95350
95431
|
}
|
|
95351
95432
|
async function installClaudeMcpConfig() {
|
|
95352
|
-
const { mkdirSync: mkdirSync12, existsSync: existsSync40, readFileSync:
|
|
95433
|
+
const { mkdirSync: mkdirSync12, existsSync: existsSync40, readFileSync: readFileSync42, writeFileSync: writeFileSync30 } = await import("node:fs");
|
|
95353
95434
|
const { join: join49, dirname: dirname16 } = await import("node:path");
|
|
95354
95435
|
const file2 = join49(ROOT, ".mcp.json");
|
|
95355
95436
|
const dir = dirname16(file2);
|
|
@@ -95357,7 +95438,7 @@ async function installClaudeMcpConfig() {
|
|
|
95357
95438
|
let cfg = {};
|
|
95358
95439
|
if (existsSync40(file2)) {
|
|
95359
95440
|
try {
|
|
95360
|
-
cfg = JSON.parse(
|
|
95441
|
+
cfg = JSON.parse(readFileSync42(file2, "utf8"));
|
|
95361
95442
|
} catch {
|
|
95362
95443
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
95363
95444
|
process.exit(2);
|
|
@@ -95371,7 +95452,7 @@ async function installClaudeMcpConfig() {
|
|
|
95371
95452
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
|
|
95372
95453
|
}
|
|
95373
95454
|
async function installCursorMcpConfig() {
|
|
95374
|
-
const { mkdirSync: mkdirSync12, existsSync: existsSync40, readFileSync:
|
|
95455
|
+
const { mkdirSync: mkdirSync12, existsSync: existsSync40, readFileSync: readFileSync42, writeFileSync: writeFileSync30 } = await import("node:fs");
|
|
95375
95456
|
const { join: join49 } = await import("node:path");
|
|
95376
95457
|
const dir = join49(ROOT, ".cursor");
|
|
95377
95458
|
if (!existsSync40(dir)) mkdirSync12(dir, { recursive: true });
|
|
@@ -95379,7 +95460,7 @@ async function installCursorMcpConfig() {
|
|
|
95379
95460
|
let cfg = {};
|
|
95380
95461
|
if (existsSync40(file2)) {
|
|
95381
95462
|
try {
|
|
95382
|
-
cfg = JSON.parse(
|
|
95463
|
+
cfg = JSON.parse(readFileSync42(file2, "utf8"));
|
|
95383
95464
|
} catch {
|
|
95384
95465
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
95385
95466
|
process.exit(2);
|
|
@@ -95582,7 +95663,21 @@ function installLogTimestamps() {
|
|
|
95582
95663
|
};
|
|
95583
95664
|
}
|
|
95584
95665
|
}
|
|
95666
|
+
function followLogHint() {
|
|
95667
|
+
const log = daemonLogPath();
|
|
95668
|
+
return process.platform === "win32" ? `Get-Content -Wait "${log}"` : `tail -f "${log}"`;
|
|
95669
|
+
}
|
|
95585
95670
|
async function cmdDash(args2) {
|
|
95671
|
+
const running = readDaemonLock(globalDaemonLock());
|
|
95672
|
+
if (running && daemonLockState(running, true) === "running") {
|
|
95673
|
+
console.log(
|
|
95674
|
+
`errata daemon already running \xB7 pid ${running.pid}${running.version ? ` \xB7 ${running.version}` : ""}${running.webUiUrl ? ` \xB7 ${running.webUiUrl}` : ""}`
|
|
95675
|
+
);
|
|
95676
|
+
console.log(` follow it: ${followLogHint()}`);
|
|
95677
|
+
console.log(` check it: errata status`);
|
|
95678
|
+
console.log(` restart it: errata stop, then errata start`);
|
|
95679
|
+
return;
|
|
95680
|
+
}
|
|
95586
95681
|
process.title = "errata-daemon";
|
|
95587
95682
|
installLogTimestamps();
|
|
95588
95683
|
refreshExistingCodexHooks();
|
|
@@ -95952,6 +96047,11 @@ async function cmdDash(args2) {
|
|
|
95952
96047
|
const shutdown = async (signal) => {
|
|
95953
96048
|
console.log(`
|
|
95954
96049
|
shutting down\u2026 (${signal})`);
|
|
96050
|
+
setTimeout(() => {
|
|
96051
|
+
console.warn(`[errata] shutdown exceeded ${SHUTDOWN_DEADLINE_MS / 1e3}s \u2014 forcing exit`);
|
|
96052
|
+
releaseOwnLock(globalDaemonLock());
|
|
96053
|
+
process.exit(1);
|
|
96054
|
+
}, SHUTDOWN_DEADLINE_MS).unref();
|
|
95955
96055
|
clearInterval(interval);
|
|
95956
96056
|
clearInterval(nightlyInterval);
|
|
95957
96057
|
if (quiesceTimer) clearTimeout(quiesceTimer);
|