@pratik7368patil/anchor-core 0.1.28 → 0.1.29
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.js +80 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/db/schema.sql +14 -0
package/dist/index.js
CHANGED
|
@@ -707,6 +707,21 @@ CREATE INDEX IF NOT EXISTS idx_org_consumers_provider ON org_api_consumers(org,
|
|
|
707
707
|
CREATE INDEX IF NOT EXISTS idx_org_consumers_consumer ON org_api_consumers(org, consumer_repo);
|
|
708
708
|
CREATE INDEX IF NOT EXISTS idx_org_anomalies_org ON org_anomaly_events(org, severity);
|
|
709
709
|
CREATE INDEX IF NOT EXISTS idx_org_graph_state_status ON org_graph_state(org, last_status);
|
|
710
|
+
|
|
711
|
+
-- Foreign-key indexes backing per-repo / per-PR bulk deletes and re-index scans.
|
|
712
|
+
-- Without these, replaceCodeIndex/deleteExistingPrData full-scan each table per repo/PR.
|
|
713
|
+
CREATE INDEX IF NOT EXISTS idx_code_chunks_repo ON code_chunks(repo_id);
|
|
714
|
+
CREATE INDEX IF NOT EXISTS idx_code_files_repo ON code_files(repo_id);
|
|
715
|
+
CREATE INDEX IF NOT EXISTS idx_code_imports_repo ON code_imports(repo_id);
|
|
716
|
+
CREATE INDEX IF NOT EXISTS idx_test_files_repo ON test_files(repo_id);
|
|
717
|
+
CREATE INDEX IF NOT EXISTS idx_test_links_repo ON test_links(repo_id);
|
|
718
|
+
CREATE INDEX IF NOT EXISTS idx_architecture_components_repo ON architecture_components(repo_id);
|
|
719
|
+
CREATE INDEX IF NOT EXISTS idx_architecture_patterns_repo ON architecture_patterns(repo_id);
|
|
720
|
+
CREATE INDEX IF NOT EXISTS idx_architecture_map_edges_repo ON architecture_map_edges(repo_id);
|
|
721
|
+
CREATE INDEX IF NOT EXISTS idx_wisdom_units_repo ON wisdom_units(repo_id);
|
|
722
|
+
CREATE INDEX IF NOT EXISTS idx_regression_events_repo ON regression_events(repo_id);
|
|
723
|
+
CREATE INDEX IF NOT EXISTS idx_pr_files_pr ON pr_files(pr_id);
|
|
724
|
+
CREATE INDEX IF NOT EXISTS idx_pr_comments_pr ON pr_comments(pr_id);
|
|
710
725
|
`;
|
|
711
726
|
|
|
712
727
|
// src/rules/team-rules.ts
|
|
@@ -1707,14 +1722,22 @@ function openAnchorDatabase(cwd, databasePath = defaultDatabasePath(cwd)) {
|
|
|
1707
1722
|
db.pragma("busy_timeout = 5000");
|
|
1708
1723
|
db.pragma("journal_mode = WAL");
|
|
1709
1724
|
db.pragma("foreign_keys = ON");
|
|
1725
|
+
applyPerformancePragmas(db);
|
|
1710
1726
|
return db;
|
|
1711
1727
|
}
|
|
1712
1728
|
function openAnchorDatabaseReadOnly(databasePath) {
|
|
1713
1729
|
const db = new Database(databasePath, { readonly: true, fileMustExist: true });
|
|
1714
1730
|
db.pragma("busy_timeout = 5000");
|
|
1715
1731
|
db.pragma("foreign_keys = ON");
|
|
1732
|
+
applyPerformancePragmas(db);
|
|
1716
1733
|
return db;
|
|
1717
1734
|
}
|
|
1735
|
+
function applyPerformancePragmas(db) {
|
|
1736
|
+
db.pragma("synchronous = NORMAL");
|
|
1737
|
+
db.pragma("cache_size = -65536");
|
|
1738
|
+
db.pragma("mmap_size = 268435456");
|
|
1739
|
+
db.pragma("temp_store = MEMORY");
|
|
1740
|
+
}
|
|
1718
1741
|
function initializeSchema(db) {
|
|
1719
1742
|
db.exec(SCHEMA_SQL);
|
|
1720
1743
|
ensureColumn(db, "sync_state", "history_coverage", "TEXT");
|
|
@@ -2921,14 +2944,24 @@ function buildRelatedTestIndex(allPaths) {
|
|
|
2921
2944
|
const testPaths = allPaths.filter((candidate) => isTestFilePath(candidate));
|
|
2922
2945
|
const byBase = /* @__PURE__ */ new Map();
|
|
2923
2946
|
const byDirectory = /* @__PURE__ */ new Map();
|
|
2947
|
+
const byDotPrefix = /* @__PURE__ */ new Map();
|
|
2924
2948
|
for (const testPath of testPaths) {
|
|
2925
2949
|
addToStringMap(byBase, testBaseFor(testPath), testPath);
|
|
2926
|
-
const
|
|
2927
|
-
for (let index = 1; index <=
|
|
2928
|
-
addToStringMap(byDirectory,
|
|
2950
|
+
const dirSegments = path6.posix.dirname(testPath).split("/").filter(Boolean);
|
|
2951
|
+
for (let index = 1; index <= dirSegments.length; index += 1) {
|
|
2952
|
+
addToStringMap(byDirectory, dirSegments.slice(0, index).join("/"), testPath);
|
|
2953
|
+
}
|
|
2954
|
+
const pathSegments2 = testPath.split("/");
|
|
2955
|
+
const dotPrefixes = /* @__PURE__ */ new Set();
|
|
2956
|
+
for (let i = 1; i < pathSegments2.length; i += 1) {
|
|
2957
|
+
const segment = pathSegments2[i] ?? "";
|
|
2958
|
+
for (let dot = segment.indexOf("."); dot >= 0; dot = segment.indexOf(".", dot + 1)) {
|
|
2959
|
+
dotPrefixes.add(segment.slice(0, dot));
|
|
2960
|
+
}
|
|
2929
2961
|
}
|
|
2962
|
+
for (const prefix of dotPrefixes) addToStringMap(byDotPrefix, prefix, testPath);
|
|
2930
2963
|
}
|
|
2931
|
-
return { testPaths, byBase, byDirectory };
|
|
2964
|
+
return { testPaths, byBase, byDirectory, byDotPrefix };
|
|
2932
2965
|
}
|
|
2933
2966
|
function relatedTestsFor(filePath, index) {
|
|
2934
2967
|
if (isTestFilePath(filePath)) return [];
|
|
@@ -2945,8 +2978,8 @@ function relatedTestsFor(filePath, index) {
|
|
|
2945
2978
|
if (parsed.dir) {
|
|
2946
2979
|
for (const testPath of index.byDirectory.get(parsed.dir) ?? []) add(testPath);
|
|
2947
2980
|
}
|
|
2948
|
-
for (const testPath of index.
|
|
2949
|
-
|
|
2981
|
+
for (const testPath of index.byDotPrefix.get(basename) ?? []) {
|
|
2982
|
+
add(testPath);
|
|
2950
2983
|
if (related.length >= 8) break;
|
|
2951
2984
|
}
|
|
2952
2985
|
return related.slice(0, 8);
|
|
@@ -4094,8 +4127,7 @@ function symbolMatch2(unit, querySymbols) {
|
|
|
4094
4127
|
const lower = symbol.toLowerCase();
|
|
4095
4128
|
if (unitSymbols.includes(lower)) best = Math.max(best, 1);
|
|
4096
4129
|
else if (text.includes(`\`${lower}\``)) best = Math.max(best, 1);
|
|
4097
|
-
else if (
|
|
4098
|
-
best = Math.max(best, 0.66);
|
|
4130
|
+
else if (symbolBoundaryRegex(lower).test(text)) best = Math.max(best, 0.66);
|
|
4099
4131
|
else if (unitSymbols.some((candidate) => candidate.includes(lower) || lower.includes(candidate))) {
|
|
4100
4132
|
best = Math.max(best, 0.35);
|
|
4101
4133
|
}
|
|
@@ -4178,6 +4210,15 @@ function scoreUnit(unit, input, duplicateCount, repeatedEvidenceCount, freshness
|
|
|
4178
4210
|
function escapeRegExp(value) {
|
|
4179
4211
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4180
4212
|
}
|
|
4213
|
+
var symbolBoundaryRegexCache = /* @__PURE__ */ new Map();
|
|
4214
|
+
function symbolBoundaryRegex(lower) {
|
|
4215
|
+
let regex = symbolBoundaryRegexCache.get(lower);
|
|
4216
|
+
if (!regex) {
|
|
4217
|
+
regex = new RegExp(`\\b${escapeRegExp(lower)}\\b`, "i");
|
|
4218
|
+
symbolBoundaryRegexCache.set(lower, regex);
|
|
4219
|
+
}
|
|
4220
|
+
return regex;
|
|
4221
|
+
}
|
|
4181
4222
|
function loadCandidates(db, input) {
|
|
4182
4223
|
const ftsQuery = buildFtsQuery(input);
|
|
4183
4224
|
const categories = "categories" in input ? input.categories ?? [] : [];
|
|
@@ -4213,9 +4254,11 @@ function loadClaimRepetitionCounts(db) {
|
|
|
4213
4254
|
}
|
|
4214
4255
|
return new Map([...grouped.entries()].map(([key, prs]) => [key, prs.size]));
|
|
4215
4256
|
}
|
|
4216
|
-
function loadFeedbackAdjustments(db) {
|
|
4217
|
-
const rows = db.prepare("SELECT result_id, rating FROM feedback_events").all();
|
|
4257
|
+
function loadFeedbackAdjustments(db, resultIds) {
|
|
4218
4258
|
const adjustments = /* @__PURE__ */ new Map();
|
|
4259
|
+
if (resultIds.length === 0) return adjustments;
|
|
4260
|
+
const placeholders = resultIds.map(() => "?").join(", ");
|
|
4261
|
+
const rows = db.prepare(`SELECT result_id, rating FROM feedback_events WHERE result_id IN (${placeholders})`).all(...resultIds);
|
|
4219
4262
|
for (const row of rows) {
|
|
4220
4263
|
const delta = row.rating === "useful" ? 0.03 : -0.03;
|
|
4221
4264
|
adjustments.set(row.result_id, (adjustments.get(row.result_id) ?? 0) + delta);
|
|
@@ -4235,7 +4278,10 @@ function rankWisdomUnits(db, input) {
|
|
|
4235
4278
|
const candidates = loadCandidates(db, input);
|
|
4236
4279
|
const codeSnapshot = loadCurrentCodeSnapshot(db);
|
|
4237
4280
|
const repetitionCounts = loadClaimRepetitionCounts(db);
|
|
4238
|
-
const feedbackAdjustments = loadFeedbackAdjustments(
|
|
4281
|
+
const feedbackAdjustments = loadFeedbackAdjustments(
|
|
4282
|
+
db,
|
|
4283
|
+
candidates.map((unit) => unit.id)
|
|
4284
|
+
);
|
|
4239
4285
|
const duplicates = /* @__PURE__ */ new Map();
|
|
4240
4286
|
for (const unit of candidates) {
|
|
4241
4287
|
const key = claimKeyFor(unit.category, unit.sanitizedText);
|
|
@@ -9897,8 +9943,9 @@ function queryTerms(input) {
|
|
|
9897
9943
|
function matchesRepo(repo, repos) {
|
|
9898
9944
|
return !repos || repos.length === 0 || repos.includes(repo);
|
|
9899
9945
|
}
|
|
9900
|
-
function rowScore(input, text, files, symbols) {
|
|
9946
|
+
function rowScore(input, text, files, symbols, lowerTerms) {
|
|
9901
9947
|
let score = 0;
|
|
9948
|
+
const lowerText = text.toLowerCase();
|
|
9902
9949
|
for (const file of input.files ?? []) {
|
|
9903
9950
|
if (files.includes(file)) score += 5;
|
|
9904
9951
|
else if (files.some((candidate) => candidate.endsWith(`/${file.split("/").pop() ?? file}`)))
|
|
@@ -9906,10 +9953,10 @@ function rowScore(input, text, files, symbols) {
|
|
|
9906
9953
|
}
|
|
9907
9954
|
for (const symbol of input.symbols ?? []) {
|
|
9908
9955
|
if (symbols.includes(symbol)) score += 4;
|
|
9909
|
-
else if (
|
|
9956
|
+
else if (lowerText.includes(symbol.toLowerCase())) score += 1;
|
|
9910
9957
|
}
|
|
9911
|
-
for (const term of
|
|
9912
|
-
if (
|
|
9958
|
+
for (const term of lowerTerms) {
|
|
9959
|
+
if (lowerText.includes(term)) score += 0.5;
|
|
9913
9960
|
}
|
|
9914
9961
|
return score;
|
|
9915
9962
|
}
|
|
@@ -9920,9 +9967,10 @@ function getWisdom(db, input, limit) {
|
|
|
9920
9967
|
ORDER BY confidence DESC, created_at DESC
|
|
9921
9968
|
LIMIT 500`
|
|
9922
9969
|
).all();
|
|
9970
|
+
const lowerTerms = queryTerms(input).map((term) => term.toLowerCase());
|
|
9923
9971
|
return rows.filter((row) => matchesRepo(row.repo, input.repos)).map((row) => ({
|
|
9924
9972
|
row,
|
|
9925
|
-
score: rowScore(input, row.sanitized_text, parseStringArray(row.file_paths_json), [])
|
|
9973
|
+
score: rowScore(input, row.sanitized_text, parseStringArray(row.file_paths_json), [], lowerTerms)
|
|
9926
9974
|
})).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);
|
|
9927
9975
|
}
|
|
9928
9976
|
function getCodeEvidence(db, input, limit) {
|
|
@@ -9932,13 +9980,15 @@ function getCodeEvidence(db, input, limit) {
|
|
|
9932
9980
|
ORDER BY updated_at DESC
|
|
9933
9981
|
LIMIT 800`
|
|
9934
9982
|
).all();
|
|
9983
|
+
const lowerTerms = queryTerms(input).map((term) => term.toLowerCase());
|
|
9935
9984
|
return rows.filter((row) => matchesRepo(row.repo, input.repos)).map((row) => ({
|
|
9936
9985
|
row,
|
|
9937
9986
|
score: rowScore(
|
|
9938
9987
|
input,
|
|
9939
9988
|
row.sanitized_text,
|
|
9940
9989
|
[row.file_path],
|
|
9941
|
-
parseStringArray(row.symbols_json)
|
|
9990
|
+
parseStringArray(row.symbols_json),
|
|
9991
|
+
lowerTerms
|
|
9942
9992
|
)
|
|
9943
9993
|
})).filter((item) => item.score > 0).sort((a, b) => b.score - a.score).slice(0, limit).map((item) => item.row);
|
|
9944
9994
|
}
|
|
@@ -9949,23 +9999,30 @@ function getArchitecture(db, input, limit) {
|
|
|
9949
9999
|
ORDER BY confidence DESC, created_at DESC
|
|
9950
10000
|
LIMIT 300`
|
|
9951
10001
|
).all();
|
|
10002
|
+
const lowerTerms = queryTerms(input).map((term) => term.toLowerCase());
|
|
9952
10003
|
return rows.filter((row) => matchesRepo(row.repo, input.repos)).map((row) => ({
|
|
9953
10004
|
row,
|
|
9954
|
-
score: rowScore(
|
|
10005
|
+
score: rowScore(
|
|
10006
|
+
input,
|
|
10007
|
+
row.summary_sanitized,
|
|
10008
|
+
parseStringArray(row.source_files_json),
|
|
10009
|
+
[],
|
|
10010
|
+
lowerTerms
|
|
10011
|
+
)
|
|
9955
10012
|
})).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);
|
|
9956
10013
|
}
|
|
9957
10014
|
function findOrgApiConsumers(db, config, input) {
|
|
9958
10015
|
initializeSchema(db);
|
|
10016
|
+
const repoClause = input.repo ? " AND (provider_repo = ? OR consumer_repo = ?)" : "";
|
|
10017
|
+
const repoParams = input.repo ? [input.repo, input.repo] : [];
|
|
9959
10018
|
const rows = db.prepare(
|
|
9960
10019
|
`SELECT provider_repo, provider_path, consumer_repo, consumer_path, contract, evidence_json, confidence
|
|
9961
10020
|
FROM org_api_consumers
|
|
9962
|
-
WHERE org =
|
|
10021
|
+
WHERE org = ?${repoClause}
|
|
9963
10022
|
ORDER BY confidence DESC`
|
|
9964
|
-
).all(config.org);
|
|
10023
|
+
).all(config.org, ...repoParams);
|
|
9965
10024
|
const limit = Math.max(1, Math.min(input.maxResults ?? 8, 25));
|
|
9966
|
-
return rows.filter(
|
|
9967
|
-
(row) => !input.repo || row.provider_repo === input.repo || row.consumer_repo === input.repo
|
|
9968
|
-
).filter((row) => {
|
|
10025
|
+
return rows.filter((row) => {
|
|
9969
10026
|
const files = input.files ?? [];
|
|
9970
10027
|
if (files.length === 0 && !input.query) return true;
|
|
9971
10028
|
return files.some((file) => row.provider_path === file || row.consumer_path === file) || Boolean(input.query && row.contract.toLowerCase().includes(input.query.toLowerCase()));
|