@inerrata-corporation/errata 2.0.2-dev.831 → 2.0.2-dev.835
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 +116 -33
- package/package.json +1 -1
package/errata.mjs
CHANGED
|
@@ -22659,7 +22659,7 @@ function buildSnapshot(opts) {
|
|
|
22659
22659
|
const stillOpen = problems.filter((p) => p.attrs["resolvedAt"] == null);
|
|
22660
22660
|
const allProblems = stillOpen.filter((p) => !isConstraintProblem(p));
|
|
22661
22661
|
allProblems.sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt);
|
|
22662
|
-
const
|
|
22662
|
+
const recent2 = allProblems.slice(0, 8).map((p) => ({
|
|
22663
22663
|
node: p,
|
|
22664
22664
|
anchors: opts.store.outEdges(p.id, ["MANIFESTED_IN", "EVIDENCED_BY"])
|
|
22665
22665
|
}));
|
|
@@ -22719,10 +22719,10 @@ function buildSnapshot(opts) {
|
|
|
22719
22719
|
packages: opts.profile.stack.map((name2) => ({ name: name2, node: matchNode(pkgNodes, pkgBase(name2)) })),
|
|
22720
22720
|
tools: toolNodes.map((node2) => ({ name: String(node2.attrs["name"] ?? node2.description), node: node2 }))
|
|
22721
22721
|
};
|
|
22722
|
-
const causalNudge =
|
|
22722
|
+
const causalNudge = recent2.length >= 2 && recent2.every(
|
|
22723
22723
|
(r) => opts.store.outEdges(r.node.id, ["CAUSED_BY"]).length === 0 && opts.store.inEdges(r.node.id, ["CAUSED_BY"]).length === 0
|
|
22724
22724
|
);
|
|
22725
|
-
const abstractUndomained =
|
|
22725
|
+
const abstractUndomained = recent2.filter((r) => {
|
|
22726
22726
|
const grounded = opts.store.outEdges(r.node.id, ["ANCHORED_AT", "OCCURS_IN", "DEPENDS_ON"]).length > 0;
|
|
22727
22727
|
const hasDomain = opts.store.outEdges(r.node.id, ["PERTAIN_TO"]).length > 0;
|
|
22728
22728
|
return !grounded && !hasDomain;
|
|
@@ -22731,7 +22731,7 @@ function buildSnapshot(opts) {
|
|
|
22731
22731
|
return {
|
|
22732
22732
|
profile: opts.profile,
|
|
22733
22733
|
profileContext,
|
|
22734
|
-
recentProblems:
|
|
22734
|
+
recentProblems: recent2,
|
|
22735
22735
|
recentResolved,
|
|
22736
22736
|
recentConstraints,
|
|
22737
22737
|
...causalNudge ? { causalNudge } : {},
|
|
@@ -54145,7 +54145,7 @@ function appendPassLedger(configDir, kind, durationMs, counts) {
|
|
|
54145
54145
|
const path2 = passLedgerPath(configDir);
|
|
54146
54146
|
try {
|
|
54147
54147
|
const mem = process.memoryUsage();
|
|
54148
|
-
const
|
|
54148
|
+
const census2 = isolateCensus();
|
|
54149
54149
|
const entry = {
|
|
54150
54150
|
ts: Date.now(),
|
|
54151
54151
|
kind,
|
|
@@ -54156,9 +54156,9 @@ function appendPassLedger(configDir, kind, durationMs, counts) {
|
|
|
54156
54156
|
heapUsedMB: Math.round(mem.heapUsed / 1048576),
|
|
54157
54157
|
externalMB: Math.round(mem.external / 1048576),
|
|
54158
54158
|
arrayBuffersMB: Math.round(mem.arrayBuffers / 1048576),
|
|
54159
|
-
isolatesLive:
|
|
54160
|
-
isolatesSpawned:
|
|
54161
|
-
isolatesPeak:
|
|
54159
|
+
isolatesLive: census2.live,
|
|
54160
|
+
isolatesSpawned: census2.spawnedTotal,
|
|
54161
|
+
isolatesPeak: census2.peak
|
|
54162
54162
|
}
|
|
54163
54163
|
};
|
|
54164
54164
|
appendFileSync2(path2, JSON.stringify(entry) + "\n");
|
|
@@ -54357,6 +54357,7 @@ var DAEMON_MAX_HEAP_MB = numEnv("ERRATA_MAX_HEAP_MB", 2048);
|
|
|
54357
54357
|
var WORKER_MAX_HEAP_MB = numEnv("ERRATA_WORKER_MAX_HEAP_MB", 1024);
|
|
54358
54358
|
var WORKSPACE_IDLE_TTL_MS = numEnv("ERRATA_WORKSPACE_IDLE_TTL_MS", 15 * 6e4);
|
|
54359
54359
|
var WORKSPACE_SWEEP_INTERVAL_MS = numEnv("ERRATA_WORKSPACE_SWEEP_MS", 6e4);
|
|
54360
|
+
var EAGER_WORKSPACES_AT_BOOT = process.env["ERRATA_EAGER_WORKSPACES"] === "1";
|
|
54360
54361
|
var HARVEST_SLICE_BYTES = numEnv("ERRATA_HARVEST_SLICE_BYTES", 4e6);
|
|
54361
54362
|
function workerResourceLimits() {
|
|
54362
54363
|
return { maxOldGenerationSizeMb: WORKER_MAX_HEAP_MB };
|
|
@@ -55486,7 +55487,7 @@ ${GITIGNORE_LINES.join("\n")}
|
|
|
55486
55487
|
var INTENT_TTL_MS = 15 * 60 * 1e3;
|
|
55487
55488
|
function createIntentState(ttlMs = INTENT_TTL_MS) {
|
|
55488
55489
|
const bySession = /* @__PURE__ */ new Map();
|
|
55489
|
-
let
|
|
55490
|
+
let recent2 = null;
|
|
55490
55491
|
const live2 = (s, nowMs) => s !== void 0 && nowMs - s.atMs < ttlMs;
|
|
55491
55492
|
return {
|
|
55492
55493
|
set(sessionId, text, nowMs) {
|
|
@@ -55494,8 +55495,8 @@ function createIntentState(ttlMs = INTENT_TTL_MS) {
|
|
|
55494
55495
|
if (!trimmed) return false;
|
|
55495
55496
|
const prev = bySession.get(sessionId);
|
|
55496
55497
|
bySession.set(sessionId, { text: trimmed, atMs: nowMs });
|
|
55497
|
-
const changed = !(
|
|
55498
|
-
|
|
55498
|
+
const changed = !(recent2 && recent2.text === trimmed);
|
|
55499
|
+
recent2 = { sessionId, text: trimmed, atMs: nowMs };
|
|
55499
55500
|
if (!changed && prev && prev.text === trimmed) return false;
|
|
55500
55501
|
return changed;
|
|
55501
55502
|
},
|
|
@@ -55504,12 +55505,12 @@ function createIntentState(ttlMs = INTENT_TTL_MS) {
|
|
|
55504
55505
|
return live2(s, nowMs) ? s.text : void 0;
|
|
55505
55506
|
},
|
|
55506
55507
|
mostRecent(nowMs) {
|
|
55507
|
-
if (!
|
|
55508
|
-
return nowMs -
|
|
55508
|
+
if (!recent2) return void 0;
|
|
55509
|
+
return nowMs - recent2.atMs < ttlMs ? recent2.text : void 0;
|
|
55509
55510
|
},
|
|
55510
55511
|
clear(sessionId) {
|
|
55511
55512
|
bySession.delete(sessionId);
|
|
55512
|
-
if (
|
|
55513
|
+
if (recent2?.sessionId === sessionId) recent2 = null;
|
|
55513
55514
|
}
|
|
55514
55515
|
};
|
|
55515
55516
|
}
|
|
@@ -55517,19 +55518,19 @@ function createIntentState(ttlMs = INTENT_TTL_MS) {
|
|
|
55517
55518
|
// src/working-file-state.ts
|
|
55518
55519
|
function createWorkingFileState() {
|
|
55519
55520
|
const bySession = /* @__PURE__ */ new Map();
|
|
55520
|
-
let
|
|
55521
|
+
let recent2 = null;
|
|
55521
55522
|
return {
|
|
55522
55523
|
set(sessionId, rel) {
|
|
55523
55524
|
bySession.set(sessionId, rel);
|
|
55524
|
-
if (rel ===
|
|
55525
|
-
|
|
55525
|
+
if (rel === recent2) return false;
|
|
55526
|
+
recent2 = rel;
|
|
55526
55527
|
return true;
|
|
55527
55528
|
},
|
|
55528
55529
|
get(sessionId) {
|
|
55529
55530
|
return bySession.get(sessionId);
|
|
55530
55531
|
},
|
|
55531
55532
|
mostRecent() {
|
|
55532
|
-
return
|
|
55533
|
+
return recent2;
|
|
55533
55534
|
}
|
|
55534
55535
|
};
|
|
55535
55536
|
}
|
|
@@ -56072,13 +56073,32 @@ function createLivenessWatch(deps) {
|
|
|
56072
56073
|
|
|
56073
56074
|
// src/loop-lag.ts
|
|
56074
56075
|
var HEARTBEAT_MS = 500;
|
|
56076
|
+
var RECENT_PASS_LIMIT = 12;
|
|
56075
56077
|
var currentPass = "idle";
|
|
56078
|
+
var currentPassStartedAt = null;
|
|
56076
56079
|
var started = false;
|
|
56080
|
+
var recent = [];
|
|
56077
56081
|
function markPass(name2) {
|
|
56078
56082
|
const prev = currentPass;
|
|
56083
|
+
const prevStart = currentPassStartedAt;
|
|
56084
|
+
const startedAt = Date.now();
|
|
56079
56085
|
currentPass = name2;
|
|
56086
|
+
currentPassStartedAt = startedAt;
|
|
56087
|
+
let restored = false;
|
|
56080
56088
|
return () => {
|
|
56089
|
+
if (restored) return;
|
|
56090
|
+
restored = true;
|
|
56091
|
+
recent.unshift({ name: name2, ms: Date.now() - startedAt, endedAt: Date.now() });
|
|
56092
|
+
if (recent.length > RECENT_PASS_LIMIT) recent.pop();
|
|
56081
56093
|
currentPass = prev;
|
|
56094
|
+
currentPassStartedAt = prevStart;
|
|
56095
|
+
};
|
|
56096
|
+
}
|
|
56097
|
+
function passState() {
|
|
56098
|
+
return {
|
|
56099
|
+
current: currentPass,
|
|
56100
|
+
runningMs: currentPassStartedAt === null ? null : Date.now() - currentPassStartedAt,
|
|
56101
|
+
recent: [...recent]
|
|
56082
56102
|
};
|
|
56083
56103
|
}
|
|
56084
56104
|
function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
@@ -56098,8 +56118,28 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
56098
56118
|
timer.unref();
|
|
56099
56119
|
}
|
|
56100
56120
|
|
|
56121
|
+
// src/watch-census.ts
|
|
56122
|
+
var census = { dispatched: 0, emitted: 0, logged: 0, rejected: 0, since: Date.now() };
|
|
56123
|
+
var noteWatchDispatched = () => void census.dispatched++;
|
|
56124
|
+
var noteWatchEmitted = () => void census.emitted++;
|
|
56125
|
+
var noteWatchLogged = () => void census.logged++;
|
|
56126
|
+
var noteWatchRejected = () => void census.rejected++;
|
|
56127
|
+
function watchCensus() {
|
|
56128
|
+
return { ...census };
|
|
56129
|
+
}
|
|
56130
|
+
function watchCensusLine(c = watchCensus()) {
|
|
56131
|
+
if (c.dispatched === 0 && c.emitted === 0) return null;
|
|
56132
|
+
const mins = Math.max(1, Math.round((Date.now() - c.since) / 6e4));
|
|
56133
|
+
const perMin = Math.round(c.dispatched / mins);
|
|
56134
|
+
const base = `${c.dispatched} OS event(s) \u2192 ${c.logged} logged (${perMin}/min, ${c.rejected} rejected here)`;
|
|
56135
|
+
if (c.logged === 0 && c.dispatched > 500) {
|
|
56136
|
+
return `${base} \u26A0 watcher is doing work with NO output \u2014 a watch target likely contains an ignored tree`;
|
|
56137
|
+
}
|
|
56138
|
+
return base;
|
|
56139
|
+
}
|
|
56140
|
+
|
|
56101
56141
|
// src/engine.ts
|
|
56102
|
-
var DAEMON_VERSION = true ? "2.0.2-dev.
|
|
56142
|
+
var DAEMON_VERSION = true ? "2.0.2-dev.835" : "2.0.0-alpha.0";
|
|
56103
56143
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
56104
56144
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
56105
56145
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -56242,8 +56282,13 @@ function createWorkspaceEngine(opts) {
|
|
|
56242
56282
|
ignoreInitial: true,
|
|
56243
56283
|
persistent: true
|
|
56244
56284
|
});
|
|
56285
|
+
watcher.on("raw", noteWatchDispatched);
|
|
56245
56286
|
const onFs = (kind) => (path2) => {
|
|
56246
|
-
|
|
56287
|
+
noteWatchEmitted();
|
|
56288
|
+
if (IGNORED_PATH.test(path2) || IGNORED_NOISE.test(path2)) {
|
|
56289
|
+
noteWatchRejected();
|
|
56290
|
+
return;
|
|
56291
|
+
}
|
|
56247
56292
|
let size = 0;
|
|
56248
56293
|
try {
|
|
56249
56294
|
size = statSync5(path2).size;
|
|
@@ -56253,6 +56298,7 @@ function createWorkspaceEngine(opts) {
|
|
|
56253
56298
|
const base = { ts: Date.now(), kind, workspaceId: profile.id, path: path2, size };
|
|
56254
56299
|
const ev = { ...base, digest: digest(base) };
|
|
56255
56300
|
log.append(ev);
|
|
56301
|
+
noteWatchLogged();
|
|
56256
56302
|
};
|
|
56257
56303
|
watcher.on("add", onFs("fs.add"));
|
|
56258
56304
|
watcher.on("change", onFs("fs.change"));
|
|
@@ -59608,17 +59654,23 @@ async function startMultiDaemon(opts = {}) {
|
|
|
59608
59654
|
}
|
|
59609
59655
|
}
|
|
59610
59656
|
const entries = listWorkspaceEntries();
|
|
59611
|
-
|
|
59612
|
-
|
|
59613
|
-
|
|
59614
|
-
|
|
59615
|
-
|
|
59657
|
+
if (opts.eagerWorkspaces ?? EAGER_WORKSPACES_AT_BOOT) {
|
|
59658
|
+
for (const entry of entries) {
|
|
59659
|
+
try {
|
|
59660
|
+
records.push(buildRecord(entry));
|
|
59661
|
+
} catch (err2) {
|
|
59662
|
+
console.warn(`[errata] skipping ${entry.name} (${entry.path}): ${err2 instanceof Error ? err2.message : err2}`);
|
|
59663
|
+
}
|
|
59616
59664
|
}
|
|
59617
|
-
|
|
59618
|
-
|
|
59619
|
-
|
|
59620
|
-
|
|
59621
|
-
|
|
59665
|
+
if (entries.length > 0 && records.length < entries.length) {
|
|
59666
|
+
const failed = entries.length - records.length;
|
|
59667
|
+
console.warn(
|
|
59668
|
+
`[errata] \u26A0 ${failed} of ${entries.length} project(s) failed to start \u2014 likely a stale daemon holding DB locks. Run \`errata stop\` (or kill the old errata process) and retry.`
|
|
59669
|
+
);
|
|
59670
|
+
}
|
|
59671
|
+
} else if (entries.length > 0) {
|
|
59672
|
+
console.log(
|
|
59673
|
+
`[errata] ${entries.length} workspace(s) registered \xB7 cold \u2014 an engine spawns on the first hook from each`
|
|
59622
59674
|
);
|
|
59623
59675
|
}
|
|
59624
59676
|
const app = new Hono2();
|
|
@@ -59733,6 +59785,16 @@ async function startMultiDaemon(opts = {}) {
|
|
|
59733
59785
|
(c) => c.json({
|
|
59734
59786
|
ok: true,
|
|
59735
59787
|
daemonVersion: DAEMON_VERSION,
|
|
59788
|
+
// What the daemon is DOING, not just what it holds. Without these a
|
|
59789
|
+
// pegged daemon is only diagnosable by attaching a CPU profiler to the
|
|
59790
|
+
// live process — see watch-census.ts for the incident that proved it.
|
|
59791
|
+
pass: passState(),
|
|
59792
|
+
watch: watchCensus(),
|
|
59793
|
+
// Registered but with no engine running (WS-cold-start). Listed so a cold
|
|
59794
|
+
// daemon is legible as "nothing has needed waking yet" rather than as
|
|
59795
|
+
// "the registry lost my projects" — an invisible cold workspace is
|
|
59796
|
+
// indistinguishable from a missing one, and only one of those is fine.
|
|
59797
|
+
cold: listWorkspaceEntries().filter((e) => !records.some((r) => normPath(r.root) === normPath(e.path))).map((e) => ({ name: e.name, path: e.path })),
|
|
59736
59798
|
projects: records.map((r) => ({
|
|
59737
59799
|
id: r.id,
|
|
59738
59800
|
name: r.entry.name,
|
|
@@ -59756,10 +59818,11 @@ async function startMultiDaemon(opts = {}) {
|
|
|
59756
59818
|
let owner = ownerOf(records, pathInBody(body2));
|
|
59757
59819
|
if (!owner) {
|
|
59758
59820
|
const missPath = pathInBody(body2);
|
|
59759
|
-
const
|
|
59760
|
-
|
|
59821
|
+
const registeredRoot = missPath ? pickOwnerRoot(listWorkspaceEntries().map((e) => e.path), missPath) : null;
|
|
59822
|
+
const wakeRoot = registeredRoot ?? (missPath ? findGitRoot(missPath) : null);
|
|
59823
|
+
if (wakeRoot && attachWorkspace(wakeRoot).attached) {
|
|
59761
59824
|
owner = ownerOf(records, missPath) ?? null;
|
|
59762
|
-
if (owner) console.log(`[errata] woke
|
|
59825
|
+
if (owner) console.log(`[errata] woke workspace ${owner.entry.name}`);
|
|
59763
59826
|
}
|
|
59764
59827
|
}
|
|
59765
59828
|
if (!owner) {
|
|
@@ -61784,6 +61847,26 @@ async function cmdStatus() {
|
|
|
61784
61847
|
console.log(
|
|
61785
61848
|
` daemon: ${running ? `running \xB7 pid ${running.pid} \xB7 ${running.webUiUrl ?? "(running)"}` : "not running (run: errata start)"}`
|
|
61786
61849
|
);
|
|
61850
|
+
if (running?.webUiUrl) {
|
|
61851
|
+
try {
|
|
61852
|
+
const res = await fetch(`${running.webUiUrl}/health`, {
|
|
61853
|
+
signal: AbortSignal.timeout(3e3)
|
|
61854
|
+
});
|
|
61855
|
+
if (res.ok) {
|
|
61856
|
+
const h = await res.json();
|
|
61857
|
+
if (h.pass) {
|
|
61858
|
+
const held = h.pass.runningMs !== null && h.pass.current !== "idle" ? ` (${(h.pass.runningMs / 1e3).toFixed(1)}s)` : "";
|
|
61859
|
+
const last = (h.pass.recent ?? []).slice(0, 3).map((p) => `${p.name} ${(p.ms / 1e3).toFixed(1)}s`).join(", ");
|
|
61860
|
+
console.log(` pass: ${h.pass.current}${held}${last ? ` \xB7 recent: ${last}` : ""}`);
|
|
61861
|
+
}
|
|
61862
|
+
if (h.watch) {
|
|
61863
|
+
const line = watchCensusLine(h.watch);
|
|
61864
|
+
if (line) console.log(` watcher: ${line}`);
|
|
61865
|
+
}
|
|
61866
|
+
}
|
|
61867
|
+
} catch {
|
|
61868
|
+
}
|
|
61869
|
+
}
|
|
61787
61870
|
const all = listWorkspaces();
|
|
61788
61871
|
const missing = all.filter((w) => w.missing).length;
|
|
61789
61872
|
console.log(
|