contextl 1.2.27 → 1.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contextl",
3
- "version": "1.2.27",
3
+ "version": "1.2.29",
4
4
  "description": "contextl — finds the most relevant files in your codebase for any change request. MCP server for AI coding agents.",
5
5
  "keywords": [
6
6
  "mcp",
@@ -19,8 +19,11 @@ from import_parser import parse_imports
19
19
  from graph_builder import build_graph, RepoGraph
20
20
 
21
21
 
22
+ import re
23
+
22
24
  # Heuristics for detecting test files by path/name
23
25
  TEST_MARKERS = ("test", "spec", "__tests__", "__mocks__")
26
+ _TEST_PATTERN = re.compile(r'\b(?:' + '|'.join(re.escape(m) for m in TEST_MARKERS) + r')\b', re.IGNORECASE)
24
27
 
25
28
 
26
29
  @dataclass
@@ -104,8 +107,7 @@ class ImpactReport:
104
107
 
105
108
 
106
109
  def _is_test_file(path: str) -> bool:
107
- lowered = path.lower()
108
- return any(marker in lowered for marker in TEST_MARKERS)
110
+ return bool(_TEST_PATTERN.search(path))
109
111
 
110
112
 
111
113
  def analyze_impact(
@@ -65,9 +65,10 @@ class RankedFile:
65
65
 
66
66
 
67
67
  def _tokenize(text: str) -> list[str]:
68
- """Lowercase, split on non-alphanumeric, remove stop words."""
68
+ """Lowercase, split on non-alphanumeric, remove stop words, deduplicate."""
69
69
  tokens = re.findall(r"[a-z0-9]+", text.lower())
70
- return [t for t in tokens if t not in STOP_WORDS and len(t) > 1]
70
+ # Deduplicate while preserving order
71
+ return list(dict.fromkeys(t for t in tokens if t not in STOP_WORDS and len(t) > 1))
71
72
 
72
73
 
73
74
  def _path_tokens(path: str) -> list[str]:
@@ -100,8 +101,7 @@ def _keyword_score(query_terms: list[str], file_path: str, idf_weights: dict[str
100
101
  matched.append(term)
101
102
  # Substring or abbreviation match on filename
102
103
  elif len(term) >= 2 and any(
103
- term in ft or ft in term or ft.startswith(term) or term.startswith(ft) or
104
- all(c in iter(ft) for c in term)
104
+ term in ft or ft in term or ft.startswith(term) or term.startswith(ft)
105
105
  for ft in filename_toks
106
106
  ):
107
107
  score += 3.0 * idf_weights.get(term, 1.0)
@@ -113,8 +113,7 @@ def _keyword_score(query_terms: list[str], file_path: str, idf_weights: dict[str
113
113
  matched.append(term)
114
114
  # Substring or abbreviation match on path
115
115
  elif len(term) >= 2 and any(
116
- term in pt or pt in term or pt.startswith(term) or term.startswith(pt) or
117
- all(c in iter(pt) for c in term)
116
+ term in pt or pt in term or pt.startswith(term) or term.startswith(pt)
118
117
  for pt in path_toks
119
118
  ):
120
119
  score += 1.5 * idf_weights.get(term, 1.0)
package/requirements.txt CHANGED
@@ -8,3 +8,5 @@ tree-sitter-java>=0.22.0
8
8
  tree-sitter-rust>=0.22.0
9
9
  tree-sitter-go>=0.22.0
10
10
  tree-sitter-cpp>=0.22.0
11
+ numpy
12
+ scipy