@inerrata-corporation/errata 2.0.2-dev.1116 → 2.0.2-dev.1166
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 +377 -20
- package/package.json +1 -1
package/errata.mjs
CHANGED
|
@@ -22976,6 +22976,14 @@ function renderSnapshot(s) {
|
|
|
22976
22976
|
);
|
|
22977
22977
|
lines.push("");
|
|
22978
22978
|
}
|
|
22979
|
+
if (s.daemonDistress) {
|
|
22980
|
+
const mins = Math.max(1, Math.round((Date.now() - s.daemonDistress.sinceTs) / 6e4));
|
|
22981
|
+
lines.push("### \u{1F6A8} errata daemon distress");
|
|
22982
|
+
lines.push(
|
|
22983
|
+
`${s.daemonDistress.body} (ongoing ~${mins} min). TELL YOUR USER about this now \u2014 the daemon cannot fix everything itself, and this line may be its only witness. \`errata status\` has detail; a daemon restart (\`errata stop\` then \`errata start\`) is safe mid-session.`
|
|
22984
|
+
);
|
|
22985
|
+
lines.push("");
|
|
22986
|
+
}
|
|
22979
22987
|
if (s.needsRevisit.length > 0) {
|
|
22980
22988
|
lines.push("### \u26A0\uFE0F Needs revisit \u2014 a fact these rested on changed");
|
|
22981
22989
|
lines.push(
|
|
@@ -23071,6 +23079,12 @@ function renderSnapshot(s) {
|
|
|
23071
23079
|
const v = m.attrs?.["stratum"];
|
|
23072
23080
|
return v === "project" || v === "team" || v === "org" ? v : void 0;
|
|
23073
23081
|
};
|
|
23082
|
+
const contributorOf = (m) => {
|
|
23083
|
+
if (stratumOf(m) === void 0) return void 0;
|
|
23084
|
+
const c = m.attrs?.["contributor"];
|
|
23085
|
+
if (!c || typeof c.label !== "string" || c.label.length === 0) return void 0;
|
|
23086
|
+
return { label: c.label, ...typeof c.team === "string" && c.team ? { team: c.team } : {} };
|
|
23087
|
+
};
|
|
23074
23088
|
const hasOwnOrg = s.remote.some((m) => stratumOf(m) !== void 0);
|
|
23075
23089
|
lines.push("### From the Errata Network \u2014 collective priors");
|
|
23076
23090
|
lines.push(
|
|
@@ -23078,14 +23092,14 @@ function renderSnapshot(s) {
|
|
|
23078
23092
|
);
|
|
23079
23093
|
if (hasOwnOrg) {
|
|
23080
23094
|
lines.push(
|
|
23081
|
-
"_Entries marked `[org]`/`[team]`/`[project]` are from YOUR org's membrane \u2014 specifics are real and checkable; someone here already hit this, so consider coordinating before re-deriving._"
|
|
23095
|
+
"_Entries marked `[org]`/`[team]`/`[project]` are from YOUR org's membrane \u2014 specifics are real and checkable; someone here already hit this, so consider coordinating before re-deriving. A `\xB7 name` after the stratum is the authoring installation \u2014 who to coordinate with._"
|
|
23082
23096
|
);
|
|
23083
23097
|
}
|
|
23084
23098
|
for (const m of s.remote) {
|
|
23085
23099
|
const stratum = stratumOf(m);
|
|
23086
|
-
|
|
23087
|
-
|
|
23088
|
-
);
|
|
23100
|
+
const contributor = contributorOf(m);
|
|
23101
|
+
const chip = stratum ? `\`[${stratum}${contributor ? ` \xB7 ${contributor.label}${contributor.team ? `/${contributor.team}` : ""}` : ""}]\` ` : "";
|
|
23102
|
+
lines.push(`- ${chip}**${m.label}:** ${m.description}${tagOf(m)}`);
|
|
23089
23103
|
}
|
|
23090
23104
|
lines.push("");
|
|
23091
23105
|
}
|
|
@@ -23282,6 +23296,7 @@ function assembleAgentContext(opts) {
|
|
|
23282
23296
|
});
|
|
23283
23297
|
if (opts.edgeElicitation) snapshot.edgeElicitation = opts.edgeElicitation;
|
|
23284
23298
|
if (opts.pendingUpdate) snapshot.pendingUpdate = opts.pendingUpdate;
|
|
23299
|
+
if (opts.daemonDistress) snapshot.daemonDistress = opts.daemonDistress;
|
|
23285
23300
|
if (opts.reviewItems?.length) snapshot.reviewItems = [...opts.reviewItems];
|
|
23286
23301
|
if (opts.statedIntent) snapshot.statedIntent = opts.statedIntent;
|
|
23287
23302
|
if (opts.remote && opts.remote.length > 0) {
|
|
@@ -24644,6 +24659,7 @@ function defaultConfig() {
|
|
|
24644
24659
|
// user opts into sync at all.
|
|
24645
24660
|
consent: { sync: false, telemetry: false, contributePackages: true },
|
|
24646
24661
|
notifications: true,
|
|
24662
|
+
opsNotices: false,
|
|
24647
24663
|
onboardedAt: null,
|
|
24648
24664
|
machineId: null,
|
|
24649
24665
|
updateChannel: "dev",
|
|
@@ -28694,7 +28710,13 @@ function generalizeSymbols(text, lexicon, level = 1, fileLexicon) {
|
|
|
28694
28710
|
}
|
|
28695
28711
|
return generalize(out2, { level }).text;
|
|
28696
28712
|
}
|
|
28697
|
-
|
|
28713
|
+
function registerRenderedContributorLabels(labels) {
|
|
28714
|
+
for (const label of labels) {
|
|
28715
|
+
const trimmed = label.trim();
|
|
28716
|
+
if (trimmed.length >= 3) renderedContributorLabels.add(trimmed);
|
|
28717
|
+
}
|
|
28718
|
+
}
|
|
28719
|
+
var SYMBOL_LABELS2, KIND_PHRASE, BUILTIN_TYPE_NAMES, DOC_COMMENT_KINDS, MAX_DOC_CHARS, RE_RESERVED2, escapeRe4, RE_LEADING_ARTICLE2, CONVENTION_FILENAMES, CONVENTION_BASENAME_MIN_FILES, CONVENTION_STEMS, FILE_TOKEN_RE, STEM_TOKEN_RE, SOURCE_EXTENSIONS, TOKEN_RE3, renderedContributorLabels;
|
|
28698
28720
|
var init_generalize_graph = __esm({
|
|
28699
28721
|
"src/generalize-graph.ts"() {
|
|
28700
28722
|
"use strict";
|
|
@@ -28835,6 +28857,7 @@ var init_generalize_graph = __esm({
|
|
|
28835
28857
|
"cypher"
|
|
28836
28858
|
]);
|
|
28837
28859
|
TOKEN_RE3 = /[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*/g;
|
|
28860
|
+
renderedContributorLabels = /* @__PURE__ */ new Set();
|
|
28838
28861
|
}
|
|
28839
28862
|
});
|
|
28840
28863
|
|
|
@@ -52793,6 +52816,7 @@ function watch(paths, options = {}) {
|
|
|
52793
52816
|
var esm_default = { watch, FSWatcher };
|
|
52794
52817
|
|
|
52795
52818
|
// src/engine.ts
|
|
52819
|
+
init_generalize_graph();
|
|
52796
52820
|
init_src();
|
|
52797
52821
|
init_src2();
|
|
52798
52822
|
init_src5();
|
|
@@ -56413,7 +56437,8 @@ var TITLES = {
|
|
|
56413
56437
|
"hotspot-problem": "Errata \xB7 high-impact problem",
|
|
56414
56438
|
"index-started": "Errata \xB7 indexing\u2026",
|
|
56415
56439
|
"index-completed": "Errata \xB7 index ready \u2713",
|
|
56416
|
-
"mechanism-stalled": "Errata \xB7 a mechanism is not working"
|
|
56440
|
+
"mechanism-stalled": "Errata \xB7 a mechanism is not working",
|
|
56441
|
+
"daemon-distress": "Errata \xB7 daemon health \u26A0"
|
|
56417
56442
|
};
|
|
56418
56443
|
var lastFired = /* @__PURE__ */ new Map();
|
|
56419
56444
|
var THROTTLE_MS = 3e4;
|
|
@@ -56429,6 +56454,14 @@ function notifyEvent(kind, body2, opts = {}) {
|
|
|
56429
56454
|
} catch {
|
|
56430
56455
|
}
|
|
56431
56456
|
}
|
|
56457
|
+
function notifyOpsEvent(kind, body2, opts = {}) {
|
|
56458
|
+
try {
|
|
56459
|
+
if (!loadConfig().opsNotices) return;
|
|
56460
|
+
} catch {
|
|
56461
|
+
return;
|
|
56462
|
+
}
|
|
56463
|
+
notifyEvent(kind, body2, opts);
|
|
56464
|
+
}
|
|
56432
56465
|
function notifyTick(delta) {
|
|
56433
56466
|
const { problemsResolved, reviewsTriggered } = delta;
|
|
56434
56467
|
if (problemsResolved > 0)
|
|
@@ -56518,11 +56551,30 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
56518
56551
|
}
|
|
56519
56552
|
|
|
56520
56553
|
// src/watch-census.ts
|
|
56521
|
-
var census = {
|
|
56554
|
+
var census = {
|
|
56555
|
+
dispatched: 0,
|
|
56556
|
+
emitted: 0,
|
|
56557
|
+
logged: 0,
|
|
56558
|
+
rejected: 0,
|
|
56559
|
+
since: Date.now(),
|
|
56560
|
+
breakerRecycles: 0,
|
|
56561
|
+
breakerQuarantined: [],
|
|
56562
|
+
topOffender: null
|
|
56563
|
+
};
|
|
56564
|
+
var QUARANTINE_LIST_CAP = 8;
|
|
56522
56565
|
var noteWatchDispatched = () => void census.dispatched++;
|
|
56523
56566
|
var noteWatchEmitted = () => void census.emitted++;
|
|
56524
56567
|
var noteWatchLogged = () => void census.logged++;
|
|
56525
56568
|
var noteWatchRejected = () => void census.rejected++;
|
|
56569
|
+
var noteBreakerRecycle = (_path) => void census.breakerRecycles++;
|
|
56570
|
+
var noteBreakerQuarantine = (path2) => {
|
|
56571
|
+
if (!census.breakerQuarantined.includes(path2) && census.breakerQuarantined.length < QUARANTINE_LIST_CAP) {
|
|
56572
|
+
census.breakerQuarantined.push(path2);
|
|
56573
|
+
}
|
|
56574
|
+
};
|
|
56575
|
+
var noteWindowOffender = (path2, count, windowMs) => {
|
|
56576
|
+
census.topOffender = { path: path2, count, windowMs, at: Date.now() };
|
|
56577
|
+
};
|
|
56526
56578
|
function watchCensus() {
|
|
56527
56579
|
return { ...census };
|
|
56528
56580
|
}
|
|
@@ -56530,9 +56582,14 @@ function watchCensusLine(c = watchCensus()) {
|
|
|
56530
56582
|
if (c.dispatched === 0 && c.emitted === 0) return null;
|
|
56531
56583
|
const mins = Math.max(1, Math.round((Date.now() - c.since) / 6e4));
|
|
56532
56584
|
const perMin = Math.round(c.dispatched / mins);
|
|
56533
|
-
|
|
56534
|
-
if (c.
|
|
56535
|
-
|
|
56585
|
+
let base = `${c.dispatched} OS event(s) \u2192 ${c.logged} logged (${perMin}/min, ${c.rejected} rejected here)`;
|
|
56586
|
+
if (c.breakerRecycles > 0 || c.breakerQuarantined.length > 0) {
|
|
56587
|
+
const q = c.breakerQuarantined.length > 0 ? `, ${c.breakerQuarantined.length} quarantined` : "";
|
|
56588
|
+
base += ` \xB7 breaker: ${c.breakerRecycles} recycled${q}`;
|
|
56589
|
+
}
|
|
56590
|
+
if (c.dispatched > 500 && c.dispatched / Math.max(c.logged, 1) > 1e4) {
|
|
56591
|
+
const top = c.topOffender ? ` \u2014 top: ${c.topOffender.path} (${c.topOffender.count}/${Math.round(c.topOffender.windowMs / 1e3)}s)` : "";
|
|
56592
|
+
return `${base} \u26A0 watcher is doing work with NO output \u2014 a watch target likely contains an ignored tree${top}`;
|
|
56536
56593
|
}
|
|
56537
56594
|
return base;
|
|
56538
56595
|
}
|
|
@@ -56574,6 +56631,11 @@ function createLivenessWatch(deps) {
|
|
|
56574
56631
|
watchEmitted: watch2.emitted,
|
|
56575
56632
|
watchLogged: watch2.logged,
|
|
56576
56633
|
watchRejected: watch2.rejected,
|
|
56634
|
+
// HZ-watch-breaker: a recycle count trending upward across hours is a
|
|
56635
|
+
// handle that keeps wedging — the restart-survivable trace the 8-16
|
|
56636
|
+
// phantom-rename storm never left.
|
|
56637
|
+
watchBreakerRecycles: watch2.breakerRecycles,
|
|
56638
|
+
watchBreakerQuarantined: watch2.breakerQuarantined.length,
|
|
56577
56639
|
// Concurrency and the longest single holder — the two readings that
|
|
56578
56640
|
// named the 6017s zombie pass. A pass legitimately running for hours
|
|
56579
56641
|
// and one wedged forever look identical without a trend.
|
|
@@ -56598,8 +56660,108 @@ function createLivenessWatch(deps) {
|
|
|
56598
56660
|
};
|
|
56599
56661
|
}
|
|
56600
56662
|
|
|
56663
|
+
// src/watch-breaker.ts
|
|
56664
|
+
function numEnv3(key, fallback) {
|
|
56665
|
+
const n = Number(process.env[key]);
|
|
56666
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
56667
|
+
}
|
|
56668
|
+
var BREAKER_WINDOW_MS = numEnv3("ERRATA_WATCH_BREAKER_WINDOW_MS", 1e4);
|
|
56669
|
+
var BREAKER_TRIP_SELF_EVENTS = numEnv3("ERRATA_WATCH_BREAKER_TRIP", 1e3);
|
|
56670
|
+
var BREAKER_MAX_RECYCLES = numEnv3("ERRATA_WATCH_BREAKER_RECYCLES", 2);
|
|
56671
|
+
var BREAKER_REWEDGE_TTL_MS = numEnv3("ERRATA_WATCH_BREAKER_TTL_MS", 6e5);
|
|
56672
|
+
var BREAKER_READD_DELAY_MS = numEnv3("ERRATA_WATCH_BREAKER_READD_MS", 250);
|
|
56673
|
+
var OFFENDER_FLOOR = 100;
|
|
56674
|
+
function normalizeWatchPath(p) {
|
|
56675
|
+
let s = p.startsWith("\\\\?\\") ? p.slice(4) : p;
|
|
56676
|
+
s = s.replace(/\\/g, "/");
|
|
56677
|
+
if (s.length > 1 && s.endsWith("/")) s = s.slice(0, -1);
|
|
56678
|
+
return process.platform === "win32" ? s.toLowerCase() : s;
|
|
56679
|
+
}
|
|
56680
|
+
function createWatchBreaker(deps) {
|
|
56681
|
+
const now = deps.now ?? Date.now;
|
|
56682
|
+
const say = deps.onAction ?? (() => {
|
|
56683
|
+
});
|
|
56684
|
+
const windows2 = /* @__PURE__ */ new Map();
|
|
56685
|
+
let windowStart = now();
|
|
56686
|
+
const recycleHistory = /* @__PURE__ */ new Map();
|
|
56687
|
+
const quarantined = /* @__PURE__ */ new Set();
|
|
56688
|
+
const pendingReadds = /* @__PURE__ */ new Set();
|
|
56689
|
+
const rotate = (t) => {
|
|
56690
|
+
let top = null;
|
|
56691
|
+
for (const [path2, w] of windows2) {
|
|
56692
|
+
if (w.dispatched >= OFFENDER_FLOOR && (!top || w.dispatched > top.count)) {
|
|
56693
|
+
top = { path: path2, count: w.dispatched };
|
|
56694
|
+
}
|
|
56695
|
+
}
|
|
56696
|
+
if (top) noteWindowOffender(top.path, top.count, BREAKER_WINDOW_MS);
|
|
56697
|
+
windows2.clear();
|
|
56698
|
+
windowStart = t;
|
|
56699
|
+
};
|
|
56700
|
+
const trip = (path2, t) => {
|
|
56701
|
+
const history = (recycleHistory.get(path2) ?? []).filter(
|
|
56702
|
+
(ts) => t - ts < BREAKER_REWEDGE_TTL_MS
|
|
56703
|
+
);
|
|
56704
|
+
if (history.length >= BREAKER_MAX_RECYCLES) {
|
|
56705
|
+
quarantined.add(path2);
|
|
56706
|
+
recycleHistory.delete(path2);
|
|
56707
|
+
try {
|
|
56708
|
+
deps.unwatch(path2);
|
|
56709
|
+
} catch {
|
|
56710
|
+
}
|
|
56711
|
+
noteBreakerQuarantine(path2);
|
|
56712
|
+
say(
|
|
56713
|
+
`QUARANTINED ${path2} \u2014 re-wedged after ${history.length} recycle(s); unwatched for this session (reconcile covers its edits)`
|
|
56714
|
+
);
|
|
56715
|
+
return;
|
|
56716
|
+
}
|
|
56717
|
+
history.push(t);
|
|
56718
|
+
recycleHistory.set(path2, history);
|
|
56719
|
+
try {
|
|
56720
|
+
deps.unwatch(path2);
|
|
56721
|
+
} catch {
|
|
56722
|
+
}
|
|
56723
|
+
const timer = setTimeout(() => {
|
|
56724
|
+
pendingReadds.delete(timer);
|
|
56725
|
+
try {
|
|
56726
|
+
deps.readd(path2);
|
|
56727
|
+
} catch {
|
|
56728
|
+
}
|
|
56729
|
+
}, BREAKER_READD_DELAY_MS);
|
|
56730
|
+
timer.unref?.();
|
|
56731
|
+
pendingReadds.add(timer);
|
|
56732
|
+
noteBreakerRecycle(path2);
|
|
56733
|
+
say(
|
|
56734
|
+
`recycled ${path2} \u2014 ${BREAKER_TRIP_SELF_EVENTS}+ phantom self-events in ${Math.round(BREAKER_WINDOW_MS / 1e3)}s; handle closed + re-created`
|
|
56735
|
+
);
|
|
56736
|
+
};
|
|
56737
|
+
return {
|
|
56738
|
+
onRaw(event, evPath, watchedPath) {
|
|
56739
|
+
if (typeof watchedPath !== "string" || watchedPath.length === 0) return;
|
|
56740
|
+
const t = now();
|
|
56741
|
+
if (t - windowStart >= BREAKER_WINDOW_MS) rotate(t);
|
|
56742
|
+
let w = windows2.get(watchedPath);
|
|
56743
|
+
if (!w) {
|
|
56744
|
+
w = { dispatched: 0, self: 0, tripped: false };
|
|
56745
|
+
windows2.set(watchedPath, w);
|
|
56746
|
+
}
|
|
56747
|
+
w.dispatched++;
|
|
56748
|
+
const self = evPath == null || evPath === "" || typeof evPath === "string" && normalizeWatchPath(evPath) === normalizeWatchPath(watchedPath);
|
|
56749
|
+
if (!self) return;
|
|
56750
|
+
w.self++;
|
|
56751
|
+
if (!w.tripped && !quarantined.has(watchedPath) && w.self >= BREAKER_TRIP_SELF_EVENTS) {
|
|
56752
|
+
w.tripped = true;
|
|
56753
|
+
trip(watchedPath, t);
|
|
56754
|
+
}
|
|
56755
|
+
},
|
|
56756
|
+
stop() {
|
|
56757
|
+
for (const timer of pendingReadds) clearTimeout(timer);
|
|
56758
|
+
pendingReadds.clear();
|
|
56759
|
+
}
|
|
56760
|
+
};
|
|
56761
|
+
}
|
|
56762
|
+
|
|
56601
56763
|
// src/engine.ts
|
|
56602
|
-
var DAEMON_VERSION = true ? "2.0.2-dev.
|
|
56764
|
+
var DAEMON_VERSION = true ? "2.0.2-dev.1166" : "2.0.0-alpha.0";
|
|
56603
56765
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
56604
56766
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
56605
56767
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -56731,6 +56893,7 @@ function createWorkspaceEngine(opts) {
|
|
|
56731
56893
|
const cloud = opts.cloud;
|
|
56732
56894
|
const telemetry = new TelemetryRecorder(profile.id, DAEMON_VERSION);
|
|
56733
56895
|
let watcher = null;
|
|
56896
|
+
let watchBreaker = null;
|
|
56734
56897
|
let lastActivityTs = Date.now();
|
|
56735
56898
|
let stopGit = null;
|
|
56736
56899
|
let flushTimer = null;
|
|
@@ -56743,7 +56906,23 @@ function createWorkspaceEngine(opts) {
|
|
|
56743
56906
|
ignoreInitial: true,
|
|
56744
56907
|
persistent: true
|
|
56745
56908
|
});
|
|
56746
|
-
|
|
56909
|
+
watchBreaker = createWatchBreaker({
|
|
56910
|
+
unwatch: (p) => void watcher?.unwatch(p),
|
|
56911
|
+
readd: (p) => void watcher?.add(p),
|
|
56912
|
+
// Toast AND log: the autostarted daemon's stdout is a discarded stream
|
|
56913
|
+
// (the 8-01 unobservability finding), so console alone would make every
|
|
56914
|
+
// production breaker action invisible — the exact gauge-with-no-alarm
|
|
56915
|
+
// shape this mechanism exists to end.
|
|
56916
|
+
onAction: (line) => {
|
|
56917
|
+
console.warn(`[errata] watch-breaker: ${line}`);
|
|
56918
|
+
notifyOpsEvent("daemon-distress", `watch-breaker: ${line}`, { key: `breaker:${profile.id}` });
|
|
56919
|
+
}
|
|
56920
|
+
});
|
|
56921
|
+
watcher.on("raw", (event, evPath, opts2) => {
|
|
56922
|
+
noteWatchDispatched();
|
|
56923
|
+
const watchedPath = opts2 && typeof opts2 === "object" && "watchedPath" in opts2 ? opts2.watchedPath : void 0;
|
|
56924
|
+
watchBreaker?.onRaw(event, evPath, watchedPath);
|
|
56925
|
+
});
|
|
56747
56926
|
const onFs = (kind) => (path2) => {
|
|
56748
56927
|
noteWatchEmitted();
|
|
56749
56928
|
if (IGNORED_PATH.test(path2) || IGNORED_NOISE.test(path2)) {
|
|
@@ -57038,6 +57217,7 @@ function createWorkspaceEngine(opts) {
|
|
|
57038
57217
|
}) : null;
|
|
57039
57218
|
const doneRender = prebuilt ? null : markPass(`context-render-inline:${profile.name}`);
|
|
57040
57219
|
const pendingUpdate = opts.pendingUpdate?.() ?? null;
|
|
57220
|
+
const daemonDistress = opts.daemonDistress?.() ?? null;
|
|
57041
57221
|
const reviewItems = pickReviewItems();
|
|
57042
57222
|
const liveIntent = intents.mostRecent(Date.now());
|
|
57043
57223
|
maybeRefreshIntentPriors(liveIntent ?? null);
|
|
@@ -57055,6 +57235,7 @@ function createWorkspaceEngine(opts) {
|
|
|
57055
57235
|
...elicit ? { edgeElicitation: { instruction: PRIOR_TAG_INSTRUCTION } } : {},
|
|
57056
57236
|
...prebuilt ? { snapshot: prebuilt } : {},
|
|
57057
57237
|
...pendingUpdate ? { pendingUpdate } : {},
|
|
57238
|
+
...daemonDistress ? { daemonDistress } : {},
|
|
57058
57239
|
...reviewItems.length ? { reviewItems } : {},
|
|
57059
57240
|
...liveIntent ? {
|
|
57060
57241
|
statedIntent: {
|
|
@@ -57135,6 +57316,13 @@ function createWorkspaceEngine(opts) {
|
|
|
57135
57316
|
};
|
|
57136
57317
|
cloud.search(q).then((res) => {
|
|
57137
57318
|
remotePriors = res.nodes ?? [];
|
|
57319
|
+
const contributorLabels = [];
|
|
57320
|
+
for (const n of remotePriors) {
|
|
57321
|
+
const c = n.attrs?.["contributor"];
|
|
57322
|
+
if (typeof c?.label === "string") contributorLabels.push(c.label);
|
|
57323
|
+
if (typeof c?.team === "string") contributorLabels.push(c.team);
|
|
57324
|
+
}
|
|
57325
|
+
if (contributorLabels.length > 0) registerRenderedContributorLabels(contributorLabels);
|
|
57138
57326
|
contextDirty = true;
|
|
57139
57327
|
}).catch(() => {
|
|
57140
57328
|
}).finally(() => {
|
|
@@ -58565,6 +58753,7 @@ function createWorkspaceEngine(opts) {
|
|
|
58565
58753
|
async stop() {
|
|
58566
58754
|
if (stopGit) stopGit();
|
|
58567
58755
|
if (passWorker) await passWorker.stop();
|
|
58756
|
+
if (watchBreaker) watchBreaker.stop();
|
|
58568
58757
|
if (watcher) await watcher.close();
|
|
58569
58758
|
if (flushTimer) clearTimeout(flushTimer);
|
|
58570
58759
|
for (const tmr of diagTimers.values()) clearTimeout(tmr);
|
|
@@ -59934,6 +60123,137 @@ function createRootAdopter(deps) {
|
|
|
59934
60123
|
};
|
|
59935
60124
|
}
|
|
59936
60125
|
|
|
60126
|
+
// src/health-sentinel.ts
|
|
60127
|
+
function numEnv4(key, fallback) {
|
|
60128
|
+
const n = Number(process.env[key]);
|
|
60129
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
60130
|
+
}
|
|
60131
|
+
var SENTINEL_TICK_MS = numEnv4("ERRATA_SENTINEL_TICK_MS", 3e4);
|
|
60132
|
+
var SENTINEL_WINDOW_TICKS = numEnv4("ERRATA_SENTINEL_WINDOW_TICKS", 6);
|
|
60133
|
+
var SENTINEL_BURN_CORES = numEnv4("ERRATA_SENTINEL_BURN_CORES", 1.2);
|
|
60134
|
+
var SENTINEL_STORM_RATE = numEnv4("ERRATA_SENTINEL_STORM_RATE", 1e3);
|
|
60135
|
+
var SENTINEL_STORM_TICKS = numEnv4("ERRATA_SENTINEL_STORM_TICKS", 4);
|
|
60136
|
+
var SENTINEL_RENOTIFY_MS = numEnv4("ERRATA_SENTINEL_RENOTIFY_MS", 18e5);
|
|
60137
|
+
var SENTINEL_CALM_TICKS = numEnv4("ERRATA_SENTINEL_CALM_TICKS", 2);
|
|
60138
|
+
var SENTINEL_TOAST_COOLDOWN_MS = numEnv4("ERRATA_SENTINEL_TOAST_COOLDOWN_MS", 6e5);
|
|
60139
|
+
function createHealthSentinel(deps = {}) {
|
|
60140
|
+
const now = deps.now ?? Date.now;
|
|
60141
|
+
const cpuUsage = deps.cpuUsage ?? (() => process.cpuUsage());
|
|
60142
|
+
const readCensus = deps.readCensus ?? (() => {
|
|
60143
|
+
const c = watchCensus();
|
|
60144
|
+
return {
|
|
60145
|
+
dispatched: c.dispatched,
|
|
60146
|
+
logged: c.logged,
|
|
60147
|
+
topOffender: c.topOffender ? { path: c.topOffender.path, count: c.topOffender.count } : null
|
|
60148
|
+
};
|
|
60149
|
+
});
|
|
60150
|
+
const activePasses = deps.activePasses ?? (() => passState().active.map((p) => p.name));
|
|
60151
|
+
const rssMb = deps.rssMb ?? (() => Math.round(process.memoryUsage.rss() / 1048576));
|
|
60152
|
+
const toast = deps.notify ?? ((body2, key) => notifyOpsEvent("daemon-distress", body2, { key }));
|
|
60153
|
+
let prevCpu = cpuUsage();
|
|
60154
|
+
let prevTs = now();
|
|
60155
|
+
let prevDispatched = null;
|
|
60156
|
+
let prevLogged = 0;
|
|
60157
|
+
const coreSamples = [];
|
|
60158
|
+
let stormTicks = 0;
|
|
60159
|
+
let calmTicks = 0;
|
|
60160
|
+
let distress = null;
|
|
60161
|
+
let lastNotifiedAt = 0;
|
|
60162
|
+
const lastToastByKind = /* @__PURE__ */ new Map();
|
|
60163
|
+
const attribution = () => {
|
|
60164
|
+
const parts2 = [];
|
|
60165
|
+
const passes = activePasses();
|
|
60166
|
+
if (passes.length > 0) parts2.push(`active pass: ${passes.join(", ")}`);
|
|
60167
|
+
const c = readCensus();
|
|
60168
|
+
if (c.topOffender) parts2.push(`hottest watch path: ${c.topOffender.path}`);
|
|
60169
|
+
parts2.push(`rss ${rssMb()}MB`);
|
|
60170
|
+
return parts2.join(" \xB7 ");
|
|
60171
|
+
};
|
|
60172
|
+
const maybeToast = (d, t) => {
|
|
60173
|
+
if (t - (lastToastByKind.get(d.kind) ?? 0) < SENTINEL_TOAST_COOLDOWN_MS) return;
|
|
60174
|
+
lastToastByKind.set(d.kind, t);
|
|
60175
|
+
toast(d.headline, d.kind);
|
|
60176
|
+
lastNotifiedAt = t;
|
|
60177
|
+
};
|
|
60178
|
+
const transition = (next) => {
|
|
60179
|
+
const t = now();
|
|
60180
|
+
if (next && !distress) {
|
|
60181
|
+
distress = next;
|
|
60182
|
+
deps.ledger?.("enter", next);
|
|
60183
|
+
maybeToast(next, t);
|
|
60184
|
+
deps.onChange?.(next);
|
|
60185
|
+
} else if (next && distress) {
|
|
60186
|
+
distress.body = next.body;
|
|
60187
|
+
distress.headline = next.headline;
|
|
60188
|
+
if (t - lastNotifiedAt >= SENTINEL_RENOTIFY_MS) maybeToast(distress, t);
|
|
60189
|
+
} else if (!next && distress) {
|
|
60190
|
+
deps.ledger?.("clear", distress);
|
|
60191
|
+
distress = null;
|
|
60192
|
+
deps.onChange?.(null);
|
|
60193
|
+
}
|
|
60194
|
+
};
|
|
60195
|
+
const evaluate = () => {
|
|
60196
|
+
const t = now();
|
|
60197
|
+
const wallMs = Math.max(1, t - prevTs);
|
|
60198
|
+
const cpu = cpuUsage();
|
|
60199
|
+
const cores = (cpu.user + cpu.system - prevCpu.user - prevCpu.system) / 1e3 / wallMs;
|
|
60200
|
+
prevCpu = cpu;
|
|
60201
|
+
prevTs = t;
|
|
60202
|
+
coreSamples.push(cores);
|
|
60203
|
+
if (coreSamples.length > SENTINEL_WINDOW_TICKS) coreSamples.shift();
|
|
60204
|
+
const c = readCensus();
|
|
60205
|
+
const dispatchRate = prevDispatched === null ? 0 : (c.dispatched - prevDispatched) / wallMs * 1e3;
|
|
60206
|
+
const survived = c.logged - prevLogged;
|
|
60207
|
+
prevDispatched = c.dispatched;
|
|
60208
|
+
prevLogged = c.logged;
|
|
60209
|
+
stormTicks = dispatchRate > SENTINEL_STORM_RATE && survived === 0 ? stormTicks + 1 : 0;
|
|
60210
|
+
let wanted = null;
|
|
60211
|
+
if (stormTicks >= SENTINEL_STORM_TICKS) {
|
|
60212
|
+
wanted = {
|
|
60213
|
+
kind: "watch-storm",
|
|
60214
|
+
headline: `errata's file watcher is stuck busy (~${Math.round(dispatchRate)} events/sec with nothing changing) \u2014 run \`errata status\` for detail`,
|
|
60215
|
+
body: `filesystem watcher is processing ~${Math.round(dispatchRate)} events/sec with NOTHING surviving \u2014 a wedged or ignored-tree watch is burning CPU for no signal \xB7 ${attribution()}`,
|
|
60216
|
+
sinceTs: distress?.kind === "watch-storm" ? distress.sinceTs : t
|
|
60217
|
+
};
|
|
60218
|
+
} else {
|
|
60219
|
+
const windowFull = coreSamples.length >= SENTINEL_WINDOW_TICKS;
|
|
60220
|
+
const avgCores = coreSamples.reduce((a, b) => a + b, 0) / Math.max(1, coreSamples.length);
|
|
60221
|
+
if (windowFull && avgCores >= SENTINEL_BURN_CORES && cores >= SENTINEL_BURN_CORES && activePasses().length === 0) {
|
|
60222
|
+
wanted = {
|
|
60223
|
+
kind: "cpu-burn",
|
|
60224
|
+
headline: `errata is using more CPU than expected (${avgCores.toFixed(1)} cores with no work running) \u2014 run \`errata status\` for detail`,
|
|
60225
|
+
body: `sustained CPU with no pass running \u2014 avg ${avgCores.toFixed(1)} cores \xB7 ${attribution()}`,
|
|
60226
|
+
sinceTs: distress?.kind === "cpu-burn" ? distress.sinceTs : t
|
|
60227
|
+
};
|
|
60228
|
+
}
|
|
60229
|
+
}
|
|
60230
|
+
if (wanted) {
|
|
60231
|
+
calmTicks = 0;
|
|
60232
|
+
transition(wanted);
|
|
60233
|
+
} else if (distress) {
|
|
60234
|
+
calmTicks++;
|
|
60235
|
+
if (calmTicks >= SENTINEL_CALM_TICKS) {
|
|
60236
|
+
calmTicks = 0;
|
|
60237
|
+
transition(null);
|
|
60238
|
+
}
|
|
60239
|
+
}
|
|
60240
|
+
};
|
|
60241
|
+
const interval = deps.scheduleTicks === false ? null : setInterval(() => {
|
|
60242
|
+
try {
|
|
60243
|
+
evaluate();
|
|
60244
|
+
} catch {
|
|
60245
|
+
}
|
|
60246
|
+
}, SENTINEL_TICK_MS);
|
|
60247
|
+
interval?.unref?.();
|
|
60248
|
+
return {
|
|
60249
|
+
current: () => distress ? { ...distress } : null,
|
|
60250
|
+
tick: evaluate,
|
|
60251
|
+
stop: () => {
|
|
60252
|
+
if (interval) clearInterval(interval);
|
|
60253
|
+
}
|
|
60254
|
+
};
|
|
60255
|
+
}
|
|
60256
|
+
|
|
59937
60257
|
// src/multi.ts
|
|
59938
60258
|
var projectSymbolSalts = /* @__PURE__ */ new Map();
|
|
59939
60259
|
async function resolveProjectSymbolSalt(client, projectId) {
|
|
@@ -60078,6 +60398,20 @@ async function startMultiDaemon(opts = {}) {
|
|
|
60078
60398
|
for (const r of records) r.engine.markContextDirty();
|
|
60079
60399
|
}
|
|
60080
60400
|
}) : null;
|
|
60401
|
+
const healthSentinel = createHealthSentinel({
|
|
60402
|
+
onChange: () => {
|
|
60403
|
+
for (const r of records) r.engine.markContextDirty();
|
|
60404
|
+
},
|
|
60405
|
+
ledger: (event, d) => {
|
|
60406
|
+
const dir = records[0]?.engine.paths.configDir;
|
|
60407
|
+
if (dir) {
|
|
60408
|
+
appendPassLedger(dir, "health-sentinel", 0, {
|
|
60409
|
+
[`distress:${event}:${d.kind}`]: 1,
|
|
60410
|
+
distressSinceTs: d.sinceTs
|
|
60411
|
+
});
|
|
60412
|
+
}
|
|
60413
|
+
}
|
|
60414
|
+
});
|
|
60081
60415
|
let serverPending = null;
|
|
60082
60416
|
const boundaryListeners = [];
|
|
60083
60417
|
let boundaryFlushing = false;
|
|
@@ -60172,6 +60506,10 @@ async function startMultiDaemon(opts = {}) {
|
|
|
60172
60506
|
reviewUrl: () => `${baseUrl}/ws/${id}/review`,
|
|
60173
60507
|
sharedStore,
|
|
60174
60508
|
pendingUpdate: () => serverPending ?? updatePoller?.current() ?? null,
|
|
60509
|
+
// Ops-gated (default OFF): the 🚨 notice reads as "errata broke my
|
|
60510
|
+
// machine" to a non-operator. Detection + ledger run regardless — only
|
|
60511
|
+
// this push surface (and the toast, gated in notifyOpsEvent) is scoped.
|
|
60512
|
+
daemonDistress: () => loadConfig().opsNotices ? healthSentinel.current() : null,
|
|
60175
60513
|
...opts.skipWatchers ? { skipWatchers: true } : {}
|
|
60176
60514
|
});
|
|
60177
60515
|
const webApp = buildWebUi({
|
|
@@ -60260,7 +60598,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
60260
60598
|
registerWorkspace(rec.engine.profile, rec.root);
|
|
60261
60599
|
} catch {
|
|
60262
60600
|
}
|
|
60263
|
-
void rec.engine.reindex({ skipEmbed: true }).catch(() => {
|
|
60601
|
+
void rec.engine.reindex({ skipEmbed: true, quiet: rec.engine.store.nodeCount() > 0 }).catch(() => {
|
|
60264
60602
|
});
|
|
60265
60603
|
console.log(`[errata] hot-registered ${rec.entry.name} (${rec.id}) \u2014 now watching live`);
|
|
60266
60604
|
return { attached: true, id: rec.id };
|
|
@@ -61178,6 +61516,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
61178
61516
|
(res) => server.close(res)
|
|
61179
61517
|
);
|
|
61180
61518
|
updatePoller?.stop();
|
|
61519
|
+
healthSentinel.stop();
|
|
61181
61520
|
for (const r of records) await r.engine.stop();
|
|
61182
61521
|
if (consolidateWorker) await consolidateWorker.stop();
|
|
61183
61522
|
try {
|
|
@@ -61933,7 +62272,7 @@ var DEFAULT_CONSOLIDATION_POLICY = {
|
|
|
61933
62272
|
quiescenceMs: 6e4
|
|
61934
62273
|
// sim preferred 60s over 90s (fresher, esp. heavy-code)
|
|
61935
62274
|
};
|
|
61936
|
-
function
|
|
62275
|
+
function numEnv5(env2, key, fallback) {
|
|
61937
62276
|
const raw2 = env2[key];
|
|
61938
62277
|
if (raw2 == null || raw2.trim() === "") return fallback;
|
|
61939
62278
|
const n = Number(raw2);
|
|
@@ -61941,12 +62280,12 @@ function numEnv3(env2, key, fallback) {
|
|
|
61941
62280
|
}
|
|
61942
62281
|
function consolidationPolicyFromEnv(env2 = process.env) {
|
|
61943
62282
|
return {
|
|
61944
|
-
baseFloorMs:
|
|
61945
|
-
dutyFactor:
|
|
61946
|
-
momentumThreshold:
|
|
61947
|
-
momentumRatio:
|
|
61948
|
-
momentumRatioCap:
|
|
61949
|
-
quiescenceMs:
|
|
62283
|
+
baseFloorMs: numEnv5(env2, "ERRATA_CONSOLIDATE_BASE_FLOOR_MS", DEFAULT_CONSOLIDATION_POLICY.baseFloorMs),
|
|
62284
|
+
dutyFactor: numEnv5(env2, "ERRATA_CONSOLIDATE_DUTY_FACTOR", DEFAULT_CONSOLIDATION_POLICY.dutyFactor),
|
|
62285
|
+
momentumThreshold: numEnv5(env2, "ERRATA_CONSOLIDATE_MOMENTUM", DEFAULT_CONSOLIDATION_POLICY.momentumThreshold),
|
|
62286
|
+
momentumRatio: numEnv5(env2, "ERRATA_CONSOLIDATE_MOMENTUM_RATIO", DEFAULT_CONSOLIDATION_POLICY.momentumRatio),
|
|
62287
|
+
momentumRatioCap: numEnv5(env2, "ERRATA_CONSOLIDATE_MOMENTUM_RATIO_CAP", DEFAULT_CONSOLIDATION_POLICY.momentumRatioCap),
|
|
62288
|
+
quiescenceMs: numEnv5(env2, "ERRATA_CONSOLIDATE_QUIESCENCE_MS", DEFAULT_CONSOLIDATION_POLICY.quiescenceMs)
|
|
61950
62289
|
};
|
|
61951
62290
|
}
|
|
61952
62291
|
function consolidationGapMs(lastPassMs, policy) {
|
|
@@ -62084,6 +62423,8 @@ async function main() {
|
|
|
62084
62423
|
return cmdConsent(rest);
|
|
62085
62424
|
case "notifications":
|
|
62086
62425
|
return cmdNotifications(rest[0] ?? "");
|
|
62426
|
+
case "ops-notices":
|
|
62427
|
+
return cmdOpsNotices(rest[0] ?? "");
|
|
62087
62428
|
case "update":
|
|
62088
62429
|
return cmdUpdate(rest);
|
|
62089
62430
|
case "projects":
|
|
@@ -62207,6 +62548,9 @@ Commands:
|
|
|
62207
62548
|
Send scrubbed feedback to the maintainers (needs login)
|
|
62208
62549
|
notifications <on|off>
|
|
62209
62550
|
Desktop toasts on problem open/resolve + review ready
|
|
62551
|
+
ops-notices <on|off>
|
|
62552
|
+
Ops-grade health surfaces (daemon-distress toast + agent
|
|
62553
|
+
notice). Default off; for people operating errata itself
|
|
62210
62554
|
|
|
62211
62555
|
Environment:
|
|
62212
62556
|
ERRATA_CLOUD_URL Cloud base URL (default ${DEFAULT_CLOUD_URL})
|
|
@@ -64732,6 +65076,19 @@ async function cmdNotifications(state) {
|
|
|
64732
65076
|
saveConfig(cfg);
|
|
64733
65077
|
console.log(`desktop notifications ${cfg.notifications ? "enabled" : "disabled"}`);
|
|
64734
65078
|
}
|
|
65079
|
+
async function cmdOpsNotices(state) {
|
|
65080
|
+
const s = state.toLowerCase();
|
|
65081
|
+
if (s !== "on" && s !== "off") {
|
|
65082
|
+
console.error("usage: errata ops-notices <on|off>");
|
|
65083
|
+
process.exit(2);
|
|
65084
|
+
}
|
|
65085
|
+
const cfg = loadConfig();
|
|
65086
|
+
cfg.opsNotices = s === "on";
|
|
65087
|
+
saveConfig(cfg);
|
|
65088
|
+
console.log(
|
|
65089
|
+
`ops health notices ${cfg.opsNotices ? "enabled \u2014 distress conditions will toast and reach the agent context" : "disabled \u2014 detection and `errata status` still run"}`
|
|
65090
|
+
);
|
|
65091
|
+
}
|
|
64735
65092
|
async function cmdFeedback(args2) {
|
|
64736
65093
|
const cfg = loadConfig();
|
|
64737
65094
|
if (!hasCloudCredential(cfg)) {
|