@inerrata-corporation/errata 2.0.8-dev.2849 → 2.0.8-dev.2870
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 +325 -82
- package/package.json +1 -1
package/errata.mjs
CHANGED
|
@@ -29066,6 +29066,92 @@ var init_agent_signals = __esm({
|
|
|
29066
29066
|
}
|
|
29067
29067
|
});
|
|
29068
29068
|
|
|
29069
|
+
// src/recall-card.ts
|
|
29070
|
+
function labelName(label) {
|
|
29071
|
+
return LABEL_NAMES[label] ?? label.toUpperCase();
|
|
29072
|
+
}
|
|
29073
|
+
function clip(text, width) {
|
|
29074
|
+
const flat = text.replace(/\s+/g, " ").trim();
|
|
29075
|
+
return flat.length > width ? `${flat.slice(0, width - 1)}\u2026` : flat;
|
|
29076
|
+
}
|
|
29077
|
+
function plural(n, word, many = `${word}s`) {
|
|
29078
|
+
return `${n} ${n === 1 ? word : many}`;
|
|
29079
|
+
}
|
|
29080
|
+
function errorCardHeadline(items) {
|
|
29081
|
+
const fixes = items.filter((it) => it.label === "Solution").length;
|
|
29082
|
+
return fixes > 0 ? `${plural(fixes, "known fix", "known fixes")} for this error` : `${plural(items.length, "prior")} for this error`;
|
|
29083
|
+
}
|
|
29084
|
+
function leadItem(items) {
|
|
29085
|
+
return items.find((it) => it.label === "Solution") ?? items[0];
|
|
29086
|
+
}
|
|
29087
|
+
function renderRecallLine(card) {
|
|
29088
|
+
const lead2 = leadItem(card.items);
|
|
29089
|
+
if (!lead2) return null;
|
|
29090
|
+
const rest2 = card.items.length - 1;
|
|
29091
|
+
return `\u26A1 errata \xB7 ${card.headline} \u2014 ${labelName(lead2.label)}: ${clip(lead2.text, INLINE_TEXT_WIDTH)}` + (lead2.note ? ` ${lead2.note}` : "") + (rest2 > 0 ? ` \xB7 +${rest2} in context` : "");
|
|
29092
|
+
}
|
|
29093
|
+
function labelColor(label) {
|
|
29094
|
+
if (label === "Solution") return GREEN;
|
|
29095
|
+
if (label === "Problem" || label === "AntiPattern") return MADDER;
|
|
29096
|
+
return AMBER;
|
|
29097
|
+
}
|
|
29098
|
+
function renderStatusCard(card) {
|
|
29099
|
+
const ordered = [...card.items].sort(
|
|
29100
|
+
(a, b) => Number(b.label === "Solution") - Number(a.label === "Solution")
|
|
29101
|
+
);
|
|
29102
|
+
const rows = ordered.slice(0, STATUS_ROWS).map((it) => {
|
|
29103
|
+
const label = labelName(it.label).padEnd(LABEL_WIDTH);
|
|
29104
|
+
const note = it.note ? ` ${DIM}${it.note}${RESET}` : "";
|
|
29105
|
+
return `${DIM}\u2502${RESET} ${BOLD}${labelColor(it.label)}${label}${RESET} ${INK}${clip(it.text, STATUS_TEXT_WIDTH)}${RESET}${note}`;
|
|
29106
|
+
});
|
|
29107
|
+
const hidden = card.items.length - STATUS_ROWS;
|
|
29108
|
+
const more = hidden > 0 ? ` ${DIM}\xB7 +${hidden} more in the agent's context${RESET}` : "";
|
|
29109
|
+
return [`${AMBER}\u26A1${RESET} ${BOLD}errata${RESET} ${DIM}\xB7${RESET} ${card.headline}${more}`, ...rows].join("\n");
|
|
29110
|
+
}
|
|
29111
|
+
function rememberCard(sessionId, card, now = Date.now()) {
|
|
29112
|
+
if (!sessionId) return;
|
|
29113
|
+
latestBySession.delete(sessionId);
|
|
29114
|
+
latestBySession.set(sessionId, { card, at: now });
|
|
29115
|
+
if (latestBySession.size > MAX_SESSIONS) {
|
|
29116
|
+
latestBySession.delete(latestBySession.keys().next().value);
|
|
29117
|
+
}
|
|
29118
|
+
}
|
|
29119
|
+
function statuslineText(sessionId, now = Date.now()) {
|
|
29120
|
+
const hit = latestBySession.get(sessionId);
|
|
29121
|
+
if (!hit || now - hit.at > STATUS_CARD_TTL_MS) return IDLE_STATUS;
|
|
29122
|
+
return renderStatusCard(hit.card);
|
|
29123
|
+
}
|
|
29124
|
+
function recallCardEnabled(env2 = process.env) {
|
|
29125
|
+
const v = (env2["ERRATA_RECALL_CARD"] ?? "").trim().toLowerCase();
|
|
29126
|
+
return !(v === "0" || v === "off" || v === "false" || v === "no");
|
|
29127
|
+
}
|
|
29128
|
+
var LABEL_NAMES, INLINE_TEXT_WIDTH, ESC, RESET, DIM, BOLD, AMBER, MADDER, GREEN, INK, STATUS_ROWS, STATUS_TEXT_WIDTH, LABEL_WIDTH, STATUS_CARD_TTL_MS, IDLE_STATUS, latestBySession, MAX_SESSIONS;
|
|
29129
|
+
var init_recall_card = __esm({
|
|
29130
|
+
"src/recall-card.ts"() {
|
|
29131
|
+
"use strict";
|
|
29132
|
+
LABEL_NAMES = {
|
|
29133
|
+
RootCause: "ROOT CAUSE",
|
|
29134
|
+
AntiPattern: "ANTIPATTERN"
|
|
29135
|
+
};
|
|
29136
|
+
INLINE_TEXT_WIDTH = 64;
|
|
29137
|
+
ESC = "\x1B[";
|
|
29138
|
+
RESET = `${ESC}0m`;
|
|
29139
|
+
DIM = `${ESC}2m`;
|
|
29140
|
+
BOLD = `${ESC}1m`;
|
|
29141
|
+
AMBER = `${ESC}38;2;217;164;65m`;
|
|
29142
|
+
MADDER = `${ESC}38;2;210;58;77m`;
|
|
29143
|
+
GREEN = `${ESC}38;2;111;191;138m`;
|
|
29144
|
+
INK = `${ESC}38;2;236;226;221m`;
|
|
29145
|
+
STATUS_ROWS = 2;
|
|
29146
|
+
STATUS_TEXT_WIDTH = 96;
|
|
29147
|
+
LABEL_WIDTH = 10;
|
|
29148
|
+
STATUS_CARD_TTL_MS = 9e4;
|
|
29149
|
+
IDLE_STATUS = `${AMBER}\u26A1${RESET} ${DIM}errata \xB7 watching${RESET}`;
|
|
29150
|
+
latestBySession = /* @__PURE__ */ new Map();
|
|
29151
|
+
MAX_SESSIONS = 256;
|
|
29152
|
+
}
|
|
29153
|
+
});
|
|
29154
|
+
|
|
29069
29155
|
// src/review.ts
|
|
29070
29156
|
import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync6 } from "node:fs";
|
|
29071
29157
|
function loadReviewQueue(paths) {
|
|
@@ -51311,8 +51397,11 @@ var init_message_accumulator = __esm({
|
|
|
51311
51397
|
// src/webui.ts
|
|
51312
51398
|
var webui_exports = {};
|
|
51313
51399
|
__export(webui_exports, {
|
|
51400
|
+
asFailedPostToolUse: () => asFailedPostToolUse,
|
|
51314
51401
|
buildWebUi: () => buildWebUi,
|
|
51315
51402
|
decideContextInject: () => decideContextInject,
|
|
51403
|
+
errorRecallTerms: () => errorRecallTerms,
|
|
51404
|
+
fileRecall: () => fileRecall,
|
|
51316
51405
|
fileUriToFsPath: () => fileUriToFsPath,
|
|
51317
51406
|
findFileByPath: () => findFileByPath,
|
|
51318
51407
|
recallForFile: () => recallForFile,
|
|
@@ -51327,9 +51416,7 @@ function fileUriToFsPath(raw2) {
|
|
|
51327
51416
|
return p;
|
|
51328
51417
|
}
|
|
51329
51418
|
function recallForError(store, errorText) {
|
|
51330
|
-
const terms =
|
|
51331
|
-
new Set(errorText.split(/[^A-Za-z0-9_.]+/).filter((t) => t.length >= 5))
|
|
51332
|
-
).slice(0, 3);
|
|
51419
|
+
const terms = errorRecallTerms(errorText);
|
|
51333
51420
|
if (terms.length === 0) return null;
|
|
51334
51421
|
const labels = ["Problem", "Solution", "RootCause"];
|
|
51335
51422
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -51344,15 +51431,46 @@ function recallForError(store, errorText) {
|
|
|
51344
51431
|
}
|
|
51345
51432
|
if (hits.length === 0) return null;
|
|
51346
51433
|
const lines = hits.slice(0, 3).map((n) => `- [${n.label}] ${(n.description ?? "").replace(/\s+/g, " ").slice(0, 140)}`);
|
|
51347
|
-
|
|
51434
|
+
const items = hits.map((n) => ({ label: n.label, text: n.description ?? "" }));
|
|
51435
|
+
return {
|
|
51436
|
+
context: `errata recall \u2014 ${hits.length} prior match(es) in the local graph for this error:
|
|
51348
51437
|
${lines.join("\n")}
|
|
51349
|
-
Reuse the prior fix if it applies before re-deriving
|
|
51438
|
+
Reuse the prior fix if it applies before re-deriving.`,
|
|
51439
|
+
card: { headline: errorCardHeadline(items), items }
|
|
51440
|
+
};
|
|
51441
|
+
}
|
|
51442
|
+
function asFailedPostToolUse(body2) {
|
|
51443
|
+
const error48 = typeof body2["error"] === "string" ? body2["error"] : "";
|
|
51444
|
+
const exit = /^Exit code (\d+)/.exec(error48);
|
|
51445
|
+
return {
|
|
51446
|
+
...body2,
|
|
51447
|
+
hook_event_name: "PostToolUse",
|
|
51448
|
+
is_error: true,
|
|
51449
|
+
tool_response: { stdout: "", stderr: error48, exitCode: exit ? Number(exit[1]) : 1 }
|
|
51450
|
+
};
|
|
51451
|
+
}
|
|
51452
|
+
function errorRecallTerms(errorText) {
|
|
51453
|
+
const seen = /* @__PURE__ */ new Set();
|
|
51454
|
+
const scored = [];
|
|
51455
|
+
errorText.split(/[^A-Za-z0-9_.-]+/).forEach((raw2, at) => {
|
|
51456
|
+
const term = raw2.replace(/^[.-]+|[.-]+$/g, "");
|
|
51457
|
+
const key = term.toLowerCase();
|
|
51458
|
+
if (term.length < 5 || seen.has(key) || GENERIC_ERROR_WORDS.has(key)) return;
|
|
51459
|
+
seen.add(key);
|
|
51460
|
+
const identifier = /[_.\d-]/.test(term) || /[a-z][A-Z]/.test(term) || /^[A-Z]{5,}$/.test(term);
|
|
51461
|
+
scored.push({ term, score: identifier ? 1 : 0, at });
|
|
51462
|
+
});
|
|
51463
|
+
const hasIdentifier = scored.some((s) => s.score > 0);
|
|
51464
|
+
return scored.filter((s) => !hasIdentifier || s.score > 0).sort((a, b) => b.score - a.score || a.at - b.at).slice(0, 3).map((s) => s.term);
|
|
51350
51465
|
}
|
|
51351
51466
|
function recallLine(n, token) {
|
|
51352
51467
|
const desc = (n.description ?? "").replace(/\s+/g, " ").slice(0, 120);
|
|
51353
51468
|
return `- [${n.label}] ${desc} \u2192 ${token}`;
|
|
51354
51469
|
}
|
|
51355
51470
|
function recallForFile(store, relPath) {
|
|
51471
|
+
return fileRecall(store, relPath)?.context ?? null;
|
|
51472
|
+
}
|
|
51473
|
+
function fileRecall(store, relPath) {
|
|
51356
51474
|
const priors = priorsForFile(store, relPath);
|
|
51357
51475
|
if (!priors) return null;
|
|
51358
51476
|
const lines = [];
|
|
@@ -51370,9 +51488,16 @@ function recallForFile(store, relPath) {
|
|
|
51370
51488
|
lines.push(recallLine(n, `cite with ${TAG_EXAMPLE.prior(n.id)}`));
|
|
51371
51489
|
}
|
|
51372
51490
|
const total = priors.openProblems.length + priors.constraints.length + priors.related.length;
|
|
51373
|
-
|
|
51491
|
+
const items = [...priors.openProblems, ...priors.constraints, ...priors.related].map((n) => ({
|
|
51492
|
+
label: n.label,
|
|
51493
|
+
text: n.description ?? ""
|
|
51494
|
+
}));
|
|
51495
|
+
return {
|
|
51496
|
+
context: `errata \u2014 ${total} prior(s) recorded on this file (act only if relevant):
|
|
51374
51497
|
${lines.join("\n")}
|
|
51375
|
-
` + buildFileRecallInstruction()
|
|
51498
|
+
` + buildFileRecallInstruction(),
|
|
51499
|
+
card: { headline: `${plural(total, "prior")} on ${relPath.split("/").slice(-2).join("/")}`, items }
|
|
51500
|
+
};
|
|
51376
51501
|
}
|
|
51377
51502
|
function workspacePackageIds(store) {
|
|
51378
51503
|
const hit = wsPackagesCache.get(store);
|
|
@@ -51383,7 +51508,11 @@ function workspacePackageIds(store) {
|
|
|
51383
51508
|
return ids;
|
|
51384
51509
|
}
|
|
51385
51510
|
function recallForTool(store, command, ctx) {
|
|
51511
|
+
return toolRecall(store, command, ctx)?.context ?? null;
|
|
51512
|
+
}
|
|
51513
|
+
function toolRecall(store, command, ctx) {
|
|
51386
51514
|
const lines = [];
|
|
51515
|
+
const items = [];
|
|
51387
51516
|
const seen = /* @__PURE__ */ new Set();
|
|
51388
51517
|
for (const name2 of extractExecutables(command)) {
|
|
51389
51518
|
if (seen.has(name2)) continue;
|
|
@@ -51397,11 +51526,19 @@ function recallForTool(store, command, ctx) {
|
|
|
51397
51526
|
fit.node.label === "Problem" ? `${TAG_EXAMPLE.fix(fit.node.id)} if you resolved it \xB7 ${TAG_EXAMPLE.prior(fit.node.id)} to cite` : `cite with ${TAG_EXAMPLE.prior(fit.node.id)}`
|
|
51398
51527
|
).slice(2)}`
|
|
51399
51528
|
);
|
|
51529
|
+
items.push({
|
|
51530
|
+
label: fit.node.label,
|
|
51531
|
+
text: `${name2}: ${fit.node.description ?? ""}`,
|
|
51532
|
+
note: fit.osMismatch ? `[seen on ${fit.observedOn.join("/")}]` : void 0
|
|
51533
|
+
});
|
|
51400
51534
|
}
|
|
51401
51535
|
}
|
|
51402
51536
|
if (lines.length === 0) return null;
|
|
51403
|
-
return
|
|
51404
|
-
${lines.
|
|
51537
|
+
return {
|
|
51538
|
+
context: `errata \u2014 ${lines.length} prior(s) about the tool(s) you're about to run (a \`[platform]\` tag means it was seen on a DIFFERENT OS than this one \u2014 judge it):
|
|
51539
|
+
${lines.join("\n")}`,
|
|
51540
|
+
card: { headline: `${plural(items.length, "prior")} before this command runs`, items }
|
|
51541
|
+
};
|
|
51405
51542
|
}
|
|
51406
51543
|
function decideContextInject(args2) {
|
|
51407
51544
|
const { event, sessionId, block, lastInjectedHash } = args2;
|
|
@@ -51559,8 +51696,10 @@ function buildWebUi(deps) {
|
|
|
51559
51696
|
if (deps.onHook) deps.onHook();
|
|
51560
51697
|
const tool = String(body2["tool_name"] ?? "");
|
|
51561
51698
|
const input = body2["tool_input"] ?? {};
|
|
51562
|
-
const
|
|
51563
|
-
|
|
51699
|
+
const hookEvent = String(body2["hook_event_name"] ?? "PreToolUse");
|
|
51700
|
+
if (hookEvent === "PostToolUseFailure") body2 = asFailedPostToolUse(body2);
|
|
51701
|
+
const event = hookEvent === "PostToolUseFailure" ? "PostToolUse" : hookEvent;
|
|
51702
|
+
let recall = null;
|
|
51564
51703
|
if (event === "PreToolUse") {
|
|
51565
51704
|
const virtual = extractVirtualReads(input);
|
|
51566
51705
|
if (virtual.length > 0) {
|
|
@@ -51575,7 +51714,7 @@ function buildWebUi(deps) {
|
|
|
51575
51714
|
}
|
|
51576
51715
|
if (tool === "Bash" && typeof input["command"] === "string") {
|
|
51577
51716
|
try {
|
|
51578
|
-
|
|
51717
|
+
recall = toolRecall(deps.store, input["command"], {
|
|
51579
51718
|
os: currentOsName(),
|
|
51580
51719
|
workspacePackageIds: workspacePackageIds(deps.store)
|
|
51581
51720
|
});
|
|
@@ -51629,7 +51768,7 @@ function buildWebUi(deps) {
|
|
|
51629
51768
|
deps.onToolsObserved?.(toolSid, observed.nodeIds);
|
|
51630
51769
|
} catch {
|
|
51631
51770
|
}
|
|
51632
|
-
if (failed)
|
|
51771
|
+
if (failed) recall = recallForError(deps.store, stderr || combined);
|
|
51633
51772
|
}
|
|
51634
51773
|
if (event === "PostToolUse" && tool && tool !== "Bash" && deps.onToolError) {
|
|
51635
51774
|
const rawResp = body2["tool_response"];
|
|
@@ -51652,11 +51791,11 @@ function buildWebUi(deps) {
|
|
|
51652
51791
|
exitCode: numericExit ?? 1,
|
|
51653
51792
|
ts: Date.now()
|
|
51654
51793
|
});
|
|
51655
|
-
|
|
51794
|
+
recall = recallForError(deps.store, errText2);
|
|
51656
51795
|
}
|
|
51657
51796
|
}
|
|
51658
51797
|
}
|
|
51659
|
-
if (event === "PostToolUse" && !
|
|
51798
|
+
if (event === "PostToolUse" && !recall && rel && (tool === "Read" || tool === "Edit" || tool === "Write" || tool === "NotebookEdit")) {
|
|
51660
51799
|
const sid = String(body2["session_id"] ?? "");
|
|
51661
51800
|
let seen = fileRecallSeen.get(sid);
|
|
51662
51801
|
if (!seen) {
|
|
@@ -51664,28 +51803,29 @@ function buildWebUi(deps) {
|
|
|
51664
51803
|
fileRecallSeen.set(sid, seen);
|
|
51665
51804
|
}
|
|
51666
51805
|
if (!seen.has(rel)) {
|
|
51667
|
-
const
|
|
51668
|
-
if (
|
|
51806
|
+
const fileHit = fileRecall(deps.store, rel);
|
|
51807
|
+
if (fileHit) {
|
|
51669
51808
|
seen.add(rel);
|
|
51670
|
-
|
|
51809
|
+
recall = fileHit;
|
|
51671
51810
|
}
|
|
51672
51811
|
}
|
|
51673
51812
|
}
|
|
51674
|
-
if (event === "PostToolUse") {
|
|
51675
|
-
|
|
51676
|
-
|
|
51677
|
-
|
|
51678
|
-
});
|
|
51679
|
-
}
|
|
51680
|
-
return c.body(null, 204);
|
|
51681
|
-
}
|
|
51682
|
-
if (event === "PreToolUse" && recallCtx) {
|
|
51813
|
+
if ((event === "PostToolUse" || event === "PreToolUse") && recall) {
|
|
51814
|
+
const showCard = recallCardEnabled();
|
|
51815
|
+
if (showCard) rememberCard(String(body2["session_id"] ?? ""), recall.card);
|
|
51816
|
+
const line = showCard ? renderRecallLine(recall.card) : null;
|
|
51683
51817
|
return c.json({
|
|
51684
|
-
|
|
51818
|
+
...line ? { systemMessage: line } : {},
|
|
51819
|
+
hookSpecificOutput: { hookEventName: hookEvent, additionalContext: recall.context }
|
|
51685
51820
|
});
|
|
51686
51821
|
}
|
|
51822
|
+
if (event === "PostToolUse") return c.body(null, 204);
|
|
51687
51823
|
return c.json({ ok: true, event, tool, recognizedFile: filePath ?? null });
|
|
51688
51824
|
});
|
|
51825
|
+
app.post("/api/statusline", async (c) => {
|
|
51826
|
+
const body2 = await c.req.json().catch(() => ({}));
|
|
51827
|
+
return c.text(statuslineText(String(body2["session_id"] ?? "")));
|
|
51828
|
+
});
|
|
51689
51829
|
app.post("/api/turn", async (c) => {
|
|
51690
51830
|
let body2;
|
|
51691
51831
|
try {
|
|
@@ -51929,7 +52069,7 @@ function proposalToIngest(p, profile, daemonVersion) {
|
|
|
51929
52069
|
payloadDigest: p.id
|
|
51930
52070
|
};
|
|
51931
52071
|
}
|
|
51932
|
-
var messageAccumulator, wsPackagesCache, WS_PACKAGES_TTL_MS, loggedToolSessions, META_LABELS;
|
|
52072
|
+
var messageAccumulator, GENERIC_ERROR_WORDS, wsPackagesCache, WS_PACKAGES_TTL_MS, loggedToolSessions, META_LABELS;
|
|
51933
52073
|
var init_webui = __esm({
|
|
51934
52074
|
"src/webui.ts"() {
|
|
51935
52075
|
"use strict";
|
|
@@ -51937,12 +52077,54 @@ var init_webui = __esm({
|
|
|
51937
52077
|
init_src6();
|
|
51938
52078
|
init_src5();
|
|
51939
52079
|
init_agent_signals();
|
|
52080
|
+
init_recall_card();
|
|
51940
52081
|
init_review2();
|
|
51941
52082
|
init_vfile();
|
|
51942
52083
|
init_tool_index();
|
|
51943
52084
|
init_outbox();
|
|
51944
52085
|
init_message_accumulator();
|
|
51945
52086
|
messageAccumulator = createMessageAccumulator();
|
|
52087
|
+
GENERIC_ERROR_WORDS = /* @__PURE__ */ new Set([
|
|
52088
|
+
"cannot",
|
|
52089
|
+
"error",
|
|
52090
|
+
"errors",
|
|
52091
|
+
"failed",
|
|
52092
|
+
"failure",
|
|
52093
|
+
"found",
|
|
52094
|
+
"install",
|
|
52095
|
+
"installed",
|
|
52096
|
+
"module",
|
|
52097
|
+
"command",
|
|
52098
|
+
"because",
|
|
52099
|
+
"while",
|
|
52100
|
+
"could",
|
|
52101
|
+
"should",
|
|
52102
|
+
"which",
|
|
52103
|
+
"there",
|
|
52104
|
+
"their",
|
|
52105
|
+
"about",
|
|
52106
|
+
"after",
|
|
52107
|
+
"before",
|
|
52108
|
+
"update",
|
|
52109
|
+
"warning",
|
|
52110
|
+
"expected",
|
|
52111
|
+
"received",
|
|
52112
|
+
"value",
|
|
52113
|
+
"undefined",
|
|
52114
|
+
"unable",
|
|
52115
|
+
"invalid",
|
|
52116
|
+
"missing",
|
|
52117
|
+
"exited",
|
|
52118
|
+
"unknown",
|
|
52119
|
+
"files",
|
|
52120
|
+
"directory",
|
|
52121
|
+
"process",
|
|
52122
|
+
"access",
|
|
52123
|
+
"denied",
|
|
52124
|
+
"permission",
|
|
52125
|
+
"running",
|
|
52126
|
+
"argument"
|
|
52127
|
+
]);
|
|
51946
52128
|
wsPackagesCache = /* @__PURE__ */ new WeakMap();
|
|
51947
52129
|
WS_PACKAGES_TTL_MS = 6e4;
|
|
51948
52130
|
loggedToolSessions = /* @__PURE__ */ new Set();
|
|
@@ -55730,8 +55912,8 @@ var require_webidl = __commonJS({
|
|
|
55730
55912
|
return new TypeError(`${message2.header}: ${message2.message}`);
|
|
55731
55913
|
};
|
|
55732
55914
|
webidl.errors.conversionFailed = function(context) {
|
|
55733
|
-
const
|
|
55734
|
-
const message2 = `${context.argument} could not be converted to${
|
|
55915
|
+
const plural2 = context.types.length === 1 ? "" : " one of";
|
|
55916
|
+
const message2 = `${context.argument} could not be converted to${plural2}: ${context.types.join(", ")}.`;
|
|
55735
55917
|
return webidl.errors.exception({
|
|
55736
55918
|
header: context.prefix,
|
|
55737
55919
|
message: message2
|
|
@@ -63095,9 +63277,9 @@ var require_pluralizer = __commonJS({
|
|
|
63095
63277
|
this: "these"
|
|
63096
63278
|
};
|
|
63097
63279
|
module2.exports = class Pluralizer {
|
|
63098
|
-
constructor(singular,
|
|
63280
|
+
constructor(singular, plural2) {
|
|
63099
63281
|
this.singular = singular;
|
|
63100
|
-
this.plural =
|
|
63282
|
+
this.plural = plural2;
|
|
63101
63283
|
}
|
|
63102
63284
|
pluralize(count) {
|
|
63103
63285
|
const one = count === 1;
|
|
@@ -71202,7 +71384,7 @@ var init_report_render = __esm({
|
|
|
71202
71384
|
// src/cli.ts
|
|
71203
71385
|
init_src6();
|
|
71204
71386
|
import { closeSync as closeSync2, existsSync as existsSync34, openSync as openSync2, readFileSync as readFileSync35, renameSync as renameSync4, statSync as statSync9 } from "node:fs";
|
|
71205
|
-
import { join as
|
|
71387
|
+
import { join as join42, resolve as pathResolve2 } from "node:path";
|
|
71206
71388
|
import { spawn as spawn5 } from "node:child_process";
|
|
71207
71389
|
|
|
71208
71390
|
// src/daemon.ts
|
|
@@ -79251,7 +79433,7 @@ function createWorkingFileState() {
|
|
|
79251
79433
|
}
|
|
79252
79434
|
|
|
79253
79435
|
// src/tool-run-state.ts
|
|
79254
|
-
var
|
|
79436
|
+
var MAX_SESSIONS2 = 64;
|
|
79255
79437
|
var MAX_TOOLS_PER_SESSION = 64;
|
|
79256
79438
|
function createToolRunState() {
|
|
79257
79439
|
const bySession = /* @__PURE__ */ new Map();
|
|
@@ -79260,7 +79442,7 @@ function createToolRunState() {
|
|
|
79260
79442
|
if (!sessionId || toolNodeIds.length === 0) return;
|
|
79261
79443
|
let set2 = bySession.get(sessionId);
|
|
79262
79444
|
if (!set2) {
|
|
79263
|
-
if (bySession.size >=
|
|
79445
|
+
if (bySession.size >= MAX_SESSIONS2) {
|
|
79264
79446
|
const oldest = bySession.keys().next().value;
|
|
79265
79447
|
if (oldest !== void 0) bySession.delete(oldest);
|
|
79266
79448
|
}
|
|
@@ -79931,7 +80113,7 @@ function createWatchBreaker(deps) {
|
|
|
79931
80113
|
}
|
|
79932
80114
|
|
|
79933
80115
|
// src/engine.ts
|
|
79934
|
-
var DAEMON_VERSION = true ? "2.0.8-dev.
|
|
80116
|
+
var DAEMON_VERSION = true ? "2.0.8-dev.2870" : "2.0.0-alpha.0";
|
|
79935
80117
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
79936
80118
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
79937
80119
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -80364,7 +80546,7 @@ function createWorkspaceEngine(opts) {
|
|
|
80364
80546
|
}
|
|
80365
80547
|
}
|
|
80366
80548
|
};
|
|
80367
|
-
const
|
|
80549
|
+
const clip2 = (s, n) => s.length > n ? `${s.slice(0, n - 1)}\u2026` : s;
|
|
80368
80550
|
const pickReviewItems = () => {
|
|
80369
80551
|
const shared = opts.sharedStore;
|
|
80370
80552
|
if (!shared) return [];
|
|
@@ -80375,12 +80557,12 @@ function createWorkspaceEngine(opts) {
|
|
|
80375
80557
|
return [{
|
|
80376
80558
|
kind: "abstraction",
|
|
80377
80559
|
candidate: small.candidate,
|
|
80378
|
-
members: small.members.map((m) => ({ id: m.id, description:
|
|
80560
|
+
members: small.members.map((m) => ({ id: m.id, description: clip2(m.description, 110) }))
|
|
80379
80561
|
}];
|
|
80380
80562
|
}
|
|
80381
80563
|
}
|
|
80382
80564
|
const [d] = pendingDiscriminators(shared, { limit: 1 });
|
|
80383
|
-
return d ? [{ kind: "discriminator", route: d.route, presenting:
|
|
80565
|
+
return d ? [{ kind: "discriminator", route: d.route, presenting: clip2(d.presenting, 140), cause: clip2(d.cause, 140) }] : [];
|
|
80384
80566
|
} catch {
|
|
80385
80567
|
return [];
|
|
80386
80568
|
}
|
|
@@ -83358,6 +83540,7 @@ function buildDrainInstances(store, sharedStore, input) {
|
|
|
83358
83540
|
|
|
83359
83541
|
// src/multi.ts
|
|
83360
83542
|
init_webui();
|
|
83543
|
+
init_recall_card();
|
|
83361
83544
|
|
|
83362
83545
|
// src/consolidate-worker-client.ts
|
|
83363
83546
|
import { Worker as Worker2 } from "node:worker_threads";
|
|
@@ -86335,6 +86518,10 @@ async function startMultiDaemon(opts = {}) {
|
|
|
86335
86518
|
app.post("/api/message", (c) => forward(c, cwdOf, { affinity: "follow" }));
|
|
86336
86519
|
app.post("/api/session-end", (c) => forward(c, cwdOf, { affinity: "follow" }));
|
|
86337
86520
|
app.post("/api/context-inject", (c) => forward(c, cwdOf, { affinity: "follow" }));
|
|
86521
|
+
app.post("/api/statusline", async (c) => {
|
|
86522
|
+
const body2 = await c.req.json().catch(() => ({}));
|
|
86523
|
+
return c.text(statuslineText(String(body2["session_id"] ?? "")));
|
|
86524
|
+
});
|
|
86338
86525
|
for (const r of records) {
|
|
86339
86526
|
mountedIds.add(r.id);
|
|
86340
86527
|
app.route(`/ws/${r.id}`, r.webApp);
|
|
@@ -86408,9 +86595,9 @@ async function startMultiDaemon(opts = {}) {
|
|
|
86408
86595
|
const reindexAll = async (rOpts) => {
|
|
86409
86596
|
const out2 = /* @__PURE__ */ new Map();
|
|
86410
86597
|
const toIndex = records.filter((r) => rOpts?.force || r.engine.store.nodeCount() === 0);
|
|
86411
|
-
const
|
|
86598
|
+
const plural2 = (n) => `repositor${n === 1 ? "y" : "ies"}`;
|
|
86412
86599
|
if (toIndex.length > 0) {
|
|
86413
|
-
notifyEvent("index-started", `Indexing ${toIndex.length} ${
|
|
86600
|
+
notifyEvent("index-started", `Indexing ${toIndex.length} ${plural2(toIndex.length)}\u2026`);
|
|
86414
86601
|
}
|
|
86415
86602
|
let indexed = 0;
|
|
86416
86603
|
for (const r of records) {
|
|
@@ -86432,7 +86619,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
86432
86619
|
}
|
|
86433
86620
|
}
|
|
86434
86621
|
if (toIndex.length > 0) {
|
|
86435
|
-
notifyEvent("index-completed", `Indexed ${indexed} ${
|
|
86622
|
+
notifyEvent("index-completed", `Indexed ${indexed} ${plural2(indexed)}`);
|
|
86436
86623
|
}
|
|
86437
86624
|
return out2;
|
|
86438
86625
|
};
|
|
@@ -87966,6 +88153,7 @@ try {
|
|
|
87966
88153
|
const event = payload.hook_event_name;
|
|
87967
88154
|
if (!Number.isInteger(port) || port < 1 || port > 65535) process.exit(0);
|
|
87968
88155
|
const contexts = [];
|
|
88156
|
+
const messages = [];
|
|
87969
88157
|
const post = async (endpoint, relay = false) => {
|
|
87970
88158
|
try {
|
|
87971
88159
|
const response = await fetch('http://127.0.0.1:' + port + '/api/' + endpoint, {
|
|
@@ -87976,6 +88164,8 @@ try {
|
|
|
87976
88164
|
const result = await response.json();
|
|
87977
88165
|
const context = result.hookSpecificOutput?.additionalContext;
|
|
87978
88166
|
if (typeof context === 'string' && context.trim()) contexts.push(context);
|
|
88167
|
+
// The user-visible recall card; Codex renders it inline as '↳ Hook · …'.
|
|
88168
|
+
if (typeof result.systemMessage === 'string' && result.systemMessage.trim()) messages.push(result.systemMessage);
|
|
87979
88169
|
} catch { /* An unavailable daemon must never block the agent. */ }
|
|
87980
88170
|
};
|
|
87981
88171
|
if (event === 'PreToolUse' || event === 'PostToolUse') await post('hook', true);
|
|
@@ -87986,10 +88176,13 @@ try {
|
|
|
87986
88176
|
// Background extraction finishing later arrives at the next tool boundary.
|
|
87987
88177
|
await post('context-inject', true);
|
|
87988
88178
|
}
|
|
87989
|
-
if (contexts.length) {
|
|
87990
|
-
process.stdout.write(JSON.stringify({
|
|
87991
|
-
|
|
87992
|
-
|
|
88179
|
+
if (contexts.length || messages.length) {
|
|
88180
|
+
process.stdout.write(JSON.stringify({
|
|
88181
|
+
...(messages.length ? { systemMessage: messages.join('\n\n') } : {}),
|
|
88182
|
+
...(contexts.length ? { hookSpecificOutput: {
|
|
88183
|
+
hookEventName: event, additionalContext: contexts.join('\n\n'),
|
|
88184
|
+
} } : {}),
|
|
88185
|
+
}));
|
|
87993
88186
|
}
|
|
87994
88187
|
} catch { /* Invalid input is also fail-open. */ }
|
|
87995
88188
|
`;
|
|
@@ -88183,6 +88376,45 @@ function consolidationGapMs(lastPassMs, policy) {
|
|
|
88183
88376
|
return Math.max(policy.baseFloorMs, lastPassMs * policy.dutyFactor);
|
|
88184
88377
|
}
|
|
88185
88378
|
|
|
88379
|
+
// src/claude-statusline.ts
|
|
88380
|
+
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync26 } from "node:fs";
|
|
88381
|
+
import { join as join41 } from "node:path";
|
|
88382
|
+
var STATUSLINE_RELAY_SOURCE = String.raw`// errata-managed: regenerated by errata install-hooks claude
|
|
88383
|
+
import { readFileSync } from 'node:fs';
|
|
88384
|
+
|
|
88385
|
+
try {
|
|
88386
|
+
const port = Number(process.argv[2]);
|
|
88387
|
+
if (Number.isInteger(port) && port > 0 && port < 65536) {
|
|
88388
|
+
const response = await fetch('http://127.0.0.1:' + port + '/api/statusline', {
|
|
88389
|
+
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
88390
|
+
body: readFileSync(0, 'utf8') || '{}', signal: AbortSignal.timeout(800),
|
|
88391
|
+
});
|
|
88392
|
+
if (response.ok) process.stdout.write(await response.text());
|
|
88393
|
+
}
|
|
88394
|
+
} catch { /* An unavailable daemon leaves the status line empty. */ }
|
|
88395
|
+
`;
|
|
88396
|
+
var STATUSLINE_RELAY_FILE = "errata-statusline.mjs";
|
|
88397
|
+
function buildStatusLine(port, nodePath, relayPath) {
|
|
88398
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error("Invalid status line port");
|
|
88399
|
+
const q = (p) => {
|
|
88400
|
+
if (/["$`\r\n]/.test(p)) throw new Error("Unsupported character in status line path");
|
|
88401
|
+
return `"${p.replace(/\\/g, "/")}"`;
|
|
88402
|
+
};
|
|
88403
|
+
return { type: "command", command: `${q(nodePath)} ${q(relayPath)} ${port}`, padding: 0 };
|
|
88404
|
+
}
|
|
88405
|
+
function isErrataStatusLine(value) {
|
|
88406
|
+
return !!value && typeof value === "object" && typeof value["command"] === "string" && value["command"].includes(STATUSLINE_RELAY_FILE);
|
|
88407
|
+
}
|
|
88408
|
+
function installStatusLine(settings, root, port, nodePath = process.execPath) {
|
|
88409
|
+
if (settings["statusLine"] !== void 0 && !isErrataStatusLine(settings["statusLine"])) return false;
|
|
88410
|
+
const dir = join41(root, ".claude", "hooks");
|
|
88411
|
+
const relay = join41(dir, STATUSLINE_RELAY_FILE);
|
|
88412
|
+
mkdirSync10(dir, { recursive: true });
|
|
88413
|
+
writeFileSync26(relay, STATUSLINE_RELAY_SOURCE, "utf8");
|
|
88414
|
+
settings["statusLine"] = buildStatusLine(port, nodePath, relay);
|
|
88415
|
+
return true;
|
|
88416
|
+
}
|
|
88417
|
+
|
|
88186
88418
|
// src/opencode-plugin.ts
|
|
88187
88419
|
var OPENCODE_PLUGIN_MARKER = "// @inerrata opencode plugin \u2014 errata-managed (errata install-hooks opencode)";
|
|
88188
88420
|
var OPENCODE_D1_CONTRACT = "Behavioral contract: (1) On ANY error, call search() BEFORE debugging \u2014 costs ~400 tokens vs 5,000\u201350,000 cold. (2) After solving non-trivial problems, contribute back: if your harness emits typed nodes (canonicalId + label + attrs), use ingest \u2014 the typed door; otherwise call contribute(), the prose fallback. (3) Before web search, try search() first \u2014 graph is 2\u201315\xD7 cheaper. (4) At session end, review what you solved and contribute anything novel.";
|
|
@@ -88589,13 +88821,13 @@ async function cmdInit() {
|
|
|
88589
88821
|
console.log("");
|
|
88590
88822
|
console.log("installing harness hooks...");
|
|
88591
88823
|
const { existsSync: existsSync35 } = await import("node:fs");
|
|
88592
|
-
const { join:
|
|
88824
|
+
const { join: join43 } = await import("node:path");
|
|
88593
88825
|
try {
|
|
88594
88826
|
await installClaudeHooks(port);
|
|
88595
88827
|
} catch (err2) {
|
|
88596
88828
|
console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
88597
88829
|
}
|
|
88598
|
-
if (existsSync35(
|
|
88830
|
+
if (existsSync35(join43(ROOT, ".cursor"))) {
|
|
88599
88831
|
try {
|
|
88600
88832
|
await installCursorMcpConfig();
|
|
88601
88833
|
} catch (err2) {
|
|
@@ -90469,7 +90701,7 @@ async function gatherReportData(generatedAt) {
|
|
|
90469
90701
|
};
|
|
90470
90702
|
}
|
|
90471
90703
|
async function cmdReport(args2) {
|
|
90472
|
-
const { mkdirSync:
|
|
90704
|
+
const { mkdirSync: mkdirSync11, writeFileSync: writeFileSync27 } = await import("node:fs");
|
|
90473
90705
|
const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
|
|
90474
90706
|
const includeFutureVerbs = args2.includes("--future-verbs");
|
|
90475
90707
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -90480,10 +90712,10 @@ async function cmdReport(args2) {
|
|
|
90480
90712
|
process.exit(2);
|
|
90481
90713
|
}
|
|
90482
90714
|
const outDir = workspacePaths(ROOT).configDir;
|
|
90483
|
-
|
|
90715
|
+
mkdirSync11(outDir, { recursive: true });
|
|
90484
90716
|
const files = renderReport2(data, { includeFutureVerbs });
|
|
90485
|
-
for (const f of files)
|
|
90486
|
-
const indexPath =
|
|
90717
|
+
for (const f of files) writeFileSync27(join42(outDir, f.name), f.html, "utf8");
|
|
90718
|
+
const indexPath = join42(outDir, "report.html");
|
|
90487
90719
|
console.log(`report \u2192 ${indexPath}`);
|
|
90488
90720
|
console.log(
|
|
90489
90721
|
` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
|
|
@@ -90603,11 +90835,11 @@ async function cmdInstallHooks(args2) {
|
|
|
90603
90835
|
}
|
|
90604
90836
|
}
|
|
90605
90837
|
async function installOpencodePlugin(port) {
|
|
90606
|
-
const { mkdirSync:
|
|
90607
|
-
const { join:
|
|
90608
|
-
const dir =
|
|
90609
|
-
if (!existsSync35(dir))
|
|
90610
|
-
const file2 =
|
|
90838
|
+
const { mkdirSync: mkdirSync11, existsSync: existsSync35, readFileSync: readFileSync36, writeFileSync: writeFileSync27 } = await import("node:fs");
|
|
90839
|
+
const { join: join43 } = await import("node:path");
|
|
90840
|
+
const dir = join43(ROOT, ".opencode", "plugin");
|
|
90841
|
+
if (!existsSync35(dir)) mkdirSync11(dir, { recursive: true });
|
|
90842
|
+
const file2 = join43(dir, "inerrata.js");
|
|
90611
90843
|
if (existsSync35(file2)) {
|
|
90612
90844
|
const head2 = readFileSync36(file2, "utf8").split("\n")[0] ?? "";
|
|
90613
90845
|
if (head2.trim() !== OPENCODE_PLUGIN_MARKER) {
|
|
@@ -90615,8 +90847,8 @@ async function installOpencodePlugin(port) {
|
|
|
90615
90847
|
process.exit(2);
|
|
90616
90848
|
}
|
|
90617
90849
|
}
|
|
90618
|
-
|
|
90619
|
-
const cfgFile =
|
|
90850
|
+
writeFileSync27(file2, buildOpencodePluginSource(port, { version: DAEMON_VERSION }), "utf8");
|
|
90851
|
+
const cfgFile = join43(ROOT, "opencode.json");
|
|
90620
90852
|
let cfg = { $schema: "https://opencode.ai/config.json" };
|
|
90621
90853
|
if (existsSync35(cfgFile)) {
|
|
90622
90854
|
try {
|
|
@@ -90631,7 +90863,7 @@ async function installOpencodePlugin(port) {
|
|
|
90631
90863
|
if (!hadErrata) {
|
|
90632
90864
|
const inv = errataMcpInvocation();
|
|
90633
90865
|
cfg.mcp["errata"] = { type: "local", command: [inv.command, ...inv.args] };
|
|
90634
|
-
|
|
90866
|
+
writeFileSync27(cfgFile, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
90635
90867
|
}
|
|
90636
90868
|
console.log(`installed OpenCode plugin \u2192 ${file2}`);
|
|
90637
90869
|
if (hadErrata) console.log(` mcp.errata already present in ${cfgFile} \u2014 left untouched`);
|
|
@@ -90651,11 +90883,11 @@ function errataMcpInvocation() {
|
|
|
90651
90883
|
return { command: cmd2, args: args2 };
|
|
90652
90884
|
}
|
|
90653
90885
|
async function installClaudeHooks(port) {
|
|
90654
|
-
const { mkdirSync:
|
|
90655
|
-
const { join:
|
|
90656
|
-
const dir =
|
|
90657
|
-
if (!existsSync35(dir))
|
|
90658
|
-
const file2 =
|
|
90886
|
+
const { mkdirSync: mkdirSync11, existsSync: existsSync35, readFileSync: readFileSync36, writeFileSync: writeFileSync27 } = await import("node:fs");
|
|
90887
|
+
const { join: join43 } = await import("node:path");
|
|
90888
|
+
const dir = join43(ROOT, ".claude");
|
|
90889
|
+
if (!existsSync35(dir)) mkdirSync11(dir, { recursive: true });
|
|
90890
|
+
const file2 = join43(dir, "settings.json");
|
|
90659
90891
|
let settings = {};
|
|
90660
90892
|
if (existsSync35(file2)) {
|
|
90661
90893
|
try {
|
|
@@ -90677,7 +90909,8 @@ async function installClaudeHooks(port) {
|
|
|
90677
90909
|
};
|
|
90678
90910
|
for (const [event, command, eventMatcher] of [
|
|
90679
90911
|
["PreToolUse", preCmd, matcher],
|
|
90680
|
-
["PostToolUse", postCmd, postMatcher]
|
|
90912
|
+
["PostToolUse", postCmd, postMatcher],
|
|
90913
|
+
["PostToolUseFailure", postCmd, postMatcher]
|
|
90681
90914
|
]) {
|
|
90682
90915
|
const list = settings.hooks[event] ??= [];
|
|
90683
90916
|
dropErrata(list);
|
|
@@ -90705,10 +90938,20 @@ async function installClaudeHooks(port) {
|
|
|
90705
90938
|
dropErrata(list);
|
|
90706
90939
|
list.push({ hooks: [{ type: "command", command: injectCmd }] });
|
|
90707
90940
|
}
|
|
90708
|
-
|
|
90941
|
+
const { homedir: homedir8 } = await import("node:os");
|
|
90942
|
+
let userStatusLine;
|
|
90943
|
+
try {
|
|
90944
|
+
userStatusLine = JSON.parse(readFileSync36(join43(homedir8(), ".claude", "settings.json"), "utf8"))["statusLine"];
|
|
90945
|
+
} catch {
|
|
90946
|
+
}
|
|
90947
|
+
const statusLineInstalled = (userStatusLine === void 0 || isErrataStatusLine(userStatusLine)) && installStatusLine(settings, ROOT, port);
|
|
90948
|
+
writeFileSync27(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
90709
90949
|
console.log(`installed Claude Code hooks \u2192 ${file2}`);
|
|
90950
|
+
console.log(
|
|
90951
|
+
statusLineInstalled ? " status line: errata recall card in colour (daemon env ERRATA_RECALL_CARD=off hides the cards)" : " status line: kept your own \u2014 errata's recall card shows inline only"
|
|
90952
|
+
);
|
|
90710
90953
|
await installClaudeMcpConfig();
|
|
90711
|
-
const claudeMd =
|
|
90954
|
+
const claudeMd = join43(ROOT, "CLAUDE.md");
|
|
90712
90955
|
const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
|
|
90713
90956
|
if (recall.kind === "collision") {
|
|
90714
90957
|
console.warn(
|
|
@@ -90720,11 +90963,11 @@ async function installClaudeHooks(port) {
|
|
|
90720
90963
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
90721
90964
|
}
|
|
90722
90965
|
async function installClaudeMcpConfig() {
|
|
90723
|
-
const { mkdirSync:
|
|
90724
|
-
const { join:
|
|
90725
|
-
const file2 =
|
|
90966
|
+
const { mkdirSync: mkdirSync11, existsSync: existsSync35, readFileSync: readFileSync36, writeFileSync: writeFileSync27 } = await import("node:fs");
|
|
90967
|
+
const { join: join43, dirname: dirname13 } = await import("node:path");
|
|
90968
|
+
const file2 = join43(ROOT, ".mcp.json");
|
|
90726
90969
|
const dir = dirname13(file2);
|
|
90727
|
-
if (!existsSync35(dir))
|
|
90970
|
+
if (!existsSync35(dir)) mkdirSync11(dir, { recursive: true });
|
|
90728
90971
|
let cfg = {};
|
|
90729
90972
|
if (existsSync35(file2)) {
|
|
90730
90973
|
try {
|
|
@@ -90736,17 +90979,17 @@ async function installClaudeMcpConfig() {
|
|
|
90736
90979
|
}
|
|
90737
90980
|
cfg.mcpServers ??= {};
|
|
90738
90981
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
90739
|
-
|
|
90982
|
+
writeFileSync27(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
90740
90983
|
console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
|
|
90741
90984
|
console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
|
|
90742
90985
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
|
|
90743
90986
|
}
|
|
90744
90987
|
async function installCursorMcpConfig() {
|
|
90745
|
-
const { mkdirSync:
|
|
90746
|
-
const { join:
|
|
90747
|
-
const dir =
|
|
90748
|
-
if (!existsSync35(dir))
|
|
90749
|
-
const file2 =
|
|
90988
|
+
const { mkdirSync: mkdirSync11, existsSync: existsSync35, readFileSync: readFileSync36, writeFileSync: writeFileSync27 } = await import("node:fs");
|
|
90989
|
+
const { join: join43 } = await import("node:path");
|
|
90990
|
+
const dir = join43(ROOT, ".cursor");
|
|
90991
|
+
if (!existsSync35(dir)) mkdirSync11(dir, { recursive: true });
|
|
90992
|
+
const file2 = join43(dir, "mcp.json");
|
|
90750
90993
|
let cfg = {};
|
|
90751
90994
|
if (existsSync35(file2)) {
|
|
90752
90995
|
try {
|
|
@@ -90758,7 +91001,7 @@ async function installCursorMcpConfig() {
|
|
|
90758
91001
|
}
|
|
90759
91002
|
cfg.mcpServers ??= {};
|
|
90760
91003
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
90761
|
-
|
|
91004
|
+
writeFileSync27(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
90762
91005
|
console.log(`installed Cursor MCP server config \u2192 ${file2}`);
|
|
90763
91006
|
console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
|
|
90764
91007
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
|
|
@@ -90769,7 +91012,7 @@ async function installCodexHooks(port) {
|
|
|
90769
91012
|
const gitRoot = nearestGitRoot(process.cwd());
|
|
90770
91013
|
const hookRoot = gitRoot && mainCheckoutOfWorktree(gitRoot) ? gitRoot : ROOT;
|
|
90771
91014
|
const file2 = writeCodexHooks(hookRoot, port);
|
|
90772
|
-
const instructions = writeManagedBlock(
|
|
91015
|
+
const instructions = writeManagedBlock(join42(hookRoot, "AGENTS.md"), {
|
|
90773
91016
|
body: AGENTS_POINTER_BODY,
|
|
90774
91017
|
stable: true
|
|
90775
91018
|
});
|
|
@@ -91173,7 +91416,7 @@ async function cmdDash(args2) {
|
|
|
91173
91416
|
await yieldToLoop2();
|
|
91174
91417
|
try {
|
|
91175
91418
|
const items = selectDurableMemory(handle2.sharedStore, r.engine.profile);
|
|
91176
|
-
const res = bleedRules(
|
|
91419
|
+
const res = bleedRules(join42(r.root, ".claude", "rules"), items);
|
|
91177
91420
|
if (res.written || res.pruned) {
|
|
91178
91421
|
console.log(
|
|
91179
91422
|
`[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")
|