@pratik7368patil/anchor-core 0.1.32 → 0.1.33
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/dist/index.d.ts +36 -1
- package/dist/index.js +576 -111
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/db/schema.sql +14 -0
package/dist/index.js
CHANGED
|
@@ -617,8 +617,12 @@ CREATE TABLE IF NOT EXISTS org_cross_repo_edges (
|
|
|
617
617
|
source_path TEXT NOT NULL,
|
|
618
618
|
target_repo TEXT NOT NULL,
|
|
619
619
|
target_path TEXT,
|
|
620
|
+
layer TEXT NOT NULL DEFAULT 'file',
|
|
620
621
|
relationship TEXT NOT NULL,
|
|
621
622
|
evidence_json TEXT NOT NULL,
|
|
623
|
+
match_reasons_json TEXT NOT NULL DEFAULT '[]',
|
|
624
|
+
evidence_count INTEGER NOT NULL DEFAULT 0,
|
|
625
|
+
is_weak INTEGER NOT NULL DEFAULT 0,
|
|
622
626
|
confidence REAL NOT NULL,
|
|
623
627
|
created_at TEXT NOT NULL
|
|
624
628
|
);
|
|
@@ -643,6 +647,9 @@ CREATE TABLE IF NOT EXISTS org_api_consumers (
|
|
|
643
647
|
consumer_path TEXT NOT NULL,
|
|
644
648
|
contract TEXT NOT NULL,
|
|
645
649
|
evidence_json TEXT NOT NULL,
|
|
650
|
+
match_reasons_json TEXT NOT NULL DEFAULT '[]',
|
|
651
|
+
evidence_count INTEGER NOT NULL DEFAULT 0,
|
|
652
|
+
is_weak INTEGER NOT NULL DEFAULT 0,
|
|
646
653
|
confidence REAL NOT NULL,
|
|
647
654
|
created_at TEXT NOT NULL
|
|
648
655
|
);
|
|
@@ -667,6 +674,10 @@ CREATE TABLE IF NOT EXISTS org_graph_state (
|
|
|
667
674
|
last_status TEXT NOT NULL DEFAULT 'unknown',
|
|
668
675
|
last_duration_ms INTEGER,
|
|
669
676
|
edge_count INTEGER NOT NULL DEFAULT 0,
|
|
677
|
+
visible_edge_count INTEGER NOT NULL DEFAULT 0,
|
|
678
|
+
weak_edge_count INTEGER NOT NULL DEFAULT 0,
|
|
679
|
+
edge_confidence_json TEXT NOT NULL DEFAULT '{"strong":0,"moderate":0,"weak":0}',
|
|
680
|
+
last_render_prep_ms INTEGER,
|
|
670
681
|
api_contract_count INTEGER NOT NULL DEFAULT 0,
|
|
671
682
|
api_consumer_count INTEGER NOT NULL DEFAULT 0,
|
|
672
683
|
last_error TEXT,
|
|
@@ -707,8 +718,11 @@ CREATE INDEX IF NOT EXISTS idx_org_repositories_org ON org_repositories(org);
|
|
|
707
718
|
CREATE INDEX IF NOT EXISTS idx_org_repo_state_org ON org_repo_state(org);
|
|
708
719
|
CREATE INDEX IF NOT EXISTS idx_org_edges_source ON org_cross_repo_edges(org, source_repo);
|
|
709
720
|
CREATE INDEX IF NOT EXISTS idx_org_edges_target ON org_cross_repo_edges(org, target_repo);
|
|
721
|
+
CREATE INDEX IF NOT EXISTS idx_org_edges_layer ON org_cross_repo_edges(org, layer, confidence);
|
|
722
|
+
CREATE INDEX IF NOT EXISTS idx_org_edges_repo_pair ON org_cross_repo_edges(org, layer, source_repo, target_repo, relationship);
|
|
710
723
|
CREATE INDEX IF NOT EXISTS idx_org_consumers_provider ON org_api_consumers(org, provider_repo);
|
|
711
724
|
CREATE INDEX IF NOT EXISTS idx_org_consumers_consumer ON org_api_consumers(org, consumer_repo);
|
|
725
|
+
CREATE INDEX IF NOT EXISTS idx_org_consumers_contract ON org_api_consumers(org, contract);
|
|
712
726
|
CREATE INDEX IF NOT EXISTS idx_org_anomalies_org ON org_anomaly_events(org, severity);
|
|
713
727
|
CREATE INDEX IF NOT EXISTS idx_org_graph_state_status ON org_graph_state(org, last_status);
|
|
714
728
|
|
|
@@ -1783,6 +1797,41 @@ function initializeSchema(db) {
|
|
|
1783
1797
|
ensureColumn(db, "sync_state", "graphql_cursor_reason", "TEXT");
|
|
1784
1798
|
ensureColumn(db, "sync_state", "graphql_cursor_updated_at", "TEXT");
|
|
1785
1799
|
ensureColumn(db, "code_index_state", "last_indexed_commit", "TEXT");
|
|
1800
|
+
ensureColumn(db, "org_cross_repo_edges", "layer", "TEXT NOT NULL DEFAULT 'file'");
|
|
1801
|
+
ensureColumn(
|
|
1802
|
+
db,
|
|
1803
|
+
"org_cross_repo_edges",
|
|
1804
|
+
"match_reasons_json",
|
|
1805
|
+
"TEXT NOT NULL DEFAULT '[]'"
|
|
1806
|
+
);
|
|
1807
|
+
ensureColumn(db, "org_cross_repo_edges", "evidence_count", "INTEGER NOT NULL DEFAULT 0");
|
|
1808
|
+
ensureColumn(db, "org_cross_repo_edges", "is_weak", "INTEGER NOT NULL DEFAULT 0");
|
|
1809
|
+
ensureColumn(
|
|
1810
|
+
db,
|
|
1811
|
+
"org_api_consumers",
|
|
1812
|
+
"match_reasons_json",
|
|
1813
|
+
"TEXT NOT NULL DEFAULT '[]'"
|
|
1814
|
+
);
|
|
1815
|
+
ensureColumn(db, "org_api_consumers", "evidence_count", "INTEGER NOT NULL DEFAULT 0");
|
|
1816
|
+
ensureColumn(db, "org_api_consumers", "is_weak", "INTEGER NOT NULL DEFAULT 0");
|
|
1817
|
+
ensureColumn(db, "org_graph_state", "visible_edge_count", "INTEGER NOT NULL DEFAULT 0");
|
|
1818
|
+
ensureColumn(db, "org_graph_state", "weak_edge_count", "INTEGER NOT NULL DEFAULT 0");
|
|
1819
|
+
ensureColumn(
|
|
1820
|
+
db,
|
|
1821
|
+
"org_graph_state",
|
|
1822
|
+
"edge_confidence_json",
|
|
1823
|
+
`TEXT NOT NULL DEFAULT '{"strong":0,"moderate":0,"weak":0}'`
|
|
1824
|
+
);
|
|
1825
|
+
ensureColumn(db, "org_graph_state", "last_render_prep_ms", "INTEGER");
|
|
1826
|
+
db.exec(
|
|
1827
|
+
"CREATE INDEX IF NOT EXISTS idx_org_edges_layer ON org_cross_repo_edges(org, layer, confidence)"
|
|
1828
|
+
);
|
|
1829
|
+
db.exec(
|
|
1830
|
+
"CREATE INDEX IF NOT EXISTS idx_org_edges_repo_pair ON org_cross_repo_edges(org, layer, source_repo, target_repo, relationship)"
|
|
1831
|
+
);
|
|
1832
|
+
db.exec(
|
|
1833
|
+
"CREATE INDEX IF NOT EXISTS idx_org_consumers_contract ON org_api_consumers(org, contract)"
|
|
1834
|
+
);
|
|
1786
1835
|
}
|
|
1787
1836
|
function ensureColumn(db, tableName, columnName, definition) {
|
|
1788
1837
|
const columns = db.prepare(`PRAGMA table_info(${tableName})`).all();
|
|
@@ -8706,6 +8755,24 @@ function resolveOrgForTool(org, baseDir = defaultOrgBaseDir()) {
|
|
|
8706
8755
|
|
|
8707
8756
|
// src/org/database.ts
|
|
8708
8757
|
import fs10 from "fs";
|
|
8758
|
+
var DEFAULT_EDGE_DISTRIBUTION = {
|
|
8759
|
+
strong: 0,
|
|
8760
|
+
moderate: 0,
|
|
8761
|
+
weak: 0
|
|
8762
|
+
};
|
|
8763
|
+
function parseEdgeDistribution(value) {
|
|
8764
|
+
if (!value) return { ...DEFAULT_EDGE_DISTRIBUTION };
|
|
8765
|
+
try {
|
|
8766
|
+
const parsed = JSON.parse(value);
|
|
8767
|
+
return {
|
|
8768
|
+
strong: Number(parsed.strong ?? 0),
|
|
8769
|
+
moderate: Number(parsed.moderate ?? 0),
|
|
8770
|
+
weak: Number(parsed.weak ?? 0)
|
|
8771
|
+
};
|
|
8772
|
+
} catch {
|
|
8773
|
+
return { ...DEFAULT_EDGE_DISTRIBUTION };
|
|
8774
|
+
}
|
|
8775
|
+
}
|
|
8709
8776
|
function openOrgDatabase(org, baseDir) {
|
|
8710
8777
|
const root = orgRoot(org, baseDir);
|
|
8711
8778
|
const db = openAnchorDatabase(root, orgDatabasePath(org, baseDir));
|
|
@@ -8835,8 +8902,9 @@ function recordOrgGraphState(db, input) {
|
|
|
8835
8902
|
db.prepare(
|
|
8836
8903
|
`INSERT INTO org_graph_state
|
|
8837
8904
|
(org, last_built_at, last_status, last_duration_ms, edge_count, api_contract_count,
|
|
8838
|
-
api_consumer_count,
|
|
8839
|
-
|
|
8905
|
+
api_consumer_count, visible_edge_count, weak_edge_count, edge_confidence_json,
|
|
8906
|
+
last_render_prep_ms, last_error, updated_at)
|
|
8907
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
8840
8908
|
ON CONFLICT(org) DO UPDATE SET
|
|
8841
8909
|
last_built_at = COALESCE(excluded.last_built_at, org_graph_state.last_built_at),
|
|
8842
8910
|
last_status = excluded.last_status,
|
|
@@ -8844,6 +8912,10 @@ function recordOrgGraphState(db, input) {
|
|
|
8844
8912
|
edge_count = excluded.edge_count,
|
|
8845
8913
|
api_contract_count = excluded.api_contract_count,
|
|
8846
8914
|
api_consumer_count = excluded.api_consumer_count,
|
|
8915
|
+
visible_edge_count = excluded.visible_edge_count,
|
|
8916
|
+
weak_edge_count = excluded.weak_edge_count,
|
|
8917
|
+
edge_confidence_json = excluded.edge_confidence_json,
|
|
8918
|
+
last_render_prep_ms = excluded.last_render_prep_ms,
|
|
8847
8919
|
last_error = excluded.last_error,
|
|
8848
8920
|
updated_at = excluded.updated_at`
|
|
8849
8921
|
).run(
|
|
@@ -8854,6 +8926,10 @@ function recordOrgGraphState(db, input) {
|
|
|
8854
8926
|
input.edgeCount ?? 0,
|
|
8855
8927
|
input.apiContractCount ?? 0,
|
|
8856
8928
|
input.apiConsumerCount ?? 0,
|
|
8929
|
+
input.visibleEdgeCount ?? input.edgeCount ?? 0,
|
|
8930
|
+
input.weakEdgeCount ?? 0,
|
|
8931
|
+
JSON.stringify(input.edgeConfidenceDistribution ?? DEFAULT_EDGE_DISTRIBUTION),
|
|
8932
|
+
input.lastRenderPrepMs ?? null,
|
|
8857
8933
|
input.error ?? null,
|
|
8858
8934
|
now
|
|
8859
8935
|
);
|
|
@@ -8868,6 +8944,10 @@ function getOrgGraphState(db, org) {
|
|
|
8868
8944
|
lastStatus: row.last_status ?? void 0,
|
|
8869
8945
|
lastDurationMs: row.last_duration_ms ?? void 0,
|
|
8870
8946
|
edgeCount: row.edge_count ?? void 0,
|
|
8947
|
+
visibleEdgeCount: row.visible_edge_count ?? void 0,
|
|
8948
|
+
weakEdgeCount: row.weak_edge_count ?? void 0,
|
|
8949
|
+
edgeConfidenceDistribution: parseEdgeDistribution(row.edge_confidence_json),
|
|
8950
|
+
lastRenderPrepMs: row.last_render_prep_ms ?? void 0,
|
|
8871
8951
|
apiContractCount: row.api_contract_count ?? void 0,
|
|
8872
8952
|
apiConsumerCount: row.api_consumer_count ?? void 0,
|
|
8873
8953
|
lastError: row.last_error ?? void 0
|
|
@@ -8880,7 +8960,19 @@ function count(db, table, where = "", params = []) {
|
|
|
8880
8960
|
function getOrgGraphCounts(db, org) {
|
|
8881
8961
|
initializeSchema(db);
|
|
8882
8962
|
return {
|
|
8883
|
-
edges: count(db, "org_cross_repo_edges", "WHERE org = ?", [org]),
|
|
8963
|
+
edges: count(db, "org_cross_repo_edges", "WHERE org = ? AND layer = 'repo'", [org]),
|
|
8964
|
+
visibleEdges: count(
|
|
8965
|
+
db,
|
|
8966
|
+
"org_cross_repo_edges",
|
|
8967
|
+
"WHERE org = ? AND layer = 'repo' AND is_weak = 0",
|
|
8968
|
+
[org]
|
|
8969
|
+
),
|
|
8970
|
+
weakEdges: count(
|
|
8971
|
+
db,
|
|
8972
|
+
"org_cross_repo_edges",
|
|
8973
|
+
"WHERE org = ? AND layer = 'repo' AND is_weak = 1",
|
|
8974
|
+
[org]
|
|
8975
|
+
),
|
|
8884
8976
|
apiContracts: count(db, "org_api_contracts", "WHERE org = ?", [org]),
|
|
8885
8977
|
apiConsumers: count(db, "org_api_consumers", "WHERE org = ?", [org])
|
|
8886
8978
|
};
|
|
@@ -8907,11 +8999,22 @@ function getOrgStatus(db, config, baseDir, options = {}) {
|
|
|
8907
8999
|
const codeFileCount = count(db, "code_files");
|
|
8908
9000
|
const codeChunkCount = count(db, "code_chunks");
|
|
8909
9001
|
const wisdomUnitCount = count(db, "wisdom_units");
|
|
8910
|
-
const crossRepoEdgeCount = count(
|
|
9002
|
+
const crossRepoEdgeCount = count(
|
|
9003
|
+
db,
|
|
9004
|
+
"org_cross_repo_edges",
|
|
9005
|
+
"WHERE org = ? AND layer = 'repo' AND is_weak = 0",
|
|
9006
|
+
[config.org]
|
|
9007
|
+
);
|
|
9008
|
+
const graphWeakEdgeCount = count(
|
|
9009
|
+
db,
|
|
9010
|
+
"org_cross_repo_edges",
|
|
9011
|
+
"WHERE org = ? AND layer = 'repo' AND is_weak = 1",
|
|
9012
|
+
[config.org]
|
|
9013
|
+
);
|
|
8911
9014
|
const apiContractCount = count(db, "org_api_contracts", "WHERE org = ?", [config.org]);
|
|
8912
9015
|
const apiConsumerCount = count(db, "org_api_consumers", "WHERE org = ?", [config.org]);
|
|
8913
9016
|
const anomalyCount = count(db, "org_anomaly_events", "WHERE org = ?", [config.org]);
|
|
8914
|
-
const graphState = db
|
|
9017
|
+
const graphState = getOrgGraphState(db, config.org);
|
|
8915
9018
|
let score = 0;
|
|
8916
9019
|
const reasons = [];
|
|
8917
9020
|
if (enabledRepos.length > 0) {
|
|
@@ -8955,10 +9058,14 @@ function getOrgStatus(db, config, baseDir, options = {}) {
|
|
|
8955
9058
|
apiContractCount,
|
|
8956
9059
|
apiConsumerCount,
|
|
8957
9060
|
anomalyCount,
|
|
8958
|
-
graphLastBuiltAt: graphState?.
|
|
8959
|
-
graphLastStatus: graphState?.
|
|
8960
|
-
graphLastDurationMs: graphState?.
|
|
8961
|
-
graphLastError: graphState?.
|
|
9061
|
+
graphLastBuiltAt: graphState?.lastBuiltAt,
|
|
9062
|
+
graphLastStatus: graphState?.lastStatus,
|
|
9063
|
+
graphLastDurationMs: graphState?.lastDurationMs,
|
|
9064
|
+
graphLastError: graphState?.lastError,
|
|
9065
|
+
graphVisibleEdgeCount: graphState?.visibleEdgeCount ?? crossRepoEdgeCount,
|
|
9066
|
+
graphWeakEdgeCount: graphState?.weakEdgeCount ?? graphWeakEdgeCount,
|
|
9067
|
+
graphRenderPrepMs: graphState?.lastRenderPrepMs,
|
|
9068
|
+
graphEdgeConfidenceDistribution: graphState?.edgeConfidenceDistribution ?? { ...DEFAULT_EDGE_DISTRIBUTION },
|
|
8962
9069
|
coverageScore: score,
|
|
8963
9070
|
coverageGrade: grade(score),
|
|
8964
9071
|
coverageReasons: reasons,
|
|
@@ -9262,6 +9369,34 @@ function orgCloneStateFromResult(org, repo, result) {
|
|
|
9262
9369
|
import crypto9 from "crypto";
|
|
9263
9370
|
import fs13 from "fs";
|
|
9264
9371
|
import path23 from "path";
|
|
9372
|
+
var MIN_FILE_EDGE_CONFIDENCE = 0.62;
|
|
9373
|
+
var MIN_REPO_EDGE_CONFIDENCE = 0.7;
|
|
9374
|
+
var MIN_VISIBLE_EVIDENCE = 2;
|
|
9375
|
+
var MIN_API_CONSUMER_CONFIDENCE = 0.68;
|
|
9376
|
+
var MAX_EDGE_EVIDENCE = 8;
|
|
9377
|
+
var MAX_EDGE_REASONS = 6;
|
|
9378
|
+
var MAX_CONTRACTS_PER_CHUNK = 24;
|
|
9379
|
+
var CONTRACT_IGNORE = /* @__PURE__ */ new Set([
|
|
9380
|
+
"api",
|
|
9381
|
+
"v1",
|
|
9382
|
+
"v2",
|
|
9383
|
+
"v3",
|
|
9384
|
+
"graphql",
|
|
9385
|
+
"query",
|
|
9386
|
+
"mutation",
|
|
9387
|
+
"subscription",
|
|
9388
|
+
"schema",
|
|
9389
|
+
"route",
|
|
9390
|
+
"routes",
|
|
9391
|
+
"controller",
|
|
9392
|
+
"client",
|
|
9393
|
+
"request"
|
|
9394
|
+
]);
|
|
9395
|
+
var DEFAULT_EDGE_DISTRIBUTION2 = {
|
|
9396
|
+
strong: 0,
|
|
9397
|
+
moderate: 0,
|
|
9398
|
+
weak: 0
|
|
9399
|
+
};
|
|
9265
9400
|
function stableId(parts) {
|
|
9266
9401
|
return crypto9.createHash("sha256").update(parts.join("\0")).digest("hex").slice(0, 32);
|
|
9267
9402
|
}
|
|
@@ -9274,6 +9409,9 @@ function fileEvidence(repo, filePath, note) {
|
|
|
9274
9409
|
note
|
|
9275
9410
|
};
|
|
9276
9411
|
}
|
|
9412
|
+
function evidenceJson(evidence) {
|
|
9413
|
+
return JSON.stringify(evidence);
|
|
9414
|
+
}
|
|
9277
9415
|
function readPackageManifest(repoPath) {
|
|
9278
9416
|
const packagePath = path23.join(repoPath, "package.json");
|
|
9279
9417
|
if (!fs13.existsSync(packagePath)) return void 0;
|
|
@@ -9319,19 +9457,53 @@ function parseJsonArray10(value) {
|
|
|
9319
9457
|
return [];
|
|
9320
9458
|
}
|
|
9321
9459
|
}
|
|
9322
|
-
function
|
|
9323
|
-
|
|
9324
|
-
|
|
9325
|
-
|
|
9326
|
-
|
|
9327
|
-
|
|
9328
|
-
|
|
9329
|
-
|
|
9330
|
-
|
|
9331
|
-
|
|
9332
|
-
if (operation) contracts.push(operation);
|
|
9460
|
+
function normalizeToken(value) {
|
|
9461
|
+
return value.toLowerCase().replace(/[{}()[\],:"'`]/g, "").replace(/\/+/g, "/").replace(/\/$/g, "").replace(/^-+/g, "").trim();
|
|
9462
|
+
}
|
|
9463
|
+
function splitTokenSymbols(value) {
|
|
9464
|
+
return value.split(/[^A-Za-z0-9_/-]+/).map((item) => normalizeToken(item)).filter((item) => item.length >= 3 && !CONTRACT_IGNORE.has(item)).slice(0, 12);
|
|
9465
|
+
}
|
|
9466
|
+
function normalizeContract(contract, kind) {
|
|
9467
|
+
if (kind === "route") {
|
|
9468
|
+
const normalized = normalizeToken(contract);
|
|
9469
|
+
return normalized.startsWith("/") ? normalized : `/${normalized}`;
|
|
9333
9470
|
}
|
|
9334
|
-
return
|
|
9471
|
+
return normalizeToken(contract);
|
|
9472
|
+
}
|
|
9473
|
+
function isGenericRoute(route) {
|
|
9474
|
+
const normalized = normalizeToken(route);
|
|
9475
|
+
if (!normalized.startsWith("/")) return true;
|
|
9476
|
+
const segments = normalized.split("/").filter((segment) => segment && !segment.startsWith(":") && segment !== "*");
|
|
9477
|
+
if (segments.length === 0) return true;
|
|
9478
|
+
const informative = segments.filter((segment) => !CONTRACT_IGNORE.has(segment));
|
|
9479
|
+
return informative.length < 1;
|
|
9480
|
+
}
|
|
9481
|
+
function extractContracts(text) {
|
|
9482
|
+
const tokens = [];
|
|
9483
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9484
|
+
const pushToken = (rawValue, kind) => {
|
|
9485
|
+
const sanitized = sanitizeHistoricalText(rawValue).slice(0, 180);
|
|
9486
|
+
if (!sanitized) return;
|
|
9487
|
+
const normalized = normalizeContract(sanitized, kind);
|
|
9488
|
+
if (!normalized || CONTRACT_IGNORE.has(normalized)) return;
|
|
9489
|
+
if (kind === "route" && isGenericRoute(normalized)) return;
|
|
9490
|
+
const key = `${kind}\0${normalized}`;
|
|
9491
|
+
if (seen.has(key)) return;
|
|
9492
|
+
seen.add(key);
|
|
9493
|
+
tokens.push({
|
|
9494
|
+
raw: sanitized,
|
|
9495
|
+
normalized,
|
|
9496
|
+
kind,
|
|
9497
|
+
symbols: splitTokenSymbols(sanitized)
|
|
9498
|
+
});
|
|
9499
|
+
};
|
|
9500
|
+
const routeMatches = text.matchAll(/["'`]((?:\/api)?\/[A-Za-z0-9_./:{}-]{3,})["'`]/g);
|
|
9501
|
+
for (const match of routeMatches) pushToken(match[1] ?? "", "route");
|
|
9502
|
+
const gqlMatches = text.matchAll(/\b(query|mutation|subscription)\s+([A-Za-z][A-Za-z0-9_]{2,})/g);
|
|
9503
|
+
for (const match of gqlMatches) pushToken(match[2] ?? "", "graphql");
|
|
9504
|
+
const schemaMatches = text.matchAll(/\b(?:type|interface|enum|input)\s+([A-Z][A-Za-z0-9_]{2,})\b/g);
|
|
9505
|
+
for (const match of schemaMatches) pushToken(match[1] ?? "", "schema");
|
|
9506
|
+
return tokens.slice(0, MAX_CONTRACTS_PER_CHUNK);
|
|
9335
9507
|
}
|
|
9336
9508
|
function isApiProviderPath(filePath) {
|
|
9337
9509
|
const normalized = filePath.toLowerCase();
|
|
@@ -9342,28 +9514,216 @@ function isApiProviderPath(filePath) {
|
|
|
9342
9514
|
function isApiConsumerText(text) {
|
|
9343
9515
|
return /\b(fetch|axios|ky|graphql|gql|client|sdk|request)\b/i.test(text);
|
|
9344
9516
|
}
|
|
9345
|
-
function evidenceJson(evidence) {
|
|
9346
|
-
return JSON.stringify(evidence);
|
|
9347
|
-
}
|
|
9348
9517
|
function shouldEmitProgress3(current, total, interval = 100) {
|
|
9349
9518
|
return current === 1 || current === total || current % interval === 0;
|
|
9350
9519
|
}
|
|
9351
9520
|
function resolveOptions(baseDirOrOptions) {
|
|
9352
9521
|
return typeof baseDirOrOptions === "string" ? { baseDir: baseDirOrOptions } : baseDirOrOptions ?? {};
|
|
9353
9522
|
}
|
|
9523
|
+
function clampConfidence(value) {
|
|
9524
|
+
if (Number.isNaN(value)) return 0;
|
|
9525
|
+
return Math.max(0, Math.min(0.99, Number(value.toFixed(3))));
|
|
9526
|
+
}
|
|
9527
|
+
function confidenceBucket(confidence) {
|
|
9528
|
+
if (confidence >= 0.82) return "strong";
|
|
9529
|
+
if (confidence >= 0.68) return "moderate";
|
|
9530
|
+
return "weak";
|
|
9531
|
+
}
|
|
9532
|
+
function uniqueEvidenceRefs(evidence) {
|
|
9533
|
+
const map = /* @__PURE__ */ new Map();
|
|
9534
|
+
for (const item of evidence) {
|
|
9535
|
+
const key = `${item.prNumber}|${item.prUrl}|${item.sourceType}|${item.filePath ?? ""}|${item.note ?? ""}`;
|
|
9536
|
+
if (!map.has(key)) map.set(key, item);
|
|
9537
|
+
}
|
|
9538
|
+
return [...map.values()].slice(0, MAX_EDGE_EVIDENCE);
|
|
9539
|
+
}
|
|
9540
|
+
function mergeReasons(a, b) {
|
|
9541
|
+
return uniqueStrings([...a, ...b]).slice(0, MAX_EDGE_REASONS);
|
|
9542
|
+
}
|
|
9543
|
+
function updateWeakFlag(edge, minConfidence2, minEvidence) {
|
|
9544
|
+
edge.evidence = uniqueEvidenceRefs(edge.evidence);
|
|
9545
|
+
edge.evidenceCount = edge.evidence.length;
|
|
9546
|
+
edge.confidence = clampConfidence(edge.confidence);
|
|
9547
|
+
edge.weak = edge.confidence < minConfidence2 || edge.evidenceCount < minEvidence;
|
|
9548
|
+
}
|
|
9549
|
+
function fileEdgeKey(edge) {
|
|
9550
|
+
return [
|
|
9551
|
+
edge.layer,
|
|
9552
|
+
edge.sourceRepo,
|
|
9553
|
+
edge.sourcePath,
|
|
9554
|
+
edge.targetRepo,
|
|
9555
|
+
edge.targetPath ?? "",
|
|
9556
|
+
edge.relationship
|
|
9557
|
+
].join("\0");
|
|
9558
|
+
}
|
|
9559
|
+
function repoEdgeKey(edge) {
|
|
9560
|
+
return [edge.layer, edge.sourceRepo, edge.targetRepo, edge.relationship].join("\0");
|
|
9561
|
+
}
|
|
9562
|
+
function upsertEdge(map, edge, minConfidence2, minEvidence) {
|
|
9563
|
+
const layer = edge.layer ?? "file";
|
|
9564
|
+
if (edge.sourceRepo === edge.targetRepo) return { inserted: false, updated: false };
|
|
9565
|
+
const key = layer === "repo" ? repoEdgeKey({ ...edge, layer }) : fileEdgeKey({ ...edge, layer });
|
|
9566
|
+
const existing = map.get(key);
|
|
9567
|
+
if (!existing) {
|
|
9568
|
+
const created = {
|
|
9569
|
+
...edge,
|
|
9570
|
+
layer,
|
|
9571
|
+
evidence: uniqueEvidenceRefs(edge.evidence),
|
|
9572
|
+
matchReasons: mergeReasons([], edge.matchReasons),
|
|
9573
|
+
evidenceCount: 0,
|
|
9574
|
+
weak: false
|
|
9575
|
+
};
|
|
9576
|
+
updateWeakFlag(created, minConfidence2, minEvidence);
|
|
9577
|
+
map.set(key, created);
|
|
9578
|
+
return { inserted: true, updated: false };
|
|
9579
|
+
}
|
|
9580
|
+
const merged = {
|
|
9581
|
+
...existing,
|
|
9582
|
+
sourcePath: existing.layer === "repo" ? "*" : existing.sourcePath,
|
|
9583
|
+
targetPath: existing.layer === "repo" ? void 0 : existing.targetPath ?? edge.targetPath,
|
|
9584
|
+
evidence: uniqueEvidenceRefs([...existing.evidence, ...edge.evidence]),
|
|
9585
|
+
matchReasons: mergeReasons(existing.matchReasons, edge.matchReasons),
|
|
9586
|
+
confidence: Math.max(existing.confidence, edge.confidence),
|
|
9587
|
+
evidenceCount: 0,
|
|
9588
|
+
weak: false
|
|
9589
|
+
};
|
|
9590
|
+
updateWeakFlag(merged, minConfidence2, minEvidence);
|
|
9591
|
+
map.set(key, merged);
|
|
9592
|
+
return { inserted: false, updated: true };
|
|
9593
|
+
}
|
|
9594
|
+
function scorePackageDependency(dependency) {
|
|
9595
|
+
const normalized = sanitizeHistoricalText(dependency);
|
|
9596
|
+
const reasons = ["exact_package_dependency"];
|
|
9597
|
+
const confidence = normalized.startsWith("@") ? 0.93 : 0.9;
|
|
9598
|
+
return { confidence, reasons };
|
|
9599
|
+
}
|
|
9600
|
+
function scoreImportEdge(input) {
|
|
9601
|
+
let score = 0.58;
|
|
9602
|
+
const reasons = ["cross_repo_import"];
|
|
9603
|
+
if (input.specifier.includes("/")) {
|
|
9604
|
+
score += 0.12;
|
|
9605
|
+
reasons.push("qualified_specifier");
|
|
9606
|
+
}
|
|
9607
|
+
if (input.importedPath) {
|
|
9608
|
+
score += 0.16;
|
|
9609
|
+
reasons.push("resolved_import_path");
|
|
9610
|
+
}
|
|
9611
|
+
if (input.importedSymbols.length > 0) {
|
|
9612
|
+
score += 0.11;
|
|
9613
|
+
reasons.push("explicit_import_symbols");
|
|
9614
|
+
}
|
|
9615
|
+
return { confidence: clampConfidence(score), reasons };
|
|
9616
|
+
}
|
|
9617
|
+
function scoreContract(input) {
|
|
9618
|
+
let score = 0.66;
|
|
9619
|
+
if (input.token.kind === "route") score += 0.08;
|
|
9620
|
+
if (input.token.kind === "graphql") score += 0.06;
|
|
9621
|
+
if (input.token.kind === "schema") score += 0.03;
|
|
9622
|
+
if (/\b(route|controller|api|schema|client)\b/i.test(input.filePath)) score += 0.05;
|
|
9623
|
+
if (input.token.symbols.length > 0) score += 0.04;
|
|
9624
|
+
return clampConfidence(score);
|
|
9625
|
+
}
|
|
9626
|
+
function overlapScore(a, b) {
|
|
9627
|
+
if (a.length === 0 || b.length === 0) return 0;
|
|
9628
|
+
const set = new Set(a);
|
|
9629
|
+
let overlaps = 0;
|
|
9630
|
+
for (const value of b) {
|
|
9631
|
+
if (set.has(value)) overlaps += 1;
|
|
9632
|
+
}
|
|
9633
|
+
return overlaps / Math.max(1, Math.min(a.length, b.length));
|
|
9634
|
+
}
|
|
9635
|
+
function scoreConsumerMatch(input) {
|
|
9636
|
+
let score = 0.58;
|
|
9637
|
+
const reasons = ["matched_contract_token"];
|
|
9638
|
+
if (input.consumerToken.kind === input.contract.kind) {
|
|
9639
|
+
score += 0.12;
|
|
9640
|
+
reasons.push("matching_contract_kind");
|
|
9641
|
+
}
|
|
9642
|
+
const symbolOverlap = overlapScore(
|
|
9643
|
+
uniqueStrings([...input.contract.symbols, ...splitTokenSymbols(input.contract.contract)]),
|
|
9644
|
+
uniqueStrings([...input.chunkSymbols, ...input.consumerToken.symbols])
|
|
9645
|
+
);
|
|
9646
|
+
if (symbolOverlap > 0) {
|
|
9647
|
+
score += Math.min(0.2, symbolOverlap * 0.22);
|
|
9648
|
+
reasons.push("symbol_overlap");
|
|
9649
|
+
}
|
|
9650
|
+
if (input.contract.kind === "route" && input.consumerToken.raw.includes("/")) {
|
|
9651
|
+
score += 0.08;
|
|
9652
|
+
reasons.push("route_literal_match");
|
|
9653
|
+
}
|
|
9654
|
+
return { confidence: clampConfidence(score), reasons };
|
|
9655
|
+
}
|
|
9656
|
+
function aggregateRepoEdges(fileEdges) {
|
|
9657
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
9658
|
+
for (const edge of fileEdges) {
|
|
9659
|
+
const key = repoEdgeKey({
|
|
9660
|
+
layer: "repo",
|
|
9661
|
+
sourceRepo: edge.sourceRepo,
|
|
9662
|
+
targetRepo: edge.targetRepo,
|
|
9663
|
+
relationship: edge.relationship
|
|
9664
|
+
});
|
|
9665
|
+
const bucket = grouped.get(key) ?? [];
|
|
9666
|
+
bucket.push(edge);
|
|
9667
|
+
grouped.set(key, bucket);
|
|
9668
|
+
}
|
|
9669
|
+
const repoEdges = [];
|
|
9670
|
+
for (const [key, group] of grouped.entries()) {
|
|
9671
|
+
const [layerValue = "repo", sourceRepo = "", targetRepo = ""] = key.split("\0");
|
|
9672
|
+
const relationship = group[0]?.relationship ?? "imports";
|
|
9673
|
+
const confidences = group.map((edge) => edge.confidence);
|
|
9674
|
+
const maxConfidence = Math.max(...confidences);
|
|
9675
|
+
const avgConfidence = confidences.reduce((sum, value) => sum + value, 0) / confidences.length;
|
|
9676
|
+
const repetitionBoost = Math.min(0.18, Math.log2(group.length + 1) * 0.06);
|
|
9677
|
+
const confidence = clampConfidence(maxConfidence * 0.6 + avgConfidence * 0.25 + repetitionBoost);
|
|
9678
|
+
const evidence = uniqueEvidenceRefs(group.flatMap((edge) => edge.evidence));
|
|
9679
|
+
const matchReasons6 = mergeReasons([], group.flatMap((edge) => edge.matchReasons));
|
|
9680
|
+
const repoEdge = {
|
|
9681
|
+
org: group[0]?.org ?? "",
|
|
9682
|
+
sourceRepo,
|
|
9683
|
+
sourcePath: "*",
|
|
9684
|
+
targetRepo,
|
|
9685
|
+
targetPath: void 0,
|
|
9686
|
+
layer: layerValue,
|
|
9687
|
+
relationship,
|
|
9688
|
+
evidence,
|
|
9689
|
+
matchReasons: matchReasons6,
|
|
9690
|
+
evidenceCount: 0,
|
|
9691
|
+
weak: false,
|
|
9692
|
+
confidence
|
|
9693
|
+
};
|
|
9694
|
+
updateWeakFlag(repoEdge, MIN_REPO_EDGE_CONFIDENCE, MIN_VISIBLE_EVIDENCE);
|
|
9695
|
+
repoEdges.push(repoEdge);
|
|
9696
|
+
}
|
|
9697
|
+
return repoEdges.sort((a, b) => b.confidence - a.confidence);
|
|
9698
|
+
}
|
|
9699
|
+
function buildQuality(repoEdges, hiddenRepoEdges) {
|
|
9700
|
+
const distribution = { ...DEFAULT_EDGE_DISTRIBUTION2 };
|
|
9701
|
+
for (const edge of repoEdges) {
|
|
9702
|
+
distribution[confidenceBucket(edge.confidence)] += 1;
|
|
9703
|
+
}
|
|
9704
|
+
return {
|
|
9705
|
+
edgeConfidenceDistribution: distribution,
|
|
9706
|
+
weakEdgesFiltered: hiddenRepoEdges.length,
|
|
9707
|
+
minVisibleConfidence: MIN_REPO_EDGE_CONFIDENCE,
|
|
9708
|
+
minVisibleEvidence: MIN_VISIBLE_EVIDENCE
|
|
9709
|
+
};
|
|
9710
|
+
}
|
|
9711
|
+
function isVisibleRepoEdge(edge) {
|
|
9712
|
+
return !edge.weak && edge.confidence >= MIN_REPO_EDGE_CONFIDENCE && edge.evidenceCount >= MIN_VISIBLE_EVIDENCE;
|
|
9713
|
+
}
|
|
9354
9714
|
function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
9355
9715
|
initializeSchema(db);
|
|
9356
9716
|
const options = resolveOptions(baseDirOrOptions);
|
|
9357
9717
|
const startedAt = Date.now();
|
|
9358
9718
|
try {
|
|
9719
|
+
const enabledRepos = config.repos.filter((repo) => repo.enabled);
|
|
9720
|
+
const repoByName = new Map(enabledRepos.map((repo) => [repo.fullName, repo]));
|
|
9359
9721
|
options.onProgress?.({
|
|
9360
9722
|
stage: "loading_package_manifests",
|
|
9361
9723
|
org: config.org,
|
|
9362
|
-
totalRepos:
|
|
9724
|
+
totalRepos: enabledRepos.length
|
|
9363
9725
|
});
|
|
9364
9726
|
const packageNames = repoPackageNames(config, options.baseDir);
|
|
9365
|
-
const enabledRepos = config.repos.filter((repo) => repo.enabled);
|
|
9366
|
-
const repoByName = new Map(enabledRepos.map((repo) => [repo.fullName, repo]));
|
|
9367
9727
|
const packageToRepo = /* @__PURE__ */ new Map();
|
|
9368
9728
|
for (const [repo, names] of packageNames.entries()) {
|
|
9369
9729
|
for (const name of names) packageToRepo.set(name, repo);
|
|
@@ -9374,31 +9734,22 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9374
9734
|
repos: enabledRepos.length,
|
|
9375
9735
|
packageNames: packageToRepo.size
|
|
9376
9736
|
});
|
|
9377
|
-
const
|
|
9378
|
-
const
|
|
9379
|
-
|
|
9380
|
-
if (edge.sourceRepo === edge.targetRepo) return;
|
|
9381
|
-
const key = [
|
|
9382
|
-
edge.sourceRepo,
|
|
9383
|
-
edge.sourcePath,
|
|
9384
|
-
edge.targetRepo,
|
|
9385
|
-
edge.targetPath ?? "",
|
|
9386
|
-
edge.relationship
|
|
9387
|
-
].join("\0");
|
|
9388
|
-
if (edgeKeys.has(key)) return;
|
|
9389
|
-
edgeKeys.add(key);
|
|
9390
|
-
edges.push(edge);
|
|
9737
|
+
const fileEdgeMap = /* @__PURE__ */ new Map();
|
|
9738
|
+
const addFileEdge = (edge) => {
|
|
9739
|
+
upsertEdge(fileEdgeMap, { ...edge, layer: "file" }, MIN_FILE_EDGE_CONFIDENCE, 1);
|
|
9391
9740
|
};
|
|
9392
9741
|
enabledRepos.forEach((repo, index) => {
|
|
9393
9742
|
const manifest = readPackageManifest(orgRepoLocalPath(config.org, repo, options.baseDir));
|
|
9394
9743
|
for (const dependency of dependenciesFor(manifest)) {
|
|
9395
9744
|
const targetRepo = packageToRepo.get(dependency);
|
|
9396
9745
|
if (!targetRepo || targetRepo === repo.fullName) continue;
|
|
9397
|
-
|
|
9746
|
+
const score = scorePackageDependency(dependency);
|
|
9747
|
+
addFileEdge({
|
|
9398
9748
|
org: config.org,
|
|
9399
9749
|
sourceRepo: repo.fullName,
|
|
9400
9750
|
sourcePath: "package.json",
|
|
9401
9751
|
targetRepo,
|
|
9752
|
+
targetPath: "package.json",
|
|
9402
9753
|
relationship: "depends_on_package",
|
|
9403
9754
|
evidence: [
|
|
9404
9755
|
fileEvidence(
|
|
@@ -9407,7 +9758,8 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9407
9758
|
`depends on ${sanitizeHistoricalText(dependency)}`
|
|
9408
9759
|
)
|
|
9409
9760
|
],
|
|
9410
|
-
|
|
9761
|
+
matchReasons: score.reasons,
|
|
9762
|
+
confidence: score.confidence
|
|
9411
9763
|
});
|
|
9412
9764
|
}
|
|
9413
9765
|
options.onProgress?.({
|
|
@@ -9416,7 +9768,7 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9416
9768
|
current: index + 1,
|
|
9417
9769
|
total: enabledRepos.length,
|
|
9418
9770
|
repo: repo.fullName,
|
|
9419
|
-
edges:
|
|
9771
|
+
edges: fileEdgeMap.size
|
|
9420
9772
|
});
|
|
9421
9773
|
});
|
|
9422
9774
|
options.onProgress?.({ stage: "loading_imports", org: config.org });
|
|
@@ -9431,7 +9783,13 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9431
9783
|
const rootSpecifier = packageRootForSpecifier(item.specifier);
|
|
9432
9784
|
const targetRepo = packageToRepo.get(rootSpecifier) ?? packageToRepo.get(item.specifier);
|
|
9433
9785
|
if (targetRepo && targetRepo !== item.repo) {
|
|
9434
|
-
|
|
9786
|
+
const importedSymbols = parseJsonArray10(item.imported_symbols_json);
|
|
9787
|
+
const score = scoreImportEdge({
|
|
9788
|
+
specifier: item.specifier,
|
|
9789
|
+
importedPath: item.imported_path,
|
|
9790
|
+
importedSymbols
|
|
9791
|
+
});
|
|
9792
|
+
addFileEdge({
|
|
9435
9793
|
org: config.org,
|
|
9436
9794
|
sourceRepo: item.repo,
|
|
9437
9795
|
sourcePath: item.source_path,
|
|
@@ -9445,7 +9803,8 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9445
9803
|
`imports ${sanitizeHistoricalText(rootSpecifier || item.specifier)}`
|
|
9446
9804
|
)
|
|
9447
9805
|
],
|
|
9448
|
-
|
|
9806
|
+
matchReasons: score.reasons,
|
|
9807
|
+
confidence: score.confidence
|
|
9449
9808
|
});
|
|
9450
9809
|
}
|
|
9451
9810
|
if (shouldEmitProgress3(index + 1, imports.length)) {
|
|
@@ -9455,7 +9814,7 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9455
9814
|
current: index + 1,
|
|
9456
9815
|
total: imports.length,
|
|
9457
9816
|
sourcePath: item.source_path,
|
|
9458
|
-
edges:
|
|
9817
|
+
edges: fileEdgeMap.size
|
|
9459
9818
|
});
|
|
9460
9819
|
}
|
|
9461
9820
|
});
|
|
@@ -9469,25 +9828,27 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9469
9828
|
(chunk) => repoByName.has(chunk.repo) && isApiProviderPath(chunk.file_path)
|
|
9470
9829
|
);
|
|
9471
9830
|
const apiContracts = [];
|
|
9472
|
-
const
|
|
9831
|
+
const contractByKey = /* @__PURE__ */ new Map();
|
|
9473
9832
|
const contractsByToken = /* @__PURE__ */ new Map();
|
|
9474
9833
|
providerChunks.forEach((chunk, index) => {
|
|
9475
|
-
for (const
|
|
9476
|
-
const
|
|
9477
|
-
|
|
9478
|
-
|
|
9479
|
-
contractKeys.add(key);
|
|
9480
|
-
const apiContract = {
|
|
9834
|
+
for (const token of extractContracts(chunk.sanitized_text)) {
|
|
9835
|
+
const key = [chunk.repo, chunk.file_path, token.kind, token.normalized].join("\0");
|
|
9836
|
+
if (contractByKey.has(key)) continue;
|
|
9837
|
+
const contract = {
|
|
9481
9838
|
repo: chunk.repo,
|
|
9482
9839
|
filePath: chunk.file_path,
|
|
9483
|
-
contract:
|
|
9484
|
-
|
|
9485
|
-
|
|
9840
|
+
contract: token.raw,
|
|
9841
|
+
normalizedContract: token.normalized,
|
|
9842
|
+
kind: token.kind,
|
|
9843
|
+
symbols: token.symbols,
|
|
9844
|
+
evidence: [fileEvidence(chunk.repo, chunk.file_path, `defines ${token.raw}`)],
|
|
9845
|
+
confidence: scoreContract({ token, filePath: chunk.file_path })
|
|
9486
9846
|
};
|
|
9487
|
-
|
|
9488
|
-
|
|
9489
|
-
bucket.
|
|
9490
|
-
|
|
9847
|
+
contractByKey.set(key, contract);
|
|
9848
|
+
apiContracts.push(contract);
|
|
9849
|
+
const bucket = contractsByToken.get(contract.normalizedContract) ?? [];
|
|
9850
|
+
bucket.push(contract);
|
|
9851
|
+
contractsByToken.set(contract.normalizedContract, bucket);
|
|
9491
9852
|
}
|
|
9492
9853
|
if (shouldEmitProgress3(index + 1, providerChunks.length)) {
|
|
9493
9854
|
options.onProgress?.({
|
|
@@ -9500,28 +9861,39 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9500
9861
|
});
|
|
9501
9862
|
}
|
|
9502
9863
|
});
|
|
9503
|
-
const apiConsumers = [];
|
|
9504
|
-
const consumerKeys = /* @__PURE__ */ new Set();
|
|
9505
9864
|
const consumerChunks = chunks.filter(
|
|
9506
9865
|
(chunk) => repoByName.has(chunk.repo) && isApiConsumerText(chunk.sanitized_text)
|
|
9507
9866
|
);
|
|
9867
|
+
const apiConsumers = [];
|
|
9868
|
+
const consumerKeySet = /* @__PURE__ */ new Set();
|
|
9508
9869
|
consumerChunks.forEach((chunk, index) => {
|
|
9509
|
-
const
|
|
9510
|
-
|
|
9511
|
-
|
|
9512
|
-
|
|
9513
|
-
|
|
9870
|
+
const chunkTokens = extractContracts(chunk.sanitized_text);
|
|
9871
|
+
const chunkSymbols = parseJsonArray10(chunk.symbols_json);
|
|
9872
|
+
let matchesForChunk = 0;
|
|
9873
|
+
for (const consumerToken of chunkTokens) {
|
|
9874
|
+
const contracts = contractsByToken.get(consumerToken.normalized);
|
|
9875
|
+
if (!contracts?.length) continue;
|
|
9514
9876
|
for (const contract of contracts) {
|
|
9515
9877
|
if (chunk.repo === contract.repo) continue;
|
|
9878
|
+
const score = scoreConsumerMatch({
|
|
9879
|
+
consumerToken,
|
|
9880
|
+
contract,
|
|
9881
|
+
chunkSymbols
|
|
9882
|
+
});
|
|
9883
|
+
if (score.confidence < MIN_API_CONSUMER_CONFIDENCE) continue;
|
|
9516
9884
|
const consumerKey = [
|
|
9517
9885
|
contract.repo,
|
|
9518
9886
|
contract.filePath,
|
|
9519
9887
|
chunk.repo,
|
|
9520
9888
|
chunk.file_path,
|
|
9521
|
-
contract.
|
|
9889
|
+
contract.normalizedContract
|
|
9522
9890
|
].join("\0");
|
|
9523
|
-
if (
|
|
9524
|
-
|
|
9891
|
+
if (consumerKeySet.has(consumerKey)) continue;
|
|
9892
|
+
consumerKeySet.add(consumerKey);
|
|
9893
|
+
const evidence = uniqueEvidenceRefs([
|
|
9894
|
+
...contract.evidence,
|
|
9895
|
+
fileEvidence(chunk.repo, chunk.file_path, `consumes ${contract.contract}`)
|
|
9896
|
+
]);
|
|
9525
9897
|
const consumer = {
|
|
9526
9898
|
org: config.org,
|
|
9527
9899
|
providerRepo: contract.repo,
|
|
@@ -9529,23 +9901,24 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9529
9901
|
consumerRepo: chunk.repo,
|
|
9530
9902
|
consumerPath: chunk.file_path,
|
|
9531
9903
|
contract: contract.contract,
|
|
9532
|
-
evidence
|
|
9533
|
-
|
|
9534
|
-
|
|
9535
|
-
|
|
9536
|
-
confidence:
|
|
9904
|
+
evidence,
|
|
9905
|
+
matchReasons: mergeReasons([], score.reasons),
|
|
9906
|
+
evidenceCount: evidence.length,
|
|
9907
|
+
weak: score.confidence < MIN_API_CONSUMER_CONFIDENCE || evidence.length < MIN_VISIBLE_EVIDENCE,
|
|
9908
|
+
confidence: score.confidence
|
|
9537
9909
|
};
|
|
9538
|
-
chunkMatches += 1;
|
|
9539
9910
|
apiConsumers.push(consumer);
|
|
9540
|
-
|
|
9911
|
+
matchesForChunk += 1;
|
|
9912
|
+
addFileEdge({
|
|
9541
9913
|
org: config.org,
|
|
9542
9914
|
sourceRepo: chunk.repo,
|
|
9543
9915
|
sourcePath: chunk.file_path,
|
|
9544
9916
|
targetRepo: contract.repo,
|
|
9545
9917
|
targetPath: contract.filePath,
|
|
9546
9918
|
relationship: "api_consumer",
|
|
9547
|
-
evidence
|
|
9548
|
-
|
|
9919
|
+
evidence,
|
|
9920
|
+
matchReasons: score.reasons,
|
|
9921
|
+
confidence: score.confidence
|
|
9549
9922
|
});
|
|
9550
9923
|
}
|
|
9551
9924
|
}
|
|
@@ -9556,46 +9929,79 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9556
9929
|
current: index + 1,
|
|
9557
9930
|
total: consumerChunks.length,
|
|
9558
9931
|
filePath: chunk.file_path,
|
|
9559
|
-
matches:
|
|
9932
|
+
matches: matchesForChunk
|
|
9560
9933
|
});
|
|
9561
9934
|
}
|
|
9562
9935
|
});
|
|
9936
|
+
const allFileEdges = [...fileEdgeMap.values()].sort((a, b) => b.confidence - a.confidence);
|
|
9937
|
+
const repoEdges = aggregateRepoEdges(allFileEdges);
|
|
9938
|
+
const visibleRepoEdges = repoEdges.filter(isVisibleRepoEdge);
|
|
9939
|
+
const hiddenRepoEdges = repoEdges.filter((edge) => !isVisibleRepoEdge(edge));
|
|
9940
|
+
const hiddenFileEdges = allFileEdges.filter(
|
|
9941
|
+
(edge) => edge.confidence < MIN_FILE_EDGE_CONFIDENCE || edge.evidenceCount < 1
|
|
9942
|
+
);
|
|
9943
|
+
const visibleFileEdges = allFileEdges.filter((edge) => !hiddenFileEdges.includes(edge));
|
|
9944
|
+
const quality = buildQuality(visibleRepoEdges, hiddenRepoEdges);
|
|
9563
9945
|
options.onProgress?.({
|
|
9564
9946
|
stage: "writing_org_graph",
|
|
9565
9947
|
org: config.org,
|
|
9566
|
-
edges:
|
|
9948
|
+
edges: repoEdges.length,
|
|
9567
9949
|
apiContracts: apiContracts.length,
|
|
9568
9950
|
apiConsumers: apiConsumers.length
|
|
9569
9951
|
});
|
|
9570
9952
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
9953
|
+
const renderPrepStartedAt = Date.now();
|
|
9571
9954
|
const transaction = db.transaction(() => {
|
|
9572
9955
|
db.prepare("DELETE FROM org_cross_repo_edges WHERE org = ?").run(config.org);
|
|
9573
9956
|
db.prepare("DELETE FROM org_api_contracts WHERE org = ?").run(config.org);
|
|
9574
9957
|
db.prepare("DELETE FROM org_api_consumers WHERE org = ?").run(config.org);
|
|
9575
9958
|
const insertEdge = db.prepare(
|
|
9576
9959
|
`INSERT INTO org_cross_repo_edges
|
|
9577
|
-
(id, org, source_repo, source_path, target_repo, target_path,
|
|
9578
|
-
|
|
9960
|
+
(id, org, source_repo, source_path, target_repo, target_path, layer, relationship,
|
|
9961
|
+
evidence_json, match_reasons_json, evidence_count, is_weak, confidence, created_at)
|
|
9962
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
9579
9963
|
ON CONFLICT(id) DO UPDATE SET
|
|
9964
|
+
source_path = excluded.source_path,
|
|
9965
|
+
target_path = excluded.target_path,
|
|
9966
|
+
layer = excluded.layer,
|
|
9580
9967
|
evidence_json = excluded.evidence_json,
|
|
9968
|
+
match_reasons_json = excluded.match_reasons_json,
|
|
9969
|
+
evidence_count = excluded.evidence_count,
|
|
9970
|
+
is_weak = excluded.is_weak,
|
|
9581
9971
|
confidence = excluded.confidence,
|
|
9582
9972
|
created_at = excluded.created_at`
|
|
9583
9973
|
);
|
|
9584
|
-
|
|
9974
|
+
const persistEdge = (edge) => {
|
|
9585
9975
|
insertEdge.run(
|
|
9586
|
-
`oge_${stableId([
|
|
9976
|
+
`oge_${stableId([
|
|
9977
|
+
edge.org,
|
|
9978
|
+
edge.layer,
|
|
9979
|
+
edge.sourceRepo,
|
|
9980
|
+
edge.sourcePath,
|
|
9981
|
+
edge.targetRepo,
|
|
9982
|
+
edge.targetPath ?? "",
|
|
9983
|
+
edge.relationship
|
|
9984
|
+
])}`,
|
|
9587
9985
|
edge.org,
|
|
9588
9986
|
edge.sourceRepo,
|
|
9589
9987
|
edge.sourcePath,
|
|
9590
9988
|
edge.targetRepo,
|
|
9591
9989
|
edge.targetPath ?? null,
|
|
9990
|
+
edge.layer,
|
|
9592
9991
|
edge.relationship,
|
|
9593
9992
|
evidenceJson(edge.evidence),
|
|
9993
|
+
JSON.stringify(edge.matchReasons),
|
|
9994
|
+
edge.evidenceCount,
|
|
9995
|
+
edge.weak ? 1 : 0,
|
|
9594
9996
|
edge.confidence,
|
|
9595
9997
|
now
|
|
9596
9998
|
);
|
|
9999
|
+
};
|
|
10000
|
+
const persistedEdges = [...repoEdges, ...allFileEdges];
|
|
10001
|
+
for (const [index, edge] of persistedEdges.entries()) {
|
|
10002
|
+
persistEdge(edge);
|
|
9597
10003
|
const current = index + 1;
|
|
9598
|
-
if (shouldEmitProgress3(current,
|
|
10004
|
+
if (shouldEmitProgress3(current, persistedEdges.length, 500)) {
|
|
9599
10005
|
options.onProgress?.({
|
|
9600
10006
|
stage: "writing_org_graph",
|
|
9601
10007
|
org: config.org,
|
|
@@ -9603,7 +10009,7 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9603
10009
|
apiContracts: apiContracts.length,
|
|
9604
10010
|
apiConsumers: apiConsumers.length,
|
|
9605
10011
|
current,
|
|
9606
|
-
total:
|
|
10012
|
+
total: persistedEdges.length,
|
|
9607
10013
|
kind: "edges"
|
|
9608
10014
|
});
|
|
9609
10015
|
}
|
|
@@ -9620,7 +10026,7 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9620
10026
|
);
|
|
9621
10027
|
for (const [index, contract] of apiContracts.entries()) {
|
|
9622
10028
|
insertContract.run(
|
|
9623
|
-
`oac_${stableId([config.org, contract.repo, contract.filePath, contract.
|
|
10029
|
+
`oac_${stableId([config.org, contract.repo, contract.filePath, contract.normalizedContract])}`,
|
|
9624
10030
|
config.org,
|
|
9625
10031
|
contract.repo,
|
|
9626
10032
|
contract.filePath,
|
|
@@ -9634,7 +10040,7 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9634
10040
|
options.onProgress?.({
|
|
9635
10041
|
stage: "writing_org_graph",
|
|
9636
10042
|
org: config.org,
|
|
9637
|
-
edges:
|
|
10043
|
+
edges: persistedEdges.length,
|
|
9638
10044
|
apiContracts: current,
|
|
9639
10045
|
apiConsumers: apiConsumers.length,
|
|
9640
10046
|
current,
|
|
@@ -9645,11 +10051,15 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9645
10051
|
}
|
|
9646
10052
|
const insertConsumer = db.prepare(
|
|
9647
10053
|
`INSERT INTO org_api_consumers
|
|
9648
|
-
(id, org, provider_repo, provider_path, consumer_repo, consumer_path, contract, evidence_json,
|
|
9649
|
-
|
|
10054
|
+
(id, org, provider_repo, provider_path, consumer_repo, consumer_path, contract, evidence_json,
|
|
10055
|
+
match_reasons_json, evidence_count, is_weak, confidence, created_at)
|
|
10056
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
9650
10057
|
ON CONFLICT(id) DO UPDATE SET
|
|
9651
10058
|
contract = excluded.contract,
|
|
9652
10059
|
evidence_json = excluded.evidence_json,
|
|
10060
|
+
match_reasons_json = excluded.match_reasons_json,
|
|
10061
|
+
evidence_count = excluded.evidence_count,
|
|
10062
|
+
is_weak = excluded.is_weak,
|
|
9653
10063
|
confidence = excluded.confidence,
|
|
9654
10064
|
created_at = excluded.created_at`
|
|
9655
10065
|
);
|
|
@@ -9661,7 +10071,7 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9661
10071
|
consumer.providerPath ?? "",
|
|
9662
10072
|
consumer.consumerRepo,
|
|
9663
10073
|
consumer.consumerPath,
|
|
9664
|
-
consumer.contract
|
|
10074
|
+
normalizeToken(consumer.contract)
|
|
9665
10075
|
])}`,
|
|
9666
10076
|
consumer.org,
|
|
9667
10077
|
consumer.providerRepo,
|
|
@@ -9670,6 +10080,9 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9670
10080
|
consumer.consumerPath,
|
|
9671
10081
|
sanitizeHistoricalText(consumer.contract),
|
|
9672
10082
|
evidenceJson(consumer.evidence),
|
|
10083
|
+
JSON.stringify(consumer.matchReasons),
|
|
10084
|
+
consumer.evidenceCount,
|
|
10085
|
+
consumer.weak ? 1 : 0,
|
|
9673
10086
|
consumer.confidence,
|
|
9674
10087
|
now
|
|
9675
10088
|
);
|
|
@@ -9678,7 +10091,7 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9678
10091
|
options.onProgress?.({
|
|
9679
10092
|
stage: "writing_org_graph",
|
|
9680
10093
|
org: config.org,
|
|
9681
|
-
edges:
|
|
10094
|
+
edges: persistedEdges.length,
|
|
9682
10095
|
apiContracts: apiContracts.length,
|
|
9683
10096
|
apiConsumers: current,
|
|
9684
10097
|
current,
|
|
@@ -9689,6 +10102,7 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9689
10102
|
}
|
|
9690
10103
|
});
|
|
9691
10104
|
transaction();
|
|
10105
|
+
const renderPrepMs = Date.now() - renderPrepStartedAt;
|
|
9692
10106
|
const durationMs = Date.now() - startedAt;
|
|
9693
10107
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9694
10108
|
recordOrgGraphState(db, {
|
|
@@ -9696,22 +10110,40 @@ function rebuildOrgGraph(db, config, baseDirOrOptions) {
|
|
|
9696
10110
|
status: "success",
|
|
9697
10111
|
builtAt: finishedAt,
|
|
9698
10112
|
durationMs,
|
|
9699
|
-
edgeCount:
|
|
10113
|
+
edgeCount: repoEdges.length,
|
|
10114
|
+
visibleEdgeCount: visibleRepoEdges.length,
|
|
10115
|
+
weakEdgeCount: hiddenRepoEdges.length,
|
|
10116
|
+
edgeConfidenceDistribution: quality.edgeConfidenceDistribution,
|
|
10117
|
+
lastRenderPrepMs: renderPrepMs,
|
|
9700
10118
|
apiContractCount: apiContracts.length,
|
|
9701
10119
|
apiConsumerCount: apiConsumers.length
|
|
9702
10120
|
});
|
|
9703
10121
|
options.onProgress?.({
|
|
9704
10122
|
stage: "completed_org_graph",
|
|
9705
10123
|
org: config.org,
|
|
9706
|
-
edges:
|
|
10124
|
+
edges: repoEdges.length,
|
|
9707
10125
|
apiContracts: apiContracts.length,
|
|
9708
10126
|
apiConsumers: apiConsumers.length,
|
|
9709
10127
|
durationMs
|
|
9710
10128
|
});
|
|
9711
10129
|
return {
|
|
9712
|
-
edges,
|
|
10130
|
+
edges: visibleRepoEdges,
|
|
10131
|
+
repoEdges: visibleRepoEdges,
|
|
10132
|
+
fileEdges: visibleFileEdges,
|
|
10133
|
+
hiddenFileEdges,
|
|
10134
|
+
hiddenRepoEdges,
|
|
9713
10135
|
apiConsumers,
|
|
9714
|
-
apiContracts
|
|
10136
|
+
apiContracts: apiContracts.map((contract) => ({
|
|
10137
|
+
repo: contract.repo,
|
|
10138
|
+
filePath: contract.filePath,
|
|
10139
|
+
contract: contract.contract,
|
|
10140
|
+
evidence: contract.evidence,
|
|
10141
|
+
confidence: contract.confidence
|
|
10142
|
+
})),
|
|
10143
|
+
quality: {
|
|
10144
|
+
...quality,
|
|
10145
|
+
lastRenderPrepMs: renderPrepMs
|
|
10146
|
+
},
|
|
9715
10147
|
durationMs
|
|
9716
10148
|
};
|
|
9717
10149
|
} catch (error) {
|
|
@@ -10055,6 +10487,8 @@ async function indexOrgRepos(db, config, options = {}) {
|
|
|
10055
10487
|
org: config.org,
|
|
10056
10488
|
status: "skipped",
|
|
10057
10489
|
edgeCount: counts.edges,
|
|
10490
|
+
visibleEdgeCount: counts.visibleEdges,
|
|
10491
|
+
weakEdgeCount: counts.weakEdges,
|
|
10058
10492
|
apiContractCount: counts.apiContracts,
|
|
10059
10493
|
apiConsumerCount: counts.apiConsumers
|
|
10060
10494
|
});
|
|
@@ -10064,7 +10498,12 @@ async function indexOrgRepos(db, config, options = {}) {
|
|
|
10064
10498
|
command,
|
|
10065
10499
|
reason: "Graph skipped because --no-graph was passed."
|
|
10066
10500
|
});
|
|
10067
|
-
graph = {
|
|
10501
|
+
graph = {
|
|
10502
|
+
edges: counts.visibleEdges,
|
|
10503
|
+
apiConsumers: counts.apiConsumers,
|
|
10504
|
+
apiContracts: counts.apiContracts,
|
|
10505
|
+
skipped: true
|
|
10506
|
+
};
|
|
10068
10507
|
} else {
|
|
10069
10508
|
try {
|
|
10070
10509
|
const rebuiltGraph = rebuildOrgGraph(db, config, {
|
|
@@ -10079,7 +10518,12 @@ async function indexOrgRepos(db, config, options = {}) {
|
|
|
10079
10518
|
} catch (error) {
|
|
10080
10519
|
const message = error instanceof Error ? error.message : String(error);
|
|
10081
10520
|
const counts = getOrgGraphCounts(db, config.org);
|
|
10082
|
-
graph = {
|
|
10521
|
+
graph = {
|
|
10522
|
+
edges: counts.visibleEdges,
|
|
10523
|
+
apiConsumers: counts.apiConsumers,
|
|
10524
|
+
apiContracts: counts.apiContracts,
|
|
10525
|
+
error: message
|
|
10526
|
+
};
|
|
10083
10527
|
}
|
|
10084
10528
|
}
|
|
10085
10529
|
recordOrgIndexRun(db, {
|
|
@@ -10123,6 +10567,15 @@ function parseEvidence2(value) {
|
|
|
10123
10567
|
return [];
|
|
10124
10568
|
}
|
|
10125
10569
|
}
|
|
10570
|
+
function parseStringArray(value) {
|
|
10571
|
+
if (!value) return [];
|
|
10572
|
+
try {
|
|
10573
|
+
const parsed = JSON.parse(value);
|
|
10574
|
+
return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
|
|
10575
|
+
} catch {
|
|
10576
|
+
return [];
|
|
10577
|
+
}
|
|
10578
|
+
}
|
|
10126
10579
|
function fileEvidence2(repo, filePath, note) {
|
|
10127
10580
|
return {
|
|
10128
10581
|
prNumber: 0,
|
|
@@ -10154,7 +10607,7 @@ function affectedConsumers(db, org, repo, changedFiles) {
|
|
|
10154
10607
|
const rows = db.prepare(
|
|
10155
10608
|
`SELECT provider_repo, provider_path, consumer_repo, consumer_path, contract, evidence_json, confidence
|
|
10156
10609
|
FROM org_api_consumers
|
|
10157
|
-
WHERE org =
|
|
10610
|
+
WHERE org = ? AND is_weak = 0`
|
|
10158
10611
|
).all(org);
|
|
10159
10612
|
return rows.filter((row) => !repo || row.provider_repo === repo || row.consumer_repo === repo).filter((row) => {
|
|
10160
10613
|
if (changedFiles.length === 0) return true;
|
|
@@ -10169,14 +10622,18 @@ function affectedConsumers(db, org, repo, changedFiles) {
|
|
|
10169
10622
|
consumerPath: row.consumer_path,
|
|
10170
10623
|
contract: sanitizeHistoricalText(row.contract),
|
|
10171
10624
|
evidence: parseEvidence2(row.evidence_json),
|
|
10625
|
+
matchReasons: parseStringArray(row.match_reasons_json),
|
|
10626
|
+
evidenceCount: row.evidence_count ?? parseEvidence2(row.evidence_json).length,
|
|
10627
|
+
weak: (row.is_weak ?? 0) === 1,
|
|
10172
10628
|
confidence: row.confidence
|
|
10173
10629
|
}));
|
|
10174
10630
|
}
|
|
10175
10631
|
function affectedEdges(db, org, repo, changedFiles) {
|
|
10176
10632
|
const rows = db.prepare(
|
|
10177
|
-
`SELECT source_repo, source_path, target_repo, target_path, relationship, evidence_json,
|
|
10633
|
+
`SELECT source_repo, source_path, target_repo, target_path, layer, relationship, evidence_json,
|
|
10634
|
+
match_reasons_json, evidence_count, is_weak, confidence
|
|
10178
10635
|
FROM org_cross_repo_edges
|
|
10179
|
-
WHERE org =
|
|
10636
|
+
WHERE org = ? AND layer = 'file'`
|
|
10180
10637
|
).all(org);
|
|
10181
10638
|
return rows.filter((row) => !repo || row.source_repo === repo || row.target_repo === repo).filter((row) => {
|
|
10182
10639
|
if (changedFiles.length === 0) return true;
|
|
@@ -10187,8 +10644,12 @@ function affectedEdges(db, org, repo, changedFiles) {
|
|
|
10187
10644
|
sourcePath: row.source_path,
|
|
10188
10645
|
targetRepo: row.target_repo,
|
|
10189
10646
|
targetPath: row.target_path ?? void 0,
|
|
10647
|
+
layer: row.layer,
|
|
10190
10648
|
relationship: row.relationship,
|
|
10191
10649
|
evidence: parseEvidence2(row.evidence_json),
|
|
10650
|
+
matchReasons: parseStringArray(row.match_reasons_json),
|
|
10651
|
+
evidenceCount: row.evidence_count ?? parseEvidence2(row.evidence_json).length,
|
|
10652
|
+
weak: (row.is_weak ?? 0) === 1,
|
|
10192
10653
|
confidence: row.confidence
|
|
10193
10654
|
}));
|
|
10194
10655
|
}
|
|
@@ -10506,7 +10967,7 @@ function evidenceLabel(evidence) {
|
|
|
10506
10967
|
if (first.prNumber > 0) return `PR #${first.prNumber}`;
|
|
10507
10968
|
return first.filePath ? `file ${first.filePath}` : first.note ?? "local file evidence";
|
|
10508
10969
|
}
|
|
10509
|
-
function
|
|
10970
|
+
function parseStringArray2(value) {
|
|
10510
10971
|
try {
|
|
10511
10972
|
const parsed = JSON.parse(value);
|
|
10512
10973
|
return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
|
|
@@ -10553,7 +11014,7 @@ function getWisdom(db, input, limit) {
|
|
|
10553
11014
|
const lowerTerms = queryTerms(input).map((term) => term.toLowerCase());
|
|
10554
11015
|
return rows.filter((row) => matchesRepo(row.repo, input.repos)).map((row) => ({
|
|
10555
11016
|
row,
|
|
10556
|
-
score: rowScore(input, row.sanitized_text,
|
|
11017
|
+
score: rowScore(input, row.sanitized_text, parseStringArray2(row.file_paths_json), [], lowerTerms)
|
|
10557
11018
|
})).filter((item) => item.score > 0 || (input.files ?? []).length === 0).sort((a, b) => b.score - a.score || b.row.confidence - a.row.confidence).slice(0, limit).map((item) => item.row);
|
|
10558
11019
|
}
|
|
10559
11020
|
function getCodeEvidence(db, input, limit) {
|
|
@@ -10570,7 +11031,7 @@ function getCodeEvidence(db, input, limit) {
|
|
|
10570
11031
|
input,
|
|
10571
11032
|
row.sanitized_text,
|
|
10572
11033
|
[row.file_path],
|
|
10573
|
-
|
|
11034
|
+
parseStringArray2(row.symbols_json),
|
|
10574
11035
|
lowerTerms
|
|
10575
11036
|
)
|
|
10576
11037
|
})).filter((item) => item.score > 0).sort((a, b) => b.score - a.score).slice(0, limit).map((item) => item.row);
|
|
@@ -10588,7 +11049,7 @@ function getArchitecture(db, input, limit) {
|
|
|
10588
11049
|
score: rowScore(
|
|
10589
11050
|
input,
|
|
10590
11051
|
row.summary_sanitized,
|
|
10591
|
-
|
|
11052
|
+
parseStringArray2(row.source_files_json),
|
|
10592
11053
|
[],
|
|
10593
11054
|
lowerTerms
|
|
10594
11055
|
)
|
|
@@ -10599,9 +11060,10 @@ function findOrgApiConsumers(db, config, input) {
|
|
|
10599
11060
|
const repoClause = input.repo ? " AND (provider_repo = ? OR consumer_repo = ?)" : "";
|
|
10600
11061
|
const repoParams = input.repo ? [input.repo, input.repo] : [];
|
|
10601
11062
|
const rows = db.prepare(
|
|
10602
|
-
`SELECT provider_repo, provider_path, consumer_repo, consumer_path, contract, evidence_json,
|
|
11063
|
+
`SELECT provider_repo, provider_path, consumer_repo, consumer_path, contract, evidence_json,
|
|
11064
|
+
match_reasons_json, evidence_count, is_weak, confidence
|
|
10603
11065
|
FROM org_api_consumers
|
|
10604
|
-
WHERE org =
|
|
11066
|
+
WHERE org = ? AND is_weak = 0${repoClause}
|
|
10605
11067
|
ORDER BY confidence DESC`
|
|
10606
11068
|
).all(config.org, ...repoParams);
|
|
10607
11069
|
const limit = Math.max(1, Math.min(input.maxResults ?? 8, 25));
|
|
@@ -10617,6 +11079,9 @@ function findOrgApiConsumers(db, config, input) {
|
|
|
10617
11079
|
consumerPath: row.consumer_path,
|
|
10618
11080
|
contract: sanitizeHistoricalText(row.contract),
|
|
10619
11081
|
evidence: parseEvidence3(row.evidence_json),
|
|
11082
|
+
matchReasons: parseStringArray2(row.match_reasons_json ?? "[]"),
|
|
11083
|
+
evidenceCount: row.evidence_count ?? parseEvidence3(row.evidence_json).length,
|
|
11084
|
+
weak: (row.is_weak ?? 0) === 1,
|
|
10620
11085
|
confidence: row.confidence
|
|
10621
11086
|
}));
|
|
10622
11087
|
}
|
|
@@ -10625,7 +11090,7 @@ function getOrgArchitectureMap(db, config, format = "mermaid") {
|
|
|
10625
11090
|
const rows = db.prepare(
|
|
10626
11091
|
`SELECT source_repo, source_path, target_repo, target_path, relationship, confidence
|
|
10627
11092
|
FROM org_cross_repo_edges
|
|
10628
|
-
WHERE org = ?
|
|
11093
|
+
WHERE org = ? AND layer = 'repo' AND is_weak = 0
|
|
10629
11094
|
ORDER BY confidence DESC, source_repo, target_repo`
|
|
10630
11095
|
).all(config.org);
|
|
10631
11096
|
const nodes = uniqueStrings(rows.flatMap((row) => [row.source_repo, row.target_repo])).map(
|
|
@@ -10703,7 +11168,7 @@ function buildOrgContextResult(db, config, input) {
|
|
|
10703
11168
|
if (architecture.length === 0) lines.push("- No matching architecture patterns found.");
|
|
10704
11169
|
else {
|
|
10705
11170
|
for (const pattern of architecture) {
|
|
10706
|
-
const files =
|
|
11171
|
+
const files = parseStringArray2(pattern.source_files_json);
|
|
10707
11172
|
lines.push(
|
|
10708
11173
|
`- [${pattern.repo}] [${pattern.area}] ${pattern.summary_sanitized} Evidence: ${files[0] ?? "indexed current code"}.`
|
|
10709
11174
|
);
|