@inerrata-corporation/errata 2.0.2-dev.276 → 2.0.2-dev.288
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 +370 -109
- package/package.json +1 -1
package/errata.mjs
CHANGED
|
@@ -20500,6 +20500,56 @@ function induceTriage(l2, opts) {
|
|
|
20500
20500
|
}
|
|
20501
20501
|
return report;
|
|
20502
20502
|
}
|
|
20503
|
+
function pendingDiscriminators(l2, opts = {}) {
|
|
20504
|
+
const minSources = opts.minSources ?? 1;
|
|
20505
|
+
const minObservations = opts.minObservations ?? 2;
|
|
20506
|
+
const out2 = [];
|
|
20507
|
+
for (const triage of l2.findNodesByLabel("Triage")) {
|
|
20508
|
+
for (const e of l2.outEdges(triage.id, [...ROUTE_EDGE_TYPES])) {
|
|
20509
|
+
if (isRouterRoute(e)) continue;
|
|
20510
|
+
if (typeof e.attrs["discriminator"] === "string") continue;
|
|
20511
|
+
if (opts.onlyUnsurfaced && e.attrs["discriminatorAsked"] === true) continue;
|
|
20512
|
+
const perContext = e.attrs["perContext"] ?? {};
|
|
20513
|
+
const global2 = perContext[TRIAGE_GLOBAL_BUCKET] ?? {};
|
|
20514
|
+
const observations = Number(global2.confirmed ?? 0);
|
|
20515
|
+
const sources = new Set(global2.contributors ?? []).size;
|
|
20516
|
+
if (sources < minSources || observations < minObservations) continue;
|
|
20517
|
+
out2.push({ route: e.id, presenting: triage.description, cause: "", sources, observations, causeId: e.to });
|
|
20518
|
+
}
|
|
20519
|
+
}
|
|
20520
|
+
out2.sort((a, b) => b.sources - a.sources || b.observations - a.observations);
|
|
20521
|
+
const top = typeof opts.limit === "number" ? out2.slice(0, opts.limit) : out2;
|
|
20522
|
+
for (const p of top) p.cause = l2.getNode(p.causeId)?.description ?? "(missing cause)";
|
|
20523
|
+
return top;
|
|
20524
|
+
}
|
|
20525
|
+
function markDiscriminatorAsked(l2, routeIds, ts) {
|
|
20526
|
+
for (const id of routeIds) {
|
|
20527
|
+
const e = l2.getEdge(id);
|
|
20528
|
+
if (!e) continue;
|
|
20529
|
+
l2.updateEdge(id, { attrs: { ...e.attrs, discriminatorAsked: true }, lastSeenAt: ts });
|
|
20530
|
+
}
|
|
20531
|
+
}
|
|
20532
|
+
function promoteRouteWithDiscriminator(l2, routeId, discriminator, ts, source) {
|
|
20533
|
+
const test = discriminator.trim();
|
|
20534
|
+
if (!test) return false;
|
|
20535
|
+
const existing = l2.getEdge(routeId);
|
|
20536
|
+
if (!existing || !ROUTE_EDGE_TYPES.includes(existing.type)) return false;
|
|
20537
|
+
const attrs = {
|
|
20538
|
+
...existing.attrs,
|
|
20539
|
+
discriminator: test,
|
|
20540
|
+
provisional: false,
|
|
20541
|
+
...source ? { discriminatorSource: source } : {}
|
|
20542
|
+
};
|
|
20543
|
+
delete attrs["discriminatorAsked"];
|
|
20544
|
+
const wantType = routeTypeFor(false);
|
|
20545
|
+
if (existing.type === wantType) {
|
|
20546
|
+
l2.updateEdge(routeId, { attrs, lastSeenAt: ts });
|
|
20547
|
+
return true;
|
|
20548
|
+
}
|
|
20549
|
+
l2.deleteEdge(routeId);
|
|
20550
|
+
l2.mergeEdge({ ...existing, type: wantType, attrs, lastSeenAt: ts });
|
|
20551
|
+
return true;
|
|
20552
|
+
}
|
|
20503
20553
|
function revisitStaleRoutes(l2, ts, opts = {}) {
|
|
20504
20554
|
const minNavFailures = opts.minNavFailures ?? 3;
|
|
20505
20555
|
const report = { flagged: 0, demoted: 0 };
|
|
@@ -20560,15 +20610,20 @@ function parseTriageFences(text) {
|
|
|
20560
20610
|
while ((m = block.exec(text)) !== null) {
|
|
20561
20611
|
const fields = {};
|
|
20562
20612
|
for (const line of m[1].split(/\r?\n/)) {
|
|
20563
|
-
const kv = /^\s*(presenting|cause|test|fix|drift)\s*:\s*(.+?)\s*$/i.exec(line);
|
|
20613
|
+
const kv = /^\s*(presenting|cause|test|fix|drift|route)\s*:\s*(.+?)\s*$/i.exec(line);
|
|
20564
20614
|
if (kv) fields[kv[1].toLowerCase()] = kv[2].trim();
|
|
20565
20615
|
}
|
|
20616
|
+
if (fields["route"] && fields["test"]) {
|
|
20617
|
+
out2.push({ presenting: "", cause: "", route: fields["route"], test: fields["test"] });
|
|
20618
|
+
continue;
|
|
20619
|
+
}
|
|
20566
20620
|
if (!fields["presenting"] || !fields["cause"]) continue;
|
|
20567
20621
|
const drift = fields["drift"]?.toLowerCase();
|
|
20568
20622
|
out2.push({
|
|
20569
20623
|
presenting: fields["presenting"],
|
|
20570
20624
|
cause: fields["cause"],
|
|
20571
20625
|
...fields["test"] ? { test: fields["test"] } : {},
|
|
20626
|
+
...fields["route"] ? { route: fields["route"] } : {},
|
|
20572
20627
|
...fields["fix"] ? { fix: fields["fix"] } : {},
|
|
20573
20628
|
...drift && DRIFT_VALUES.has(drift) ? { drift } : {}
|
|
20574
20629
|
});
|
|
@@ -20577,7 +20632,12 @@ function parseTriageFences(text) {
|
|
|
20577
20632
|
}
|
|
20578
20633
|
function harvestTriageFences(l2, text, opts) {
|
|
20579
20634
|
let recorded = 0;
|
|
20635
|
+
let promoted = 0;
|
|
20580
20636
|
for (const f of parseTriageFences(text)) {
|
|
20637
|
+
if (f.route && f.test) {
|
|
20638
|
+
if (promoteRouteWithDiscriminator(l2, f.route.trim(), f.test, opts.ts, opts.contributor)) promoted++;
|
|
20639
|
+
continue;
|
|
20640
|
+
}
|
|
20581
20641
|
const cause = f.cause.trim();
|
|
20582
20642
|
const causeId = `dcause_${digest({ statement: cause })}`.slice(0, 56);
|
|
20583
20643
|
recordTriageObservation(
|
|
@@ -20608,7 +20668,7 @@ function harvestTriageFences(l2, text, opts) {
|
|
|
20608
20668
|
}
|
|
20609
20669
|
recorded++;
|
|
20610
20670
|
}
|
|
20611
|
-
return { recorded };
|
|
20671
|
+
return { recorded, promoted };
|
|
20612
20672
|
}
|
|
20613
20673
|
var COOCCUR_BONUS, routeEdgeId, ROUTE_EDGE_TYPES, routeTypeFor, isRouterRoute, INDUCTED_MARK, DRIFT_VALUES;
|
|
20614
20674
|
var init_triage2 = __esm({
|
|
@@ -20981,6 +21041,7 @@ __export(src_exports2, {
|
|
|
20981
21041
|
linkProblemToSymbols: () => linkProblemToSymbols,
|
|
20982
21042
|
listNeedsRevisit: () => listNeedsRevisit,
|
|
20983
21043
|
localEdgeViolation: () => localEdgeViolation,
|
|
21044
|
+
markDiscriminatorAsked: () => markDiscriminatorAsked,
|
|
20984
21045
|
markRevisit: () => markRevisit,
|
|
20985
21046
|
matchLanguagesInText: () => matchLanguagesInText,
|
|
20986
21047
|
matchPackagesInText: () => matchPackagesInText,
|
|
@@ -20997,8 +21058,10 @@ __export(src_exports2, {
|
|
|
20997
21058
|
parseSemver: () => parseSemver,
|
|
20998
21059
|
parseTriageFences: () => parseTriageFences,
|
|
20999
21060
|
pendingAbstractions: () => pendingAbstractions,
|
|
21061
|
+
pendingDiscriminators: () => pendingDiscriminators,
|
|
21000
21062
|
percolate: () => percolate,
|
|
21001
21063
|
priorsForFile: () => priorsForFile,
|
|
21064
|
+
promoteRouteWithDiscriminator: () => promoteRouteWithDiscriminator,
|
|
21002
21065
|
propagateFactChange: () => propagateFactChange,
|
|
21003
21066
|
propagateVersionChange: () => propagateVersionChange,
|
|
21004
21067
|
rankToolsForHandles: () => rankToolsForHandles,
|
|
@@ -21411,15 +21474,24 @@ function dropLowestUnit(s) {
|
|
|
21411
21474
|
case "skills":
|
|
21412
21475
|
if (s.skills.length) return s.skills.pop(), true;
|
|
21413
21476
|
break;
|
|
21477
|
+
case "motifsOverFloor":
|
|
21478
|
+
if (s.motifs.length > MOTIF_FLOOR) return s.motifs.pop(), true;
|
|
21479
|
+
break;
|
|
21414
21480
|
case "motifs":
|
|
21415
21481
|
if (s.motifs.length) return s.motifs.pop(), true;
|
|
21416
21482
|
break;
|
|
21417
21483
|
case "workingFile":
|
|
21418
21484
|
if (s.workingFile) return delete s.workingFile, true;
|
|
21419
21485
|
break;
|
|
21486
|
+
case "remoteOverFloor":
|
|
21487
|
+
if (s.remote && s.remote.length > REMOTE_FLOOR) return s.remote.pop(), true;
|
|
21488
|
+
break;
|
|
21420
21489
|
case "remote":
|
|
21421
21490
|
if (s.remote && s.remote.length) return s.remote.pop(), true;
|
|
21422
21491
|
break;
|
|
21492
|
+
case "recentProblemsOverFloor":
|
|
21493
|
+
if (s.recentProblems.length > PROBLEM_FLOOR) return s.recentProblems.pop(), true;
|
|
21494
|
+
break;
|
|
21423
21495
|
case "recentResolved":
|
|
21424
21496
|
if (s.recentResolved.length) return s.recentResolved.pop(), true;
|
|
21425
21497
|
break;
|
|
@@ -21478,7 +21550,7 @@ _${dropped} lower-priority item${dropped === 1 ? "" : "s"} omitted to fit the pa
|
|
|
21478
21550
|
}
|
|
21479
21551
|
return { body: body2, snapshot, dropped };
|
|
21480
21552
|
}
|
|
21481
|
-
var RECALL_FIRST_HEADER, RECALL_FIRST_BODY, RECALL_FIRST_BLOCK, SEARCH_IMPERATIVE_HEADER, SEARCH_IMPERATIVE_BODY, EVICTION_ORDER, DEFAULT_AGENT_CONTEXT_BUDGET;
|
|
21553
|
+
var RECALL_FIRST_HEADER, RECALL_FIRST_BODY, RECALL_FIRST_BLOCK, SEARCH_IMPERATIVE_HEADER, SEARCH_IMPERATIVE_BODY, EVICTION_ORDER, MOTIF_FLOOR, REMOTE_FLOOR, PROBLEM_FLOOR, DEFAULT_AGENT_CONTEXT_BUDGET;
|
|
21482
21554
|
var init_render = __esm({
|
|
21483
21555
|
"../../packages/context-writer/src/render.ts"() {
|
|
21484
21556
|
"use strict";
|
|
@@ -21493,9 +21565,19 @@ ${RECALL_FIRST_BODY}`;
|
|
|
21493
21565
|
SEARCH_IMPERATIVE_BODY = "Everything below is a budgeted, top-of-head slice of a much larger graph. Any prior id below is a live burst seed: `errata.burst` it (or read `.errata/g/burst/<id>`) to pull its wider neighborhood \u2014 causes, fixes, siblings. When a prior is adjacent-but-not-quite, or none fit, that gap is exactly when to search deeper before solving cold: a stuck search is itself a signal that routes help to you.";
|
|
21494
21566
|
EVICTION_ORDER = [
|
|
21495
21567
|
"skills",
|
|
21496
|
-
|
|
21568
|
+
// Collective floors (EE-evidence-live): motifs/remote trim to a FLOOR here and
|
|
21569
|
+
// fully drain only near the very end. The unfloored order zeroed them on every
|
|
21570
|
+
// render (~44 units dropped per block, live 8-01), which starved §5.4 at the
|
|
21571
|
+
// source: every witness channel (corroborate/refute) fires only on a prior the
|
|
21572
|
+
// agent was SHOWN, the self-gate correctly refuses same-session cites, so a
|
|
21573
|
+
// surface showing ONLY the session's own problems produces zero evidence by
|
|
21574
|
+
// construction — corroborationCount was 0 across all 1,785 cloud nodes while
|
|
21575
|
+
// the transport, parser and gate all worked. Same shape as the needsRevisit
|
|
21576
|
+
// inversion below: the budget optimized one objective and silently killed
|
|
21577
|
+
// another channel's entire input.
|
|
21578
|
+
"motifsOverFloor",
|
|
21497
21579
|
"workingFile",
|
|
21498
|
-
"
|
|
21580
|
+
"remoteOverFloor",
|
|
21499
21581
|
// Resolved priors are jumping-off points, not live defects — under a tight
|
|
21500
21582
|
// budget they drop before anything open/actionable.
|
|
21501
21583
|
"recentResolved",
|
|
@@ -21512,8 +21594,17 @@ ${RECALL_FIRST_BODY}`;
|
|
|
21512
21594
|
// about something ALREADY closed; a live prior is the substrate every link verb
|
|
21513
21595
|
// needs. Problems outrank it now.
|
|
21514
21596
|
"needsRevisit",
|
|
21597
|
+
// Problems trim to a floor before the collective floors give way: a starved
|
|
21598
|
+
// budget keeps a few of BOTH (own problems to act on, cross-session priors to
|
|
21599
|
+
// witness against) rather than all of one and none of the other.
|
|
21600
|
+
"recentProblemsOverFloor",
|
|
21601
|
+
"motifs",
|
|
21602
|
+
"remote",
|
|
21515
21603
|
"recentProblems"
|
|
21516
21604
|
];
|
|
21605
|
+
MOTIF_FLOOR = 2;
|
|
21606
|
+
REMOTE_FLOOR = 3;
|
|
21607
|
+
PROBLEM_FLOOR = 4;
|
|
21517
21608
|
DEFAULT_AGENT_CONTEXT_BUDGET = 9e3;
|
|
21518
21609
|
}
|
|
21519
21610
|
});
|
|
@@ -36969,6 +37060,36 @@ function takeEnrichmentNudge(store) {
|
|
|
36969
37060
|
return `\u26A1 errata \u2014 ${pulls.length} recent fix(es) await a one-line root cause (optional, answer in-flow):
|
|
36970
37061
|
` + items;
|
|
36971
37062
|
}
|
|
37063
|
+
function takeDiscriminatorNudge(path2) {
|
|
37064
|
+
if (!path2 || !existsSync10(path2)) return null;
|
|
37065
|
+
let shared;
|
|
37066
|
+
try {
|
|
37067
|
+
shared = openGraphStore({ path: path2 });
|
|
37068
|
+
} catch {
|
|
37069
|
+
return null;
|
|
37070
|
+
}
|
|
37071
|
+
try {
|
|
37072
|
+
const pending = pendingDiscriminators(shared, { limit: 1, onlyUnsurfaced: true });
|
|
37073
|
+
const top = pending[0];
|
|
37074
|
+
if (!top) return null;
|
|
37075
|
+
markDiscriminatorAsked(shared, [top.route], Date.now());
|
|
37076
|
+
return [
|
|
37077
|
+
`\u26A1 errata \u2014 a known wrong-door is one field from ranking: "${top.presenting.slice(0, 90)}"`,
|
|
37078
|
+
` usually turns out to be: ${top.cause.slice(0, 90)} (seen ${top.observations}x)`,
|
|
37079
|
+
" Know a CHEAP check that confirms it? Answer in-flow \u2014 it promotes the route so the",
|
|
37080
|
+
" next agent gets it first. Only if you actually know one: a guessed test ranks first",
|
|
37081
|
+
" and misroutes everyone after you.",
|
|
37082
|
+
" ```errata-triage",
|
|
37083
|
+
` route: ${top.route}`,
|
|
37084
|
+
" test: <the cheap check>",
|
|
37085
|
+
" ```"
|
|
37086
|
+
].join("\n");
|
|
37087
|
+
} catch {
|
|
37088
|
+
return null;
|
|
37089
|
+
} finally {
|
|
37090
|
+
shared.close();
|
|
37091
|
+
}
|
|
37092
|
+
}
|
|
36972
37093
|
function commentAnchorId(store, commentId) {
|
|
36973
37094
|
const out2 = store.outEdges(commentId, ["EXPLAINS", "ANNOTATES"]);
|
|
36974
37095
|
if (out2.length > 0) return out2[0].to;
|
|
@@ -37176,6 +37297,7 @@ function createMcpHandler(store, ctx = {}) {
|
|
|
37176
37297
|
let auditReadRun = 0;
|
|
37177
37298
|
let toolCallIndex = 0;
|
|
37178
37299
|
let lastAuditNudgeAt = Number.NEGATIVE_INFINITY;
|
|
37300
|
+
let lastDiscriminatorNudgeAt = Number.NEGATIVE_INFINITY;
|
|
37179
37301
|
return async function handle2(req) {
|
|
37180
37302
|
const id = req.id ?? null;
|
|
37181
37303
|
const isNotification = req.id === void 0;
|
|
@@ -37222,6 +37344,7 @@ function createMcpHandler(store, ctx = {}) {
|
|
|
37222
37344
|
{ type: "text", text: JSON.stringify(out2, null, 2) }
|
|
37223
37345
|
];
|
|
37224
37346
|
const isEnrichmentTool = params.name === "errata.pending_enrichment" || params.name === "errata.annotate_resolution";
|
|
37347
|
+
const isTriageTool = params.name === "errata.pending_discriminators" || params.name === "errata.triage";
|
|
37225
37348
|
toolCallIndex++;
|
|
37226
37349
|
auditReadRun = isEnrichmentTool ? 0 : auditReadRun + 1;
|
|
37227
37350
|
if (!isEnrichmentTool) {
|
|
@@ -37233,6 +37356,13 @@ function createMcpHandler(store, ctx = {}) {
|
|
|
37233
37356
|
lastAuditNudgeAt = toolCallIndex;
|
|
37234
37357
|
auditReadRun = 0;
|
|
37235
37358
|
}
|
|
37359
|
+
if (!isTriageTool && content.length === 1 && toolCallIndex - lastDiscriminatorNudgeAt >= DISCRIMINATOR_NUDGE_COOLDOWN) {
|
|
37360
|
+
const disc = takeDiscriminatorNudge(ctx.sharedDbPath);
|
|
37361
|
+
if (disc) {
|
|
37362
|
+
content.push({ type: "text", text: disc });
|
|
37363
|
+
lastDiscriminatorNudgeAt = toolCallIndex;
|
|
37364
|
+
}
|
|
37365
|
+
}
|
|
37236
37366
|
return { jsonrpc: "2.0", id, result: { content } };
|
|
37237
37367
|
}
|
|
37238
37368
|
default:
|
|
@@ -37282,7 +37412,11 @@ async function runMcpServer(workspaceRoot) {
|
|
|
37282
37412
|
}
|
|
37283
37413
|
return summariesMemo.map;
|
|
37284
37414
|
};
|
|
37285
|
-
const handle2 = createMcpHandler(store, {
|
|
37415
|
+
const handle2 = createMcpHandler(store, {
|
|
37416
|
+
...buildToolContext(),
|
|
37417
|
+
symbolSummaries,
|
|
37418
|
+
sharedDbPath: sharedStorePath()
|
|
37419
|
+
});
|
|
37286
37420
|
process.stdin.setEncoding("utf8");
|
|
37287
37421
|
let buffer = "";
|
|
37288
37422
|
process.stdin.on("data", (chunk) => {
|
|
@@ -37310,7 +37444,7 @@ async function runMcpServer(workspaceRoot) {
|
|
|
37310
37444
|
if (resp) process.stdout.write(JSON.stringify(resp) + "\n");
|
|
37311
37445
|
}
|
|
37312
37446
|
}
|
|
37313
|
-
var INSTRUCTIONS, AUDIT_RUN_THRESHOLD, AUDIT_NUDGE_COOLDOWN, AUDIT_FLAG_NUDGE, TOOLS;
|
|
37447
|
+
var INSTRUCTIONS, AUDIT_RUN_THRESHOLD, AUDIT_NUDGE_COOLDOWN, DISCRIMINATOR_NUDGE_COOLDOWN, AUDIT_FLAG_NUDGE, TOOLS;
|
|
37314
37448
|
var init_mcp = __esm({
|
|
37315
37449
|
"src/mcp.ts"() {
|
|
37316
37450
|
"use strict";
|
|
@@ -37371,6 +37505,7 @@ var init_mcp = __esm({
|
|
|
37371
37505
|
].join("\n");
|
|
37372
37506
|
AUDIT_RUN_THRESHOLD = 5;
|
|
37373
37507
|
AUDIT_NUDGE_COOLDOWN = 12;
|
|
37508
|
+
DISCRIMINATOR_NUDGE_COOLDOWN = 40;
|
|
37374
37509
|
AUDIT_FLAG_NUDGE = "\u26A1 errata \u2014 reading/auditing? anything you notice that's off, flag it inline as `[!one line]` (`[?\u2026]` = TODO) \u2014 no tool call, we harvest it.";
|
|
37375
37510
|
TOOLS = [
|
|
37376
37511
|
{
|
|
@@ -38396,6 +38531,47 @@ var init_mcp = __esm({
|
|
|
38396
38531
|
}
|
|
38397
38532
|
}
|
|
38398
38533
|
},
|
|
38534
|
+
{
|
|
38535
|
+
name: "errata.pending_discriminators",
|
|
38536
|
+
description: "Routes awaiting the ONE field that promotes them to routers (PLAN_TRIAGE). A route is a known wrong-door \u2014 symptom S usually turns out to be cause C \u2014 but it only ranks as a ROUTER once someone supplies its `discriminator`: the cheap ante-hoc test that confirms C before you commit. Returns provisional routes corroborated by 2+ DISTINCT CONTRIBUTORS, most-corroborated first; these are one field away from ranking every future `errata.triage` on that symptom. Answer only where you actually know a cheap check \u2014 a guessed test is worse than none, because it ranks first and sends the next agent down it. Empty = nothing awaiting. Reads the machine-wide shared store.",
|
|
38537
|
+
inputSchema: {
|
|
38538
|
+
type: "object",
|
|
38539
|
+
properties: {
|
|
38540
|
+
limit: { type: "number", description: "Max routes to return (default 10)." },
|
|
38541
|
+
minSources: { type: "number", description: "Min distinct contributors behind the route (default 2)." }
|
|
38542
|
+
}
|
|
38543
|
+
},
|
|
38544
|
+
handler: (args2) => {
|
|
38545
|
+
const path2 = sharedStorePath();
|
|
38546
|
+
if (!existsSync10(path2)) return { count: 0, pending: [] };
|
|
38547
|
+
const shared = openGraphStore({ path: path2 });
|
|
38548
|
+
try {
|
|
38549
|
+
const pending = pendingDiscriminators(shared, {
|
|
38550
|
+
limit: typeof args2?.limit === "number" ? args2.limit : 10,
|
|
38551
|
+
...typeof args2?.minSources === "number" ? { minSources: args2.minSources } : {}
|
|
38552
|
+
});
|
|
38553
|
+
return {
|
|
38554
|
+
count: pending.length,
|
|
38555
|
+
pending,
|
|
38556
|
+
...pending.length > 0 ? {
|
|
38557
|
+
howToAnswer: [
|
|
38558
|
+
"For each route you know a cheap test for, emit an errata-triage fence",
|
|
38559
|
+
"carrying its `route` id and the `test` \u2014 no presenting/cause needed, the",
|
|
38560
|
+
"route id identifies both endpoints. Attaching a test does NOT count as",
|
|
38561
|
+
"another sighting, so it cannot inflate the route's evidence.",
|
|
38562
|
+
"",
|
|
38563
|
+
"```errata-triage",
|
|
38564
|
+
"route: <route id from above>",
|
|
38565
|
+
"test: <the cheap check that confirms this cause>",
|
|
38566
|
+
"```"
|
|
38567
|
+
].join("\n")
|
|
38568
|
+
} : {}
|
|
38569
|
+
};
|
|
38570
|
+
} finally {
|
|
38571
|
+
shared.close();
|
|
38572
|
+
}
|
|
38573
|
+
}
|
|
38574
|
+
},
|
|
38399
38575
|
{
|
|
38400
38576
|
name: "errata.triage",
|
|
38401
38577
|
description: "Before you chase a problem, TRIAGE it \u2014 is it a known wrong-door? (PLAN_TRIAGE). Pass the problem you're about to work on (`problem`: a one-line statement, or `id`: a dprob_\u2026 id) and YOUR context (`stack`, `domain`) so the probabilities are conditioned on it \u2014 a symptom routes to different causes on different stacks. Returns the differential: candidate causes ranked router-first then by context-conditioned probability \u2014 {route, cause:{description}, probability, sampleSize, trust, router, discriminator, solutions:[\u2026]}. `probability` is P(cause | symptom, your context); `trust`/`sampleSize` tell you how much evidence stands behind it. Run the top router's `discriminator` (a cheap check) before committing. Empty = not a known wrong-door. Reads the machine-wide shared store.",
|
|
@@ -46989,6 +47165,69 @@ var init_webui = __esm({
|
|
|
46989
47165
|
}
|
|
46990
47166
|
});
|
|
46991
47167
|
|
|
47168
|
+
// src/witness-ledger.ts
|
|
47169
|
+
var witness_ledger_exports = {};
|
|
47170
|
+
__export(witness_ledger_exports, {
|
|
47171
|
+
appendWitnessLedger: () => appendWitnessLedger,
|
|
47172
|
+
readWitnessLedger: () => readWitnessLedger,
|
|
47173
|
+
summarizeWitnessLedger: () => summarizeWitnessLedger,
|
|
47174
|
+
witnessLedgerPath: () => witnessLedgerPath
|
|
47175
|
+
});
|
|
47176
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync20, readFileSync as readFileSync20, writeFileSync as writeFileSync17 } from "node:fs";
|
|
47177
|
+
import { join as join25 } from "node:path";
|
|
47178
|
+
function witnessLedgerPath(configDir) {
|
|
47179
|
+
return join25(configDir, "witness-ledger.jsonl");
|
|
47180
|
+
}
|
|
47181
|
+
function appendWitnessLedger(configDir, entry) {
|
|
47182
|
+
const path2 = witnessLedgerPath(configDir);
|
|
47183
|
+
try {
|
|
47184
|
+
appendFileSync2(path2, JSON.stringify(entry) + "\n");
|
|
47185
|
+
const lines = readFileSync20(path2, "utf8").split("\n").filter(Boolean);
|
|
47186
|
+
if (lines.length > LEDGER_MAX_LINES) {
|
|
47187
|
+
writeFileSync17(path2, lines.slice(-Math.floor(LEDGER_MAX_LINES / 2)).join("\n") + "\n");
|
|
47188
|
+
}
|
|
47189
|
+
} catch {
|
|
47190
|
+
}
|
|
47191
|
+
}
|
|
47192
|
+
function readWitnessLedger(configDir) {
|
|
47193
|
+
const path2 = witnessLedgerPath(configDir);
|
|
47194
|
+
if (!existsSync20(path2)) return [];
|
|
47195
|
+
try {
|
|
47196
|
+
return readFileSync20(path2, "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l)).filter((e) => typeof e.ts === "number" && typeof e.channel === "string");
|
|
47197
|
+
} catch {
|
|
47198
|
+
return [];
|
|
47199
|
+
}
|
|
47200
|
+
}
|
|
47201
|
+
function summarizeWitnessLedger(configDir, nowMs) {
|
|
47202
|
+
const entries = readWitnessLedger(configDir);
|
|
47203
|
+
if (entries.length === 0) return [];
|
|
47204
|
+
const byChannel = /* @__PURE__ */ new Map();
|
|
47205
|
+
for (const e of entries) {
|
|
47206
|
+
const c = byChannel.get(e.channel) ?? { recorded: 0, selfSkipped: 0, selfGated: 0, unmatched: 0, lastTs: 0 };
|
|
47207
|
+
c.recorded += e.recorded ?? 0;
|
|
47208
|
+
c.selfSkipped += e.clientSelfSkipped ?? 0;
|
|
47209
|
+
c.selfGated += e.selfGated ?? 0;
|
|
47210
|
+
c.unmatched += e.unmatched ?? 0;
|
|
47211
|
+
c.lastTs = Math.max(c.lastTs, e.ts);
|
|
47212
|
+
byChannel.set(e.channel, c);
|
|
47213
|
+
}
|
|
47214
|
+
const out2 = [];
|
|
47215
|
+
for (const [channel, c] of byChannel) {
|
|
47216
|
+
const ageH = Math.round((nowMs - c.lastTs) / 36e5);
|
|
47217
|
+
out2.push(
|
|
47218
|
+
`${channel}: recorded ${c.recorded} \xB7 self-gated ${c.selfSkipped + c.selfGated} \xB7 unmatched ${c.unmatched} \xB7 last activity ${ageH}h ago`
|
|
47219
|
+
);
|
|
47220
|
+
}
|
|
47221
|
+
return out2;
|
|
47222
|
+
}
|
|
47223
|
+
var LEDGER_MAX_LINES;
|
|
47224
|
+
var init_witness_ledger = __esm({
|
|
47225
|
+
"src/witness-ledger.ts"() {
|
|
47226
|
+
"use strict";
|
|
47227
|
+
LEDGER_MAX_LINES = 500;
|
|
47228
|
+
}
|
|
47229
|
+
});
|
|
47230
|
+
|
|
46992
47231
|
// src/report-render.ts
|
|
46993
47232
|
var report_render_exports = {};
|
|
46994
47233
|
__export(report_render_exports, {
|
|
@@ -47380,12 +47619,12 @@ var init_report_render = __esm({
|
|
|
47380
47619
|
|
|
47381
47620
|
// src/cli.ts
|
|
47382
47621
|
init_src5();
|
|
47383
|
-
import { closeSync as closeSync2, existsSync as
|
|
47384
|
-
import { join as
|
|
47622
|
+
import { closeSync as closeSync2, existsSync as existsSync27, openSync as openSync2, readFileSync as readFileSync26, renameSync as renameSync4, statSync as statSync6 } from "node:fs";
|
|
47623
|
+
import { join as join30 } from "node:path";
|
|
47385
47624
|
import { spawn as spawn3 } from "node:child_process";
|
|
47386
47625
|
|
|
47387
47626
|
// src/daemon.ts
|
|
47388
|
-
import { existsSync as
|
|
47627
|
+
import { existsSync as existsSync22, writeFileSync as writeFileSync19 } from "node:fs";
|
|
47389
47628
|
|
|
47390
47629
|
// ../../node_modules/.pnpm/@hono+node-server@1.19.11_hono@4.12.8/node_modules/@hono/node-server/dist/index.mjs
|
|
47391
47630
|
import { createServer as createServerHTTP } from "http";
|
|
@@ -47965,8 +48204,8 @@ init_config();
|
|
|
47965
48204
|
|
|
47966
48205
|
// src/engine.ts
|
|
47967
48206
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
47968
|
-
import { existsSync as
|
|
47969
|
-
import { join as
|
|
48207
|
+
import { existsSync as existsSync21, statSync as statSync5, appendFileSync as appendFileSync3, readdirSync as readdirSync9, renameSync as renameSync3, readFileSync as readFileSync21, writeFileSync as writeFileSync18 } from "node:fs";
|
|
48208
|
+
import { join as join26, relative as relative6, sep as sep4 } from "node:path";
|
|
47970
48209
|
|
|
47971
48210
|
// ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
|
|
47972
48211
|
import { stat as statcb } from "fs";
|
|
@@ -52412,6 +52651,9 @@ function retireWitnesses(queue, channel, settledKeys) {
|
|
|
52412
52651
|
return queue.filter((w) => !(w.channel === channel && settledKeys.has(w.witnessKey)));
|
|
52413
52652
|
}
|
|
52414
52653
|
|
|
52654
|
+
// src/engine.ts
|
|
52655
|
+
init_witness_ledger();
|
|
52656
|
+
|
|
52415
52657
|
// src/causal.ts
|
|
52416
52658
|
var SUPPRESSORS = [
|
|
52417
52659
|
{ kind: "ts-nocheck", re: /@ts-nocheck\b/g },
|
|
@@ -52664,7 +52906,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
|
|
|
52664
52906
|
}
|
|
52665
52907
|
|
|
52666
52908
|
// src/engine.ts
|
|
52667
|
-
var DAEMON_VERSION = true ? "2.0.2-dev.
|
|
52909
|
+
var DAEMON_VERSION = true ? "2.0.2-dev.288" : "2.0.0-alpha.0";
|
|
52668
52910
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
52669
52911
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
52670
52912
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -52674,17 +52916,17 @@ var TURN_REPLAY_LOOKBACK_MS = 7 * 24 * 60 * 6e4;
|
|
|
52674
52916
|
function appendIdentityAudit(path2, record2, line) {
|
|
52675
52917
|
if (!record2.accepted && record2.score <= 0) return;
|
|
52676
52918
|
try {
|
|
52677
|
-
if (
|
|
52919
|
+
if (existsSync21(path2) && statSync5(path2).size >= IDENTITY_AUDIT_MAX_BYTES) {
|
|
52678
52920
|
renameSync3(path2, `${path2}.1`);
|
|
52679
52921
|
}
|
|
52680
|
-
|
|
52922
|
+
appendFileSync3(path2, line);
|
|
52681
52923
|
} catch {
|
|
52682
52924
|
}
|
|
52683
52925
|
}
|
|
52684
52926
|
var yieldToLoop = () => new Promise((r) => setImmediate(r));
|
|
52685
52927
|
function loadTurnCursors(path2) {
|
|
52686
52928
|
try {
|
|
52687
|
-
const raw2 = JSON.parse(
|
|
52929
|
+
const raw2 = JSON.parse(readFileSync21(path2, "utf8"));
|
|
52688
52930
|
return new Map(
|
|
52689
52931
|
Object.entries(raw2).map(([k, v]) => [k, typeof v === "string" ? v : String(v?.uuid ?? "")])
|
|
52690
52932
|
);
|
|
@@ -52694,7 +52936,7 @@ function loadTurnCursors(path2) {
|
|
|
52694
52936
|
}
|
|
52695
52937
|
function loadTurnOffsets(path2) {
|
|
52696
52938
|
try {
|
|
52697
|
-
const raw2 = JSON.parse(
|
|
52939
|
+
const raw2 = JSON.parse(readFileSync21(path2, "utf8"));
|
|
52698
52940
|
const out2 = /* @__PURE__ */ new Map();
|
|
52699
52941
|
for (const [k, v] of Object.entries(raw2)) {
|
|
52700
52942
|
const off = typeof v === "object" && v !== null ? v.offset : void 0;
|
|
@@ -52710,7 +52952,7 @@ function saveTurnCursors(path2, cursors, offsets) {
|
|
|
52710
52952
|
const merged = {};
|
|
52711
52953
|
for (const [k, uuid3] of cursors) merged[k] = { uuid: uuid3, offset: offsets.get(k) ?? 0 };
|
|
52712
52954
|
for (const [k, offset] of offsets) if (!merged[k]) merged[k] = { uuid: "", offset };
|
|
52713
|
-
|
|
52955
|
+
writeFileSync18(path2, JSON.stringify(merged), "utf8");
|
|
52714
52956
|
} catch {
|
|
52715
52957
|
}
|
|
52716
52958
|
}
|
|
@@ -52732,7 +52974,7 @@ function gitSourceWatchTargets(root) {
|
|
|
52732
52974
|
["-C", root, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"],
|
|
52733
52975
|
{ encoding: "utf8", maxBuffer: 256 * 1024 * 1024, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
|
|
52734
52976
|
);
|
|
52735
|
-
ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(
|
|
52977
|
+
ignoredDirs = igOut.split("\0").filter(Boolean).map((d) => d.replace(/\/+$/, "")).filter((d) => !IGNORED_PATH.test(join26(root, d) + sep4));
|
|
52736
52978
|
} catch {
|
|
52737
52979
|
}
|
|
52738
52980
|
const hasIgnoredChild = (dir) => ignoredDirs.some((ig) => ig.startsWith(dir + "/"));
|
|
@@ -52744,19 +52986,19 @@ function gitSourceWatchTargets(root) {
|
|
|
52744
52986
|
if (!f.startsWith(prefix)) continue;
|
|
52745
52987
|
const rest2 = f.slice(prefix.length);
|
|
52746
52988
|
if (rest2.includes("/")) children.add(dir === "" ? rest2.slice(0, rest2.indexOf("/")) : dir + "/" + rest2.slice(0, rest2.indexOf("/")));
|
|
52747
|
-
else targets.add(
|
|
52989
|
+
else targets.add(join26(root, f));
|
|
52748
52990
|
}
|
|
52749
52991
|
for (const c of children) {
|
|
52750
|
-
if (IGNORED_PATH.test(
|
|
52992
|
+
if (IGNORED_PATH.test(join26(root, c) + sep4)) continue;
|
|
52751
52993
|
if (hasIgnoredChild(c)) addUnder(c);
|
|
52752
|
-
else targets.add(
|
|
52994
|
+
else targets.add(join26(root, c));
|
|
52753
52995
|
}
|
|
52754
52996
|
};
|
|
52755
52997
|
addUnder("");
|
|
52756
52998
|
if (targets.size > 0) return [...targets];
|
|
52757
52999
|
} catch {
|
|
52758
53000
|
}
|
|
52759
|
-
return readdirSync9(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(
|
|
53001
|
+
return readdirSync9(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !IGNORED_PATH.test(join26(root, String(e.name)) + sep4)).map((e) => join26(root, String(e.name)));
|
|
52760
53002
|
}
|
|
52761
53003
|
function createWorkspaceEngine(opts) {
|
|
52762
53004
|
const paths = workspacePaths(opts.workspaceRoot);
|
|
@@ -52914,7 +53156,7 @@ function createWorkspaceEngine(opts) {
|
|
|
52914
53156
|
const srcPaths = diff.changedPaths.filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs|py)$/i.test(p));
|
|
52915
53157
|
let episodeId2;
|
|
52916
53158
|
if (srcPaths.length > 0) {
|
|
52917
|
-
const abs = srcPaths.map((p) =>
|
|
53159
|
+
const abs = srcPaths.map((p) => join26(opts.workspaceRoot, p));
|
|
52918
53160
|
try {
|
|
52919
53161
|
const r = await runReindexPass(
|
|
52920
53162
|
`git-reindex:${profile.name} (${abs.length} files)`,
|
|
@@ -52950,8 +53192,8 @@ function createWorkspaceEngine(opts) {
|
|
|
52950
53192
|
`[errata] git: ${ev.kind} ${ev.newSha.slice(0, 7)} by ${meta3.authorName} \u2014 ${diff.changedPaths.length} file(s), ${diff.renames.length} rename(s)`
|
|
52951
53193
|
);
|
|
52952
53194
|
};
|
|
52953
|
-
const gitDir =
|
|
52954
|
-
if (
|
|
53195
|
+
const gitDir = join26(opts.workspaceRoot, ".git");
|
|
53196
|
+
if (existsSync21(gitDir)) {
|
|
52955
53197
|
stopGit = startGitSensor(gitDir, (ev) => {
|
|
52956
53198
|
void handleGitEvent(ev).catch((err2) => {
|
|
52957
53199
|
console.warn("[errata] git event handler failed:", err2);
|
|
@@ -53021,10 +53263,10 @@ function createWorkspaceEngine(opts) {
|
|
|
53021
53263
|
});
|
|
53022
53264
|
doneRender?.();
|
|
53023
53265
|
writeContextFile(opts.workspaceRoot, body2);
|
|
53024
|
-
const target =
|
|
53266
|
+
const target = join26(opts.workspaceRoot, "AGENTS.md");
|
|
53025
53267
|
writeManagedBlock(target, { body: AGENTS_POINTER_BODY, stable: true, force: true });
|
|
53026
53268
|
if (elicit) {
|
|
53027
|
-
writePrimingHandles(
|
|
53269
|
+
writePrimingHandles(join26(paths.configDir, "priming-handles.json"), [
|
|
53028
53270
|
...snapshot.recentProblems.map((r) => r.node),
|
|
53029
53271
|
// Resolved-band handles: the ✓ problem AND its Solution are citable
|
|
53030
53272
|
// (a fix tag on an already-resolved problem no-ops idempotently; the
|
|
@@ -53054,7 +53296,7 @@ function createWorkspaceEngine(opts) {
|
|
|
53054
53296
|
remoteInFlight = true;
|
|
53055
53297
|
lastRemoteAt = now;
|
|
53056
53298
|
try {
|
|
53057
|
-
const norm = (xs) => (xs ?? []).map((t) => t.trim().toLowerCase().replace(/[@\s].*$/, "")).filter(Boolean);
|
|
53299
|
+
const norm = (xs) => (xs ?? []).map((t) => t.trim().toLowerCase().replace(/(?!^)[@\s].*$/, "")).filter(Boolean);
|
|
53058
53300
|
const seed = store.findNodesByLabel("Problem").sort((a, b) => b.lastUpdatedAt - a.lastUpdatedAt).slice(0, 6).map((p) => p.id);
|
|
53059
53301
|
const q = {
|
|
53060
53302
|
stack: norm(profile.stack),
|
|
@@ -53240,7 +53482,7 @@ function createWorkspaceEngine(opts) {
|
|
|
53240
53482
|
resultSummary: { exitCode: e.exitCode ?? 1, errorTokens: e.errorTokens }
|
|
53241
53483
|
});
|
|
53242
53484
|
};
|
|
53243
|
-
const turnCursorPath =
|
|
53485
|
+
const turnCursorPath = join26(paths.configDir, "turn-cursors.json");
|
|
53244
53486
|
const lastTurnUuid = loadTurnCursors(turnCursorPath);
|
|
53245
53487
|
const turnOffset = loadTurnOffsets(turnCursorPath);
|
|
53246
53488
|
const sessionLastProblem = /* @__PURE__ */ new Map();
|
|
@@ -53264,7 +53506,7 @@ function createWorkspaceEngine(opts) {
|
|
|
53264
53506
|
const t = Date.now();
|
|
53265
53507
|
let processedTurns = 0;
|
|
53266
53508
|
const elicit = isEdgeElicitationEnabled();
|
|
53267
|
-
const handleMap = elicit ? readPrimingHandles(
|
|
53509
|
+
const handleMap = elicit ? readPrimingHandles(join26(paths.configDir, "priming-handles.json")) : {};
|
|
53268
53510
|
const wsRoot = (opts.workspaceRoot ?? "").replace(/\\/g, "/");
|
|
53269
53511
|
const toRel = (abs) => {
|
|
53270
53512
|
const p = abs.replace(/\\/g, "/");
|
|
@@ -53655,6 +53897,15 @@ function createWorkspaceEngine(opts) {
|
|
|
53655
53897
|
console.log(
|
|
53656
53898
|
`[errata] ${channel}: ${formatDisposition({ recorded, unmatched, duplicate, selfGated })}` + (queued.length > 0 ? ` (incl. ${queued.length} replayed)` : "")
|
|
53657
53899
|
);
|
|
53900
|
+
appendWitnessLedger(paths.configDir, {
|
|
53901
|
+
ts: Date.now(),
|
|
53902
|
+
channel,
|
|
53903
|
+
recorded,
|
|
53904
|
+
unmatched,
|
|
53905
|
+
duplicate,
|
|
53906
|
+
selfGated,
|
|
53907
|
+
parked: pendingFor(witnessQueue, channel).length
|
|
53908
|
+
});
|
|
53658
53909
|
};
|
|
53659
53910
|
if (typeof cloud.reportContradictions === "function") {
|
|
53660
53911
|
await sendWitnesses(
|
|
@@ -53671,7 +53922,10 @@ function createWorkspaceEngine(opts) {
|
|
|
53671
53922
|
if (typeof cloud.reportCorroborations === "function") {
|
|
53672
53923
|
const emit = plan.corroborations.filter((c) => !mintedHere(c.nodeId));
|
|
53673
53924
|
const skipped = plan.corroborations.length - emit.length;
|
|
53674
|
-
if (skipped > 0)
|
|
53925
|
+
if (skipped > 0) {
|
|
53926
|
+
console.log(`[errata] corroborate: ${skipped} skipped (this session authored the node)`);
|
|
53927
|
+
appendWitnessLedger(paths.configDir, { ts: Date.now(), channel: "corroborate", clientSelfSkipped: skipped });
|
|
53928
|
+
}
|
|
53675
53929
|
await sendWitnesses(
|
|
53676
53930
|
"corroborate",
|
|
53677
53931
|
emit,
|
|
@@ -53873,7 +54127,7 @@ function createWorkspaceEngine(opts) {
|
|
|
53873
54127
|
try {
|
|
53874
54128
|
const inputs = emitInputsFromManifest(paths.configDir, paths.skillsManifest);
|
|
53875
54129
|
emitAndProjectSkills(opts.workspaceRoot, inputs);
|
|
53876
|
-
writePrimingHandles(
|
|
54130
|
+
writePrimingHandles(join26(paths.configDir, "priming-handles.json"), skillHandleNodes(inputs));
|
|
53877
54131
|
} catch (err2) {
|
|
53878
54132
|
console.warn("[skills] agent-skills projection failed (non-fatal):", err2 instanceof Error ? err2.message : err2);
|
|
53879
54133
|
}
|
|
@@ -54060,7 +54314,7 @@ function createWorkspaceEngine(opts) {
|
|
|
54060
54314
|
console.log(
|
|
54061
54315
|
"[errata] sync skipped \u2014 cloud sync consent is off (enable with `errata consent sync on`)"
|
|
54062
54316
|
);
|
|
54063
|
-
const pending =
|
|
54317
|
+
const pending = existsSync21(paths.outbox) ? readdirSync9(paths.outbox).filter((f) => f.endsWith(".json")).length : 0;
|
|
54064
54318
|
return { uploaded: 0, failed: 0, remaining: pending };
|
|
54065
54319
|
}
|
|
54066
54320
|
try {
|
|
@@ -54147,7 +54401,7 @@ async function startDaemon(opts) {
|
|
|
54147
54401
|
reviewUrl: () => webUiUrl + "/review"
|
|
54148
54402
|
});
|
|
54149
54403
|
const writeLockFile = (url2) => {
|
|
54150
|
-
|
|
54404
|
+
writeFileSync19(
|
|
54151
54405
|
engine.paths.daemonLock,
|
|
54152
54406
|
JSON.stringify({ pid: process.pid, webUiUrl: url2, startedAt: Date.now() }),
|
|
54153
54407
|
"utf8"
|
|
@@ -54190,7 +54444,7 @@ async function startDaemon(opts) {
|
|
|
54190
54444
|
);
|
|
54191
54445
|
await engine.stop();
|
|
54192
54446
|
try {
|
|
54193
|
-
if (
|
|
54447
|
+
if (existsSync22(engine.paths.daemonLock)) {
|
|
54194
54448
|
}
|
|
54195
54449
|
} catch {
|
|
54196
54450
|
}
|
|
@@ -54207,16 +54461,16 @@ async function listenServer(fetchFn, port) {
|
|
|
54207
54461
|
|
|
54208
54462
|
// src/registry.ts
|
|
54209
54463
|
init_paths();
|
|
54210
|
-
import { existsSync as
|
|
54211
|
-
import { join as
|
|
54464
|
+
import { existsSync as existsSync23, readFileSync as readFileSync22, writeFileSync as writeFileSync20 } from "node:fs";
|
|
54465
|
+
import { join as join27 } from "node:path";
|
|
54212
54466
|
function registryPath() {
|
|
54213
|
-
return process.env["ERRATA_REGISTRY_PATH"] ??
|
|
54467
|
+
return process.env["ERRATA_REGISTRY_PATH"] ?? join27(globalDir(), "workspaces.json");
|
|
54214
54468
|
}
|
|
54215
54469
|
function read() {
|
|
54216
54470
|
const p = registryPath();
|
|
54217
|
-
if (!
|
|
54471
|
+
if (!existsSync23(p)) return { version: 1, workspaces: {} };
|
|
54218
54472
|
try {
|
|
54219
|
-
const parsed = JSON.parse(
|
|
54473
|
+
const parsed = JSON.parse(readFileSync22(p, "utf8"));
|
|
54220
54474
|
return { version: 1, workspaces: parsed.workspaces ?? {} };
|
|
54221
54475
|
} catch {
|
|
54222
54476
|
return { version: 1, workspaces: {} };
|
|
@@ -54224,7 +54478,7 @@ function read() {
|
|
|
54224
54478
|
}
|
|
54225
54479
|
function write(reg) {
|
|
54226
54480
|
ensureDir(globalDir());
|
|
54227
|
-
|
|
54481
|
+
writeFileSync20(registryPath(), JSON.stringify(reg, null, 2), "utf8");
|
|
54228
54482
|
}
|
|
54229
54483
|
function registerWorkspace(profile, root, now = Date.now()) {
|
|
54230
54484
|
const reg = read();
|
|
@@ -54241,7 +54495,7 @@ function pruneMissingWorkspaces() {
|
|
|
54241
54495
|
const reg = read();
|
|
54242
54496
|
const removed = [];
|
|
54243
54497
|
for (const [id, entry] of Object.entries(reg.workspaces)) {
|
|
54244
|
-
if (!
|
|
54498
|
+
if (!existsSync23(entry.path)) {
|
|
54245
54499
|
removed.push(entry);
|
|
54246
54500
|
delete reg.workspaces[id];
|
|
54247
54501
|
}
|
|
@@ -54250,13 +54504,13 @@ function pruneMissingWorkspaces() {
|
|
|
54250
54504
|
return removed;
|
|
54251
54505
|
}
|
|
54252
54506
|
function workspaceStatus(entry) {
|
|
54253
|
-
const missing = !
|
|
54507
|
+
const missing = !existsSync23(entry.path);
|
|
54254
54508
|
const lockPath = workspacePaths(entry.path).daemonLock;
|
|
54255
54509
|
let running = false;
|
|
54256
54510
|
let webUiUrl = null;
|
|
54257
|
-
if (
|
|
54511
|
+
if (existsSync23(lockPath)) {
|
|
54258
54512
|
try {
|
|
54259
|
-
const lock = JSON.parse(
|
|
54513
|
+
const lock = JSON.parse(readFileSync22(lockPath, "utf8"));
|
|
54260
54514
|
if (lock.pid && lock.webUiUrl && pidAlive(lock.pid)) {
|
|
54261
54515
|
running = true;
|
|
54262
54516
|
webUiUrl = lock.webUiUrl;
|
|
@@ -54284,7 +54538,7 @@ function pidAlive(pid) {
|
|
|
54284
54538
|
// src/multi.ts
|
|
54285
54539
|
init_dist();
|
|
54286
54540
|
init_src4();
|
|
54287
|
-
import { readFileSync as
|
|
54541
|
+
import { readFileSync as readFileSync25, unlinkSync as unlinkSync3, writeFileSync as writeFileSync21 } from "node:fs";
|
|
54288
54542
|
|
|
54289
54543
|
// src/principle-sync.ts
|
|
54290
54544
|
init_src4();
|
|
@@ -54312,8 +54566,8 @@ init_reconcile();
|
|
|
54312
54566
|
|
|
54313
54567
|
// src/lockfile-auto.ts
|
|
54314
54568
|
init_src();
|
|
54315
|
-
import { existsSync as
|
|
54316
|
-
import { join as
|
|
54569
|
+
import { existsSync as existsSync24, readFileSync as readFileSync23 } from "node:fs";
|
|
54570
|
+
import { join as join28 } from "node:path";
|
|
54317
54571
|
|
|
54318
54572
|
// src/package-index.ts
|
|
54319
54573
|
init_src();
|
|
@@ -54462,11 +54716,11 @@ function runLockfilePass(opts) {
|
|
|
54462
54716
|
{ file: "package-lock.json", parse: parsePackageLockJson }
|
|
54463
54717
|
];
|
|
54464
54718
|
for (const c of candidates) {
|
|
54465
|
-
const p =
|
|
54466
|
-
if (!
|
|
54719
|
+
const p = join28(opts.root, c.file);
|
|
54720
|
+
if (!existsSync24(p)) continue;
|
|
54467
54721
|
let sbom;
|
|
54468
54722
|
try {
|
|
54469
|
-
sbom = c.parse(
|
|
54723
|
+
sbom = c.parse(readFileSync23(p, "utf8"));
|
|
54470
54724
|
} catch {
|
|
54471
54725
|
continue;
|
|
54472
54726
|
}
|
|
@@ -54914,7 +55168,7 @@ var ConsolidateWorker = class {
|
|
|
54914
55168
|
init_paths();
|
|
54915
55169
|
|
|
54916
55170
|
// src/lock.ts
|
|
54917
|
-
import { existsSync as
|
|
55171
|
+
import { existsSync as existsSync25, readFileSync as readFileSync24 } from "node:fs";
|
|
54918
55172
|
function isProcessAlive(pid) {
|
|
54919
55173
|
if (!pid || pid <= 0) return false;
|
|
54920
55174
|
try {
|
|
@@ -54925,9 +55179,9 @@ function isProcessAlive(pid) {
|
|
|
54925
55179
|
}
|
|
54926
55180
|
}
|
|
54927
55181
|
function readDaemonLock(lockPath) {
|
|
54928
|
-
if (!
|
|
55182
|
+
if (!existsSync25(lockPath)) return null;
|
|
54929
55183
|
try {
|
|
54930
|
-
const lock = JSON.parse(
|
|
55184
|
+
const lock = JSON.parse(readFileSync24(lockPath, "utf8"));
|
|
54931
55185
|
return typeof lock.pid === "number" ? lock : null;
|
|
54932
55186
|
} catch {
|
|
54933
55187
|
return null;
|
|
@@ -55206,12 +55460,12 @@ async function reanchorProject(opts) {
|
|
|
55206
55460
|
}
|
|
55207
55461
|
|
|
55208
55462
|
// src/adopt.ts
|
|
55209
|
-
import { existsSync as
|
|
55210
|
-
import { dirname as dirname10, join as
|
|
55463
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
55464
|
+
import { dirname as dirname10, join as join29 } from "node:path";
|
|
55211
55465
|
function findGitRoot(absPath) {
|
|
55212
55466
|
let dir = absPath;
|
|
55213
55467
|
for (let depth = 0; depth < 64; depth++) {
|
|
55214
|
-
if (
|
|
55468
|
+
if (existsSync26(join29(dir, ".git"))) return dir;
|
|
55215
55469
|
const parent = dirname10(dir);
|
|
55216
55470
|
if (parent === dir) return null;
|
|
55217
55471
|
dir = parent;
|
|
@@ -55460,7 +55714,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55460
55714
|
void ambientLinkAll();
|
|
55461
55715
|
app.route(`/ws/${rec.id}`, rec.webApp);
|
|
55462
55716
|
try {
|
|
55463
|
-
|
|
55717
|
+
writeFileSync21(
|
|
55464
55718
|
rec.engine.paths.daemonLock,
|
|
55465
55719
|
JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${rec.id}`, startedAt: Date.now() }),
|
|
55466
55720
|
"utf8"
|
|
@@ -55649,7 +55903,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55649
55903
|
baseUrl = `http://127.0.0.1:${port}`;
|
|
55650
55904
|
try {
|
|
55651
55905
|
ensureDir(globalDir());
|
|
55652
|
-
|
|
55906
|
+
writeFileSync21(
|
|
55653
55907
|
lockPath,
|
|
55654
55908
|
JSON.stringify({ pid: process.pid, webUiUrl: baseUrl, startedAt: Date.now() }),
|
|
55655
55909
|
"utf8"
|
|
@@ -55658,7 +55912,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
55658
55912
|
}
|
|
55659
55913
|
for (const r of records) {
|
|
55660
55914
|
try {
|
|
55661
|
-
|
|
55915
|
+
writeFileSync21(
|
|
55662
55916
|
r.engine.paths.daemonLock,
|
|
55663
55917
|
JSON.stringify({ pid: process.pid, webUiUrl: `${baseUrl}/ws/${r.id}`, startedAt: Date.now() }),
|
|
55664
55918
|
"utf8"
|
|
@@ -56156,7 +56410,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
56156
56410
|
},
|
|
56157
56411
|
async stop() {
|
|
56158
56412
|
try {
|
|
56159
|
-
const cur =
|
|
56413
|
+
const cur = readFileSync25(lockPath, "utf8");
|
|
56160
56414
|
if (JSON.parse(cur).pid === process.pid) unlinkSync3(lockPath);
|
|
56161
56415
|
} catch {
|
|
56162
56416
|
}
|
|
@@ -57173,21 +57427,21 @@ async function cmdInit() {
|
|
|
57173
57427
|
if (!skipHooks) {
|
|
57174
57428
|
console.log("");
|
|
57175
57429
|
console.log("installing harness hooks...");
|
|
57176
|
-
const { existsSync:
|
|
57177
|
-
const { join:
|
|
57430
|
+
const { existsSync: existsSync28 } = await import("node:fs");
|
|
57431
|
+
const { join: join31 } = await import("node:path");
|
|
57178
57432
|
try {
|
|
57179
57433
|
await installClaudeHooks(port);
|
|
57180
57434
|
} catch (err2) {
|
|
57181
57435
|
console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
57182
57436
|
}
|
|
57183
|
-
if (
|
|
57437
|
+
if (existsSync28(join31(ROOT, ".cursor"))) {
|
|
57184
57438
|
try {
|
|
57185
57439
|
await installCursorMcpConfig();
|
|
57186
57440
|
} catch (err2) {
|
|
57187
57441
|
console.warn(` \u26A0\uFE0F Cursor MCP config failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
57188
57442
|
}
|
|
57189
57443
|
}
|
|
57190
|
-
if (
|
|
57444
|
+
if (existsSync28(join31(ROOT, ".codex"))) {
|
|
57191
57445
|
try {
|
|
57192
57446
|
await installCodexHooks(port);
|
|
57193
57447
|
} catch (err2) {
|
|
@@ -57344,9 +57598,9 @@ async function cmdStatus() {
|
|
|
57344
57598
|
console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
|
|
57345
57599
|
console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
|
|
57346
57600
|
}
|
|
57347
|
-
console.log(` graph db: ${
|
|
57348
|
-
console.log(` event log: ${
|
|
57349
|
-
if (
|
|
57601
|
+
console.log(` graph db: ${existsSync27(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
|
|
57602
|
+
console.log(` event log: ${existsSync27(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
|
|
57603
|
+
if (existsSync27(paths.castalia)) {
|
|
57350
57604
|
try {
|
|
57351
57605
|
const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
|
|
57352
57606
|
const store = openGraphStore2({ path: paths.castalia });
|
|
@@ -57378,6 +57632,13 @@ async function cmdStatus() {
|
|
|
57378
57632
|
} catch {
|
|
57379
57633
|
}
|
|
57380
57634
|
}
|
|
57635
|
+
try {
|
|
57636
|
+
const { summarizeWitnessLedger: summarizeWitnessLedger2 } = await Promise.resolve().then(() => (init_witness_ledger(), witness_ledger_exports));
|
|
57637
|
+
const lines = summarizeWitnessLedger2(paths.configDir, Date.now());
|
|
57638
|
+
if (lines.length === 0) console.log(" evidence: no witness activity ledgered yet (corroborate/contradict have never fired here)");
|
|
57639
|
+
else for (const l of lines) console.log(` evidence: ${l}`);
|
|
57640
|
+
} catch {
|
|
57641
|
+
}
|
|
57381
57642
|
const lockPath = globalDaemonLock();
|
|
57382
57643
|
const running = isDaemonAlive(lockPath) ? readDaemonLock(lockPath) : null;
|
|
57383
57644
|
console.log(
|
|
@@ -58020,11 +58281,11 @@ function cmdInstallationProfile(args2) {
|
|
|
58020
58281
|
}
|
|
58021
58282
|
async function cmdReview() {
|
|
58022
58283
|
const paths = workspacePaths(ROOT);
|
|
58023
|
-
if (!
|
|
58284
|
+
if (!existsSync27(paths.reviewQueue)) {
|
|
58024
58285
|
console.log("(review queue empty)");
|
|
58025
58286
|
return;
|
|
58026
58287
|
}
|
|
58027
|
-
const queue = JSON.parse(
|
|
58288
|
+
const queue = JSON.parse(readFileSync26(paths.reviewQueue, "utf8"));
|
|
58028
58289
|
if (queue.length === 0) {
|
|
58029
58290
|
console.log("(review queue empty)");
|
|
58030
58291
|
return;
|
|
@@ -58695,7 +58956,7 @@ async function gatherRepo(store, ws) {
|
|
|
58695
58956
|
};
|
|
58696
58957
|
}
|
|
58697
58958
|
async function gatherReportData(generatedAt) {
|
|
58698
|
-
const { existsSync:
|
|
58959
|
+
const { existsSync: existsSync28 } = await import("node:fs");
|
|
58699
58960
|
const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src4(), src_exports2));
|
|
58700
58961
|
const cfg = loadConfig();
|
|
58701
58962
|
const outbound = cfg.consent.sync ? "auto" : "off";
|
|
@@ -58703,7 +58964,7 @@ async function gatherReportData(generatedAt) {
|
|
|
58703
58964
|
for (const ws of listWorkspaces()) {
|
|
58704
58965
|
if (ws.missing) continue;
|
|
58705
58966
|
const dbPath = workspacePaths(ws.path).castalia;
|
|
58706
|
-
if (!
|
|
58967
|
+
if (!existsSync28(dbPath)) continue;
|
|
58707
58968
|
let store = null;
|
|
58708
58969
|
try {
|
|
58709
58970
|
store = openGraphStore2({ path: dbPath });
|
|
@@ -58734,7 +58995,7 @@ async function gatherReportData(generatedAt) {
|
|
|
58734
58995
|
};
|
|
58735
58996
|
}
|
|
58736
58997
|
async function cmdReport(args2) {
|
|
58737
|
-
const { mkdirSync: mkdirSync8, writeFileSync:
|
|
58998
|
+
const { mkdirSync: mkdirSync8, writeFileSync: writeFileSync22 } = await import("node:fs");
|
|
58738
58999
|
const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
|
|
58739
59000
|
const includeFutureVerbs = args2.includes("--future-verbs");
|
|
58740
59001
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -58747,8 +59008,8 @@ async function cmdReport(args2) {
|
|
|
58747
59008
|
const outDir = workspacePaths(ROOT).configDir;
|
|
58748
59009
|
mkdirSync8(outDir, { recursive: true });
|
|
58749
59010
|
const files = renderReport2(data, { includeFutureVerbs });
|
|
58750
|
-
for (const f of files)
|
|
58751
|
-
const indexPath =
|
|
59011
|
+
for (const f of files) writeFileSync22(join30(outDir, f.name), f.html, "utf8");
|
|
59012
|
+
const indexPath = join30(outDir, "report.html");
|
|
58752
59013
|
console.log(`report \u2192 ${indexPath}`);
|
|
58753
59014
|
console.log(
|
|
58754
59015
|
` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
|
|
@@ -58866,15 +59127,15 @@ function hookRelayCommand(port, path2) {
|
|
|
58866
59127
|
return process.platform === "win32" ? `cmd //c "curl -s --connect-timeout 1 --max-time 2 -X POST -H \\"Content-Type: application/json\\" --data-binary @- ${url2} 2>NUL || echo {}"` : `curl -s --connect-timeout 1 --max-time 2 -X POST -H 'Content-Type: application/json' --data-binary @- ${url2} 2>/dev/null || echo '{}'`;
|
|
58867
59128
|
}
|
|
58868
59129
|
async function installClaudeHooks(port) {
|
|
58869
|
-
const { mkdirSync: mkdirSync8, existsSync:
|
|
58870
|
-
const { join:
|
|
58871
|
-
const dir =
|
|
58872
|
-
if (!
|
|
58873
|
-
const file2 =
|
|
59130
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync28, readFileSync: readFileSync27, writeFileSync: writeFileSync22 } = await import("node:fs");
|
|
59131
|
+
const { join: join31 } = await import("node:path");
|
|
59132
|
+
const dir = join31(ROOT, ".claude");
|
|
59133
|
+
if (!existsSync28(dir)) mkdirSync8(dir, { recursive: true });
|
|
59134
|
+
const file2 = join31(dir, "settings.json");
|
|
58874
59135
|
let settings = {};
|
|
58875
|
-
if (
|
|
59136
|
+
if (existsSync28(file2)) {
|
|
58876
59137
|
try {
|
|
58877
|
-
settings = JSON.parse(
|
|
59138
|
+
settings = JSON.parse(readFileSync27(file2, "utf8"));
|
|
58878
59139
|
} catch {
|
|
58879
59140
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
58880
59141
|
process.exit(2);
|
|
@@ -58920,10 +59181,10 @@ async function installClaudeHooks(port) {
|
|
|
58920
59181
|
dropErrata(list);
|
|
58921
59182
|
list.push({ hooks: [{ type: "command", command: injectCmd }] });
|
|
58922
59183
|
}
|
|
58923
|
-
|
|
59184
|
+
writeFileSync22(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
58924
59185
|
console.log(`installed Claude Code hooks \u2192 ${file2}`);
|
|
58925
59186
|
await installClaudeMcpConfig();
|
|
58926
|
-
const claudeMd =
|
|
59187
|
+
const claudeMd = join31(ROOT, "CLAUDE.md");
|
|
58927
59188
|
const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
|
|
58928
59189
|
if (recall.kind === "collision") {
|
|
58929
59190
|
console.warn(
|
|
@@ -58935,15 +59196,15 @@ async function installClaudeHooks(port) {
|
|
|
58935
59196
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
58936
59197
|
}
|
|
58937
59198
|
async function installClaudeMcpConfig() {
|
|
58938
|
-
const { mkdirSync: mkdirSync8, existsSync:
|
|
58939
|
-
const { join:
|
|
58940
|
-
const file2 =
|
|
59199
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync28, readFileSync: readFileSync27, writeFileSync: writeFileSync22 } = await import("node:fs");
|
|
59200
|
+
const { join: join31, dirname: dirname11 } = await import("node:path");
|
|
59201
|
+
const file2 = join31(ROOT, ".mcp.json");
|
|
58941
59202
|
const dir = dirname11(file2);
|
|
58942
|
-
if (!
|
|
59203
|
+
if (!existsSync28(dir)) mkdirSync8(dir, { recursive: true });
|
|
58943
59204
|
let cfg = {};
|
|
58944
|
-
if (
|
|
59205
|
+
if (existsSync28(file2)) {
|
|
58945
59206
|
try {
|
|
58946
|
-
cfg = JSON.parse(
|
|
59207
|
+
cfg = JSON.parse(readFileSync27(file2, "utf8"));
|
|
58947
59208
|
} catch {
|
|
58948
59209
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
58949
59210
|
process.exit(2);
|
|
@@ -58951,21 +59212,21 @@ async function installClaudeMcpConfig() {
|
|
|
58951
59212
|
}
|
|
58952
59213
|
cfg.mcpServers ??= {};
|
|
58953
59214
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
58954
|
-
|
|
59215
|
+
writeFileSync22(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
58955
59216
|
console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
|
|
58956
59217
|
console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
|
|
58957
59218
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
|
|
58958
59219
|
}
|
|
58959
59220
|
async function installCursorMcpConfig() {
|
|
58960
|
-
const { mkdirSync: mkdirSync8, existsSync:
|
|
58961
|
-
const { join:
|
|
58962
|
-
const dir =
|
|
58963
|
-
if (!
|
|
58964
|
-
const file2 =
|
|
59221
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync28, readFileSync: readFileSync27, writeFileSync: writeFileSync22 } = await import("node:fs");
|
|
59222
|
+
const { join: join31 } = await import("node:path");
|
|
59223
|
+
const dir = join31(ROOT, ".cursor");
|
|
59224
|
+
if (!existsSync28(dir)) mkdirSync8(dir, { recursive: true });
|
|
59225
|
+
const file2 = join31(dir, "mcp.json");
|
|
58965
59226
|
let cfg = {};
|
|
58966
|
-
if (
|
|
59227
|
+
if (existsSync28(file2)) {
|
|
58967
59228
|
try {
|
|
58968
|
-
cfg = JSON.parse(
|
|
59229
|
+
cfg = JSON.parse(readFileSync27(file2, "utf8"));
|
|
58969
59230
|
} catch {
|
|
58970
59231
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
58971
59232
|
process.exit(2);
|
|
@@ -58973,7 +59234,7 @@ async function installCursorMcpConfig() {
|
|
|
58973
59234
|
}
|
|
58974
59235
|
cfg.mcpServers ??= {};
|
|
58975
59236
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
58976
|
-
|
|
59237
|
+
writeFileSync22(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
58977
59238
|
console.log(`installed Cursor MCP server config \u2192 ${file2}`);
|
|
58978
59239
|
console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
|
|
58979
59240
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
|
|
@@ -58981,16 +59242,16 @@ async function installCursorMcpConfig() {
|
|
|
58981
59242
|
console.log(` \u26A0\uFE0F reload Cursor (Cmd/Ctrl-Shift-P \u2192 "Reload Window") to pick it up.`);
|
|
58982
59243
|
}
|
|
58983
59244
|
async function installCodexHooks(port) {
|
|
58984
|
-
const { mkdirSync: mkdirSync8, existsSync:
|
|
58985
|
-
const { join:
|
|
58986
|
-
const dir =
|
|
58987
|
-
if (!
|
|
58988
|
-
const file2 =
|
|
59245
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync28, readFileSync: readFileSync27, writeFileSync: writeFileSync22 } = await import("node:fs");
|
|
59246
|
+
const { join: join31 } = await import("node:path");
|
|
59247
|
+
const dir = join31(ROOT, ".codex");
|
|
59248
|
+
if (!existsSync28(dir)) mkdirSync8(dir, { recursive: true });
|
|
59249
|
+
const file2 = join31(dir, "config.toml");
|
|
58989
59250
|
const BEGIN = `# >>> errata hooks (errata-managed)`;
|
|
58990
59251
|
const END = `# <<< errata hooks`;
|
|
58991
59252
|
let existing = "";
|
|
58992
|
-
if (
|
|
58993
|
-
existing =
|
|
59253
|
+
if (existsSync28(file2)) {
|
|
59254
|
+
existing = readFileSync27(file2, "utf8");
|
|
58994
59255
|
const beginIdx = existing.indexOf(BEGIN);
|
|
58995
59256
|
const endIdx = existing.indexOf(END);
|
|
58996
59257
|
if (beginIdx >= 0 && endIdx > beginIdx) {
|
|
@@ -59019,7 +59280,7 @@ ${END}
|
|
|
59019
59280
|
const final = existing.length > 0 && !existing.endsWith("\n") ? `${existing}
|
|
59020
59281
|
|
|
59021
59282
|
${block}` : existing + (existing.endsWith("\n\n") ? "" : "\n") + block;
|
|
59022
|
-
|
|
59283
|
+
writeFileSync22(file2, final, "utf8");
|
|
59023
59284
|
console.log(`installed Codex hooks \u2192 ${file2}`);
|
|
59024
59285
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
59025
59286
|
console.log("");
|
|
@@ -59333,7 +59594,7 @@ async function cmdDash(args2) {
|
|
|
59333
59594
|
await yieldToLoop2();
|
|
59334
59595
|
try {
|
|
59335
59596
|
const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
|
|
59336
|
-
const res = bleedRules(
|
|
59597
|
+
const res = bleedRules(join30(r.root, ".claude", "rules"), items);
|
|
59337
59598
|
if (res.written || res.pruned) {
|
|
59338
59599
|
console.log(
|
|
59339
59600
|
`[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")
|