@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 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 segments = path6.posix.dirname(testPath).split("/").filter(Boolean);
2927
- for (let index = 1; index <= segments.length; index += 1) {
2928
- addToStringMap(byDirectory, segments.slice(0, index).join("/"), testPath);
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.testPaths) {
2949
- if (testPath.includes(`/${basename}.`)) add(testPath);
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 (new RegExp(`\\b${escapeRegExp(lower)}\\b`, "i").test(text))
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(db);
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 (text.toLowerCase().includes(symbol.toLowerCase())) score += 1;
9956
+ else if (lowerText.includes(symbol.toLowerCase())) score += 1;
9910
9957
  }
9911
- for (const term of queryTerms(input)) {
9912
- if (text.toLowerCase().includes(term.toLowerCase())) score += 0.5;
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(input, row.summary_sanitized, parseStringArray(row.source_files_json), [])
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()));