@inerrata-corporation/errata 2.0.21-dev.3745 → 2.0.21-dev.3763

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.
@@ -15726,10 +15726,12 @@ var init_history_quality = __esm({
15726
15726
  });
15727
15727
 
15728
15728
  // ../../packages/shared/src/history-read.ts
15729
+ var CLOUD_ATTR_DUPLICATE_KEYS;
15729
15730
  var init_history_read = __esm({
15730
15731
  "../../packages/shared/src/history-read.ts"() {
15731
15732
  "use strict";
15732
15733
  init_history_dependencies();
15734
+ CLOUD_ATTR_DUPLICATE_KEYS = ["attrsJson", "embedding"];
15733
15735
  }
15734
15736
  });
15735
15737
 
@@ -16396,7 +16398,237 @@ function installEditPlaceholderRetirement(db) {
16396
16398
  });
16397
16399
  }
16398
16400
 
16401
+ // ../../packages/local-graph/src/cloud-attr-compaction.ts
16402
+ init_src2();
16403
+ var CLOUD_ATTR_COMPACTION_KEY = "cloud-attr-compaction-1";
16404
+ var DUPES = CLOUD_ATTR_DUPLICATE_KEYS.map((k) => `'${k}'`).join(",");
16405
+ function compacted(row) {
16406
+ const packed = `json_extract(${row}.attrs_json, '$.attrsJson')`;
16407
+ const nested = `CASE WHEN json_type(${row}.attrs_json, '$.attrsJson') = 'text' AND json_valid(${packed})
16408
+ AND json_type(${packed}) = 'object' THEN ${packed} ELSE '{}' END`;
16409
+ const value = `CASE WHEN type IN ('array','object') THEN json(value) WHEN type IN ('true','false') THEN json(type) ELSE value END`;
16410
+ return `(SELECT json_group_object(key, ${value}) FROM (
16411
+ SELECT key, value, type, min(pri) FROM (
16412
+ SELECT key, value, type, 0 AS pri FROM json_each(${row}.attrs_json)
16413
+ UNION ALL
16414
+ SELECT key, value, type, 1 AS pri FROM json_each(${nested})
16415
+ ) WHERE key NOT IN (${DUPES}) GROUP BY key))`;
16416
+ }
16417
+ function dirty(row) {
16418
+ const has = CLOUD_ATTR_DUPLICATE_KEYS.map((k) => `json_type(${row}.attrs_json, '$.${k}') IS NOT NULL`).join(" OR ");
16419
+ return `json_extract(${row}.attrs_json, '$.source') = 'cloud' AND (${has})`;
16420
+ }
16421
+ function installCloudAttrCompaction(db) {
16422
+ if (db.prepare("SELECT value FROM store_meta WHERE key = ?").get(CLOUD_ATTR_COMPACTION_KEY)) return;
16423
+ db.transaction(() => {
16424
+ for (const operation of ["INSERT", "UPDATE"]) {
16425
+ db.exec(`CREATE TRIGGER IF NOT EXISTS cloud_attr_compact_${operation.toLowerCase()}
16426
+ AFTER ${operation} ON nodes WHEN ${dirty("NEW")}
16427
+ BEGIN UPDATE nodes SET attrs_json = ${compacted("nodes")} WHERE id = NEW.id; END;`);
16428
+ }
16429
+ db.exec(`UPDATE nodes SET attrs_json = ${compacted("nodes")} WHERE ${dirty("nodes")}`);
16430
+ db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(CLOUD_ATTR_COMPACTION_KEY, "installed");
16431
+ });
16432
+ }
16433
+
16434
+ // ../../packages/math/src/constants.ts
16435
+ var NEMORI_DEDUP_COSINE = 0.88;
16436
+
16437
+ // ../../packages/math/src/triage.ts
16438
+ var TRIAGE_GLOBAL_BUCKET = "*";
16439
+ function triageContextBuckets(ctx) {
16440
+ const out = [];
16441
+ for (const s of ctx.stack ?? []) {
16442
+ const t = s.trim().toLowerCase();
16443
+ if (t) out.push(`stack:${t}`);
16444
+ }
16445
+ const domains = Array.isArray(ctx.domain) ? ctx.domain : typeof ctx.domain === "string" ? [ctx.domain] : [];
16446
+ for (const d of domains) {
16447
+ const t = d.trim().toLowerCase();
16448
+ if (t) out.push(`domain:${t}`);
16449
+ }
16450
+ return out;
16451
+ }
16452
+
16453
+ // ../../packages/math/src/relevance.ts
16454
+ function pageRankScale(ranks) {
16455
+ const positive = [...ranks].filter((r) => Number.isFinite(r) && r > 0).sort((a, b) => a - b);
16456
+ return positive.length ? Math.max(1e-9, positive[Math.floor((positive.length - 1) * 0.95)]) : 1;
16457
+ }
16458
+
16459
+ // ../../packages/math/src/leiden.ts
16460
+ function buildGraph(nodeIds, adj) {
16461
+ const nbr = /* @__PURE__ */ new Map();
16462
+ const deg = /* @__PURE__ */ new Map();
16463
+ const present = new Set(nodeIds);
16464
+ for (const id of nodeIds) {
16465
+ nbr.set(id, /* @__PURE__ */ new Map());
16466
+ deg.set(id, 0);
16467
+ }
16468
+ let m2 = 0;
16469
+ for (const id of nodeIds) {
16470
+ for (const { to, weight } of adj.get(id) ?? []) {
16471
+ if (!present.has(to)) continue;
16472
+ const row = nbr.get(id);
16473
+ row.set(to, (row.get(to) ?? 0) + weight);
16474
+ deg.set(id, (deg.get(id) ?? 0) + weight);
16475
+ m2 += weight;
16476
+ }
16477
+ }
16478
+ return { nbr, deg, m2 };
16479
+ }
16480
+ function localMoving(nodeIds, g) {
16481
+ const community = new Map(nodeIds.map((n) => [n, n]));
16482
+ const comTot = new Map(nodeIds.map((n) => [n, g.deg.get(n) ?? 0]));
16483
+ const order = [...nodeIds].sort();
16484
+ const m2 = g.m2 > 0 ? g.m2 : 1;
16485
+ let improved = true;
16486
+ let iter = 0;
16487
+ while (improved && iter < 100) {
16488
+ improved = false;
16489
+ iter++;
16490
+ for (const node of order) {
16491
+ const ci = community.get(node);
16492
+ const ki = g.deg.get(node) ?? 0;
16493
+ comTot.set(ci, (comTot.get(ci) ?? 0) - ki);
16494
+ const wToComm = /* @__PURE__ */ new Map();
16495
+ for (const [nb, w] of g.nbr.get(node) ?? []) {
16496
+ if (nb === node) continue;
16497
+ const c = community.get(nb);
16498
+ wToComm.set(c, (wToComm.get(c) ?? 0) + w);
16499
+ }
16500
+ let bestC = ci;
16501
+ let bestGain = (wToComm.get(ci) ?? 0) - (comTot.get(ci) ?? 0) * ki / m2;
16502
+ for (const [c, kiIn] of [...wToComm.entries()].sort(
16503
+ (a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0
16504
+ )) {
16505
+ const gain = kiIn - (comTot.get(c) ?? 0) * ki / m2;
16506
+ if (gain > bestGain) {
16507
+ bestGain = gain;
16508
+ bestC = c;
16509
+ }
16510
+ }
16511
+ community.set(node, bestC);
16512
+ comTot.set(bestC, (comTot.get(bestC) ?? 0) + ki);
16513
+ if (bestC !== ci) improved = true;
16514
+ }
16515
+ }
16516
+ return community;
16517
+ }
16518
+ function refineConnectivity(community, g) {
16519
+ const members = /* @__PURE__ */ new Map();
16520
+ for (const [id, c] of community) {
16521
+ const l = members.get(c) ?? [];
16522
+ l.push(id);
16523
+ members.set(c, l);
16524
+ }
16525
+ const refined = /* @__PURE__ */ new Map();
16526
+ for (const [, group] of members) {
16527
+ const inGroup = new Set(group);
16528
+ const seen = /* @__PURE__ */ new Set();
16529
+ for (const start of [...group].sort()) {
16530
+ if (seen.has(start)) continue;
16531
+ const comp = [];
16532
+ const stack = [start];
16533
+ seen.add(start);
16534
+ while (stack.length) {
16535
+ const cur = stack.pop();
16536
+ comp.push(cur);
16537
+ for (const [nb] of g.nbr.get(cur) ?? []) {
16538
+ if (inGroup.has(nb) && !seen.has(nb)) {
16539
+ seen.add(nb);
16540
+ stack.push(nb);
16541
+ }
16542
+ }
16543
+ }
16544
+ const anchor = [...comp].sort()[0];
16545
+ for (const id of comp) refined.set(id, anchor);
16546
+ }
16547
+ }
16548
+ return refined;
16549
+ }
16550
+ function normalize(assignment) {
16551
+ const groups = /* @__PURE__ */ new Map();
16552
+ for (const [id, c] of assignment) {
16553
+ const l = groups.get(c) ?? [];
16554
+ l.push(id);
16555
+ groups.set(c, l);
16556
+ }
16557
+ const community = /* @__PURE__ */ new Map();
16558
+ for (const grp of groups.values()) {
16559
+ const anchor = [...grp].sort()[0];
16560
+ const cid = `community_${anchor}`;
16561
+ for (const m of grp) community.set(m, cid);
16562
+ }
16563
+ return { community, count: groups.size, iterations: 1 };
16564
+ }
16565
+ function causalComponents(nodeIds, pairs) {
16566
+ const parent = new Map(nodeIds.map((n) => [n, n]));
16567
+ const find = (x) => {
16568
+ let r = x;
16569
+ while (parent.get(r) !== r) r = parent.get(r);
16570
+ let c = x;
16571
+ while (parent.get(c) !== r) {
16572
+ const next = parent.get(c);
16573
+ parent.set(c, r);
16574
+ c = next;
16575
+ }
16576
+ return r;
16577
+ };
16578
+ for (const [a, b] of pairs) {
16579
+ const ra = find(a);
16580
+ const rb = find(b);
16581
+ if (ra !== rb) parent.set(ra < rb ? rb : ra, ra < rb ? ra : rb);
16582
+ }
16583
+ return find;
16584
+ }
16585
+ function detectCommunitiesLeiden(input, opts = {}) {
16586
+ const idSet = new Set(input.nodeIds);
16587
+ const protect = [...opts.protect ?? []].filter(
16588
+ ([a, b]) => a !== b && idSet.has(a) && idSet.has(b)
16589
+ );
16590
+ if (protect.length === 0) {
16591
+ const g = buildGraph(input.nodeIds, input.adj);
16592
+ return normalize(refineConnectivity(localMoving(input.nodeIds, g), g));
16593
+ }
16594
+ const rep = causalComponents(input.nodeIds, protect);
16595
+ const superIds = [...new Set(input.nodeIds.map(rep))];
16596
+ const superAdj = /* @__PURE__ */ new Map();
16597
+ const acc = /* @__PURE__ */ new Map();
16598
+ for (const id of input.nodeIds) {
16599
+ const ra = rep(id);
16600
+ for (const { to, weight } of input.adj.get(id) ?? []) {
16601
+ if (!idSet.has(to)) continue;
16602
+ const rb = rep(to);
16603
+ if (ra === rb) continue;
16604
+ const row = acc.get(ra) ?? /* @__PURE__ */ new Map();
16605
+ row.set(rb, (row.get(rb) ?? 0) + weight);
16606
+ acc.set(ra, row);
16607
+ }
16608
+ }
16609
+ for (const [a, row] of acc) superAdj.set(a, [...row].map(([to, weight]) => ({ to, weight })));
16610
+ const sg = buildGraph(superIds, superAdj);
16611
+ const superComm = refineConnectivity(localMoving(superIds, sg), sg);
16612
+ const assignment = /* @__PURE__ */ new Map();
16613
+ for (const id of input.nodeIds) assignment.set(id, superComm.get(rep(id)) ?? rep(id));
16614
+ return normalize(assignment);
16615
+ }
16616
+
16399
16617
  // ../../packages/local-graph/src/store.ts
16618
+ var PAGE_RANK_SCALE_KEY = "pageRankScale.p95.v1";
16619
+ var TEXT_SEARCH_COLUMNS = `id, label, description, page_rank,
16620
+ json_object('test', json(CASE WHEN json_type(attrs_json, '$.test') = 'true' THEN 'true' ELSE 'false' END),
16621
+ 'relPath', json_extract(attrs_json, '$.relPath'),
16622
+ 'resolutionSuspect', json(CASE WHEN json_type(attrs_json, '$.resolutionSuspect') = 'true' THEN 'true' ELSE 'false' END),
16623
+ 'resolvedAt', json_extract(attrs_json, '$.resolvedAt'),
16624
+ 'refutedAt', json_extract(attrs_json, '$.refutedAt'),
16625
+ 'refuteReasons', json_extract(attrs_json, '$.refuteReasons'),
16626
+ 'reopenedFrom', json_extract(attrs_json, '$.reopenedFrom'),
16627
+ 'resolvedAs', json_extract(attrs_json, '$.resolvedAs')) AS search_attrs`;
16628
+ function textSearchNode(row) {
16629
+ const attrs = JSON.parse(row.search_attrs);
16630
+ return { id: row.id, label: row.label, description: row.description, pageRank: row.page_rank, attrs };
16631
+ }
16400
16632
  var LOCAL_RULE_OVERRIDES = {
16401
16633
  ANCHORED_AT: {
16402
16634
  from: EDGE_RULES["ANCHORED_AT"]?.from,
@@ -16540,6 +16772,9 @@ CREATE INDEX IF NOT EXISTS edges_session_evidence ON edges(id) WHERE ${SESSION_E
16540
16772
  DROP INDEX IF EXISTS nodes_live_fingerprint;
16541
16773
  DROP INDEX IF EXISTS nodes_instance_fingerprint;
16542
16774
  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');
16775
+ -- Calibrate rank from a covering scalar index; the global page-rank index
16776
+ -- requires a table lookup per node to exclude frozen versions.
16777
+ CREATE INDEX IF NOT EXISTS nodes_live_page_rank ON nodes(valid_to, page_rank);
16543
16778
  CREATE INDEX IF NOT EXISTS nodes_logical ON nodes(logical_id, version);
16544
16779
  CREATE INDEX IF NOT EXISTS edges_live ON edges(valid_to);
16545
16780
  -- Expression index on the per-node relPath (stored in attrs_json) so the
@@ -16552,6 +16787,12 @@ CREATE INDEX IF NOT EXISTS nodes_live_description ON nodes(description, label) W
16552
16787
  -- Problems by the file their anchor hint names: the harvest upgrades hints for
16553
16788
  -- every edited file of every turn, and a scan parses every Problem's attrs.
16554
16789
  CREATE INDEX IF NOT EXISTS nodes_anchor_hint_path ON nodes(json_extract(attrs_json, '$.anchorHint.path')) WHERE valid_to IS NULL;
16790
+ -- Problems by the command / checker / file that opened them. The generalizer
16791
+ -- looked these up per shell or tool EVENT by hydrating every Problem: ~12s of
16792
+ -- every minute of daemon main-thread time on a 3.4k-Problem store (2026-10-05).
16793
+ CREATE INDEX IF NOT EXISTS nodes_command_signature ON nodes(json_extract(attrs_json, '$.commandSignature')) WHERE valid_to IS NULL;
16794
+ CREATE INDEX IF NOT EXISTS nodes_diag_command ON nodes(json_extract(attrs_json, '$.diagCommand')) WHERE valid_to IS NULL;
16795
+ CREATE INDEX IF NOT EXISTS nodes_lsp_rel_path ON nodes(json_extract(attrs_json, '$.lspRelPath')) WHERE valid_to IS NULL;
16555
16796
  -- Nodes still waiting on a root-cause ask. The MCP server checks this on EVERY
16556
16797
  -- tool response (the enrichment piggyback), so it must not parse every
16557
16798
  -- Solution's and Problem's attrs per call. Not partial: the Problem pull reads
@@ -16638,6 +16879,7 @@ var SqliteGraphStore = class {
16638
16879
  * ALL upserts incl. code reindex) — this counter is the knowledge-arrival axis
16639
16880
  * Δseq is measured over, so code reindex churn must NOT advance it. */
16640
16881
  ingestSeq = 0;
16882
+ initialPageRankScale;
16641
16883
  constructor(opts) {
16642
16884
  this.db = openDatabase(opts.path);
16643
16885
  this.db.exec(SCHEMA_SQL);
@@ -16654,6 +16896,7 @@ var SqliteGraphStore = class {
16654
16896
  this.db.exec(TEMPORAL_INDEX_SQL);
16655
16897
  installHistoryCacheFloor(this.db);
16656
16898
  installEditPlaceholderRetirement(this.db);
16899
+ installCloudAttrCompaction(this.db);
16657
16900
  if (!this.db.prepare("SELECT value FROM store_meta WHERE key = ?").get(SESSION_REPAIR_KEY)) {
16658
16901
  this.db.transaction(() => {
16659
16902
  this.repairSessionAliases();
@@ -17257,6 +17500,34 @@ var SqliteGraphStore = class {
17257
17500
  ).all(...terms.map((t) => `%${t}%`), Math.max(1, limit));
17258
17501
  return rows.map((r) => ({ node: rowToNode(r), matched: Number(r.matched) }));
17259
17502
  }
17503
+ searchTextCandidates(terms) {
17504
+ if (terms.length === 0) return [];
17505
+ const rows = this.db.prepare(`WITH matches AS MATERIALIZED (
17506
+ SELECT n.id, COUNT(*) AS matched FROM nodes n INDEXED BY nodes_live_description, json_each(:terms) t
17507
+ WHERE n.valid_to IS NULL AND n.description LIKE '%' || t.value || '%'
17508
+ GROUP BY n.id
17509
+ ) SELECT ${TEXT_SEARCH_COLUMNS}, matches.matched FROM nodes
17510
+ JOIN matches USING (id) ORDER BY page_rank DESC, last_updated_at DESC`).all({ terms: JSON.stringify(terms) });
17511
+ return rows.map((row) => ({ node: textSearchNode(row), matched: row.matched }));
17512
+ }
17513
+ getTextSearchNode(id) {
17514
+ const row = this.db.prepare(`SELECT ${TEXT_SEARCH_COLUMNS} FROM nodes WHERE id = ? AND valid_to IS NULL`).get(id);
17515
+ return row ? textSearchNode(row) : null;
17516
+ }
17517
+ readPageRankScale() {
17518
+ const rows = this.db.prepare("SELECT page_rank FROM nodes WHERE valid_to IS NULL AND page_rank > 0").all();
17519
+ return pageRankScale(rows.map((row) => row.page_rank));
17520
+ }
17521
+ pageRankScale() {
17522
+ const value = Number(this.getMeta(PAGE_RANK_SCALE_KEY));
17523
+ if (Number.isFinite(value) && value > 0) return value;
17524
+ return this.initialPageRankScale ??= this.readPageRankScale();
17525
+ }
17526
+ refreshPageRankScale() {
17527
+ const scale = this.readPageRankScale();
17528
+ this.setMeta(PAGE_RANK_SCALE_KEY, String(scale));
17529
+ return scale;
17530
+ }
17260
17531
  typedEdgeStmt(sql) {
17261
17532
  let stmt = this.typedEdgeStmts.get(sql);
17262
17533
  if (!stmt) {
@@ -17802,183 +18073,6 @@ function percolate(l1, l2, opts) {
17802
18073
  init_src();
17803
18074
  init_src2();
17804
18075
 
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
18076
  // ../../packages/local-graph/src/triage.ts
17983
18077
  init_src();
17984
18078
  init_src();