@inerrata-corporation/errata 2.0.8 → 2.0.10
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/consolidate-worker.mjs +84 -13
- package/errata.mjs +380 -125
- package/package.json +1 -1
- package/pass-worker.mjs +46 -1
package/errata.mjs
CHANGED
|
@@ -15732,6 +15732,13 @@ function isSeedProvenance(source) {
|
|
|
15732
15732
|
function isAnchorLabelKind(kind) {
|
|
15733
15733
|
return typeof kind === "string" && ANCHOR_LABEL_KINDS.includes(kind);
|
|
15734
15734
|
}
|
|
15735
|
+
function triageDiscriminatorAttrs(type, attrs) {
|
|
15736
|
+
if (!["CONFIRMS", "INDICATES", "ROUTES_TO"].includes(type)) return {};
|
|
15737
|
+
const value = attrs?.["discriminator"];
|
|
15738
|
+
if (typeof value !== "string") return {};
|
|
15739
|
+
const test = value.trim();
|
|
15740
|
+
return test && test.length <= TRIAGE_DISCRIMINATOR_MAX_LENGTH && !(test.startsWith("<") && test.endsWith(">")) ? { discriminator: test } : {};
|
|
15741
|
+
}
|
|
15735
15742
|
function anchorVersionAttrs(attrs) {
|
|
15736
15743
|
if (!attrs) return {};
|
|
15737
15744
|
const commit = attrs["observedAtCommit"];
|
|
@@ -15792,7 +15799,7 @@ function summarizeIngestResult(r) {
|
|
|
15792
15799
|
...r.patternReconciliation ? { patternReconciliation: r.patternReconciliation } : {}
|
|
15793
15800
|
};
|
|
15794
15801
|
}
|
|
15795
|
-
var CLOUD_NODE_LABELS, CLOUD_WRITABLE_NODE_LABELS, PROJECT_ONLY_NODE_LABELS, PROJECT_ONLY_NODE_LABEL_SET, PROJECT_ONLY_EDGE_TYPES, PROJECT_ONLY_EDGE_TYPE_SET, CLOUD_WRITABLE_NODE_LABEL_SET, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, QUARANTINE_EXTRACTION_SOURCE_PREFIX, MAX_NODES_PER_PAYLOAD, MAX_EDGES_PER_PAYLOAD, CastaliaIngestNodeSchema, RouteContextCountWireSchema, ANCHOR_COMMIT_SHA_RE, ANCHOR_BODY_HASH_RE, ANCHOR_SYMBOL_KINDS, ANCHOR_LABEL_KINDS, FILE_ANCHOR_QNAME, ANCHOR_LABEL_PATH_RE, ANCHOR_LABEL_QNAME_RE, ANCHOR_LABEL_KEYS, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
|
|
15802
|
+
var CLOUD_NODE_LABELS, CLOUD_WRITABLE_NODE_LABELS, PROJECT_ONLY_NODE_LABELS, PROJECT_ONLY_NODE_LABEL_SET, PROJECT_ONLY_EDGE_TYPES, PROJECT_ONLY_EDGE_TYPE_SET, CLOUD_WRITABLE_NODE_LABEL_SET, CLOUD_EDGE_TYPES, INGEST_SOURCES, INGEST_EXTRACTION_SOURCES, QUARANTINE_EXTRACTION_SOURCE_PREFIX, MAX_NODES_PER_PAYLOAD, MAX_EDGES_PER_PAYLOAD, CastaliaIngestNodeSchema, RouteContextCountWireSchema, ANCHOR_COMMIT_SHA_RE, ANCHOR_BODY_HASH_RE, ANCHOR_SYMBOL_KINDS, ANCHOR_LABEL_KINDS, FILE_ANCHOR_QNAME, ANCHOR_LABEL_PATH_RE, ANCHOR_LABEL_QNAME_RE, ANCHOR_LABEL_KEYS, TRIAGE_DISCRIMINATOR_MAX_LENGTH, CastaliaIngestEdgeSchema, SymbolSummarySidecarSchema, CastaliaIngestPayloadSchema;
|
|
15796
15803
|
var init_wire = __esm({
|
|
15797
15804
|
"../../packages/shared/src/wire.ts"() {
|
|
15798
15805
|
"use strict";
|
|
@@ -15915,6 +15922,7 @@ var init_wire = __esm({
|
|
|
15915
15922
|
ANCHOR_LABEL_PATH_RE = /^(?![/])(?![A-Za-z]:)(?!(?:.*\/)?\.\.(?:\/|$))[^\x00-\x1f\x7f\\`]{1,512}$/;
|
|
15916
15923
|
ANCHOR_LABEL_QNAME_RE = /^[^\x00-\x1f\x7f`]{1,256}$/;
|
|
15917
15924
|
ANCHOR_LABEL_KEYS = ["labelRelPath", "labelQname", "labelKind", "labelLine"];
|
|
15925
|
+
TRIAGE_DISCRIMINATOR_MAX_LENGTH = 2e3;
|
|
15918
15926
|
CastaliaIngestEdgeSchema = external_exports.object({
|
|
15919
15927
|
fromCanonicalId: external_exports.string().min(6).max(160),
|
|
15920
15928
|
toCanonicalId: external_exports.string().min(6).max(160),
|
|
@@ -15925,6 +15933,8 @@ var init_wire = __esm({
|
|
|
15925
15933
|
/** Triage route per-context counts (T3 induction). Carried as structured data
|
|
15926
15934
|
* here; stored JSON-encoded on the Neo4j rel (`perContextJson`). */
|
|
15927
15935
|
perContext: external_exports.record(external_exports.string(), RouteContextCountWireSchema).optional(),
|
|
15936
|
+
/** Scrubbed diagnostic check for a triage route, re-scanned at the cloud door. */
|
|
15937
|
+
discriminator: external_exports.string().trim().min(1).max(TRIAGE_DISCRIMINATOR_MAX_LENGTH).optional(),
|
|
15928
15938
|
/** PJ-anchor-version: WHICH version of a symbol an `ANCHORED_AT` was
|
|
15929
15939
|
* witnessed against. Both opaque — the observing checkout's HEAD sha and
|
|
15930
15940
|
* the indexer's 16-hex sha256 of the symbol body. Neither is reversible
|
|
@@ -16827,6 +16837,7 @@ __export(src_exports, {
|
|
|
16827
16837
|
TAXONOMY_EDGES: () => TAXONOMY_EDGES,
|
|
16828
16838
|
TOOL_KINDS: () => TOOL_KINDS,
|
|
16829
16839
|
TRANSFER_EDGES: () => TRANSFER_EDGES,
|
|
16840
|
+
TRIAGE_DISCRIMINATOR_MAX_LENGTH: () => TRIAGE_DISCRIMINATOR_MAX_LENGTH,
|
|
16830
16841
|
TRIAGE_EDGES: () => TRIAGE_EDGES,
|
|
16831
16842
|
TRUTH_KIND: () => TRUTH_KIND,
|
|
16832
16843
|
UnregisteredGraphEventError: () => UnregisteredGraphEventError,
|
|
@@ -16910,6 +16921,7 @@ __export(src_exports, {
|
|
|
16910
16921
|
summaryRejectionReason: () => summaryRejectionReason,
|
|
16911
16922
|
toCloudAttrs: () => toCloudAttrs,
|
|
16912
16923
|
toolCanonicalId: () => toolCanonicalId,
|
|
16924
|
+
triageDiscriminatorAttrs: () => triageDiscriminatorAttrs,
|
|
16913
16925
|
unregisteredGraphEventKeys: () => unregisteredGraphEventKeys,
|
|
16914
16926
|
validateCastaliaPayload: () => validateCastaliaPayload,
|
|
16915
16927
|
versionlessPurl: () => versionlessPurl,
|
|
@@ -17438,7 +17450,7 @@ function rowToEdge(r) {
|
|
|
17438
17450
|
function openGraphStore(opts) {
|
|
17439
17451
|
return new SqliteGraphStore(opts);
|
|
17440
17452
|
}
|
|
17441
|
-
var LOCAL_RULE_OVERRIDES, SCHEMA_VERSION, SCHEMA_SQL, TEMPORAL_INDEX_SQL, SqliteGraphStore;
|
|
17453
|
+
var LOCAL_RULE_OVERRIDES, SCHEMA_VERSION, SCHEMA_SQL, TEMPORAL_INDEX_SQL, FINGERPRINT_INDEXED_LABELS, SqliteGraphStore;
|
|
17442
17454
|
var init_store = __esm({
|
|
17443
17455
|
"../../packages/local-graph/src/store.ts"() {
|
|
17444
17456
|
"use strict";
|
|
@@ -17559,6 +17571,12 @@ CREATE UNIQUE INDEX IF NOT EXISTS edges_triple ON edges(from_id, type, to_id);
|
|
|
17559
17571
|
`;
|
|
17560
17572
|
TEMPORAL_INDEX_SQL = `
|
|
17561
17573
|
CREATE INDEX IF NOT EXISTS nodes_live ON nodes(label, valid_to);
|
|
17574
|
+
-- Covering + partial index for labelFingerprint over the instance labels: the
|
|
17575
|
+
-- live-push probe runs it per workspace on a timer, and each hit used to read
|
|
17576
|
+
-- its table row. Partial, so it maintains a few thousand rows instead of adding
|
|
17577
|
+
-- a write to every node write. Its label list is FINGERPRINT_INDEXED_LABELS.
|
|
17578
|
+
DROP INDEX IF EXISTS nodes_live_fingerprint;
|
|
17579
|
+
CREATE INDEX IF NOT EXISTS nodes_instance_fingerprint ON nodes(label, last_updated_at, last_reinforced_at_seq, created_at_seq) WHERE valid_to IS NULL AND label IN ('Problem','Solution','RootCause');
|
|
17562
17580
|
CREATE INDEX IF NOT EXISTS nodes_logical ON nodes(logical_id, version);
|
|
17563
17581
|
CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
|
|
17564
17582
|
-- Expression index on the per-node relPath (stored in attrs_json) so the
|
|
@@ -17572,6 +17590,7 @@ CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) W
|
|
|
17572
17590
|
-- every edited file of every turn, and a scan parses every Problem's attrs.
|
|
17573
17591
|
CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_json, '$.anchorHint.path')) WHERE valid_to IS NULL;
|
|
17574
17592
|
`;
|
|
17593
|
+
FINGERPRINT_INDEXED_LABELS = ["Problem", "Solution", "RootCause"];
|
|
17575
17594
|
SqliteGraphStore = class {
|
|
17576
17595
|
db;
|
|
17577
17596
|
// Typed edge lookups build their SQL from the number of types asked for, and
|
|
@@ -18048,6 +18067,32 @@ CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_js
|
|
|
18048
18067
|
attrs: JSON.parse(r.attrs_json)
|
|
18049
18068
|
}));
|
|
18050
18069
|
}
|
|
18070
|
+
*iterateNodeIdentitiesByLabel(label, pageSize = 2e3) {
|
|
18071
|
+
const page = this.db.prepare(
|
|
18072
|
+
"SELECT rowid AS rid, id, json_extract(attrs_json, '$.relPath') AS relPath, json_extract(attrs_json, '$.qname') AS qname FROM nodes WHERE rowid > ? AND label = ? AND valid_to IS NULL ORDER BY rowid LIMIT ?"
|
|
18073
|
+
);
|
|
18074
|
+
let after = 0;
|
|
18075
|
+
for (; ; ) {
|
|
18076
|
+
const rows = page.all(after, label, pageSize);
|
|
18077
|
+
for (const r of rows) {
|
|
18078
|
+
yield {
|
|
18079
|
+
id: r.id,
|
|
18080
|
+
relPath: typeof r.relPath === "string" ? r.relPath : null,
|
|
18081
|
+
qname: typeof r.qname === "string" ? r.qname : null
|
|
18082
|
+
};
|
|
18083
|
+
}
|
|
18084
|
+
if (rows.length < pageSize) return;
|
|
18085
|
+
after = rows[rows.length - 1].rid;
|
|
18086
|
+
}
|
|
18087
|
+
}
|
|
18088
|
+
recentNodeIds(label, limit) {
|
|
18089
|
+
const rows = this.db.prepare("SELECT id FROM nodes WHERE label = ? AND valid_to IS NULL ORDER BY last_updated_at DESC LIMIT ?").all(label, Math.max(0, limit));
|
|
18090
|
+
return rows.map((r) => r.id);
|
|
18091
|
+
}
|
|
18092
|
+
hasLiveNodes() {
|
|
18093
|
+
const r = this.db.prepare("SELECT EXISTS(SELECT 1 FROM nodes WHERE valid_to IS NULL) AS e").get();
|
|
18094
|
+
return r.e === 1;
|
|
18095
|
+
}
|
|
18051
18096
|
findNodeIdentitiesByLabel(label) {
|
|
18052
18097
|
const rows = this.stmts.identitiesByLabel.all(label);
|
|
18053
18098
|
return rows.map((r) => ({
|
|
@@ -18195,6 +18240,15 @@ CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_js
|
|
|
18195
18240
|
}
|
|
18196
18241
|
labelFingerprint(labels) {
|
|
18197
18242
|
if (labels.length === 0) return "0";
|
|
18243
|
+
if (labels.length === FINGERPRINT_INDEXED_LABELS.length && FINGERPRINT_INDEXED_LABELS.every((l) => labels.includes(l))) {
|
|
18244
|
+
const r2 = this.db.prepare(
|
|
18245
|
+
`SELECT COUNT(*) AS n, MAX(last_updated_at) AS t,
|
|
18246
|
+
MAX(COALESCE(last_reinforced_at_seq, created_at_seq, 0)) AS s
|
|
18247
|
+
FROM nodes INDEXED BY nodes_instance_fingerprint
|
|
18248
|
+
WHERE valid_to IS NULL AND label IN ('Problem','Solution','RootCause')`
|
|
18249
|
+
).get();
|
|
18250
|
+
return `${r2.n}:${r2.t ?? 0}:${r2.s ?? 0}`;
|
|
18251
|
+
}
|
|
18198
18252
|
const r = this.db.prepare(
|
|
18199
18253
|
`SELECT COUNT(*) AS n, MAX(last_updated_at) AS t,
|
|
18200
18254
|
MAX(COALESCE(last_reinforced_at_seq, created_at_seq, 0)) AS s
|
|
@@ -22578,7 +22632,8 @@ function pendingDiscriminators(l2, opts = {}) {
|
|
|
22578
22632
|
const perContext = e.attrs["perContext"] ?? {};
|
|
22579
22633
|
const global2 = perContext[TRIAGE_GLOBAL_BUCKET] ?? {};
|
|
22580
22634
|
const observations = Number(global2.confirmed ?? 0);
|
|
22581
|
-
const
|
|
22635
|
+
const inferred = new Set(global2.inferredContributors ?? []);
|
|
22636
|
+
const sources = new Set((global2.contributors ?? []).filter((id) => !inferred.has(id))).size;
|
|
22582
22637
|
if (sources < minSources || observations < minObservations) continue;
|
|
22583
22638
|
out2.push({ route: e.id, presenting: triage.description, cause: "", sources, observations, causeId: e.to });
|
|
22584
22639
|
}
|
|
@@ -22596,7 +22651,7 @@ function markDiscriminatorAsked(l2, routeIds, ts) {
|
|
|
22596
22651
|
}
|
|
22597
22652
|
}
|
|
22598
22653
|
function promoteRouteWithDiscriminator(l2, routeId, discriminator, ts, source) {
|
|
22599
|
-
const test = discriminator.
|
|
22654
|
+
const test = triageDiscriminatorAttrs("CONFIRMS", { discriminator }).discriminator;
|
|
22600
22655
|
if (!test) return false;
|
|
22601
22656
|
if (isUnfilledPlaceholder(test)) return false;
|
|
22602
22657
|
const existing = l2.getEdge(routeId);
|
|
@@ -22698,9 +22753,12 @@ function parseTriageFences(text) {
|
|
|
22698
22753
|
return out2;
|
|
22699
22754
|
}
|
|
22700
22755
|
function harvestTriageFences(l2, text, opts) {
|
|
22756
|
+
const seen = [...text.matchAll(/```errata-triage[^\n]*\n([\s\S]*?)```/g)].length;
|
|
22701
22757
|
let recorded = 0;
|
|
22702
22758
|
let promoted = 0;
|
|
22703
22759
|
for (const f of parseTriageFences(text)) {
|
|
22760
|
+
if ([f.presenting, f.cause, f.test, f.fix, f.route].some((value) => value && isUnfilledPlaceholder(value))) continue;
|
|
22761
|
+
if (f.test && !triageDiscriminatorAttrs("CONFIRMS", { discriminator: f.test }).discriminator) continue;
|
|
22704
22762
|
if (f.route && f.test) {
|
|
22705
22763
|
if (promoteRouteWithDiscriminator(l2, f.route.trim(), f.test, opts.ts, opts.contributor)) promoted++;
|
|
22706
22764
|
continue;
|
|
@@ -22736,7 +22794,7 @@ function harvestTriageFences(l2, text, opts) {
|
|
|
22736
22794
|
}
|
|
22737
22795
|
recorded++;
|
|
22738
22796
|
}
|
|
22739
|
-
return { recorded, promoted };
|
|
22797
|
+
return { seen, recorded, promoted, rejected: seen - recorded - promoted };
|
|
22740
22798
|
}
|
|
22741
22799
|
var COOCCUR_BONUS, routeEdgeId, ROUTE_EDGE_TYPES, routeTypeFor, isRouterRoute, INDUCTED_MARK, DRIFT_VALUES;
|
|
22742
22800
|
var init_triage2 = __esm({
|
|
@@ -23978,6 +24036,7 @@ __export(src_exports2, {
|
|
|
23978
24036
|
CODE_REACH_EDGES: () => CODE_REACH_EDGES,
|
|
23979
24037
|
CREDIT_FAMILY: () => CREDIT_FAMILY,
|
|
23980
24038
|
DEFAULT_MIN_COVERAGE: () => DEFAULT_MIN_COVERAGE,
|
|
24039
|
+
FINGERPRINT_INDEXED_LABELS: () => FINGERPRINT_INDEXED_LABELS,
|
|
23981
24040
|
FIX_CANDIDATE_ASK_LIMIT: () => FIX_CANDIDATE_ASK_LIMIT,
|
|
23982
24041
|
FOLD_EMBED_AUTO_COSINE: () => FOLD_EMBED_AUTO_COSINE,
|
|
23983
24042
|
FOLD_JUDGE_MIN_COSINE: () => FOLD_JUDGE_MIN_COSINE,
|
|
@@ -24353,7 +24412,7 @@ function renderSnapshot(s) {
|
|
|
24353
24412
|
lines.push("");
|
|
24354
24413
|
lines.push("### \u270D\uFE0F CAPTURE PROTOCOL \u2014 tags are the record");
|
|
24355
24414
|
lines.push(
|
|
24356
|
-
"errata records
|
|
24415
|
+
"For problems and fixes, errata records inline tags: `[!one line]` for every problem you state, `(fix:[id])` when your edit fixed a shown problem, and to JUDGE a prior shown below \u2014 `(confirm:[id])` if it held, `(refute:[id] why)` if it's wrong or didn't hold. Untagged prose is silently lost \u2014 tag as you write. Requested errata-* answer blocks keep their fences; put them in your turn-final reply."
|
|
24357
24416
|
);
|
|
24358
24417
|
lines.push("");
|
|
24359
24418
|
lines.push(SEARCH_IMPERATIVE_HEADER);
|
|
@@ -24639,7 +24698,7 @@ function renderSnapshot(s) {
|
|
|
24639
24698
|
for (const item of reviewItems) {
|
|
24640
24699
|
if (item.kind === "discriminator") {
|
|
24641
24700
|
lines.push(
|
|
24642
|
-
`- **A recurring diagnosis is one cheap check from promoting** \u2014 "${item.presenting}" usually turns out to be: ${item.cause}. If (and only if) you KNOW a cheap ante-hoc check that confirms it,
|
|
24701
|
+
`- **A recurring diagnosis is one cheap check from promoting** \u2014 "${item.presenting}" usually turns out to be: ${item.cause}. If (and only if) you KNOW a cheap ante-hoc check that confirms it, fill this fenced block in your turn-final reply:`
|
|
24643
24702
|
);
|
|
24644
24703
|
lines.push(" ```errata-triage");
|
|
24645
24704
|
lines.push(` route: ${item.route}`);
|
|
@@ -24647,7 +24706,7 @@ function renderSnapshot(s) {
|
|
|
24647
24706
|
lines.push(" ```");
|
|
24648
24707
|
} else {
|
|
24649
24708
|
lines.push(
|
|
24650
|
-
`- **Name the principle this cluster of your beliefs generalizes** \u2014 it ships to the collective only once named
|
|
24709
|
+
`- **Name the principle this cluster of your beliefs generalizes** \u2014 it ships to the collective only once named. Cover ALL members in one sentence; fill this fenced block in your turn-final reply:`
|
|
24651
24710
|
);
|
|
24652
24711
|
for (const m of item.members) lines.push(` - ${m.description}`);
|
|
24653
24712
|
lines.push(" ```errata-abstraction");
|
|
@@ -25153,6 +25212,7 @@ function toWirePayload(batch, runId) {
|
|
|
25153
25212
|
attrs: {
|
|
25154
25213
|
...typeof e.confidence === "number" ? { confidence: clamp012(e.confidence) } : {},
|
|
25155
25214
|
...perContext ? { perContext } : {},
|
|
25215
|
+
...triageDiscriminatorAttrs(e.type, e.attrs),
|
|
25156
25216
|
// PJ-anchor-version: the two opaque version stamps ride on anchors only.
|
|
25157
25217
|
...e.type === "ANCHORED_AT" ? anchorVersionAttrs(e.attrs) : {},
|
|
25158
25218
|
// PJ-anchor-labels: readable labels ride only when the producer set the
|
|
@@ -25759,6 +25819,7 @@ var init_client = __esm({
|
|
|
25759
25819
|
if (q.seed?.length) qs.set("seed", q.seed.join(","));
|
|
25760
25820
|
if (q.q) qs.set("q", q.q);
|
|
25761
25821
|
if (q.channel) qs.set("channel", q.channel);
|
|
25822
|
+
if (q.includeTriage) qs.set("includeTriage", "true");
|
|
25762
25823
|
const publicCtx = process.env["ERRATA_PRIMING_PUBLIC_CONTEXT"];
|
|
25763
25824
|
const usePublicCtx = Boolean(publicCtx && publicCtx !== "0" && q.channel === "priming");
|
|
25764
25825
|
const UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -28973,7 +29034,7 @@ function buildAgentInstruction(opts = {}) {
|
|
|
28973
29034
|
const signals = opts.signals ?? ["prior", "problem", "domain", "fix", "constraint", "triage", "attempt", "link"];
|
|
28974
29035
|
const ref = opts.referent ?? "its-handle";
|
|
28975
29036
|
const token = (s) => s === "problem" ? TAG_EXAMPLE.problem() : s === "constraint" ? TAG_EXAMPLE.constraint() : s === "attempt" ? TAG_EXAMPLE.tried() : s === "domain" ? TAG_EXAMPLE.domain() : s === "link" ? TAG_EXAMPLE.pattern() : s === "verdict" ? TAG_EXAMPLE.confirm(ref) : TAG_EXAMPLE[s](ref);
|
|
28976
|
-
const head2 = `We tag the priors we show you with a short handle like [${opts.handleExample ?? "chokidar-glob"}].
|
|
29037
|
+
const head2 = `We tag the priors we show you with a short handle like [${opts.handleExample ?? "chokidar-glob"}]. Untagged prose is silently lost. Put each tag inline in prose (no fences or backticks). Requested errata-* answer blocks are the exception: keep their fences in your turn-final reply. Tag everything, we filter downstream:`;
|
|
28977
29038
|
const tail = "Mid-turn text (between tool calls) can be dropped by the harness \u2014 RESTATE every tag in your turn-final message; the final message is what reliably survives \u2014 EXCEPT one already shown above with an id: that is captured, so cite `[its-handle]` rather than retyping it (drift mints a duplicate).";
|
|
28978
29039
|
return [
|
|
28979
29040
|
head2,
|
|
@@ -29131,6 +29192,12 @@ function statuslineText(sessionId, now = Date.now()) {
|
|
|
29131
29192
|
if (!hit || now - hit.at > STATUS_CARD_TTL_MS) return IDLE_STATUS;
|
|
29132
29193
|
return renderStatusCard(hit.card);
|
|
29133
29194
|
}
|
|
29195
|
+
function statuslineDir(body2) {
|
|
29196
|
+
const ws = body2["workspace"];
|
|
29197
|
+
const current = ws && typeof ws === "object" ? ws["current_dir"] : void 0;
|
|
29198
|
+
if (typeof current === "string" && current) return current;
|
|
29199
|
+
return typeof body2["cwd"] === "string" && body2["cwd"] ? body2["cwd"] : null;
|
|
29200
|
+
}
|
|
29134
29201
|
function recallCardEnabled(env2 = process.env) {
|
|
29135
29202
|
const v = (env2["ERRATA_RECALL_CARD"] ?? "").trim().toLowerCase();
|
|
29136
29203
|
return !(v === "0" || v === "off" || v === "false" || v === "no");
|
|
@@ -29457,6 +29524,18 @@ function resolveWorkspaceIdentity(cfg, entry, env2 = process.env) {
|
|
|
29457
29524
|
function identityKey(id) {
|
|
29458
29525
|
return id.profileName ?? "@default";
|
|
29459
29526
|
}
|
|
29527
|
+
function publicWorkspaceIdentity(identity) {
|
|
29528
|
+
return {
|
|
29529
|
+
profileName: identity.profileName,
|
|
29530
|
+
rule: identity.rule,
|
|
29531
|
+
invalid: identity.invalid,
|
|
29532
|
+
reason: identity.reason,
|
|
29533
|
+
profile: identity.profile ? {
|
|
29534
|
+
installationId: identity.profile.installationId,
|
|
29535
|
+
cloudUrl: identity.profile.cloudUrl
|
|
29536
|
+
} : null
|
|
29537
|
+
};
|
|
29538
|
+
}
|
|
29460
29539
|
function blockedCloudClient(reason) {
|
|
29461
29540
|
return new Proxy(
|
|
29462
29541
|
{},
|
|
@@ -41839,7 +41918,7 @@ function takeDiscriminatorNudge(path2) {
|
|
|
41839
41918
|
return [
|
|
41840
41919
|
`\u26A1 errata \u2014 a known wrong-door is one field from ranking: "${top.presenting.slice(0, 90)}"`,
|
|
41841
41920
|
` usually turns out to be: ${top.cause.slice(0, 90)} (seen ${top.observations}x)`,
|
|
41842
|
-
" Know a CHEAP check that confirms it?
|
|
41921
|
+
" Know a CHEAP check that confirms it? Fill this fenced block in your turn-final reply so the",
|
|
41843
41922
|
" next agent gets it first. Only if you actually know one: a guessed test ranks first",
|
|
41844
41923
|
" and misroutes everyone after you.",
|
|
41845
41924
|
" ```errata-triage",
|
|
@@ -43356,7 +43435,7 @@ var init_mcp = __esm({
|
|
|
43356
43435
|
pending,
|
|
43357
43436
|
...pending.length > 0 ? {
|
|
43358
43437
|
howToAnswer: [
|
|
43359
|
-
"For each route you know a cheap test for, emit an errata-triage fence",
|
|
43438
|
+
"For each route you know a cheap test for, emit an errata-triage fence in your turn-final reply",
|
|
43360
43439
|
"carrying its `route` id and the `test` \u2014 no presenting/cause needed, the",
|
|
43361
43440
|
"route id identifies both endpoints. Attaching a test does NOT count as",
|
|
43362
43441
|
"another sighting, so it cannot inflate the route's evidence.",
|
|
@@ -71393,7 +71472,7 @@ var init_report_render = __esm({
|
|
|
71393
71472
|
|
|
71394
71473
|
// src/cli.ts
|
|
71395
71474
|
init_src6();
|
|
71396
|
-
import { closeSync as closeSync2, existsSync as
|
|
71475
|
+
import { closeSync as closeSync2, existsSync as existsSync35, openSync as openSync2, readFileSync as readFileSync36, renameSync as renameSync4, statSync as statSync10 } from "node:fs";
|
|
71397
71476
|
import { join as join43, resolve as pathResolve2 } from "node:path";
|
|
71398
71477
|
import { spawn as spawn5 } from "node:child_process";
|
|
71399
71478
|
|
|
@@ -72715,9 +72794,9 @@ var NodeFsHandler = class {
|
|
|
72715
72794
|
if (this.fsw.closed) {
|
|
72716
72795
|
return;
|
|
72717
72796
|
}
|
|
72718
|
-
const
|
|
72797
|
+
const dirname14 = sysPath.dirname(file2);
|
|
72719
72798
|
const basename8 = sysPath.basename(file2);
|
|
72720
|
-
const parent = this.fsw._getWatchedDir(
|
|
72799
|
+
const parent = this.fsw._getWatchedDir(dirname14);
|
|
72721
72800
|
let prevStats = stats;
|
|
72722
72801
|
if (parent.has(basename8))
|
|
72723
72802
|
return;
|
|
@@ -72744,7 +72823,7 @@ var NodeFsHandler = class {
|
|
|
72744
72823
|
prevStats = newStats2;
|
|
72745
72824
|
}
|
|
72746
72825
|
} catch (error48) {
|
|
72747
|
-
this.fsw._remove(
|
|
72826
|
+
this.fsw._remove(dirname14, basename8);
|
|
72748
72827
|
}
|
|
72749
72828
|
} else if (parent.has(basename8)) {
|
|
72750
72829
|
const at = newStats.atimeMs;
|
|
@@ -74083,18 +74162,21 @@ function readTailWithLosses(path2, maxBytes) {
|
|
|
74083
74162
|
try {
|
|
74084
74163
|
fd = openSync(path2, "r");
|
|
74085
74164
|
} catch {
|
|
74086
|
-
return { text: "", bytesUnreachable: 0, ioFailed: true };
|
|
74165
|
+
return { text: "", bytesUnreachable: 0, parseStartByte: 0, ioFailed: true };
|
|
74087
74166
|
}
|
|
74088
74167
|
try {
|
|
74089
74168
|
const size = fstatSync(fd).size;
|
|
74090
74169
|
const start2 = Math.max(0, size - maxBytes);
|
|
74091
74170
|
const len = size - start2;
|
|
74092
|
-
if (len <= 0) return { text: "", bytesUnreachable: 0, ioFailed: false };
|
|
74171
|
+
if (len <= 0) return { text: "", bytesUnreachable: 0, parseStartByte: 0, ioFailed: false };
|
|
74093
74172
|
const buf = Buffer.allocUnsafe(len);
|
|
74094
74173
|
readSync(fd, buf, 0, len, start2);
|
|
74095
|
-
|
|
74174
|
+
const text = buf.toString("utf8");
|
|
74175
|
+
const firstNewline = buf.indexOf(10);
|
|
74176
|
+
const parseStartByte = firstNewline < 0 ? start2 : start2 + firstNewline + 1 - Buffer.byteLength(buf.subarray(0, firstNewline + 1).toString("utf8"));
|
|
74177
|
+
return { text, bytesUnreachable: start2, parseStartByte, ioFailed: false };
|
|
74096
74178
|
} catch {
|
|
74097
|
-
return { text: "", bytesUnreachable: 0, ioFailed: true };
|
|
74179
|
+
return { text: "", bytesUnreachable: 0, parseStartByte: 0, ioFailed: true };
|
|
74098
74180
|
} finally {
|
|
74099
74181
|
closeSync(fd);
|
|
74100
74182
|
}
|
|
@@ -74158,7 +74240,7 @@ function isUserTurnBoundary(obj) {
|
|
|
74158
74240
|
}
|
|
74159
74241
|
function readAssistantTurnsWithLosses(transcriptPath, includeThinking = true, maxBytes = 2e6) {
|
|
74160
74242
|
const tail = readTailWithLosses(transcriptPath, maxBytes);
|
|
74161
|
-
const parsed = parseAssistantTurns(tail.text, includeThinking, false);
|
|
74243
|
+
const parsed = parseAssistantTurns(tail.text, includeThinking, false, tail.parseStartByte);
|
|
74162
74244
|
return {
|
|
74163
74245
|
turns: parsed.turns,
|
|
74164
74246
|
losses: {
|
|
@@ -74170,7 +74252,8 @@ function readAssistantTurnsWithLosses(transcriptPath, includeThinking = true, ma
|
|
|
74170
74252
|
}
|
|
74171
74253
|
function readAssistantTurnsFrom(transcriptPath, fromByte, includeThinking = true, maxBytes) {
|
|
74172
74254
|
const { text, nextOffset, more, ioFailed } = readFrom(transcriptPath, fromByte, maxBytes);
|
|
74173
|
-
const
|
|
74255
|
+
const startByte = fromByte > 0 && fromByte <= nextOffset ? fromByte : 0;
|
|
74256
|
+
const parsed = parseAssistantTurns(text, includeThinking, fromByte > 0, startByte);
|
|
74174
74257
|
return {
|
|
74175
74258
|
turns: parsed.turns,
|
|
74176
74259
|
nextOffset,
|
|
@@ -74206,10 +74289,10 @@ function detectHostHarness(raw2) {
|
|
|
74206
74289
|
}
|
|
74207
74290
|
return "claude_code";
|
|
74208
74291
|
}
|
|
74209
|
-
function parseAssistantTurns(raw2, includeThinking, skipFirstLineParseFailure = false) {
|
|
74292
|
+
function parseAssistantTurns(raw2, includeThinking, skipFirstLineParseFailure = false, startByte = 0) {
|
|
74210
74293
|
if (!raw2) return { turns: [], parseFailures: 0 };
|
|
74211
74294
|
const harness = detectHostHarness(raw2);
|
|
74212
|
-
if (harness === "codex") return parseCodexAssistantTurns(raw2, skipFirstLineParseFailure);
|
|
74295
|
+
if (harness === "codex") return parseCodexAssistantTurns(raw2, skipFirstLineParseFailure, startByte);
|
|
74213
74296
|
if (harness === "gemini") return parseGeminiAssistantTurns(raw2, skipFirstLineParseFailure);
|
|
74214
74297
|
if (harness === "opencode") return parseOpencodeAssistantTurns(raw2, skipFirstLineParseFailure);
|
|
74215
74298
|
return parseClaudeAssistantTurns(raw2, includeThinking, skipFirstLineParseFailure);
|
|
@@ -74300,13 +74383,16 @@ function parseGeminiAssistantTurns(raw2, skipFirstLineParseFailure = false) {
|
|
|
74300
74383
|
const turns = [...byId.entries()].sort((a, b) => a[1].order - b[1].order).map(([uuid3, v]) => ({ uuid: uuid3, text: v.text, hostHarness: "gemini" }));
|
|
74301
74384
|
return { turns, parseFailures };
|
|
74302
74385
|
}
|
|
74303
|
-
function parseCodexAssistantTurns(raw2, skipFirstLineParseFailure = false) {
|
|
74386
|
+
function parseCodexAssistantTurns(raw2, skipFirstLineParseFailure = false, startByte = 0) {
|
|
74304
74387
|
const turns = [];
|
|
74305
|
-
const lines = raw2.split(
|
|
74388
|
+
const lines = raw2.split("\n");
|
|
74306
74389
|
let parseFailures = 0;
|
|
74390
|
+
let nextByte = startByte;
|
|
74307
74391
|
for (let i2 = 0; i2 < lines.length; i2++) {
|
|
74308
74392
|
const line = lines[i2];
|
|
74309
|
-
|
|
74393
|
+
const lineByte = nextByte;
|
|
74394
|
+
nextByte += Buffer.byteLength(line ?? "", "utf8") + 1;
|
|
74395
|
+
if (!line?.trim()) continue;
|
|
74310
74396
|
let obj;
|
|
74311
74397
|
try {
|
|
74312
74398
|
obj = JSON.parse(line);
|
|
@@ -74325,7 +74411,9 @@ function parseCodexAssistantTurns(raw2, skipFirstLineParseFailure = false) {
|
|
|
74325
74411
|
}
|
|
74326
74412
|
if (parts2.length === 0) continue;
|
|
74327
74413
|
turns.push({
|
|
74328
|
-
|
|
74414
|
+
// Slice-local line numbers repeat on every Stop. Position distinguishes
|
|
74415
|
+
// identical messages; the digest distinguishes a replaced row at that position.
|
|
74416
|
+
uuid: typeof payload["id"] === "string" && payload["id"].length > 0 ? payload["id"] : `codex-${lineByte}-${createHash14("sha256").update(line.trimEnd()).digest("hex")}`,
|
|
74329
74417
|
text: parts2.join("\n\n"),
|
|
74330
74418
|
hostHarness: "codex"
|
|
74331
74419
|
});
|
|
@@ -76897,21 +76985,31 @@ async function pullCloudTriage(shared, cloud, profile, limit = 50) {
|
|
|
76897
76985
|
stack: profile.stack,
|
|
76898
76986
|
domains: profile.domains,
|
|
76899
76987
|
kinds: ["Problem"],
|
|
76988
|
+
includeTriage: true,
|
|
76900
76989
|
limit
|
|
76901
76990
|
});
|
|
76902
76991
|
const byId = new Map(res.nodes.map((n) => [n.id, n]));
|
|
76903
76992
|
const now = Date.now();
|
|
76904
76993
|
let merged = 0;
|
|
76994
|
+
const landedTriages = /* @__PURE__ */ new Set();
|
|
76905
76995
|
const landNode = (id) => {
|
|
76906
|
-
|
|
76996
|
+
const existing = shared.getNode(id);
|
|
76907
76997
|
const n = byId.get(id);
|
|
76998
|
+
if (existing) {
|
|
76999
|
+
if (n && existing.attrs["source"] === "cloud") {
|
|
77000
|
+
shared.updateNode(id, { attrs: { ...existing.attrs, ...n.attrs, source: "cloud" }, lastUpdatedAt: now });
|
|
77001
|
+
}
|
|
77002
|
+
return true;
|
|
77003
|
+
}
|
|
76908
77004
|
if (!n) return false;
|
|
76909
77005
|
shared.mergeNode({ ...n, extractionSource: "bko-inferred", embedding: [], attrs: { ...n.attrs, source: "cloud" } });
|
|
76910
77006
|
return true;
|
|
76911
77007
|
};
|
|
76912
77008
|
for (const edge2 of res.edges) {
|
|
76913
77009
|
if (edge2.type !== "CONFIRMS" && edge2.type !== "ROUTES_TO") continue;
|
|
77010
|
+
if (!triageDiscriminatorAttrs(edge2.type, edge2.attrs).discriminator) continue;
|
|
76914
77011
|
if (!landNode(edge2.from) || !landNode(edge2.to)) continue;
|
|
77012
|
+
landedTriages.add(edge2.from);
|
|
76915
77013
|
const cloudAttrs = { ...edge2.attrs, source: "cloud", provisional: false };
|
|
76916
77014
|
const existing = shared.getEdge(edge2.id);
|
|
76917
77015
|
if (existing && existing.type === "CONFIRMS") {
|
|
@@ -76922,6 +77020,11 @@ async function pullCloudTriage(shared, cloud, profile, limit = 50) {
|
|
|
76922
77020
|
}
|
|
76923
77021
|
merged++;
|
|
76924
77022
|
}
|
|
77023
|
+
for (const edge2 of res.edges) {
|
|
77024
|
+
if (edge2.type !== "TRIAGED_BY" || !landedTriages.has(edge2.to)) continue;
|
|
77025
|
+
if (!landNode(edge2.from)) continue;
|
|
77026
|
+
shared.mergeEdge({ ...edge2, attrs: { ...edge2.attrs, source: "cloud" } });
|
|
77027
|
+
}
|
|
76925
77028
|
return merged;
|
|
76926
77029
|
}
|
|
76927
77030
|
|
|
@@ -80218,7 +80321,7 @@ function createWatchBreaker(deps) {
|
|
|
80218
80321
|
}
|
|
80219
80322
|
|
|
80220
80323
|
// src/engine.ts
|
|
80221
|
-
var DAEMON_VERSION = true ? "2.0.
|
|
80324
|
+
var DAEMON_VERSION = true ? "2.0.10" : "2.0.0-alpha.0";
|
|
80222
80325
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
80223
80326
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
80224
80327
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -80785,7 +80888,7 @@ function createWorkspaceEngine(opts) {
|
|
|
80785
80888
|
lastRemoteAt = now;
|
|
80786
80889
|
try {
|
|
80787
80890
|
const norm = normStackTokens;
|
|
80788
|
-
const seed = store.
|
|
80891
|
+
const seed = store.recentNodeIds("Problem", 6);
|
|
80789
80892
|
const q = {
|
|
80790
80893
|
stack: outboundStack(),
|
|
80791
80894
|
domains: norm(profile.domains),
|
|
@@ -81104,6 +81207,9 @@ function createWorkspaceEngine(opts) {
|
|
|
81104
81207
|
let resolved = 0;
|
|
81105
81208
|
let abstracted = 0;
|
|
81106
81209
|
let triaged = 0;
|
|
81210
|
+
let triageFencesSeen = 0;
|
|
81211
|
+
let triagePromoted = 0;
|
|
81212
|
+
let triageFencesRejected = 0;
|
|
81107
81213
|
let priorEdges = 0;
|
|
81108
81214
|
let exposureShown = 0;
|
|
81109
81215
|
let exposureEvicted = 0;
|
|
@@ -81167,11 +81273,16 @@ function createWorkspaceEngine(opts) {
|
|
|
81167
81273
|
console.warn("[errata] abstraction harvest failed:", err2);
|
|
81168
81274
|
}
|
|
81169
81275
|
try {
|
|
81170
|
-
|
|
81276
|
+
const triage = harvestTriageFences(opts.sharedStore, turn.text, {
|
|
81171
81277
|
context: { stack: profile.stack, domain: profile.domains[0] },
|
|
81172
81278
|
contributor: sessionId,
|
|
81173
81279
|
ts: t
|
|
81174
|
-
})
|
|
81280
|
+
});
|
|
81281
|
+
triaged += triage.recorded;
|
|
81282
|
+
triageFencesSeen += triage.seen;
|
|
81283
|
+
triagePromoted += triage.promoted;
|
|
81284
|
+
triageFencesRejected += triage.rejected;
|
|
81285
|
+
if (triage.recorded > 0 || triage.promoted > 0) contextDirty = true;
|
|
81175
81286
|
} catch (err2) {
|
|
81176
81287
|
console.warn("[errata] triage harvest failed:", err2);
|
|
81177
81288
|
}
|
|
@@ -81847,8 +81958,8 @@ function createWorkspaceEngine(opts) {
|
|
|
81847
81958
|
if (abstracted > 0) {
|
|
81848
81959
|
console.log(`[errata] abstraction: ${abstracted} principle(s) distilled from the conversation`);
|
|
81849
81960
|
}
|
|
81850
|
-
if (triaged > 0) {
|
|
81851
|
-
console.log(`[errata] triage: ${triaged}
|
|
81961
|
+
if (triaged > 0 || triagePromoted > 0 || triageFencesRejected > 0) {
|
|
81962
|
+
console.log(`[errata] triage: ${triaged} diagnosis(es), ${triagePromoted} route promotion(s), ${triageFencesRejected} rejected fence(s)`);
|
|
81852
81963
|
}
|
|
81853
81964
|
if (processedTurns > 0) {
|
|
81854
81965
|
appendPassLedger(paths.configDir, "capture", Date.now() - t, {
|
|
@@ -81863,6 +81974,9 @@ function createWorkspaceEngine(opts) {
|
|
|
81863
81974
|
tagsRestated,
|
|
81864
81975
|
resolved,
|
|
81865
81976
|
triaged,
|
|
81977
|
+
triageFencesSeen,
|
|
81978
|
+
triagePromoted,
|
|
81979
|
+
triageFencesRejected,
|
|
81866
81980
|
priorEdges,
|
|
81867
81981
|
corroboratedEdges,
|
|
81868
81982
|
// RG-mark: refute witnesses stamped onto local nodes (the local half of
|
|
@@ -82664,6 +82778,40 @@ async function listenServer(fetchFn, port) {
|
|
|
82664
82778
|
init_registry();
|
|
82665
82779
|
init_identity2();
|
|
82666
82780
|
|
|
82781
|
+
// src/instance-receipts.ts
|
|
82782
|
+
import { createHash as createHash16 } from "node:crypto";
|
|
82783
|
+
var FIELDS = ["contributedAtSeq", "cloudNodeId", "anchorsContributedDigest", "projectAnchorsContributedDigest", "semanticEdgesContributedDigest", "shipRefusedSinceSeq", "shipRefusedCount", "shipRefusedReason", "shipRefusedFingerprint"];
|
|
82784
|
+
function instanceDestinationKey(input) {
|
|
82785
|
+
return createHash16("sha256").update(JSON.stringify([
|
|
82786
|
+
input.workspace,
|
|
82787
|
+
input.cloudUrl.replace(/\/+$/, ""),
|
|
82788
|
+
input.installationId ?? input.profileName ?? "default",
|
|
82789
|
+
input.projectId ?? null,
|
|
82790
|
+
input.writeTarget?.visibility ?? null,
|
|
82791
|
+
input.writeTarget?.org_id ?? null,
|
|
82792
|
+
input.writeTarget?.team_id ?? null
|
|
82793
|
+
])).digest("hex");
|
|
82794
|
+
}
|
|
82795
|
+
function receiptMap(attrs) {
|
|
82796
|
+
const value = attrs["instanceReceipts"];
|
|
82797
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
82798
|
+
}
|
|
82799
|
+
function instanceReceipt(n, destination) {
|
|
82800
|
+
return destination ? receiptMap(n.attrs)[destination] ?? {} : n.attrs;
|
|
82801
|
+
}
|
|
82802
|
+
function updateInstanceReceipt(n, destination, patch, mirrorLegacy) {
|
|
82803
|
+
const receipt = { ...instanceReceipt(n, destination), ...patch };
|
|
82804
|
+
const attrs = { ...n.attrs, instanceReceipts: { ...receiptMap(n.attrs), [destination]: receipt } };
|
|
82805
|
+
if (mirrorLegacy) for (const field of FIELDS) {
|
|
82806
|
+
if (field in receipt) attrs[field] = receipt[field];
|
|
82807
|
+
else delete attrs[field];
|
|
82808
|
+
}
|
|
82809
|
+
return attrs;
|
|
82810
|
+
}
|
|
82811
|
+
function instanceReceiptSequence(n) {
|
|
82812
|
+
return Math.max(n.lastReinforcedAtSeq ?? 0, n.createdAtSeq ?? 0);
|
|
82813
|
+
}
|
|
82814
|
+
|
|
82667
82815
|
// src/multi.ts
|
|
82668
82816
|
init_dist();
|
|
82669
82817
|
init_src5();
|
|
@@ -83068,8 +83216,8 @@ function compositionCounters(c) {
|
|
|
83068
83216
|
...Object.fromEntries(buckets.map((b) => [`sidecarDrop_${b}`, sidecarDropReasons[b] ?? 0]))
|
|
83069
83217
|
};
|
|
83070
83218
|
}
|
|
83071
|
-
function contributedWireId(n) {
|
|
83072
|
-
const cloudId = n
|
|
83219
|
+
function contributedWireId(n, destinationKey) {
|
|
83220
|
+
const cloudId = instanceReceipt(n, destinationKey)["cloudNodeId"];
|
|
83073
83221
|
return isMembraneSaltedId(cloudId) ? cloudId : n.id;
|
|
83074
83222
|
}
|
|
83075
83223
|
var WIRE_CANONICAL_ID_MIN = 6;
|
|
@@ -83213,10 +83361,26 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
83213
83361
|
fileRefsSubstituted: 0,
|
|
83214
83362
|
fileRefLexiconMisses: 0
|
|
83215
83363
|
};
|
|
83364
|
+
const sharedCauses = /* @__PURE__ */ new Map();
|
|
83365
|
+
const causalQueue = store.findNodesByLabel("Problem").filter(
|
|
83366
|
+
(n) => n.attrs["source"] !== "cloud" && n.attrs["resolvedAs"] !== PROBLEM_RESOLUTION.FALSE_POSITIVE && !ignored(n.description)
|
|
83367
|
+
).map((n) => n.id);
|
|
83368
|
+
const causalSeen = new Set(causalQueue);
|
|
83369
|
+
for (let i2 = 0; i2 < causalQueue.length; i2++) {
|
|
83370
|
+
const id = causalQueue[i2];
|
|
83371
|
+
for (const e of [...store.outEdges(id, ["CAUSED_BY"]), ...opts.sharedStore?.outEdges(id, ["CAUSED_BY"]) ?? []]) {
|
|
83372
|
+
if (causalSeen.has(e.to)) continue;
|
|
83373
|
+
causalSeen.add(e.to);
|
|
83374
|
+
const cause = nodeOf(e.to);
|
|
83375
|
+
if (!cause || cause.label !== "RootCause" || cause.attrs["source"] === "cloud" || ignored(cause.description)) continue;
|
|
83376
|
+
sharedCauses.set(cause.id, cause);
|
|
83377
|
+
causalQueue.push(cause.id);
|
|
83378
|
+
}
|
|
83379
|
+
}
|
|
83216
83380
|
for (const label of INSTANCE_LABELS) {
|
|
83217
83381
|
const ref = [];
|
|
83218
83382
|
includedByLabel.set(label, ref);
|
|
83219
|
-
const population = label === "RootCause" && opts.sharedStore ? [...store.findNodesByLabel(label), ...
|
|
83383
|
+
const population = label === "RootCause" && opts.sharedStore ? [...store.findNodesByLabel(label), ...sharedCauses.values()] : store.findNodesByLabel(label);
|
|
83220
83384
|
for (const n of population) {
|
|
83221
83385
|
if (seen.has(n.id)) continue;
|
|
83222
83386
|
if (walked.has(n.id)) continue;
|
|
@@ -83234,18 +83398,18 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
83234
83398
|
composition.ignored++;
|
|
83235
83399
|
continue;
|
|
83236
83400
|
}
|
|
83237
|
-
const contributedAtSeq = n.
|
|
83401
|
+
const contributedAtSeq = instanceReceipt(n, opts.destinationKey)["contributedAtSeq"];
|
|
83238
83402
|
if (typeof contributedAtSeq === "number" && (n.lastReinforcedAtSeq ?? 0) <= contributedAtSeq) {
|
|
83239
83403
|
composition.watermarked++;
|
|
83240
83404
|
anchorSources.add(n.id);
|
|
83241
|
-
semanticEndpoints.set(n.id, contributedWireId(n));
|
|
83405
|
+
semanticEndpoints.set(n.id, contributedWireId(n, opts.destinationKey));
|
|
83242
83406
|
continue;
|
|
83243
83407
|
}
|
|
83244
83408
|
if (label === "Solution" && n.description.startsWith(AUTO_MINT_PREFIX)) {
|
|
83245
83409
|
composition.autoMint++;
|
|
83246
83410
|
continue;
|
|
83247
83411
|
}
|
|
83248
|
-
if (isTerminallyRefused(n)) {
|
|
83412
|
+
if (isTerminallyRefused({ ...n, attrs: instanceReceipt(n, opts.destinationKey) })) {
|
|
83249
83413
|
composition.terminalRefused++;
|
|
83250
83414
|
continue;
|
|
83251
83415
|
}
|
|
@@ -83304,9 +83468,9 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
83304
83468
|
}
|
|
83305
83469
|
const dg = digest(targets.map(({ e, wireId }) => `${e.type}>${wireId}`).sort());
|
|
83306
83470
|
const sourceNode = nodeOf(sourceId);
|
|
83307
|
-
if (sourceNode
|
|
83471
|
+
if ((sourceNode && instanceReceipt(sourceNode, opts.destinationKey)["anchorsContributedDigest"]) === dg) continue;
|
|
83308
83472
|
anchorDigests[sourceId] = dg;
|
|
83309
|
-
const wireFrom = seen.has(sourceId) || !sourceNode ? sourceId : contributedWireId(sourceNode);
|
|
83473
|
+
const wireFrom = seen.has(sourceId) || !sourceNode ? sourceId : contributedWireId(sourceNode, opts.destinationKey);
|
|
83310
83474
|
for (const { e, t, wireId } of targets) {
|
|
83311
83475
|
const reject = unshippableReason(wireId, t.label);
|
|
83312
83476
|
if (reject) {
|
|
@@ -83335,7 +83499,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
83335
83499
|
for (const sourceId of anchorSources) {
|
|
83336
83500
|
const source = nodeOf(sourceId);
|
|
83337
83501
|
if (!source) continue;
|
|
83338
|
-
const wireFrom = seen.has(sourceId) ? sourceId : contributedWireId(source);
|
|
83502
|
+
const wireFrom = seen.has(sourceId) ? sourceId : contributedWireId(source, opts.destinationKey);
|
|
83339
83503
|
const planned = [];
|
|
83340
83504
|
for (const e of store.outEdges(sourceId, ["ANCHORED_AT"])) {
|
|
83341
83505
|
const target = nodeOf(e.to);
|
|
@@ -83370,7 +83534,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
83370
83534
|
const dg = digest(
|
|
83371
83535
|
planned.map(({ symId, wireAttrs }) => `ANCHORED_AT>${symId}>${JSON.stringify(wireAttrs)}`).sort()
|
|
83372
83536
|
);
|
|
83373
|
-
if (source.
|
|
83537
|
+
if (instanceReceipt(source, opts.destinationKey)["projectAnchorsContributedDigest"] === dg) continue;
|
|
83374
83538
|
projectAnchorDigests[sourceId] = dg;
|
|
83375
83539
|
for (const { e, target, symId, wireAttrs } of planned) {
|
|
83376
83540
|
if (!contextSeen.has(symId)) {
|
|
@@ -83416,7 +83580,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
83416
83580
|
if (outs.length === 0) continue;
|
|
83417
83581
|
const dg = digest(outs.map(({ e, wireTo }) => `${e.type}>${wireTo}`).sort());
|
|
83418
83582
|
const owner = nodeOf(sourceId);
|
|
83419
|
-
const digestSkip = owner
|
|
83583
|
+
const digestSkip = (owner && instanceReceipt(owner, opts.destinationKey)["semanticEdgesContributedDigest"]) === dg;
|
|
83420
83584
|
if (!digestSkip) semanticEdgeDigests[sourceId] = dg;
|
|
83421
83585
|
for (const { e, wireTo } of outs) {
|
|
83422
83586
|
if (digestSkip && !shippedById.has(e.to)) continue;
|
|
@@ -83473,7 +83637,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
83473
83637
|
for (const wn of nodes) {
|
|
83474
83638
|
if (wn.label !== "RootCause" && wn.label !== "Solution") continue;
|
|
83475
83639
|
const src = nodeOf(wn.id);
|
|
83476
|
-
if (typeof src
|
|
83640
|
+
if (src && typeof instanceReceipt(src, opts.destinationKey)["contributedAtSeq"] === "number") continue;
|
|
83477
83641
|
if (bindingEndpoints.has(wn.id)) continue;
|
|
83478
83642
|
heldOrphans.add(wn.id);
|
|
83479
83643
|
}
|
|
@@ -83627,6 +83791,7 @@ function buildDrainInstances(store, sharedStore, input) {
|
|
|
83627
83791
|
...input.includePackages !== void 0 ? { includePackages: input.includePackages } : {},
|
|
83628
83792
|
workspaceRoot: input.workspaceRoot,
|
|
83629
83793
|
sharedStore,
|
|
83794
|
+
destinationKey: input.destinationKey,
|
|
83630
83795
|
onComposition: (c) => {
|
|
83631
83796
|
composition = c;
|
|
83632
83797
|
},
|
|
@@ -84124,7 +84289,7 @@ function buildReverseSymbolMap(opts) {
|
|
|
84124
84289
|
function* reverseSymbolEntries(opts) {
|
|
84125
84290
|
const { store, salt, projectId } = opts;
|
|
84126
84291
|
for (const kind of ANCHOR_SYMBOL_KINDS2) {
|
|
84127
|
-
for (const n of store.
|
|
84292
|
+
for (const n of store.iterateNodeIdentitiesByLabel(kind)) {
|
|
84128
84293
|
const { relPath, qname } = n;
|
|
84129
84294
|
if (relPath === null || qname === null) continue;
|
|
84130
84295
|
const sym = projectSymbolId(salt, projectId, relPath, qname, kind);
|
|
@@ -84132,7 +84297,7 @@ function* reverseSymbolEntries(opts) {
|
|
|
84132
84297
|
yield [projectSaltedNodeId(sym, salt), n.id];
|
|
84133
84298
|
}
|
|
84134
84299
|
}
|
|
84135
|
-
for (const n of store.
|
|
84300
|
+
for (const n of store.iterateNodeIdentitiesByLabel("File")) {
|
|
84136
84301
|
if (n.relPath === null) continue;
|
|
84137
84302
|
const sym = projectSymbolId(salt, projectId, n.relPath, FILE_ANCHOR_QNAME, "File");
|
|
84138
84303
|
yield [sym, n.id];
|
|
@@ -84172,7 +84337,7 @@ function buildOwnKnowledgeMap(opts) {
|
|
|
84172
84337
|
function* ownKnowledgeEntries(opts) {
|
|
84173
84338
|
const { store, salt } = opts;
|
|
84174
84339
|
for (const kind of ANCHOR_SOURCE_KINDS) {
|
|
84175
|
-
for (const n of store.
|
|
84340
|
+
for (const n of store.iterateNodeIdentitiesByLabel(kind)) {
|
|
84176
84341
|
if (n.id.startsWith("projn_")) continue;
|
|
84177
84342
|
yield [projectSaltedNodeId(n.id, salt), n.id];
|
|
84178
84343
|
}
|
|
@@ -85294,7 +85459,7 @@ async function startHistoryStage(root, input, client, walk11 = {}) {
|
|
|
85294
85459
|
|
|
85295
85460
|
// src/link-flow.ts
|
|
85296
85461
|
init_cloud_auth();
|
|
85297
|
-
import { createHash as
|
|
85462
|
+
import { createHash as createHash17 } from "node:crypto";
|
|
85298
85463
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
85299
85464
|
import { existsSync as existsSync30, writeFileSync as writeFileSync23 } from "node:fs";
|
|
85300
85465
|
import { join as join38 } from "node:path";
|
|
@@ -85588,7 +85753,7 @@ async function loginOAuthLoopback(opts) {
|
|
|
85588
85753
|
|
|
85589
85754
|
// src/link-flow.ts
|
|
85590
85755
|
function remoteFingerprint(locator) {
|
|
85591
|
-
return
|
|
85756
|
+
return createHash17("sha256").update(locator).digest("hex");
|
|
85592
85757
|
}
|
|
85593
85758
|
function isDecision(value) {
|
|
85594
85759
|
if (!value || typeof value !== "object") return false;
|
|
@@ -86483,7 +86648,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
86483
86648
|
registerWorkspace(rec.engine.profile, rec.root);
|
|
86484
86649
|
} catch {
|
|
86485
86650
|
}
|
|
86486
|
-
if (wakeIndexPlan(rec.engine.store.
|
|
86651
|
+
if (wakeIndexPlan(rec.engine.store.hasLiveNodes() ? 1 : 0, opts.reindexOnStart !== false) === "full-index") {
|
|
86487
86652
|
void enqueueWakeIndex(async () => {
|
|
86488
86653
|
const done = markPass(`wake-index:${rec.entry.name}`);
|
|
86489
86654
|
try {
|
|
@@ -86706,6 +86871,15 @@ async function startMultiDaemon(opts = {}) {
|
|
|
86706
86871
|
app.post("/api/context-inject", (c) => forward(c, cwdOf, { affinity: "follow" }));
|
|
86707
86872
|
app.post("/api/statusline", async (c) => {
|
|
86708
86873
|
const body2 = await c.req.json().catch(() => ({}));
|
|
86874
|
+
const dir = statuslineDir(body2);
|
|
86875
|
+
if (dir !== null) {
|
|
86876
|
+
const d = normPath(dir);
|
|
86877
|
+
const known = listWorkspaceEntries().some((e) => {
|
|
86878
|
+
const root = normPath(e.path);
|
|
86879
|
+
return d === root || d.startsWith(`${root}/`);
|
|
86880
|
+
});
|
|
86881
|
+
if (!known) return c.text("");
|
|
86882
|
+
}
|
|
86709
86883
|
return c.text(statuslineText(String(body2["session_id"] ?? "")));
|
|
86710
86884
|
});
|
|
86711
86885
|
for (const r of records) {
|
|
@@ -86886,11 +87060,17 @@ async function startMultiDaemon(opts = {}) {
|
|
|
86886
87060
|
const ANCHOR_PULL_INTERVAL_MS = 10 * 60 * 1e3;
|
|
86887
87061
|
const anchorPullAll = async () => {
|
|
86888
87062
|
const c = loadConfig();
|
|
86889
|
-
if (
|
|
86890
|
-
const client = cloudNow();
|
|
87063
|
+
if (registryCorrupt()) return;
|
|
86891
87064
|
for (const r of records) {
|
|
86892
87065
|
const projectId = r.engine.profile.projectId;
|
|
86893
87066
|
if (!projectId || !effectiveConsent(c, r.engine.profile).sync) continue;
|
|
87067
|
+
const identity = identityFor(liveWorkspaceEntry(r.entry));
|
|
87068
|
+
if (identity.invalid) {
|
|
87069
|
+
noteIdentityBlock(r.id, r.entry.name, identity);
|
|
87070
|
+
continue;
|
|
87071
|
+
}
|
|
87072
|
+
if (identity.rule !== "workspace-binding" && !hasCloudCredential(c)) continue;
|
|
87073
|
+
const client = cloudForIdentity(identity);
|
|
86894
87074
|
try {
|
|
86895
87075
|
const { salt } = await resolveProjectSymbolSalt(client, projectId);
|
|
86896
87076
|
await pullProjectAnchors(r, client, salt);
|
|
@@ -86904,11 +87084,17 @@ async function startMultiDaemon(opts = {}) {
|
|
|
86904
87084
|
}, ANCHOR_PULL_INTERVAL_MS);
|
|
86905
87085
|
const ambientLinkAll = async () => {
|
|
86906
87086
|
const c = loadConfig();
|
|
86907
|
-
if (
|
|
86908
|
-
const client = cloudNow();
|
|
87087
|
+
if (registryCorrupt()) return;
|
|
86909
87088
|
for (const r of records) {
|
|
86910
87089
|
const working = loadProfile(r.root) ?? r.engine.profile;
|
|
86911
87090
|
if (!effectiveConsent(c, working).sync) continue;
|
|
87091
|
+
const identity = identityFor(liveWorkspaceEntry(r.entry));
|
|
87092
|
+
if (identity.invalid) {
|
|
87093
|
+
noteIdentityBlock(r.id, r.entry.name, identity);
|
|
87094
|
+
continue;
|
|
87095
|
+
}
|
|
87096
|
+
if (identity.rule !== "workspace-binding" && !hasCloudCredential(c)) continue;
|
|
87097
|
+
const client = cloudForIdentity(identity);
|
|
86912
87098
|
const out2 = await ensureProjectLink(r.root, working, client);
|
|
86913
87099
|
if (working !== r.engine.profile) adoptLinkFields(r.engine.profile, working);
|
|
86914
87100
|
if (out2.linked) {
|
|
@@ -87296,6 +87482,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
87296
87482
|
}
|
|
87297
87483
|
const ignore2 = loadClaimIgnorePatterns(globalDir());
|
|
87298
87484
|
const clientPool = /* @__PURE__ */ new Map();
|
|
87485
|
+
const receiptContexts = /* @__PURE__ */ new Map();
|
|
87299
87486
|
const poolFor = (identity) => {
|
|
87300
87487
|
const k = identityKey(identity);
|
|
87301
87488
|
let c = clientPool.get(k);
|
|
@@ -87438,7 +87625,26 @@ async function startMultiDaemon(opts = {}) {
|
|
|
87438
87625
|
return res.accepted;
|
|
87439
87626
|
});
|
|
87440
87627
|
}
|
|
87628
|
+
const receiptProfile = recordIdentity.profile ?? (cfg2.activeInstallationProfile ? cfg2.installationProfiles[cfg2.activeInstallationProfile] : void 0);
|
|
87629
|
+
let receiptContext = receiptContexts.get(identityKey(recordIdentity));
|
|
87630
|
+
if (!receiptContext) {
|
|
87631
|
+
try {
|
|
87632
|
+
receiptContext = await client.context();
|
|
87633
|
+
receiptContexts.set(identityKey(recordIdentity), receiptContext);
|
|
87634
|
+
} catch (err2) {
|
|
87635
|
+
errors.push(`[${projectName}] instance destination unresolved: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
87636
|
+
continue;
|
|
87637
|
+
}
|
|
87638
|
+
}
|
|
87639
|
+
const destinationKey = instanceDestinationKey({
|
|
87640
|
+
workspace: r.id,
|
|
87641
|
+
cloudUrl: opts.cloudUrl ?? receiptProfile?.cloudUrl ?? cfg2.cloudUrl,
|
|
87642
|
+
installationId: receiptContext.context.installation_id ?? receiptContext.identity.credential_id,
|
|
87643
|
+
projectId: project?.projectId,
|
|
87644
|
+
writeTarget: project ? null : receiptContext.context.default_write_target
|
|
87645
|
+
});
|
|
87441
87646
|
const built = await buildInstanceBatch(r, {
|
|
87647
|
+
destinationKey,
|
|
87442
87648
|
profile: r.engine.profile,
|
|
87443
87649
|
daemonVersion: DAEMON_VERSION,
|
|
87444
87650
|
ignorePatterns: [...ignore2],
|
|
@@ -87483,7 +87689,6 @@ async function startMultiDaemon(opts = {}) {
|
|
|
87483
87689
|
);
|
|
87484
87690
|
}
|
|
87485
87691
|
uploaded += res.accepted;
|
|
87486
|
-
const seq = store.currentIngestSeq();
|
|
87487
87692
|
const cloudIdByLocal = new Map(
|
|
87488
87693
|
res.result.nodes.filter((rn) => rn.nodeId).map((rn) => [rn.canonicalId, rn.nodeId])
|
|
87489
87694
|
);
|
|
@@ -87492,6 +87697,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
87492
87697
|
if (rn.decision === "rejected") rejected.set(rn.canonicalId, rn.reason ?? "no reason given");
|
|
87493
87698
|
}
|
|
87494
87699
|
const rejectedEdges = res.result.edges.filter((re) => re.decision === "rejected");
|
|
87700
|
+
const edgeReceiptsComplete = rejectedEdges.length === 0 && res.result.edges.length === instances.edges.length;
|
|
87495
87701
|
if (rejectedEdges.length > 0) {
|
|
87496
87702
|
const byReason = /* @__PURE__ */ new Map();
|
|
87497
87703
|
for (const re of rejectedEdges) {
|
|
@@ -87522,17 +87728,17 @@ async function startMultiDaemon(opts = {}) {
|
|
|
87522
87728
|
const owner = owningStore(id);
|
|
87523
87729
|
if (!owner) return;
|
|
87524
87730
|
const fp = refusalFingerprint(reason, owner.n.description);
|
|
87525
|
-
const same = owner.n
|
|
87526
|
-
const count = same ? Number(owner.n
|
|
87527
|
-
if (owner.n
|
|
87731
|
+
const same = instanceReceipt(owner.n, destinationKey)["shipRefusedFingerprint"] === fp;
|
|
87732
|
+
const count = same ? Number(instanceReceipt(owner.n, destinationKey)["shipRefusedCount"] ?? 0) + 1 : 1;
|
|
87733
|
+
if (instanceReceipt(owner.n, destinationKey)["shipRefusedSinceSeq"] !== void 0) repeat();
|
|
87528
87734
|
owner.s.updateNode(id, {
|
|
87529
|
-
attrs: {
|
|
87530
|
-
...owner.n
|
|
87531
|
-
...same && owner.n
|
|
87735
|
+
attrs: updateInstanceReceipt(owner.n, destinationKey, {
|
|
87736
|
+
...instanceReceipt(owner.n, destinationKey),
|
|
87737
|
+
...same && instanceReceipt(owner.n, destinationKey)["shipRefusedSinceSeq"] !== void 0 ? {} : { shipRefusedSinceSeq: owner.s.currentIngestSeq() },
|
|
87532
87738
|
shipRefusedCount: count,
|
|
87533
87739
|
shipRefusedReason: reason,
|
|
87534
87740
|
shipRefusedFingerprint: fp
|
|
87535
|
-
}
|
|
87741
|
+
}, owner.s === store)
|
|
87536
87742
|
});
|
|
87537
87743
|
if (same && count === SHIP_TERMINAL_REFUSALS && !isRetryableRefusal(reason)) {
|
|
87538
87744
|
nowHeld.push({ id, reason });
|
|
@@ -87549,6 +87755,7 @@ async function startMultiDaemon(opts = {}) {
|
|
|
87549
87755
|
const owner = owningStore(n.id);
|
|
87550
87756
|
if (!owner || !["Problem", "Solution", "RootCause"].includes(owner.n.label)) return;
|
|
87551
87757
|
if (blocked.has(n.id)) return;
|
|
87758
|
+
if (!cloudIdByLocal.has(n.id)) return;
|
|
87552
87759
|
if (rejected.has(n.id)) return;
|
|
87553
87760
|
const cloudNodeId = cloudIdByLocal.get(n.id);
|
|
87554
87761
|
const {
|
|
@@ -87557,37 +87764,41 @@ async function startMultiDaemon(opts = {}) {
|
|
|
87557
87764
|
shipRefusedReason: _clearedReason,
|
|
87558
87765
|
shipRefusedFingerprint: _clearedFp,
|
|
87559
87766
|
...carried
|
|
87560
|
-
} = owner.n
|
|
87767
|
+
} = instanceReceipt(owner.n, destinationKey);
|
|
87561
87768
|
owner.s.updateNode(n.id, {
|
|
87562
|
-
attrs: {
|
|
87769
|
+
attrs: updateInstanceReceipt(owner.n, destinationKey, {
|
|
87563
87770
|
...carried,
|
|
87564
|
-
|
|
87565
|
-
|
|
87566
|
-
|
|
87771
|
+
shipRefusedSinceSeq: void 0,
|
|
87772
|
+
shipRefusedCount: void 0,
|
|
87773
|
+
shipRefusedReason: void 0,
|
|
87774
|
+
shipRefusedFingerprint: void 0,
|
|
87775
|
+
contributedAtSeq: instanceReceiptSequence(n),
|
|
87776
|
+
cloudNodeId
|
|
87777
|
+
}, owner.s === store)
|
|
87567
87778
|
});
|
|
87568
87779
|
});
|
|
87569
87780
|
await stampBatched(Object.entries(instances.anchorDigests), ([localId, dg]) => {
|
|
87570
87781
|
const owner = owningStore(localId);
|
|
87571
87782
|
if (!owner) return;
|
|
87572
|
-
if (rejected.has(localId) || blocked.has(localId)) return;
|
|
87783
|
+
if (!edgeReceiptsComplete || !instanceReceipt(owner.n, destinationKey)["cloudNodeId"] || rejected.has(localId) || blocked.has(localId)) return;
|
|
87573
87784
|
owner.s.updateNode(localId, {
|
|
87574
|
-
attrs:
|
|
87785
|
+
attrs: updateInstanceReceipt(owner.n, destinationKey, { anchorsContributedDigest: dg }, owner.s === store)
|
|
87575
87786
|
});
|
|
87576
87787
|
});
|
|
87577
87788
|
await stampBatched(Object.entries(instances.projectAnchorDigests), ([localId, dg]) => {
|
|
87578
87789
|
const owner = owningStore(localId);
|
|
87579
87790
|
if (!owner) return;
|
|
87580
|
-
if (rejected.has(localId) || blocked.has(localId)) return;
|
|
87791
|
+
if (!edgeReceiptsComplete || !instanceReceipt(owner.n, destinationKey)["cloudNodeId"] || rejected.has(localId) || blocked.has(localId)) return;
|
|
87581
87792
|
owner.s.updateNode(localId, {
|
|
87582
|
-
attrs:
|
|
87793
|
+
attrs: updateInstanceReceipt(owner.n, destinationKey, { projectAnchorsContributedDigest: dg }, owner.s === store)
|
|
87583
87794
|
});
|
|
87584
87795
|
});
|
|
87585
87796
|
await stampBatched(Object.entries(instances.semanticEdgeDigests), ([localId, dg]) => {
|
|
87586
87797
|
const owner = owningStore(localId);
|
|
87587
87798
|
if (!owner) return;
|
|
87588
|
-
if (rejected.has(localId) || blocked.has(localId)) return;
|
|
87799
|
+
if (!edgeReceiptsComplete || !instanceReceipt(owner.n, destinationKey)["cloudNodeId"] || rejected.has(localId) || blocked.has(localId)) return;
|
|
87589
87800
|
owner.s.updateNode(localId, {
|
|
87590
|
-
attrs:
|
|
87801
|
+
attrs: updateInstanceReceipt(owner.n, destinationKey, { semanticEdgesContributedDigest: dg }, owner.s === store)
|
|
87591
87802
|
});
|
|
87592
87803
|
});
|
|
87593
87804
|
appendPassLedger(r.engine.paths.configDir, "ship", Date.now() - shipStartedAt, {
|
|
@@ -88566,9 +88777,10 @@ function consolidationGapMs(lastPassMs, policy) {
|
|
|
88566
88777
|
}
|
|
88567
88778
|
|
|
88568
88779
|
// src/claude-statusline.ts
|
|
88569
|
-
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync26 } from "node:fs";
|
|
88570
|
-
import {
|
|
88571
|
-
|
|
88780
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync10, readFileSync as readFileSync35, writeFileSync as writeFileSync26 } from "node:fs";
|
|
88781
|
+
import { homedir as homedir8 } from "node:os";
|
|
88782
|
+
import { dirname as dirname13, join as join42 } from "node:path";
|
|
88783
|
+
var STATUSLINE_RELAY_SOURCE = String.raw`// errata-managed: regenerated by errata init / install-hooks claude
|
|
88572
88784
|
import { readFileSync } from 'node:fs';
|
|
88573
88785
|
|
|
88574
88786
|
try {
|
|
@@ -88594,15 +88806,57 @@ function buildStatusLine(port, nodePath, relayPath) {
|
|
|
88594
88806
|
function isErrataStatusLine(value) {
|
|
88595
88807
|
return !!value && typeof value === "object" && typeof value["command"] === "string" && value["command"].includes(STATUSLINE_RELAY_FILE);
|
|
88596
88808
|
}
|
|
88597
|
-
function
|
|
88598
|
-
if (
|
|
88599
|
-
|
|
88600
|
-
const relay = join42(dir, STATUSLINE_RELAY_FILE);
|
|
88601
|
-
mkdirSync10(dir, { recursive: true });
|
|
88602
|
-
writeFileSync26(relay, STATUSLINE_RELAY_SOURCE, "utf8");
|
|
88603
|
-
settings["statusLine"] = buildStatusLine(port, nodePath, relay);
|
|
88809
|
+
function removeProjectStatusLine(settings) {
|
|
88810
|
+
if (!isErrataStatusLine(settings["statusLine"])) return false;
|
|
88811
|
+
delete settings["statusLine"];
|
|
88604
88812
|
return true;
|
|
88605
88813
|
}
|
|
88814
|
+
function userClaudeSettingsPath() {
|
|
88815
|
+
const base = process.env["CLAUDE_CONFIG_DIR"] ?? join42(homedir8(), ".claude");
|
|
88816
|
+
return join42(base, "settings.json");
|
|
88817
|
+
}
|
|
88818
|
+
function ensureUserStatusLine(opts) {
|
|
88819
|
+
const env2 = opts.env ?? process.env;
|
|
88820
|
+
const off = (env2["ERRATA_STATUSLINE"] ?? "").trim().toLowerCase();
|
|
88821
|
+
if (off === "0" || off === "off" || off === "false" || off === "no") return "disabled";
|
|
88822
|
+
const settingsPath = opts.userSettingsPath ?? userClaudeSettingsPath();
|
|
88823
|
+
let settings = {};
|
|
88824
|
+
if (existsSync34(settingsPath)) {
|
|
88825
|
+
try {
|
|
88826
|
+
const parsed = JSON.parse(readFileSync35(settingsPath, "utf8"));
|
|
88827
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return "unreadable";
|
|
88828
|
+
settings = parsed;
|
|
88829
|
+
} catch {
|
|
88830
|
+
return "unreadable";
|
|
88831
|
+
}
|
|
88832
|
+
}
|
|
88833
|
+
if (settings["statusLine"] !== void 0 && !isErrataStatusLine(settings["statusLine"])) return "kept-own";
|
|
88834
|
+
const relay = join42(opts.relayDir, STATUSLINE_RELAY_FILE);
|
|
88835
|
+
mkdirSync10(opts.relayDir, { recursive: true });
|
|
88836
|
+
if (!existsSync34(relay) || readFileSync35(relay, "utf8") !== STATUSLINE_RELAY_SOURCE) {
|
|
88837
|
+
writeFileSync26(relay, STATUSLINE_RELAY_SOURCE, "utf8");
|
|
88838
|
+
}
|
|
88839
|
+
const next = buildStatusLine(opts.port, opts.nodePath ?? process.execPath, relay);
|
|
88840
|
+
if (JSON.stringify(settings["statusLine"]) === JSON.stringify(next)) return "unchanged";
|
|
88841
|
+
settings["statusLine"] = next;
|
|
88842
|
+
mkdirSync10(dirname13(settingsPath), { recursive: true });
|
|
88843
|
+
writeFileSync26(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
88844
|
+
return "installed";
|
|
88845
|
+
}
|
|
88846
|
+
function describeStatusLineOutcome(outcome) {
|
|
88847
|
+
switch (outcome) {
|
|
88848
|
+
case "installed":
|
|
88849
|
+
return "status line: errata recall card in colour (user settings; ERRATA_STATUSLINE=off opts out)";
|
|
88850
|
+
case "unchanged":
|
|
88851
|
+
return "status line: errata recall card already set up";
|
|
88852
|
+
case "kept-own":
|
|
88853
|
+
return "status line: kept your own \u2014 errata's recall card shows inline only";
|
|
88854
|
+
case "disabled":
|
|
88855
|
+
return "status line: skipped (ERRATA_STATUSLINE=off)";
|
|
88856
|
+
case "unreadable":
|
|
88857
|
+
return "status line: skipped \u2014 ~/.claude/settings.json is not valid JSON";
|
|
88858
|
+
}
|
|
88859
|
+
}
|
|
88606
88860
|
|
|
88607
88861
|
// src/opencode-plugin.ts
|
|
88608
88862
|
var OPENCODE_PLUGIN_MARKER = "// @inerrata opencode plugin \u2014 errata-managed (errata install-hooks opencode)";
|
|
@@ -89009,14 +89263,14 @@ async function cmdInit() {
|
|
|
89009
89263
|
if (!skipHooks) {
|
|
89010
89264
|
console.log("");
|
|
89011
89265
|
console.log("installing harness hooks...");
|
|
89012
|
-
const { existsSync:
|
|
89266
|
+
const { existsSync: existsSync36 } = await import("node:fs");
|
|
89013
89267
|
const { join: join44 } = await import("node:path");
|
|
89014
89268
|
try {
|
|
89015
89269
|
await installClaudeHooks(port);
|
|
89016
89270
|
} catch (err2) {
|
|
89017
89271
|
console.warn(` \u26A0\uFE0F Claude hook install failed: ${err2 instanceof Error ? err2.message : err2}`);
|
|
89018
89272
|
}
|
|
89019
|
-
if (
|
|
89273
|
+
if (existsSync36(join44(ROOT, ".cursor"))) {
|
|
89020
89274
|
try {
|
|
89021
89275
|
await installCursorMcpConfig();
|
|
89022
89276
|
} catch (err2) {
|
|
@@ -89118,6 +89372,7 @@ async function cmdStart() {
|
|
|
89118
89372
|
await ensureProfile();
|
|
89119
89373
|
const profile = loadProfile(ROOT);
|
|
89120
89374
|
if (profile) registerWorkspace(profile, ROOT);
|
|
89375
|
+
if (profile) console.log(`errata: ${ensureStatusLine(resolveHookPort())}`);
|
|
89121
89376
|
const lockPath = globalDaemonLock();
|
|
89122
89377
|
const running = isDaemonAlive(lockPath) ? readDaemonLock(lockPath) : null;
|
|
89123
89378
|
const where = profile ? `${profile.name} (${profile.id})` : ROOT;
|
|
@@ -89205,9 +89460,9 @@ async function cmdStatus() {
|
|
|
89205
89460
|
console.log(` stack: ${profile.stack.join(", ") || "(none)"}`);
|
|
89206
89461
|
console.log(` languages: ${profile.languages.join(", ") || "(none)"}`);
|
|
89207
89462
|
}
|
|
89208
|
-
console.log(` graph db: ${
|
|
89209
|
-
console.log(` event log: ${
|
|
89210
|
-
if (
|
|
89463
|
+
console.log(` graph db: ${existsSync35(paths.castalia) ? "yes" : "no"} (${paths.castalia})`);
|
|
89464
|
+
console.log(` event log: ${existsSync35(paths.eventLog) ? "yes" : "no"} (${paths.eventLog})`);
|
|
89465
|
+
if (existsSync35(paths.castalia)) {
|
|
89211
89466
|
try {
|
|
89212
89467
|
const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src5(), src_exports2));
|
|
89213
89468
|
const store = openGraphStore2({ path: paths.castalia });
|
|
@@ -89437,7 +89692,7 @@ async function cmdWhoami(args2) {
|
|
|
89437
89692
|
`note: daemon capture and the MCP server resolve identically; a process with ERRATA_CONFIG_PATH set resolves by rule 1 regardless of binding.`
|
|
89438
89693
|
];
|
|
89439
89694
|
if (args2.includes("--json")) {
|
|
89440
|
-
console.log(JSON.stringify({ path: path2, registered: Boolean(entry), ...identity }, null, 2));
|
|
89695
|
+
console.log(JSON.stringify({ path: path2, registered: Boolean(entry), ...publicWorkspaceIdentity(identity) }, null, 2));
|
|
89441
89696
|
} else {
|
|
89442
89697
|
for (const l of lines) console.log(l);
|
|
89443
89698
|
}
|
|
@@ -89840,6 +90095,7 @@ async function cmdLink(args2) {
|
|
|
89840
90095
|
process.exitCode = 1;
|
|
89841
90096
|
return;
|
|
89842
90097
|
}
|
|
90098
|
+
console.log(ensureStatusLine(resolveHookPort()));
|
|
89843
90099
|
delete profile.projectLinkDisabled;
|
|
89844
90100
|
const remote = flag("--remote");
|
|
89845
90101
|
if (remote) {
|
|
@@ -90176,11 +90432,11 @@ function cmdInstallationProfile(args2) {
|
|
|
90176
90432
|
}
|
|
90177
90433
|
async function cmdReview() {
|
|
90178
90434
|
const paths = workspacePaths(ROOT);
|
|
90179
|
-
if (!
|
|
90435
|
+
if (!existsSync35(paths.reviewQueue)) {
|
|
90180
90436
|
console.log("(review queue empty)");
|
|
90181
90437
|
return;
|
|
90182
90438
|
}
|
|
90183
|
-
const queue = JSON.parse(
|
|
90439
|
+
const queue = JSON.parse(readFileSync36(paths.reviewQueue, "utf8"));
|
|
90184
90440
|
if (queue.length === 0) {
|
|
90185
90441
|
console.log("(review queue empty)");
|
|
90186
90442
|
return;
|
|
@@ -90851,7 +91107,7 @@ async function gatherRepo(store, ws) {
|
|
|
90851
91107
|
};
|
|
90852
91108
|
}
|
|
90853
91109
|
async function gatherReportData(generatedAt) {
|
|
90854
|
-
const { existsSync:
|
|
91110
|
+
const { existsSync: existsSync36 } = await import("node:fs");
|
|
90855
91111
|
const { openGraphStore: openGraphStore2 } = await Promise.resolve().then(() => (init_src5(), src_exports2));
|
|
90856
91112
|
const cfg = loadConfig();
|
|
90857
91113
|
const outbound = cfg.consent.sync ? "auto" : "off";
|
|
@@ -90859,7 +91115,7 @@ async function gatherReportData(generatedAt) {
|
|
|
90859
91115
|
for (const ws of listWorkspaces()) {
|
|
90860
91116
|
if (ws.missing) continue;
|
|
90861
91117
|
const dbPath = workspacePaths(ws.path).castalia;
|
|
90862
|
-
if (!
|
|
91118
|
+
if (!existsSync36(dbPath)) continue;
|
|
90863
91119
|
let store = null;
|
|
90864
91120
|
try {
|
|
90865
91121
|
store = openGraphStore2({ path: dbPath });
|
|
@@ -91024,13 +91280,13 @@ async function cmdInstallHooks(args2) {
|
|
|
91024
91280
|
}
|
|
91025
91281
|
}
|
|
91026
91282
|
async function installOpencodePlugin(port) {
|
|
91027
|
-
const { mkdirSync: mkdirSync11, existsSync:
|
|
91283
|
+
const { mkdirSync: mkdirSync11, existsSync: existsSync36, readFileSync: readFileSync37, writeFileSync: writeFileSync27 } = await import("node:fs");
|
|
91028
91284
|
const { join: join44 } = await import("node:path");
|
|
91029
91285
|
const dir = join44(ROOT, ".opencode", "plugin");
|
|
91030
|
-
if (!
|
|
91286
|
+
if (!existsSync36(dir)) mkdirSync11(dir, { recursive: true });
|
|
91031
91287
|
const file2 = join44(dir, "inerrata.js");
|
|
91032
|
-
if (
|
|
91033
|
-
const head2 =
|
|
91288
|
+
if (existsSync36(file2)) {
|
|
91289
|
+
const head2 = readFileSync37(file2, "utf8").split("\n")[0] ?? "";
|
|
91034
91290
|
if (head2.trim() !== OPENCODE_PLUGIN_MARKER) {
|
|
91035
91291
|
console.error(`refusing to overwrite ${file2}: not an errata-managed plugin (line 1 lacks the marker)`);
|
|
91036
91292
|
process.exit(2);
|
|
@@ -91039,9 +91295,9 @@ async function installOpencodePlugin(port) {
|
|
|
91039
91295
|
writeFileSync27(file2, buildOpencodePluginSource(port, { version: DAEMON_VERSION }), "utf8");
|
|
91040
91296
|
const cfgFile = join44(ROOT, "opencode.json");
|
|
91041
91297
|
let cfg = { $schema: "https://opencode.ai/config.json" };
|
|
91042
|
-
if (
|
|
91298
|
+
if (existsSync36(cfgFile)) {
|
|
91043
91299
|
try {
|
|
91044
|
-
cfg = JSON.parse(
|
|
91300
|
+
cfg = JSON.parse(readFileSync37(cfgFile, "utf8"));
|
|
91045
91301
|
} catch {
|
|
91046
91302
|
console.error(`refusing to touch invalid JSON at ${cfgFile} \u2014 fix it and re-run`);
|
|
91047
91303
|
process.exit(2);
|
|
@@ -91071,16 +91327,23 @@ function errataMcpInvocation() {
|
|
|
91071
91327
|
const { cmd: cmd2, args: args2 } = selfArgv("mcp");
|
|
91072
91328
|
return { command: cmd2, args: args2 };
|
|
91073
91329
|
}
|
|
91330
|
+
function ensureStatusLine(port) {
|
|
91331
|
+
try {
|
|
91332
|
+
return describeStatusLineOutcome(ensureUserStatusLine({ port, relayDir: globalDir() }));
|
|
91333
|
+
} catch (err2) {
|
|
91334
|
+
return `status line: not installed (${err2 instanceof Error ? err2.message : err2})`;
|
|
91335
|
+
}
|
|
91336
|
+
}
|
|
91074
91337
|
async function installClaudeHooks(port) {
|
|
91075
|
-
const { mkdirSync: mkdirSync11, existsSync:
|
|
91338
|
+
const { mkdirSync: mkdirSync11, existsSync: existsSync36, readFileSync: readFileSync37, writeFileSync: writeFileSync27 } = await import("node:fs");
|
|
91076
91339
|
const { join: join44 } = await import("node:path");
|
|
91077
91340
|
const dir = join44(ROOT, ".claude");
|
|
91078
|
-
if (!
|
|
91341
|
+
if (!existsSync36(dir)) mkdirSync11(dir, { recursive: true });
|
|
91079
91342
|
const file2 = join44(dir, "settings.json");
|
|
91080
91343
|
let settings = {};
|
|
91081
|
-
if (
|
|
91344
|
+
if (existsSync36(file2)) {
|
|
91082
91345
|
try {
|
|
91083
|
-
settings = JSON.parse(
|
|
91346
|
+
settings = JSON.parse(readFileSync37(file2, "utf8"));
|
|
91084
91347
|
} catch {
|
|
91085
91348
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
91086
91349
|
process.exit(2);
|
|
@@ -91127,18 +91390,10 @@ async function installClaudeHooks(port) {
|
|
|
91127
91390
|
dropErrata(list);
|
|
91128
91391
|
list.push({ hooks: [{ type: "command", command: injectCmd }] });
|
|
91129
91392
|
}
|
|
91130
|
-
|
|
91131
|
-
let userStatusLine;
|
|
91132
|
-
try {
|
|
91133
|
-
userStatusLine = JSON.parse(readFileSync36(join44(homedir8(), ".claude", "settings.json"), "utf8"))["statusLine"];
|
|
91134
|
-
} catch {
|
|
91135
|
-
}
|
|
91136
|
-
const statusLineInstalled = (userStatusLine === void 0 || isErrataStatusLine(userStatusLine)) && installStatusLine(settings, ROOT, port);
|
|
91393
|
+
removeProjectStatusLine(settings);
|
|
91137
91394
|
writeFileSync27(file2, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
91138
91395
|
console.log(`installed Claude Code hooks \u2192 ${file2}`);
|
|
91139
|
-
console.log(
|
|
91140
|
-
statusLineInstalled ? " status line: errata recall card in colour (daemon env ERRATA_RECALL_CARD=off hides the cards)" : " status line: kept your own \u2014 errata's recall card shows inline only"
|
|
91141
|
-
);
|
|
91396
|
+
console.log(` ${ensureStatusLine(port)}`);
|
|
91142
91397
|
await installClaudeMcpConfig();
|
|
91143
91398
|
const claudeMd = join44(ROOT, "CLAUDE.md");
|
|
91144
91399
|
const recall = writeManagedBlock(claudeMd, { body: RECALL_FIRST_BLOCK });
|
|
@@ -91152,15 +91407,15 @@ async function installClaudeHooks(port) {
|
|
|
91152
91407
|
console.log(` endpoint: http://127.0.0.1:${port}/api/hook`);
|
|
91153
91408
|
}
|
|
91154
91409
|
async function installClaudeMcpConfig() {
|
|
91155
|
-
const { mkdirSync: mkdirSync11, existsSync:
|
|
91156
|
-
const { join: join44, dirname:
|
|
91410
|
+
const { mkdirSync: mkdirSync11, existsSync: existsSync36, readFileSync: readFileSync37, writeFileSync: writeFileSync27 } = await import("node:fs");
|
|
91411
|
+
const { join: join44, dirname: dirname14 } = await import("node:path");
|
|
91157
91412
|
const file2 = join44(ROOT, ".mcp.json");
|
|
91158
|
-
const dir =
|
|
91159
|
-
if (!
|
|
91413
|
+
const dir = dirname14(file2);
|
|
91414
|
+
if (!existsSync36(dir)) mkdirSync11(dir, { recursive: true });
|
|
91160
91415
|
let cfg = {};
|
|
91161
|
-
if (
|
|
91416
|
+
if (existsSync36(file2)) {
|
|
91162
91417
|
try {
|
|
91163
|
-
cfg = JSON.parse(
|
|
91418
|
+
cfg = JSON.parse(readFileSync37(file2, "utf8"));
|
|
91164
91419
|
} catch {
|
|
91165
91420
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
91166
91421
|
process.exit(2);
|
|
@@ -91174,15 +91429,15 @@ async function installClaudeMcpConfig() {
|
|
|
91174
91429
|
console.log(` Tools: errata.search / locate / neighbors / callers_of / what_uses / show / similar`);
|
|
91175
91430
|
}
|
|
91176
91431
|
async function installCursorMcpConfig() {
|
|
91177
|
-
const { mkdirSync: mkdirSync11, existsSync:
|
|
91432
|
+
const { mkdirSync: mkdirSync11, existsSync: existsSync36, readFileSync: readFileSync37, writeFileSync: writeFileSync27 } = await import("node:fs");
|
|
91178
91433
|
const { join: join44 } = await import("node:path");
|
|
91179
91434
|
const dir = join44(ROOT, ".cursor");
|
|
91180
|
-
if (!
|
|
91435
|
+
if (!existsSync36(dir)) mkdirSync11(dir, { recursive: true });
|
|
91181
91436
|
const file2 = join44(dir, "mcp.json");
|
|
91182
91437
|
let cfg = {};
|
|
91183
|
-
if (
|
|
91438
|
+
if (existsSync36(file2)) {
|
|
91184
91439
|
try {
|
|
91185
|
-
cfg = JSON.parse(
|
|
91440
|
+
cfg = JSON.parse(readFileSync37(file2, "utf8"));
|
|
91186
91441
|
} catch {
|
|
91187
91442
|
console.error(`refusing to overwrite invalid JSON at ${file2}`);
|
|
91188
91443
|
process.exit(2);
|