@inerrata-corporation/errata 2.0.21 → 2.0.22-dev.4049
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 +502 -187
- package/errata.mjs +7106 -5336
- package/generalize-worker.mjs +17489 -0
- package/install.ps1 +1 -1
- package/package.json +2 -1
- package/pass-worker.mjs +3147 -2640
- package/resources/claude-mods/errata-minimap/.claude-plugin/plugin.json +2 -2
- package/resources/claude-mods/errata-minimap/hooks/bookcase.ts +450 -0
- package/resources/claude-mods/errata-minimap/hooks/chains.ts +427 -0
- package/resources/claude-mods/errata-minimap/hooks/graph.ts +349 -0
- package/resources/claude-mods/errata-minimap/hooks/minimap.ts +39 -351
- package/resources/claude-mods/errata-minimap/hooks/register.tsx +440 -148
- package/resources/claude-mods/errata-minimap/hooks/tags.ts +129 -0
- package/resources/claude-mods/errata-minimap/types/index.d.ts +42 -8
- package/resources/context-plugin/.codex-plugin/plugin.json +1 -1
- package/resources/context-plugin/SHA256SUMS +1 -1
package/consolidate-worker.mjs
CHANGED
|
@@ -594,6 +594,13 @@ function aliasRegex(alias) {
|
|
|
594
594
|
const body = escapeRe(alias).replace(/\\?\s+/g, "\\s+");
|
|
595
595
|
return new RegExp(`(?<![\\w-])${body}(?![\\w-])`, "i");
|
|
596
596
|
}
|
|
597
|
+
function withoutEntityMentions(text, entityId) {
|
|
598
|
+
let out = text;
|
|
599
|
+
for (const { entity, re } of COMPILED) {
|
|
600
|
+
if (entity.id === entityId) out = out.replace(new RegExp(re.source, "gi"), " ");
|
|
601
|
+
}
|
|
602
|
+
return out;
|
|
603
|
+
}
|
|
597
604
|
function prefilterEntities(text) {
|
|
598
605
|
const seen = /* @__PURE__ */ new Set();
|
|
599
606
|
const hits = [];
|
|
@@ -770,13 +777,19 @@ var init_concept_bag = __esm({
|
|
|
770
777
|
|
|
771
778
|
// ../../packages/shared/src/nlp/claim-id.ts
|
|
772
779
|
function claimStructure(text, scope) {
|
|
773
|
-
const
|
|
780
|
+
const extracted = prefilterEntities(text);
|
|
781
|
+
const entities = extracted.map((e) => e.id).sort();
|
|
774
782
|
const predicate = normalizePredicate(text);
|
|
775
783
|
const stance = detectStance(text);
|
|
776
784
|
const base = { entities, predicate, stance, scope: scope ?? {} };
|
|
777
|
-
if (predicate === ""
|
|
785
|
+
if (predicate === "" || entities.length === 0 || predicateIsTheEntity(text, extracted[0].id, entities.length)) {
|
|
786
|
+
base.raw = conceptBag(text);
|
|
787
|
+
}
|
|
778
788
|
return base;
|
|
779
789
|
}
|
|
790
|
+
function predicateIsTheEntity(text, entityId, entityCount) {
|
|
791
|
+
return entityCount === 1 && normalizePredicate(withoutEntityMentions(text, entityId)) === "";
|
|
792
|
+
}
|
|
780
793
|
function canonicalClaimId(text, scope) {
|
|
781
794
|
const s = claimStructure(text, scope);
|
|
782
795
|
return digest(
|
|
@@ -15242,6 +15255,36 @@ var init_history_evidence = __esm({
|
|
|
15242
15255
|
});
|
|
15243
15256
|
|
|
15244
15257
|
// ../../packages/shared/src/history-dependencies.ts
|
|
15258
|
+
function historyDependencyIdentity(raw) {
|
|
15259
|
+
const compact = compactDependencyIdentity(raw);
|
|
15260
|
+
if (compact !== void 0) return compact;
|
|
15261
|
+
const parsed = HistoryDependencyContextSchema.safeParse(raw);
|
|
15262
|
+
if (!parsed.success || !parsed.data.complete || parsed.data.conflict) return null;
|
|
15263
|
+
if (parsed.data.dependencies.some((d) => !exactHistoryDependencyVersion(d))) return null;
|
|
15264
|
+
return digest(parsed.data.dependencies.map((d) => [d.packageId, d.manifestId, d.side, d.declaredRange, d.resolvedVersion]).sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b))));
|
|
15265
|
+
}
|
|
15266
|
+
function exactHistoryDependencyVersion(d) {
|
|
15267
|
+
return d.resolvedVersion ?? (/^\d+\.\d+\.\d+(?:-[\w.-]+)?$/.test(d.declaredRange ?? "") ? d.declaredRange : null);
|
|
15268
|
+
}
|
|
15269
|
+
function compactDependencyIdentity(raw) {
|
|
15270
|
+
if (!raw || typeof raw !== "object" || raw.compact !== true) return void 0;
|
|
15271
|
+
const identity = raw.identity;
|
|
15272
|
+
return typeof identity === "string" ? identity : null;
|
|
15273
|
+
}
|
|
15274
|
+
function compactHistoryQuality(quality) {
|
|
15275
|
+
const out = { ...quality };
|
|
15276
|
+
const context = quality["dependencyContext"];
|
|
15277
|
+
if (context !== void 0 && compactDependencyIdentity(context) === void 0) {
|
|
15278
|
+
const compact = { schemaVersion: "history-deps-1", compact: true, identity: historyDependencyIdentity(context) };
|
|
15279
|
+
out["dependencyContext"] = compact;
|
|
15280
|
+
}
|
|
15281
|
+
const evidence = quality["reconciliationEvidence"];
|
|
15282
|
+
if (evidence && typeof evidence === "object" && !Array.isArray(evidence)) {
|
|
15283
|
+
const build = evidence["build"];
|
|
15284
|
+
out["reconciliationEvidence"] = build === void 0 ? {} : { build };
|
|
15285
|
+
}
|
|
15286
|
+
return out;
|
|
15287
|
+
}
|
|
15245
15288
|
var version2, HistoryDependencySchema, HistoryDependencyContextSchema;
|
|
15246
15289
|
var init_history_dependencies = __esm({
|
|
15247
15290
|
"../../packages/shared/src/history-dependencies.ts"() {
|
|
@@ -15726,10 +15769,12 @@ var init_history_quality = __esm({
|
|
|
15726
15769
|
});
|
|
15727
15770
|
|
|
15728
15771
|
// ../../packages/shared/src/history-read.ts
|
|
15772
|
+
var CLOUD_ATTR_DUPLICATE_KEYS;
|
|
15729
15773
|
var init_history_read = __esm({
|
|
15730
15774
|
"../../packages/shared/src/history-read.ts"() {
|
|
15731
15775
|
"use strict";
|
|
15732
15776
|
init_history_dependencies();
|
|
15777
|
+
CLOUD_ATTR_DUPLICATE_KEYS = ["attrsJson", "embedding"];
|
|
15733
15778
|
}
|
|
15734
15779
|
});
|
|
15735
15780
|
|
|
@@ -16396,7 +16441,307 @@ function installEditPlaceholderRetirement(db) {
|
|
|
16396
16441
|
});
|
|
16397
16442
|
}
|
|
16398
16443
|
|
|
16444
|
+
// ../../packages/local-graph/src/cloud-attr-compaction.ts
|
|
16445
|
+
init_src2();
|
|
16446
|
+
var CLOUD_ATTR_COMPACTION_KEY = "cloud-attr-compaction-1";
|
|
16447
|
+
var DUPES = CLOUD_ATTR_DUPLICATE_KEYS.map((k) => `'${k}'`).join(",");
|
|
16448
|
+
function compacted(row) {
|
|
16449
|
+
const packed = `json_extract(${row}.attrs_json, '$.attrsJson')`;
|
|
16450
|
+
const nested = `CASE WHEN json_type(${row}.attrs_json, '$.attrsJson') = 'text' AND json_valid(${packed})
|
|
16451
|
+
AND json_type(${packed}) = 'object' THEN ${packed} ELSE '{}' END`;
|
|
16452
|
+
const value = `CASE WHEN type IN ('array','object') THEN json(value) WHEN type IN ('true','false') THEN json(type) ELSE value END`;
|
|
16453
|
+
return `(SELECT json_group_object(key, ${value}) FROM (
|
|
16454
|
+
SELECT key, value, type, min(pri) FROM (
|
|
16455
|
+
SELECT key, value, type, 0 AS pri FROM json_each(${row}.attrs_json)
|
|
16456
|
+
UNION ALL
|
|
16457
|
+
SELECT key, value, type, 1 AS pri FROM json_each(${nested})
|
|
16458
|
+
) WHERE key NOT IN (${DUPES}) GROUP BY key))`;
|
|
16459
|
+
}
|
|
16460
|
+
function dirty(row) {
|
|
16461
|
+
const has = CLOUD_ATTR_DUPLICATE_KEYS.map((k) => `json_type(${row}.attrs_json, '$.${k}') IS NOT NULL`).join(" OR ");
|
|
16462
|
+
return `json_extract(${row}.attrs_json, '$.source') = 'cloud' AND (${has})`;
|
|
16463
|
+
}
|
|
16464
|
+
function installCloudAttrCompaction(db) {
|
|
16465
|
+
if (db.prepare("SELECT value FROM store_meta WHERE key = ?").get(CLOUD_ATTR_COMPACTION_KEY)) return;
|
|
16466
|
+
db.transaction(() => {
|
|
16467
|
+
for (const operation of ["INSERT", "UPDATE"]) {
|
|
16468
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS cloud_attr_compact_${operation.toLowerCase()}
|
|
16469
|
+
AFTER ${operation} ON nodes WHEN ${dirty("NEW")}
|
|
16470
|
+
BEGIN UPDATE nodes SET attrs_json = ${compacted("nodes")} WHERE id = NEW.id; END;`);
|
|
16471
|
+
}
|
|
16472
|
+
db.exec(`UPDATE nodes SET attrs_json = ${compacted("nodes")} WHERE ${dirty("nodes")}`);
|
|
16473
|
+
db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(CLOUD_ATTR_COMPACTION_KEY, "installed");
|
|
16474
|
+
});
|
|
16475
|
+
}
|
|
16476
|
+
|
|
16477
|
+
// ../../packages/local-graph/src/history-attr-slim.ts
|
|
16478
|
+
init_src();
|
|
16479
|
+
var HISTORY_ATTR_SLIM_KEY = "history-attr-slim-1";
|
|
16480
|
+
var SLIM_BATCH = 500;
|
|
16481
|
+
function installHistoryAttrSlim(db) {
|
|
16482
|
+
if (db.prepare("SELECT value FROM store_meta WHERE key = ?").get(HISTORY_ATTR_SLIM_KEY)) return;
|
|
16483
|
+
const select = db.prepare(`SELECT rowid AS rid, json_extract(attrs_json, '$.historyQuality') AS q FROM nodes
|
|
16484
|
+
WHERE rowid > ? AND (json_type(attrs_json, '$.historyQuality.dependencyContext.dependencies') IS NOT NULL
|
|
16485
|
+
OR json_type(attrs_json, '$.historyQuality.reconciliationEvidence') = 'object')
|
|
16486
|
+
ORDER BY rowid LIMIT ${SLIM_BATCH}`);
|
|
16487
|
+
const write = db.prepare(`UPDATE nodes SET attrs_json = json_set(attrs_json, '$.historyQuality', json(?)) WHERE rowid = ?`);
|
|
16488
|
+
let after = 0;
|
|
16489
|
+
for (; ; ) {
|
|
16490
|
+
const rows = select.all(after);
|
|
16491
|
+
if (rows.length === 0) break;
|
|
16492
|
+
db.transaction(() => {
|
|
16493
|
+
for (const { rid, q } of rows) {
|
|
16494
|
+
if (!q) continue;
|
|
16495
|
+
let quality;
|
|
16496
|
+
try {
|
|
16497
|
+
quality = JSON.parse(q);
|
|
16498
|
+
} catch {
|
|
16499
|
+
continue;
|
|
16500
|
+
}
|
|
16501
|
+
if (!quality || typeof quality !== "object" || Array.isArray(quality)) continue;
|
|
16502
|
+
const slim = JSON.stringify(compactHistoryQuality(quality));
|
|
16503
|
+
if (slim !== q) write.run(slim, rid);
|
|
16504
|
+
}
|
|
16505
|
+
});
|
|
16506
|
+
after = rows[rows.length - 1].rid;
|
|
16507
|
+
}
|
|
16508
|
+
db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(HISTORY_ATTR_SLIM_KEY, "done");
|
|
16509
|
+
}
|
|
16510
|
+
|
|
16511
|
+
// ../../packages/local-graph/src/text-index.ts
|
|
16512
|
+
var TEXT_INDEX_KEY = "text-index-trigram-1";
|
|
16513
|
+
var TEXT_INDEX_MIN_TERM = 3;
|
|
16514
|
+
function installTextIndex(db) {
|
|
16515
|
+
if (db.prepare("SELECT value FROM store_meta WHERE key = ?").get(TEXT_INDEX_KEY)) return;
|
|
16516
|
+
try {
|
|
16517
|
+
db.exec(`CREATE VIRTUAL TABLE temp.fts5_probe USING fts5(x, tokenize='trigram'); DROP TABLE temp.fts5_probe`);
|
|
16518
|
+
} catch {
|
|
16519
|
+
db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(TEXT_INDEX_KEY, "unavailable");
|
|
16520
|
+
return;
|
|
16521
|
+
}
|
|
16522
|
+
db.transaction(() => {
|
|
16523
|
+
db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS nodes_text
|
|
16524
|
+
USING fts5(description, content='nodes', content_rowid='rowid', tokenize='trigram')`);
|
|
16525
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_insert AFTER INSERT ON nodes WHEN NEW.valid_to IS NULL
|
|
16526
|
+
BEGIN INSERT INTO nodes_text(rowid, description) VALUES (NEW.rowid, NEW.description); END;`);
|
|
16527
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_update_out AFTER UPDATE OF description, valid_to ON nodes
|
|
16528
|
+
WHEN OLD.valid_to IS NULL
|
|
16529
|
+
BEGIN INSERT INTO nodes_text(nodes_text, rowid, description) VALUES ('delete', OLD.rowid, OLD.description); END;`);
|
|
16530
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_update_in AFTER UPDATE OF description, valid_to ON nodes
|
|
16531
|
+
WHEN NEW.valid_to IS NULL
|
|
16532
|
+
BEGIN INSERT INTO nodes_text(rowid, description) VALUES (NEW.rowid, NEW.description); END;`);
|
|
16533
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_delete AFTER DELETE ON nodes WHEN OLD.valid_to IS NULL
|
|
16534
|
+
BEGIN INSERT INTO nodes_text(nodes_text, rowid, description) VALUES ('delete', OLD.rowid, OLD.description); END;`);
|
|
16535
|
+
db.exec(`INSERT INTO nodes_text(rowid, description) SELECT rowid, description FROM nodes WHERE valid_to IS NULL`);
|
|
16536
|
+
db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(TEXT_INDEX_KEY, "installed");
|
|
16537
|
+
});
|
|
16538
|
+
}
|
|
16539
|
+
function textIndexReady(db) {
|
|
16540
|
+
return db.prepare("SELECT value FROM store_meta WHERE key = ?").get(TEXT_INDEX_KEY)?.["value"] === "installed";
|
|
16541
|
+
}
|
|
16542
|
+
|
|
16543
|
+
// ../../packages/math/src/constants.ts
|
|
16544
|
+
var NEMORI_DEDUP_COSINE = 0.88;
|
|
16545
|
+
|
|
16546
|
+
// ../../packages/math/src/triage.ts
|
|
16547
|
+
var TRIAGE_GLOBAL_BUCKET = "*";
|
|
16548
|
+
function triageContextBuckets(ctx) {
|
|
16549
|
+
const out = [];
|
|
16550
|
+
for (const s of ctx.stack ?? []) {
|
|
16551
|
+
const t = s.trim().toLowerCase();
|
|
16552
|
+
if (t) out.push(`stack:${t}`);
|
|
16553
|
+
}
|
|
16554
|
+
const domains = Array.isArray(ctx.domain) ? ctx.domain : typeof ctx.domain === "string" ? [ctx.domain] : [];
|
|
16555
|
+
for (const d of domains) {
|
|
16556
|
+
const t = d.trim().toLowerCase();
|
|
16557
|
+
if (t) out.push(`domain:${t}`);
|
|
16558
|
+
}
|
|
16559
|
+
return out;
|
|
16560
|
+
}
|
|
16561
|
+
|
|
16562
|
+
// ../../packages/math/src/relevance.ts
|
|
16563
|
+
function pageRankScale(ranks) {
|
|
16564
|
+
const positive = [...ranks].filter((r) => Number.isFinite(r) && r > 0).sort((a, b) => a - b);
|
|
16565
|
+
return positive.length ? Math.max(1e-9, positive[Math.floor((positive.length - 1) * 0.95)]) : 1;
|
|
16566
|
+
}
|
|
16567
|
+
|
|
16568
|
+
// ../../packages/math/src/leiden.ts
|
|
16569
|
+
function buildGraph(nodeIds, adj) {
|
|
16570
|
+
const nbr = /* @__PURE__ */ new Map();
|
|
16571
|
+
const deg = /* @__PURE__ */ new Map();
|
|
16572
|
+
const present = new Set(nodeIds);
|
|
16573
|
+
for (const id of nodeIds) {
|
|
16574
|
+
nbr.set(id, /* @__PURE__ */ new Map());
|
|
16575
|
+
deg.set(id, 0);
|
|
16576
|
+
}
|
|
16577
|
+
let m2 = 0;
|
|
16578
|
+
for (const id of nodeIds) {
|
|
16579
|
+
for (const { to, weight } of adj.get(id) ?? []) {
|
|
16580
|
+
if (!present.has(to)) continue;
|
|
16581
|
+
const row = nbr.get(id);
|
|
16582
|
+
row.set(to, (row.get(to) ?? 0) + weight);
|
|
16583
|
+
deg.set(id, (deg.get(id) ?? 0) + weight);
|
|
16584
|
+
m2 += weight;
|
|
16585
|
+
}
|
|
16586
|
+
}
|
|
16587
|
+
return { nbr, deg, m2 };
|
|
16588
|
+
}
|
|
16589
|
+
function localMoving(nodeIds, g) {
|
|
16590
|
+
const community = new Map(nodeIds.map((n) => [n, n]));
|
|
16591
|
+
const comTot = new Map(nodeIds.map((n) => [n, g.deg.get(n) ?? 0]));
|
|
16592
|
+
const order = [...nodeIds].sort();
|
|
16593
|
+
const m2 = g.m2 > 0 ? g.m2 : 1;
|
|
16594
|
+
let improved = true;
|
|
16595
|
+
let iter = 0;
|
|
16596
|
+
while (improved && iter < 100) {
|
|
16597
|
+
improved = false;
|
|
16598
|
+
iter++;
|
|
16599
|
+
for (const node of order) {
|
|
16600
|
+
const ci = community.get(node);
|
|
16601
|
+
const ki = g.deg.get(node) ?? 0;
|
|
16602
|
+
comTot.set(ci, (comTot.get(ci) ?? 0) - ki);
|
|
16603
|
+
const wToComm = /* @__PURE__ */ new Map();
|
|
16604
|
+
for (const [nb, w] of g.nbr.get(node) ?? []) {
|
|
16605
|
+
if (nb === node) continue;
|
|
16606
|
+
const c = community.get(nb);
|
|
16607
|
+
wToComm.set(c, (wToComm.get(c) ?? 0) + w);
|
|
16608
|
+
}
|
|
16609
|
+
let bestC = ci;
|
|
16610
|
+
let bestGain = (wToComm.get(ci) ?? 0) - (comTot.get(ci) ?? 0) * ki / m2;
|
|
16611
|
+
for (const [c, kiIn] of [...wToComm.entries()].sort(
|
|
16612
|
+
(a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0
|
|
16613
|
+
)) {
|
|
16614
|
+
const gain = kiIn - (comTot.get(c) ?? 0) * ki / m2;
|
|
16615
|
+
if (gain > bestGain) {
|
|
16616
|
+
bestGain = gain;
|
|
16617
|
+
bestC = c;
|
|
16618
|
+
}
|
|
16619
|
+
}
|
|
16620
|
+
community.set(node, bestC);
|
|
16621
|
+
comTot.set(bestC, (comTot.get(bestC) ?? 0) + ki);
|
|
16622
|
+
if (bestC !== ci) improved = true;
|
|
16623
|
+
}
|
|
16624
|
+
}
|
|
16625
|
+
return community;
|
|
16626
|
+
}
|
|
16627
|
+
function refineConnectivity(community, g) {
|
|
16628
|
+
const members = /* @__PURE__ */ new Map();
|
|
16629
|
+
for (const [id, c] of community) {
|
|
16630
|
+
const l = members.get(c) ?? [];
|
|
16631
|
+
l.push(id);
|
|
16632
|
+
members.set(c, l);
|
|
16633
|
+
}
|
|
16634
|
+
const refined = /* @__PURE__ */ new Map();
|
|
16635
|
+
for (const [, group] of members) {
|
|
16636
|
+
const inGroup = new Set(group);
|
|
16637
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16638
|
+
for (const start of [...group].sort()) {
|
|
16639
|
+
if (seen.has(start)) continue;
|
|
16640
|
+
const comp = [];
|
|
16641
|
+
const stack = [start];
|
|
16642
|
+
seen.add(start);
|
|
16643
|
+
while (stack.length) {
|
|
16644
|
+
const cur = stack.pop();
|
|
16645
|
+
comp.push(cur);
|
|
16646
|
+
for (const [nb] of g.nbr.get(cur) ?? []) {
|
|
16647
|
+
if (inGroup.has(nb) && !seen.has(nb)) {
|
|
16648
|
+
seen.add(nb);
|
|
16649
|
+
stack.push(nb);
|
|
16650
|
+
}
|
|
16651
|
+
}
|
|
16652
|
+
}
|
|
16653
|
+
const anchor = [...comp].sort()[0];
|
|
16654
|
+
for (const id of comp) refined.set(id, anchor);
|
|
16655
|
+
}
|
|
16656
|
+
}
|
|
16657
|
+
return refined;
|
|
16658
|
+
}
|
|
16659
|
+
function normalize(assignment) {
|
|
16660
|
+
const groups = /* @__PURE__ */ new Map();
|
|
16661
|
+
for (const [id, c] of assignment) {
|
|
16662
|
+
const l = groups.get(c) ?? [];
|
|
16663
|
+
l.push(id);
|
|
16664
|
+
groups.set(c, l);
|
|
16665
|
+
}
|
|
16666
|
+
const community = /* @__PURE__ */ new Map();
|
|
16667
|
+
for (const grp of groups.values()) {
|
|
16668
|
+
const anchor = [...grp].sort()[0];
|
|
16669
|
+
const cid = `community_${anchor}`;
|
|
16670
|
+
for (const m of grp) community.set(m, cid);
|
|
16671
|
+
}
|
|
16672
|
+
return { community, count: groups.size, iterations: 1 };
|
|
16673
|
+
}
|
|
16674
|
+
function causalComponents(nodeIds, pairs) {
|
|
16675
|
+
const parent = new Map(nodeIds.map((n) => [n, n]));
|
|
16676
|
+
const find = (x) => {
|
|
16677
|
+
let r = x;
|
|
16678
|
+
while (parent.get(r) !== r) r = parent.get(r);
|
|
16679
|
+
let c = x;
|
|
16680
|
+
while (parent.get(c) !== r) {
|
|
16681
|
+
const next = parent.get(c);
|
|
16682
|
+
parent.set(c, r);
|
|
16683
|
+
c = next;
|
|
16684
|
+
}
|
|
16685
|
+
return r;
|
|
16686
|
+
};
|
|
16687
|
+
for (const [a, b] of pairs) {
|
|
16688
|
+
const ra = find(a);
|
|
16689
|
+
const rb = find(b);
|
|
16690
|
+
if (ra !== rb) parent.set(ra < rb ? rb : ra, ra < rb ? ra : rb);
|
|
16691
|
+
}
|
|
16692
|
+
return find;
|
|
16693
|
+
}
|
|
16694
|
+
function detectCommunitiesLeiden(input, opts = {}) {
|
|
16695
|
+
const idSet = new Set(input.nodeIds);
|
|
16696
|
+
const protect = [...opts.protect ?? []].filter(
|
|
16697
|
+
([a, b]) => a !== b && idSet.has(a) && idSet.has(b)
|
|
16698
|
+
);
|
|
16699
|
+
if (protect.length === 0) {
|
|
16700
|
+
const g = buildGraph(input.nodeIds, input.adj);
|
|
16701
|
+
return normalize(refineConnectivity(localMoving(input.nodeIds, g), g));
|
|
16702
|
+
}
|
|
16703
|
+
const rep = causalComponents(input.nodeIds, protect);
|
|
16704
|
+
const superIds = [...new Set(input.nodeIds.map(rep))];
|
|
16705
|
+
const superAdj = /* @__PURE__ */ new Map();
|
|
16706
|
+
const acc = /* @__PURE__ */ new Map();
|
|
16707
|
+
for (const id of input.nodeIds) {
|
|
16708
|
+
const ra = rep(id);
|
|
16709
|
+
for (const { to, weight } of input.adj.get(id) ?? []) {
|
|
16710
|
+
if (!idSet.has(to)) continue;
|
|
16711
|
+
const rb = rep(to);
|
|
16712
|
+
if (ra === rb) continue;
|
|
16713
|
+
const row = acc.get(ra) ?? /* @__PURE__ */ new Map();
|
|
16714
|
+
row.set(rb, (row.get(rb) ?? 0) + weight);
|
|
16715
|
+
acc.set(ra, row);
|
|
16716
|
+
}
|
|
16717
|
+
}
|
|
16718
|
+
for (const [a, row] of acc) superAdj.set(a, [...row].map(([to, weight]) => ({ to, weight })));
|
|
16719
|
+
const sg = buildGraph(superIds, superAdj);
|
|
16720
|
+
const superComm = refineConnectivity(localMoving(superIds, sg), sg);
|
|
16721
|
+
const assignment = /* @__PURE__ */ new Map();
|
|
16722
|
+
for (const id of input.nodeIds) assignment.set(id, superComm.get(rep(id)) ?? rep(id));
|
|
16723
|
+
return normalize(assignment);
|
|
16724
|
+
}
|
|
16725
|
+
|
|
16726
|
+
// ../../packages/math/src/void-demand.ts
|
|
16727
|
+
var DEMAND_HOT = Math.log1p(10);
|
|
16728
|
+
var DEMAND_WARM = Math.log1p(5);
|
|
16729
|
+
|
|
16399
16730
|
// ../../packages/local-graph/src/store.ts
|
|
16731
|
+
var PAGE_RANK_SCALE_KEY = "pageRankScale.p95.v1";
|
|
16732
|
+
var TEXT_SEARCH_COLUMNS = `id, label, description, page_rank,
|
|
16733
|
+
json_object('test', json(CASE WHEN json_type(attrs_json, '$.test') = 'true' THEN 'true' ELSE 'false' END),
|
|
16734
|
+
'relPath', json_extract(attrs_json, '$.relPath'),
|
|
16735
|
+
'resolutionSuspect', json(CASE WHEN json_type(attrs_json, '$.resolutionSuspect') = 'true' THEN 'true' ELSE 'false' END),
|
|
16736
|
+
'resolvedAt', json_extract(attrs_json, '$.resolvedAt'),
|
|
16737
|
+
'refutedAt', json_extract(attrs_json, '$.refutedAt'),
|
|
16738
|
+
'refuteReasons', json_extract(attrs_json, '$.refuteReasons'),
|
|
16739
|
+
'reopenedFrom', json_extract(attrs_json, '$.reopenedFrom'),
|
|
16740
|
+
'resolvedAs', json_extract(attrs_json, '$.resolvedAs')) AS search_attrs`;
|
|
16741
|
+
function textSearchNode(row) {
|
|
16742
|
+
const attrs = JSON.parse(row.search_attrs);
|
|
16743
|
+
return { id: row.id, label: row.label, description: row.description, pageRank: row.page_rank, attrs };
|
|
16744
|
+
}
|
|
16400
16745
|
var LOCAL_RULE_OVERRIDES = {
|
|
16401
16746
|
ANCHORED_AT: {
|
|
16402
16747
|
from: EDGE_RULES["ANCHORED_AT"]?.from,
|
|
@@ -16540,6 +16885,9 @@ CREATE INDEX IF NOT EXISTS edges_session_evidence ON edges(id) WHERE ${SESSION_E
|
|
|
16540
16885
|
DROP INDEX IF EXISTS nodes_live_fingerprint;
|
|
16541
16886
|
DROP INDEX IF EXISTS nodes_instance_fingerprint;
|
|
16542
16887
|
CREATE INDEX IF NOT EXISTS nodes_instance_fingerprint_v2 ON nodes(label, last_updated_at, last_reinforced_at_seq, created_at_seq) WHERE valid_to IS NULL AND label IN ('Problem','Vulnerability','Solution','RootCause');
|
|
16888
|
+
-- Calibrate rank from a covering scalar index; the global page-rank index
|
|
16889
|
+
-- requires a table lookup per node to exclude frozen versions.
|
|
16890
|
+
CREATE INDEX IF NOT EXISTS nodes_live_page_rank ON nodes(valid_to, page_rank);
|
|
16543
16891
|
CREATE INDEX IF NOT EXISTS nodes_logical ON nodes(logical_id, version);
|
|
16544
16892
|
CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
|
|
16545
16893
|
-- Expression index on the per-node relPath (stored in attrs_json) so the
|
|
@@ -16552,6 +16900,16 @@ CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) W
|
|
|
16552
16900
|
-- Problems by the file their anchor hint names: the harvest upgrades hints for
|
|
16553
16901
|
-- every edited file of every turn, and a scan parses every Problem's attrs.
|
|
16554
16902
|
CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_json, '$.anchorHint.path')) WHERE valid_to IS NULL;
|
|
16903
|
+
-- Problems by the command / checker / file that opened them. The generalizer
|
|
16904
|
+
-- looked these up per shell or tool EVENT by hydrating every Problem: ~12s of
|
|
16905
|
+
-- every minute of daemon main-thread time on a 3.4k-Problem store (2026-10-05).
|
|
16906
|
+
CREATE INDEX IF NOT EXISTS nodes_command_signature ON nodes(json_extract(attrs_json, '$.commandSignature')) WHERE valid_to IS NULL;
|
|
16907
|
+
CREATE INDEX IF NOT EXISTS nodes_diag_command ON nodes(json_extract(attrs_json, '$.diagCommand')) WHERE valid_to IS NULL;
|
|
16908
|
+
CREATE INDEX IF NOT EXISTS nodes_lsp_rel_path ON nodes(json_extract(attrs_json, '$.lspRelPath')) WHERE valid_to IS NULL;
|
|
16909
|
+
-- Local nodes by the cloud twin their upload receipt recorded. Every burst /
|
|
16910
|
+
-- search fusion folds the Network copy of the caller's own knowledge back onto
|
|
16911
|
+
-- the local node; unindexed, the reverse lookup was a ~300ms attrs scan per call.
|
|
16912
|
+
CREATE INDEX IF NOT EXISTS nodes_cloud_node_id ON nodes(json_extract(attrs_json, '$.cloudNodeId')) WHERE valid_to IS NULL;
|
|
16555
16913
|
-- Nodes still waiting on a root-cause ask. The MCP server checks this on EVERY
|
|
16556
16914
|
-- tool response (the enrichment piggyback), so it must not parse every
|
|
16557
16915
|
-- Solution's and Problem's attrs per call. Not partial: the Problem pull reads
|
|
@@ -16638,6 +16996,7 @@ var SqliteGraphStore = class {
|
|
|
16638
16996
|
* ALL upserts incl. code reindex) — this counter is the knowledge-arrival axis
|
|
16639
16997
|
* Δseq is measured over, so code reindex churn must NOT advance it. */
|
|
16640
16998
|
ingestSeq = 0;
|
|
16999
|
+
initialPageRankScale;
|
|
16641
17000
|
constructor(opts) {
|
|
16642
17001
|
this.db = openDatabase(opts.path);
|
|
16643
17002
|
this.db.exec(SCHEMA_SQL);
|
|
@@ -16654,6 +17013,9 @@ var SqliteGraphStore = class {
|
|
|
16654
17013
|
this.db.exec(TEMPORAL_INDEX_SQL);
|
|
16655
17014
|
installHistoryCacheFloor(this.db);
|
|
16656
17015
|
installEditPlaceholderRetirement(this.db);
|
|
17016
|
+
installCloudAttrCompaction(this.db);
|
|
17017
|
+
installHistoryAttrSlim(this.db);
|
|
17018
|
+
installTextIndex(this.db);
|
|
16657
17019
|
if (!this.db.prepare("SELECT value FROM store_meta WHERE key = ?").get(SESSION_REPAIR_KEY)) {
|
|
16658
17020
|
this.db.transaction(() => {
|
|
16659
17021
|
this.repairSessionAliases();
|
|
@@ -16705,6 +17067,12 @@ var SqliteGraphStore = class {
|
|
|
16705
17067
|
setPageRank: this.db.prepare("UPDATE nodes SET page_rank = :v WHERE id = :id"),
|
|
16706
17068
|
setLandmark: this.db.prepare("UPDATE nodes SET is_landmark = :v WHERE id = :id"),
|
|
16707
17069
|
setCommunity: this.db.prepare("UPDATE nodes SET community = :v WHERE id = :id"),
|
|
17070
|
+
setLocalCommunity: this.db.prepare(`
|
|
17071
|
+
UPDATE nodes SET
|
|
17072
|
+
attrs_json = CASE WHEN :v IS NULL THEN json_remove(attrs_json, '$.localCommunity')
|
|
17073
|
+
ELSE json_set(attrs_json, '$.localCommunity', :v) END,
|
|
17074
|
+
community = CASE WHEN :col = 1 THEN :v ELSE community END
|
|
17075
|
+
WHERE id = :id`),
|
|
16708
17076
|
updateNode: this.db.prepare(`
|
|
16709
17077
|
UPDATE nodes SET
|
|
16710
17078
|
description = COALESCE(:description, description),
|
|
@@ -17025,6 +17393,36 @@ var SqliteGraphStore = class {
|
|
|
17025
17393
|
setLandmark(id, isLandmark) {
|
|
17026
17394
|
this.stmts.setLandmark.run({ id, v: isLandmark ? 1 : 0 });
|
|
17027
17395
|
}
|
|
17396
|
+
setLocalCommunity(id, community, column) {
|
|
17397
|
+
this.stmts.setLocalCommunity.run({ id, v: community, col: column ? 1 : 0 });
|
|
17398
|
+
}
|
|
17399
|
+
fieldStmts = /* @__PURE__ */ new Map();
|
|
17400
|
+
findNodeFieldsByLabel(label, attrKeys) {
|
|
17401
|
+
for (const k of attrKeys) if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) throw new Error(`findNodeFieldsByLabel: bad attr key ${k}`);
|
|
17402
|
+
const cacheKey = attrKeys.join(",");
|
|
17403
|
+
let stmt = this.fieldStmts.get(cacheKey);
|
|
17404
|
+
if (!stmt) {
|
|
17405
|
+
const cols = attrKeys.map((k, i) => `, json_extract(attrs_json, '$.${k}') AS a${i}`).join("");
|
|
17406
|
+
stmt = this.db.prepare(
|
|
17407
|
+
`SELECT id, description, community, extraction_confidence${cols} FROM nodes WHERE label = ? AND valid_to IS NULL`
|
|
17408
|
+
);
|
|
17409
|
+
this.fieldStmts.set(cacheKey, stmt);
|
|
17410
|
+
}
|
|
17411
|
+
return stmt.all(label).map((r) => {
|
|
17412
|
+
const attrs = {};
|
|
17413
|
+
attrKeys.forEach((k, i) => {
|
|
17414
|
+
const v = r[`a${i}`];
|
|
17415
|
+
if (v !== null && v !== void 0) attrs[k] = v;
|
|
17416
|
+
});
|
|
17417
|
+
return {
|
|
17418
|
+
id: r["id"],
|
|
17419
|
+
description: r["description"] ?? "",
|
|
17420
|
+
community: r["community"] ?? null,
|
|
17421
|
+
extractionConfidence: r["extraction_confidence"],
|
|
17422
|
+
attrs
|
|
17423
|
+
};
|
|
17424
|
+
});
|
|
17425
|
+
}
|
|
17028
17426
|
setCommunity(id, community) {
|
|
17029
17427
|
this.stmts.setCommunity.run({ id, v: community });
|
|
17030
17428
|
}
|
|
@@ -17151,6 +17549,19 @@ var SqliteGraphStore = class {
|
|
|
17151
17549
|
* read attrs and never the vector. `findNodesByLabel` decodes every embedding
|
|
17152
17550
|
* blob; the liveness watch's coverage pass spent 3.4s of a 4.3s main-thread
|
|
17153
17551
|
* hold doing exactly that on a 227k-node store (2026-09-24). */
|
|
17552
|
+
findNodeStampsByLabel(label, attrKey) {
|
|
17553
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(attrKey)) throw new Error(`findNodeStampsByLabel: bad attr key ${attrKey}`);
|
|
17554
|
+
const rows = this.db.prepare(
|
|
17555
|
+
`SELECT id, created_at, created_at_seq, json_type(attrs_json, '$.${attrKey}') IS NOT NULL AS has
|
|
17556
|
+
FROM nodes WHERE label = ? AND valid_to IS NULL`
|
|
17557
|
+
).all(label);
|
|
17558
|
+
return rows.map((r) => ({
|
|
17559
|
+
id: r.id,
|
|
17560
|
+
createdAt: r.created_at,
|
|
17561
|
+
...r.created_at_seq != null ? { createdAtSeq: r.created_at_seq } : {},
|
|
17562
|
+
has: r.has === 1
|
|
17563
|
+
}));
|
|
17564
|
+
}
|
|
17154
17565
|
findNodeAttrsByLabel(label) {
|
|
17155
17566
|
const rows = this.stmts.attrsByLabel.all(label);
|
|
17156
17567
|
return rows.map((r) => ({
|
|
@@ -17257,6 +17668,60 @@ var SqliteGraphStore = class {
|
|
|
17257
17668
|
).all(...terms.map((t) => `%${t}%`), Math.max(1, limit));
|
|
17258
17669
|
return rows.map((r) => ({ node: rowToNode(r), matched: Number(r.matched) }));
|
|
17259
17670
|
}
|
|
17671
|
+
searchTextCandidates(terms) {
|
|
17672
|
+
if (terms.length === 0) return [];
|
|
17673
|
+
const indexed = terms.filter((t) => t.length >= TEXT_INDEX_MIN_TERM);
|
|
17674
|
+
if (indexed.length > 0 && textIndexReady(this.db)) {
|
|
17675
|
+
const short = terms.filter((t) => t.length < TEXT_INDEX_MIN_TERM).map((t) => t.toLowerCase());
|
|
17676
|
+
const rows2 = this.db.prepare(`WITH hits AS MATERIALIZED (
|
|
17677
|
+
SELECT t.rowid AS rid, COUNT(*) AS matched FROM json_each(:terms) q, nodes_text t
|
|
17678
|
+
WHERE t.description LIKE '%' || q.value || '%' GROUP BY t.rowid
|
|
17679
|
+
) SELECT ${TEXT_SEARCH_COLUMNS}, hits.matched FROM hits JOIN nodes ON nodes.rowid = hits.rid
|
|
17680
|
+
WHERE nodes.valid_to IS NULL ORDER BY page_rank DESC, last_updated_at DESC`).all({ terms: JSON.stringify(indexed) });
|
|
17681
|
+
return rows2.map((row) => {
|
|
17682
|
+
const text = row.description.toLowerCase();
|
|
17683
|
+
const extra = short.filter((t) => text.includes(t)).length;
|
|
17684
|
+
return { node: textSearchNode(row), matched: row.matched + extra };
|
|
17685
|
+
});
|
|
17686
|
+
}
|
|
17687
|
+
const rows = this.db.prepare(`WITH matches AS MATERIALIZED (
|
|
17688
|
+
SELECT n.id, COUNT(*) AS matched FROM nodes n INDEXED BY nodes_live_description, json_each(:terms) t
|
|
17689
|
+
WHERE n.valid_to IS NULL AND n.description LIKE '%' || t.value || '%'
|
|
17690
|
+
GROUP BY n.id
|
|
17691
|
+
) SELECT ${TEXT_SEARCH_COLUMNS}, matches.matched FROM nodes
|
|
17692
|
+
JOIN matches USING (id) ORDER BY page_rank DESC, last_updated_at DESC`).all({ terms: JSON.stringify(terms) });
|
|
17693
|
+
return rows.map((row) => ({ node: textSearchNode(row), matched: row.matched }));
|
|
17694
|
+
}
|
|
17695
|
+
commentAnchors(commentIds) {
|
|
17696
|
+
const out = /* @__PURE__ */ new Map();
|
|
17697
|
+
if (commentIds.length === 0) return out;
|
|
17698
|
+
const rows = this.db.prepare(`WITH a AS MATERIALIZED (
|
|
17699
|
+
SELECT q.value AS cid, COALESCE(
|
|
17700
|
+
(SELECT to_id FROM edges WHERE from_id = q.value AND type IN ('EXPLAINS', 'ANNOTATES') AND valid_to IS NULL LIMIT 1),
|
|
17701
|
+
(SELECT from_id FROM edges WHERE to_id = q.value AND type = 'DOCUMENTED_BY' AND valid_to IS NULL LIMIT 1)
|
|
17702
|
+
) AS aid FROM json_each(:ids) q
|
|
17703
|
+
) SELECT a.cid AS cid, ${TEXT_SEARCH_COLUMNS} FROM a JOIN nodes ON nodes.id = a.aid AND nodes.valid_to IS NULL`).all({ ids: JSON.stringify(commentIds) });
|
|
17704
|
+
for (const row of rows) out.set(row.cid, textSearchNode(row));
|
|
17705
|
+
return out;
|
|
17706
|
+
}
|
|
17707
|
+
getTextSearchNode(id) {
|
|
17708
|
+
const row = this.db.prepare(`SELECT ${TEXT_SEARCH_COLUMNS} FROM nodes WHERE id = ? AND valid_to IS NULL`).get(id);
|
|
17709
|
+
return row ? textSearchNode(row) : null;
|
|
17710
|
+
}
|
|
17711
|
+
readPageRankScale() {
|
|
17712
|
+
const rows = this.db.prepare("SELECT page_rank FROM nodes WHERE valid_to IS NULL AND page_rank > 0").all();
|
|
17713
|
+
return pageRankScale(rows.map((row) => row.page_rank));
|
|
17714
|
+
}
|
|
17715
|
+
pageRankScale() {
|
|
17716
|
+
const value = Number(this.getMeta(PAGE_RANK_SCALE_KEY));
|
|
17717
|
+
if (Number.isFinite(value) && value > 0) return value;
|
|
17718
|
+
return this.initialPageRankScale ??= this.readPageRankScale();
|
|
17719
|
+
}
|
|
17720
|
+
refreshPageRankScale() {
|
|
17721
|
+
const scale = this.readPageRankScale();
|
|
17722
|
+
this.setMeta(PAGE_RANK_SCALE_KEY, String(scale));
|
|
17723
|
+
return scale;
|
|
17724
|
+
}
|
|
17260
17725
|
typedEdgeStmt(sql) {
|
|
17261
17726
|
let stmt = this.typedEdgeStmts.get(sql);
|
|
17262
17727
|
if (!stmt) {
|
|
@@ -17491,6 +17956,19 @@ var SqliteGraphStore = class {
|
|
|
17491
17956
|
).get(attr, `%${marker}%`, limit);
|
|
17492
17957
|
return { count: Number(r.count), total: Number(r.total) };
|
|
17493
17958
|
}
|
|
17959
|
+
liveNodeIdsByCloudNodeId(cloudIds) {
|
|
17960
|
+
const out = /* @__PURE__ */ new Map();
|
|
17961
|
+
const CHUNK = 900;
|
|
17962
|
+
for (let i = 0; i < cloudIds.length; i += CHUNK) {
|
|
17963
|
+
const slice = cloudIds.slice(i, i + CHUNK);
|
|
17964
|
+
if (slice.length === 0) continue;
|
|
17965
|
+
const rows = this.db.prepare(
|
|
17966
|
+
`SELECT id, json_extract(attrs_json, '$.cloudNodeId') AS cloud FROM nodes INDEXED BY nodes_cloud_node_id WHERE json_extract(attrs_json, '$.cloudNodeId') IN (${slice.map(() => "?").join(",")}) AND valid_to IS NULL ORDER BY id`
|
|
17967
|
+
).all(...slice);
|
|
17968
|
+
for (const r of rows) out.set(r.cloud, [...out.get(r.cloud) ?? [], r.id]);
|
|
17969
|
+
}
|
|
17970
|
+
return out;
|
|
17971
|
+
}
|
|
17494
17972
|
liveNodeIds(ids) {
|
|
17495
17973
|
const live = /* @__PURE__ */ new Set();
|
|
17496
17974
|
const CHUNK = 900;
|
|
@@ -17552,7 +18030,10 @@ var SqliteGraphStore = class {
|
|
|
17552
18030
|
if (relPaths.length === 0) return [];
|
|
17553
18031
|
const placeholders = relPaths.map(() => "?").join(",");
|
|
17554
18032
|
const rows = this.db.prepare(
|
|
17555
|
-
|
|
18033
|
+
// INDEXED BY: unforced, the planner took nodes_live_page_rank and
|
|
18034
|
+
// json-parsed every live row — 11–25s per reindexed file pair on the
|
|
18035
|
+
// live store vs 7ms here (2026-10-08).
|
|
18036
|
+
`SELECT * FROM nodes INDEXED BY nodes_relpath WHERE valid_to IS NULL AND json_extract(attrs_json, '$.relPath') IN (${placeholders})`
|
|
17556
18037
|
).all(...relPaths);
|
|
17557
18038
|
return rows.map(rowToNode);
|
|
17558
18039
|
}
|
|
@@ -17802,183 +18283,6 @@ function percolate(l1, l2, opts) {
|
|
|
17802
18283
|
init_src();
|
|
17803
18284
|
init_src2();
|
|
17804
18285
|
|
|
17805
|
-
// ../../packages/math/src/constants.ts
|
|
17806
|
-
var NEMORI_DEDUP_COSINE = 0.88;
|
|
17807
|
-
|
|
17808
|
-
// ../../packages/math/src/triage.ts
|
|
17809
|
-
var TRIAGE_GLOBAL_BUCKET = "*";
|
|
17810
|
-
function triageContextBuckets(ctx) {
|
|
17811
|
-
const out = [];
|
|
17812
|
-
for (const s of ctx.stack ?? []) {
|
|
17813
|
-
const t = s.trim().toLowerCase();
|
|
17814
|
-
if (t) out.push(`stack:${t}`);
|
|
17815
|
-
}
|
|
17816
|
-
const domains = Array.isArray(ctx.domain) ? ctx.domain : typeof ctx.domain === "string" ? [ctx.domain] : [];
|
|
17817
|
-
for (const d of domains) {
|
|
17818
|
-
const t = d.trim().toLowerCase();
|
|
17819
|
-
if (t) out.push(`domain:${t}`);
|
|
17820
|
-
}
|
|
17821
|
-
return out;
|
|
17822
|
-
}
|
|
17823
|
-
|
|
17824
|
-
// ../../packages/math/src/leiden.ts
|
|
17825
|
-
function buildGraph(nodeIds, adj) {
|
|
17826
|
-
const nbr = /* @__PURE__ */ new Map();
|
|
17827
|
-
const deg = /* @__PURE__ */ new Map();
|
|
17828
|
-
const present = new Set(nodeIds);
|
|
17829
|
-
for (const id of nodeIds) {
|
|
17830
|
-
nbr.set(id, /* @__PURE__ */ new Map());
|
|
17831
|
-
deg.set(id, 0);
|
|
17832
|
-
}
|
|
17833
|
-
let m2 = 0;
|
|
17834
|
-
for (const id of nodeIds) {
|
|
17835
|
-
for (const { to, weight } of adj.get(id) ?? []) {
|
|
17836
|
-
if (!present.has(to)) continue;
|
|
17837
|
-
const row = nbr.get(id);
|
|
17838
|
-
row.set(to, (row.get(to) ?? 0) + weight);
|
|
17839
|
-
deg.set(id, (deg.get(id) ?? 0) + weight);
|
|
17840
|
-
m2 += weight;
|
|
17841
|
-
}
|
|
17842
|
-
}
|
|
17843
|
-
return { nbr, deg, m2 };
|
|
17844
|
-
}
|
|
17845
|
-
function localMoving(nodeIds, g) {
|
|
17846
|
-
const community = new Map(nodeIds.map((n) => [n, n]));
|
|
17847
|
-
const comTot = new Map(nodeIds.map((n) => [n, g.deg.get(n) ?? 0]));
|
|
17848
|
-
const order = [...nodeIds].sort();
|
|
17849
|
-
const m2 = g.m2 > 0 ? g.m2 : 1;
|
|
17850
|
-
let improved = true;
|
|
17851
|
-
let iter = 0;
|
|
17852
|
-
while (improved && iter < 100) {
|
|
17853
|
-
improved = false;
|
|
17854
|
-
iter++;
|
|
17855
|
-
for (const node of order) {
|
|
17856
|
-
const ci = community.get(node);
|
|
17857
|
-
const ki = g.deg.get(node) ?? 0;
|
|
17858
|
-
comTot.set(ci, (comTot.get(ci) ?? 0) - ki);
|
|
17859
|
-
const wToComm = /* @__PURE__ */ new Map();
|
|
17860
|
-
for (const [nb, w] of g.nbr.get(node) ?? []) {
|
|
17861
|
-
if (nb === node) continue;
|
|
17862
|
-
const c = community.get(nb);
|
|
17863
|
-
wToComm.set(c, (wToComm.get(c) ?? 0) + w);
|
|
17864
|
-
}
|
|
17865
|
-
let bestC = ci;
|
|
17866
|
-
let bestGain = (wToComm.get(ci) ?? 0) - (comTot.get(ci) ?? 0) * ki / m2;
|
|
17867
|
-
for (const [c, kiIn] of [...wToComm.entries()].sort(
|
|
17868
|
-
(a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0
|
|
17869
|
-
)) {
|
|
17870
|
-
const gain = kiIn - (comTot.get(c) ?? 0) * ki / m2;
|
|
17871
|
-
if (gain > bestGain) {
|
|
17872
|
-
bestGain = gain;
|
|
17873
|
-
bestC = c;
|
|
17874
|
-
}
|
|
17875
|
-
}
|
|
17876
|
-
community.set(node, bestC);
|
|
17877
|
-
comTot.set(bestC, (comTot.get(bestC) ?? 0) + ki);
|
|
17878
|
-
if (bestC !== ci) improved = true;
|
|
17879
|
-
}
|
|
17880
|
-
}
|
|
17881
|
-
return community;
|
|
17882
|
-
}
|
|
17883
|
-
function refineConnectivity(community, g) {
|
|
17884
|
-
const members = /* @__PURE__ */ new Map();
|
|
17885
|
-
for (const [id, c] of community) {
|
|
17886
|
-
const l = members.get(c) ?? [];
|
|
17887
|
-
l.push(id);
|
|
17888
|
-
members.set(c, l);
|
|
17889
|
-
}
|
|
17890
|
-
const refined = /* @__PURE__ */ new Map();
|
|
17891
|
-
for (const [, group] of members) {
|
|
17892
|
-
const inGroup = new Set(group);
|
|
17893
|
-
const seen = /* @__PURE__ */ new Set();
|
|
17894
|
-
for (const start of [...group].sort()) {
|
|
17895
|
-
if (seen.has(start)) continue;
|
|
17896
|
-
const comp = [];
|
|
17897
|
-
const stack = [start];
|
|
17898
|
-
seen.add(start);
|
|
17899
|
-
while (stack.length) {
|
|
17900
|
-
const cur = stack.pop();
|
|
17901
|
-
comp.push(cur);
|
|
17902
|
-
for (const [nb] of g.nbr.get(cur) ?? []) {
|
|
17903
|
-
if (inGroup.has(nb) && !seen.has(nb)) {
|
|
17904
|
-
seen.add(nb);
|
|
17905
|
-
stack.push(nb);
|
|
17906
|
-
}
|
|
17907
|
-
}
|
|
17908
|
-
}
|
|
17909
|
-
const anchor = [...comp].sort()[0];
|
|
17910
|
-
for (const id of comp) refined.set(id, anchor);
|
|
17911
|
-
}
|
|
17912
|
-
}
|
|
17913
|
-
return refined;
|
|
17914
|
-
}
|
|
17915
|
-
function normalize(assignment) {
|
|
17916
|
-
const groups = /* @__PURE__ */ new Map();
|
|
17917
|
-
for (const [id, c] of assignment) {
|
|
17918
|
-
const l = groups.get(c) ?? [];
|
|
17919
|
-
l.push(id);
|
|
17920
|
-
groups.set(c, l);
|
|
17921
|
-
}
|
|
17922
|
-
const community = /* @__PURE__ */ new Map();
|
|
17923
|
-
for (const grp of groups.values()) {
|
|
17924
|
-
const anchor = [...grp].sort()[0];
|
|
17925
|
-
const cid = `community_${anchor}`;
|
|
17926
|
-
for (const m of grp) community.set(m, cid);
|
|
17927
|
-
}
|
|
17928
|
-
return { community, count: groups.size, iterations: 1 };
|
|
17929
|
-
}
|
|
17930
|
-
function causalComponents(nodeIds, pairs) {
|
|
17931
|
-
const parent = new Map(nodeIds.map((n) => [n, n]));
|
|
17932
|
-
const find = (x) => {
|
|
17933
|
-
let r = x;
|
|
17934
|
-
while (parent.get(r) !== r) r = parent.get(r);
|
|
17935
|
-
let c = x;
|
|
17936
|
-
while (parent.get(c) !== r) {
|
|
17937
|
-
const next = parent.get(c);
|
|
17938
|
-
parent.set(c, r);
|
|
17939
|
-
c = next;
|
|
17940
|
-
}
|
|
17941
|
-
return r;
|
|
17942
|
-
};
|
|
17943
|
-
for (const [a, b] of pairs) {
|
|
17944
|
-
const ra = find(a);
|
|
17945
|
-
const rb = find(b);
|
|
17946
|
-
if (ra !== rb) parent.set(ra < rb ? rb : ra, ra < rb ? ra : rb);
|
|
17947
|
-
}
|
|
17948
|
-
return find;
|
|
17949
|
-
}
|
|
17950
|
-
function detectCommunitiesLeiden(input, opts = {}) {
|
|
17951
|
-
const idSet = new Set(input.nodeIds);
|
|
17952
|
-
const protect = [...opts.protect ?? []].filter(
|
|
17953
|
-
([a, b]) => a !== b && idSet.has(a) && idSet.has(b)
|
|
17954
|
-
);
|
|
17955
|
-
if (protect.length === 0) {
|
|
17956
|
-
const g = buildGraph(input.nodeIds, input.adj);
|
|
17957
|
-
return normalize(refineConnectivity(localMoving(input.nodeIds, g), g));
|
|
17958
|
-
}
|
|
17959
|
-
const rep = causalComponents(input.nodeIds, protect);
|
|
17960
|
-
const superIds = [...new Set(input.nodeIds.map(rep))];
|
|
17961
|
-
const superAdj = /* @__PURE__ */ new Map();
|
|
17962
|
-
const acc = /* @__PURE__ */ new Map();
|
|
17963
|
-
for (const id of input.nodeIds) {
|
|
17964
|
-
const ra = rep(id);
|
|
17965
|
-
for (const { to, weight } of input.adj.get(id) ?? []) {
|
|
17966
|
-
if (!idSet.has(to)) continue;
|
|
17967
|
-
const rb = rep(to);
|
|
17968
|
-
if (ra === rb) continue;
|
|
17969
|
-
const row = acc.get(ra) ?? /* @__PURE__ */ new Map();
|
|
17970
|
-
row.set(rb, (row.get(rb) ?? 0) + weight);
|
|
17971
|
-
acc.set(ra, row);
|
|
17972
|
-
}
|
|
17973
|
-
}
|
|
17974
|
-
for (const [a, row] of acc) superAdj.set(a, [...row].map(([to, weight]) => ({ to, weight })));
|
|
17975
|
-
const sg = buildGraph(superIds, superAdj);
|
|
17976
|
-
const superComm = refineConnectivity(localMoving(superIds, sg), sg);
|
|
17977
|
-
const assignment = /* @__PURE__ */ new Map();
|
|
17978
|
-
for (const id of input.nodeIds) assignment.set(id, superComm.get(rep(id)) ?? rep(id));
|
|
17979
|
-
return normalize(assignment);
|
|
17980
|
-
}
|
|
17981
|
-
|
|
17982
18286
|
// ../../packages/local-graph/src/triage.ts
|
|
17983
18287
|
init_src();
|
|
17984
18288
|
init_src();
|
|
@@ -19368,7 +19672,7 @@ var DOC_COMMENT_KINDS = /* @__PURE__ */ new Set(["docstring", "explanation"]);
|
|
|
19368
19672
|
var MAX_DOC_CHARS = 600;
|
|
19369
19673
|
function buildDocIndex(store) {
|
|
19370
19674
|
const byName = /* @__PURE__ */ new Map();
|
|
19371
|
-
for (const c of store.
|
|
19675
|
+
for (const c of store.findNodeFieldsByLabel("Comment", ["attachedTo", "kind", "text"])) {
|
|
19372
19676
|
const name = c.attrs["attachedTo"];
|
|
19373
19677
|
const kind = c.attrs["kind"];
|
|
19374
19678
|
if (typeof name !== "string" || !name) continue;
|
|
@@ -19384,7 +19688,7 @@ function buildSymbolLexicon(store) {
|
|
|
19384
19688
|
const docs = buildDocIndex(store);
|
|
19385
19689
|
const candidates = [];
|
|
19386
19690
|
for (const [label, kind] of SYMBOL_LABELS) {
|
|
19387
|
-
for (const n of store.
|
|
19691
|
+
for (const n of store.findNodeFieldsByLabel(label, ["qname"])) {
|
|
19388
19692
|
const qname = String(n.attrs["qname"] ?? "");
|
|
19389
19693
|
const doc = (n.description ? docs.get(n.description) : void 0) ?? (qname ? docs.get(qname) : void 0);
|
|
19390
19694
|
for (const name of [n.description, qname]) {
|
|
@@ -19490,7 +19794,7 @@ function buildFileLexicon(store) {
|
|
|
19490
19794
|
const basenameCount = /* @__PURE__ */ new Map();
|
|
19491
19795
|
const stemRelPaths = /* @__PURE__ */ new Map();
|
|
19492
19796
|
const entries = [];
|
|
19493
|
-
for (const n of store.
|
|
19797
|
+
for (const n of store.findNodeFieldsByLabel("File", ["relPath"])) {
|
|
19494
19798
|
const relPath = typeof n.attrs["relPath"] === "string" && n.attrs["relPath"].length > 0 ? n.attrs["relPath"] : n.description;
|
|
19495
19799
|
if (!relPath) continue;
|
|
19496
19800
|
const basename = relPath.split("/").pop();
|
|
@@ -19812,9 +20116,7 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
19812
20116
|
collapsedEdges: 0
|
|
19813
20117
|
};
|
|
19814
20118
|
const sharedCauses = /* @__PURE__ */ new Map();
|
|
19815
|
-
const causalQueue = store.
|
|
19816
|
-
(n) => n.attrs["source"] !== "cloud" && n.attrs["resolvedAs"] !== PROBLEM_RESOLUTION.FALSE_POSITIVE && !ignored(n.description)
|
|
19817
|
-
).map((n) => n.id);
|
|
20119
|
+
const causalQueue = store.findNodeFieldsByLabel("Problem", ["source", "resolvedAs"]).filter((r) => r.attrs["source"] !== "cloud" && r.attrs["resolvedAs"] !== PROBLEM_RESOLUTION.FALSE_POSITIVE).map((r) => r.id).filter((id) => ignorePatterns.length === 0 || !ignored(store.getNode(id)?.description ?? ""));
|
|
19818
20120
|
const causalSeen = new Set(causalQueue);
|
|
19819
20121
|
for (let i = 0; i < causalQueue.length; i++) {
|
|
19820
20122
|
const id = causalQueue[i];
|
|
@@ -19830,7 +20132,20 @@ function buildInstanceIngest(store, profile, daemonVersion, ignorePatterns = [],
|
|
|
19830
20132
|
for (const label of INSTANCE_LABELS) {
|
|
19831
20133
|
const ref = [];
|
|
19832
20134
|
includedByLabel.set(label, ref);
|
|
19833
|
-
const
|
|
20135
|
+
const local = [];
|
|
20136
|
+
for (const row of store.findNodeFieldsByLabel(label, ["source", "privateFinding"])) {
|
|
20137
|
+
if (row.attrs["source"] !== "cloud") {
|
|
20138
|
+
const n = store.getNode(row.id);
|
|
20139
|
+
if (n) local.push(n);
|
|
20140
|
+
continue;
|
|
20141
|
+
}
|
|
20142
|
+
if (seen.has(row.id) || walked.has(row.id)) continue;
|
|
20143
|
+
walked.add(row.id);
|
|
20144
|
+
composition.candidates++;
|
|
20145
|
+
if ((row.attrs["privateFinding"] || label === "Vulnerability") && !opts.project) composition.privateTargetMissing++;
|
|
20146
|
+
else composition.cloudSourced++;
|
|
20147
|
+
}
|
|
20148
|
+
const population = label === "RootCause" && opts.sharedStore ? [...local, ...sharedCauses.values()] : local;
|
|
19834
20149
|
for (const n of population) {
|
|
19835
20150
|
if (seen.has(n.id)) continue;
|
|
19836
20151
|
if (walked.has(n.id)) continue;
|