@inerrata-corporation/errata 2.0.22-dev.4148 → 2.0.22-dev.4173
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
CHANGED
|
@@ -94,7 +94,7 @@ function toCloudAttrs(attrs) {
|
|
|
94
94
|
}
|
|
95
95
|
return rest2;
|
|
96
96
|
}
|
|
97
|
-
var SEMANTIC_NODE_LABELS, ANCHOR_REFUSAL_REASONS, ROUTING_REASONS, CONTEXT_NODE_LABELS, CODE_NODE_LABELS, ALL_NODE_LABELS, STRUCTURAL_EDGES, CAUSAL_EDGES, RESOLUTION_EDGES, CONCEPTUAL_EDGES, EVIDENCE_EDGES, CODE_EDGES, BRIDGE_EDGES, IDENTITY_EDGES, JUSTIFICATION_EDGES, BELIEF_EDGES, ABSTRACTION_EDGES, DECOMPOSITION_EDGES, TRANSFER_EDGES, SOLUTION_STRUCTURE_EDGES, SUSPICION_EDGES, TAXONOMY_EDGES, TRIAGE_EDGES, GIT_EDGES, ALL_EDGE_TYPES, PAGERANK_EXCLUSIONS, EDGE_WEIGHT, EDGE_CONDUCTANCE_OVERRIDES, CAUSAL_PROTECT_EDGES, VALIDATION_SOURCES, TRUTH_KIND, ABSTRACTION_LEVEL, PROBLEM_RESOLUTION, DRIFT_KIND, TEST_PATH_RE, TEST_SCOPE_RE;
|
|
97
|
+
var SEMANTIC_NODE_LABELS, ANCHOR_REFUSAL_REASONS, ROUTING_REASONS, CONTEXT_NODE_LABELS, CODE_NODE_LABELS, ALL_NODE_LABELS, STRUCTURAL_EDGES, CAUSAL_EDGES, RESOLUTION_EDGES, CONCEPTUAL_EDGES, EVIDENCE_EDGES, CODE_EDGES, BRIDGE_EDGES, IDENTITY_EDGES, JUSTIFICATION_EDGES, BELIEF_EDGES, ABSTRACTION_EDGES, DECOMPOSITION_EDGES, TRANSFER_EDGES, PROJECT_SYNC_EDGE_TYPES, SOLUTION_STRUCTURE_EDGES, SUSPICION_EDGES, TAXONOMY_EDGES, TRIAGE_EDGES, GIT_EDGES, ALL_EDGE_TYPES, PAGERANK_EXCLUSIONS, EDGE_WEIGHT, EDGE_CONDUCTANCE_OVERRIDES, CAUSAL_PROTECT_EDGES, VALIDATION_SOURCES, TRUTH_KIND, ABSTRACTION_LEVEL, PROBLEM_RESOLUTION, DRIFT_KIND, TEST_PATH_RE, TEST_SCOPE_RE;
|
|
98
98
|
var init_castalia = __esm({
|
|
99
99
|
"../../packages/shared/src/castalia.ts"() {
|
|
100
100
|
"use strict";
|
|
@@ -321,6 +321,7 @@ var init_castalia = __esm({
|
|
|
321
321
|
ABSTRACTION_EDGES = ["GENERALIZES", "DERIVED_FROM"];
|
|
322
322
|
DECOMPOSITION_EDGES = ["SPLIT_INTO"];
|
|
323
323
|
TRANSFER_EDGES = ["MAY_RESOLVE"];
|
|
324
|
+
PROJECT_SYNC_EDGE_TYPES = ["SOLVED_BY", "CAUSED_BY", "FIXED_BY", "MAY_RESOLVE"];
|
|
324
325
|
SOLUTION_STRUCTURE_EDGES = ["BUILDS_ON", "SUPERSEDES", "ALTERNATIVE_TO"];
|
|
325
326
|
SUSPICION_EDGES = ["SUSPECTED_LINK", "REGRESSION_OF"];
|
|
326
327
|
TAXONOMY_EDGES = ["IS_A"];
|
|
@@ -1167,6 +1168,11 @@ function versionlessPurl(purl) {
|
|
|
1167
1168
|
const lastAt = purl.lastIndexOf("@");
|
|
1168
1169
|
return lastAt > lastSlash ? purl.slice(0, lastAt) : purl;
|
|
1169
1170
|
}
|
|
1171
|
+
function splitNameAtVersion(slug2) {
|
|
1172
|
+
const at = slug2.lastIndexOf("@");
|
|
1173
|
+
if (at <= 0) return { name: slug2.trim(), version: null };
|
|
1174
|
+
return { name: slug2.slice(0, at).trim(), version: slug2.slice(at + 1).trim() || null };
|
|
1175
|
+
}
|
|
1170
1176
|
function parsePackageRef(ref) {
|
|
1171
1177
|
let rest2 = ref.trim();
|
|
1172
1178
|
if (rest2.startsWith("pkg:")) {
|
|
@@ -1176,9 +1182,7 @@ function parsePackageRef(ref) {
|
|
|
1176
1182
|
const q = rest2.search(/[?#]/);
|
|
1177
1183
|
if (q !== -1) rest2 = rest2.slice(0, q);
|
|
1178
1184
|
}
|
|
1179
|
-
const
|
|
1180
|
-
const name2 = at > 0 ? rest2.slice(0, at) : rest2;
|
|
1181
|
-
const version3 = at > 0 ? rest2.slice(at + 1) || null : null;
|
|
1185
|
+
const { name: name2, version: version3 } = splitNameAtVersion(rest2);
|
|
1182
1186
|
const slug2 = (version3 ? `${name2}@${version3}` : name2).toLowerCase();
|
|
1183
1187
|
return { name: name2, version: version3, slug: slug2 };
|
|
1184
1188
|
}
|
|
@@ -17625,6 +17629,7 @@ __export(src_exports, {
|
|
|
17625
17629
|
PROBLEM_RESOLUTION: () => PROBLEM_RESOLUTION,
|
|
17626
17630
|
PROJECT_ONLY_EDGE_TYPES: () => PROJECT_ONLY_EDGE_TYPES,
|
|
17627
17631
|
PROJECT_ONLY_NODE_LABELS: () => PROJECT_ONLY_NODE_LABELS,
|
|
17632
|
+
PROJECT_SYNC_EDGE_TYPES: () => PROJECT_SYNC_EDGE_TYPES,
|
|
17628
17633
|
QUARANTINE_EXTRACTION_SOURCE_PREFIX: () => QUARANTINE_EXTRACTION_SOURCE_PREFIX,
|
|
17629
17634
|
REDACTED_CREDENTIAL: () => REDACTED_CREDENTIAL,
|
|
17630
17635
|
REDACTED_EMAIL: () => REDACTED_EMAIL,
|
|
@@ -17744,6 +17749,7 @@ __export(src_exports, {
|
|
|
17744
17749
|
sha256Short: () => sha256Short,
|
|
17745
17750
|
sidecarDropBucket: () => sidecarDropBucket,
|
|
17746
17751
|
spineDeps: () => spineDeps,
|
|
17752
|
+
splitNameAtVersion: () => splitNameAtVersion,
|
|
17747
17753
|
splitPnpmKey: () => splitPnpmKey,
|
|
17748
17754
|
stripAnchorLabels: () => stripAnchorLabels,
|
|
17749
17755
|
substituteSymbolSummaries: () => substituteSymbolSummaries,
|
|
@@ -21452,6 +21458,20 @@ CREATE INDEX IF NOT EXISTS nodes_revisit_true ON nodes(valid_from) WHERE json_ty
|
|
|
21452
21458
|
if (revived > 0) this.mutations++;
|
|
21453
21459
|
return revived;
|
|
21454
21460
|
}
|
|
21461
|
+
incomingEdgeCoverage(label, edgeTypes, cloudOnly) {
|
|
21462
|
+
if (edgeTypes.length === 0) return { count: 0, total: 0 };
|
|
21463
|
+
const r = this.db.prepare(
|
|
21464
|
+
`SELECT COUNT(*) AS total,
|
|
21465
|
+
COALESCE(SUM(CASE WHEN EXISTS (
|
|
21466
|
+
SELECT 1 FROM edges e WHERE e.to_id = n.id AND e.valid_to IS NULL
|
|
21467
|
+
AND e.type IN (${edgeTypes.map(() => "?").join(",")})
|
|
21468
|
+
) THEN 1 ELSE 0 END), 0) AS count
|
|
21469
|
+
FROM nodes n
|
|
21470
|
+
WHERE n.label = ? AND n.valid_to IS NULL
|
|
21471
|
+
AND (? = 0 OR json_extract(n.attrs_json, '$.source') = 'cloud')`
|
|
21472
|
+
).get(...edgeTypes, label, cloudOnly ? 1 : 0);
|
|
21473
|
+
return { count: Number(r.count), total: Number(r.total) };
|
|
21474
|
+
}
|
|
21455
21475
|
recentEdgeAttrCoverage(marker, attr, limit) {
|
|
21456
21476
|
const r = this.db.prepare(
|
|
21457
21477
|
`SELECT COUNT(*) AS total,
|
|
@@ -26337,6 +26357,14 @@ var init_principle_sync = __esm({
|
|
|
26337
26357
|
|
|
26338
26358
|
// ../../packages/local-graph/src/mechanism-liveness.ts
|
|
26339
26359
|
function evaluateFed(store, d) {
|
|
26360
|
+
if (d.fedIncoming) {
|
|
26361
|
+
const { count: count2, total } = store.incomingEdgeCoverage?.(
|
|
26362
|
+
d.fedIncoming.label,
|
|
26363
|
+
d.fedIncoming.edgeTypes,
|
|
26364
|
+
d.fedIncoming.cloudOnly
|
|
26365
|
+
) ?? { count: 0, total: 0 };
|
|
26366
|
+
return { count: count2, total, fraction: total === 0 ? 0 : count2 / total };
|
|
26367
|
+
}
|
|
26340
26368
|
if (d.fedEdges) {
|
|
26341
26369
|
const { count: count2, total } = store.recentEdgeAttrCoverage(
|
|
26342
26370
|
d.fedEdges.marker,
|
|
@@ -26388,7 +26416,7 @@ function evaluateMechanisms(store, invocations = /* @__PURE__ */ new Map(), mech
|
|
|
26388
26416
|
if (d.configCounter && inv?.lastTotals?.[d.configCounter] === 0) verdict = "unconfigured";
|
|
26389
26417
|
else if ((backlog ?? 0) === 0 && (!hasInput && !d.inputOptional || missingRequiredNodes)) verdict = "no-input";
|
|
26390
26418
|
else if (!inv || inv.runs === 0) verdict = "never-invoked";
|
|
26391
|
-
else if (fed.fraction < (d
|
|
26419
|
+
else if (fed.fraction < minFractionOf(d)) verdict = "starved";
|
|
26392
26420
|
else if (stalled) verdict = "stalled";
|
|
26393
26421
|
else if (effectCount === 0) verdict = "no-effect";
|
|
26394
26422
|
else verdict = "ok";
|
|
@@ -26399,7 +26427,7 @@ function evaluateMechanisms(store, invocations = /* @__PURE__ */ new Map(), mech
|
|
|
26399
26427
|
fedCount: fed.count,
|
|
26400
26428
|
fedTotal: fed.total,
|
|
26401
26429
|
fedFraction: fed.fraction,
|
|
26402
|
-
minFraction: d
|
|
26430
|
+
minFraction: minFractionOf(d),
|
|
26403
26431
|
...inv ? { lastInvokedMs: inv.lastTs } : {},
|
|
26404
26432
|
runs: inv?.runs ?? 0,
|
|
26405
26433
|
effectCount,
|
|
@@ -26411,6 +26439,9 @@ function evaluateMechanisms(store, invocations = /* @__PURE__ */ new Map(), mech
|
|
|
26411
26439
|
};
|
|
26412
26440
|
});
|
|
26413
26441
|
}
|
|
26442
|
+
function minFractionOf(d) {
|
|
26443
|
+
return d.fedIncoming?.minFraction ?? d.fedEdges?.minFraction ?? d.fed?.minFraction ?? 0;
|
|
26444
|
+
}
|
|
26414
26445
|
function formatMechanismStatus(rows, nowMs) {
|
|
26415
26446
|
return rows.map((r) => {
|
|
26416
26447
|
const pct = (r.fedFraction * 100).toFixed(r.fedFraction < 0.01 ? 2 : 1);
|
|
@@ -26697,6 +26728,25 @@ var init_mechanism_liveness = __esm({
|
|
|
26697
26728
|
// reading is IDLE — correct, and it declares no backlog on purpose.
|
|
26698
26729
|
effectCounter: "alarms",
|
|
26699
26730
|
note: "steady-state IDLE is healthy; the row exists for its invocation age"
|
|
26731
|
+
},
|
|
26732
|
+
{
|
|
26733
|
+
id: "project-causal-sync",
|
|
26734
|
+
what: "lands the cloud project stratum's SOLVED_BY/FIXED_BY edges onto the knowledge the anchor feed mirrors",
|
|
26735
|
+
// PRODUCER: the anchor feed's causal leg — `fetchProjectAnchors` returns the
|
|
26736
|
+
// edges, `syncProjectAnchors` (apps/daemon/src/project-reanchor.ts) lands or
|
|
26737
|
+
// parks them, on the `anchor-pull` beat. CONSUMERS: every local walk that
|
|
26738
|
+
// crosses Problem→Solution — errata_trace/why/burst over the store, and the
|
|
26739
|
+
// passive priming block that renders a problem with its fix. Before
|
|
26740
|
+
// PJ-sync-causal the feed mirrored 5,054 cloud Solutions on the dev checkout
|
|
26741
|
+
// with not one incoming SOLVED_BY: this row would have read 0.0% for months.
|
|
26742
|
+
pass: "anchor-pull",
|
|
26743
|
+
fedIncoming: { label: "Solution", edgeTypes: ["SOLVED_BY", "FIXED_BY"], cloudOnly: true, minFraction: 0.5 },
|
|
26744
|
+
effectCounter: "edgesLanded",
|
|
26745
|
+
// Parked edges waiting on an endpoint — a flat, non-zero backlog is a stratum
|
|
26746
|
+
// whose other ends never arrive here (a cap, or a gate that refuses them).
|
|
26747
|
+
backlogCounter: "edgesPending",
|
|
26748
|
+
requiresNodes: ["Problem"],
|
|
26749
|
+
note: "an orphaned cloud Solution reads as a fix with no problem; the one-time causal re-walk lifts this after the server ships the leg"
|
|
26700
26750
|
}
|
|
26701
26751
|
];
|
|
26702
26752
|
COLUMN_INPUTS = {
|
|
@@ -28994,7 +29044,7 @@ var init_client = __esm({
|
|
|
28994
29044
|
"GET",
|
|
28995
29045
|
`/v2/projects/${encodeURIComponent(projectId)}/anchors?since=${String(Math.max(0, Math.floor(since)))}&limit=${String(limit)}`
|
|
28996
29046
|
);
|
|
28997
|
-
const { nodes } = this.toCastalia({ nodes: res.nodes ?? [], edges: [] });
|
|
29047
|
+
const { nodes, edges } = this.toCastalia({ nodes: res.nodes ?? [], edges: res.edges ?? [] });
|
|
28998
29048
|
const anchors = (res.anchors ?? []).map((a) => ({
|
|
28999
29049
|
from: a.fromCanonicalId,
|
|
29000
29050
|
toSymbolId: a.toSymbolId,
|
|
@@ -29002,7 +29052,7 @@ var init_client = __esm({
|
|
|
29002
29052
|
attrs: a.attrs ?? {},
|
|
29003
29053
|
stampedAt: typeof a.stampedAt === "number" ? a.stampedAt : 0
|
|
29004
29054
|
}));
|
|
29005
|
-
return { nodes, anchors, cursor: typeof res.cursor === "number" ? res.cursor : since };
|
|
29055
|
+
return { nodes, edges, causalLeg: Array.isArray(res.edges), anchors, cursor: typeof res.cursor === "number" ? res.cursor : since };
|
|
29006
29056
|
}
|
|
29007
29057
|
/** Pull cloud-induced skills + the session-bootstrap prime payload. `seed` is the
|
|
29008
29058
|
* canonical ids of the agent's recent problems — the cloud ranks the skills whose
|
|
@@ -76377,8 +76427,8 @@ var init_report_render = __esm({
|
|
|
76377
76427
|
|
|
76378
76428
|
// src/cli.ts
|
|
76379
76429
|
init_src6();
|
|
76380
|
-
import { closeSync as closeSync3, existsSync as existsSync40, openSync as openSync3, readFileSync as
|
|
76381
|
-
import { join as
|
|
76430
|
+
import { closeSync as closeSync3, existsSync as existsSync40, openSync as openSync3, readFileSync as readFileSync43, renameSync as renameSync8, statSync as statSync13 } from "node:fs";
|
|
76431
|
+
import { join as join50, resolve as pathResolve2 } from "node:path";
|
|
76382
76432
|
import { spawn as spawn5 } from "node:child_process";
|
|
76383
76433
|
|
|
76384
76434
|
// src/daemon.ts
|
|
@@ -77843,9 +77893,9 @@ var NodeFsHandler = class {
|
|
|
77843
77893
|
if (this.fsw.closed) {
|
|
77844
77894
|
return;
|
|
77845
77895
|
}
|
|
77846
|
-
const
|
|
77896
|
+
const dirname18 = sysPath.dirname(file2);
|
|
77847
77897
|
const basename10 = sysPath.basename(file2);
|
|
77848
|
-
const parent = this.fsw._getWatchedDir(
|
|
77898
|
+
const parent = this.fsw._getWatchedDir(dirname18);
|
|
77849
77899
|
let prevStats = stats;
|
|
77850
77900
|
if (parent.has(basename10))
|
|
77851
77901
|
return;
|
|
@@ -77872,7 +77922,7 @@ var NodeFsHandler = class {
|
|
|
77872
77922
|
prevStats = newStats2;
|
|
77873
77923
|
}
|
|
77874
77924
|
} catch (error48) {
|
|
77875
|
-
this.fsw._remove(
|
|
77925
|
+
this.fsw._remove(dirname18, basename10);
|
|
77876
77926
|
}
|
|
77877
77927
|
} else if (parent.has(basename10)) {
|
|
77878
77928
|
const at = newStats.atimeMs;
|
|
@@ -85786,7 +85836,7 @@ function createWatchBreaker(deps) {
|
|
|
85786
85836
|
}
|
|
85787
85837
|
|
|
85788
85838
|
// src/engine.ts
|
|
85789
|
-
var DAEMON_VERSION = true ? "2.0.22-dev.
|
|
85839
|
+
var DAEMON_VERSION = true ? "2.0.22-dev.4173" : "2.0.0-alpha.0";
|
|
85790
85840
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
85791
85841
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
85792
85842
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -88912,7 +88962,7 @@ function invalidateInstanceReceipt(current, destination, failedId, mirrorLegacy)
|
|
|
88912
88962
|
// src/multi.ts
|
|
88913
88963
|
init_dist();
|
|
88914
88964
|
init_src5();
|
|
88915
|
-
import { existsSync as existsSync34, writeFileSync as
|
|
88965
|
+
import { existsSync as existsSync34, writeFileSync as writeFileSync27 } from "node:fs";
|
|
88916
88966
|
import { resolve as pathResolve } from "node:path";
|
|
88917
88967
|
|
|
88918
88968
|
// src/principle-sync.ts
|
|
@@ -90402,7 +90452,6 @@ function liveCloudClient(src) {
|
|
|
90402
90452
|
init_identity2();
|
|
90403
90453
|
|
|
90404
90454
|
// src/project-hydrate.ts
|
|
90405
|
-
init_src11();
|
|
90406
90455
|
init_profile2();
|
|
90407
90456
|
|
|
90408
90457
|
// src/project-reanchor.ts
|
|
@@ -90477,6 +90526,62 @@ async function syncHistoryCorrections(opts) {
|
|
|
90477
90526
|
}
|
|
90478
90527
|
}
|
|
90479
90528
|
|
|
90529
|
+
// src/project-reanchor.ts
|
|
90530
|
+
init_paths();
|
|
90531
|
+
|
|
90532
|
+
// src/project-sync-landing.ts
|
|
90533
|
+
init_src11();
|
|
90534
|
+
function landCloudNode(store, n, isOwnTwin) {
|
|
90535
|
+
if (store.getNode(n.id)) return "present";
|
|
90536
|
+
if (isOwnTwin) return "own";
|
|
90537
|
+
store.mergeNode(n);
|
|
90538
|
+
return "landed";
|
|
90539
|
+
}
|
|
90540
|
+
function landCloudEdge(store, e, from, to) {
|
|
90541
|
+
if (store.outEdges(from, [e.type]).some((x) => x.to === to)) return false;
|
|
90542
|
+
const id = from === e.from && to === e.to ? e.id : edgeId(from, e.type, to);
|
|
90543
|
+
if (store.getEdge(id)) return false;
|
|
90544
|
+
store.mergeEdge({ ...e, id, from, to, attrs: { ...e.attrs, source: "cloud" } });
|
|
90545
|
+
return true;
|
|
90546
|
+
}
|
|
90547
|
+
|
|
90548
|
+
// src/causal-edge-queue.ts
|
|
90549
|
+
import { readFileSync as readFileSync35, renameSync as renameSync5, writeFileSync as writeFileSync25 } from "node:fs";
|
|
90550
|
+
import { dirname as dirname13, join as join39 } from "node:path";
|
|
90551
|
+
var CAUSAL_EDGE_QUEUE_CAP = 5e3;
|
|
90552
|
+
var CAUSAL_EDGE_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
90553
|
+
function causalEdgeQueuePath(workspaceConfigDir) {
|
|
90554
|
+
return join39(workspaceConfigDir, "causal-edge-queue.json");
|
|
90555
|
+
}
|
|
90556
|
+
function parkedEdgeKey(e) {
|
|
90557
|
+
return `${e.from}|${e.type}|${e.to}`;
|
|
90558
|
+
}
|
|
90559
|
+
function loadCausalEdgeQueue(path3) {
|
|
90560
|
+
let raw2;
|
|
90561
|
+
try {
|
|
90562
|
+
raw2 = JSON.parse(readFileSync35(path3, "utf8"));
|
|
90563
|
+
} catch {
|
|
90564
|
+
return [];
|
|
90565
|
+
}
|
|
90566
|
+
if (!Array.isArray(raw2)) return [];
|
|
90567
|
+
return raw2.filter(
|
|
90568
|
+
(p) => !!p && typeof p === "object" && typeof p.ts === "number" && typeof p.edge?.from === "string" && typeof p.edge?.to === "string" && typeof p.edge?.type === "string"
|
|
90569
|
+
);
|
|
90570
|
+
}
|
|
90571
|
+
function saveCausalEdgeQueue(path3, queue) {
|
|
90572
|
+
try {
|
|
90573
|
+
const tmp = join39(dirname13(path3), `.${Date.now()}.causal-edge-queue.tmp`);
|
|
90574
|
+
writeFileSync25(tmp, JSON.stringify(queue), "utf8");
|
|
90575
|
+
renameSync5(tmp, path3);
|
|
90576
|
+
} catch {
|
|
90577
|
+
}
|
|
90578
|
+
}
|
|
90579
|
+
function pruneCausalEdgeQueue(queue, now) {
|
|
90580
|
+
const live3 = queue.filter((p) => now - p.ts < CAUSAL_EDGE_TTL_MS);
|
|
90581
|
+
if (live3.length <= CAUSAL_EDGE_QUEUE_CAP) return live3;
|
|
90582
|
+
return [...live3].sort((a, b) => a.ts - b.ts).slice(live3.length - CAUSAL_EDGE_QUEUE_CAP);
|
|
90583
|
+
}
|
|
90584
|
+
|
|
90480
90585
|
// src/project-reanchor.ts
|
|
90481
90586
|
var DEFAULT_LIMIT = 50;
|
|
90482
90587
|
var ANCHOR_SYMBOL_KINDS2 = [
|
|
@@ -90676,10 +90781,12 @@ async function reanchorProject(opts) {
|
|
|
90676
90781
|
}
|
|
90677
90782
|
var SYNC_PAGE = 200;
|
|
90678
90783
|
var SYNC_MAX_PAGES = 25;
|
|
90784
|
+
var SYNC_EDGE_TYPES = new Set(PROJECT_SYNC_EDGE_TYPES);
|
|
90679
90785
|
async function syncProjectAnchors(opts) {
|
|
90680
90786
|
const { root, profile, store, cloud, salt } = opts;
|
|
90681
90787
|
if (!profile.projectId) return { synced: false, reason: "no-project" };
|
|
90682
90788
|
const projectId = profile.projectId;
|
|
90789
|
+
const clock = opts.now ?? Date.now;
|
|
90683
90790
|
const key = `${projectId}|${salt}`;
|
|
90684
90791
|
const reverse = cachedMap(
|
|
90685
90792
|
reverseCache,
|
|
@@ -90688,23 +90795,95 @@ async function syncProjectAnchors(opts) {
|
|
|
90688
90795
|
() => buildReverseSymbolMap({ store, salt, projectId })
|
|
90689
90796
|
);
|
|
90690
90797
|
const own = cachedMap(ownCache, store, salt, () => collectLastWinsYielding(ownKnowledgeEntries({ store, salt })));
|
|
90798
|
+
const resolveKnowledge = async (id) => store.getNode(id) ? id : lookupLive(store, own, id);
|
|
90799
|
+
const queuePath = opts.edgeQueuePath ?? causalEdgeQueuePath(workspacePaths(root).configDir);
|
|
90800
|
+
let parked = pruneCausalEdgeQueue(loadCausalEdgeQueue(queuePath), clock());
|
|
90801
|
+
let parkedDirty = false;
|
|
90802
|
+
const parkedKeys = new Set(parked.map((p) => parkedEdgeKey(p.edge)));
|
|
90691
90803
|
const limit = opts.limit ?? SYNC_PAGE;
|
|
90692
90804
|
const maxPages = opts.maxPages ?? SYNC_MAX_PAGES;
|
|
90693
90805
|
let anchors = 0;
|
|
90694
90806
|
let updated = 0;
|
|
90695
90807
|
let dropped = 0;
|
|
90696
90808
|
let landed = 0;
|
|
90697
|
-
let
|
|
90809
|
+
let edgesLanded = 0;
|
|
90810
|
+
let edgesParked = 0;
|
|
90811
|
+
let edgesReplayed = 0;
|
|
90812
|
+
let persistedCursor = 0;
|
|
90813
|
+
let cursor = 0;
|
|
90814
|
+
let backfillPending = false;
|
|
90815
|
+
let backfillStarted = false;
|
|
90816
|
+
const settleEdges = async (incoming) => {
|
|
90817
|
+
for (const e of incoming) {
|
|
90818
|
+
if (!SYNC_EDGE_TYPES.has(e.type)) continue;
|
|
90819
|
+
const from = await resolveKnowledge(e.from);
|
|
90820
|
+
const to = from ? await resolveKnowledge(e.to) : null;
|
|
90821
|
+
const k = parkedEdgeKey(e);
|
|
90822
|
+
if (from && to) {
|
|
90823
|
+
if (from !== to && landCloudEdge(store, e, from, to)) edgesLanded++;
|
|
90824
|
+
if (parkedKeys.delete(k)) {
|
|
90825
|
+
parked = parked.filter((p) => parkedEdgeKey(p.edge) !== k);
|
|
90826
|
+
parkedDirty = true;
|
|
90827
|
+
}
|
|
90828
|
+
} else if (!parkedKeys.has(k)) {
|
|
90829
|
+
parkedKeys.add(k);
|
|
90830
|
+
parked.push({ edge: e, ts: clock() });
|
|
90831
|
+
parkedDirty = true;
|
|
90832
|
+
edgesParked++;
|
|
90833
|
+
}
|
|
90834
|
+
}
|
|
90835
|
+
if (parked.length === 0) return;
|
|
90836
|
+
const still = [];
|
|
90837
|
+
for (const p of parked) {
|
|
90838
|
+
const from = await resolveKnowledge(p.edge.from);
|
|
90839
|
+
const to = from ? await resolveKnowledge(p.edge.to) : null;
|
|
90840
|
+
if (from && to) {
|
|
90841
|
+
if (from !== to && landCloudEdge(store, p.edge, from, to)) edgesReplayed++;
|
|
90842
|
+
parkedKeys.delete(parkedEdgeKey(p.edge));
|
|
90843
|
+
parkedDirty = true;
|
|
90844
|
+
} else {
|
|
90845
|
+
still.push(p);
|
|
90846
|
+
}
|
|
90847
|
+
}
|
|
90848
|
+
parked = still;
|
|
90849
|
+
};
|
|
90850
|
+
const flushParked = () => {
|
|
90851
|
+
if (!parkedDirty) return;
|
|
90852
|
+
parked = pruneCausalEdgeQueue(parked, clock());
|
|
90853
|
+
saveCausalEdgeQueue(queuePath, parked);
|
|
90854
|
+
parkedDirty = false;
|
|
90855
|
+
};
|
|
90698
90856
|
try {
|
|
90699
90857
|
await syncHistoryCorrections({ root, profile, store, cloud, ...opts.correctionMirrors ? { mirrors: opts.correctionMirrors } : {} });
|
|
90858
|
+
persistedCursor = profile.projectAnchorCursor ?? 0;
|
|
90859
|
+
backfillPending = !profile.projectCausalBackfillAt;
|
|
90860
|
+
cursor = backfillPending ? 0 : persistedCursor;
|
|
90700
90861
|
for (let page = 0; page < maxPages; page++) {
|
|
90862
|
+
if (page > 0) await new Promise((r) => setImmediate(r));
|
|
90701
90863
|
const res = await cloud.getProjectAnchors(projectId, cursor, limit);
|
|
90864
|
+
if (backfillPending) {
|
|
90865
|
+
backfillPending = false;
|
|
90866
|
+
if (res.causalLeg) {
|
|
90867
|
+
profile.projectCausalBackfillAt = clock();
|
|
90868
|
+
profile.projectAnchorCursor = 0;
|
|
90869
|
+
saveProfile(root, profile);
|
|
90870
|
+
backfillStarted = persistedCursor > 0;
|
|
90871
|
+
} else if (cursor !== persistedCursor) {
|
|
90872
|
+
cursor = persistedCursor;
|
|
90873
|
+
page--;
|
|
90874
|
+
continue;
|
|
90875
|
+
}
|
|
90876
|
+
}
|
|
90702
90877
|
if (res.anchors.length === 0) break;
|
|
90703
90878
|
if ((await reverse.get()).size === 0 && (await reverse.refresh()).size === 0) {
|
|
90704
90879
|
return { synced: false, reason: "no-local-symbols" };
|
|
90705
90880
|
}
|
|
90706
|
-
const
|
|
90707
|
-
|
|
90881
|
+
for (const node2 of res.nodes) {
|
|
90882
|
+
if (store.getNode(node2.id)) continue;
|
|
90883
|
+
const ownTwin = await lookupLive(store, own, node2.id) !== null;
|
|
90884
|
+
if (landCloudNode(store, node2, ownTwin) === "landed") landed++;
|
|
90885
|
+
}
|
|
90886
|
+
const now = clock();
|
|
90708
90887
|
for (const a of res.anchors) {
|
|
90709
90888
|
if (a.type !== "ANCHORED_AT") continue;
|
|
90710
90889
|
const localTo = await lookupLive(store, reverse, a.toSymbolId);
|
|
@@ -90712,16 +90891,10 @@ async function syncProjectAnchors(opts) {
|
|
|
90712
90891
|
dropped++;
|
|
90713
90892
|
continue;
|
|
90714
90893
|
}
|
|
90715
|
-
|
|
90894
|
+
const from = await resolveKnowledge(a.from);
|
|
90716
90895
|
if (!from) {
|
|
90717
|
-
|
|
90718
|
-
|
|
90719
|
-
dropped++;
|
|
90720
|
-
continue;
|
|
90721
|
-
}
|
|
90722
|
-
store.mergeNode(node2);
|
|
90723
|
-
landed++;
|
|
90724
|
-
from = node2.id;
|
|
90896
|
+
dropped++;
|
|
90897
|
+
continue;
|
|
90725
90898
|
}
|
|
90726
90899
|
const existing = existingAnchor(store, from, localTo);
|
|
90727
90900
|
const id = existing?.id ?? edgeId(from, "ANCHORED_AT", localTo);
|
|
@@ -90753,6 +90926,8 @@ async function syncProjectAnchors(opts) {
|
|
|
90753
90926
|
if (existing) updated++;
|
|
90754
90927
|
else anchors++;
|
|
90755
90928
|
}
|
|
90929
|
+
await settleEdges(res.edges ?? []);
|
|
90930
|
+
flushParked();
|
|
90756
90931
|
const next = typeof res.cursor === "number" && res.cursor > cursor ? res.cursor : cursor;
|
|
90757
90932
|
if (next !== cursor) {
|
|
90758
90933
|
cursor = next;
|
|
@@ -90761,8 +90936,23 @@ async function syncProjectAnchors(opts) {
|
|
|
90761
90936
|
}
|
|
90762
90937
|
if (res.anchors.length < limit) break;
|
|
90763
90938
|
}
|
|
90764
|
-
|
|
90939
|
+
await settleEdges([]);
|
|
90940
|
+
flushParked();
|
|
90941
|
+
return {
|
|
90942
|
+
synced: true,
|
|
90943
|
+
anchors,
|
|
90944
|
+
updated,
|
|
90945
|
+
dropped,
|
|
90946
|
+
landed,
|
|
90947
|
+
cursor,
|
|
90948
|
+
edgesLanded,
|
|
90949
|
+
edgesParked,
|
|
90950
|
+
edgesReplayed,
|
|
90951
|
+
edgesPending: parked.length,
|
|
90952
|
+
backfillStarted
|
|
90953
|
+
};
|
|
90765
90954
|
} catch (err2) {
|
|
90955
|
+
flushParked();
|
|
90766
90956
|
return { synced: false, reason: "error", detail: err2 instanceof Error ? err2.message : String(err2) };
|
|
90767
90957
|
}
|
|
90768
90958
|
}
|
|
@@ -90780,24 +90970,16 @@ async function hydrateProject(opts) {
|
|
|
90780
90970
|
let landedNodes = 0;
|
|
90781
90971
|
let ownNodes = 0;
|
|
90782
90972
|
for (const n of res.nodes) {
|
|
90783
|
-
|
|
90784
|
-
if (own
|
|
90785
|
-
|
|
90786
|
-
continue;
|
|
90787
|
-
}
|
|
90788
|
-
store.mergeNode(n);
|
|
90789
|
-
landedNodes++;
|
|
90973
|
+
const landing = landCloudNode(store, n, own.has(n.id));
|
|
90974
|
+
if (landing === "own") ownNodes++;
|
|
90975
|
+
else if (landing === "landed") landedNodes++;
|
|
90790
90976
|
}
|
|
90791
90977
|
let landedEdges = 0;
|
|
90792
90978
|
for (const e of res.edges) {
|
|
90793
90979
|
const from = localId(e.from);
|
|
90794
90980
|
const to = localId(e.to);
|
|
90795
90981
|
if (!from || !to) continue;
|
|
90796
|
-
if (store
|
|
90797
|
-
const id = from === e.from && to === e.to ? e.id : edgeId(from, e.type, to);
|
|
90798
|
-
if (store.getEdge(id)) continue;
|
|
90799
|
-
store.mergeEdge({ ...e, id, from, to });
|
|
90800
|
-
landedEdges++;
|
|
90982
|
+
if (landCloudEdge(store, e, from, to)) landedEdges++;
|
|
90801
90983
|
}
|
|
90802
90984
|
profile.projectHydratedAt = Date.now();
|
|
90803
90985
|
saveProfile(root, profile);
|
|
@@ -91061,8 +91243,8 @@ async function syncHistoryRevisionPage(opts) {
|
|
|
91061
91243
|
init_src7();
|
|
91062
91244
|
init_src();
|
|
91063
91245
|
import { execFile as execFile6 } from "node:child_process";
|
|
91064
|
-
import { readFileSync as
|
|
91065
|
-
import { join as
|
|
91246
|
+
import { readFileSync as readFileSync36 } from "node:fs";
|
|
91247
|
+
import { join as join40 } from "node:path";
|
|
91066
91248
|
import { promisify as promisify5 } from "node:util";
|
|
91067
91249
|
|
|
91068
91250
|
// src/history-walk.ts
|
|
@@ -91614,7 +91796,7 @@ async function defaultGit(root, args2) {
|
|
|
91614
91796
|
function readIgnoreLines(root, profile) {
|
|
91615
91797
|
let lines = [];
|
|
91616
91798
|
try {
|
|
91617
|
-
lines =
|
|
91799
|
+
lines = readFileSync36(join40(root, ".errataignore"), "utf8").split("\n");
|
|
91618
91800
|
} catch {
|
|
91619
91801
|
}
|
|
91620
91802
|
return [...lines, ...profile.ignoreExtra ?? []].map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
@@ -92190,8 +92372,8 @@ async function startHistoryStage(root, input, client, walk11 = {}) {
|
|
|
92190
92372
|
init_cloud_auth();
|
|
92191
92373
|
import { createHash as createHash19 } from "node:crypto";
|
|
92192
92374
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
92193
|
-
import { existsSync as existsSync32, writeFileSync as
|
|
92194
|
-
import { join as
|
|
92375
|
+
import { existsSync as existsSync32, writeFileSync as writeFileSync26 } from "node:fs";
|
|
92376
|
+
import { join as join41 } from "node:path";
|
|
92195
92377
|
|
|
92196
92378
|
// src/device-poll.ts
|
|
92197
92379
|
var THROTTLED_POLL_MIN_WAIT_MS = 11e3;
|
|
@@ -92650,9 +92832,9 @@ function applyLinkDecision(root, profile, config2, decision, now = Date.now) {
|
|
|
92650
92832
|
delete nextProfile.projectLinkHold;
|
|
92651
92833
|
let wroteIgnore = false;
|
|
92652
92834
|
if (decision.writeIgnoreStarter !== false) {
|
|
92653
|
-
const target =
|
|
92835
|
+
const target = join41(root, ".errataignore");
|
|
92654
92836
|
if (!existsSync32(target)) {
|
|
92655
|
-
|
|
92837
|
+
writeFileSync26(target, IGNORE_STARTER, "utf8");
|
|
92656
92838
|
wroteIgnore = true;
|
|
92657
92839
|
}
|
|
92658
92840
|
}
|
|
@@ -92666,12 +92848,12 @@ init_registry();
|
|
|
92666
92848
|
// src/adopt.ts
|
|
92667
92849
|
init_git_remote();
|
|
92668
92850
|
import { existsSync as existsSync33 } from "node:fs";
|
|
92669
|
-
import { dirname as
|
|
92851
|
+
import { dirname as dirname14, join as join42 } from "node:path";
|
|
92670
92852
|
function findGitRoot(absPath) {
|
|
92671
92853
|
let dir = absPath;
|
|
92672
92854
|
for (let depth = 0; depth < 64; depth++) {
|
|
92673
|
-
if (existsSync33(
|
|
92674
|
-
const parent =
|
|
92855
|
+
if (existsSync33(join42(dir, ".git"))) return dir;
|
|
92856
|
+
const parent = dirname14(dir);
|
|
92675
92857
|
if (parent === dir) return null;
|
|
92676
92858
|
dir = parent;
|
|
92677
92859
|
}
|
|
@@ -93388,7 +93570,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
93388
93570
|
records.push(rec);
|
|
93389
93571
|
void ambientLinkAll();
|
|
93390
93572
|
try {
|
|
93391
|
-
|
|
93573
|
+
writeFileSync27(
|
|
93392
93574
|
rec.engine.paths.daemonLock,
|
|
93393
93575
|
daemonLockPayload({
|
|
93394
93576
|
pid: process.pid,
|
|
@@ -93767,7 +93949,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
93767
93949
|
baseUrl = `http://127.0.0.1:${port}`;
|
|
93768
93950
|
try {
|
|
93769
93951
|
ensureDir(globalDir());
|
|
93770
|
-
|
|
93952
|
+
writeFileSync27(
|
|
93771
93953
|
lockPath,
|
|
93772
93954
|
daemonLockPayload({ pid: process.pid, webUiUrl: baseUrl, processStartedAt: PROCESS_STARTED_AT, entry: SELF_ENTRY, version: DAEMON_VERSION }),
|
|
93773
93955
|
"utf8"
|
|
@@ -93776,7 +93958,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
93776
93958
|
}
|
|
93777
93959
|
for (const r of records) {
|
|
93778
93960
|
try {
|
|
93779
|
-
|
|
93961
|
+
writeFileSync27(
|
|
93780
93962
|
r.engine.paths.daemonLock,
|
|
93781
93963
|
daemonLockPayload({
|
|
93782
93964
|
pid: process.pid,
|
|
@@ -93818,6 +94000,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
93818
94000
|
const lastAnchorPull = /* @__PURE__ */ new Map();
|
|
93819
94001
|
const pullProjectAnchors = async (r, client, salt) => {
|
|
93820
94002
|
const donePass = markPass(`anchor-pull:${r.engine.profile.name}`);
|
|
94003
|
+
const pullStartedAt = Date.now();
|
|
93821
94004
|
const beforeCorrections = r.engine.profile.projectHistoryCorrectionCursor ?? 0;
|
|
93822
94005
|
const sync = await syncProjectAnchors({
|
|
93823
94006
|
root: r.root,
|
|
@@ -93839,10 +94022,22 @@ async function startMultiDaemon(opts = {}) {
|
|
|
93839
94022
|
console.warn(`[errata] history revision reconciliation failed for ${r.engine.profile.name}: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
93840
94023
|
}
|
|
93841
94024
|
if (sync.synced) {
|
|
93842
|
-
|
|
94025
|
+
appendPassLedger(r.engine.paths.configDir, "anchor-pull", Date.now() - pullStartedAt, {
|
|
94026
|
+
anchorsLanded: sync.anchors,
|
|
94027
|
+
anchorsUpdated: sync.updated,
|
|
94028
|
+
nodesLanded: sync.landed,
|
|
94029
|
+
edgesLanded: sync.edgesLanded + sync.edgesReplayed,
|
|
94030
|
+
edgesParked: sync.edgesParked,
|
|
94031
|
+
edgesReplayed: sync.edgesReplayed,
|
|
94032
|
+
edgesPending: sync.edgesPending
|
|
94033
|
+
});
|
|
94034
|
+
if (sync.backfillStarted) {
|
|
94035
|
+
console.log(`[errata] causal re-walk started for ${r.engine.profile.name} \u2014 anchor cursor reset to 0 once`);
|
|
94036
|
+
}
|
|
94037
|
+
if (sync.anchors + sync.updated + sync.landed + sync.edgesLanded + sync.edgesReplayed > 0) {
|
|
93843
94038
|
r.engine.markContextDirty();
|
|
93844
94039
|
console.log(
|
|
93845
|
-
`[errata] anchors pulled for ${r.engine.profile.name} \u2014 ${sync.anchors} new, ${sync.updated} re-versioned, ${sync.dropped} unresolved (${sync.landed} priors landed, cursor ${sync.cursor})`
|
|
94040
|
+
`[errata] anchors pulled for ${r.engine.profile.name} \u2014 ${sync.anchors} new, ${sync.updated} re-versioned, ${sync.dropped} unresolved (${sync.landed} priors landed, ${sync.edgesLanded + sync.edgesReplayed} causal edges landed, ${sync.edgesPending} parked, cursor ${sync.cursor})`
|
|
93846
94041
|
);
|
|
93847
94042
|
}
|
|
93848
94043
|
} else if (sync.reason === "error") {
|
|
@@ -95258,7 +95453,7 @@ import { spawnSync as spawnSync2 } from "node:child_process";
|
|
|
95258
95453
|
|
|
95259
95454
|
// src/codex-runtime.ts
|
|
95260
95455
|
import { readdirSync as readdirSync13, statSync as statSync10 } from "node:fs";
|
|
95261
|
-
import { join as
|
|
95456
|
+
import { join as join43 } from "node:path";
|
|
95262
95457
|
function resolveCodexExecutable(options = {}) {
|
|
95263
95458
|
const platform = options.platform ?? process.platform;
|
|
95264
95459
|
const env2 = options.env ?? process.env;
|
|
@@ -95273,13 +95468,13 @@ function resolveCodexExecutable(options = {}) {
|
|
|
95273
95468
|
};
|
|
95274
95469
|
for (const dir of (env2["PATH"] ?? env2["Path"] ?? "").split(";")) {
|
|
95275
95470
|
if (!dir.trim()) continue;
|
|
95276
|
-
const path3 =
|
|
95471
|
+
const path3 = join43(dir.trim().replace(/^"|"$/g, ""), "codex.exe");
|
|
95277
95472
|
if (fileTime(path3) !== null) return path3;
|
|
95278
95473
|
}
|
|
95279
95474
|
if (!env2["LOCALAPPDATA"]) return "codex";
|
|
95280
|
-
const root =
|
|
95475
|
+
const root = join43(env2["LOCALAPPDATA"], "OpenAI", "Codex", "bin");
|
|
95281
95476
|
try {
|
|
95282
|
-
const candidates = readdirSync13(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) =>
|
|
95477
|
+
const candidates = readdirSync13(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join43(root, entry.name, "codex.exe")).map((path3) => ({ path: path3, mtime: fileTime(path3) })).filter((candidate) => candidate.mtime !== null).sort((a, b) => b.mtime - a.mtime || a.path.localeCompare(b.path));
|
|
95283
95478
|
return candidates[0]?.path ?? "codex";
|
|
95284
95479
|
} catch {
|
|
95285
95480
|
return "codex";
|
|
@@ -95418,14 +95613,14 @@ async function diagnoseInstallation(cfg, dependencies) {
|
|
|
95418
95613
|
|
|
95419
95614
|
// src/codex-doctor.ts
|
|
95420
95615
|
import { spawn as spawn4 } from "node:child_process";
|
|
95421
|
-
import { readFileSync as
|
|
95422
|
-
import { join as
|
|
95616
|
+
import { readFileSync as readFileSync38, statSync as statSync11 } from "node:fs";
|
|
95617
|
+
import { join as join45 } from "node:path";
|
|
95423
95618
|
import { createInterface } from "node:readline";
|
|
95424
95619
|
|
|
95425
95620
|
// src/codex-hooks.ts
|
|
95426
|
-
import { existsSync as existsSync35, mkdirSync as mkdirSync9, readFileSync as
|
|
95621
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync9, readFileSync as readFileSync37, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync28 } from "node:fs";
|
|
95427
95622
|
import { homedir as homedir7 } from "node:os";
|
|
95428
|
-
import { join as
|
|
95623
|
+
import { join as join44 } from "node:path";
|
|
95429
95624
|
|
|
95430
95625
|
// src/hook-commands.ts
|
|
95431
95626
|
function hookCurlCommand(port, path3 = "/api/hook") {
|
|
@@ -95629,34 +95824,34 @@ function buildCodexRelaySource(workspaceRoot) {
|
|
|
95629
95824
|
init_checkout_root();
|
|
95630
95825
|
var CODEX_HOOK_REVIEW_HELP = "Codex desktop: Settings > Hooks, select this project, expand each event and Trust the Errata hook. CLI users can use /hooks.";
|
|
95631
95826
|
function writeRelay(file2, source) {
|
|
95632
|
-
if (existsSync35(file2) &&
|
|
95827
|
+
if (existsSync35(file2) && readFileSync37(file2, "utf8") === source) return;
|
|
95633
95828
|
const temp = `${file2}.${process.pid}.tmp`;
|
|
95634
95829
|
try {
|
|
95635
|
-
|
|
95636
|
-
|
|
95830
|
+
writeFileSync28(temp, source, { encoding: "utf8", mode: 384 });
|
|
95831
|
+
renameSync6(temp, file2);
|
|
95637
95832
|
} finally {
|
|
95638
95833
|
if (existsSync35(temp)) unlinkSync5(temp);
|
|
95639
95834
|
}
|
|
95640
95835
|
}
|
|
95641
95836
|
function refreshCodexRelay(root) {
|
|
95642
|
-
const config2 =
|
|
95837
|
+
const config2 = join44(root, ".codex", "config.toml");
|
|
95643
95838
|
if (!existsSync35(config2)) return "absent";
|
|
95644
|
-
const existing =
|
|
95839
|
+
const existing = readFileSync37(config2, "utf8");
|
|
95645
95840
|
if (!existing.includes(CODEX_HOOKS_BEGIN) && !existing.includes(CODEX_HOOKS_END)) return "absent";
|
|
95646
95841
|
replaceCodexHooks(existing, "");
|
|
95647
|
-
const relay =
|
|
95648
|
-
const prior = existsSync35(relay) ?
|
|
95842
|
+
const relay = join44(root, ".codex", "hooks", "errata-relay.mjs");
|
|
95843
|
+
const prior = existsSync35(relay) ? readFileSync37(relay, "utf8") : "";
|
|
95649
95844
|
if (prior && !prior.startsWith("// errata-managed: regenerated by errata install-hooks codex")) {
|
|
95650
95845
|
throw new Error("Codex relay is not Errata-managed; preserved it. Run errata install-hooks codex to explicitly replace it.");
|
|
95651
95846
|
}
|
|
95652
95847
|
const source = buildCodexRelaySource(checkoutRootOf(root));
|
|
95653
95848
|
if (prior === source) return "current";
|
|
95654
|
-
mkdirSync9(
|
|
95849
|
+
mkdirSync9(join44(root, ".codex", "hooks"), { recursive: true });
|
|
95655
95850
|
writeRelay(relay, source);
|
|
95656
95851
|
return "updated";
|
|
95657
95852
|
}
|
|
95658
|
-
function hasCodexConfig(root, codexHome = process.env["CODEX_HOME"] ||
|
|
95659
|
-
return existsSync35(
|
|
95853
|
+
function hasCodexConfig(root, codexHome = process.env["CODEX_HOME"] || join44(homedir7(), ".codex")) {
|
|
95854
|
+
return existsSync35(join44(root, ".codex")) || existsSync35(codexHome);
|
|
95660
95855
|
}
|
|
95661
95856
|
function replaceCodexHooks(existing, block) {
|
|
95662
95857
|
const begin = existing.indexOf(CODEX_HOOKS_BEGIN);
|
|
@@ -95672,14 +95867,14 @@ function replaceCodexHooks(existing, block) {
|
|
|
95672
95867
|
return existing.trimEnd() + (existing.trim() ? "\n\n" : "") + block;
|
|
95673
95868
|
}
|
|
95674
95869
|
function writeCodexHooks(root, port, nodePath = process.execPath) {
|
|
95675
|
-
const dir =
|
|
95676
|
-
const file2 =
|
|
95677
|
-
const relay =
|
|
95870
|
+
const dir = join44(root, ".codex");
|
|
95871
|
+
const file2 = join44(dir, "config.toml");
|
|
95872
|
+
const relay = join44(dir, "hooks", "errata-relay.mjs");
|
|
95678
95873
|
const block = buildCodexHooksToml(port, { nodePath, relayPath: relay });
|
|
95679
|
-
const final = replaceCodexHooks(existsSync35(file2) ?
|
|
95680
|
-
mkdirSync9(
|
|
95874
|
+
const final = replaceCodexHooks(existsSync35(file2) ? readFileSync37(file2, "utf8") : "", block);
|
|
95875
|
+
mkdirSync9(join44(dir, "hooks"), { recursive: true });
|
|
95681
95876
|
writeRelay(relay, buildCodexRelaySource(checkoutRootOf(root)));
|
|
95682
|
-
if (!existsSync35(file2) ||
|
|
95877
|
+
if (!existsSync35(file2) || readFileSync37(file2, "utf8") !== final) writeFileSync28(file2, final, "utf8");
|
|
95683
95878
|
return file2;
|
|
95684
95879
|
}
|
|
95685
95880
|
|
|
@@ -95688,7 +95883,7 @@ init_checkout_root();
|
|
|
95688
95883
|
function inspectCodexRelay(cwd) {
|
|
95689
95884
|
const root = nearestGitRoot(cwd) ?? cwd;
|
|
95690
95885
|
try {
|
|
95691
|
-
const source =
|
|
95886
|
+
const source = readFileSync38(join45(root, ".codex", "hooks", "errata-relay.mjs"), "utf8");
|
|
95692
95887
|
if (source === buildCodexRelaySource(checkoutRootOf(root))) {
|
|
95693
95888
|
return { id: "codex_relay", status: "pass", detail: "Installed Codex relay matches this Errata version" };
|
|
95694
95889
|
}
|
|
@@ -95699,8 +95894,8 @@ function inspectCodexRelay(cwd) {
|
|
|
95699
95894
|
function inspectCodexContext(cwd) {
|
|
95700
95895
|
const root = checkoutRootOf(nearestGitRoot(cwd) ?? cwd);
|
|
95701
95896
|
try {
|
|
95702
|
-
const file2 =
|
|
95703
|
-
if (statSync11(file2).size <= 128 * 1024 &&
|
|
95897
|
+
const file2 = join45(root, ".errata", "context.md");
|
|
95898
|
+
if (statSync11(file2).size <= 128 * 1024 && readFileSync38(file2, "utf8").trim()) {
|
|
95704
95899
|
return { id: "codex_context", status: "pass", detail: "Saved workspace context is readable by the relay; this does not prove live daemon freshness" };
|
|
95705
95900
|
}
|
|
95706
95901
|
} catch {
|
|
@@ -95878,9 +96073,9 @@ function consolidationGapMs(lastPassMs, policy) {
|
|
|
95878
96073
|
|
|
95879
96074
|
// src/codex-context-plugin.ts
|
|
95880
96075
|
import { createHash as createHash20 } from "node:crypto";
|
|
95881
|
-
import { cpSync as cpSync2, existsSync as existsSync36, mkdirSync as mkdirSync10, readFileSync as
|
|
96076
|
+
import { cpSync as cpSync2, existsSync as existsSync36, mkdirSync as mkdirSync10, readFileSync as readFileSync39, renameSync as renameSync7, writeFileSync as writeFileSync29 } from "node:fs";
|
|
95882
96077
|
import { homedir as homedir8 } from "node:os";
|
|
95883
|
-
import { join as
|
|
96078
|
+
import { join as join46 } from "node:path";
|
|
95884
96079
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
95885
96080
|
|
|
95886
96081
|
// ../../node_modules/.pnpm/smol-toml@1.6.1/node_modules/smol-toml/dist/error.js
|
|
@@ -96578,23 +96773,23 @@ var NAME = "errata-context";
|
|
|
96578
96773
|
var PREFIX2 = `./.errata/plugins/${NAME}/`;
|
|
96579
96774
|
var object2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
96580
96775
|
function readText(file2) {
|
|
96581
|
-
return existsSync36(file2) ?
|
|
96776
|
+
return existsSync36(file2) ? readFileSync39(file2, "utf8") : "";
|
|
96582
96777
|
}
|
|
96583
96778
|
function writeChanged(file2, content) {
|
|
96584
96779
|
if (readText(file2) === content) return;
|
|
96585
96780
|
const temp = `${file2}.${process.pid}.tmp`;
|
|
96586
|
-
|
|
96587
|
-
|
|
96781
|
+
writeFileSync29(temp, content, "utf8");
|
|
96782
|
+
renameSync7(temp, file2);
|
|
96588
96783
|
}
|
|
96589
96784
|
function bundledContextPlugin() {
|
|
96590
96785
|
const packaged = fileURLToPath2(new URL("./resources/context-plugin/", import.meta.url));
|
|
96591
|
-
if (existsSync36(
|
|
96786
|
+
if (existsSync36(join46(packaged, ".codex-plugin/plugin.json"))) return packaged;
|
|
96592
96787
|
return fileURLToPath2(new URL("../dist/resources/context-plugin/", import.meta.url));
|
|
96593
96788
|
}
|
|
96594
96789
|
function refreshCodexContextPlugin(root) {
|
|
96595
|
-
const file2 =
|
|
96790
|
+
const file2 = join46(root, ".agents", "plugins", "marketplace.json");
|
|
96596
96791
|
if (!existsSync36(file2)) return false;
|
|
96597
|
-
const marketplace = JSON.parse(
|
|
96792
|
+
const marketplace = JSON.parse(readFileSync39(file2, "utf8"));
|
|
96598
96793
|
const entries = Array.isArray(marketplace.plugins) ? marketplace.plugins : [];
|
|
96599
96794
|
const entry = entries.map(object2).find((value) => value.name === NAME && String(object2(value.source).path).startsWith(PREFIX2));
|
|
96600
96795
|
if (!entry) return false;
|
|
@@ -96605,24 +96800,24 @@ function refreshCodexContextPlugin(root) {
|
|
|
96605
96800
|
function installCodexContextPlugin(root, options = {}) {
|
|
96606
96801
|
const bundle = options.bundle ?? bundledContextPlugin();
|
|
96607
96802
|
const manifest = JSON.parse(
|
|
96608
|
-
|
|
96803
|
+
readFileSync39(join46(bundle, ".codex-plugin/plugin.json"), "utf8")
|
|
96609
96804
|
);
|
|
96610
96805
|
if (manifest.name !== NAME || typeof manifest.version !== "string" || !/^[\w.-]+$/.test(manifest.version)) {
|
|
96611
96806
|
throw new Error("Invalid bundled Errata Context manifest.");
|
|
96612
96807
|
}
|
|
96613
|
-
const checksums =
|
|
96808
|
+
const checksums = readFileSync39(join46(bundle, "SHA256SUMS"), "utf8");
|
|
96614
96809
|
for (const line of checksums.trim().split("\n")) {
|
|
96615
96810
|
const match2 = /^([a-f0-9]{64}) ([\w./-]+)$/.exec(line);
|
|
96616
96811
|
if (!match2 || match2[2].startsWith("/") || match2[2].split("/").includes("..")) {
|
|
96617
96812
|
throw new Error("Invalid bundled Errata Context checksum manifest.");
|
|
96618
96813
|
}
|
|
96619
|
-
const actual = createHash20("sha256").update(
|
|
96814
|
+
const actual = createHash20("sha256").update(readFileSync39(join46(bundle, match2[2]))).digest("hex");
|
|
96620
96815
|
if (actual !== match2[1])
|
|
96621
96816
|
throw new Error(`Bundled Errata Context checksum mismatch: ${match2[2]}`);
|
|
96622
96817
|
}
|
|
96623
96818
|
const release = `${manifest.version}-${createHash20("sha256").update(checksums).digest("hex").slice(0, 12)}`;
|
|
96624
|
-
const plugin =
|
|
96625
|
-
const marketplaceFile =
|
|
96819
|
+
const plugin = join46(root, ".errata", "plugins", NAME, release);
|
|
96820
|
+
const marketplaceFile = join46(root, ".agents", "plugins", "marketplace.json");
|
|
96626
96821
|
const priorMarketplace = readText(marketplaceFile);
|
|
96627
96822
|
const marketplace = priorMarketplace ? JSON.parse(priorMarketplace) : {
|
|
96628
96823
|
name: "errata-local",
|
|
@@ -96643,12 +96838,12 @@ function installCodexContextPlugin(root, options = {}) {
|
|
|
96643
96838
|
);
|
|
96644
96839
|
}
|
|
96645
96840
|
const key = `${NAME}@${marketplace.name}`;
|
|
96646
|
-
const configFile =
|
|
96841
|
+
const configFile = join46(root, ".codex", "config.toml");
|
|
96647
96842
|
const config2 = readText(configFile);
|
|
96648
96843
|
const parsed = parse4(config2);
|
|
96649
96844
|
const plugins = object2(parsed.plugins);
|
|
96650
|
-
const codexHome = options.codexHome ?? process.env["CODEX_HOME"] ??
|
|
96651
|
-
const globalPlugins = object2(parse4(readText(
|
|
96845
|
+
const codexHome = options.codexHome ?? process.env["CODEX_HOME"] ?? join46(homedir8(), ".codex");
|
|
96846
|
+
const globalPlugins = object2(parse4(readText(join46(codexHome, "config.toml"))).plugins);
|
|
96652
96847
|
const disabledGlobally = Object.entries(globalPlugins).some(
|
|
96653
96848
|
([name2, value]) => (name2 === NAME || name2.startsWith(`${NAME}@`)) && object2(value).enabled === false
|
|
96654
96849
|
);
|
|
@@ -96672,13 +96867,13 @@ enabled = ${enabled}
|
|
|
96672
96867
|
mkdirSync10(plugin, { recursive: true });
|
|
96673
96868
|
cpSync2(bundle, plugin, { recursive: true });
|
|
96674
96869
|
writeChanged(
|
|
96675
|
-
|
|
96870
|
+
join46(plugin, ".mcp.json"),
|
|
96676
96871
|
JSON.stringify(
|
|
96677
96872
|
{
|
|
96678
96873
|
mcpServers: {
|
|
96679
96874
|
errata_context: {
|
|
96680
96875
|
command: options.nodePath ?? process.execPath,
|
|
96681
|
-
args: [
|
|
96876
|
+
args: [join46(plugin, "dist", "mcp-server.mjs")],
|
|
96682
96877
|
env: { ERRATA_WORKSPACE: root, ERRATA_CONTEXT_VERSION: manifest.version }
|
|
96683
96878
|
}
|
|
96684
96879
|
}
|
|
@@ -96687,8 +96882,8 @@ enabled = ${enabled}
|
|
|
96687
96882
|
2
|
|
96688
96883
|
) + "\n"
|
|
96689
96884
|
);
|
|
96690
|
-
mkdirSync10(
|
|
96691
|
-
mkdirSync10(
|
|
96885
|
+
mkdirSync10(join46(root, ".agents", "plugins"), { recursive: true });
|
|
96886
|
+
mkdirSync10(join46(root, ".codex"), { recursive: true });
|
|
96692
96887
|
writeChanged(marketplaceFile, JSON.stringify(marketplace, null, 2) + "\n");
|
|
96693
96888
|
writeChanged(configFile, nextConfig);
|
|
96694
96889
|
return { plugin, enabled, marketplace: marketplaceFile };
|
|
@@ -96696,15 +96891,15 @@ enabled = ${enabled}
|
|
|
96696
96891
|
|
|
96697
96892
|
// src/codex-hook-refresh.ts
|
|
96698
96893
|
init_checkout_root();
|
|
96699
|
-
import { existsSync as existsSync37, readdirSync as readdirSync14, readFileSync as
|
|
96700
|
-
import { dirname as
|
|
96894
|
+
import { existsSync as existsSync37, readdirSync as readdirSync14, readFileSync as readFileSync40 } from "node:fs";
|
|
96895
|
+
import { dirname as dirname15, join as join47, resolve as resolve8 } from "node:path";
|
|
96701
96896
|
init_registry();
|
|
96702
96897
|
function codexHookRoots(roots) {
|
|
96703
96898
|
const found = new Set(roots.map((root) => resolve8(root)));
|
|
96704
96899
|
for (const root of [...found]) {
|
|
96705
96900
|
const main2 = mainCheckoutOfWorktree(root) ?? root;
|
|
96706
96901
|
found.add(main2);
|
|
96707
|
-
const dir =
|
|
96902
|
+
const dir = join47(main2, ".git", "worktrees");
|
|
96708
96903
|
if (!existsSync37(dir)) continue;
|
|
96709
96904
|
let names;
|
|
96710
96905
|
try {
|
|
@@ -96714,7 +96909,7 @@ function codexHookRoots(roots) {
|
|
|
96714
96909
|
}
|
|
96715
96910
|
for (const name2 of names) {
|
|
96716
96911
|
try {
|
|
96717
|
-
const checkout =
|
|
96912
|
+
const checkout = dirname15(readFileSync40(join47(dir, name2, "gitdir"), "utf8").trim());
|
|
96718
96913
|
if (mainCheckoutOfWorktree(checkout) === main2) found.add(checkout);
|
|
96719
96914
|
} catch {
|
|
96720
96915
|
}
|
|
@@ -96736,9 +96931,9 @@ function refreshInstalledCodexRelays(roots = listWorkspaceEntries().map((entry)
|
|
|
96736
96931
|
}
|
|
96737
96932
|
|
|
96738
96933
|
// src/claude-statusline.ts
|
|
96739
|
-
import { existsSync as existsSync38, mkdirSync as mkdirSync11, readFileSync as
|
|
96934
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync11, readFileSync as readFileSync41, writeFileSync as writeFileSync30 } from "node:fs";
|
|
96740
96935
|
import { homedir as homedir9 } from "node:os";
|
|
96741
|
-
import { dirname as
|
|
96936
|
+
import { dirname as dirname16, join as join48 } from "node:path";
|
|
96742
96937
|
var STATUSLINE_RELAY_SOURCE = String.raw`// errata-managed: regenerated by errata init / install-hooks claude
|
|
96743
96938
|
import { readFileSync } from 'node:fs';
|
|
96744
96939
|
|
|
@@ -96786,8 +96981,8 @@ function isSameInstall(value, relay) {
|
|
|
96786
96981
|
return command.includes(relay.replace(/\\/g, "/").toLowerCase());
|
|
96787
96982
|
}
|
|
96788
96983
|
function userClaudeSettingsPath() {
|
|
96789
|
-
const base = process.env["CLAUDE_CONFIG_DIR"] ??
|
|
96790
|
-
return
|
|
96984
|
+
const base = process.env["CLAUDE_CONFIG_DIR"] ?? join48(homedir9(), ".claude");
|
|
96985
|
+
return join48(base, "settings.json");
|
|
96791
96986
|
}
|
|
96792
96987
|
function ensureUserStatusLine(opts) {
|
|
96793
96988
|
const env2 = opts.env ?? process.env;
|
|
@@ -96797,21 +96992,21 @@ function ensureUserStatusLine(opts) {
|
|
|
96797
96992
|
let settings = {};
|
|
96798
96993
|
if (existsSync38(settingsPath)) {
|
|
96799
96994
|
try {
|
|
96800
|
-
const parsed = JSON.parse(
|
|
96995
|
+
const parsed = JSON.parse(readFileSync41(settingsPath, "utf8"));
|
|
96801
96996
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return "unreadable";
|
|
96802
96997
|
settings = parsed;
|
|
96803
96998
|
} catch {
|
|
96804
96999
|
return "unreadable";
|
|
96805
97000
|
}
|
|
96806
97001
|
}
|
|
96807
|
-
const relay =
|
|
97002
|
+
const relay = join48(opts.relayDir, STATUSLINE_RELAY_FILE);
|
|
96808
97003
|
const keep = (value) => value !== void 0 && (!isErrataStatusLine(value) || !isSameInstall(value, relay));
|
|
96809
97004
|
const ownMain = keep(settings["statusLine"]);
|
|
96810
97005
|
const ownRows = keep(settings["subagentStatusLine"]);
|
|
96811
97006
|
if (ownMain && ownRows) return "kept-own";
|
|
96812
97007
|
mkdirSync11(opts.relayDir, { recursive: true });
|
|
96813
|
-
if (!existsSync38(relay) ||
|
|
96814
|
-
|
|
97008
|
+
if (!existsSync38(relay) || readFileSync41(relay, "utf8") !== STATUSLINE_RELAY_SOURCE) {
|
|
97009
|
+
writeFileSync30(relay, STATUSLINE_RELAY_SOURCE, "utf8");
|
|
96815
97010
|
}
|
|
96816
97011
|
const nodePath = opts.nodePath ?? process.execPath;
|
|
96817
97012
|
const next = {
|
|
@@ -96822,8 +97017,8 @@ function ensureUserStatusLine(opts) {
|
|
|
96822
97017
|
return ownMain ? "kept-own" : "unchanged";
|
|
96823
97018
|
}
|
|
96824
97019
|
Object.assign(settings, next);
|
|
96825
|
-
mkdirSync11(
|
|
96826
|
-
|
|
97020
|
+
mkdirSync11(dirname16(settingsPath), { recursive: true });
|
|
97021
|
+
writeFileSync30(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
96827
97022
|
return "installed";
|
|
96828
97023
|
}
|
|
96829
97024
|
function describeStatusLineOutcome(outcome) {
|
|
@@ -96843,8 +97038,8 @@ function describeStatusLineOutcome(outcome) {
|
|
|
96843
97038
|
|
|
96844
97039
|
// src/claude-mods.ts
|
|
96845
97040
|
import { createHash as createHash21 } from "node:crypto";
|
|
96846
|
-
import { cpSync as cpSync3, existsSync as existsSync39, mkdirSync as mkdirSync12, readFileSync as
|
|
96847
|
-
import { delimiter as delimiter2, dirname as
|
|
97041
|
+
import { cpSync as cpSync3, existsSync as existsSync39, mkdirSync as mkdirSync12, readFileSync as readFileSync42, readdirSync as readdirSync15, rmSync as rmSync4, statSync as statSync12, writeFileSync as writeFileSync31 } from "node:fs";
|
|
97042
|
+
import { delimiter as delimiter2, dirname as dirname17, join as join49, relative as relative8, resolve as resolve9, sep as sep5 } from "node:path";
|
|
96848
97043
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
96849
97044
|
var CLAUDE_PLUGIN_DIRS_ENV = "CLAUDE_CODE_PLUGIN_DIRS";
|
|
96850
97045
|
var HASH_FILE = ".errata-mod-hash";
|
|
@@ -96859,7 +97054,7 @@ function isEngineOwned(relPath) {
|
|
|
96859
97054
|
function listFiles(root, dir = root) {
|
|
96860
97055
|
const out2 = [];
|
|
96861
97056
|
for (const name2 of readdirSync15(dir)) {
|
|
96862
|
-
const abs =
|
|
97057
|
+
const abs = join49(dir, name2);
|
|
96863
97058
|
if (isEngineOwned(relative8(root, abs))) continue;
|
|
96864
97059
|
if (statSync12(abs).isDirectory()) out2.push(...listFiles(root, abs));
|
|
96865
97060
|
else out2.push(abs);
|
|
@@ -96871,14 +97066,14 @@ function modHash(dir) {
|
|
|
96871
97066
|
for (const abs of listFiles(dir).sort()) {
|
|
96872
97067
|
h.update(relative8(dir, abs).split(sep5).join("/"));
|
|
96873
97068
|
h.update("\0");
|
|
96874
|
-
h.update(
|
|
97069
|
+
h.update(readFileSync42(abs));
|
|
96875
97070
|
h.update("\0");
|
|
96876
97071
|
}
|
|
96877
97072
|
return h.digest("hex");
|
|
96878
97073
|
}
|
|
96879
97074
|
function bundledMods(bundleDir) {
|
|
96880
97075
|
if (!existsSync39(bundleDir)) return [];
|
|
96881
|
-
return readdirSync15(bundleDir).filter((name2) => existsSync39(
|
|
97076
|
+
return readdirSync15(bundleDir).filter((name2) => existsSync39(join49(bundleDir, name2, ".claude-plugin", "plugin.json")));
|
|
96882
97077
|
}
|
|
96883
97078
|
function sameDir(a, b) {
|
|
96884
97079
|
const norm = (p) => resolve9(p).replace(/[\\/]+$/, "").toLowerCase();
|
|
@@ -96895,7 +97090,7 @@ function off(env2) {
|
|
|
96895
97090
|
function readSettings(path3) {
|
|
96896
97091
|
if (!existsSync39(path3)) return {};
|
|
96897
97092
|
try {
|
|
96898
|
-
const parsed = JSON.parse(
|
|
97093
|
+
const parsed = JSON.parse(readFileSync42(path3, "utf8"));
|
|
96899
97094
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
96900
97095
|
return parsed;
|
|
96901
97096
|
} catch {
|
|
@@ -96919,13 +97114,13 @@ function currentDirs(settings) {
|
|
|
96919
97114
|
return raw2.split(delimiter2).map((s) => s.trim()).filter(Boolean);
|
|
96920
97115
|
}
|
|
96921
97116
|
function writeSettings(path3, settings) {
|
|
96922
|
-
mkdirSync12(
|
|
96923
|
-
|
|
97117
|
+
mkdirSync12(dirname17(path3), { recursive: true });
|
|
97118
|
+
writeFileSync31(path3, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
96924
97119
|
}
|
|
96925
97120
|
function ensureClaudeMods(opts) {
|
|
96926
97121
|
const env2 = opts.env ?? process.env;
|
|
96927
97122
|
const settingsPath = opts.userSettingsPath ?? userClaudeSettingsPath();
|
|
96928
|
-
const modsRoot =
|
|
97123
|
+
const modsRoot = join49(opts.installRoot, "claude-mods");
|
|
96929
97124
|
if (off(env2)) {
|
|
96930
97125
|
const settings2 = readSettings(settingsPath);
|
|
96931
97126
|
if (!settings2) return { kind: "unreadable" };
|
|
@@ -96942,14 +97137,14 @@ function ensureClaudeMods(opts) {
|
|
|
96942
97137
|
let changed = false;
|
|
96943
97138
|
const installed = [];
|
|
96944
97139
|
for (const name2 of names) {
|
|
96945
|
-
const src =
|
|
96946
|
-
const dest =
|
|
97140
|
+
const src = join49(bundleDir, name2);
|
|
97141
|
+
const dest = join49(modsRoot, name2);
|
|
96947
97142
|
const hash2 = modHash(src);
|
|
96948
|
-
const hashFile =
|
|
96949
|
-
if (!existsSync39(hashFile) ||
|
|
97143
|
+
const hashFile = join49(dest, HASH_FILE);
|
|
97144
|
+
if (!existsSync39(hashFile) || readFileSync42(hashFile, "utf8") !== hash2) {
|
|
96950
97145
|
rmSync4(dest, { recursive: true, force: true });
|
|
96951
97146
|
cpSync3(src, dest, { recursive: true, filter: (p) => !isEngineOwned(relative8(src, p)) });
|
|
96952
|
-
|
|
97147
|
+
writeFileSync31(hashFile, hash2, "utf8");
|
|
96953
97148
|
changed = true;
|
|
96954
97149
|
}
|
|
96955
97150
|
installed.push(dest);
|
|
@@ -97370,9 +97565,9 @@ function resolveHookPort(explicit) {
|
|
|
97370
97565
|
}
|
|
97371
97566
|
}
|
|
97372
97567
|
}
|
|
97373
|
-
const settingsPath =
|
|
97568
|
+
const settingsPath = join50(ROOT, ".claude", "settings.json");
|
|
97374
97569
|
try {
|
|
97375
|
-
if (existsSync40(settingsPath)) return installedHookPort(
|
|
97570
|
+
if (existsSync40(settingsPath)) return installedHookPort(readFileSync43(settingsPath, "utf8")) ?? 7891;
|
|
97376
97571
|
} catch {
|
|
97377
97572
|
}
|
|
97378
97573
|
return 7891;
|
|
@@ -97398,13 +97593,13 @@ async function cmdInit() {
|
|
|
97398
97593
|
console.log("");
|
|
97399
97594
|
console.log("installing harness hooks...");
|
|
97400
97595
|
const { existsSync: existsSync41 } = await import("node:fs");
|
|
97401
|
-
const { join:
|
|
97596
|
+
const { join: join51 } = await import("node:path");
|
|
97402
97597
|
try {
|
|
97403
97598
|
await installClaudeHooks(port);
|
|
97404
97599
|
} catch (err2) {
|
|
97405
97600
|
console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
97406
97601
|
}
|
|
97407
|
-
if (existsSync41(
|
|
97602
|
+
if (existsSync41(join51(ROOT, ".cursor"))) {
|
|
97408
97603
|
try {
|
|
97409
97604
|
await installCursorMcpConfig();
|
|
97410
97605
|
} catch (err2) {
|
|
@@ -98626,7 +98821,7 @@ async function cmdReview() {
|
|
|
98626
98821
|
console.log("(review queue empty)");
|
|
98627
98822
|
return;
|
|
98628
98823
|
}
|
|
98629
|
-
const queue = JSON.parse(
|
|
98824
|
+
const queue = JSON.parse(readFileSync43(paths.reviewQueue, "utf8"));
|
|
98630
98825
|
if (queue.length === 0) {
|
|
98631
98826
|
console.log("(review queue empty)");
|
|
98632
98827
|
return;
|
|
@@ -99365,7 +99560,7 @@ async function gatherReportData(generatedAt) {
|
|
|
99365
99560
|
};
|
|
99366
99561
|
}
|
|
99367
99562
|
async function cmdReport(args2) {
|
|
99368
|
-
const { mkdirSync: mkdirSync13, writeFileSync:
|
|
99563
|
+
const { mkdirSync: mkdirSync13, writeFileSync: writeFileSync32 } = await import("node:fs");
|
|
99369
99564
|
const { renderReport: renderReport2 } = await Promise.resolve().then(() => (init_report_render(), report_render_exports));
|
|
99370
99565
|
const includeFutureVerbs = args2.includes("--future-verbs");
|
|
99371
99566
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -99378,8 +99573,8 @@ async function cmdReport(args2) {
|
|
|
99378
99573
|
const outDir = workspacePaths(ROOT).configDir;
|
|
99379
99574
|
mkdirSync13(outDir, { recursive: true });
|
|
99380
99575
|
const files = renderReport2(data, { includeFutureVerbs });
|
|
99381
|
-
for (const f of files)
|
|
99382
|
-
const indexPath =
|
|
99576
|
+
for (const f of files) writeFileSync32(join50(outDir, f.name), f.html, "utf8");
|
|
99577
|
+
const indexPath = join50(outDir, "report.html");
|
|
99383
99578
|
console.log(`report \u2192 ${indexPath}`);
|
|
99384
99579
|
console.log(
|
|
99385
99580
|
` ${data.repos.length} repo(s) \xB7 ${files.length} file(s) \xB7 ${data.rollup.nodes.toLocaleString("en-US")} nodes`
|
|
@@ -99435,7 +99630,7 @@ function spawnDaemonDetached(options = {}) {
|
|
|
99435
99630
|
try {
|
|
99436
99631
|
const logPath = daemonLogPath();
|
|
99437
99632
|
try {
|
|
99438
|
-
if (statSync13(logPath).size > 5 * 1024 * 1024)
|
|
99633
|
+
if (statSync13(logPath).size > 5 * 1024 * 1024) renameSync8(logPath, `${logPath}.1`);
|
|
99439
99634
|
} catch {
|
|
99440
99635
|
}
|
|
99441
99636
|
out2 = openSync3(logPath, "a");
|
|
@@ -99504,24 +99699,24 @@ async function cmdInstallHooks(args2) {
|
|
|
99504
99699
|
}
|
|
99505
99700
|
}
|
|
99506
99701
|
async function installOpencodePlugin(port) {
|
|
99507
|
-
const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync:
|
|
99508
|
-
const { join:
|
|
99509
|
-
const dir =
|
|
99702
|
+
const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
|
|
99703
|
+
const { join: join51 } = await import("node:path");
|
|
99704
|
+
const dir = join51(ROOT, ".opencode", "plugin");
|
|
99510
99705
|
if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
|
|
99511
|
-
const file2 =
|
|
99706
|
+
const file2 = join51(dir, "inerrata.js");
|
|
99512
99707
|
if (existsSync41(file2)) {
|
|
99513
|
-
const head2 =
|
|
99708
|
+
const head2 = readFileSync44(file2, "utf8").split("\n")[0] ?? "";
|
|
99514
99709
|
if (head2.trim() !== OPENCODE_PLUGIN_MARKER) {
|
|
99515
99710
|
console.error(`refusing to overwrite ${file2}: not an errata-managed plugin (line 1 lacks the marker)`);
|
|
99516
99711
|
process.exit(2);
|
|
99517
99712
|
}
|
|
99518
99713
|
}
|
|
99519
|
-
|
|
99520
|
-
const cfgFile =
|
|
99714
|
+
writeFileSync32(file2, buildOpencodePluginSource(port, { version: DAEMON_VERSION }), "utf8");
|
|
99715
|
+
const cfgFile = join51(ROOT, "opencode.json");
|
|
99521
99716
|
let cfg = { $schema: "https://opencode.ai/config.json" };
|
|
99522
99717
|
if (existsSync41(cfgFile)) {
|
|
99523
99718
|
try {
|
|
99524
|
-
cfg = JSON.parse(
|
|
99719
|
+
cfg = JSON.parse(readFileSync44(cfgFile, "utf8"));
|
|
99525
99720
|
} catch {
|
|
99526
99721
|
console.error(`refusing to touch invalid JSON at ${cfgFile} \u2014 fix it and re-run`);
|
|
99527
99722
|
process.exit(2);
|
|
@@ -99532,7 +99727,7 @@ async function installOpencodePlugin(port) {
|
|
|
99532
99727
|
if (!hadErrata) {
|
|
99533
99728
|
const inv = errataMcpInvocation();
|
|
99534
99729
|
cfg.mcp["errata"] = { type: "local", command: [inv.command, ...inv.args] };
|
|
99535
|
-
|
|
99730
|
+
writeFileSync32(cfgFile, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
99536
99731
|
}
|
|
99537
99732
|
console.log(`installed OpenCode plugin \u2192 ${file2}`);
|
|
99538
99733
|
if (hadErrata) console.log(` mcp.errata already present in ${cfgFile} \u2014 left untouched`);
|
|
@@ -99567,15 +99762,15 @@ function installClaudeMods() {
|
|
|
99567
99762
|
}
|
|
99568
99763
|
}
|
|
99569
99764
|
async function installClaudeHooks(port) {
|
|
99570
|
-
const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync:
|
|
99571
|
-
const { join:
|
|
99572
|
-
const dir =
|
|
99765
|
+
const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
|
|
99766
|
+
const { join: join51 } = await import("node:path");
|
|
99767
|
+
const dir = join51(ROOT, ".claude");
|
|
99573
99768
|
if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
|
|
99574
|
-
const file2 =
|
|
99769
|
+
const file2 = join51(dir, "settings.json");
|
|
99575
99770
|
let settings = {};
|
|
99576
99771
|
if (existsSync41(file2)) {
|
|
99577
99772
|
try {
|
|
99578
|
-
settings = JSON.parse(
|
|
99773
|
+
settings = JSON.parse(readFileSync44(file2, "utf8"));
|
|
99579
99774
|
} catch {
|
|
99580
99775
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
99581
99776
|
process.exit(2);
|
|
@@ -99624,12 +99819,12 @@ async function installClaudeHooks(port) {
|
|
|
99624
99819
|
list.push({ hooks: [{ type: "command", command: injectCmd }] });
|
|
99625
99820
|
}
|
|
99626
99821
|
removeProjectStatusLine(settings);
|
|
99627
|
-
|
|
99822
|
+
writeFileSync32(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
99628
99823
|
console.log(`installed Claude Code hooks \u2192 ${file2}`);
|
|
99629
99824
|
console.log(` ${ensureStatusLine(port)}`);
|
|
99630
99825
|
console.log(` ${installClaudeMods().line}`);
|
|
99631
99826
|
await installClaudeMcpConfig();
|
|
99632
|
-
const claudeMd =
|
|
99827
|
+
const claudeMd = join51(ROOT, "CLAUDE.md");
|
|
99633
99828
|
const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
|
|
99634
99829
|
if (recall.kind === "collision") {
|
|
99635
99830
|
console.warn(
|
|
@@ -99641,15 +99836,15 @@ async function installClaudeHooks(port) {
|
|
|
99641
99836
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
99642
99837
|
}
|
|
99643
99838
|
async function installClaudeMcpConfig() {
|
|
99644
|
-
const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync:
|
|
99645
|
-
const { join:
|
|
99646
|
-
const file2 =
|
|
99647
|
-
const dir =
|
|
99839
|
+
const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
|
|
99840
|
+
const { join: join51, dirname: dirname18 } = await import("node:path");
|
|
99841
|
+
const file2 = join51(ROOT, ".mcp.json");
|
|
99842
|
+
const dir = dirname18(file2);
|
|
99648
99843
|
if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
|
|
99649
99844
|
let cfg = {};
|
|
99650
99845
|
if (existsSync41(file2)) {
|
|
99651
99846
|
try {
|
|
99652
|
-
cfg = JSON.parse(
|
|
99847
|
+
cfg = JSON.parse(readFileSync44(file2, "utf8"));
|
|
99653
99848
|
} catch {
|
|
99654
99849
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
99655
99850
|
process.exit(2);
|
|
@@ -99657,21 +99852,21 @@ async function installClaudeMcpConfig() {
|
|
|
99657
99852
|
}
|
|
99658
99853
|
cfg.mcpServers ??= {};
|
|
99659
99854
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
99660
|
-
|
|
99855
|
+
writeFileSync32(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
99661
99856
|
console.log(`installed Claude Code MCP server config \u2192 ${file2}`);
|
|
99662
99857
|
console.log(` Claude Code will spawn \`errata mcp\` on workspace open.`);
|
|
99663
99858
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
|
|
99664
99859
|
}
|
|
99665
99860
|
async function installCursorMcpConfig() {
|
|
99666
|
-
const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync:
|
|
99667
|
-
const { join:
|
|
99668
|
-
const dir =
|
|
99861
|
+
const { mkdirSync: mkdirSync13, existsSync: existsSync41, readFileSync: readFileSync44, writeFileSync: writeFileSync32 } = await import("node:fs");
|
|
99862
|
+
const { join: join51 } = await import("node:path");
|
|
99863
|
+
const dir = join51(ROOT, ".cursor");
|
|
99669
99864
|
if (!existsSync41(dir)) mkdirSync13(dir, { recursive: true });
|
|
99670
|
-
const file2 =
|
|
99865
|
+
const file2 = join51(dir, "mcp.json");
|
|
99671
99866
|
let cfg = {};
|
|
99672
99867
|
if (existsSync41(file2)) {
|
|
99673
99868
|
try {
|
|
99674
|
-
cfg = JSON.parse(
|
|
99869
|
+
cfg = JSON.parse(readFileSync44(file2, "utf8"));
|
|
99675
99870
|
} catch {
|
|
99676
99871
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
99677
99872
|
process.exit(2);
|
|
@@ -99679,7 +99874,7 @@ async function installCursorMcpConfig() {
|
|
|
99679
99874
|
}
|
|
99680
99875
|
cfg.mcpServers ??= {};
|
|
99681
99876
|
cfg.mcpServers["errata"] = errataMcpInvocation();
|
|
99682
|
-
|
|
99877
|
+
writeFileSync32(file2, JSON.stringify(cfg, null, 2) + "\n", "utf8");
|
|
99683
99878
|
console.log(`installed Cursor MCP server config \u2192 ${file2}`);
|
|
99684
99879
|
console.log(` Cursor will spawn \`errata mcp\` on workspace open.`);
|
|
99685
99880
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses`);
|
|
@@ -99690,7 +99885,7 @@ async function installCodexHooks(port) {
|
|
|
99690
99885
|
const gitRoot = nearestGitRoot(process.cwd());
|
|
99691
99886
|
const hookRoot = gitRoot && mainCheckoutOfWorktree(gitRoot) ? gitRoot : ROOT;
|
|
99692
99887
|
const file2 = writeCodexHooks(hookRoot, port);
|
|
99693
|
-
const instructions = writeManagedBlock(
|
|
99888
|
+
const instructions = writeManagedBlock(join50(hookRoot, "AGENTS.md"), {
|
|
99694
99889
|
body: AGENTS_POINTER_BODY,
|
|
99695
99890
|
stable: true
|
|
99696
99891
|
});
|
|
@@ -100136,9 +100331,9 @@ async function cmdDash(args2) {
|
|
|
100136
100331
|
await yieldToLoop2();
|
|
100137
100332
|
try {
|
|
100138
100333
|
const items = selectDurableMemory(handle2.sharedStore, r.engine.profile, {
|
|
100139
|
-
atCommit: readGitRefState(
|
|
100334
|
+
atCommit: readGitRefState(join50(r.root, ".git")).sha ?? void 0
|
|
100140
100335
|
});
|
|
100141
|
-
const res = bleedRules(
|
|
100336
|
+
const res = bleedRules(join50(r.root, ".claude", "rules"), items);
|
|
100142
100337
|
if (res.written || res.pruned) {
|
|
100143
100338
|
console.log(
|
|
100144
100339
|
`[rules:${r.entry.name}] ${res.written} collective principle(s) \u2192 .claude/rules` + (res.pruned ? `, ${res.pruned} pruned` : "")
|