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