@inerrata-corporation/errata 2.0.22-dev.4020 → 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
CHANGED
|
@@ -16508,6 +16508,38 @@ function installHistoryAttrSlim(db) {
|
|
|
16508
16508
|
db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(HISTORY_ATTR_SLIM_KEY, "done");
|
|
16509
16509
|
}
|
|
16510
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
|
+
|
|
16511
16543
|
// ../../packages/math/src/constants.ts
|
|
16512
16544
|
var NEMORI_DEDUP_COSINE = 0.88;
|
|
16513
16545
|
|
|
@@ -16983,6 +17015,7 @@ var SqliteGraphStore = class {
|
|
|
16983
17015
|
installEditPlaceholderRetirement(this.db);
|
|
16984
17016
|
installCloudAttrCompaction(this.db);
|
|
16985
17017
|
installHistoryAttrSlim(this.db);
|
|
17018
|
+
installTextIndex(this.db);
|
|
16986
17019
|
if (!this.db.prepare("SELECT value FROM store_meta WHERE key = ?").get(SESSION_REPAIR_KEY)) {
|
|
16987
17020
|
this.db.transaction(() => {
|
|
16988
17021
|
this.repairSessionAliases();
|
|
@@ -17637,6 +17670,20 @@ var SqliteGraphStore = class {
|
|
|
17637
17670
|
}
|
|
17638
17671
|
searchTextCandidates(terms) {
|
|
17639
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
|
+
}
|
|
17640
17687
|
const rows = this.db.prepare(`WITH matches AS MATERIALIZED (
|
|
17641
17688
|
SELECT n.id, COUNT(*) AS matched FROM nodes n INDEXED BY nodes_live_description, json_each(:terms) t
|
|
17642
17689
|
WHERE n.valid_to IS NULL AND n.description LIKE '%' || t.value || '%'
|
|
@@ -17645,6 +17692,18 @@ var SqliteGraphStore = class {
|
|
|
17645
17692
|
JOIN matches USING (id) ORDER BY page_rank DESC, last_updated_at DESC`).all({ terms: JSON.stringify(terms) });
|
|
17646
17693
|
return rows.map((row) => ({ node: textSearchNode(row), matched: row.matched }));
|
|
17647
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
|
+
}
|
|
17648
17707
|
getTextSearchNode(id) {
|
|
17649
17708
|
const row = this.db.prepare(`SELECT ${TEXT_SEARCH_COLUMNS} FROM nodes WHERE id = ? AND valid_to IS NULL`).get(id);
|
|
17650
17709
|
return row ? textSearchNode(row) : null;
|
package/errata.mjs
CHANGED
|
@@ -18483,6 +18483,44 @@ var init_history_attr_slim = __esm({
|
|
|
18483
18483
|
}
|
|
18484
18484
|
});
|
|
18485
18485
|
|
|
18486
|
+
// ../../packages/local-graph/src/text-index.ts
|
|
18487
|
+
function installTextIndex(db) {
|
|
18488
|
+
if (db.prepare("SELECT value FROM store_meta WHERE key = ?").get(TEXT_INDEX_KEY)) return;
|
|
18489
|
+
try {
|
|
18490
|
+
db.exec(`CREATE VIRTUAL TABLE temp.fts5_probe USING fts5(x, tokenize='trigram'); DROP TABLE temp.fts5_probe`);
|
|
18491
|
+
} catch {
|
|
18492
|
+
db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(TEXT_INDEX_KEY, "unavailable");
|
|
18493
|
+
return;
|
|
18494
|
+
}
|
|
18495
|
+
db.transaction(() => {
|
|
18496
|
+
db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS nodes_text
|
|
18497
|
+
USING fts5(description, content='nodes', content_rowid='rowid', tokenize='trigram')`);
|
|
18498
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_insert AFTER INSERT ON nodes WHEN NEW.valid_to IS NULL
|
|
18499
|
+
BEGIN INSERT INTO nodes_text(rowid, description) VALUES (NEW.rowid, NEW.description); END;`);
|
|
18500
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_update_out AFTER UPDATE OF description, valid_to ON nodes
|
|
18501
|
+
WHEN OLD.valid_to IS NULL
|
|
18502
|
+
BEGIN INSERT INTO nodes_text(nodes_text, rowid, description) VALUES ('delete', OLD.rowid, OLD.description); END;`);
|
|
18503
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_update_in AFTER UPDATE OF description, valid_to ON nodes
|
|
18504
|
+
WHEN NEW.valid_to IS NULL
|
|
18505
|
+
BEGIN INSERT INTO nodes_text(rowid, description) VALUES (NEW.rowid, NEW.description); END;`);
|
|
18506
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_delete AFTER DELETE ON nodes WHEN OLD.valid_to IS NULL
|
|
18507
|
+
BEGIN INSERT INTO nodes_text(nodes_text, rowid, description) VALUES ('delete', OLD.rowid, OLD.description); END;`);
|
|
18508
|
+
db.exec(`INSERT INTO nodes_text(rowid, description) SELECT rowid, description FROM nodes WHERE valid_to IS NULL`);
|
|
18509
|
+
db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(TEXT_INDEX_KEY, "installed");
|
|
18510
|
+
});
|
|
18511
|
+
}
|
|
18512
|
+
function textIndexReady(db) {
|
|
18513
|
+
return db.prepare("SELECT value FROM store_meta WHERE key = ?").get(TEXT_INDEX_KEY)?.["value"] === "installed";
|
|
18514
|
+
}
|
|
18515
|
+
var TEXT_INDEX_KEY, TEXT_INDEX_MIN_TERM;
|
|
18516
|
+
var init_text_index = __esm({
|
|
18517
|
+
"../../packages/local-graph/src/text-index.ts"() {
|
|
18518
|
+
"use strict";
|
|
18519
|
+
TEXT_INDEX_KEY = "text-index-trigram-1";
|
|
18520
|
+
TEXT_INDEX_MIN_TERM = 3;
|
|
18521
|
+
}
|
|
18522
|
+
});
|
|
18523
|
+
|
|
18486
18524
|
// ../../packages/math/src/constants.ts
|
|
18487
18525
|
var SURPRISE_MOMENTUM, SURPRISE_LEARNING_RATE, SURPRISE_LEARNING_RATE_SCALING, TIER_HALFLIFE_MULTIPLIER, HIT_RATE_SCALING_ALPHA, BASE_HALF_LIFE_SEQ, MOMENTUM_GATE_FLOOR, SURPRISE_RECENCY_LAMBDA_SEQ, NEMORI_SOFT_WRITE_MIN_COSINE, NEMORI_SOFT_WRITE_MAX_COSINE, NEMORI_DEDUP_COSINE, NEMORI_SOFT_ALPHA_MIN, NEMORI_SOFT_ALPHA_MAX, NEMORI_HIGH_SURPRISE_THRESHOLD, NEMORI_PREDICTION_FLOOR, REVIEW_SURPRISE_THRESHOLD, REVIEW_HITS_THRESHOLD;
|
|
18488
18526
|
var init_constants = __esm({
|
|
@@ -19426,7 +19464,7 @@ function graphStoreNeedsPreparation(path2) {
|
|
|
19426
19464
|
for (const match2 of (SCHEMA_SQL + TEMPORAL_INDEX_SQL).matchAll(/CREATE INDEX IF NOT EXISTS (\w+)/g)) {
|
|
19427
19465
|
if (!indexes.has(match2[1])) return true;
|
|
19428
19466
|
}
|
|
19429
|
-
return [SESSION_REPAIR_KEY, HISTORY_CACHE_FLOOR_KEY, EDIT_PLACEHOLDER_FLOOR_KEY, CLOUD_ATTR_COMPACTION_KEY, HISTORY_ATTR_SLIM_KEY].some((key) => !db.prepare("SELECT value FROM store_meta WHERE key = ?").get(key));
|
|
19467
|
+
return [SESSION_REPAIR_KEY, HISTORY_CACHE_FLOOR_KEY, EDIT_PLACEHOLDER_FLOOR_KEY, CLOUD_ATTR_COMPACTION_KEY, HISTORY_ATTR_SLIM_KEY, TEXT_INDEX_KEY].some((key) => !db.prepare("SELECT value FROM store_meta WHERE key = ?").get(key));
|
|
19430
19468
|
} catch {
|
|
19431
19469
|
return true;
|
|
19432
19470
|
} finally {
|
|
@@ -19504,6 +19542,7 @@ var init_store = __esm({
|
|
|
19504
19542
|
init_edit_placeholder_retirement();
|
|
19505
19543
|
init_cloud_attr_compaction();
|
|
19506
19544
|
init_history_attr_slim();
|
|
19545
|
+
init_text_index();
|
|
19507
19546
|
init_src3();
|
|
19508
19547
|
PAGE_RANK_SCALE_KEY = "pageRankScale.p95.v1";
|
|
19509
19548
|
TEXT_SEARCH_COLUMNS = `id, label, description, page_rank,
|
|
@@ -19716,6 +19755,7 @@ CREATE INDEX IF NOT EXISTS nodes_enrichment_pending ON nodes(json_extract(attrs_
|
|
|
19716
19755
|
installEditPlaceholderRetirement(this.db);
|
|
19717
19756
|
installCloudAttrCompaction(this.db);
|
|
19718
19757
|
installHistoryAttrSlim(this.db);
|
|
19758
|
+
installTextIndex(this.db);
|
|
19719
19759
|
if (!this.db.prepare("SELECT value FROM store_meta WHERE key = ?").get(SESSION_REPAIR_KEY)) {
|
|
19720
19760
|
this.db.transaction(() => {
|
|
19721
19761
|
this.repairSessionAliases();
|
|
@@ -20370,6 +20410,20 @@ CREATE INDEX IF NOT EXISTS nodes_enrichment_pending ON nodes(json_extract(attrs_
|
|
|
20370
20410
|
}
|
|
20371
20411
|
searchTextCandidates(terms) {
|
|
20372
20412
|
if (terms.length === 0) return [];
|
|
20413
|
+
const indexed = terms.filter((t) => t.length >= TEXT_INDEX_MIN_TERM);
|
|
20414
|
+
if (indexed.length > 0 && textIndexReady(this.db)) {
|
|
20415
|
+
const short = terms.filter((t) => t.length < TEXT_INDEX_MIN_TERM).map((t) => t.toLowerCase());
|
|
20416
|
+
const rows2 = this.db.prepare(`WITH hits AS MATERIALIZED (
|
|
20417
|
+
SELECT t.rowid AS rid, COUNT(*) AS matched FROM json_each(:terms) q, nodes_text t
|
|
20418
|
+
WHERE t.description LIKE '%' || q.value || '%' GROUP BY t.rowid
|
|
20419
|
+
) SELECT ${TEXT_SEARCH_COLUMNS}, hits.matched FROM hits JOIN nodes ON nodes.rowid = hits.rid
|
|
20420
|
+
WHERE nodes.valid_to IS NULL ORDER BY page_rank DESC, last_updated_at DESC`).all({ terms: JSON.stringify(indexed) });
|
|
20421
|
+
return rows2.map((row) => {
|
|
20422
|
+
const text = row.description.toLowerCase();
|
|
20423
|
+
const extra = short.filter((t) => text.includes(t)).length;
|
|
20424
|
+
return { node: textSearchNode(row), matched: row.matched + extra };
|
|
20425
|
+
});
|
|
20426
|
+
}
|
|
20373
20427
|
const rows = this.db.prepare(`WITH matches AS MATERIALIZED (
|
|
20374
20428
|
SELECT n.id, COUNT(*) AS matched FROM nodes n INDEXED BY nodes_live_description, json_each(:terms) t
|
|
20375
20429
|
WHERE n.valid_to IS NULL AND n.description LIKE '%' || t.value || '%'
|
|
@@ -20378,6 +20432,18 @@ CREATE INDEX IF NOT EXISTS nodes_enrichment_pending ON nodes(json_extract(attrs_
|
|
|
20378
20432
|
JOIN matches USING (id) ORDER BY page_rank DESC, last_updated_at DESC`).all({ terms: JSON.stringify(terms) });
|
|
20379
20433
|
return rows.map((row) => ({ node: textSearchNode(row), matched: row.matched }));
|
|
20380
20434
|
}
|
|
20435
|
+
commentAnchors(commentIds) {
|
|
20436
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
20437
|
+
if (commentIds.length === 0) return out2;
|
|
20438
|
+
const rows = this.db.prepare(`WITH a AS MATERIALIZED (
|
|
20439
|
+
SELECT q.value AS cid, COALESCE(
|
|
20440
|
+
(SELECT to_id FROM edges WHERE from_id = q.value AND type IN ('EXPLAINS', 'ANNOTATES') AND valid_to IS NULL LIMIT 1),
|
|
20441
|
+
(SELECT from_id FROM edges WHERE to_id = q.value AND type = 'DOCUMENTED_BY' AND valid_to IS NULL LIMIT 1)
|
|
20442
|
+
) AS aid FROM json_each(:ids) q
|
|
20443
|
+
) 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) });
|
|
20444
|
+
for (const row of rows) out2.set(row.cid, textSearchNode(row));
|
|
20445
|
+
return out2;
|
|
20446
|
+
}
|
|
20381
20447
|
getTextSearchNode(id) {
|
|
20382
20448
|
const row = this.db.prepare(`SELECT ${TEXT_SEARCH_COLUMNS} FROM nodes WHERE id = ? AND valid_to IS NULL`).get(id);
|
|
20383
20449
|
return row ? textSearchNode(row) : null;
|
|
@@ -32983,42 +33049,77 @@ function burstStaticConductance(type, seedLabel) {
|
|
|
32983
33049
|
function burstConductance(edge2, seedLabel) {
|
|
32984
33050
|
return learnedConductance(burstStaticConductance(edge2.type, seedLabel), edge2);
|
|
32985
33051
|
}
|
|
32986
|
-
function
|
|
32987
|
-
const
|
|
32988
|
-
const
|
|
32989
|
-
const nodeCap = opts.nodeCap ?? 200;
|
|
32990
|
-
const seed = store.getNode(seedId);
|
|
32991
|
-
if (!seed) return [];
|
|
32992
|
-
const act = /* @__PURE__ */ new Map([[seedId, 1]]);
|
|
32993
|
-
const hopOf = /* @__PURE__ */ new Map([[seedId, 0]]);
|
|
33052
|
+
function spreadActivation(store, seeds, opts) {
|
|
33053
|
+
const act = /* @__PURE__ */ new Map();
|
|
33054
|
+
const hopOf = /* @__PURE__ */ new Map();
|
|
32994
33055
|
const viaOf = /* @__PURE__ */ new Map();
|
|
33056
|
+
const originLabel = /* @__PURE__ */ new Map();
|
|
33057
|
+
const bestArrival = /* @__PURE__ */ new Map();
|
|
33058
|
+
const seedIds = new Set(seeds.map((s) => s.id));
|
|
32995
33059
|
const expanded = /* @__PURE__ */ new Set();
|
|
32996
33060
|
const frontier = new ActivationHeap();
|
|
32997
|
-
|
|
33061
|
+
for (const s of seeds) {
|
|
33062
|
+
act.set(s.id, (act.get(s.id) ?? 0) + s.weight);
|
|
33063
|
+
hopOf.set(s.id, 0);
|
|
33064
|
+
if (!originLabel.has(s.id)) originLabel.set(s.id, s.label);
|
|
33065
|
+
}
|
|
33066
|
+
for (const s of seeds) frontier.push(s.id, act.get(s.id));
|
|
32998
33067
|
let strongest = 0;
|
|
32999
|
-
while (frontier.size > 0 && expanded.size < nodeCap) {
|
|
33068
|
+
while (frontier.size > 0 && expanded.size < opts.nodeCap) {
|
|
33000
33069
|
const top = frontier.pop();
|
|
33001
33070
|
if (expanded.has(top.id) || top.a < (act.get(top.id) ?? 0)) continue;
|
|
33002
33071
|
if (top.a < ACTIVATION_EPSILON || top.a < strongest * BURST_RELATIVE_FLOOR) break;
|
|
33003
33072
|
expanded.add(top.id);
|
|
33004
33073
|
const hops = hopOf.get(top.id) ?? 0;
|
|
33005
|
-
if (hops >= maxHops) continue;
|
|
33074
|
+
if (hops >= opts.maxHops) continue;
|
|
33075
|
+
const label = originLabel.get(top.id) ?? "";
|
|
33006
33076
|
const edges = [
|
|
33007
33077
|
...store.outEdges(top.id).map((e) => ({ e, nb: e.to, forward: true })),
|
|
33008
33078
|
...store.inEdges(top.id).map((e) => ({ e, nb: e.from, forward: false }))
|
|
33009
33079
|
].filter(({ e }) => walksRelatedness(e.type));
|
|
33010
33080
|
const damp = BURST_STEP_DAMPING / Math.sqrt(Math.max(1, edges.length));
|
|
33011
33081
|
for (const { e, nb, forward } of edges) {
|
|
33012
|
-
if (nb ===
|
|
33013
|
-
const a = top.a * burstConductance(e,
|
|
33082
|
+
if (nb === top.id) continue;
|
|
33083
|
+
const a = top.a * burstConductance(e, label) * damp;
|
|
33084
|
+
if (opts.accumulate) {
|
|
33085
|
+
if (a < ACTIVATION_EPSILON) continue;
|
|
33086
|
+
const total = (act.get(nb) ?? 0) + a;
|
|
33087
|
+
act.set(nb, total);
|
|
33088
|
+
if (a > (bestArrival.get(nb) ?? 0)) {
|
|
33089
|
+
bestArrival.set(nb, a);
|
|
33090
|
+
if (!seedIds.has(nb)) {
|
|
33091
|
+
hopOf.set(nb, hops + 1);
|
|
33092
|
+
viaOf.set(nb, { edgeType: e.type, parentId: top.id, forward });
|
|
33093
|
+
originLabel.set(nb, label);
|
|
33094
|
+
}
|
|
33095
|
+
}
|
|
33096
|
+
if (!seedIds.has(nb) && total > strongest) strongest = total;
|
|
33097
|
+
if (!expanded.has(nb)) frontier.push(nb, total);
|
|
33098
|
+
continue;
|
|
33099
|
+
}
|
|
33100
|
+
if (seedIds.has(nb) || expanded.has(nb)) continue;
|
|
33014
33101
|
if (a <= (act.get(nb) ?? 0)) continue;
|
|
33015
33102
|
act.set(nb, a);
|
|
33016
33103
|
if (a > strongest) strongest = a;
|
|
33017
33104
|
hopOf.set(nb, hops + 1);
|
|
33018
33105
|
viaOf.set(nb, { edgeType: e.type, parentId: top.id, forward });
|
|
33106
|
+
originLabel.set(nb, label);
|
|
33019
33107
|
frontier.push(nb, a);
|
|
33020
33108
|
}
|
|
33021
33109
|
}
|
|
33110
|
+
return { act, hopOf, viaOf };
|
|
33111
|
+
}
|
|
33112
|
+
function localBurst(store, seedId, opts = {}) {
|
|
33113
|
+
const maxHops = opts.maxHops ?? 3;
|
|
33114
|
+
const limit = opts.limit ?? 20;
|
|
33115
|
+
const nodeCap = opts.nodeCap ?? 200;
|
|
33116
|
+
const seed = store.getNode(seedId);
|
|
33117
|
+
if (!seed) return [];
|
|
33118
|
+
const { act, hopOf, viaOf } = spreadActivation(store, [{ id: seedId, weight: 1, label: seed.label }], {
|
|
33119
|
+
maxHops,
|
|
33120
|
+
nodeCap,
|
|
33121
|
+
accumulate: false
|
|
33122
|
+
});
|
|
33022
33123
|
act.delete(seedId);
|
|
33023
33124
|
const ctxSeed = seed.embedding.length > 0 ? { seedEmbedding: seed.embedding, seedEmbeddingVersion: seed.attrs["embeddingVersion"] } : {};
|
|
33024
33125
|
const gated = seed.embedding.length > 0;
|
|
@@ -33040,6 +33141,32 @@ function localBurst(store, seedId, opts = {}) {
|
|
|
33040
33141
|
return { id: node2.id, score: score2, components: r.components, node: node2, hops: hopOf.get(node2.id) ?? 0, ...via ? { via } : {} };
|
|
33041
33142
|
}).filter((r) => !gated || r.score > 0).sort((a, b) => b.score - a.score).slice(0, limit);
|
|
33042
33143
|
}
|
|
33144
|
+
function burstFromSeeds(store, seeds, opts = {}) {
|
|
33145
|
+
const live3 = seeds.filter((s) => s.weight > 0);
|
|
33146
|
+
if (live3.length === 0) return [];
|
|
33147
|
+
const { act, hopOf, viaOf } = spreadActivation(store, live3, {
|
|
33148
|
+
maxHops: opts.maxHops ?? 3,
|
|
33149
|
+
nodeCap: opts.nodeCap ?? 300,
|
|
33150
|
+
accumulate: true
|
|
33151
|
+
});
|
|
33152
|
+
const seedIds = new Set(live3.map((s) => s.id));
|
|
33153
|
+
const labelOf = store.nodeLabels([...act.keys()]);
|
|
33154
|
+
const pool = (keep) => [...act.entries()].filter(([id]) => keep(labelOf.get(id) ?? "")).sort((x, y) => y[1] - x[1]).slice(0, BURST_SCORED_CANDIDATES);
|
|
33155
|
+
const isKnowledge = (label) => typeRelevance(label) >= KNOWLEDGE_TYPE_RELEVANCE;
|
|
33156
|
+
const reached = [...new Map([...pool(isKnowledge), ...pool((l) => !isKnowledge(l))]).entries()].map(([id, a]) => ({ node: store.getNode(id), a })).filter((x) => x.node != null);
|
|
33157
|
+
const maxAct = Math.max(1e-12, ...reached.map((x) => x.a));
|
|
33158
|
+
const weights = { centralityScale: store.pageRankScale?.() ?? 1, ...opts.weights };
|
|
33159
|
+
const now = store.currentIngestSeq();
|
|
33160
|
+
const typed = opts.typeRelevanceForSeeds ?? true;
|
|
33161
|
+
const hubDamp = (id) => seedIds.has(id) ? 1 : 1 / Math.sqrt(Math.max(1, store.outEdges(id).length + store.inEdges(id).length));
|
|
33162
|
+
return reached.map(({ node: node2, a }) => {
|
|
33163
|
+
const r = scoreCandidate(node2, { decay: nodeFreshness(node2, now) }, weights);
|
|
33164
|
+
const type = typed || !seedIds.has(node2.id) ? typeRelevance(node2.label) : 1;
|
|
33165
|
+
const score2 = a / maxAct * r.score * type * hubDamp(node2.id);
|
|
33166
|
+
const via = viaOf.get(node2.id);
|
|
33167
|
+
return { id: node2.id, score: score2, components: r.components, node: node2, hops: hopOf.get(node2.id) ?? 0, ...via ? { via } : {} };
|
|
33168
|
+
}).sort((a, b) => b.score - a.score).slice(0, opts.limit ?? 20);
|
|
33169
|
+
}
|
|
33043
33170
|
var BURST_STEP_DAMPING, ACTIVATION_EPSILON, BURST_RELATIVE_FLOOR, BURST_SCORED_CANDIDATES, KNOWLEDGE_TYPE_RELEVANCE, BURST_ANCHORED_AT_CONDUCTANCE, BURST_DEPENDS_ON_FLOOR, ActivationHeap;
|
|
33044
33171
|
var init_relevance_rank = __esm({
|
|
33045
33172
|
"../../packages/generalizer/src/relevance-rank.ts"() {
|
|
@@ -33165,6 +33292,7 @@ __export(src_exports3, {
|
|
|
33165
33292
|
bindCanonicalNeighbors: () => bindCanonicalNeighbors,
|
|
33166
33293
|
bindResolvedRegressions: () => bindResolvedRegressions,
|
|
33167
33294
|
burstConductance: () => burstConductance,
|
|
33295
|
+
burstFromSeeds: () => burstFromSeeds,
|
|
33168
33296
|
burstStaticConductance: () => burstStaticConductance,
|
|
33169
33297
|
closeProblem: () => closeProblem,
|
|
33170
33298
|
commandSignature: () => commandSignature,
|
|
@@ -35652,8 +35780,28 @@ function mergeDualBurst(local, cloud, opts = {}) {
|
|
|
35652
35780
|
if (parent === n.id) delete n.via;
|
|
35653
35781
|
else if (parent !== n.via.parentId) n.via = { ...n.via, parentId: parent };
|
|
35654
35782
|
}
|
|
35783
|
+
if (opts.fuse === "rank") fuseByRank();
|
|
35655
35784
|
nodes.sort((a, b) => b.score - a.score);
|
|
35656
35785
|
return { nodes, collectiveCount, corroboratedCount };
|
|
35786
|
+
function fuseByRank() {
|
|
35787
|
+
const localRank = /* @__PURE__ */ new Map();
|
|
35788
|
+
local.filter((l) => !isSeedTwin(l.id)).forEach((l, i2) => {
|
|
35789
|
+
const n = byId.get(l.id) ?? byId.get(recordedBy.get(l.id) ?? "");
|
|
35790
|
+
if (n && !localRank.has(n.id)) localRank.set(n.id, i2);
|
|
35791
|
+
});
|
|
35792
|
+
const cloudRank = /* @__PURE__ */ new Map();
|
|
35793
|
+
cloud.forEach((c, i2) => {
|
|
35794
|
+
if (isSeedTwin(c.id)) return;
|
|
35795
|
+
const mine = twins?.localOf(c.id);
|
|
35796
|
+
const n = owner.get(c.id) ?? byId.get(c.id) ?? (mine ? byId.get(mine.id) : void 0);
|
|
35797
|
+
if (n && !cloudRank.has(n.id)) cloudRank.set(n.id, i2);
|
|
35798
|
+
});
|
|
35799
|
+
for (const n of nodes) {
|
|
35800
|
+
const lr = localRank.get(n.id);
|
|
35801
|
+
const cr = cloudRank.get(n.id);
|
|
35802
|
+
n.score = (lr === void 0 ? 0 : 1 / (SEARCH_FUSE_K + lr + 1)) + (cr === void 0 ? 0 : SEARCH_FUSE_NETWORK_WEIGHT / (SEARCH_FUSE_K + cr + 1));
|
|
35803
|
+
}
|
|
35804
|
+
}
|
|
35657
35805
|
function canonicalId(id) {
|
|
35658
35806
|
if (opts.seedId && isSeedTwin(id)) return opts.seedId;
|
|
35659
35807
|
return owner.get(id)?.id ?? recordedBy.get(id) ?? twins?.localOf(id)?.id ?? id;
|
|
@@ -35735,11 +35883,13 @@ function searchResultToCloudHits(result) {
|
|
|
35735
35883
|
};
|
|
35736
35884
|
});
|
|
35737
35885
|
}
|
|
35738
|
-
var DUAL_BURST_SEMANTIC_NEUTRAL;
|
|
35886
|
+
var DUAL_BURST_SEMANTIC_NEUTRAL, SEARCH_FUSE_K, SEARCH_FUSE_NETWORK_WEIGHT;
|
|
35739
35887
|
var init_dual_burst = __esm({
|
|
35740
35888
|
"src/dual-burst.ts"() {
|
|
35741
35889
|
"use strict";
|
|
35742
35890
|
DUAL_BURST_SEMANTIC_NEUTRAL = 0.3;
|
|
35891
|
+
SEARCH_FUSE_K = 10;
|
|
35892
|
+
SEARCH_FUSE_NETWORK_WEIGHT = 0.7;
|
|
35743
35893
|
}
|
|
35744
35894
|
});
|
|
35745
35895
|
|
|
@@ -35874,7 +36024,8 @@ async function dualAugment(opts) {
|
|
|
35874
36024
|
const parent = c.via?.parentId;
|
|
35875
36025
|
return parent ? [c.id, parent] : [c.id];
|
|
35876
36026
|
})),
|
|
35877
|
-
...seedNode ? { seedId: seedNode.id } : {}
|
|
36027
|
+
...seedNode ? { seedId: seedNode.id } : {},
|
|
36028
|
+
...opts.fuse ? { fuse: opts.fuse } : {}
|
|
35878
36029
|
}),
|
|
35879
36030
|
seedProvenance,
|
|
35880
36031
|
seedUsageCount
|
|
@@ -45027,10 +45178,17 @@ __export(mcp_exports, {
|
|
|
45027
45178
|
INSTRUCTIONS: () => INSTRUCTIONS,
|
|
45028
45179
|
RG_REFUTED_DAMP: () => RG_REFUTED_DAMP,
|
|
45029
45180
|
RG_SUSPECT_BOOST: () => RG_SUSPECT_BOOST,
|
|
45181
|
+
SEARCH_CODE_SEEDS: () => SEARCH_CODE_SEEDS,
|
|
45182
|
+
SEARCH_KNOWLEDGE_SEEDS: () => SEARCH_KNOWLEDGE_SEEDS,
|
|
45030
45183
|
createMcpHandler: () => createMcpHandler,
|
|
45031
45184
|
runMcpServer: () => runMcpServer,
|
|
45032
45185
|
runTool: () => runTool,
|
|
45033
|
-
|
|
45186
|
+
searchEntries: () => searchEntries,
|
|
45187
|
+
searchGraph: () => searchGraph,
|
|
45188
|
+
searchGraphWalk: () => searchGraphWalk,
|
|
45189
|
+
searchWalkEnabled: () => searchWalkEnabled,
|
|
45190
|
+
textMatches: () => textMatches,
|
|
45191
|
+
withLinks: () => withLinks
|
|
45034
45192
|
});
|
|
45035
45193
|
import { existsSync as existsSync17, readFileSync as readFileSync16 } from "node:fs";
|
|
45036
45194
|
import { resolve as resolve4 } from "node:path";
|
|
@@ -45152,49 +45310,166 @@ function localCommunityOf(node2) {
|
|
|
45152
45310
|
return typeof cid === "string" ? cid : null;
|
|
45153
45311
|
}
|
|
45154
45312
|
function searchGraph(store, query, limit) {
|
|
45313
|
+
if (!Number.isFinite(limit) || limit < 1) return [];
|
|
45314
|
+
return textMatches(store, query).slice(0, limit).map((m) => toSearchHit(m.node, m.via, m.rg));
|
|
45315
|
+
}
|
|
45316
|
+
function toSearchHit(node2, via, rg) {
|
|
45317
|
+
return {
|
|
45318
|
+
id: node2.id,
|
|
45319
|
+
label: node2.label,
|
|
45320
|
+
description: node2.description,
|
|
45321
|
+
pageRank: node2.pageRank,
|
|
45322
|
+
...via ? { via } : {},
|
|
45323
|
+
...rg.state ? { state: rg.state } : {},
|
|
45324
|
+
...rg.refutedWhy ? { refutedWhy: rg.refutedWhy } : {}
|
|
45325
|
+
};
|
|
45326
|
+
}
|
|
45327
|
+
function textMatches(store, query) {
|
|
45155
45328
|
const q = query.trim();
|
|
45156
|
-
if (!q
|
|
45329
|
+
if (!q) return [];
|
|
45157
45330
|
const terms = q.split(/\s+/).filter((t) => t.length >= 2);
|
|
45158
45331
|
const raw2 = /* @__PURE__ */ new Map();
|
|
45159
45332
|
const searchTerms = terms.length <= 1 ? [q] : terms;
|
|
45160
45333
|
const scored = store.searchTextCandidates ? store.searchTextCandidates(searchTerms) : store.searchDescriptionTerms(searchTerms, Number.MAX_SAFE_INTEGER);
|
|
45161
45334
|
for (const hit of scored) raw2.set(hit.node.id, hit);
|
|
45335
|
+
const lowered = searchTerms.map((t) => t.toLowerCase());
|
|
45336
|
+
const hasTerm = /* @__PURE__ */ new Map();
|
|
45337
|
+
const df = lowered.map(() => 0);
|
|
45338
|
+
for (const { node: node2 } of raw2.values()) {
|
|
45339
|
+
const text = node2.description.toLowerCase();
|
|
45340
|
+
const has = lowered.map((t) => text.includes(t));
|
|
45341
|
+
has.forEach((h, i2) => {
|
|
45342
|
+
if (h) df[i2] += 1;
|
|
45343
|
+
});
|
|
45344
|
+
hasTerm.set(node2.id, has);
|
|
45345
|
+
}
|
|
45346
|
+
const idf = df.map((d) => Math.log(1 + raw2.size / (1 + d)));
|
|
45347
|
+
const idfTotal = idf.reduce((a, b) => a + b, 0) || 1;
|
|
45348
|
+
const coverageOf = (id) => {
|
|
45349
|
+
const has = hasTerm.get(id);
|
|
45350
|
+
return has ? has.reduce((a, h, i2) => a + (h ? idf[i2] : 0), 0) / idfTotal : 0;
|
|
45351
|
+
};
|
|
45162
45352
|
const merged = /* @__PURE__ */ new Map();
|
|
45163
|
-
const add = (node2, matched, via) => {
|
|
45353
|
+
const add = (node2, matched, coverage, via) => {
|
|
45164
45354
|
const e = merged.get(node2.id);
|
|
45165
45355
|
if (e) {
|
|
45166
45356
|
e.matched = Math.max(e.matched, matched);
|
|
45357
|
+
e.coverage = Math.max(e.coverage, coverage);
|
|
45167
45358
|
if (!e.via && via) e.via = via;
|
|
45168
45359
|
} else {
|
|
45169
|
-
merged.set(node2.id, { node: node2, matched, via });
|
|
45360
|
+
merged.set(node2.id, { node: node2, matched, coverage, via });
|
|
45170
45361
|
}
|
|
45171
45362
|
};
|
|
45172
45363
|
const anchors = /* @__PURE__ */ new Map();
|
|
45364
|
+
const batched = store.commentAnchors?.(
|
|
45365
|
+
[...raw2.values()].filter((h) => h.node.label === "Comment").map((h) => h.node.id)
|
|
45366
|
+
);
|
|
45173
45367
|
for (const { node: node2, matched } of raw2.values()) {
|
|
45174
45368
|
if (node2.label === "Comment") {
|
|
45175
|
-
|
|
45176
|
-
if (
|
|
45177
|
-
|
|
45369
|
+
let anchor;
|
|
45370
|
+
if (batched) {
|
|
45371
|
+
anchor = batched.get(node2.id) ?? null;
|
|
45372
|
+
} else {
|
|
45373
|
+
const anchorId = commentAnchorId(store, node2.id);
|
|
45374
|
+
if (anchorId && !anchors.has(anchorId)) {
|
|
45375
|
+
anchors.set(anchorId, store.getTextSearchNode ? store.getTextSearchNode(anchorId) : store.getNode(anchorId));
|
|
45376
|
+
}
|
|
45377
|
+
anchor = anchorId ? anchors.get(anchorId) : null;
|
|
45178
45378
|
}
|
|
45179
|
-
const anchor = anchorId ? anchors.get(anchorId) : null;
|
|
45180
45379
|
if (anchor) {
|
|
45181
|
-
add(anchor, matched, { kind: "comment", text: node2.description });
|
|
45380
|
+
add(anchor, matched, coverageOf(node2.id), { kind: "comment", text: node2.description });
|
|
45182
45381
|
continue;
|
|
45183
45382
|
}
|
|
45184
45383
|
}
|
|
45185
|
-
add(node2, matched);
|
|
45384
|
+
add(node2, matched, coverageOf(node2.id));
|
|
45186
45385
|
}
|
|
45187
45386
|
return [...merged.values()].map((e) => ({ ...e, rg: hitState(e.node) })).sort(
|
|
45188
45387
|
(a, b) => rankTier(a.node) - rankTier(b.node) || b.matched - a.matched || b.node.pageRank * b.rg.factor - a.node.pageRank * a.rg.factor
|
|
45189
|
-
).
|
|
45190
|
-
|
|
45191
|
-
|
|
45192
|
-
|
|
45193
|
-
|
|
45194
|
-
|
|
45195
|
-
|
|
45196
|
-
|
|
45197
|
-
|
|
45388
|
+
).map(({ node: node2, via, rg, coverage, matched }) => ({ node: node2, via, rg, coverage, matched }));
|
|
45389
|
+
}
|
|
45390
|
+
function isIdentifierToken(t) {
|
|
45391
|
+
return t.length >= 4 && IDENTIFIER_TOKEN.test(t) && (/[a-z][A-Z]/.test(t) || /_/.test(t) || t.includes("."));
|
|
45392
|
+
}
|
|
45393
|
+
function symbolName(description) {
|
|
45394
|
+
return description.split(/[\s—(]/, 1)[0] ?? "";
|
|
45395
|
+
}
|
|
45396
|
+
function withLinks(store, hits) {
|
|
45397
|
+
const idOf = (h) => String(h.id ?? "");
|
|
45398
|
+
const ids = new Set(hits.map(idOf));
|
|
45399
|
+
return hits.map((h) => {
|
|
45400
|
+
const id = idOf(h);
|
|
45401
|
+
const links = store.outEdges(id).filter((e) => e.to !== id && ids.has(e.to)).map((e) => ({ edgeType: e.type, to: e.to }));
|
|
45402
|
+
return links.length > 0 ? { ...h, links } : h;
|
|
45403
|
+
});
|
|
45404
|
+
}
|
|
45405
|
+
function searchEntries(query, matches) {
|
|
45406
|
+
const words = query.trim().split(/\s+/).filter(Boolean);
|
|
45407
|
+
const idents = new Set(words.filter(isIdentifierToken));
|
|
45408
|
+
const phrases = [];
|
|
45409
|
+
for (let i2 = 0; i2 + PHRASE_WORDS <= words.length; i2++) {
|
|
45410
|
+
phrases.push(words.slice(i2, i2 + PHRASE_WORDS).join(" ").toLowerCase());
|
|
45411
|
+
}
|
|
45412
|
+
const seeds = /* @__PURE__ */ new Map();
|
|
45413
|
+
const put = (m, weight) => {
|
|
45414
|
+
const w = weight * m.rg.factor;
|
|
45415
|
+
const prev = seeds.get(m.node.id);
|
|
45416
|
+
if (!prev || prev.weight < w) seeds.set(m.node.id, { id: m.node.id, label: m.node.label, weight: w });
|
|
45417
|
+
};
|
|
45418
|
+
for (const m of matches) {
|
|
45419
|
+
if (idents.size === 0) break;
|
|
45420
|
+
const name2 = symbolName(m.node.description);
|
|
45421
|
+
const last = name2.slice(name2.lastIndexOf(".") + 1);
|
|
45422
|
+
if (idents.has(name2) || idents.has(last)) put(m, m.coverage * m.coverage * (SEED_TIER_WEIGHT[rankTier(m.node)] ?? 1));
|
|
45423
|
+
}
|
|
45424
|
+
const knowledge = matches.filter((m) => KNOWLEDGE_LABELS.has(m.node.label)).map((m) => {
|
|
45425
|
+
const text = m.node.description.toLowerCase();
|
|
45426
|
+
return { m, w: phrases.some((ph) => text.includes(ph)) ? 1 : m.coverage * m.coverage };
|
|
45427
|
+
}).filter(({ m, w }) => w === 1 || (words.length < 2 || m.matched >= 2) && m.coverage >= DEFAULT_MIN_COVERAGE).sort((a, b) => b.w - a.w).slice(0, SEARCH_KNOWLEDGE_SEEDS);
|
|
45428
|
+
for (const { m, w } of knowledge) put(m, w);
|
|
45429
|
+
const code = matches.filter((m) => !KNOWLEDGE_LABELS.has(m.node.label)).map((m) => ({ m, w: m.coverage * m.coverage * (SEED_TIER_WEIGHT[rankTier(m.node)] ?? 1) })).sort((a, b) => b.w - a.w).slice(0, SEARCH_CODE_SEEDS);
|
|
45430
|
+
for (const { m, w } of code) put(m, w);
|
|
45431
|
+
return [...seeds.values()].filter((sd) => sd.weight > 0);
|
|
45432
|
+
}
|
|
45433
|
+
function withoutSymbolInternals(store, ranked) {
|
|
45434
|
+
const ids = new Set(ranked.map((r) => r.id));
|
|
45435
|
+
const internal = /* @__PURE__ */ new Set();
|
|
45436
|
+
for (const r of ranked) {
|
|
45437
|
+
for (const e of store.inEdges(r.id, ["DEFINES"])) {
|
|
45438
|
+
if (!ids.has(e.from)) continue;
|
|
45439
|
+
const parent = store.getNode(e.from);
|
|
45440
|
+
if (parent && SYMBOL_PARENT_LABELS.has(parent.label)) internal.add(r.id);
|
|
45441
|
+
}
|
|
45442
|
+
}
|
|
45443
|
+
return internal.size > 0 ? ranked.filter((r) => !internal.has(r.id)) : ranked;
|
|
45444
|
+
}
|
|
45445
|
+
function searchWalkEnabled(env2 = process.env) {
|
|
45446
|
+
return !/^(0|off|false|no)$/i.test((env2["ERRATA_SEARCH_WALK"] ?? "").trim());
|
|
45447
|
+
}
|
|
45448
|
+
function searchGraphWalk(store, query, limit) {
|
|
45449
|
+
if (!Number.isFinite(limit) || limit < 1) return [];
|
|
45450
|
+
const matches = textMatches(store, query);
|
|
45451
|
+
if (matches.length === 0) return [];
|
|
45452
|
+
const byId = new Map(matches.map((m) => [m.node.id, m]));
|
|
45453
|
+
const walked = withoutSymbolInternals(
|
|
45454
|
+
store,
|
|
45455
|
+
burstFromSeeds(store, searchEntries(query, matches), { limit: limit * 4, typeRelevanceForSeeds: false })
|
|
45456
|
+
);
|
|
45457
|
+
const lanes = [walked.filter((r) => KNOWLEDGE_LABELS.has(r.node.label)), walked.filter((r) => !KNOWLEDGE_LABELS.has(r.node.label))];
|
|
45458
|
+
const ranked = [];
|
|
45459
|
+
for (let i2 = 0; ranked.length < limit && i2 < walked.length; i2++) {
|
|
45460
|
+
for (const lane of lanes) if (lane[i2] && ranked.length < limit) ranked.push(lane[i2]);
|
|
45461
|
+
}
|
|
45462
|
+
return ranked.map((r) => {
|
|
45463
|
+
const m = byId.get(r.id);
|
|
45464
|
+
if (m) return { ...toSearchHit(m.node, m.via, m.rg), score: r.score, matched: true };
|
|
45465
|
+
const rg = hitState(r.node);
|
|
45466
|
+
return {
|
|
45467
|
+
...toSearchHit(r.node, void 0, rg),
|
|
45468
|
+
score: r.score,
|
|
45469
|
+
matched: false,
|
|
45470
|
+
...r.via ? { reachedVia: { edgeType: r.via.edgeType, from: r.via.parentId } } : {}
|
|
45471
|
+
};
|
|
45472
|
+
});
|
|
45198
45473
|
}
|
|
45199
45474
|
function runTool(name2, args2, store, ctx = {}) {
|
|
45200
45475
|
const tool = TOOLS.find((t) => t.name === name2);
|
|
@@ -45530,7 +45805,7 @@ async function runMcpServer(workspaceRoot, options = {}) {
|
|
|
45530
45805
|
if (resp) process.stdout.write(JSON.stringify(resp) + "\n");
|
|
45531
45806
|
}
|
|
45532
45807
|
}
|
|
45533
|
-
var INSTRUCTIONS, AUDIT_RUN_THRESHOLD, AUDIT_NUDGE_COOLDOWN, DISCRIMINATOR_NUDGE_COOLDOWN, AUDIT_FLAG_NUDGE, RG_REFUTED_DAMP, RG_SUSPECT_BOOST, TOOLS;
|
|
45808
|
+
var INSTRUCTIONS, AUDIT_RUN_THRESHOLD, AUDIT_NUDGE_COOLDOWN, DISCRIMINATOR_NUDGE_COOLDOWN, AUDIT_FLAG_NUDGE, RG_REFUTED_DAMP, RG_SUSPECT_BOOST, SEARCH_KNOWLEDGE_SEEDS, SEARCH_CODE_SEEDS, PHRASE_WORDS, KNOWLEDGE_LABELS, IDENTIFIER_TOKEN, SYMBOL_PARENT_LABELS, SEED_TIER_WEIGHT, TOOLS;
|
|
45534
45809
|
var init_mcp = __esm({
|
|
45535
45810
|
"src/mcp.ts"() {
|
|
45536
45811
|
"use strict";
|
|
@@ -45563,6 +45838,13 @@ var init_mcp = __esm({
|
|
|
45563
45838
|
AUDIT_FLAG_NUDGE = "\u26A1 errata \u2014 reading/auditing? anything you notice that's off, flag it inline as `[!one line]` (`[?\u2026]` = TODO) \u2014 no tool call, we harvest it.";
|
|
45564
45839
|
RG_REFUTED_DAMP = 0.75;
|
|
45565
45840
|
RG_SUSPECT_BOOST = 1.25;
|
|
45841
|
+
SEARCH_KNOWLEDGE_SEEDS = 30;
|
|
45842
|
+
SEARCH_CODE_SEEDS = 15;
|
|
45843
|
+
PHRASE_WORDS = 3;
|
|
45844
|
+
KNOWLEDGE_LABELS = new Set(SEMANTIC_NODE_LABELS);
|
|
45845
|
+
IDENTIFIER_TOKEN = /^(?:[A-Za-z_$][\w$]*\.)*[A-Za-z_$][\w$]*$/;
|
|
45846
|
+
SYMBOL_PARENT_LABELS = /* @__PURE__ */ new Set(["Function", "Method", "Class", "Interface"]);
|
|
45847
|
+
SEED_TIER_WEIGHT = [1, 0.4, 0.4];
|
|
45566
45848
|
TOOLS = [
|
|
45567
45849
|
{
|
|
45568
45850
|
name: "errata.switch_context",
|
|
@@ -45601,7 +45883,7 @@ var init_mcp = __esm({
|
|
|
45601
45883
|
},
|
|
45602
45884
|
{
|
|
45603
45885
|
name: "errata.search",
|
|
45604
|
-
description: "Find a symbol, string,
|
|
45886
|
+
description: "Find a symbol, string, comment, or the knowledge around them, as a GRAPH search. The query's words pick entry points \u2014 a symbol an identifier names, knowledge carrying the query's words (a literal phrase counts most), the strongest code matches \u2014 and one walk from all of them ranks what sits at their centre, so a Problem anchored on the function you named surfaces without repeating your words. Knowledge and code alternate down the list. Each hit carries `matched` (true = the text matched; false = the walk reached it, with `reachedVia` {edgeType, from}), `score`, and `links` \u2014 its edges to the OTHER hits in this answer, so a Problem \u2014CAUSED_BY\u2192 RootCause or a fix \u2014ANCHORED_AT\u2192 the function reads as a chain. Word order and punctuation don't matter. A comment that documents a symbol resolves to that SYMBOL (the comment rides along as `via` \u2014 it's the why, not the destination); test scaffolding and floating comments sort below production code. When the collective is reachable, results BLEND cross-project knowledge, each tagged `provenance` (local | collective | corroborated) with `usageCount`.",
|
|
45605
45887
|
inputSchema: {
|
|
45606
45888
|
type: "object",
|
|
45607
45889
|
properties: {
|
|
@@ -45613,13 +45895,16 @@ var init_mcp = __esm({
|
|
|
45613
45895
|
handler: async (args2, store, ctx) => {
|
|
45614
45896
|
const query = String(args2["query"] ?? "");
|
|
45615
45897
|
const limit = Math.max(1, Math.min(100, Number(args2["limit"] ?? 20)));
|
|
45616
|
-
const hits =
|
|
45898
|
+
const hits = withLinks(
|
|
45899
|
+
store,
|
|
45900
|
+
searchWalkEnabled() ? searchGraphWalk(store, query, limit) : searchGraph(store, query, limit).map((h) => ({ ...h, score: h.pageRank, matched: true }))
|
|
45901
|
+
);
|
|
45617
45902
|
if (ctx.cloud && query.trim()) {
|
|
45618
45903
|
const localHits = hits.map((h) => ({
|
|
45619
45904
|
id: h.id,
|
|
45620
45905
|
node: { label: h.label, description: h.description },
|
|
45621
|
-
score: h.
|
|
45622
|
-
hops: 0
|
|
45906
|
+
score: h.score,
|
|
45907
|
+
hops: h.matched ? 0 : 1
|
|
45623
45908
|
}));
|
|
45624
45909
|
const dual = await dualAugment({
|
|
45625
45910
|
store,
|
|
@@ -45627,7 +45912,8 @@ var init_mcp = __esm({
|
|
|
45627
45912
|
...ctx.generalizeSoft ? { generalizeSoft: ctx.generalizeSoft } : {},
|
|
45628
45913
|
localHits,
|
|
45629
45914
|
queryText: query,
|
|
45630
|
-
limit
|
|
45915
|
+
limit,
|
|
45916
|
+
fuse: "rank"
|
|
45631
45917
|
});
|
|
45632
45918
|
if (dual.status === "merged") {
|
|
45633
45919
|
return {
|
|
@@ -45637,7 +45923,7 @@ var init_mcp = __esm({
|
|
|
45637
45923
|
count: dual.merged.nodes.length,
|
|
45638
45924
|
corroborated: dual.merged.corroboratedCount,
|
|
45639
45925
|
collective: dual.merged.collectiveCount,
|
|
45640
|
-
results: formatDualNodes(dual.merged)
|
|
45926
|
+
results: withLinks(store, formatDualNodes(dual.merged))
|
|
45641
45927
|
};
|
|
45642
45928
|
}
|
|
45643
45929
|
return {
|
|
@@ -77688,9 +77974,38 @@ function createSubagentState() {
|
|
|
77688
77974
|
// src/subagent-context.ts
|
|
77689
77975
|
init_src6();
|
|
77690
77976
|
init_src8();
|
|
77691
|
-
init_src5();
|
|
77692
77977
|
init_src2();
|
|
77693
77978
|
init_recall_signal();
|
|
77979
|
+
|
|
77980
|
+
// src/intent-walk.ts
|
|
77981
|
+
init_src8();
|
|
77982
|
+
init_src5();
|
|
77983
|
+
var INTENT_WALK_SEEDS = 30;
|
|
77984
|
+
var RECALLABLE2 = /* @__PURE__ */ new Set(["Problem", "Solution", "RootCause", "Pattern"]);
|
|
77985
|
+
function walkIntent(store, intent, opts) {
|
|
77986
|
+
const entries = searchByIntent(store, intent, { limit: INTENT_WALK_SEEDS });
|
|
77987
|
+
if (entries.length === 0) return [];
|
|
77988
|
+
const out2 = entries.slice(0, opts.limit);
|
|
77989
|
+
if (out2.length >= opts.limit) return out2;
|
|
77990
|
+
const shown = new Set(out2.map((h) => h.node.id));
|
|
77991
|
+
const seedIds = new Set(entries.map((h) => h.node.id));
|
|
77992
|
+
const ranked = burstFromSeeds(
|
|
77993
|
+
store,
|
|
77994
|
+
entries.map((h) => ({ id: h.node.id, label: h.node.label, weight: h.coverage * h.coverage })),
|
|
77995
|
+
{ limit: opts.limit * 10, typeRelevanceForSeeds: false }
|
|
77996
|
+
);
|
|
77997
|
+
for (const r of ranked) {
|
|
77998
|
+
if (out2.length >= opts.limit) break;
|
|
77999
|
+
if (shown.has(r.id) || seedIds.has(r.id)) continue;
|
|
78000
|
+
const n = r.node;
|
|
78001
|
+
if (!RECALLABLE2.has(n.label) || n.attrs["mergedInto"] !== void 0) continue;
|
|
78002
|
+
if (n.label === "Problem" && n.attrs["resolvedAt"] != null && !isConstraintProblem(n)) continue;
|
|
78003
|
+
out2.push({ node: n, coverage: 0, matched: [] });
|
|
78004
|
+
}
|
|
78005
|
+
return out2;
|
|
78006
|
+
}
|
|
78007
|
+
|
|
78008
|
+
// src/subagent-context.ts
|
|
77694
78009
|
var MAX_SHARED_PRIORS = 8;
|
|
77695
78010
|
var INTENT_HITS = 4;
|
|
77696
78011
|
function resolveSharedPriors(store, wanted, handleMap, remote) {
|
|
@@ -77713,7 +78028,7 @@ function renderSubagentBlock(args2) {
|
|
|
77713
78028
|
const slice = sliceForFile(store, entry.workingFile, args2.atCommit);
|
|
77714
78029
|
if (slice) snapshot.workingFile = slice;
|
|
77715
78030
|
}
|
|
77716
|
-
const hits = entry.intent ?
|
|
78031
|
+
const hits = entry.intent ? walkIntent(store, entry.intent, { limit: INTENT_HITS }).map((h) => ({
|
|
77717
78032
|
id: h.node.id,
|
|
77718
78033
|
label: h.node.label,
|
|
77719
78034
|
description: h.node.description,
|
|
@@ -84076,7 +84391,7 @@ function createWatchBreaker(deps) {
|
|
|
84076
84391
|
}
|
|
84077
84392
|
|
|
84078
84393
|
// src/engine.ts
|
|
84079
|
-
var DAEMON_VERSION = true ? "2.0.22-dev.
|
|
84394
|
+
var DAEMON_VERSION = true ? "2.0.22-dev.4049" : "2.0.0-alpha.0";
|
|
84080
84395
|
var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
|
|
84081
84396
|
var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
|
|
84082
84397
|
var GIT_OP_MUTE_MS = 4e3;
|
|
@@ -84546,7 +84861,7 @@ function createWorkspaceEngine(opts) {
|
|
|
84546
84861
|
const collective = intentRemote?.forIntent === intent ? intentRemote : null;
|
|
84547
84862
|
return {
|
|
84548
84863
|
text: intent,
|
|
84549
|
-
hits:
|
|
84864
|
+
hits: walkIntent(store, intent, { limit: 4 }).map((h) => ({
|
|
84550
84865
|
id: h.node.id,
|
|
84551
84866
|
label: h.node.label,
|
|
84552
84867
|
description: h.node.description,
|
package/generalize-worker.mjs
CHANGED
|
@@ -15093,6 +15093,38 @@ function installHistoryAttrSlim(db) {
|
|
|
15093
15093
|
db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(HISTORY_ATTR_SLIM_KEY, "done");
|
|
15094
15094
|
}
|
|
15095
15095
|
|
|
15096
|
+
// ../../packages/local-graph/src/text-index.ts
|
|
15097
|
+
var TEXT_INDEX_KEY = "text-index-trigram-1";
|
|
15098
|
+
var TEXT_INDEX_MIN_TERM = 3;
|
|
15099
|
+
function installTextIndex(db) {
|
|
15100
|
+
if (db.prepare("SELECT value FROM store_meta WHERE key = ?").get(TEXT_INDEX_KEY)) return;
|
|
15101
|
+
try {
|
|
15102
|
+
db.exec(`CREATE VIRTUAL TABLE temp.fts5_probe USING fts5(x, tokenize='trigram'); DROP TABLE temp.fts5_probe`);
|
|
15103
|
+
} catch {
|
|
15104
|
+
db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(TEXT_INDEX_KEY, "unavailable");
|
|
15105
|
+
return;
|
|
15106
|
+
}
|
|
15107
|
+
db.transaction(() => {
|
|
15108
|
+
db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS nodes_text
|
|
15109
|
+
USING fts5(description, content='nodes', content_rowid='rowid', tokenize='trigram')`);
|
|
15110
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_insert AFTER INSERT ON nodes WHEN NEW.valid_to IS NULL
|
|
15111
|
+
BEGIN INSERT INTO nodes_text(rowid, description) VALUES (NEW.rowid, NEW.description); END;`);
|
|
15112
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_update_out AFTER UPDATE OF description, valid_to ON nodes
|
|
15113
|
+
WHEN OLD.valid_to IS NULL
|
|
15114
|
+
BEGIN INSERT INTO nodes_text(nodes_text, rowid, description) VALUES ('delete', OLD.rowid, OLD.description); END;`);
|
|
15115
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_update_in AFTER UPDATE OF description, valid_to ON nodes
|
|
15116
|
+
WHEN NEW.valid_to IS NULL
|
|
15117
|
+
BEGIN INSERT INTO nodes_text(rowid, description) VALUES (NEW.rowid, NEW.description); END;`);
|
|
15118
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_delete AFTER DELETE ON nodes WHEN OLD.valid_to IS NULL
|
|
15119
|
+
BEGIN INSERT INTO nodes_text(nodes_text, rowid, description) VALUES ('delete', OLD.rowid, OLD.description); END;`);
|
|
15120
|
+
db.exec(`INSERT INTO nodes_text(rowid, description) SELECT rowid, description FROM nodes WHERE valid_to IS NULL`);
|
|
15121
|
+
db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(TEXT_INDEX_KEY, "installed");
|
|
15122
|
+
});
|
|
15123
|
+
}
|
|
15124
|
+
function textIndexReady(db) {
|
|
15125
|
+
return db.prepare("SELECT value FROM store_meta WHERE key = ?").get(TEXT_INDEX_KEY)?.["value"] === "installed";
|
|
15126
|
+
}
|
|
15127
|
+
|
|
15096
15128
|
// ../../packages/math/src/relevance.ts
|
|
15097
15129
|
function pageRankScale(ranks) {
|
|
15098
15130
|
const positive = [...ranks].filter((r) => Number.isFinite(r) && r > 0).sort((a, b) => a - b);
|
|
@@ -15391,6 +15423,7 @@ var SqliteGraphStore = class {
|
|
|
15391
15423
|
installEditPlaceholderRetirement(this.db);
|
|
15392
15424
|
installCloudAttrCompaction(this.db);
|
|
15393
15425
|
installHistoryAttrSlim(this.db);
|
|
15426
|
+
installTextIndex(this.db);
|
|
15394
15427
|
if (!this.db.prepare("SELECT value FROM store_meta WHERE key = ?").get(SESSION_REPAIR_KEY)) {
|
|
15395
15428
|
this.db.transaction(() => {
|
|
15396
15429
|
this.repairSessionAliases();
|
|
@@ -16045,6 +16078,20 @@ var SqliteGraphStore = class {
|
|
|
16045
16078
|
}
|
|
16046
16079
|
searchTextCandidates(terms) {
|
|
16047
16080
|
if (terms.length === 0) return [];
|
|
16081
|
+
const indexed = terms.filter((t) => t.length >= TEXT_INDEX_MIN_TERM);
|
|
16082
|
+
if (indexed.length > 0 && textIndexReady(this.db)) {
|
|
16083
|
+
const short = terms.filter((t) => t.length < TEXT_INDEX_MIN_TERM).map((t) => t.toLowerCase());
|
|
16084
|
+
const rows2 = this.db.prepare(`WITH hits AS MATERIALIZED (
|
|
16085
|
+
SELECT t.rowid AS rid, COUNT(*) AS matched FROM json_each(:terms) q, nodes_text t
|
|
16086
|
+
WHERE t.description LIKE '%' || q.value || '%' GROUP BY t.rowid
|
|
16087
|
+
) SELECT ${TEXT_SEARCH_COLUMNS}, hits.matched FROM hits JOIN nodes ON nodes.rowid = hits.rid
|
|
16088
|
+
WHERE nodes.valid_to IS NULL ORDER BY page_rank DESC, last_updated_at DESC`).all({ terms: JSON.stringify(indexed) });
|
|
16089
|
+
return rows2.map((row) => {
|
|
16090
|
+
const text = row.description.toLowerCase();
|
|
16091
|
+
const extra = short.filter((t) => text.includes(t)).length;
|
|
16092
|
+
return { node: textSearchNode(row), matched: row.matched + extra };
|
|
16093
|
+
});
|
|
16094
|
+
}
|
|
16048
16095
|
const rows = this.db.prepare(`WITH matches AS MATERIALIZED (
|
|
16049
16096
|
SELECT n.id, COUNT(*) AS matched FROM nodes n INDEXED BY nodes_live_description, json_each(:terms) t
|
|
16050
16097
|
WHERE n.valid_to IS NULL AND n.description LIKE '%' || t.value || '%'
|
|
@@ -16053,6 +16100,18 @@ var SqliteGraphStore = class {
|
|
|
16053
16100
|
JOIN matches USING (id) ORDER BY page_rank DESC, last_updated_at DESC`).all({ terms: JSON.stringify(terms) });
|
|
16054
16101
|
return rows.map((row) => ({ node: textSearchNode(row), matched: row.matched }));
|
|
16055
16102
|
}
|
|
16103
|
+
commentAnchors(commentIds) {
|
|
16104
|
+
const out = /* @__PURE__ */ new Map();
|
|
16105
|
+
if (commentIds.length === 0) return out;
|
|
16106
|
+
const rows = this.db.prepare(`WITH a AS MATERIALIZED (
|
|
16107
|
+
SELECT q.value AS cid, COALESCE(
|
|
16108
|
+
(SELECT to_id FROM edges WHERE from_id = q.value AND type IN ('EXPLAINS', 'ANNOTATES') AND valid_to IS NULL LIMIT 1),
|
|
16109
|
+
(SELECT from_id FROM edges WHERE to_id = q.value AND type = 'DOCUMENTED_BY' AND valid_to IS NULL LIMIT 1)
|
|
16110
|
+
) AS aid FROM json_each(:ids) q
|
|
16111
|
+
) 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) });
|
|
16112
|
+
for (const row of rows) out.set(row.cid, textSearchNode(row));
|
|
16113
|
+
return out;
|
|
16114
|
+
}
|
|
16056
16115
|
getTextSearchNode(id) {
|
|
16057
16116
|
const row = this.db.prepare(`SELECT ${TEXT_SEARCH_COLUMNS} FROM nodes WHERE id = ? AND valid_to IS NULL`).get(id);
|
|
16058
16117
|
return row ? textSearchNode(row) : null;
|
package/package.json
CHANGED
package/pass-worker.mjs
CHANGED
|
@@ -25515,6 +25515,38 @@ function installHistoryAttrSlim(db) {
|
|
|
25515
25515
|
db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(HISTORY_ATTR_SLIM_KEY, "done");
|
|
25516
25516
|
}
|
|
25517
25517
|
|
|
25518
|
+
// ../../packages/local-graph/src/text-index.ts
|
|
25519
|
+
var TEXT_INDEX_KEY = "text-index-trigram-1";
|
|
25520
|
+
var TEXT_INDEX_MIN_TERM = 3;
|
|
25521
|
+
function installTextIndex(db) {
|
|
25522
|
+
if (db.prepare("SELECT value FROM store_meta WHERE key = ?").get(TEXT_INDEX_KEY)) return;
|
|
25523
|
+
try {
|
|
25524
|
+
db.exec(`CREATE VIRTUAL TABLE temp.fts5_probe USING fts5(x, tokenize='trigram'); DROP TABLE temp.fts5_probe`);
|
|
25525
|
+
} catch {
|
|
25526
|
+
db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(TEXT_INDEX_KEY, "unavailable");
|
|
25527
|
+
return;
|
|
25528
|
+
}
|
|
25529
|
+
db.transaction(() => {
|
|
25530
|
+
db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS nodes_text
|
|
25531
|
+
USING fts5(description, content='nodes', content_rowid='rowid', tokenize='trigram')`);
|
|
25532
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_insert AFTER INSERT ON nodes WHEN NEW.valid_to IS NULL
|
|
25533
|
+
BEGIN INSERT INTO nodes_text(rowid, description) VALUES (NEW.rowid, NEW.description); END;`);
|
|
25534
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_update_out AFTER UPDATE OF description, valid_to ON nodes
|
|
25535
|
+
WHEN OLD.valid_to IS NULL
|
|
25536
|
+
BEGIN INSERT INTO nodes_text(nodes_text, rowid, description) VALUES ('delete', OLD.rowid, OLD.description); END;`);
|
|
25537
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_update_in AFTER UPDATE OF description, valid_to ON nodes
|
|
25538
|
+
WHEN NEW.valid_to IS NULL
|
|
25539
|
+
BEGIN INSERT INTO nodes_text(rowid, description) VALUES (NEW.rowid, NEW.description); END;`);
|
|
25540
|
+
db.exec(`CREATE TRIGGER IF NOT EXISTS nodes_text_delete AFTER DELETE ON nodes WHEN OLD.valid_to IS NULL
|
|
25541
|
+
BEGIN INSERT INTO nodes_text(nodes_text, rowid, description) VALUES ('delete', OLD.rowid, OLD.description); END;`);
|
|
25542
|
+
db.exec(`INSERT INTO nodes_text(rowid, description) SELECT rowid, description FROM nodes WHERE valid_to IS NULL`);
|
|
25543
|
+
db.prepare("INSERT INTO store_meta(key,value) VALUES (?,?)").run(TEXT_INDEX_KEY, "installed");
|
|
25544
|
+
});
|
|
25545
|
+
}
|
|
25546
|
+
function textIndexReady(db) {
|
|
25547
|
+
return db.prepare("SELECT value FROM store_meta WHERE key = ?").get(TEXT_INDEX_KEY)?.["value"] === "installed";
|
|
25548
|
+
}
|
|
25549
|
+
|
|
25518
25550
|
// ../../packages/math/src/pagerank.ts
|
|
25519
25551
|
function pagerank(input) {
|
|
25520
25552
|
const damping = input.damping ?? 0.85;
|
|
@@ -26249,6 +26281,7 @@ var SqliteGraphStore = class {
|
|
|
26249
26281
|
installEditPlaceholderRetirement(this.db);
|
|
26250
26282
|
installCloudAttrCompaction(this.db);
|
|
26251
26283
|
installHistoryAttrSlim(this.db);
|
|
26284
|
+
installTextIndex(this.db);
|
|
26252
26285
|
if (!this.db.prepare("SELECT value FROM store_meta WHERE key = ?").get(SESSION_REPAIR_KEY)) {
|
|
26253
26286
|
this.db.transaction(() => {
|
|
26254
26287
|
this.repairSessionAliases();
|
|
@@ -26903,6 +26936,20 @@ var SqliteGraphStore = class {
|
|
|
26903
26936
|
}
|
|
26904
26937
|
searchTextCandidates(terms) {
|
|
26905
26938
|
if (terms.length === 0) return [];
|
|
26939
|
+
const indexed = terms.filter((t) => t.length >= TEXT_INDEX_MIN_TERM);
|
|
26940
|
+
if (indexed.length > 0 && textIndexReady(this.db)) {
|
|
26941
|
+
const short = terms.filter((t) => t.length < TEXT_INDEX_MIN_TERM).map((t) => t.toLowerCase());
|
|
26942
|
+
const rows2 = this.db.prepare(`WITH hits AS MATERIALIZED (
|
|
26943
|
+
SELECT t.rowid AS rid, COUNT(*) AS matched FROM json_each(:terms) q, nodes_text t
|
|
26944
|
+
WHERE t.description LIKE '%' || q.value || '%' GROUP BY t.rowid
|
|
26945
|
+
) SELECT ${TEXT_SEARCH_COLUMNS}, hits.matched FROM hits JOIN nodes ON nodes.rowid = hits.rid
|
|
26946
|
+
WHERE nodes.valid_to IS NULL ORDER BY page_rank DESC, last_updated_at DESC`).all({ terms: JSON.stringify(indexed) });
|
|
26947
|
+
return rows2.map((row) => {
|
|
26948
|
+
const text = row.description.toLowerCase();
|
|
26949
|
+
const extra = short.filter((t) => text.includes(t)).length;
|
|
26950
|
+
return { node: textSearchNode(row), matched: row.matched + extra };
|
|
26951
|
+
});
|
|
26952
|
+
}
|
|
26906
26953
|
const rows = this.db.prepare(`WITH matches AS MATERIALIZED (
|
|
26907
26954
|
SELECT n.id, COUNT(*) AS matched FROM nodes n INDEXED BY nodes_live_description, json_each(:terms) t
|
|
26908
26955
|
WHERE n.valid_to IS NULL AND n.description LIKE '%' || t.value || '%'
|
|
@@ -26911,6 +26958,18 @@ var SqliteGraphStore = class {
|
|
|
26911
26958
|
JOIN matches USING (id) ORDER BY page_rank DESC, last_updated_at DESC`).all({ terms: JSON.stringify(terms) });
|
|
26912
26959
|
return rows.map((row) => ({ node: textSearchNode(row), matched: row.matched }));
|
|
26913
26960
|
}
|
|
26961
|
+
commentAnchors(commentIds) {
|
|
26962
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
26963
|
+
if (commentIds.length === 0) return out2;
|
|
26964
|
+
const rows = this.db.prepare(`WITH a AS MATERIALIZED (
|
|
26965
|
+
SELECT q.value AS cid, COALESCE(
|
|
26966
|
+
(SELECT to_id FROM edges WHERE from_id = q.value AND type IN ('EXPLAINS', 'ANNOTATES') AND valid_to IS NULL LIMIT 1),
|
|
26967
|
+
(SELECT from_id FROM edges WHERE to_id = q.value AND type = 'DOCUMENTED_BY' AND valid_to IS NULL LIMIT 1)
|
|
26968
|
+
) AS aid FROM json_each(:ids) q
|
|
26969
|
+
) 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) });
|
|
26970
|
+
for (const row of rows) out2.set(row.cid, textSearchNode(row));
|
|
26971
|
+
return out2;
|
|
26972
|
+
}
|
|
26914
26973
|
getTextSearchNode(id) {
|
|
26915
26974
|
const row = this.db.prepare(`SELECT ${TEXT_SEARCH_COLUMNS} FROM nodes WHERE id = ? AND valid_to IS NULL`).get(id);
|
|
26916
26975
|
return row ? textSearchNode(row) : null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
fed0cc007727934c2ac9ad932429797dfe773ebb96c0219d09141979f2886c84 .codex-plugin/plugin.json
|
|
2
2
|
a7bebae9fb01c838d6c75fc784129e28be571233fa66ff5ee8039b574f35ccf7 assets/icon.png
|
|
3
3
|
fc38b64e4df1e0b72c35764bef6c4c05430d97c9009ad0ecc8a9e75b4deab232 configure-local.mjs
|
|
4
4
|
73dc6028b3b070257c7c31f252d11e55a9e096f4aed0f187f10cb21716e1e6d7 dist/client.js
|